Files
2026-05-27 23:47:53 +01:00

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) and count (total matching items).
  • MemoryPaginationAdapter<T> — 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

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.