# `AshScylla.DataLayer.Pagination`
[🔗](https://github.com/ohhi-vn/ash_scylla/blob/main/lib/ash_scylla/data_layer/pagination.ex#L15)

Token-based pagination support for AshScylla.

ScyllaDB/Cassandra uses Xandra's native paging state mechanism for efficient
pagination.

## Token-Based Pagination

AshScylla uses keyset pagination by default (`data_layer_keyset_by_default?/0`
returns `true`). When `pagination :token` is set in the scylla DSL,
queries use Xandra's built-in paging state to efficiently page through results.

## Usage

    # First page
    {:ok, records, next_page_token} =
      AshScylla.DataLayer.Pagination.fetch_page(repo, table, filters, nil, 10)

    # Subsequent pages
    {:ok, records, next_page_token} =
      AshScylla.DataLayer.Pagination.fetch_page(repo, table, filters, page_token, 10)

## Page Token Format

Page tokens are opaque binaries returned by Xandra's paging_state.
They should be treated as opaque by callers and only passed back
to fetch the next page.

## Limits

Default page size: 50. Maximum page size: 1000.

# `page_result`

```elixir
@type page_result() :: {:ok, [term()], String.t() | nil} | {:error, term()}
```

# `page_token`

```elixir
@type page_token() :: String.t() | nil
```

# `build_paginated_query`

```elixir
@spec build_paginated_query(String.t(), list(), pos_integer()) ::
  {:ok, {String.t(), list()}} | {:error, {:unknown_filter, term()}}
```

Builds a CQL query string with LIMIT for pagination.

Returns `{query, params}` suitable for `repo.query/3`.

# `build_paginated_query`

```elixir
@spec build_paginated_query(String.t(), list(), page_token(), pos_integer()) ::
  {:ok, {String.t(), list()}} | {:error, {:unknown_filter, term()}}
```

Builds a CQL query string with LIMIT for pagination, with optional page token.

When `page_token` is non-nil, adds a `token() > ?` condition to the WHERE clause.
Returns `{query, params}` suitable for `repo.query/3`.

`uuid_fields` and `cql_types` are optional and, when provided, ensure UUID
filter values are converted to 16-byte binaries tagged as `{"uuid", bin}`
(otherwise ScyllaDB rejects them with "Validation failed for uuid - got N bytes").

# `build_paginated_query`

# `decode_cursor`

```elixir
@spec decode_cursor(String.t()) :: {:ok, binary()} | {:error, :invalid_cursor}
```

Decodes a cursor string back to a paging state binary.
Returns `{:ok, binary}` on success or `{:error, :invalid_cursor}` on failure.

# `decode_page_token`

```elixir
@spec decode_page_token(String.t()) :: {:ok, binary()} | {:error, :invalid_token}
```

Decodes a page token string back to a paging state binary.

Returns `{:ok, binary}` on success or `{:error, :invalid_token}` on failure.

# `default_page_size`

```elixir
@spec default_page_size() :: pos_integer()
```

Returns the default page size.

# `encode_cursor`

```elixir
@spec encode_cursor(binary()) :: String.t()
```

Encodes a paging state binary to an opaque cursor string (base64url).

# `encode_page_token`

```elixir
@spec encode_page_token(binary()) :: String.t()
```

Encodes a paging state binary to an opaque page token string.

# `extract_paging_state`

```elixir
@spec extract_paging_state(term()) :: binary() | nil
```

Extract the `paging_state` from a query result for use in the next page request.
Returns `nil` if this was the last page.

# `fetch_page`

```elixir
@spec fetch_page(module(), String.t(), list(), page_token(), pos_integer()) ::
  page_result()
```

Fetches a page of results using Xandra's native paging state.

## Parameters

- `repo` - The AshScylla repo module
- `table` - The table name
- `filters` - Filter list for WHERE clause
- `page_token` - Opaque page token from previous page (nil for first page)
- `page_size` - Number of results per page (default: 50, max: 1000)

## Returns

`{:ok, records, next_page_token}` where `next_page_token` is nil
when there are no more pages.

# `fetch_page`

```elixir
@spec fetch_page(
  module(),
  String.t(),
  list(),
  page_token(),
  pos_integer(),
  MapSet.t(),
  map()
) :: page_result()
```

# `max_page_size`

```elixir
@spec max_page_size() :: pos_integer()
```

Returns the maximum allowed page size.

# `page_opts`

```elixir
@spec page_opts(page_token() | nil, pos_integer()) :: keyword()
```

Build query options for a given page request.
Pass `nil` for the first page, or a previously returned `paging_state`
binary for subsequent pages.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
