drizzle-cursor
Version:
Utils for Drizzle ORM cursor based pagination
126 lines (114 loc) • 3.48 kB
text/typescript
import { type CursorConfig, generateCursor, parse, serialize } from "../src";
import { and, asc, desc, eq, gt, lt, or } from "drizzle-orm";
import { describe, expect, test } from "vitest";
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
describe("cursors", () => {
const table = sqliteTable("users", {
id: integer("id").primaryKey({ autoIncrement: true }),
firstName: text("first_name"),
middleName: text("middle_name"),
lastName: text("last_name"),
phone: text("phone"),
email: text("email"),
});
const config: CursorConfig = {
cursors: [
{ key: "firstName", schema: table.firstName, order: "DESC" },
{ key: "lastName", schema: table.lastName },
{ key: "middleName", schema: table.middleName, order: "DESC" },
],
primaryCursor: { key: "id", schema: table.id, order: "ASC" },
};
const data = {
id: 1,
firstName: "John",
middleName: "Doe",
lastName: "Smith",
phone: "1234567890",
email: "john@doe.com",
};
const cursorToken =
"eyJpZCI6MSwiZmlyc3ROYW1lIjoiSm9obiIsImxhc3ROYW1lIjoiU21pdGgiLCJtaWRkbGVOYW1lIjoiRG9lIn0=";
describe("parse", () => {
test("parses a cursor", () => {
expect(parse(config, cursorToken)).to.deep.equal({
// Not email or phono in the cursor
id: data.id,
firstName: data.firstName,
middleName: data.middleName,
lastName: data.lastName,
});
});
});
describe("parse & serialize", () => {
test("generates the same cursor", () => {
expect(serialize(config, parse(config, cursorToken))).to.equal(
cursorToken,
);
});
});
describe("parse & generateCursor", () => {
test("generates cursor with parse", () => {
const cursor = generateCursor(config);
expect(cursor.orderBy).toEqual([
desc(table.firstName),
asc(table.lastName),
desc(table.middleName),
asc(table.id),
]);
expect(cursor.where(data)).toEqual(
or(
and(lt(table.firstName, data.firstName)),
and(
eq(table.firstName, data.firstName),
gt(table.lastName, data.lastName),
),
and(
eq(table.firstName, data.firstName),
eq(table.lastName, data.lastName),
lt(table.middleName, data.middleName),
),
and(
eq(table.firstName, data.firstName),
eq(table.lastName, data.lastName),
eq(table.middleName, data.middleName),
gt(table.id, data.id),
),
),
);
});
test("generates cursor with token directly", () => {
const _cursor = generateCursor(config);
expect(_cursor.orderBy).toEqual([
desc(table.firstName),
asc(table.lastName),
desc(table.middleName),
asc(table.id),
]);
expect(_cursor.where()).toEqual(undefined);
expect(_cursor.where(cursorToken)).toEqual(
or(
and(lt(table.firstName, "John")),
and(eq(table.firstName, "John"), gt(table.lastName, "Smith")),
and(
eq(table.firstName, "John"),
eq(table.lastName, "Smith"),
lt(table.middleName, "Doe"),
),
and(
eq(table.firstName, "John"),
eq(table.lastName, "Smith"),
eq(table.middleName, "Doe"),
gt(table.id, 1),
),
),
);
});
test("where with token or data object should generate the same cursor", () => {
const cursor = generateCursor(config);
expect(cursor.where(data)).toEqual(cursor.where(serialize(config, data)));
expect(cursor.where(data)).toEqual(cursor.where(cursor.serialize(data)));
expect(cursor.where(data)).toEqual(cursor.where(cursorToken));
});
});
});