# Pagination Adapters _(no submodules)_ ## Purpose The adapters module defines the `PaginationAdapter` interface that all three pagination strategies — cursor, offset, and keyset — consume for data access. It also ships `MemoryPaginationAdapter`, a pure in-memory reference implementation that stores items in a plain array and supports equality-based filtering and single-field sorting. The adapter abstraction decouples pagination logic from the underlying data layer, so swapping from an in-memory store to a SQL database or HTTP API requires implementing just two methods. ## Features - `PaginationAdapter` interface — two methods: `fetchPage` (paginated fetch) and `count` (total matching items). - `MemoryPaginationAdapter` — in-memory implementation with `addItems`, `setItems`, `getAll`, `fetchPage`, and `count`. - `createMemoryAdapter` — factory function that creates a pre-populated `MemoryPaginationAdapter`. - `createSortConfig` — convenience builder for `SortConfig` values. ## Usage: Basic Example ```typescript import { createMemoryAdapter, createSortConfig } from "@suaveplan/pagination/adapters"; const adapter = createMemoryAdapter([ { id: 1, name: "Alice", age: 30 }, { id: 2, name: "Bob", age: 25 }, { id: 3, name: "Carol", age: 35 }, ]); const sort = createSortConfig("name", "asc"); const page = await adapter.fetchPage(0, 2, sort); // page.items → [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }] // page.total → 3 ``` ## Usage: Advanced Example ```typescript import { createMemoryAdapter } from "@suaveplan/pagination/adapters"; import { fetchAfter, encodeCursor } from "@suaveplan/pagination/cursor"; const adapter = createMemoryAdapter( Array.from({ length: 50 }, (_, i) => ({ id: i + 1, score: i * 2 })) ); // Count with filter const activeCount = await adapter.count({ score: 10 }); // Use with cursor pagination const page = await fetchAfter(adapter, undefined, { limit: 5, sortBy: "id" }, (i) => i.id); // page.items → first 5 items sorted by id // Replace dataset at runtime adapter.setItems([{ id: 99, score: 0 }]); const count = await adapter.count(); // → 1 ``` ## API Reference ### `interface PaginationAdapter` | Method | Signature | |-------------|------------------------------------------------------------------------------| | `fetchPage` | `(offset, limit, sort?, filter?) => Promise>` | | `count` | `(filter?) => Promise` | `fetchPage` must return items in the requested sort order and the total matching count in `PageResult.total`. ### `class MemoryPaginationAdapter` | Method | Description | |-------------|-----------------------------------------------------| | `constructor(items?)` | Initialises with a shallow copy of `items`. | | `addItems(items)` | Appends items to the store. | | `setItems(items)` | Replaces the entire store. | | `getAll()` | Returns a shallow copy of all items. | | `fetchPage(...)` | Applies filter, sorts, slices, returns `PageResult`. | | `count(filter?)` | Returns the count of items matching the filter. | ### `createMemoryAdapter(items?): MemoryPaginationAdapter` Factory that creates a `MemoryPaginationAdapter` pre-populated with `items` (default: empty array). ### `createSortConfig(field, direction?): SortConfig` Builds a `{ field, direction }` sort config. Direction defaults to `"asc"`. ## Implementation Notes Filtering uses strict equality (`===`) on top-level fields only — nested field access is not supported in the reference implementation. Sorting uses `localeCompare` for strings and arithmetic comparison for numbers; null values sort last. The `items` array is always stored as a shallow copy to prevent external mutation from affecting the adapter state. Class members are `protected` (not `private`) to enable subclassing in tests without re-implementing the full interface.