From 641ce4237ef3fec6752f097a695d81d2949e6920 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Tue, 7 Jan 2025 16:28:37 +0100 Subject: [PATCH] Use an array as a backing store for after --- api/src/models/utils/keyset-paginate.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/api/src/models/utils/keyset-paginate.ts b/api/src/models/utils/keyset-paginate.ts index d6710af3..81610499 100644 --- a/api/src/models/utils/keyset-paginate.ts +++ b/api/src/models/utils/keyset-paginate.ts @@ -3,9 +3,7 @@ import { eq, or, type Column, and, gt, lt } from "drizzle-orm"; type Table = Record; -type After = Record & { - reverse?: boolean; -}; +type After = [boolean, ...[string | number | boolean | undefined]]; // Create a filter (where) expression on the query to skip everything before/after the referenceID. // The generalized expression for this in pseudocode is: @@ -31,18 +29,20 @@ export const keysetPaginate = < sort: Sort; }) => { if (!after) return undefined; - const { reverse, ...cursor }: After = JSON.parse( + const [reverse, ...cursor]: After = JSON.parse( Buffer.from(after, "base64").toString("utf-8"), ); + const pkSort = { key: "pk" as const, desc: false }; + // TODO: Add an outer query >= for perf // PERF: See https://use-the-index-luke.com/sql/partial-results/fetch-next-page#sb-equivalent-logic let where = undefined; let previous = undefined; - for (const by of [...sort, { key: "pk" as const, desc: false }]) { + for (const [i, by] of [...sort, pkSort].entries()) { const cmp = by.desc !== reverse ? lt : gt; - where = or(where, and(previous, cmp(table[by.key], cursor[by.key]))); - previous = and(previous, eq(table[by.key], cursor[by.key])); + where = or(where, and(previous, cmp(table[by.key], cursor[i]))); + previous = and(previous, eq(table[by.key], cursor[i])); } return where; @@ -53,9 +53,10 @@ export const generateAfter = ( sort: Sort, reverse?: boolean, ) => { - const ret: After = { reverse }; - for (const by of sort) { - ret[by.key] = cursor[by.key]; - } + const ret = [ + reverse ?? false, + ...sort.map((by) => cursor[by.key]), + cursor.pk, + ]; return Buffer.from(JSON.stringify(ret), "utf-8").toString("base64"); };