@adonis-agora/filter
Version:
Server-side query filtering/sorting/pagination for AdonisJS — Spatie-style input, a Lucid adapter, and field allow-listing. Part of the Agora ecosystem.
92 lines • 4.25 kB
TypeScript
import type { SortItem } from './types.js';
/**
* A decoded keyset cursor: the ordered values of the keyset columns (the active
* sort columns plus a stable primary-key tiebreaker) captured from a boundary
* row. The values line up positionally with the keyset's {@link SortItem}[].
*/
export type CursorValues = unknown[];
/**
* Cursor (keyset) pagination parameters, as parsed from a request:
*
* - `after` — return the page immediately following this opaque cursor (forward).
* - `before` — return the page immediately preceding this opaque cursor (backward).
* - `first` / `last` — page size for forward / backward paging respectively.
*
* `after` and `before` are mutually exclusive; if both are given, `after` wins.
*/
export interface CursorParams {
after?: string;
before?: string;
first?: number;
last?: number;
}
/**
* A single page of keyset-paginated results assembled by {@link buildCursorPage}.
*
* - `items` — the rows for this page, in the requested order.
* - `nextCursor` — opaque cursor for the next forward page, or `null` when this
* is the last page.
* - `prevCursor` — opaque cursor for the previous (backward) page, or `null`
* when this is the first page.
* - `hasNext` / `hasPrev` — convenience booleans mirroring the cursors.
*/
export interface CursorPage<T> {
items: T[];
nextCursor: string | null;
prevCursor: string | null;
hasNext: boolean;
hasPrev: boolean;
}
/**
* Encodes keyset cursor values into a compact, URL-safe opaque string
* (base64url of a JSON array). The shape is intentionally opaque to clients —
* only this module reads it back.
*
* `Date` values are encoded as `{ $d: <iso> }` so they round-trip to `Date`
* instances on decode (plain JSON would yield a string and break date keyset
* comparisons).
*/
export declare function encodeCursor(values: CursorValues): string;
/**
* Decodes an opaque cursor string back into its keyset values. Returns `null`
* when the cursor is malformed (bad base64, bad JSON, or not an array) so the
* caller can ignore an invalid cursor instead of crashing.
*/
export declare function decodeCursor(cursor: string): CursorValues | null;
/**
* Builds the keyset {@link SortItem}[] for cursor pagination: the caller's
* effective sorts, with a stable primary-key tiebreaker appended if it is not
* already present. The tiebreaker inherits the direction of the last sort column
* so the overall ordering stays monotonic (important for a correct
* `(cols, pk) > (...)` comparison).
*/
export declare function buildKeyset(sorts: SortItem[], primaryKey: string): SortItem[];
/** Flips every keyset column's direction (for backward cursor paging). */
export declare function reverseKeyset(keyset: SortItem[]): SortItem[];
/**
* Extracts the keyset values from a fetched row, in keyset column order.
* Supports dotted relation paths (e.g. `author.name`) by walking the object.
*/
export declare function extractCursorValues(row: Record<string, unknown>, keyset: SortItem[]): CursorValues;
/** The keyset shape {@link applyCursor} resolves and hands to {@link buildCursorPage}. */
export interface ResolvedCursor {
/** The base keyset (effective sort + primary-key tiebreaker), in forward order. */
keyset: SortItem[];
/** Effective page size — the number of rows to keep for this page. */
size: number;
/** True when paging backward (a `before` cursor was supplied). */
backward: boolean;
/** True when a cursor (`after`/`before`) was supplied — the opposite page is then known to exist. */
hasCursor: boolean;
}
/**
* Assembles a {@link CursorPage} from the rows fetched for a keyset query.
*
* The query is expected to have been built by {@link applyCursor}, which fetches
* one extra row (`limit = size + 1`) so we can detect a further page. For
* backward paging the rows come back reversed and are flipped here to restore
* the caller's requested order. Boundary cursors are computed from the base
* keyset so they round-trip regardless of paging direction.
*/
export declare function buildCursorPage<T extends Record<string, unknown>>(rows: T[], resolved: ResolvedCursor): CursorPage<T>;
//# sourceMappingURL=cursor.d.ts.map