4.1 KiB
Pagination Adapters
(no submodules)
Purpose
The adapters module defines the PaginationAdapter<T> interface that all three pagination strategies — cursor, offset, and keyset — consume for data access. It also ships MemoryPaginationAdapter<T>, 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<T>interface — two methods:fetchPage(paginated fetch) andcount(total matching items).MemoryPaginationAdapter<T>— in-memory implementation withaddItems,setItems,getAll,fetchPage, andcount.createMemoryAdapter— factory function that creates a pre-populatedMemoryPaginationAdapter.createSortConfig— convenience builder forSortConfigvalues.
Usage: Basic Example
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
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<T>
| Method | Signature |
|---|---|
fetchPage |
(offset, limit, sort?, filter?) => Promise<PageResult<T>> |
count |
(filter?) => Promise<number> |
fetchPage must return items in the requested sort order and the total matching count in PageResult.total.
class MemoryPaginationAdapter<T>
| 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<T>(items?): MemoryPaginationAdapter<T>
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.