fraci
Version:
Fractional indexing that's robust, performant, and secure, with first-class support for Drizzle ORM and Prisma ORM.
766 lines (753 loc) • 16.6 kB
JavaScript
;
var W = Object.defineProperty;
var _n = Object.getOwnPropertyDescriptor;
var Bn = Object.getOwnPropertyNames;
var Pn = Object.prototype.hasOwnProperty;
var bn = (n, e) => {
for (var r in e)
W(n, r, { get: e[r], enumerable: !0 });
}, wn = (n, e, r, t) => {
if (e && typeof e == "object" || typeof e == "function")
for (let i of Bn(e))
!Pn.call(n, i) && i !== r && W(n, i, { get: () => e[i], enumerable: !(t = _n(e, i)) || t.enumerable });
return n;
};
var Tn = (n) => wn(W({}, "__esModule", { value: !0 }), n);
// src/prisma.ts
var Sn = {};
bn(Sn, {
definePrismaFraci: () => Mn,
prismaFraci: () => Un
});
module.exports = Tn(Sn);
// src/prisma/extension.ts
var Cn = require("@prisma/client/extension.js");
// src/lib/decimal-binary.ts
var Z = new Uint8Array([128, 0]), Nn = new Uint8Array([127, 255]);
function b(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 H(n) {
let [e] = n;
return e - (e >= 128 ? 127 : 128);
}
function tn(n) {
return n + (n < 0 ? 128 : 127);
}
function U(n) {
return n.length === 129 && n.every((e) => e === 0);
}
function w(n) {
let e = Math.abs(H(n)) + 1;
if (!(Number.isNaN(e) || n.length < e))
return [n.subarray(0, e), n.subarray(e)];
}
function q(n) {
if (!n.length)
return;
let e = H(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 Z.slice();
let t = e + 1;
if (t > 128)
return null;
let i = new Uint8Array(Math.abs(t) + 1);
return i[0] = tn(t), i;
}
function on(n) {
let e = H(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 Nn.slice();
let t = e - 1;
if (t < -128)
return null;
let i = new Uint8Array(Math.abs(t) + 1).fill(255);
return i[0] = tn(t), i;
}
function M(n, e) {
if (e != null && b(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 z(n, e) {
return e.get(n[0]);
}
function T(n, e) {
let r = Math.abs(z(n, e) ?? 0) + 1;
if (!(r < 2 || n.length < r))
return [n.slice(0, r), n.slice(r)];
}
function an(n, e) {
return e.get(1) + n[0];
}
function sn(n, e) {
let r = Math.min(...Array.from(e.keys()));
return `${e.get(r)}${n[0].repeat(Math.abs(r))}`;
}
function J(n, e, r, t, i) {
let o = z(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 p = r.get(l[d]);
if (p == null)
return;
if (p < e.length - 1)
return l[d] = e[p + 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 ln(n, e, r, t, i) {
let o = z(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 p = r.get(l[d]);
if (p == null)
return;
if (p > 0)
return l[d] = e[p - 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 S(n) {
return n?.constructor.name === "Buffer" ? new Uint8Array(n.buffer, n.byteOffset, n.length) : n;
}
function L(n) {
if (!n.length || U(n))
return !1;
let e = w(n);
if (!e)
return !1;
let [, r] = e;
return r?.at(-1) !== 0;
}
function E(n) {
if (n === void 0)
throw new f("INTERNAL_ERROR", "Unexpected undefined");
return n;
}
function N(n, e) {
if (!n) {
if (!e)
return Z.slice();
let [s, l] = E(w(e));
if (U(s))
return C(
s,
E(M(new Uint8Array(), l))
);
if (l.length)
return s.slice();
let c = E(
on(s)
);
if (!U(c))
return c;
let u = new Uint8Array(c.length + 1);
return u.set(c), u[c.length] = 255, u;
}
if (!e) {
let s = E(w(n)), [l, c] = s, u = E(q(l));
return u || C(l, E(M(c, null)));
}
let [r, t] = E(w(n)), [i, o] = E(w(e));
if (!b(r, i))
return C(
r,
E(M(t, o))
);
let a = E(q(r));
return a && b(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 cn(n, e) {
return n != null && !L(n) || e != null && !L(e) || n != null && e != null && b(n, e) >= 0 ? void 0 : N(S(n), S(e));
}
function Y(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 [
...Y(n, i, t),
i,
...Y(i, e, r - t - 1)
];
}
function dn(n, e, r) {
return n != null && !L(n) || e != null && !L(e) || n != null && e != null && b(n, e) >= 0 ? void 0 : Y(S(n), S(e), r);
}
function nn(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 = T(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 h(n) {
if (n === void 0)
throw new f("INTERNAL_ERROR", "Unexpected undefined");
return n;
}
function R(n, e, r, t, i, o, a) {
if (!n) {
if (!e)
return an(r, i);
let [y, F] = h(T(e, o));
if (y === a)
return `${y}${h(
O("", F, r, t)
)}`;
if (F)
return y;
let g = h(
ln(
y,
r,
t,
i,
o
)
);
return g === a ? `${g}${r[r.length - 1]}` : g;
}
if (!e) {
let y = h(T(n, o)), [F, g] = y, x = h(
J(
F,
r,
t,
i,
o
)
);
return x !== null ? x : `${F}${h(
O(g, null, r, t)
)}`;
}
let s = h(T(n, o)), l = h(T(e, o)), [c, u] = s, [d, p] = l;
if (c === d)
return `${c}${h(
O(u, p, r, t)
)}`;
let I = h(
J(
c,
r,
t,
i,
o
)
);
return I !== null && I !== d ? (
// 1. If incrementing a's integer doesn't reach b's integer,
// we can use the incremented value (shorter key)
I
) : (
// 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}${h(
O(u, null, r, t)
)}`
);
}
function un(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 en(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 [
...en(n, o, i, ...t),
o,
...en(o, e, r - i - 1, ...t)
];
}
function fn(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 : en(
n,
e,
r,
t,
i,
o,
a,
s
);
}
function rn(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 yn = "INITIALIZATION_FAILED";
function pn(n) {
let e = n.split("");
if (e.length < 4)
throw new f(
yn,
"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(
yn,
"Base string characters must be unique and in ascending order"
);
r = i;
}
return e;
}
function gn(n) {
let e = pn(n);
return [e, new Map(e.map((r, t) => [r, t]))];
}
function mn(n) {
let e = pn(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 V = 50, j = 5, $ = "INVALID_FRACTIONAL_INDEX", X = "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 Fn(n, e, r) {
if (!n)
return r();
let t = n.get(e);
return t === void 0 && (t = r(), n.set(e, t)), t;
}
function hn({
maxLength: n = V,
maxRetries: e = j
} = {}) {
return {
base: { type: "binary" },
*generateKeyBetween(r, t, i = 0) {
let o = cn(r, t);
if (!o)
throw new f(
$,
X
);
for (let a = 0; a < e; a++) {
let s = C(o, nn(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 = dn(r, t, i);
if (!a)
throw new f(
$,
X
);
let s = a.reduce((l, c) => Math.max(l, c.length), 0);
for (let l = 0; l < e; l++) {
let c = nn(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 In({
lengthBase: n,
digitBase: e,
maxLength: r = V,
maxRetries: t = j
}, i) {
let [o, a] = Fn(
i,
`L${n}`,
mn.bind(null, n)
), [s, l] = Fn(
i,
`D${e}`,
gn.bind(null, e)
), c = sn(s, o);
return {
base: {
type: "string",
lengthBase: n,
digitBase: e
},
*generateKeyBetween(u, d, p = 0) {
let I = un(
u,
d,
s,
l,
o,
a,
c
);
if (!I)
throw new f(
$,
X
);
for (let y = 0; y < t; y++) {
let F = `${I}${rn(y + p, s)}`;
if (F.length > r)
throw new f(
k,
K
);
yield F;
}
throw new f(
G,
Q
);
},
*generateNKeysBetween(u, d, p, I = 0) {
let y = fn(
u,
d,
p,
s,
l,
o,
a,
c
);
if (!y)
throw new f(
$,
X
);
let F = y.reduce((g, x) => Math.max(g, x.length), 0);
for (let g = 0; g < t; g++) {
let x = rn(g + I, s);
if (F + x.length > r)
throw new f(
k,
K
);
yield y.map((m) => `${m}${x}`);
}
throw new f(
G,
Q
);
}
};
}
// src/prisma/common.ts
var Rn = "P2002";
function An(n, e, r) {
return n instanceof Error && n.name === "PrismaClientKnownRequestError" && n.code === Rn && // 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 xn = "fraci";
// src/prisma/extension.ts
function Un(n, {
fields: e,
maxLength: r = V,
maxRetries: t = j
}) {
return Cn.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: p } = i[u]?.fields?.[d] ?? {};
if (!p)
throw new f(
"INITIALIZATION_FAILED",
`Could not get field information for ${u}.${d}`
);
let I = c.type === "binary" ? hn({
maxLength: r,
maxRetries: t
}) : In(
{
...c,
maxLength: r,
maxRetries: t
},
o
), y = async (m, A, _, B, P = i) => {
if (!A) {
let On = 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, On?.[d] ?? null);
}
let v = 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 v.length < 1 ? (
// Return undefined if cursor not found
void 0
) : (
// Return the indices in the appropriate order based on direction
B(v[0][d], v[1]?.[d] ?? null)
);
}, F = (m, A, _) => y(m, A, "asc", (B, P) => [B, P], _), g = (m, A, _) => y(m, A, "desc", (B, P) => [P, B], _), x = {
...I,
// Include all methods from the base fraci helper
isIndexConflictError: (m) => An(m, p, 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: xn,
model: s
});
});
}
// src/prisma/schema.ts
function Mn(n, e) {
return e;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
definePrismaFraci,
prismaFraci
});
//# sourceMappingURL=prisma.cjs.map