drizzle-cursor
Version:
Utils for Drizzle ORM cursor based pagination
208 lines (201 loc) • 6.41 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc2) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
decoder: () => decoder,
default: () => generateCursor,
encoder: () => encoder,
generateCursor: () => generateCursor,
parse: () => parse,
parser: () => parser,
serialize: () => serialize,
serializer: () => serializer
});
module.exports = __toCommonJS(src_exports);
// src/generateCursor.ts
var import_drizzle_orm = require("drizzle-orm");
// src/utils.ts
function generateSubArrays(arr) {
const subArrays = [];
for (let i = 0; i < arr.length; i++) {
subArrays.push([...arr.slice(0, i + 1)]);
}
return subArrays;
}
var decoder = (data) => Buffer.from(data, "base64").toString("utf-8");
var encoder = (str) => Buffer.from(str, "utf-8").toString("base64");
var parser = JSON.parse;
var serializer = JSON.stringify;
var ISO_DATE_TIME_REGEX = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?(?:Z|([+-])(\d{2}):(\d{2}))?)?$/;
function isValidDateOrDateTimeString(value) {
if (typeof value !== "string") {
return false;
}
const m = ISO_DATE_TIME_REGEX.exec(value);
if (!m)
return false;
const [
,
y,
mo,
d,
hh = "00",
mm = "00",
ss = "00",
sss = "0",
tzSign,
tzH = "00",
tzM = "00"
] = m;
const year = Number(y);
const month = Number(mo) - 1;
const day = Number(d);
const hour = Number(hh);
const minute = Number(mm);
const sec = Number(ss);
const milli = Number(sss.padEnd(3, "0"));
const offH = Number(tzH);
const offM = Number(tzM);
if (hour > 23 || minute > 59 || sec > 59)
return false;
if (tzSign) {
if (offH > 14)
return false;
if (offM > 59)
return false;
if (offH === 14 && offM !== 0)
return false;
}
let date = new Date(Date.UTC(year, month, day, hour, minute, sec, milli));
if (Number.isNaN(date.getTime()) || date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day || date.getUTCHours() !== hour || date.getUTCMinutes() !== minute || date.getUTCSeconds() !== sec || date.getUTCMilliseconds() !== milli)
return false;
if (tzSign) {
const offsetMin = offH * 60 + offM;
const sign = tzSign === "+" ? -1 : 1;
date = new Date(date.getTime() + sign * offsetMin * 6e4);
}
const hostParsed = new Date(value);
if (Number.isNaN(hostParsed.getTime()))
return false;
return true;
}
// src/parse.ts
function parse({ primaryCursor, cursors = [] }, cursor, decoder2 = decoder, parser2 = parser) {
if (!cursor) {
return null;
}
const keys = [primaryCursor, ...cursors].map((cursor2) => cursor2.key);
const data = parser2(decoder2(cursor));
const item = keys.reduce(
(acc, key) => {
let value = data[key];
if (typeof value === "string" && isValidDateOrDateTimeString(value)) {
value = new Date(value);
}
acc[key] = value;
return acc;
},
{}
);
return item;
}
// src/serialize.ts
function serialize({ primaryCursor, cursors = [] }, data, encoder2 = encoder, serializer2 = serializer) {
if (!data) {
return null;
}
const keys = [primaryCursor, ...cursors].map((cursor) => cursor.key);
const item = keys.reduce(
(acc, key) => {
let value = data[key];
if (typeof value === "string" && isValidDateOrDateTimeString(value)) {
value = new Date(value).toISOString();
}
if (value instanceof Date) {
value = value.toISOString();
}
acc[key] = value;
return acc;
},
{}
);
return encoder2(serializer2(item));
}
// src/generateCursor.ts
var generateCursor = (config, options) => {
const { cursors = [], primaryCursor } = config;
const {
decoder: decoder2 = decoder,
encoder: encoder2 = encoder,
parser: parser2 = parser,
serializer: serializer2 = serializer,
parse: parse2 = parse,
serialize: serialize2 = serialize
} = options != null ? options : {};
const orderBy = [];
for (const { order = "ASC", schema } of [...cursors, primaryCursor]) {
const fn = order === "ASC" ? import_drizzle_orm.asc : import_drizzle_orm.desc;
const sql = fn(schema);
orderBy.push(sql);
}
return {
orderBy,
where: (lastPreviousItemData) => {
if (!lastPreviousItemData) {
return void 0;
}
const data = typeof lastPreviousItemData === "string" ? parse2(config, lastPreviousItemData, decoder2, parser2) : lastPreviousItemData;
if (!data) {
return void 0;
}
const matrix = generateSubArrays([...cursors, primaryCursor]);
const ors = [];
for (const posibilities of matrix) {
const ands = [];
for (const cursor of posibilities) {
const lastValue = cursor === (posibilities == null ? void 0 : posibilities.at(-1));
const { order = "ASC", schema, key } = cursor;
const fn = order === "ASC" ? import_drizzle_orm.gt : import_drizzle_orm.lt;
const sql = !lastValue ? (0, import_drizzle_orm.eq)(schema, data[key]) : fn(schema, data[key]);
ands.push(sql);
}
const _and = (0, import_drizzle_orm.and)(...ands);
if (!_and) {
continue;
}
ors.push(_and);
}
const where = (0, import_drizzle_orm.or)(...ors);
return where;
},
parse: (cursor) => parse2(config, cursor, decoder2, parser2),
serialize: (data) => serialize2(config, data, encoder2, serializer2)
};
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
decoder,
encoder,
generateCursor,
parse,
parser,
serialize,
serializer
});