Easy Relay cursor pagination for your Knex queries
- 🚀 implements the GraphQL Cursor Connections Specification
- 🔌 integrates easily with GraphQL tools like Apollo Server
- 📦 well-tested with 100% coverage
yarn add knex-relay-cursor-pagination
import { createPagination } from 'knex-relay-cursor-pagination';
export type Post = {
id: string;
title: string;
creation_timestamp: string;
};
async function getPosts(first?: number, after?: string, last?: number, before?: string): Promise<Page<Post>> {
const pagination = createPagination({
from: 'posts',
sortColumn: 'creation_timestamp',
sortDirection: 'desc',
cursorColumn: 'id',
first,
after,
last,
before,
});
const rows = await this.db.from('posts')
.where(pagination.where.column, pagination.where.comparator, pagination.where.value)
.orderBy(pagination.orderBy.column, pagination.orderBy.direction)
.limit(pagination.limit)
.select('*');
return pagination.getPage<Post>(rows);
}
To sort by a derived sorting column, use Knex .with
and pass the query alias to .from
.
Here is an example of sorting posts by their count of associated comments:
const cte = db
.from('posts')
.select(
'posts.*',
db.raw(`concat(count("comments"."id"), ':', "posts".id) as comments_count`)
)
.leftJoin('comments', 'posts.id', 'comments.post_id')
.groupBy('posts.id')
.orderBy('comments_count', 'desc');
const pagination = createPagination({
from: 'cte',
sortColumn: 'comments_count',
sortDirection: 'desc',
cursorColumn: 'id',
first,
after,
last,
before,
});
const rows = await db
.with('cte', cte)
.from('cte')
.where(
pagination.where.column,
pagination.where.comparator,
pagination.where.value
)
.orderBy(pagination.orderBy.column, pagination.orderBy.direction)
.limit(pagination.limit);
pagination.getPage<Post>(rows);
Takes a configuration parameter and returns an object containing values to pass into the knex query and a function to transform the queried rows into a Relay connection page object.
Required
cursorColumn
: the column to be used for the cursor. Values must be uniquesortColumn
: the column that the data is sorted bysortDirection
: the sort direction of the datafrom
: the table or common-table-expression being queried from
Either first
or last
is required
first
: corresponds to thefirst
param of the Relay specafter
: corresponds to theafter
param of the Relay speclast
: corresponds to thelast
param of the Relay specbefore
: corresponds to thebefore
param of the Relay spec
obfuscateCursor
: a function for transforming the cursor's raw value to an opaque valuedeobfuscateCursor
: a function for transforming the cursor's opaque value to the raw valueonCursorMissing
:'omit' | 'throw'
, the behavior for when a queried row's cursor value is missing. Defaults to'omit'
See the example app in the /example directory of this repo. See its README.md for more info.