UNPKG

fraci

Version:

Fractional indexing that's robust, performant, and secure, with first-class support for Drizzle ORM and Prisma ORM.

784 lines (771 loc) 17.7 kB
"use strict"; var v = Object.defineProperty; var Bn = Object.getOwnPropertyDescriptor; var Pn = Object.getOwnPropertyNames; var wn = Object.prototype.hasOwnProperty; var Tn = (n, e) => { for (var r in e) v(n, r, { get: e[r], enumerable: !0 }); }, bn = (n, e, r, t) => { if (e && typeof e == "object" || typeof e == "function") for (let i of Pn(e)) !wn.call(n, i) && i !== r && v(n, i, { get: () => e[i], enumerable: !(t = Bn(e, i)) || t.enumerable }); return n; }; var Nn = (n) => bn(v({}, "__esModule", { value: !0 }), n); // src/prisma.ts var Ln = {}; Tn(Ln, { definePrismaFraci: () => On, prismaFraci: () => Sn }); module.exports = Nn(Ln); // src/prisma/extension.ts var Mn = require("@prisma/client/extension.js"); // src/lib/decimal-binary.ts var H = new Uint8Array([128, 0]), Rn = new Uint8Array([127, 255]); function w(n, e) { let r = Math.min(n.length, e.length), t = 0; for (let i = 0; !t && i < r; i++) t = n[i] - e[i]; return t || n.length - e.length; } function C(n, e) { let r = new Uint8Array(n.length + e.length); return r.set(n), r.set(e, n.length), r; } function q(n) { let [e] = n; return e - (e >= 128 ? 127 : 128); } function on(n) { return n + (n < 0 ? 128 : 127); } function S(n) { return n.length === 129 && n.every((e) => e === 0); } function T(n) { let e = Math.abs(q(n)) + 1; if (!(Number.isNaN(e) || n.length < e)) return [n.subarray(0, e), n.subarray(e)]; } function z(n) { if (!n.length) return; let e = q(n), r = n.slice(0, Math.abs(e) + 1); for (let o = r.length - 1; o >= 1; o--) if (r[o]++ < 255) return r; if (e === -1) return H.slice(); let t = e + 1; if (t > 128) return null; let i = new Uint8Array(Math.abs(t) + 1); return i[0] = on(t), i; } function an(n) { let e = q(n); if (Number.isNaN(e)) return; let r = n.slice(0, Math.abs(e) + 1); for (let o = r.length - 1; o >= 1; o--) if (r[o]--) return r; if (e === 1) return Rn.slice(); let t = e - 1; if (t < -128) return null; let i = new Uint8Array(Math.abs(t) + 1).fill(255); return i[0] = on(t), i; } function M(n, e) { if (e != null && w(n, e) >= 0) return; if (e) { let a = e.findIndex((s, l) => s !== (n[l] ?? 0)); if (a > 0) { let s = M( n.subarray(a), e.subarray(a) ); return s ? C(e.subarray(0, a), s) : void 0; } } let r = n[0] ?? 0, t = e ? e[0] : 256; if (t == null) return; if (r + 1 !== t) { let a = r + t >> 1; return new Uint8Array([a]); } if (e && e.length > 1) return new Uint8Array([e[0]]); let i = M(n.subarray(1), null); if (!i) return; let o = new Uint8Array(1 + i.length); return o[0] = r, o.set(i, 1), o; } // src/lib/decimal-string.ts function J(n, e) { return e.get(n[0]); } function b(n, e) { let r = Math.abs(J(n, e) ?? 0) + 1; if (!(r < 2 || n.length < r)) return [n.slice(0, r), n.slice(r)]; } function sn(n, e) { return e.get(1) + n[0]; } function ln(n, e) { let r = Math.min(...Array.from(e.keys())); return `${e.get(r)}${n[0].repeat(Math.abs(r))}`; } function Y(n, e, r, t, i) { let o = J(n, i); if (!o) return; let a = e[0], [s, ...l] = n.slice(0, Math.abs(o) + 1); for (let d = l.length - 1; d >= 0; d--) { let y = r.get(l[d]); if (y == null) return; if (y < e.length - 1) return l[d] = e[y + 1], `${s}${l.join("")}`; l[d] = a; } if (o === -1) return `${t.get(1)}${a}`; let c = o + 1, u = t.get(c); return u ? `${u}${a.repeat(Math.abs(c))}` : null; } function cn(n, e, r, t, i) { let o = J(n, i); if (!o) return; let a = e[e.length - 1], [s, ...l] = n.slice(0, Math.abs(o) + 1); for (let d = l.length - 1; d >= 0; d--) { let y = r.get(l[d]); if (y == null) return; if (y > 0) return l[d] = e[y - 1], `${s}${l.join("")}`; l[d] = a; } if (o === 1) return `${t.get(-1)}${a}`; let c = o - 1, u = t.get(c); return u ? `${u}${a.repeat(Math.abs(c))}` : null; } function O(n, e, r, t) { if (e != null && e <= n) return; if (e) { let a = n.padEnd(e.length, r[0]), s = Array.prototype.findIndex.call( e, (l, c) => l !== a[c] ); if (s > 0) return `${e.slice(0, s)}${O( n.slice(s), e.slice(s), r, t )}`; } let i = n ? t.get(n[0]) : 0, o = e ? t.get(e[0]) : r.length; if (!(i == null || o == null)) { if (i + 1 !== o) { let a = i + o >> 1; return r[a]; } return e && e.length > 1 ? e[0] : `${r[i]}${O( n.slice(1), null, r, t )}`; } } // src/lib/errors.ts var f = class extends Error { constructor(r, t) { super(`[${r}] ${t}`); this.code = r; this.message = t; this.name = "FraciError"; } name; }; // src/lib/fractional-indexing-binary.ts function L(n) { return n?.constructor.name === "Buffer" ? new Uint8Array(n.buffer, n.byteOffset, n.length) : n; } function $(n) { if (!n.length || S(n)) return !1; let e = T(n); if (!e) return !1; let [, r] = e; return r?.at(-1) !== 0; } function E(n) { if (n === void 0) throw console.error( "FraciError: [INTERNAL_ERROR] Unexpected undefined. Please file an issue to report this error." ), new f("INTERNAL_ERROR", "Unexpected undefined"); return n; } function N(n, e) { if (!n) { if (!e) return H.slice(); let [s, l] = E(T(e)); if (S(s)) return C( s, E(M(new Uint8Array(), l)) ); if (l.length) return s.slice(); let c = E( an(s) ); if (!S(c)) return c; let u = new Uint8Array(c.length + 1); return u.set(c), u[c.length] = 255, u; } if (!e) { let s = E(T(n)), [l, c] = s, u = E(z(l)); return u || C(l, E(M(c, null))); } let [r, t] = E(T(n)), [i, o] = E(T(e)); if (!w(r, i)) return C( r, E(M(t, o)) ); let a = E(z(r)); return a && w(a, i) ? ( // 1. If incrementing a's integer doesn't reach b's integer, // we can use the incremented value (shorter key) a ) : ( // 2. If incrementing a's integer equals b's integer or we can't increment, // we need to use a's integer with a fractional part that sorts after a's fractional part C(r, E(M(t, null))) ); } function dn(n, e) { return n != null && !$(n) || e != null && !$(e) || n != null && e != null && w(n, e) >= 0 ? void 0 : N(L(n), L(e)); } function nn(n, e, r) { if (r < 1) return []; if (r === 1) return [N(n, e)]; if (e == null) { let o = n; return Array.from( { length: r }, () => o = N(o, e) ); } if (n == null) { let o = e; return Array.from( { length: r }, () => o = N(n, o) ).reverse(); } let t = r >> 1, i = N(n, e); return [ ...nn(n, i, t), i, ...nn(i, e, r - t - 1) ]; } function un(n, e, r) { return n != null && !$(n) || e != null && !$(e) || n != null && e != null && w(n, e) >= 0 ? void 0 : nn(L(n), L(e), r); } function en(n) { let e = []; for (; n > 0; ) e.push(n & 255), n >>= 8; return new Uint8Array(e); } // src/lib/fractional-indexing-string.ts function D(n, e, r, t, i) { if (!n || n === i) return !1; let o = b(n, t); if (!o) return !1; let [a, s] = o; if (s.endsWith(e[0])) return !1; for (let l of a.slice(1)) if (!r.has(l)) return !1; for (let l of s) if (!r.has(l)) return !1; return !0; } function I(n) { if (n === void 0) throw console.error( "FraciError: [INTERNAL_ERROR] Unexpected undefined. Please file an issue to report this error." ), new f("INTERNAL_ERROR", "Unexpected undefined"); return n; } function R(n, e, r, t, i, o, a) { if (!n) { if (!e) return sn(r, i); let [p, F] = I(b(e, o)); if (p === a) return `${p}${I( O("", F, r, t) )}`; if (F) return p; let g = I( cn( p, r, t, i, o ) ); return g === a ? `${g}${r[r.length - 1]}` : g; } if (!e) { let p = I(b(n, o)), [F, g] = p, x = I( Y( F, r, t, i, o ) ); return x !== null ? x : `${F}${I( O(g, null, r, t) )}`; } let s = I(b(n, o)), l = I(b(e, o)), [c, u] = s, [d, y] = l; if (c === d) return `${c}${I( O(u, y, r, t) )}`; let h = I( Y( c, r, t, i, o ) ); return h !== null && h !== d ? ( // 1. If incrementing a's integer doesn't reach b's integer, // we can use the incremented value (shorter key) h ) : ( // 2. If incrementing a's integer equals b's integer or we can't increment, // we need to use a's integer with a fractional part that sorts after a's fractional part `${c}${I( O(u, null, r, t) )}` ); } function fn(n, e, r, t, i, o, a) { return n != null && !D( n, r, t, o, a ) || e != null && !D( e, r, t, o, a ) || n != null && e != null && e <= n ? void 0 : R( n, e, r, t, i, o, a ); } function rn(n, e, r, ...t) { if (r < 1) return []; if (r === 1) return [R(n, e, ...t)]; if (e == null) { let a = n; return Array.from( { length: r }, () => a = R(a, e, ...t) ); } if (n == null) { let a = e; return Array.from( { length: r }, () => a = R(n, a, ...t) ).reverse(); } let i = r >> 1, o = R(n, e, ...t); return [ ...rn(n, o, i, ...t), o, ...rn(o, e, r - i - 1, ...t) ]; } function yn(n, e, r, t, i, o, a, s) { return n != null && !D( n, t, i, a, s ) || e != null && !D( e, t, i, a, s ) || n != null && e != null && e <= n ? void 0 : rn( n, e, r, t, i, o, a, s ); } function tn(n, e) { let r = e.length, t = ""; for (; n > 0; ) t += e[n % r], n = Math.floor(n / r); return t; } // src/lib/utils.ts var pn = "INITIALIZATION_FAILED"; function gn(n) { let e = n.split(""); if (e.length < 4) throw new f( pn, "Base string must have at least 4 unique characters" ); let r = -1; for (let t of e) { let i = t.charCodeAt(0); if (i <= r) throw new f( pn, "Base string characters must be unique and in ascending order" ); r = i; } return e; } function mn(n) { let e = gn(n); return [e, new Map(e.map((r, t) => [r, t]))]; } function Fn(n) { let e = gn(n), r = e.length >> 1, t = e.map( (i, o) => [ o < r ? ( // For characters in the first half, assign negative values starting from -1 o - r ) : ( // For characters in the second half, assign positive values starting from 1 o - r + 1 ), // This maps to 1, 2, 3, etc. (skipping 0) i ] ); return [ new Map(t), new Map(t.map(([i, o]) => [o, i])) ]; } // src/factory.ts var j = 50, W = 5, X = "INVALID_FRACTIONAL_INDEX", U = "Invalid indices provided", K = "MAX_LENGTH_EXCEEDED", k = "Exceeded maximum length", G = "MAX_RETRIES_EXCEEDED", Q = "Exceeded maximum retries"; function En() { return /* @__PURE__ */ new Map(); } function hn(n, e, r) { if (!n) return r(); let t = n.get(e); return t === void 0 && (t = r(), n.set(e, t)), t; } function V(n, e, r) { console.error( `FraciError: [INVALID_FRACTIONAL_INDEX] ${U}. a = ${n}, b = ${e}, skip = ${r} Make sure that - Fractional indices generated by the same fraci instance with the same configuration are being used as-is - Indices in different groups have not been mixed up - a (the first argument item) comes before b (the second argument item) in the group File an issue if you use the library correctly and still encounter this error.` ); } function In({ maxLength: n = j, maxRetries: e = W } = {}) { return { base: { type: "binary" }, *generateKeyBetween(r, t, i = 0) { let o = dn(r, t); if (!o) throw V(r, t, i), new f( X, U ); for (let a = 0; a < e; a++) { let s = C(o, en(a + i)); if (s.length > n) throw new f( K, k ); yield s; } throw new f( G, Q ); }, *generateNKeysBetween(r, t, i, o = 0) { let a = un(r, t, i); if (!a) throw V(r, t, o), new f( X, U ); let s = a.reduce((l, c) => Math.max(l, c.length), 0); for (let l = 0; l < e; l++) { let c = en(l + o); if (s + c.length > n) throw new f( K, k ); yield a.map((u) => C(u, c)); } throw new f( G, Q ); } }; } function An({ lengthBase: n, digitBase: e, maxLength: r = j, maxRetries: t = W }, i) { let [o, a] = hn( i, `L${n}`, Fn.bind(null, n) ), [s, l] = hn( i, `D${e}`, mn.bind(null, e) ), c = ln(s, o); return { base: { type: "string", lengthBase: n, digitBase: e }, *generateKeyBetween(u, d, y = 0) { let h = fn( u, d, s, l, o, a, c ); if (!h) throw V(u, d, y), new f( X, U ); for (let p = 0; p < t; p++) { let F = `${h}${tn(p + y, s)}`; if (F.length > r) throw new f( K, k ); yield F; } throw new f( G, Q ); }, *generateNKeysBetween(u, d, y, h = 0) { let p = yn( u, d, y, s, l, o, a, c ); if (!p) throw V(u, d, h), new f( X, U ); let F = p.reduce((g, x) => Math.max(g, x.length), 0); for (let g = 0; g < t; g++) { let x = tn(g + h, s); if (F + x.length > r) throw new f( K, k ); yield p.map((m) => `${m}${x}`); } throw new f( G, Q ); } }; } // src/prisma/common.ts var Un = "P2002"; function xn(n, e, r) { return n instanceof Error && n.name === "PrismaClientKnownRequestError" && n.code === Un && // P2002 is the Prisma code for unique constraint violations n.meta?.modelName === e && // Check if the error is for the correct model Array.isArray(n.meta?.target) && // Check if the target field is specified n.meta.target.includes(r); } // src/prisma/constants.ts var Cn = "fraci"; // src/prisma/extension.ts function Sn(n, { fields: e, maxLength: r = j, maxRetries: t = W }) { return Mn.Prisma.defineExtension((i) => { let o = En(), a = /* @__PURE__ */ new Map(); for (let [l, c] of Object.entries(e)) { let [u, d] = l.split(".", 2), { modelName: y } = i[u]?.fields?.[d] ?? {}; if (!y) throw console.error(`FraciError: [INITIALIZATION_FAILED] Could not get field information for ${u}.${d}. Make sure that - The model and field names are correct and exist in the Prisma schema - The Prisma client is generated with the correct schema - The Prisma version is compatible with the extension`), new f( "INITIALIZATION_FAILED", `Could not get field information for ${u}.${d}` ); let h = c.type === "binary" ? In({ maxLength: r, maxRetries: t }) : An( { ...c, maxLength: r, maxRetries: t }, o ), p = async (m, A, _, B, P = i) => { if (!A) { let _n = await P[u].findFirst({ where: m, // Filter by group conditions select: { [d]: !0 }, // Only select the fractional index field orderBy: { [d]: _ } // Order by the fractional index in appropriate direction }); return B(null, _n?.[d] ?? null); } let Z = await P[u].findMany({ cursor: A, // Start from the cursor position where: m, // Filter by group conditions select: { [d]: !0 }, // Only select the fractional index field orderBy: { [d]: _ }, // Order by the fractional index in appropriate direction take: 2 // Get the cursor item and the adjacent item }); return Z.length < 1 ? ( // Return undefined if cursor not found void 0 ) : ( // Return the indices in the appropriate order based on direction B(Z[0][d], Z[1]?.[d] ?? null) ); }, F = (m, A, _) => p(m, A, "asc", (B, P) => [B, P], _), g = (m, A, _) => p(m, A, "desc", (B, P) => [P, B], _), x = { ...h, // Include all methods from the base fraci helper isIndexConflictError: (m) => xn(m, y, d), indicesForAfter: F, indicesForBefore: g, indicesForFirst: (m, A) => F(m, null, A), indicesForLast: (m, A) => g(m, null, A) }; a.set(`${u}\0${d}`, x); } let s = /* @__PURE__ */ Object.create(null); for (let l of Object.keys(i)) l.startsWith("$") || l.startsWith("_") || (s[l] = { // This method retrieves the appropriate helper for the specified field fraci(c) { return a.get(`${l}\0${c}`); } }); return i.$extends({ name: Cn, model: s }); }); } // src/prisma/schema.ts function On(n, e) { return e; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { definePrismaFraci, prismaFraci }); //# sourceMappingURL=prisma.cjs.map