Registry / database / sql-cursor-pagination

sql-cursor-pagination

JSON →
library4.3.0jsnpmunverified

Library for implementing cursor-based pagination from SQL databases, conforming to the GraphQL Cursor Connections Specification (Relay-compatible). Current stable version is 4.3.0, released with support for Node >=18 and TypeScript types built-in. Key differentiators: generates encrypted opaque cursors, supports forward/backward pagination (first/last, before/after), works with any SQL query builder or raw SQL via provided fragments (where, order by). Unlike offset-based pagination, cursors prevent duplicate or skipped items when data changes between requests.

npm install sql-cursor-pagination
INSTALL
IMPORT
SIG · SQL-CURSOR-PAGINAT
S
sql-cursor-pagination
databasejavascriptv4.3.0
harness data pending
Install & Compatibility
Where this runs

No compatibility data collected yet for this library.

Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

withPagination
✓ import { withPagination } from 'sql-cursor-pagination'
✗ const { withPagination } = require('sql-cursor-pagination')
ESM-only since v4; Node >=18 required. CommonJS require() will fail.
Order
✓ import { Order } from 'sql-cursor-pagination'
TypeScript type (enum-like union) for sort order values: 'ASC' | 'DESC'. No runtime export for CJS.
buildCursorSecret
✓ import { buildCursorSecret } from 'sql-cursor-pagination'
✗ import { buildCursorSecret } from 'sql-cursor-pagination/buildCursorSecret'
Direct named export; no subpath import. Function returns a Buffer from a string or Buffer secret.

Shows complete setup with Knex and TypeScript: table creation, paginated query with cursor support.

import knex from 'knex'; import { withPagination, Order, buildCursorSecret } from 'sql-cursor-pagination'; const db = knex({ client: 'sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true, }); await db.schema.createTable('users', (table) => { table.integer('id').notNullable(); table.integer('created_at').notNullable(); table.string('first_name').notNullable(); table.string('last_name').notNullable(); table.string('email').notNullable(); table.boolean('admin').notNullable(); }); async function fetchUsers(userInput: { order: Order; admins: boolean; first?: number; last?: number; before?: string; after?: string; }) { const query = db('users').where('admin', userInput.admins); const { edges, pageInfo } = await withPagination({ query: { first: userInput.first, last: userInput.last, before: userInput.before, after: userInput.after, }, setup: { sortFields: [ { field: 'first_name', order: userInput.order }, { field: 'last_name', order: userInput.order }, { field: 'id', order: userInput.order }, ], cursorSecret: buildCursorSecret('somethingSecret'), queryName: 'users', runQuery: async ({ limit, whereFragmentBuilder, orderByFragmentBuilder }) => { const whereFragment = whereFragmentBuilder.withArrayBindings(); const orderByFragment = orderByFragmentBuilder.withArrayBindings(); const rows = await query .limit(limit) .whereRaw(whereFragment.sql, whereFragment.bindings) .orderByRaw(orderByFragment.sql, orderByFragment.bindings); return rows; }, }, }); return { edges: edges, pageInfo: pageInfo }; }
Debug
Known issues
breakingBreaking change in v4: dropped CommonJS support. Only ESM with Node >=18.
fix
Migrate to ES modules (type: 'module' in package.json or .mjs extension) and ensure Node >=18.
affects: >=4.0.0
breakingBreaking change in v3: renamed 'cursorSecret' to 'buildCursorSecret' and changed return type to Buffer.
fix
Update code to use buildCursorSecret() instead of direct buffer variable.
affects: >=3.0.0 <4.0.0
gotchaThe 'sortFields' array must include a unique key (or combination) as the last field to avoid tie-breaking issues and incorrect pagination.
fix
Always set a unique key (like 'id') as the final sort field.
affects: >=1.0.0
gotchaIf using fragments with positional bindings (withPositionalBindings) instead of array bindings, the fragment SQL uses '?' placeholders which may conflict with some databases.
fix
Use withArrayBindings() for better compatibility with most SQL drivers.
affects: >=1.0.0
Errors
Common errors & fixes
Error: 'withPagination' is not exported from 'sql-cursor-pagination' (or similar import error)
Using CommonJS require() with ESM-only package (v4+).
fix
Switch to import statement or use dynamic import: const { withPagination } = await import('sql-cursor-pagination');
could not determine unique field in sort fields
sortFields array does not include a unique key (like primary key) as the last field.
fix
Add a unique field, e.g., { field: 'id', order: 'ASC' } as the last element in sortFields.
Cannot read properties of undefined (reading 'sql')
Misuse of whereFragmentBuilder or orderByFragmentBuilder without calling withArrayBindings() or withPositionalBindings().
fix
Call whereFragmentBuilder.withArrayBindings() (or the positional variant) to get the fragment object.
Upgrade
Version history
4.3.0latest on npm
Audit
Dependencies

No dependency data recorded yet.

Agent activity
17 hits · last 30 days
node
10
OpenAI (training)
1
Resources
sql-cursor-pagination — npm install sql-cursor-pagination · libregistry