UNPKG

drizzle-cursor

Version:

Utils for Drizzle ORM cursor based pagination

208 lines (201 loc) 6.41 kB
"use strict"; 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 });