Current section
Files
Jump to
Current section
Files
lib/aurora/ctx/pagination.ex
defmodule Aurora.Ctx.Pagination do
@moduledoc """
Provides a structured approach to handling pagination state in database queries and data
retrieval operations.
This module defines a struct that encapsulates all necessary pagination information including
options used for the initial records request, current page position, page size, total counts, and
the actual data entries. It supports configurable defaults and safe initialization
with automatic fallback to sensible defaults when invalid values are provided.
## Configuration
Default pagination settings can be configured in your `config.exs`:
```elixir
config :aurora_ctx, :pagination,
page: 1,
per_page: 40
```
If not configured, defaults to `page: 1`, `per_page: 40`.
## Fields
* `repo_module` - Repository module used for database operations
* `schema_module` - Schema module representing the data being paginated
* `entries_count` - Total number of records available
* `pages_count` - Total number of pages based on entries_count and per_page
* `page` - Current page number (default: 1)
* `per_page` - Number of entries per page (default: 40)
* `opts` - Additional query options passed to database operations
* `entries` - List of records for the current page
"""
@type t :: %__MODULE__{
repo_module: module() | nil,
schema_module: module() | nil,
entries_count: non_neg_integer() | nil,
pages_count: pos_integer() | nil,
page: pos_integer(),
per_page: pos_integer(),
opts: keyword(),
entries: list()
}
defstruct [
:repo_module,
:schema_module,
:entries_count,
:pages_count,
page: 1,
per_page: 40,
opts: [],
entries: []
]
@page 1
@per_page 40
@default_pagination Application.compile_env(:aurora_ctx, :pagination, %{})
@doc """
Creates a new pagination struct with safe defaults from the application configuration.
Delegates to new/1 with the configured defaults.
Any invalid configuration values will be replaced with pagination defaults.
## Returns
Returns a `t()` struct with default values applied.
"""
@spec new() :: t()
def new, do: new(@default_pagination)
@doc """
Creates a new pagination struct with the given attributes.
Validates and normalizes input attributes, ensuring that `page` and `per_page` are positive
integers. Invalid or missing values are replaced with safe defaults.
## Parameters
- attrs (`map()` | `keyword()`) - Pagination attributes
- `:page` (`pos_integer()`) - Page number (default: 1)
- `:per_page` (`pos_integer()`) - Items per page (default: 40)
- `:opts` (`keyword()`) - Additional query options for database operations
- `:entries` (`list()`) - Initial list of entries for the current page
## Returns
Returns a `t()` struct with validated and normalized values.
"""
@spec new(map() | keyword()) :: t()
def new(attrs) when is_list(attrs), do: attrs |> Enum.into(%{}) |> new()
def new(attrs) when is_map(attrs) do
%__MODULE__{
page: get_positive_integer(attrs, :page, @page),
per_page: get_positive_integer(attrs, :per_page, @per_page),
opts: Map.get(attrs, :opts, []),
entries: Map.get(attrs, :entries, [])
}
end
## PRIVATE
# Extracts a positive integer value from a map, falling back to default if invalid
@spec get_positive_integer(map(), atom(), integer()) :: integer()
defp get_positive_integer(map, key, default) do
case Map.get(map, key, default) do
value when is_integer(value) and value > 0 -> value
_ -> default
end
end
end