@querykitjs/prisma-pg 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +363 -0
- package/README.md +362 -0
- package/dist/index.cjs +844 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +494 -0
- package/dist/index.d.ts +494 -0
- package/dist/index.js +837 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,837 @@
|
|
|
1
|
+
import { TEXT_FILTER_OPERATORS, QueryKitError, DEFAULT_MAX_LIMIT, DEFAULT_MAX_PER_PAGE, DEFAULT_LIMIT, DEFAULT_PER_PAGE, createFilters as createFilters$1 } from '@querykitjs/core';
|
|
2
|
+
export { f } from '@querykitjs/core';
|
|
3
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
4
|
+
|
|
5
|
+
// src/registry.ts
|
|
6
|
+
|
|
7
|
+
// src/internal/fields.ts
|
|
8
|
+
function isDelegate(value) {
|
|
9
|
+
if (typeof value !== "object" || value === null) return false;
|
|
10
|
+
const d = value;
|
|
11
|
+
return typeof d.findMany === "function" && typeof d.findFirst === "function" && typeof d.count === "function";
|
|
12
|
+
}
|
|
13
|
+
function delegateKeys(client) {
|
|
14
|
+
return Object.keys(client).filter((key) => !key.startsWith("$") && !key.startsWith("_") && key !== "constructor" && isDelegate(client[key]));
|
|
15
|
+
}
|
|
16
|
+
var uncapitalize = (name) => name ? name[0].toLowerCase() + name.slice(1) : name;
|
|
17
|
+
var KINDS = /* @__PURE__ */ new Set(["scalar", "enum", "object", "unsupported"]);
|
|
18
|
+
var normalizeKind = (kind) => typeof kind === "string" && KINDS.has(kind) ? kind : "scalar";
|
|
19
|
+
function fromRuntimeDataModel(client, delegateKey) {
|
|
20
|
+
const rdm = client._runtimeDataModel;
|
|
21
|
+
const models = rdm?.models;
|
|
22
|
+
if (!models || typeof models !== "object") return void 0;
|
|
23
|
+
const modelName = Object.keys(models).find((name) => uncapitalize(name) === delegateKey);
|
|
24
|
+
if (!modelName) return void 0;
|
|
25
|
+
const raw = models[modelName]?.fields;
|
|
26
|
+
if (!Array.isArray(raw)) return void 0;
|
|
27
|
+
const fields = [];
|
|
28
|
+
for (const field of raw) {
|
|
29
|
+
if (typeof field?.name !== "string") continue;
|
|
30
|
+
fields.push({
|
|
31
|
+
name: field.name,
|
|
32
|
+
type: typeof field.type === "string" ? field.type : "",
|
|
33
|
+
kind: normalizeKind(field.kind),
|
|
34
|
+
isId: field.isId === true,
|
|
35
|
+
isUpdatedAt: field.isUpdatedAt === true,
|
|
36
|
+
isList: field.isList === true,
|
|
37
|
+
...typeof field.dbName === "string" && field.dbName ? { dbName: field.dbName } : {}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return fields.length ? { name: modelName, fields, primaryKey: models[modelName]?.primaryKey ?? null } : void 0;
|
|
41
|
+
}
|
|
42
|
+
function fromDelegateFields(delegate, delegateKey) {
|
|
43
|
+
const refs = delegate?.fields;
|
|
44
|
+
if (!refs || typeof refs !== "object") return void 0;
|
|
45
|
+
const fields = [];
|
|
46
|
+
let modelName;
|
|
47
|
+
for (const ref of Object.values(refs)) {
|
|
48
|
+
const r = ref;
|
|
49
|
+
if (typeof r.name !== "string") continue;
|
|
50
|
+
if (typeof r.modelName === "string") modelName ??= r.modelName;
|
|
51
|
+
fields.push({
|
|
52
|
+
name: r.name,
|
|
53
|
+
type: typeof r.typeName === "string" ? r.typeName : "",
|
|
54
|
+
kind: r.isEnum === true ? "enum" : "scalar",
|
|
55
|
+
isId: r.name === "id",
|
|
56
|
+
isUpdatedAt: false,
|
|
57
|
+
isList: r.isList === true
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return fields.length ? { name: modelName ?? delegateKey, fields } : void 0;
|
|
61
|
+
}
|
|
62
|
+
function readModelMeta(client, delegateKey, override) {
|
|
63
|
+
const delegate = client[delegateKey];
|
|
64
|
+
if (!isDelegate(delegate)) {
|
|
65
|
+
const available = delegateKeys(client);
|
|
66
|
+
throw new Error(
|
|
67
|
+
`createRegistry: "${delegateKey}" is not a model delegate on this Prisma client. Available models: ${available.join(", ") || "(none)"}. Note the key is camelCase \u2014 model "LegalEntity" is "legalEntity".`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
const discovered = fromRuntimeDataModel(client, delegateKey) ?? fromDelegateFields(delegate, delegateKey);
|
|
71
|
+
const source = override?.length ? { name: discovered?.name ?? delegateKey, fields: [...override] } : discovered;
|
|
72
|
+
if (!source) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`createRegistry: could not read field metadata for model "${delegateKey}". This adapter reads it from the Prisma client at runtime (\`_runtimeDataModel\`, then \`delegate.fields\`); both were unavailable, which usually means an unsupported @prisma/client version (>=5 expected). Pass \`fields\` in the repository options to supply it explicitly.`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
const fields = /* @__PURE__ */ new Map();
|
|
78
|
+
const byDbName = /* @__PURE__ */ new Map();
|
|
79
|
+
for (const field of source.fields) {
|
|
80
|
+
fields.set(field.name, field);
|
|
81
|
+
if (field.dbName && field.dbName !== field.name) byDbName.set(field.dbName, field.name);
|
|
82
|
+
}
|
|
83
|
+
for (const name of fields.keys()) byDbName.delete(name);
|
|
84
|
+
const idField = fields.get("id")?.name ?? [...fields.values()].find((f2) => f2.isId)?.name;
|
|
85
|
+
const updatedAt = fields.get("updatedAt");
|
|
86
|
+
const compositeRaw = source.primaryKey;
|
|
87
|
+
const compositeFields = Array.isArray(compositeRaw?.fields) ? compositeRaw.fields.filter((f2) => typeof f2 === "string") : [];
|
|
88
|
+
const primaryKey = idField ? [idField] : compositeFields.filter((f2) => fields.has(f2));
|
|
89
|
+
const primaryKeyName = idField ? void 0 : (typeof compositeRaw?.name === "string" && compositeRaw.name ? compositeRaw.name : primaryKey.join("_")) || void 0;
|
|
90
|
+
return {
|
|
91
|
+
name: source.name,
|
|
92
|
+
fields,
|
|
93
|
+
byDbName,
|
|
94
|
+
primaryKey,
|
|
95
|
+
primaryKeyName,
|
|
96
|
+
idField,
|
|
97
|
+
hasDeletedAt: fields.has("deletedAt"),
|
|
98
|
+
// Prisma maintains `@updatedAt` itself; stamping it again would be redundant
|
|
99
|
+
// (mongoose does the same dance around schema `timestamps`).
|
|
100
|
+
stampUpdatedAt: updatedAt && !updatedAt.isUpdatedAt ? updatedAt.name : void 0,
|
|
101
|
+
hasCreatedAt: fields.has("createdAt")
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function resolveField(meta, key) {
|
|
105
|
+
if (key === "id") return meta.fields.has("id") ? "id" : meta.idField;
|
|
106
|
+
if (meta.fields.has(key)) return key;
|
|
107
|
+
return meta.byDbName.get(key);
|
|
108
|
+
}
|
|
109
|
+
function fieldMeta(meta, field) {
|
|
110
|
+
return meta.fields.get(field);
|
|
111
|
+
}
|
|
112
|
+
function isDateField(meta, field) {
|
|
113
|
+
return meta.fields.get(field)?.type === "DateTime";
|
|
114
|
+
}
|
|
115
|
+
function isStringField(meta, field) {
|
|
116
|
+
return meta.fields.get(field)?.type === "String";
|
|
117
|
+
}
|
|
118
|
+
function castValue(meta, field, value) {
|
|
119
|
+
if (!isDateField(meta, field)) return value;
|
|
120
|
+
if (value === null || value === void 0 || value instanceof Date) return value;
|
|
121
|
+
if (typeof value !== "string" && typeof value !== "number") return value;
|
|
122
|
+
const date = new Date(value);
|
|
123
|
+
return Number.isNaN(date.getTime()) ? value : date;
|
|
124
|
+
}
|
|
125
|
+
function reportSkip(diag, info) {
|
|
126
|
+
if (!diag) return;
|
|
127
|
+
const full = { ...info, source: diag.source };
|
|
128
|
+
if (diag.strict) throw new QueryKitError(full);
|
|
129
|
+
diag.onSkipped?.(full);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/internal/projection.ts
|
|
133
|
+
function truthyKeys(selection) {
|
|
134
|
+
return Object.entries(selection).filter(([, on]) => on).map(([key]) => key);
|
|
135
|
+
}
|
|
136
|
+
function pickColumns(guard, columns) {
|
|
137
|
+
if (guard.forcedKeys) return guard.forcedKeys;
|
|
138
|
+
const requested = columns ? truthyKeys(columns) : [];
|
|
139
|
+
if (!guard.allowed) return requested.length > 0 ? requested : void 0;
|
|
140
|
+
const intersection = requested.filter((key) => guard.allowed.has(key));
|
|
141
|
+
return intersection.length > 0 ? intersection : [...guard.allowed];
|
|
142
|
+
}
|
|
143
|
+
function buildProjection(meta, guard, columns, withRelations, forceKeys = []) {
|
|
144
|
+
const relations = {};
|
|
145
|
+
if (withRelations) {
|
|
146
|
+
for (const [key, value] of Object.entries(withRelations)) {
|
|
147
|
+
if (value) relations[key] = value;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const hasRelations = Object.keys(relations).length > 0;
|
|
151
|
+
const keys = pickColumns(guard, columns);
|
|
152
|
+
const select = {};
|
|
153
|
+
if (keys) {
|
|
154
|
+
for (const key of [...keys, ...forceKeys]) {
|
|
155
|
+
const field = resolveField(meta, key);
|
|
156
|
+
if (field) select[field] = true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const hasSelect = Object.keys(select).length > 0;
|
|
160
|
+
if (!hasSelect) return hasRelations ? { include: relations } : {};
|
|
161
|
+
if (hasRelations) return { select: { ...select, ...relations } };
|
|
162
|
+
return { select };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/internal/cursor.ts
|
|
166
|
+
function encodeCursor(value) {
|
|
167
|
+
const normalized = value instanceof Date ? value.toISOString() : value;
|
|
168
|
+
const json = JSON.stringify({ v: normalized });
|
|
169
|
+
return Buffer.from(json, "utf8").toString("base64url");
|
|
170
|
+
}
|
|
171
|
+
function decodeCursor(cursor) {
|
|
172
|
+
if (!cursor) return void 0;
|
|
173
|
+
try {
|
|
174
|
+
const json = Buffer.from(cursor, "base64url").toString("utf8");
|
|
175
|
+
const payload = JSON.parse(json);
|
|
176
|
+
return payload.v;
|
|
177
|
+
} catch {
|
|
178
|
+
return void 0;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/internal/order-by.ts
|
|
183
|
+
function normalize(sort) {
|
|
184
|
+
if (!sort) return [];
|
|
185
|
+
return sort.filter((item) => item && item.key).map((item) => ({ key: item.key, direction: item.direction ?? "asc" }));
|
|
186
|
+
}
|
|
187
|
+
function buildOrderBy(meta, sort, diag) {
|
|
188
|
+
const orderBy = [];
|
|
189
|
+
for (const { key, direction } of normalize(sort)) {
|
|
190
|
+
const field = resolveField(meta, key);
|
|
191
|
+
if (field) orderBy.push({ [field]: direction });
|
|
192
|
+
else reportSkip(diag, { site: "sort", key, reason: "unknown-key" });
|
|
193
|
+
}
|
|
194
|
+
if (orderBy.length > 0) return orderBy;
|
|
195
|
+
if (meta.hasCreatedAt) return [{ createdAt: "desc" }];
|
|
196
|
+
return meta.idField ? [{ [meta.idField]: "desc" }] : [];
|
|
197
|
+
}
|
|
198
|
+
var TEXT_OPERATORS = new Set(TEXT_FILTER_OPERATORS);
|
|
199
|
+
var INVALID_VALUE = /* @__PURE__ */ Symbol("querykit.invalid-value");
|
|
200
|
+
var isTextOperator = (operator) => TEXT_OPERATORS.has(operator);
|
|
201
|
+
function castForField(meta, field, value) {
|
|
202
|
+
if (value === null || value === void 0) return value;
|
|
203
|
+
const type = fieldMeta(meta, field)?.type;
|
|
204
|
+
if (type === "DateTime") {
|
|
205
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? INVALID_VALUE : value;
|
|
206
|
+
const cast = castValue(meta, field, value);
|
|
207
|
+
if (cast instanceof Date) return Number.isNaN(cast.getTime()) ? INVALID_VALUE : cast;
|
|
208
|
+
return INVALID_VALUE;
|
|
209
|
+
}
|
|
210
|
+
if (type === "Int" || type === "BigInt") {
|
|
211
|
+
if (typeof value === "number") return Number.isInteger(value) ? value : INVALID_VALUE;
|
|
212
|
+
if (typeof value === "bigint") return value;
|
|
213
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
214
|
+
const n = Number(value);
|
|
215
|
+
return Number.isInteger(n) ? n : INVALID_VALUE;
|
|
216
|
+
}
|
|
217
|
+
return INVALID_VALUE;
|
|
218
|
+
}
|
|
219
|
+
if (type === "Float" || type === "Decimal") {
|
|
220
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : INVALID_VALUE;
|
|
221
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
222
|
+
const n = Number(value);
|
|
223
|
+
return Number.isFinite(n) ? n : INVALID_VALUE;
|
|
224
|
+
}
|
|
225
|
+
return INVALID_VALUE;
|
|
226
|
+
}
|
|
227
|
+
if (type === "Boolean") {
|
|
228
|
+
if (typeof value === "boolean") return value;
|
|
229
|
+
if (value === "true" || value === "1" || value === 1) return true;
|
|
230
|
+
if (value === "false" || value === "0" || value === 0) return false;
|
|
231
|
+
return INVALID_VALUE;
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
}
|
|
235
|
+
function coerceCondition(meta, field, operator, value) {
|
|
236
|
+
if (value === void 0 || TEXT_OPERATORS.has(operator)) return value;
|
|
237
|
+
if (Array.isArray(value)) {
|
|
238
|
+
const items = [];
|
|
239
|
+
for (const item of value) {
|
|
240
|
+
const cast2 = castForField(meta, field, item);
|
|
241
|
+
if (cast2 === INVALID_VALUE) return INVALID_VALUE;
|
|
242
|
+
items.push(cast2);
|
|
243
|
+
}
|
|
244
|
+
return items;
|
|
245
|
+
}
|
|
246
|
+
const cast = castForField(meta, field, value);
|
|
247
|
+
return cast === INVALID_VALUE ? INVALID_VALUE : cast;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/internal/operators.ts
|
|
251
|
+
var isWhereFragment = (value) => typeof value?.buildFor === "function";
|
|
252
|
+
var text = (value) => String(value ?? "");
|
|
253
|
+
var asTuple = (value) => Array.isArray(value) && value.length === 2 ? [value[0], value[1]] : void 0;
|
|
254
|
+
var insensitive = (fragment, ctx) => ctx.isString ? { ...fragment, mode: "insensitive" } : fragment;
|
|
255
|
+
function tokenizeLike(pattern) {
|
|
256
|
+
const tokens = [];
|
|
257
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
258
|
+
const ch = pattern[i];
|
|
259
|
+
if (ch === "\\") {
|
|
260
|
+
const next = pattern[i + 1];
|
|
261
|
+
if (next === void 0) return void 0;
|
|
262
|
+
tokens.push({ kind: "lit", char: next });
|
|
263
|
+
i++;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (ch === "%") tokens.push({ kind: "any", char: "%" });
|
|
267
|
+
else if (ch === "_") tokens.push({ kind: "one", char: "_" });
|
|
268
|
+
else tokens.push({ kind: "lit", char: ch });
|
|
269
|
+
}
|
|
270
|
+
return tokens;
|
|
271
|
+
}
|
|
272
|
+
var renderPattern = (tokens) => tokens.map((t) => t.kind === "lit" && (t.char === "%" || t.char === "_" || t.char === "\\") ? `\\${t.char}` : t.char).join("");
|
|
273
|
+
function parseLikePattern(pattern) {
|
|
274
|
+
const tokens = tokenizeLike(pattern);
|
|
275
|
+
if (!tokens) return void 0;
|
|
276
|
+
let start = 0;
|
|
277
|
+
let end = tokens.length;
|
|
278
|
+
let leading = false;
|
|
279
|
+
let trailing = false;
|
|
280
|
+
while (start < end && tokens[start].kind === "any") {
|
|
281
|
+
leading = true;
|
|
282
|
+
start++;
|
|
283
|
+
}
|
|
284
|
+
while (end > start && tokens[end - 1].kind === "any") {
|
|
285
|
+
trailing = true;
|
|
286
|
+
end--;
|
|
287
|
+
}
|
|
288
|
+
const core = tokens.slice(start, end);
|
|
289
|
+
if (core.some((t) => t.kind !== "lit")) return void 0;
|
|
290
|
+
const value = core.map((t) => t.char).join("");
|
|
291
|
+
const op = leading && trailing ? "contains" : leading ? "endsWith" : trailing ? "startsWith" : "equals";
|
|
292
|
+
if (op !== "equals" && /[%_]/.test(value)) return void 0;
|
|
293
|
+
return { op, value };
|
|
294
|
+
}
|
|
295
|
+
function rawLikePlan(pattern, ctx, caseInsensitive) {
|
|
296
|
+
const tokens = tokenizeLike(pattern);
|
|
297
|
+
if (!tokens) return void 0;
|
|
298
|
+
const mode = (fragment) => caseInsensitive ? insensitive(fragment, ctx) : fragment;
|
|
299
|
+
const raw = renderPattern(tokens);
|
|
300
|
+
return {
|
|
301
|
+
buildFor(field) {
|
|
302
|
+
if (tokens[tokens.length - 1]?.kind === "any") {
|
|
303
|
+
return { [field]: mode({ startsWith: raw.replace(/%$/, "") }) };
|
|
304
|
+
}
|
|
305
|
+
const lastAny = tokens.map((t) => t.kind).lastIndexOf("any");
|
|
306
|
+
if (lastAny >= 0) {
|
|
307
|
+
const tail = renderPattern(tokens.slice(lastAny + 1));
|
|
308
|
+
return { AND: [{ [field]: mode({ startsWith: raw }) }, { [field]: mode({ endsWith: tail }) }] };
|
|
309
|
+
}
|
|
310
|
+
return { AND: [{ [field]: mode({ startsWith: raw }) }, { NOT: { [field]: mode({ startsWith: `${raw}_` }) } }] };
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
var likeFragment = (value, ctx, caseInsensitive) => {
|
|
315
|
+
const pattern = text(value);
|
|
316
|
+
const shape = parseLikePattern(pattern);
|
|
317
|
+
if (shape) {
|
|
318
|
+
const fragment = { [shape.op]: shape.value };
|
|
319
|
+
return caseInsensitive ? insensitive(fragment, ctx) : fragment;
|
|
320
|
+
}
|
|
321
|
+
return rawLikePlan(pattern, ctx, caseInsensitive);
|
|
322
|
+
};
|
|
323
|
+
var operators = {
|
|
324
|
+
"=": (v) => ({ equals: v }),
|
|
325
|
+
eq: (v) => ({ equals: v }),
|
|
326
|
+
"!=": (v) => ({ not: v }),
|
|
327
|
+
ne: (v) => ({ not: v }),
|
|
328
|
+
">": (v) => ({ gt: v }),
|
|
329
|
+
gt: (v) => ({ gt: v }),
|
|
330
|
+
">=": (v) => ({ gte: v }),
|
|
331
|
+
gte: (v) => ({ gte: v }),
|
|
332
|
+
"<": (v) => ({ lt: v }),
|
|
333
|
+
lt: (v) => ({ lt: v }),
|
|
334
|
+
"<=": (v) => ({ lte: v }),
|
|
335
|
+
lte: (v) => ({ lte: v }),
|
|
336
|
+
contains: (v, ctx) => insensitive({ contains: text(v) }, ctx),
|
|
337
|
+
"%_%": (v, ctx) => insensitive({ contains: text(v) }, ctx),
|
|
338
|
+
startsWith: (v, ctx) => insensitive({ startsWith: text(v) }, ctx),
|
|
339
|
+
"%_": (v, ctx) => insensitive({ startsWith: text(v) }, ctx),
|
|
340
|
+
endsWith: (v, ctx) => insensitive({ endsWith: text(v) }, ctx),
|
|
341
|
+
"_%": (v, ctx) => insensitive({ endsWith: text(v) }, ctx),
|
|
342
|
+
like: (v, ctx) => likeFragment(v, ctx, false),
|
|
343
|
+
ilike: (v, ctx) => likeFragment(v, ctx, true),
|
|
344
|
+
notLike: (v, ctx) => {
|
|
345
|
+
const inner = likeFragment(v, ctx, false);
|
|
346
|
+
if (!inner) return void 0;
|
|
347
|
+
if (isWhereFragment(inner)) return { buildFor: (field) => ({ NOT: inner.buildFor(field) }) };
|
|
348
|
+
return { not: inner };
|
|
349
|
+
},
|
|
350
|
+
in: (v) => Array.isArray(v) ? { in: v } : void 0,
|
|
351
|
+
notIn: (v) => Array.isArray(v) ? { notIn: v } : void 0,
|
|
352
|
+
between: (v) => {
|
|
353
|
+
const t = asTuple(v);
|
|
354
|
+
return t ? { gte: t[0], lte: t[1] } : void 0;
|
|
355
|
+
},
|
|
356
|
+
notBetween: (v) => {
|
|
357
|
+
const t = asTuple(v);
|
|
358
|
+
return t ? { not: { gte: t[0], lte: t[1] } } : void 0;
|
|
359
|
+
},
|
|
360
|
+
isNull: () => ({ equals: null }),
|
|
361
|
+
isNotNull: () => ({ not: null })
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
// src/internal/where.ts
|
|
365
|
+
var isObject = (node) => typeof node === "object" && node !== null;
|
|
366
|
+
var isFieldCondition = (node) => isObject(node) && "key" in node && !("and" in node) && !("or" in node) && !("not" in node);
|
|
367
|
+
function combine(kind, parts) {
|
|
368
|
+
const valid = parts.filter((part) => part !== void 0);
|
|
369
|
+
if (valid.length === 0) return void 0;
|
|
370
|
+
if (valid.length === 1) return valid[0];
|
|
371
|
+
return { [kind]: valid };
|
|
372
|
+
}
|
|
373
|
+
function buildCondition(meta, condition, diag) {
|
|
374
|
+
const operator = condition.operation ?? "=";
|
|
375
|
+
const build = operators[operator];
|
|
376
|
+
if (!build) throw new Error(`Unsupported filter operator: "${operator}"`);
|
|
377
|
+
const field = resolveField(meta, condition.key);
|
|
378
|
+
if (!field) {
|
|
379
|
+
reportSkip(diag, { site: "filter", key: condition.key, operation: operator, reason: "unknown-key" });
|
|
380
|
+
return void 0;
|
|
381
|
+
}
|
|
382
|
+
const isString = isStringField(meta, field);
|
|
383
|
+
if (isTextOperator(operator) && !isString) {
|
|
384
|
+
reportSkip(diag, { site: "filter", key: condition.key, operation: operator, reason: "invalid-value" });
|
|
385
|
+
return void 0;
|
|
386
|
+
}
|
|
387
|
+
const value = coerceCondition(meta, field, operator, condition.value);
|
|
388
|
+
if (value === INVALID_VALUE) {
|
|
389
|
+
reportSkip(diag, { site: "filter", key: condition.key, operation: operator, reason: "invalid-value" });
|
|
390
|
+
return void 0;
|
|
391
|
+
}
|
|
392
|
+
const fragment = build(value, { isString });
|
|
393
|
+
if (fragment === void 0) {
|
|
394
|
+
reportSkip(diag, { site: "filter", key: condition.key, operation: operator, reason: "invalid-value" });
|
|
395
|
+
return void 0;
|
|
396
|
+
}
|
|
397
|
+
if (isWhereFragment(fragment)) return fragment.buildFor(field);
|
|
398
|
+
return { [field]: fragment };
|
|
399
|
+
}
|
|
400
|
+
function buildNode(meta, node, diag) {
|
|
401
|
+
if (isFieldCondition(node)) return buildCondition(meta, node, diag);
|
|
402
|
+
if (!isObject(node)) return void 0;
|
|
403
|
+
if ("and" in node) {
|
|
404
|
+
return combine(
|
|
405
|
+
"AND",
|
|
406
|
+
node.and.map((child) => buildNode(meta, child, diag))
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
if ("or" in node) {
|
|
410
|
+
return combine(
|
|
411
|
+
"OR",
|
|
412
|
+
node.or.map((child) => buildNode(meta, child, diag))
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
if ("not" in node) {
|
|
416
|
+
const inner = buildNode(meta, node.not, diag);
|
|
417
|
+
return inner ? { NOT: inner } : void 0;
|
|
418
|
+
}
|
|
419
|
+
return node;
|
|
420
|
+
}
|
|
421
|
+
function buildWhere(meta, filter, diag) {
|
|
422
|
+
if (filter === void 0) return void 0;
|
|
423
|
+
if (Array.isArray(filter)) {
|
|
424
|
+
return combine(
|
|
425
|
+
"AND",
|
|
426
|
+
filter.map((node) => buildNode(meta, node, diag))
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
return buildNode(meta, filter, diag);
|
|
430
|
+
}
|
|
431
|
+
function andWhere(parts) {
|
|
432
|
+
return combine("AND", parts);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/repository.ts
|
|
436
|
+
var CHUNK_SIZE = 1e3;
|
|
437
|
+
var clampPageSize = (requested, fallback, max) => Math.min(max, Math.max(1, Math.trunc(requested ?? fallback)));
|
|
438
|
+
var toArray = (value) => value === void 0 ? [] : Array.isArray(value) ? value : [value];
|
|
439
|
+
function buildRepository(runtime, modelKey, config = {}) {
|
|
440
|
+
const meta = readModelMeta(runtime.baseClient, modelKey, config.fields);
|
|
441
|
+
const delegate = () => runtime.getExecutor()[modelKey];
|
|
442
|
+
const diag = {
|
|
443
|
+
source: meta.name,
|
|
444
|
+
strict: runtime.strict,
|
|
445
|
+
onSkipped: runtime.onSkippedCondition
|
|
446
|
+
};
|
|
447
|
+
const requirePrimaryKey = (method) => {
|
|
448
|
+
if (meta.primaryKey.length === 0) {
|
|
449
|
+
throw new Error(
|
|
450
|
+
`${method}: model "${meta.name}" has no primary key, so a row cannot be addressed individually. Use updateWhere/deleteWhere with an explicit filter instead.`
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
return meta.primaryKey;
|
|
454
|
+
};
|
|
455
|
+
const keySelect = (key) => Object.fromEntries(key.map((field) => [field, true]));
|
|
456
|
+
const uniqueWhere = (key, row) => {
|
|
457
|
+
if (key.length === 1) return { [key[0]]: row[key[0]] };
|
|
458
|
+
return { [meta.primaryKeyName ?? key.join("_")]: Object.fromEntries(key.map((field) => [field, row[field]])) };
|
|
459
|
+
};
|
|
460
|
+
const keyedIn = (key, rows) => {
|
|
461
|
+
if (key.length === 1) return { [key[0]]: { in: rows.map((row) => row[key[0]]) } };
|
|
462
|
+
return { OR: rows.map((row) => Object.fromEntries(key.map((field) => [field, row[field]]))) };
|
|
463
|
+
};
|
|
464
|
+
const scopeConditions = config.scope ? Object.entries(config.scope).map(([key, value]) => ({ key, operation: "=", value })) : [];
|
|
465
|
+
for (const condition of scopeConditions) {
|
|
466
|
+
if (!resolveField(meta, condition.key)) {
|
|
467
|
+
throw new QueryKitError({ source: meta.name, site: "filter", key: condition.key, reason: "unknown-key" });
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const scopeWhere = scopeConditions.length ? buildWhere(meta, scopeConditions) : void 0;
|
|
471
|
+
const composeWhere = (userFilter, withDeleted) => andWhere([buildWhere(meta, userFilter, diag), scopeWhere, meta.hasDeletedAt && !withDeleted ? { deletedAt: null } : void 0]);
|
|
472
|
+
const withId = (filter, idKey, id) => {
|
|
473
|
+
if (!resolveField(meta, idKey)) {
|
|
474
|
+
throw new QueryKitError({ source: meta.name, site: "filter", key: idKey, reason: "unknown-key" });
|
|
475
|
+
}
|
|
476
|
+
const idCondition = { key: idKey, operation: "=", value: id };
|
|
477
|
+
if (!filter) return [idCondition];
|
|
478
|
+
if (Array.isArray(filter)) return [...filter, idCondition];
|
|
479
|
+
return { and: [filter, idCondition] };
|
|
480
|
+
};
|
|
481
|
+
const forcedKeys = config.forcedColumns ? truthyKeys(config.forcedColumns) : void 0;
|
|
482
|
+
if (config.forcedColumns && forcedKeys.length === 0) {
|
|
483
|
+
throw new Error("buildRepository: forcedColumns must select at least one field (an empty selection would return the full row).");
|
|
484
|
+
}
|
|
485
|
+
const allowed = config.allowedColumns ? new Set(config.allowedColumns) : void 0;
|
|
486
|
+
if (config.allowedColumns && allowed.size === 0) {
|
|
487
|
+
throw new Error("buildRepository: allowedColumns must list at least one field (an empty allowlist would return the full row).");
|
|
488
|
+
}
|
|
489
|
+
const guard = { forcedKeys, allowed };
|
|
490
|
+
const guarded = Boolean(forcedKeys ?? allowed);
|
|
491
|
+
const permits = (key) => forcedKeys ? forcedKeys.includes(key) : allowed ? allowed.has(key) : true;
|
|
492
|
+
const projection = (columns, withRelations, forceKeys) => buildProjection(meta, guard, columns, withRelations, forceKeys);
|
|
493
|
+
const forInsert = (values) => ({
|
|
494
|
+
...config.scope,
|
|
495
|
+
...values,
|
|
496
|
+
...config.scope
|
|
497
|
+
});
|
|
498
|
+
const forUpdate = (patch) => {
|
|
499
|
+
const stamped = { ...patch };
|
|
500
|
+
if (meta.stampUpdatedAt) stamped[meta.stampUpdatedAt] = /* @__PURE__ */ new Date();
|
|
501
|
+
return stamped;
|
|
502
|
+
};
|
|
503
|
+
const countWhere = (where) => delegate().count({ where });
|
|
504
|
+
const upsertWhere = (targets, values) => {
|
|
505
|
+
const fields = targets.map((key) => {
|
|
506
|
+
const field = resolveField(meta, key);
|
|
507
|
+
if (!field) throw new Error(`upsert: unknown target field "${key}".`);
|
|
508
|
+
return field;
|
|
509
|
+
});
|
|
510
|
+
if (fields.length === 1) return { [fields[0]]: values[fields[0]] };
|
|
511
|
+
return { [fields.join("_")]: Object.fromEntries(fields.map((field) => [field, values[field]])) };
|
|
512
|
+
};
|
|
513
|
+
const defaultConflictSet = (values, targetKeys) => {
|
|
514
|
+
const skip = /* @__PURE__ */ new Set([...targetKeys, "createdAt"]);
|
|
515
|
+
const set = {};
|
|
516
|
+
for (const [key, value] of Object.entries(values)) {
|
|
517
|
+
if (!skip.has(key)) set[key] = value;
|
|
518
|
+
}
|
|
519
|
+
return forUpdate(set);
|
|
520
|
+
};
|
|
521
|
+
const repository = {
|
|
522
|
+
get delegate() {
|
|
523
|
+
return delegate();
|
|
524
|
+
},
|
|
525
|
+
async findAll(params = {}) {
|
|
526
|
+
const rows = await delegate().findMany({
|
|
527
|
+
where: composeWhere(params.filter, params.withDeleted),
|
|
528
|
+
orderBy: buildOrderBy(meta, params.sort, diag),
|
|
529
|
+
...projection(params.columns, params.with)
|
|
530
|
+
});
|
|
531
|
+
return rows;
|
|
532
|
+
},
|
|
533
|
+
async findOne(params = {}) {
|
|
534
|
+
const row = await delegate().findFirst({
|
|
535
|
+
where: composeWhere(params.filter, params.withDeleted),
|
|
536
|
+
orderBy: buildOrderBy(meta, params.sort, diag),
|
|
537
|
+
...projection(params.columns, params.with)
|
|
538
|
+
});
|
|
539
|
+
return row ?? void 0;
|
|
540
|
+
},
|
|
541
|
+
async findById(id, params = {}) {
|
|
542
|
+
const { idKey = "id", filter } = params;
|
|
543
|
+
const row = await delegate().findFirst({
|
|
544
|
+
where: composeWhere(withId(filter, idKey, id), params.withDeleted),
|
|
545
|
+
...projection(params.columns, params.with)
|
|
546
|
+
});
|
|
547
|
+
return row ?? void 0;
|
|
548
|
+
},
|
|
549
|
+
async findList(params = {}) {
|
|
550
|
+
const page = Math.max(1, Math.trunc(params.page ?? 1));
|
|
551
|
+
const perPage = clampPageSize(params.perPage, runtime.defaultPerPage, runtime.maxPerPage);
|
|
552
|
+
const where = composeWhere(params.filter, params.withDeleted);
|
|
553
|
+
const [data, total_items] = await Promise.all([
|
|
554
|
+
delegate().findMany({
|
|
555
|
+
where,
|
|
556
|
+
orderBy: buildOrderBy(meta, params.sort, diag),
|
|
557
|
+
take: perPage,
|
|
558
|
+
skip: (page - 1) * perPage,
|
|
559
|
+
...projection(params.columns, params.with)
|
|
560
|
+
}),
|
|
561
|
+
countWhere(where)
|
|
562
|
+
]);
|
|
563
|
+
const total_pages = Math.ceil(total_items / perPage);
|
|
564
|
+
return {
|
|
565
|
+
data,
|
|
566
|
+
meta: {
|
|
567
|
+
total_items,
|
|
568
|
+
total_pages,
|
|
569
|
+
current_page: page,
|
|
570
|
+
per_page: perPage,
|
|
571
|
+
has_next: page < total_pages,
|
|
572
|
+
has_prev: page > 1
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
},
|
|
576
|
+
async findInfinite(params = {}) {
|
|
577
|
+
const limit = clampPageSize(params.limit, runtime.defaultLimit, runtime.maxLimit);
|
|
578
|
+
const offset = Math.max(0, Math.trunc(params.offset ?? 0));
|
|
579
|
+
const rows = await delegate().findMany({
|
|
580
|
+
where: composeWhere(params.filter, params.withDeleted),
|
|
581
|
+
orderBy: buildOrderBy(meta, params.sort, diag),
|
|
582
|
+
take: limit + 1,
|
|
583
|
+
skip: offset,
|
|
584
|
+
...projection(params.columns, params.with)
|
|
585
|
+
});
|
|
586
|
+
const has_more = rows.length > limit;
|
|
587
|
+
const data = has_more ? rows.slice(0, limit) : rows;
|
|
588
|
+
return {
|
|
589
|
+
data,
|
|
590
|
+
meta: { limit, offset, count: data.length, has_more, next_offset: has_more ? offset + limit : null }
|
|
591
|
+
};
|
|
592
|
+
},
|
|
593
|
+
async findCursor(params = {}) {
|
|
594
|
+
const limit = clampPageSize(params.limit, runtime.defaultLimit, runtime.maxLimit);
|
|
595
|
+
const cursorKey = params.cursorKey ?? "id";
|
|
596
|
+
const order = params.order ?? "asc";
|
|
597
|
+
const direction = params.direction ?? "forward";
|
|
598
|
+
const field = resolveField(meta, cursorKey);
|
|
599
|
+
if (!field) throw new QueryKitError({ source: diag.source, site: "cursorKey", key: cursorKey, reason: "unknown-key" });
|
|
600
|
+
const decoded = decodeCursor(params.cursor);
|
|
601
|
+
const cursorValue = decoded === void 0 ? void 0 : castValue(meta, field, decoded);
|
|
602
|
+
const baseWhere = composeWhere(params.filter, params.withDeleted);
|
|
603
|
+
const ascInQuery = direction === "forward" ? order === "asc" : order === "desc";
|
|
604
|
+
const seek = cursorValue !== void 0 ? { [field]: ascInQuery ? { gt: cursorValue } : { lt: cursorValue } } : void 0;
|
|
605
|
+
const where = andWhere([baseWhere, seek]);
|
|
606
|
+
const selected = pickColumns(guard, params.columns);
|
|
607
|
+
const leaksCursorField = guarded && selected !== void 0 && !permits(cursorKey) && !permits(field);
|
|
608
|
+
const rows = await delegate().findMany({
|
|
609
|
+
where,
|
|
610
|
+
orderBy: [{ [field]: ascInQuery ? "asc" : "desc" }],
|
|
611
|
+
take: limit + 1,
|
|
612
|
+
...projection(params.columns, params.with, [field])
|
|
613
|
+
});
|
|
614
|
+
const hasExtra = rows.length > limit;
|
|
615
|
+
let page = hasExtra ? rows.slice(0, limit) : rows;
|
|
616
|
+
if (direction === "backward") page = [...page].reverse();
|
|
617
|
+
const first = page[0];
|
|
618
|
+
const last = page[page.length - 1];
|
|
619
|
+
const has_next = direction === "forward" ? hasExtra : cursorValue !== void 0;
|
|
620
|
+
const has_prev = direction === "forward" ? cursorValue !== void 0 : hasExtra;
|
|
621
|
+
const meta_ = {
|
|
622
|
+
limit,
|
|
623
|
+
has_next,
|
|
624
|
+
has_prev,
|
|
625
|
+
next_cursor: has_next && last ? encodeCursor(last[field]) : null,
|
|
626
|
+
prev_cursor: has_prev && first ? encodeCursor(first[field]) : null
|
|
627
|
+
};
|
|
628
|
+
if (leaksCursorField) {
|
|
629
|
+
page = page.map((row) => {
|
|
630
|
+
const { [field]: _cursor, ...rest } = row;
|
|
631
|
+
return rest;
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
return { data: page, meta: meta_ };
|
|
635
|
+
},
|
|
636
|
+
count(filter) {
|
|
637
|
+
return countWhere(composeWhere(filter));
|
|
638
|
+
},
|
|
639
|
+
async exists(filter) {
|
|
640
|
+
return await countWhere(composeWhere(filter)) > 0;
|
|
641
|
+
},
|
|
642
|
+
/* ------------------------------- writes ------------------------------- */
|
|
643
|
+
async create(values) {
|
|
644
|
+
const row = await delegate().create({ data: forInsert(values) });
|
|
645
|
+
return row;
|
|
646
|
+
},
|
|
647
|
+
async createMany(values) {
|
|
648
|
+
if (values.length === 0) return [];
|
|
649
|
+
const data = values.map((v) => forInsert(v));
|
|
650
|
+
const d = delegate();
|
|
651
|
+
if (typeof d.createManyAndReturn === "function") {
|
|
652
|
+
return await d.createManyAndReturn({ data });
|
|
653
|
+
}
|
|
654
|
+
const out = [];
|
|
655
|
+
for (const item of data) out.push(await d.create({ data: item }));
|
|
656
|
+
return out;
|
|
657
|
+
},
|
|
658
|
+
async upsert(values, options) {
|
|
659
|
+
const targetKeys = toArray(options.target);
|
|
660
|
+
const inserted = forInsert(values);
|
|
661
|
+
const update = options.set ? forUpdate(options.set) : defaultConflictSet(inserted, targetKeys);
|
|
662
|
+
const row = await delegate().upsert({
|
|
663
|
+
where: upsertWhere(targetKeys, inserted),
|
|
664
|
+
create: inserted,
|
|
665
|
+
update
|
|
666
|
+
});
|
|
667
|
+
return row;
|
|
668
|
+
},
|
|
669
|
+
async upsertMany(values, options) {
|
|
670
|
+
if (values.length === 0) return [];
|
|
671
|
+
const targetKeys = toArray(options.target);
|
|
672
|
+
const out = [];
|
|
673
|
+
for (let i = 0; i < values.length; i += CHUNK_SIZE) {
|
|
674
|
+
for (const value of values.slice(i, i + CHUNK_SIZE)) {
|
|
675
|
+
const inserted = forInsert(value);
|
|
676
|
+
const update = options.set ? forUpdate(options.set) : defaultConflictSet(inserted, targetKeys);
|
|
677
|
+
out.push(
|
|
678
|
+
await delegate().upsert({
|
|
679
|
+
where: upsertWhere(targetKeys, inserted),
|
|
680
|
+
create: inserted,
|
|
681
|
+
update
|
|
682
|
+
})
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return out;
|
|
687
|
+
},
|
|
688
|
+
async updateById(id, patch, idKey = "id") {
|
|
689
|
+
return updateOne(composeWhere(withId(void 0, idKey, id)), forUpdate(patch), "updateById");
|
|
690
|
+
},
|
|
691
|
+
async updateWhere(filter, patch) {
|
|
692
|
+
const key = requirePrimaryKey("updateWhere");
|
|
693
|
+
const where = composeWhere(filter);
|
|
694
|
+
const d = delegate();
|
|
695
|
+
const found = await d.findMany({ where, select: keySelect(key) });
|
|
696
|
+
if (found.length === 0) return [];
|
|
697
|
+
const keyed = keyedIn(key, found);
|
|
698
|
+
await d.updateMany({ where: keyed, data: forUpdate(patch) });
|
|
699
|
+
return await d.findMany({ where: keyed });
|
|
700
|
+
},
|
|
701
|
+
async deleteById(id, idKey = "id") {
|
|
702
|
+
const key = requirePrimaryKey("deleteById");
|
|
703
|
+
const d = delegate();
|
|
704
|
+
const target = await d.findFirst({ where: composeWhere(withId(void 0, idKey, id)) });
|
|
705
|
+
if (!target) return void 0;
|
|
706
|
+
return await d.delete({ where: uniqueWhere(key, target) });
|
|
707
|
+
},
|
|
708
|
+
async deleteWhere(filter) {
|
|
709
|
+
const key = requirePrimaryKey("deleteWhere");
|
|
710
|
+
const d = delegate();
|
|
711
|
+
const where = composeWhere(filter);
|
|
712
|
+
const rows = await d.findMany({ where });
|
|
713
|
+
if (rows.length === 0) return [];
|
|
714
|
+
await d.deleteMany({ where: keyedIn(key, rows) });
|
|
715
|
+
return rows;
|
|
716
|
+
},
|
|
717
|
+
async softDelete(id, idKey = "id") {
|
|
718
|
+
if (!meta.hasDeletedAt) throw new Error("softDelete: model has no deletedAt field.");
|
|
719
|
+
return updateOne(composeWhere(withId(void 0, idKey, id), false), forUpdate({ deletedAt: /* @__PURE__ */ new Date() }), "softDelete");
|
|
720
|
+
},
|
|
721
|
+
async restore(id, idKey = "id") {
|
|
722
|
+
if (!meta.hasDeletedAt) throw new Error("restore: model has no deletedAt field.");
|
|
723
|
+
return updateOne(composeWhere(withId(void 0, idKey, id), true), forUpdate({ deletedAt: null }), "restore");
|
|
724
|
+
},
|
|
725
|
+
async aggregate(spec) {
|
|
726
|
+
const aggregable = (key) => {
|
|
727
|
+
const field = permits(key) ? resolveField(meta, key) : void 0;
|
|
728
|
+
if (!field) reportSkip(diag, { site: "aggregate", key, reason: "unknown-key" });
|
|
729
|
+
return field;
|
|
730
|
+
};
|
|
731
|
+
const groupFields = toArray(spec.groupBy).map(aggregable).filter((field) => Boolean(field));
|
|
732
|
+
const selectionFor = (keys) => {
|
|
733
|
+
const picked = {};
|
|
734
|
+
for (const key of keys) {
|
|
735
|
+
const field = aggregable(key);
|
|
736
|
+
if (field) picked[field] = true;
|
|
737
|
+
}
|
|
738
|
+
return Object.keys(picked).length ? picked : void 0;
|
|
739
|
+
};
|
|
740
|
+
const sum = selectionFor(toArray(spec.sum));
|
|
741
|
+
const avg = selectionFor(toArray(spec.avg));
|
|
742
|
+
const min = selectionFor(toArray(spec.min));
|
|
743
|
+
const max = selectionFor(toArray(spec.max));
|
|
744
|
+
const args = { where: composeWhere(spec.filter, spec.withDeleted) };
|
|
745
|
+
if (spec.count) args._count = true;
|
|
746
|
+
if (sum) args._sum = sum;
|
|
747
|
+
if (avg) args._avg = avg;
|
|
748
|
+
if (min) args._min = min;
|
|
749
|
+
if (max) args._max = max;
|
|
750
|
+
const flatten = (row) => {
|
|
751
|
+
const out = {};
|
|
752
|
+
for (const [key, value] of Object.entries(row)) {
|
|
753
|
+
if (!key.startsWith("_")) {
|
|
754
|
+
out[key] = value;
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
if (key === "_count") {
|
|
758
|
+
if (typeof value === "number") out.count = value;
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
const prefix = key.slice(1);
|
|
762
|
+
for (const [field, aggregated] of Object.entries(value ?? {})) {
|
|
763
|
+
if (aggregated !== void 0) out[`${prefix}_${field}`] = aggregated;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
return out;
|
|
767
|
+
};
|
|
768
|
+
if (groupFields.length > 0) {
|
|
769
|
+
const rows = await delegate().groupBy({ ...args, by: groupFields });
|
|
770
|
+
return rows.map(flatten);
|
|
771
|
+
}
|
|
772
|
+
return [flatten(await delegate().aggregate(args))];
|
|
773
|
+
},
|
|
774
|
+
scoped(scope) {
|
|
775
|
+
return buildRepository(runtime, modelKey, { ...config, scope: { ...config.scope, ...scope } });
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
async function updateOne(where, data, method) {
|
|
779
|
+
const key = requirePrimaryKey(method);
|
|
780
|
+
const d = delegate();
|
|
781
|
+
const target = await d.findFirst({ where, select: keySelect(key) });
|
|
782
|
+
if (!target) return void 0;
|
|
783
|
+
return await d.update({ where: uniqueWhere(key, target), data });
|
|
784
|
+
}
|
|
785
|
+
return repository;
|
|
786
|
+
}
|
|
787
|
+
function createContextStore() {
|
|
788
|
+
const als = new AsyncLocalStorage();
|
|
789
|
+
return {
|
|
790
|
+
get: () => als.getStore(),
|
|
791
|
+
run: (patch, fn) => als.run({ ...als.getStore(), ...patch }, fn)
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/registry.ts
|
|
796
|
+
function resolveModelKey(client, model) {
|
|
797
|
+
if (typeof model === "string") return model;
|
|
798
|
+
const keys = delegateKeys(client);
|
|
799
|
+
const found = keys.find((key) => client[key] === model);
|
|
800
|
+
if (!found) {
|
|
801
|
+
throw new Error(
|
|
802
|
+
`createRegistry: the given delegate does not belong to this Prisma client. Pass a model from the same client you passed to createRegistry (available: ${keys.join(", ") || "(none)"}), or use its name, e.g. repository("user").`
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
return found;
|
|
806
|
+
}
|
|
807
|
+
function createRegistry(prisma, options = {}) {
|
|
808
|
+
const ctx = createContextStore();
|
|
809
|
+
const runtime = {
|
|
810
|
+
baseClient: prisma,
|
|
811
|
+
getExecutor: () => ctx.get()?.executor ?? prisma,
|
|
812
|
+
defaultPerPage: options.defaultPerPage ?? DEFAULT_PER_PAGE,
|
|
813
|
+
defaultLimit: options.defaultLimit ?? DEFAULT_LIMIT,
|
|
814
|
+
maxPerPage: options.maxPerPage ?? DEFAULT_MAX_PER_PAGE,
|
|
815
|
+
maxLimit: options.maxLimit ?? DEFAULT_MAX_LIMIT,
|
|
816
|
+
strict: options.strict ?? false,
|
|
817
|
+
onSkippedCondition: options.onSkippedCondition
|
|
818
|
+
};
|
|
819
|
+
function repository(model, arg2, arg3) {
|
|
820
|
+
const repoOptions = typeof arg2 === "function" ? void 0 : arg2;
|
|
821
|
+
const extend = typeof arg2 === "function" ? arg2 : arg3;
|
|
822
|
+
const base = buildRepository(runtime, resolveModelKey(prisma, model), repoOptions);
|
|
823
|
+
return extend ? { ...base, ...extend(base) } : base;
|
|
824
|
+
}
|
|
825
|
+
const transaction = (fn) => {
|
|
826
|
+
if (ctx.get()?.executor) return fn();
|
|
827
|
+
return prisma.$transaction((tx) => ctx.run({ executor: tx }, fn));
|
|
828
|
+
};
|
|
829
|
+
return { client: prisma, repository, transaction };
|
|
830
|
+
}
|
|
831
|
+
function createFilters() {
|
|
832
|
+
return createFilters$1();
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
export { buildRepository, createFilters, createRegistry };
|
|
836
|
+
//# sourceMappingURL=index.js.map
|
|
837
|
+
//# sourceMappingURL=index.js.map
|