sqlite-zod-orm 3.7.3 → 3.9.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/README.md +146 -93
- package/dist/index.js +1846 -1815
- package/package.json +5 -3
- package/src/ast.ts +1 -1
- package/src/context.ts +25 -0
- package/src/crud.ts +145 -0
- package/src/database.ts +181 -377
- package/src/entity.ts +62 -0
- package/src/helpers.ts +87 -0
- package/src/index.ts +2 -3
- package/src/query.ts +856 -0
- package/src/types.ts +19 -4
- package/dist/satidb.js +0 -26
- package/src/build.ts +0 -21
- package/src/proxy-query.ts +0 -312
- package/src/query-builder.ts +0 -698
package/dist/index.js
CHANGED
|
@@ -72,601 +72,6 @@ var op = {
|
|
|
72
72
|
not: (node) => ({ type: "operator", op: "NOT", left: { type: "literal", value: "" }, right: wrapNode(node) })
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
// src/query-builder.ts
|
|
76
|
-
var OPERATOR_MAP = {
|
|
77
|
-
$gt: ">",
|
|
78
|
-
$gte: ">=",
|
|
79
|
-
$lt: "<",
|
|
80
|
-
$lte: "<=",
|
|
81
|
-
$ne: "!=",
|
|
82
|
-
$in: "IN"
|
|
83
|
-
};
|
|
84
|
-
function transformValueForStorage(value) {
|
|
85
|
-
if (value instanceof Date)
|
|
86
|
-
return value.toISOString();
|
|
87
|
-
if (typeof value === "boolean")
|
|
88
|
-
return value ? 1 : 0;
|
|
89
|
-
return value;
|
|
90
|
-
}
|
|
91
|
-
function compileIQO(tableName, iqo) {
|
|
92
|
-
const params = [];
|
|
93
|
-
const selectParts = [];
|
|
94
|
-
if (iqo.selects.length > 0) {
|
|
95
|
-
selectParts.push(...iqo.selects.map((s) => `${tableName}.${s}`));
|
|
96
|
-
} else {
|
|
97
|
-
selectParts.push(`${tableName}.*`);
|
|
98
|
-
}
|
|
99
|
-
for (const j of iqo.joins) {
|
|
100
|
-
if (j.columns.length > 0) {
|
|
101
|
-
selectParts.push(...j.columns.map((c) => `${j.table}.${c} AS ${j.table}_${c}`));
|
|
102
|
-
} else {
|
|
103
|
-
selectParts.push(`${j.table}.*`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
let sql = `SELECT ${selectParts.join(", ")} FROM ${tableName}`;
|
|
107
|
-
for (const j of iqo.joins) {
|
|
108
|
-
sql += ` JOIN ${j.table} ON ${tableName}.${j.fromCol} = ${j.table}.${j.toCol}`;
|
|
109
|
-
}
|
|
110
|
-
if (iqo.whereAST) {
|
|
111
|
-
const compiled = compileAST(iqo.whereAST);
|
|
112
|
-
sql += ` WHERE ${compiled.sql}`;
|
|
113
|
-
params.push(...compiled.params);
|
|
114
|
-
} else if (iqo.wheres.length > 0) {
|
|
115
|
-
const hasJoins = iqo.joins.length > 0;
|
|
116
|
-
const qualify = (field) => hasJoins && !field.includes(".") ? `${tableName}.${field}` : field;
|
|
117
|
-
const whereParts = [];
|
|
118
|
-
for (const w of iqo.wheres) {
|
|
119
|
-
if (w.operator === "IN") {
|
|
120
|
-
const arr = w.value;
|
|
121
|
-
if (arr.length === 0) {
|
|
122
|
-
whereParts.push("1 = 0");
|
|
123
|
-
} else {
|
|
124
|
-
const placeholders = arr.map(() => "?").join(", ");
|
|
125
|
-
whereParts.push(`${qualify(w.field)} IN (${placeholders})`);
|
|
126
|
-
params.push(...arr.map(transformValueForStorage));
|
|
127
|
-
}
|
|
128
|
-
} else {
|
|
129
|
-
whereParts.push(`${qualify(w.field)} ${w.operator} ?`);
|
|
130
|
-
params.push(transformValueForStorage(w.value));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
sql += ` WHERE ${whereParts.join(" AND ")}`;
|
|
134
|
-
}
|
|
135
|
-
if (iqo.whereOrs.length > 0) {
|
|
136
|
-
for (const orGroup of iqo.whereOrs) {
|
|
137
|
-
const orParts = [];
|
|
138
|
-
for (const w of orGroup) {
|
|
139
|
-
if (w.operator === "IN") {
|
|
140
|
-
const arr = w.value;
|
|
141
|
-
if (arr.length === 0) {
|
|
142
|
-
orParts.push("1 = 0");
|
|
143
|
-
} else {
|
|
144
|
-
orParts.push(`${w.field} IN (${arr.map(() => "?").join(", ")})`);
|
|
145
|
-
params.push(...arr.map(transformValueForStorage));
|
|
146
|
-
}
|
|
147
|
-
} else {
|
|
148
|
-
orParts.push(`${w.field} ${w.operator} ?`);
|
|
149
|
-
params.push(transformValueForStorage(w.value));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (orParts.length > 0) {
|
|
153
|
-
const orClause = `(${orParts.join(" OR ")})`;
|
|
154
|
-
sql += sql.includes(" WHERE ") ? ` AND ${orClause}` : ` WHERE ${orClause}`;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (iqo.orderBy.length > 0) {
|
|
159
|
-
const parts = iqo.orderBy.map((o) => `${o.field} ${o.direction.toUpperCase()}`);
|
|
160
|
-
sql += ` ORDER BY ${parts.join(", ")}`;
|
|
161
|
-
}
|
|
162
|
-
if (iqo.limit !== null) {
|
|
163
|
-
sql += ` LIMIT ${iqo.limit}`;
|
|
164
|
-
}
|
|
165
|
-
if (iqo.offset !== null) {
|
|
166
|
-
sql += ` OFFSET ${iqo.offset}`;
|
|
167
|
-
}
|
|
168
|
-
return { sql, params };
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
class QueryBuilder {
|
|
172
|
-
iqo;
|
|
173
|
-
tableName;
|
|
174
|
-
executor;
|
|
175
|
-
singleExecutor;
|
|
176
|
-
joinResolver;
|
|
177
|
-
conditionResolver;
|
|
178
|
-
revisionGetter;
|
|
179
|
-
eagerLoader;
|
|
180
|
-
defaultPollInterval;
|
|
181
|
-
constructor(tableName, executor, singleExecutor, joinResolver, conditionResolver, revisionGetter, eagerLoader, pollInterval) {
|
|
182
|
-
this.tableName = tableName;
|
|
183
|
-
this.executor = executor;
|
|
184
|
-
this.singleExecutor = singleExecutor;
|
|
185
|
-
this.joinResolver = joinResolver ?? null;
|
|
186
|
-
this.conditionResolver = conditionResolver ?? null;
|
|
187
|
-
this.revisionGetter = revisionGetter ?? null;
|
|
188
|
-
this.eagerLoader = eagerLoader ?? null;
|
|
189
|
-
this.defaultPollInterval = pollInterval ?? 500;
|
|
190
|
-
this.iqo = {
|
|
191
|
-
selects: [],
|
|
192
|
-
wheres: [],
|
|
193
|
-
whereOrs: [],
|
|
194
|
-
whereAST: null,
|
|
195
|
-
joins: [],
|
|
196
|
-
limit: null,
|
|
197
|
-
offset: null,
|
|
198
|
-
orderBy: [],
|
|
199
|
-
includes: [],
|
|
200
|
-
raw: false
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
select(...cols) {
|
|
204
|
-
this.iqo.selects.push(...cols);
|
|
205
|
-
return this;
|
|
206
|
-
}
|
|
207
|
-
where(criteriaOrCallback) {
|
|
208
|
-
if (typeof criteriaOrCallback === "function") {
|
|
209
|
-
const ast = criteriaOrCallback(createColumnProxy(), createFunctionProxy(), op);
|
|
210
|
-
if (this.iqo.whereAST) {
|
|
211
|
-
this.iqo.whereAST = { type: "operator", op: "AND", left: this.iqo.whereAST, right: ast };
|
|
212
|
-
} else {
|
|
213
|
-
this.iqo.whereAST = ast;
|
|
214
|
-
}
|
|
215
|
-
} else {
|
|
216
|
-
const resolved = this.conditionResolver ? this.conditionResolver(criteriaOrCallback) : criteriaOrCallback;
|
|
217
|
-
for (const [key, value] of Object.entries(resolved)) {
|
|
218
|
-
if (key === "$or" && Array.isArray(value)) {
|
|
219
|
-
const orConditions = [];
|
|
220
|
-
for (const branch of value) {
|
|
221
|
-
const resolvedBranch = this.conditionResolver ? this.conditionResolver(branch) : branch;
|
|
222
|
-
for (const [bKey, bValue] of Object.entries(resolvedBranch)) {
|
|
223
|
-
if (typeof bValue === "object" && bValue !== null && !Array.isArray(bValue) && !(bValue instanceof Date)) {
|
|
224
|
-
for (const [opKey, operand] of Object.entries(bValue)) {
|
|
225
|
-
const sqlOp = OPERATOR_MAP[opKey];
|
|
226
|
-
if (sqlOp)
|
|
227
|
-
orConditions.push({ field: bKey, operator: sqlOp, value: operand });
|
|
228
|
-
}
|
|
229
|
-
} else {
|
|
230
|
-
orConditions.push({ field: bKey, operator: "=", value: bValue });
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (orConditions.length > 0)
|
|
235
|
-
this.iqo.whereOrs.push(orConditions);
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
|
|
239
|
-
for (const [opKey, operand] of Object.entries(value)) {
|
|
240
|
-
const sqlOp = OPERATOR_MAP[opKey];
|
|
241
|
-
if (!sqlOp)
|
|
242
|
-
throw new Error(`Unsupported query operator: '${opKey}' on field '${key}'.`);
|
|
243
|
-
this.iqo.wheres.push({
|
|
244
|
-
field: key,
|
|
245
|
-
operator: sqlOp,
|
|
246
|
-
value: operand
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
} else {
|
|
250
|
-
this.iqo.wheres.push({ field: key, operator: "=", value });
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return this;
|
|
255
|
-
}
|
|
256
|
-
limit(n) {
|
|
257
|
-
this.iqo.limit = n;
|
|
258
|
-
return this;
|
|
259
|
-
}
|
|
260
|
-
offset(n) {
|
|
261
|
-
this.iqo.offset = n;
|
|
262
|
-
return this;
|
|
263
|
-
}
|
|
264
|
-
orderBy(field, direction = "asc") {
|
|
265
|
-
this.iqo.orderBy.push({ field, direction });
|
|
266
|
-
return this;
|
|
267
|
-
}
|
|
268
|
-
join(tableOrAccessor, fkOrCols, colsOrPk, pk) {
|
|
269
|
-
let table;
|
|
270
|
-
let fromCol;
|
|
271
|
-
let toCol;
|
|
272
|
-
let columns;
|
|
273
|
-
if (typeof tableOrAccessor === "object" && "_tableName" in tableOrAccessor) {
|
|
274
|
-
table = tableOrAccessor._tableName;
|
|
275
|
-
columns = Array.isArray(fkOrCols) ? fkOrCols : [];
|
|
276
|
-
if (!this.joinResolver)
|
|
277
|
-
throw new Error(`Cannot auto-resolve join: no relationship data available`);
|
|
278
|
-
const resolved = this.joinResolver(this.tableName, table);
|
|
279
|
-
if (!resolved)
|
|
280
|
-
throw new Error(`No relationship found between '${this.tableName}' and '${table}'`);
|
|
281
|
-
fromCol = resolved.fk;
|
|
282
|
-
toCol = resolved.pk;
|
|
283
|
-
} else {
|
|
284
|
-
table = tableOrAccessor;
|
|
285
|
-
fromCol = fkOrCols;
|
|
286
|
-
columns = Array.isArray(colsOrPk) ? colsOrPk : [];
|
|
287
|
-
toCol = (typeof colsOrPk === "string" ? colsOrPk : pk) ?? "id";
|
|
288
|
-
}
|
|
289
|
-
this.iqo.joins.push({ table, fromCol, toCol, columns });
|
|
290
|
-
this.iqo.raw = true;
|
|
291
|
-
return this;
|
|
292
|
-
}
|
|
293
|
-
raw() {
|
|
294
|
-
this.iqo.raw = true;
|
|
295
|
-
return this;
|
|
296
|
-
}
|
|
297
|
-
with(...relations) {
|
|
298
|
-
this.iqo.includes.push(...relations);
|
|
299
|
-
return this;
|
|
300
|
-
}
|
|
301
|
-
_applyEagerLoads(results) {
|
|
302
|
-
if (this.iqo.includes.length === 0 || !this.eagerLoader || results.length === 0) {
|
|
303
|
-
return results;
|
|
304
|
-
}
|
|
305
|
-
const parentIds = results.map((r) => r.id).filter((id) => typeof id === "number");
|
|
306
|
-
if (parentIds.length === 0)
|
|
307
|
-
return results;
|
|
308
|
-
for (const relation of this.iqo.includes) {
|
|
309
|
-
const loaded = this.eagerLoader(this.tableName, relation, parentIds);
|
|
310
|
-
if (!loaded)
|
|
311
|
-
continue;
|
|
312
|
-
for (const row of results) {
|
|
313
|
-
row[loaded.key] = loaded.groups.get(row.id) ?? [];
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return results;
|
|
317
|
-
}
|
|
318
|
-
all() {
|
|
319
|
-
const { sql, params } = compileIQO(this.tableName, this.iqo);
|
|
320
|
-
const results = this.executor(sql, params, this.iqo.raw);
|
|
321
|
-
return this._applyEagerLoads(results);
|
|
322
|
-
}
|
|
323
|
-
get() {
|
|
324
|
-
this.iqo.limit = 1;
|
|
325
|
-
const { sql, params } = compileIQO(this.tableName, this.iqo);
|
|
326
|
-
const result = this.singleExecutor(sql, params, this.iqo.raw);
|
|
327
|
-
if (!result)
|
|
328
|
-
return null;
|
|
329
|
-
const [loaded] = this._applyEagerLoads([result]);
|
|
330
|
-
return loaded ?? null;
|
|
331
|
-
}
|
|
332
|
-
count() {
|
|
333
|
-
const params = [];
|
|
334
|
-
let sql = `SELECT COUNT(*) as count FROM ${this.tableName}`;
|
|
335
|
-
if (this.iqo.whereAST) {
|
|
336
|
-
const compiled = compileAST(this.iqo.whereAST);
|
|
337
|
-
sql += ` WHERE ${compiled.sql}`;
|
|
338
|
-
params.push(...compiled.params);
|
|
339
|
-
} else if (this.iqo.wheres.length > 0) {
|
|
340
|
-
const whereParts = [];
|
|
341
|
-
for (const w of this.iqo.wheres) {
|
|
342
|
-
if (w.operator === "IN") {
|
|
343
|
-
const arr = w.value;
|
|
344
|
-
if (arr.length === 0) {
|
|
345
|
-
whereParts.push("1 = 0");
|
|
346
|
-
} else {
|
|
347
|
-
const placeholders = arr.map(() => "?").join(", ");
|
|
348
|
-
whereParts.push(`${w.field} IN (${placeholders})`);
|
|
349
|
-
params.push(...arr.map(transformValueForStorage));
|
|
350
|
-
}
|
|
351
|
-
} else {
|
|
352
|
-
whereParts.push(`${w.field} ${w.operator} ?`);
|
|
353
|
-
params.push(transformValueForStorage(w.value));
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
sql += ` WHERE ${whereParts.join(" AND ")}`;
|
|
357
|
-
}
|
|
358
|
-
const results = this.executor(sql, params, true);
|
|
359
|
-
return results[0]?.count ?? 0;
|
|
360
|
-
}
|
|
361
|
-
subscribe(callback, options = {}) {
|
|
362
|
-
const { interval = this.defaultPollInterval, immediate = true } = options;
|
|
363
|
-
const fingerprintSQL = this.buildFingerprintSQL();
|
|
364
|
-
let lastCount = null;
|
|
365
|
-
let lastMax = null;
|
|
366
|
-
let lastInMemoryRev = null;
|
|
367
|
-
let stopped = false;
|
|
368
|
-
const poll = async () => {
|
|
369
|
-
if (stopped)
|
|
370
|
-
return;
|
|
371
|
-
try {
|
|
372
|
-
const rev = this.revisionGetter?.() ?? "0";
|
|
373
|
-
const inMemoryChanged = rev !== lastInMemoryRev;
|
|
374
|
-
lastInMemoryRev = rev;
|
|
375
|
-
const fpRows = this.executor(fingerprintSQL.sql, fingerprintSQL.params, true);
|
|
376
|
-
const fpRow = fpRows[0];
|
|
377
|
-
const cnt = fpRow?._cnt ?? 0;
|
|
378
|
-
const max = fpRow?._max ?? 0;
|
|
379
|
-
const fpChanged = cnt !== lastCount || max !== lastMax;
|
|
380
|
-
lastCount = cnt;
|
|
381
|
-
lastMax = max;
|
|
382
|
-
if (inMemoryChanged || fpChanged) {
|
|
383
|
-
const rows = this.all();
|
|
384
|
-
await callback(rows);
|
|
385
|
-
}
|
|
386
|
-
} catch {}
|
|
387
|
-
if (!stopped)
|
|
388
|
-
setTimeout(poll, interval);
|
|
389
|
-
};
|
|
390
|
-
if (immediate) {
|
|
391
|
-
poll();
|
|
392
|
-
} else {
|
|
393
|
-
setTimeout(poll, interval);
|
|
394
|
-
}
|
|
395
|
-
return () => {
|
|
396
|
-
stopped = true;
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
each(callback, options = {}) {
|
|
400
|
-
const { interval = this.defaultPollInterval } = options;
|
|
401
|
-
const userWhere = this.buildWhereClause();
|
|
402
|
-
const maxRows = this.executor(`SELECT MAX(id) as _max FROM ${this.tableName} ${userWhere.sql ? `WHERE ${userWhere.sql}` : ""}`, userWhere.params, true);
|
|
403
|
-
let lastMaxId = maxRows[0]?._max ?? 0;
|
|
404
|
-
let lastRevision = this.revisionGetter?.() ?? "0";
|
|
405
|
-
let stopped = false;
|
|
406
|
-
const poll = async () => {
|
|
407
|
-
if (stopped)
|
|
408
|
-
return;
|
|
409
|
-
const rev = this.revisionGetter?.() ?? "0";
|
|
410
|
-
if (rev !== lastRevision) {
|
|
411
|
-
lastRevision = rev;
|
|
412
|
-
const params = [...userWhere.params, lastMaxId];
|
|
413
|
-
const whereClause = userWhere.sql ? `WHERE ${userWhere.sql} AND id > ? ORDER BY id ASC` : `WHERE id > ? ORDER BY id ASC`;
|
|
414
|
-
const sql = `SELECT * FROM ${this.tableName} ${whereClause}`;
|
|
415
|
-
const newRows = this.executor(sql, params, false);
|
|
416
|
-
for (const row of newRows) {
|
|
417
|
-
if (stopped)
|
|
418
|
-
return;
|
|
419
|
-
await callback(row);
|
|
420
|
-
lastMaxId = row.id;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if (!stopped)
|
|
424
|
-
setTimeout(poll, interval);
|
|
425
|
-
};
|
|
426
|
-
setTimeout(poll, interval);
|
|
427
|
-
return () => {
|
|
428
|
-
stopped = true;
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
buildWhereClause() {
|
|
432
|
-
const params = [];
|
|
433
|
-
if (this.iqo.whereAST) {
|
|
434
|
-
const compiled = compileAST(this.iqo.whereAST);
|
|
435
|
-
return { sql: compiled.sql, params: compiled.params };
|
|
436
|
-
}
|
|
437
|
-
if (this.iqo.wheres.length > 0) {
|
|
438
|
-
const whereParts = [];
|
|
439
|
-
for (const w of this.iqo.wheres) {
|
|
440
|
-
if (w.operator === "IN") {
|
|
441
|
-
const arr = w.value;
|
|
442
|
-
if (arr.length === 0) {
|
|
443
|
-
whereParts.push("1 = 0");
|
|
444
|
-
} else {
|
|
445
|
-
const placeholders = arr.map(() => "?").join(", ");
|
|
446
|
-
whereParts.push(`${w.field} IN (${placeholders})`);
|
|
447
|
-
params.push(...arr.map(transformValueForStorage));
|
|
448
|
-
}
|
|
449
|
-
} else {
|
|
450
|
-
whereParts.push(`${w.field} ${w.operator} ?`);
|
|
451
|
-
params.push(transformValueForStorage(w.value));
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
return { sql: whereParts.join(" AND "), params };
|
|
455
|
-
}
|
|
456
|
-
return { sql: "", params: [] };
|
|
457
|
-
}
|
|
458
|
-
buildFingerprintSQL() {
|
|
459
|
-
const where = this.buildWhereClause();
|
|
460
|
-
const sql = `SELECT COUNT(*) as _cnt, MAX(id) as _max FROM ${this.tableName}${where.sql ? ` WHERE ${where.sql}` : ""}`;
|
|
461
|
-
return { sql, params: where.params };
|
|
462
|
-
}
|
|
463
|
-
then(onfulfilled, onrejected) {
|
|
464
|
-
try {
|
|
465
|
-
const result = this.all();
|
|
466
|
-
return Promise.resolve(result).then(onfulfilled, onrejected);
|
|
467
|
-
} catch (err) {
|
|
468
|
-
return Promise.reject(err).then(onfulfilled, onrejected);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// src/proxy-query.ts
|
|
474
|
-
class ColumnNode {
|
|
475
|
-
table;
|
|
476
|
-
column;
|
|
477
|
-
alias;
|
|
478
|
-
_type = "COL";
|
|
479
|
-
constructor(table, column, alias) {
|
|
480
|
-
this.table = table;
|
|
481
|
-
this.column = column;
|
|
482
|
-
this.alias = alias;
|
|
483
|
-
}
|
|
484
|
-
toString() {
|
|
485
|
-
return `"${this.alias}"."${this.column}"`;
|
|
486
|
-
}
|
|
487
|
-
[Symbol.toPrimitive]() {
|
|
488
|
-
return this.toString();
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
function q(name) {
|
|
492
|
-
return `"${name}"`;
|
|
493
|
-
}
|
|
494
|
-
function qRef(alias, column) {
|
|
495
|
-
return `"${alias}"."${column}"`;
|
|
496
|
-
}
|
|
497
|
-
function createTableProxy(tableName, alias, columns) {
|
|
498
|
-
return new Proxy({}, {
|
|
499
|
-
get(_target, prop) {
|
|
500
|
-
if (prop === Symbol.toPrimitive || prop === "toString" || prop === "valueOf") {
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
return new ColumnNode(tableName, prop, alias);
|
|
504
|
-
},
|
|
505
|
-
ownKeys() {
|
|
506
|
-
return [...columns];
|
|
507
|
-
},
|
|
508
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
509
|
-
if (columns.has(prop)) {
|
|
510
|
-
return { configurable: true, enumerable: true, value: new ColumnNode(tableName, prop, alias) };
|
|
511
|
-
}
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
function createContextProxy(schemas) {
|
|
517
|
-
const aliases = new Map;
|
|
518
|
-
let aliasCounter = 0;
|
|
519
|
-
const proxy = new Proxy({}, {
|
|
520
|
-
get(_target, tableName) {
|
|
521
|
-
if (typeof tableName !== "string")
|
|
522
|
-
return;
|
|
523
|
-
const schema = schemas[tableName];
|
|
524
|
-
const shape = schema ? schema.shape : {};
|
|
525
|
-
const columns = new Set(Object.keys(shape));
|
|
526
|
-
aliasCounter++;
|
|
527
|
-
const alias = `t${aliasCounter}`;
|
|
528
|
-
const tableProxy = createTableProxy(tableName, alias, columns);
|
|
529
|
-
const entries = aliases.get(tableName) || [];
|
|
530
|
-
entries.push({ tableName, alias, proxy: tableProxy });
|
|
531
|
-
aliases.set(tableName, entries);
|
|
532
|
-
return tableProxy;
|
|
533
|
-
}
|
|
534
|
-
});
|
|
535
|
-
return { proxy, aliasMap: aliases };
|
|
536
|
-
}
|
|
537
|
-
function isColumnNode(val) {
|
|
538
|
-
return val && typeof val === "object" && val._type === "COL";
|
|
539
|
-
}
|
|
540
|
-
function compileProxyQuery(queryResult, aliasMap) {
|
|
541
|
-
const params = [];
|
|
542
|
-
const tablesUsed = new Map;
|
|
543
|
-
for (const [tableName, entries] of aliasMap) {
|
|
544
|
-
for (const entry of entries) {
|
|
545
|
-
tablesUsed.set(entry.alias, { tableName, alias: entry.alias });
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
const selectParts = [];
|
|
549
|
-
for (const [outputName, colOrValue] of Object.entries(queryResult.select)) {
|
|
550
|
-
if (isColumnNode(colOrValue)) {
|
|
551
|
-
if (outputName === colOrValue.column) {
|
|
552
|
-
selectParts.push(qRef(colOrValue.alias, colOrValue.column));
|
|
553
|
-
} else {
|
|
554
|
-
selectParts.push(`${qRef(colOrValue.alias, colOrValue.column)} AS ${q(outputName)}`);
|
|
555
|
-
}
|
|
556
|
-
} else {
|
|
557
|
-
selectParts.push(`? AS ${q(outputName)}`);
|
|
558
|
-
params.push(colOrValue);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
const allAliases = [...tablesUsed.values()];
|
|
562
|
-
if (allAliases.length === 0)
|
|
563
|
-
throw new Error("No tables referenced in query.");
|
|
564
|
-
const primaryAlias = allAliases[0];
|
|
565
|
-
let sql = `SELECT ${selectParts.join(", ")} FROM ${q(primaryAlias.tableName)} ${q(primaryAlias.alias)}`;
|
|
566
|
-
if (queryResult.join) {
|
|
567
|
-
const joins = Array.isArray(queryResult.join[0]) ? queryResult.join : [queryResult.join];
|
|
568
|
-
for (const [left, right] of joins) {
|
|
569
|
-
const leftTable = tablesUsed.get(left.alias);
|
|
570
|
-
const rightTable = tablesUsed.get(right.alias);
|
|
571
|
-
if (!leftTable || !rightTable)
|
|
572
|
-
throw new Error("Join references unknown table alias.");
|
|
573
|
-
const joinAlias = leftTable.alias === primaryAlias.alias ? rightTable : leftTable;
|
|
574
|
-
sql += ` JOIN ${q(joinAlias.tableName)} ${q(joinAlias.alias)} ON ${qRef(left.alias, left.column)} = ${qRef(right.alias, right.column)}`;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
if (queryResult.where && Object.keys(queryResult.where).length > 0) {
|
|
578
|
-
const whereParts = [];
|
|
579
|
-
for (const [key, value] of Object.entries(queryResult.where)) {
|
|
580
|
-
let fieldRef;
|
|
581
|
-
const quotedMatch = key.match(/^"([^"]+)"\."([^"]+)"$/);
|
|
582
|
-
if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
|
|
583
|
-
fieldRef = key;
|
|
584
|
-
} else {
|
|
585
|
-
fieldRef = qRef(primaryAlias.alias, key);
|
|
586
|
-
}
|
|
587
|
-
if (isColumnNode(value)) {
|
|
588
|
-
whereParts.push(`${fieldRef} = ${qRef(value.alias, value.column)}`);
|
|
589
|
-
} else if (Array.isArray(value)) {
|
|
590
|
-
if (value.length === 0) {
|
|
591
|
-
whereParts.push("1 = 0");
|
|
592
|
-
} else {
|
|
593
|
-
const placeholders = value.map(() => "?").join(", ");
|
|
594
|
-
whereParts.push(`${fieldRef} IN (${placeholders})`);
|
|
595
|
-
params.push(...value);
|
|
596
|
-
}
|
|
597
|
-
} else if (typeof value === "object" && value !== null && !(value instanceof Date)) {
|
|
598
|
-
for (const [op2, operand] of Object.entries(value)) {
|
|
599
|
-
if (op2 === "$in") {
|
|
600
|
-
const arr = operand;
|
|
601
|
-
if (arr.length === 0) {
|
|
602
|
-
whereParts.push("1 = 0");
|
|
603
|
-
} else {
|
|
604
|
-
const placeholders = arr.map(() => "?").join(", ");
|
|
605
|
-
whereParts.push(`${fieldRef} IN (${placeholders})`);
|
|
606
|
-
params.push(...arr);
|
|
607
|
-
}
|
|
608
|
-
continue;
|
|
609
|
-
}
|
|
610
|
-
const opMap = {
|
|
611
|
-
$gt: ">",
|
|
612
|
-
$gte: ">=",
|
|
613
|
-
$lt: "<",
|
|
614
|
-
$lte: "<=",
|
|
615
|
-
$ne: "!="
|
|
616
|
-
};
|
|
617
|
-
const sqlOp = opMap[op2];
|
|
618
|
-
if (!sqlOp)
|
|
619
|
-
throw new Error(`Unsupported where operator: ${op2}`);
|
|
620
|
-
whereParts.push(`${fieldRef} ${sqlOp} ?`);
|
|
621
|
-
params.push(operand);
|
|
622
|
-
}
|
|
623
|
-
} else {
|
|
624
|
-
whereParts.push(`${fieldRef} = ?`);
|
|
625
|
-
params.push(value instanceof Date ? value.toISOString() : value);
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
if (whereParts.length > 0) {
|
|
629
|
-
sql += ` WHERE ${whereParts.join(" AND ")}`;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
if (queryResult.orderBy) {
|
|
633
|
-
const parts = [];
|
|
634
|
-
for (const [key, dir] of Object.entries(queryResult.orderBy)) {
|
|
635
|
-
let fieldRef;
|
|
636
|
-
const quotedMatch = key.match(/^"([^"]+)"\."([^"]+)"$/);
|
|
637
|
-
if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
|
|
638
|
-
fieldRef = key;
|
|
639
|
-
} else {
|
|
640
|
-
fieldRef = qRef(primaryAlias.alias, key);
|
|
641
|
-
}
|
|
642
|
-
parts.push(`${fieldRef} ${dir.toUpperCase()}`);
|
|
643
|
-
}
|
|
644
|
-
if (parts.length > 0) {
|
|
645
|
-
sql += ` ORDER BY ${parts.join(", ")}`;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
if (queryResult.groupBy && queryResult.groupBy.length > 0) {
|
|
649
|
-
const parts = queryResult.groupBy.filter(Boolean).map((col) => qRef(col.alias, col.column));
|
|
650
|
-
sql += ` GROUP BY ${parts.join(", ")}`;
|
|
651
|
-
}
|
|
652
|
-
if (queryResult.limit !== undefined) {
|
|
653
|
-
sql += ` LIMIT ${queryResult.limit}`;
|
|
654
|
-
}
|
|
655
|
-
if (queryResult.offset !== undefined) {
|
|
656
|
-
sql += ` OFFSET ${queryResult.offset}`;
|
|
657
|
-
}
|
|
658
|
-
return { sql, params };
|
|
659
|
-
}
|
|
660
|
-
function executeProxyQuery(schemas, callback, executor) {
|
|
661
|
-
const { proxy, aliasMap } = createContextProxy(schemas);
|
|
662
|
-
const queryResult = callback(proxy);
|
|
663
|
-
const { sql, params } = compileProxyQuery(queryResult, aliasMap);
|
|
664
|
-
return executor(sql, params);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
// src/types.ts
|
|
668
|
-
var asZodObject = (s) => s;
|
|
669
|
-
|
|
670
75
|
// node_modules/zod/v3/external.js
|
|
671
76
|
var exports_external = {};
|
|
672
77
|
__export(exports_external, {
|
|
@@ -3557,1212 +2962,2014 @@ class ZodIntersection extends ZodType {
|
|
|
3557
2962
|
})
|
|
3558
2963
|
]).then(([left, right]) => handleParsed(left, right));
|
|
3559
2964
|
} else {
|
|
3560
|
-
return handleParsed(this._def.left._parseSync({
|
|
3561
|
-
data: ctx.data,
|
|
3562
|
-
path: ctx.path,
|
|
3563
|
-
parent: ctx
|
|
3564
|
-
}), this._def.right._parseSync({
|
|
3565
|
-
data: ctx.data,
|
|
3566
|
-
path: ctx.path,
|
|
3567
|
-
parent: ctx
|
|
3568
|
-
}));
|
|
2965
|
+
return handleParsed(this._def.left._parseSync({
|
|
2966
|
+
data: ctx.data,
|
|
2967
|
+
path: ctx.path,
|
|
2968
|
+
parent: ctx
|
|
2969
|
+
}), this._def.right._parseSync({
|
|
2970
|
+
data: ctx.data,
|
|
2971
|
+
path: ctx.path,
|
|
2972
|
+
parent: ctx
|
|
2973
|
+
}));
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
ZodIntersection.create = (left, right, params) => {
|
|
2978
|
+
return new ZodIntersection({
|
|
2979
|
+
left,
|
|
2980
|
+
right,
|
|
2981
|
+
typeName: ZodFirstPartyTypeKind.ZodIntersection,
|
|
2982
|
+
...processCreateParams(params)
|
|
2983
|
+
});
|
|
2984
|
+
};
|
|
2985
|
+
|
|
2986
|
+
class ZodTuple extends ZodType {
|
|
2987
|
+
_parse(input) {
|
|
2988
|
+
const { status, ctx } = this._processInputParams(input);
|
|
2989
|
+
if (ctx.parsedType !== ZodParsedType.array) {
|
|
2990
|
+
addIssueToContext(ctx, {
|
|
2991
|
+
code: ZodIssueCode.invalid_type,
|
|
2992
|
+
expected: ZodParsedType.array,
|
|
2993
|
+
received: ctx.parsedType
|
|
2994
|
+
});
|
|
2995
|
+
return INVALID;
|
|
2996
|
+
}
|
|
2997
|
+
if (ctx.data.length < this._def.items.length) {
|
|
2998
|
+
addIssueToContext(ctx, {
|
|
2999
|
+
code: ZodIssueCode.too_small,
|
|
3000
|
+
minimum: this._def.items.length,
|
|
3001
|
+
inclusive: true,
|
|
3002
|
+
exact: false,
|
|
3003
|
+
type: "array"
|
|
3004
|
+
});
|
|
3005
|
+
return INVALID;
|
|
3006
|
+
}
|
|
3007
|
+
const rest = this._def.rest;
|
|
3008
|
+
if (!rest && ctx.data.length > this._def.items.length) {
|
|
3009
|
+
addIssueToContext(ctx, {
|
|
3010
|
+
code: ZodIssueCode.too_big,
|
|
3011
|
+
maximum: this._def.items.length,
|
|
3012
|
+
inclusive: true,
|
|
3013
|
+
exact: false,
|
|
3014
|
+
type: "array"
|
|
3015
|
+
});
|
|
3016
|
+
status.dirty();
|
|
3017
|
+
}
|
|
3018
|
+
const items = [...ctx.data].map((item, itemIndex) => {
|
|
3019
|
+
const schema = this._def.items[itemIndex] || this._def.rest;
|
|
3020
|
+
if (!schema)
|
|
3021
|
+
return null;
|
|
3022
|
+
return schema._parse(new ParseInputLazyPath(ctx, item, ctx.path, itemIndex));
|
|
3023
|
+
}).filter((x) => !!x);
|
|
3024
|
+
if (ctx.common.async) {
|
|
3025
|
+
return Promise.all(items).then((results) => {
|
|
3026
|
+
return ParseStatus.mergeArray(status, results);
|
|
3027
|
+
});
|
|
3028
|
+
} else {
|
|
3029
|
+
return ParseStatus.mergeArray(status, items);
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
get items() {
|
|
3033
|
+
return this._def.items;
|
|
3034
|
+
}
|
|
3035
|
+
rest(rest) {
|
|
3036
|
+
return new ZodTuple({
|
|
3037
|
+
...this._def,
|
|
3038
|
+
rest
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
ZodTuple.create = (schemas, params) => {
|
|
3043
|
+
if (!Array.isArray(schemas)) {
|
|
3044
|
+
throw new Error("You must pass an array of schemas to z.tuple([ ... ])");
|
|
3045
|
+
}
|
|
3046
|
+
return new ZodTuple({
|
|
3047
|
+
items: schemas,
|
|
3048
|
+
typeName: ZodFirstPartyTypeKind.ZodTuple,
|
|
3049
|
+
rest: null,
|
|
3050
|
+
...processCreateParams(params)
|
|
3051
|
+
});
|
|
3052
|
+
};
|
|
3053
|
+
|
|
3054
|
+
class ZodRecord extends ZodType {
|
|
3055
|
+
get keySchema() {
|
|
3056
|
+
return this._def.keyType;
|
|
3057
|
+
}
|
|
3058
|
+
get valueSchema() {
|
|
3059
|
+
return this._def.valueType;
|
|
3060
|
+
}
|
|
3061
|
+
_parse(input) {
|
|
3062
|
+
const { status, ctx } = this._processInputParams(input);
|
|
3063
|
+
if (ctx.parsedType !== ZodParsedType.object) {
|
|
3064
|
+
addIssueToContext(ctx, {
|
|
3065
|
+
code: ZodIssueCode.invalid_type,
|
|
3066
|
+
expected: ZodParsedType.object,
|
|
3067
|
+
received: ctx.parsedType
|
|
3068
|
+
});
|
|
3069
|
+
return INVALID;
|
|
3070
|
+
}
|
|
3071
|
+
const pairs = [];
|
|
3072
|
+
const keyType = this._def.keyType;
|
|
3073
|
+
const valueType = this._def.valueType;
|
|
3074
|
+
for (const key in ctx.data) {
|
|
3075
|
+
pairs.push({
|
|
3076
|
+
key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, key)),
|
|
3077
|
+
value: valueType._parse(new ParseInputLazyPath(ctx, ctx.data[key], ctx.path, key)),
|
|
3078
|
+
alwaysSet: key in ctx.data
|
|
3079
|
+
});
|
|
3080
|
+
}
|
|
3081
|
+
if (ctx.common.async) {
|
|
3082
|
+
return ParseStatus.mergeObjectAsync(status, pairs);
|
|
3083
|
+
} else {
|
|
3084
|
+
return ParseStatus.mergeObjectSync(status, pairs);
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
get element() {
|
|
3088
|
+
return this._def.valueType;
|
|
3089
|
+
}
|
|
3090
|
+
static create(first, second, third) {
|
|
3091
|
+
if (second instanceof ZodType) {
|
|
3092
|
+
return new ZodRecord({
|
|
3093
|
+
keyType: first,
|
|
3094
|
+
valueType: second,
|
|
3095
|
+
typeName: ZodFirstPartyTypeKind.ZodRecord,
|
|
3096
|
+
...processCreateParams(third)
|
|
3097
|
+
});
|
|
3098
|
+
}
|
|
3099
|
+
return new ZodRecord({
|
|
3100
|
+
keyType: ZodString.create(),
|
|
3101
|
+
valueType: first,
|
|
3102
|
+
typeName: ZodFirstPartyTypeKind.ZodRecord,
|
|
3103
|
+
...processCreateParams(second)
|
|
3104
|
+
});
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
class ZodMap extends ZodType {
|
|
3109
|
+
get keySchema() {
|
|
3110
|
+
return this._def.keyType;
|
|
3111
|
+
}
|
|
3112
|
+
get valueSchema() {
|
|
3113
|
+
return this._def.valueType;
|
|
3114
|
+
}
|
|
3115
|
+
_parse(input) {
|
|
3116
|
+
const { status, ctx } = this._processInputParams(input);
|
|
3117
|
+
if (ctx.parsedType !== ZodParsedType.map) {
|
|
3118
|
+
addIssueToContext(ctx, {
|
|
3119
|
+
code: ZodIssueCode.invalid_type,
|
|
3120
|
+
expected: ZodParsedType.map,
|
|
3121
|
+
received: ctx.parsedType
|
|
3122
|
+
});
|
|
3123
|
+
return INVALID;
|
|
3124
|
+
}
|
|
3125
|
+
const keyType = this._def.keyType;
|
|
3126
|
+
const valueType = this._def.valueType;
|
|
3127
|
+
const pairs = [...ctx.data.entries()].map(([key, value], index) => {
|
|
3128
|
+
return {
|
|
3129
|
+
key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index, "key"])),
|
|
3130
|
+
value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index, "value"]))
|
|
3131
|
+
};
|
|
3132
|
+
});
|
|
3133
|
+
if (ctx.common.async) {
|
|
3134
|
+
const finalMap = new Map;
|
|
3135
|
+
return Promise.resolve().then(async () => {
|
|
3136
|
+
for (const pair of pairs) {
|
|
3137
|
+
const key = await pair.key;
|
|
3138
|
+
const value = await pair.value;
|
|
3139
|
+
if (key.status === "aborted" || value.status === "aborted") {
|
|
3140
|
+
return INVALID;
|
|
3141
|
+
}
|
|
3142
|
+
if (key.status === "dirty" || value.status === "dirty") {
|
|
3143
|
+
status.dirty();
|
|
3144
|
+
}
|
|
3145
|
+
finalMap.set(key.value, value.value);
|
|
3146
|
+
}
|
|
3147
|
+
return { status: status.value, value: finalMap };
|
|
3148
|
+
});
|
|
3149
|
+
} else {
|
|
3150
|
+
const finalMap = new Map;
|
|
3151
|
+
for (const pair of pairs) {
|
|
3152
|
+
const key = pair.key;
|
|
3153
|
+
const value = pair.value;
|
|
3154
|
+
if (key.status === "aborted" || value.status === "aborted") {
|
|
3155
|
+
return INVALID;
|
|
3156
|
+
}
|
|
3157
|
+
if (key.status === "dirty" || value.status === "dirty") {
|
|
3158
|
+
status.dirty();
|
|
3159
|
+
}
|
|
3160
|
+
finalMap.set(key.value, value.value);
|
|
3161
|
+
}
|
|
3162
|
+
return { status: status.value, value: finalMap };
|
|
3569
3163
|
}
|
|
3570
3164
|
}
|
|
3571
3165
|
}
|
|
3572
|
-
|
|
3573
|
-
return new
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
typeName: ZodFirstPartyTypeKind.
|
|
3166
|
+
ZodMap.create = (keyType, valueType, params) => {
|
|
3167
|
+
return new ZodMap({
|
|
3168
|
+
valueType,
|
|
3169
|
+
keyType,
|
|
3170
|
+
typeName: ZodFirstPartyTypeKind.ZodMap,
|
|
3577
3171
|
...processCreateParams(params)
|
|
3578
3172
|
});
|
|
3579
3173
|
};
|
|
3580
3174
|
|
|
3581
|
-
class
|
|
3175
|
+
class ZodSet extends ZodType {
|
|
3582
3176
|
_parse(input) {
|
|
3583
3177
|
const { status, ctx } = this._processInputParams(input);
|
|
3584
|
-
if (ctx.parsedType !== ZodParsedType.
|
|
3178
|
+
if (ctx.parsedType !== ZodParsedType.set) {
|
|
3585
3179
|
addIssueToContext(ctx, {
|
|
3586
3180
|
code: ZodIssueCode.invalid_type,
|
|
3587
|
-
expected: ZodParsedType.
|
|
3181
|
+
expected: ZodParsedType.set,
|
|
3588
3182
|
received: ctx.parsedType
|
|
3589
3183
|
});
|
|
3590
3184
|
return INVALID;
|
|
3591
3185
|
}
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3186
|
+
const def = this._def;
|
|
3187
|
+
if (def.minSize !== null) {
|
|
3188
|
+
if (ctx.data.size < def.minSize.value) {
|
|
3189
|
+
addIssueToContext(ctx, {
|
|
3190
|
+
code: ZodIssueCode.too_small,
|
|
3191
|
+
minimum: def.minSize.value,
|
|
3192
|
+
type: "set",
|
|
3193
|
+
inclusive: true,
|
|
3194
|
+
exact: false,
|
|
3195
|
+
message: def.minSize.message
|
|
3196
|
+
});
|
|
3197
|
+
status.dirty();
|
|
3198
|
+
}
|
|
3601
3199
|
}
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3200
|
+
if (def.maxSize !== null) {
|
|
3201
|
+
if (ctx.data.size > def.maxSize.value) {
|
|
3202
|
+
addIssueToContext(ctx, {
|
|
3203
|
+
code: ZodIssueCode.too_big,
|
|
3204
|
+
maximum: def.maxSize.value,
|
|
3205
|
+
type: "set",
|
|
3206
|
+
inclusive: true,
|
|
3207
|
+
exact: false,
|
|
3208
|
+
message: def.maxSize.message
|
|
3209
|
+
});
|
|
3210
|
+
status.dirty();
|
|
3211
|
+
}
|
|
3612
3212
|
}
|
|
3613
|
-
const
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3213
|
+
const valueType = this._def.valueType;
|
|
3214
|
+
function finalizeSet(elements2) {
|
|
3215
|
+
const parsedSet = new Set;
|
|
3216
|
+
for (const element of elements2) {
|
|
3217
|
+
if (element.status === "aborted")
|
|
3218
|
+
return INVALID;
|
|
3219
|
+
if (element.status === "dirty")
|
|
3220
|
+
status.dirty();
|
|
3221
|
+
parsedSet.add(element.value);
|
|
3222
|
+
}
|
|
3223
|
+
return { status: status.value, value: parsedSet };
|
|
3224
|
+
}
|
|
3225
|
+
const elements = [...ctx.data.values()].map((item, i) => valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i)));
|
|
3619
3226
|
if (ctx.common.async) {
|
|
3620
|
-
return Promise.all(
|
|
3621
|
-
return ParseStatus.mergeArray(status, results);
|
|
3622
|
-
});
|
|
3227
|
+
return Promise.all(elements).then((elements2) => finalizeSet(elements2));
|
|
3623
3228
|
} else {
|
|
3624
|
-
return
|
|
3229
|
+
return finalizeSet(elements);
|
|
3625
3230
|
}
|
|
3626
3231
|
}
|
|
3627
|
-
|
|
3628
|
-
return
|
|
3232
|
+
min(minSize, message) {
|
|
3233
|
+
return new ZodSet({
|
|
3234
|
+
...this._def,
|
|
3235
|
+
minSize: { value: minSize, message: errorUtil.toString(message) }
|
|
3236
|
+
});
|
|
3629
3237
|
}
|
|
3630
|
-
|
|
3631
|
-
return new
|
|
3238
|
+
max(maxSize, message) {
|
|
3239
|
+
return new ZodSet({
|
|
3632
3240
|
...this._def,
|
|
3633
|
-
|
|
3241
|
+
maxSize: { value: maxSize, message: errorUtil.toString(message) }
|
|
3634
3242
|
});
|
|
3635
3243
|
}
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
if (!Array.isArray(schemas)) {
|
|
3639
|
-
throw new Error("You must pass an array of schemas to z.tuple([ ... ])");
|
|
3244
|
+
size(size, message) {
|
|
3245
|
+
return this.min(size, message).max(size, message);
|
|
3640
3246
|
}
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3247
|
+
nonempty(message) {
|
|
3248
|
+
return this.min(1, message);
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
ZodSet.create = (valueType, params) => {
|
|
3252
|
+
return new ZodSet({
|
|
3253
|
+
valueType,
|
|
3254
|
+
minSize: null,
|
|
3255
|
+
maxSize: null,
|
|
3256
|
+
typeName: ZodFirstPartyTypeKind.ZodSet,
|
|
3645
3257
|
...processCreateParams(params)
|
|
3646
3258
|
});
|
|
3647
3259
|
};
|
|
3648
3260
|
|
|
3649
|
-
class
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
get valueSchema() {
|
|
3654
|
-
return this._def.valueType;
|
|
3261
|
+
class ZodFunction extends ZodType {
|
|
3262
|
+
constructor() {
|
|
3263
|
+
super(...arguments);
|
|
3264
|
+
this.validate = this.implement;
|
|
3655
3265
|
}
|
|
3656
3266
|
_parse(input) {
|
|
3657
|
-
const {
|
|
3658
|
-
if (ctx.parsedType !== ZodParsedType.
|
|
3267
|
+
const { ctx } = this._processInputParams(input);
|
|
3268
|
+
if (ctx.parsedType !== ZodParsedType.function) {
|
|
3659
3269
|
addIssueToContext(ctx, {
|
|
3660
3270
|
code: ZodIssueCode.invalid_type,
|
|
3661
|
-
expected: ZodParsedType.
|
|
3271
|
+
expected: ZodParsedType.function,
|
|
3662
3272
|
received: ctx.parsedType
|
|
3663
3273
|
});
|
|
3664
3274
|
return INVALID;
|
|
3665
3275
|
}
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3276
|
+
function makeArgsIssue(args, error) {
|
|
3277
|
+
return makeIssue({
|
|
3278
|
+
data: args,
|
|
3279
|
+
path: ctx.path,
|
|
3280
|
+
errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), en_default].filter((x) => !!x),
|
|
3281
|
+
issueData: {
|
|
3282
|
+
code: ZodIssueCode.invalid_arguments,
|
|
3283
|
+
argumentsError: error
|
|
3284
|
+
}
|
|
3674
3285
|
});
|
|
3675
3286
|
}
|
|
3676
|
-
|
|
3677
|
-
return
|
|
3287
|
+
function makeReturnsIssue(returns, error) {
|
|
3288
|
+
return makeIssue({
|
|
3289
|
+
data: returns,
|
|
3290
|
+
path: ctx.path,
|
|
3291
|
+
errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), en_default].filter((x) => !!x),
|
|
3292
|
+
issueData: {
|
|
3293
|
+
code: ZodIssueCode.invalid_return_type,
|
|
3294
|
+
returnTypeError: error
|
|
3295
|
+
}
|
|
3296
|
+
});
|
|
3297
|
+
}
|
|
3298
|
+
const params = { errorMap: ctx.common.contextualErrorMap };
|
|
3299
|
+
const fn = ctx.data;
|
|
3300
|
+
if (this._def.returns instanceof ZodPromise) {
|
|
3301
|
+
const me = this;
|
|
3302
|
+
return OK(async function(...args) {
|
|
3303
|
+
const error = new ZodError([]);
|
|
3304
|
+
const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => {
|
|
3305
|
+
error.addIssue(makeArgsIssue(args, e));
|
|
3306
|
+
throw error;
|
|
3307
|
+
});
|
|
3308
|
+
const result = await Reflect.apply(fn, this, parsedArgs);
|
|
3309
|
+
const parsedReturns = await me._def.returns._def.type.parseAsync(result, params).catch((e) => {
|
|
3310
|
+
error.addIssue(makeReturnsIssue(result, e));
|
|
3311
|
+
throw error;
|
|
3312
|
+
});
|
|
3313
|
+
return parsedReturns;
|
|
3314
|
+
});
|
|
3678
3315
|
} else {
|
|
3679
|
-
|
|
3316
|
+
const me = this;
|
|
3317
|
+
return OK(function(...args) {
|
|
3318
|
+
const parsedArgs = me._def.args.safeParse(args, params);
|
|
3319
|
+
if (!parsedArgs.success) {
|
|
3320
|
+
throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
|
|
3321
|
+
}
|
|
3322
|
+
const result = Reflect.apply(fn, this, parsedArgs.data);
|
|
3323
|
+
const parsedReturns = me._def.returns.safeParse(result, params);
|
|
3324
|
+
if (!parsedReturns.success) {
|
|
3325
|
+
throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]);
|
|
3326
|
+
}
|
|
3327
|
+
return parsedReturns.data;
|
|
3328
|
+
});
|
|
3680
3329
|
}
|
|
3681
3330
|
}
|
|
3682
|
-
|
|
3683
|
-
return this._def.
|
|
3331
|
+
parameters() {
|
|
3332
|
+
return this._def.args;
|
|
3333
|
+
}
|
|
3334
|
+
returnType() {
|
|
3335
|
+
return this._def.returns;
|
|
3336
|
+
}
|
|
3337
|
+
args(...items) {
|
|
3338
|
+
return new ZodFunction({
|
|
3339
|
+
...this._def,
|
|
3340
|
+
args: ZodTuple.create(items).rest(ZodUnknown.create())
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
returns(returnType) {
|
|
3344
|
+
return new ZodFunction({
|
|
3345
|
+
...this._def,
|
|
3346
|
+
returns: returnType
|
|
3347
|
+
});
|
|
3348
|
+
}
|
|
3349
|
+
implement(func) {
|
|
3350
|
+
const validatedFunc = this.parse(func);
|
|
3351
|
+
return validatedFunc;
|
|
3684
3352
|
}
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
keyType: ZodString.create(),
|
|
3696
|
-
valueType: first,
|
|
3697
|
-
typeName: ZodFirstPartyTypeKind.ZodRecord,
|
|
3698
|
-
...processCreateParams(second)
|
|
3353
|
+
strictImplement(func) {
|
|
3354
|
+
const validatedFunc = this.parse(func);
|
|
3355
|
+
return validatedFunc;
|
|
3356
|
+
}
|
|
3357
|
+
static create(args, returns, params) {
|
|
3358
|
+
return new ZodFunction({
|
|
3359
|
+
args: args ? args : ZodTuple.create([]).rest(ZodUnknown.create()),
|
|
3360
|
+
returns: returns || ZodUnknown.create(),
|
|
3361
|
+
typeName: ZodFirstPartyTypeKind.ZodFunction,
|
|
3362
|
+
...processCreateParams(params)
|
|
3699
3363
|
});
|
|
3700
3364
|
}
|
|
3701
3365
|
}
|
|
3702
3366
|
|
|
3703
|
-
class
|
|
3704
|
-
get
|
|
3705
|
-
return this._def.
|
|
3367
|
+
class ZodLazy extends ZodType {
|
|
3368
|
+
get schema() {
|
|
3369
|
+
return this._def.getter();
|
|
3706
3370
|
}
|
|
3707
|
-
|
|
3708
|
-
|
|
3371
|
+
_parse(input) {
|
|
3372
|
+
const { ctx } = this._processInputParams(input);
|
|
3373
|
+
const lazySchema = this._def.getter();
|
|
3374
|
+
return lazySchema._parse({ data: ctx.data, path: ctx.path, parent: ctx });
|
|
3709
3375
|
}
|
|
3376
|
+
}
|
|
3377
|
+
ZodLazy.create = (getter, params) => {
|
|
3378
|
+
return new ZodLazy({
|
|
3379
|
+
getter,
|
|
3380
|
+
typeName: ZodFirstPartyTypeKind.ZodLazy,
|
|
3381
|
+
...processCreateParams(params)
|
|
3382
|
+
});
|
|
3383
|
+
};
|
|
3384
|
+
|
|
3385
|
+
class ZodLiteral extends ZodType {
|
|
3710
3386
|
_parse(input) {
|
|
3711
|
-
|
|
3712
|
-
|
|
3387
|
+
if (input.data !== this._def.value) {
|
|
3388
|
+
const ctx = this._getOrReturnCtx(input);
|
|
3713
3389
|
addIssueToContext(ctx, {
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3390
|
+
received: ctx.data,
|
|
3391
|
+
code: ZodIssueCode.invalid_literal,
|
|
3392
|
+
expected: this._def.value
|
|
3717
3393
|
});
|
|
3718
3394
|
return INVALID;
|
|
3719
3395
|
}
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index, "key"])),
|
|
3725
|
-
value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index, "value"]))
|
|
3726
|
-
};
|
|
3727
|
-
});
|
|
3728
|
-
if (ctx.common.async) {
|
|
3729
|
-
const finalMap = new Map;
|
|
3730
|
-
return Promise.resolve().then(async () => {
|
|
3731
|
-
for (const pair of pairs) {
|
|
3732
|
-
const key = await pair.key;
|
|
3733
|
-
const value = await pair.value;
|
|
3734
|
-
if (key.status === "aborted" || value.status === "aborted") {
|
|
3735
|
-
return INVALID;
|
|
3736
|
-
}
|
|
3737
|
-
if (key.status === "dirty" || value.status === "dirty") {
|
|
3738
|
-
status.dirty();
|
|
3739
|
-
}
|
|
3740
|
-
finalMap.set(key.value, value.value);
|
|
3741
|
-
}
|
|
3742
|
-
return { status: status.value, value: finalMap };
|
|
3743
|
-
});
|
|
3744
|
-
} else {
|
|
3745
|
-
const finalMap = new Map;
|
|
3746
|
-
for (const pair of pairs) {
|
|
3747
|
-
const key = pair.key;
|
|
3748
|
-
const value = pair.value;
|
|
3749
|
-
if (key.status === "aborted" || value.status === "aborted") {
|
|
3750
|
-
return INVALID;
|
|
3751
|
-
}
|
|
3752
|
-
if (key.status === "dirty" || value.status === "dirty") {
|
|
3753
|
-
status.dirty();
|
|
3754
|
-
}
|
|
3755
|
-
finalMap.set(key.value, value.value);
|
|
3756
|
-
}
|
|
3757
|
-
return { status: status.value, value: finalMap };
|
|
3758
|
-
}
|
|
3396
|
+
return { status: "valid", value: input.data };
|
|
3397
|
+
}
|
|
3398
|
+
get value() {
|
|
3399
|
+
return this._def.value;
|
|
3759
3400
|
}
|
|
3760
3401
|
}
|
|
3761
|
-
|
|
3762
|
-
return new
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
typeName: ZodFirstPartyTypeKind.ZodMap,
|
|
3402
|
+
ZodLiteral.create = (value, params) => {
|
|
3403
|
+
return new ZodLiteral({
|
|
3404
|
+
value,
|
|
3405
|
+
typeName: ZodFirstPartyTypeKind.ZodLiteral,
|
|
3766
3406
|
...processCreateParams(params)
|
|
3767
3407
|
});
|
|
3768
3408
|
};
|
|
3409
|
+
function createZodEnum(values, params) {
|
|
3410
|
+
return new ZodEnum({
|
|
3411
|
+
values,
|
|
3412
|
+
typeName: ZodFirstPartyTypeKind.ZodEnum,
|
|
3413
|
+
...processCreateParams(params)
|
|
3414
|
+
});
|
|
3415
|
+
}
|
|
3769
3416
|
|
|
3770
|
-
class
|
|
3417
|
+
class ZodEnum extends ZodType {
|
|
3771
3418
|
_parse(input) {
|
|
3772
|
-
|
|
3773
|
-
|
|
3419
|
+
if (typeof input.data !== "string") {
|
|
3420
|
+
const ctx = this._getOrReturnCtx(input);
|
|
3421
|
+
const expectedValues = this._def.values;
|
|
3774
3422
|
addIssueToContext(ctx, {
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3423
|
+
expected: util.joinValues(expectedValues),
|
|
3424
|
+
received: ctx.parsedType,
|
|
3425
|
+
code: ZodIssueCode.invalid_type
|
|
3778
3426
|
});
|
|
3779
3427
|
return INVALID;
|
|
3780
3428
|
}
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
if (ctx.data.size < def.minSize.value) {
|
|
3784
|
-
addIssueToContext(ctx, {
|
|
3785
|
-
code: ZodIssueCode.too_small,
|
|
3786
|
-
minimum: def.minSize.value,
|
|
3787
|
-
type: "set",
|
|
3788
|
-
inclusive: true,
|
|
3789
|
-
exact: false,
|
|
3790
|
-
message: def.minSize.message
|
|
3791
|
-
});
|
|
3792
|
-
status.dirty();
|
|
3793
|
-
}
|
|
3429
|
+
if (!this._cache) {
|
|
3430
|
+
this._cache = new Set(this._def.values);
|
|
3794
3431
|
}
|
|
3795
|
-
if (
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
});
|
|
3805
|
-
status.dirty();
|
|
3806
|
-
}
|
|
3432
|
+
if (!this._cache.has(input.data)) {
|
|
3433
|
+
const ctx = this._getOrReturnCtx(input);
|
|
3434
|
+
const expectedValues = this._def.values;
|
|
3435
|
+
addIssueToContext(ctx, {
|
|
3436
|
+
received: ctx.data,
|
|
3437
|
+
code: ZodIssueCode.invalid_enum_value,
|
|
3438
|
+
options: expectedValues
|
|
3439
|
+
});
|
|
3440
|
+
return INVALID;
|
|
3807
3441
|
}
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
}
|
|
3818
|
-
return { status: status.value, value: parsedSet };
|
|
3442
|
+
return OK(input.data);
|
|
3443
|
+
}
|
|
3444
|
+
get options() {
|
|
3445
|
+
return this._def.values;
|
|
3446
|
+
}
|
|
3447
|
+
get enum() {
|
|
3448
|
+
const enumValues = {};
|
|
3449
|
+
for (const val of this._def.values) {
|
|
3450
|
+
enumValues[val] = val;
|
|
3819
3451
|
}
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3452
|
+
return enumValues;
|
|
3453
|
+
}
|
|
3454
|
+
get Values() {
|
|
3455
|
+
const enumValues = {};
|
|
3456
|
+
for (const val of this._def.values) {
|
|
3457
|
+
enumValues[val] = val;
|
|
3825
3458
|
}
|
|
3459
|
+
return enumValues;
|
|
3826
3460
|
}
|
|
3827
|
-
|
|
3828
|
-
|
|
3461
|
+
get Enum() {
|
|
3462
|
+
const enumValues = {};
|
|
3463
|
+
for (const val of this._def.values) {
|
|
3464
|
+
enumValues[val] = val;
|
|
3465
|
+
}
|
|
3466
|
+
return enumValues;
|
|
3467
|
+
}
|
|
3468
|
+
extract(values, newDef = this._def) {
|
|
3469
|
+
return ZodEnum.create(values, {
|
|
3829
3470
|
...this._def,
|
|
3830
|
-
|
|
3471
|
+
...newDef
|
|
3831
3472
|
});
|
|
3832
3473
|
}
|
|
3833
|
-
|
|
3834
|
-
return
|
|
3474
|
+
exclude(values, newDef = this._def) {
|
|
3475
|
+
return ZodEnum.create(this.options.filter((opt) => !values.includes(opt)), {
|
|
3835
3476
|
...this._def,
|
|
3836
|
-
|
|
3477
|
+
...newDef
|
|
3837
3478
|
});
|
|
3838
3479
|
}
|
|
3839
|
-
|
|
3840
|
-
|
|
3480
|
+
}
|
|
3481
|
+
ZodEnum.create = createZodEnum;
|
|
3482
|
+
|
|
3483
|
+
class ZodNativeEnum extends ZodType {
|
|
3484
|
+
_parse(input) {
|
|
3485
|
+
const nativeEnumValues = util.getValidEnumValues(this._def.values);
|
|
3486
|
+
const ctx = this._getOrReturnCtx(input);
|
|
3487
|
+
if (ctx.parsedType !== ZodParsedType.string && ctx.parsedType !== ZodParsedType.number) {
|
|
3488
|
+
const expectedValues = util.objectValues(nativeEnumValues);
|
|
3489
|
+
addIssueToContext(ctx, {
|
|
3490
|
+
expected: util.joinValues(expectedValues),
|
|
3491
|
+
received: ctx.parsedType,
|
|
3492
|
+
code: ZodIssueCode.invalid_type
|
|
3493
|
+
});
|
|
3494
|
+
return INVALID;
|
|
3495
|
+
}
|
|
3496
|
+
if (!this._cache) {
|
|
3497
|
+
this._cache = new Set(util.getValidEnumValues(this._def.values));
|
|
3498
|
+
}
|
|
3499
|
+
if (!this._cache.has(input.data)) {
|
|
3500
|
+
const expectedValues = util.objectValues(nativeEnumValues);
|
|
3501
|
+
addIssueToContext(ctx, {
|
|
3502
|
+
received: ctx.data,
|
|
3503
|
+
code: ZodIssueCode.invalid_enum_value,
|
|
3504
|
+
options: expectedValues
|
|
3505
|
+
});
|
|
3506
|
+
return INVALID;
|
|
3507
|
+
}
|
|
3508
|
+
return OK(input.data);
|
|
3841
3509
|
}
|
|
3842
|
-
|
|
3843
|
-
return this.
|
|
3510
|
+
get enum() {
|
|
3511
|
+
return this._def.values;
|
|
3844
3512
|
}
|
|
3845
3513
|
}
|
|
3846
|
-
|
|
3847
|
-
return new
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
maxSize: null,
|
|
3851
|
-
typeName: ZodFirstPartyTypeKind.ZodSet,
|
|
3514
|
+
ZodNativeEnum.create = (values, params) => {
|
|
3515
|
+
return new ZodNativeEnum({
|
|
3516
|
+
values,
|
|
3517
|
+
typeName: ZodFirstPartyTypeKind.ZodNativeEnum,
|
|
3852
3518
|
...processCreateParams(params)
|
|
3853
3519
|
});
|
|
3854
3520
|
};
|
|
3855
3521
|
|
|
3856
|
-
class
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
this.validate = this.implement;
|
|
3522
|
+
class ZodPromise extends ZodType {
|
|
3523
|
+
unwrap() {
|
|
3524
|
+
return this._def.type;
|
|
3860
3525
|
}
|
|
3861
3526
|
_parse(input) {
|
|
3862
3527
|
const { ctx } = this._processInputParams(input);
|
|
3863
|
-
if (ctx.parsedType !== ZodParsedType.
|
|
3528
|
+
if (ctx.parsedType !== ZodParsedType.promise && ctx.common.async === false) {
|
|
3864
3529
|
addIssueToContext(ctx, {
|
|
3865
3530
|
code: ZodIssueCode.invalid_type,
|
|
3866
|
-
expected: ZodParsedType.
|
|
3531
|
+
expected: ZodParsedType.promise,
|
|
3867
3532
|
received: ctx.parsedType
|
|
3868
3533
|
});
|
|
3869
3534
|
return INVALID;
|
|
3870
3535
|
}
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3536
|
+
const promisified = ctx.parsedType === ZodParsedType.promise ? ctx.data : Promise.resolve(ctx.data);
|
|
3537
|
+
return OK(promisified.then((data) => {
|
|
3538
|
+
return this._def.type.parseAsync(data, {
|
|
3874
3539
|
path: ctx.path,
|
|
3875
|
-
|
|
3876
|
-
issueData: {
|
|
3877
|
-
code: ZodIssueCode.invalid_arguments,
|
|
3878
|
-
argumentsError: error
|
|
3879
|
-
}
|
|
3540
|
+
errorMap: ctx.common.contextualErrorMap
|
|
3880
3541
|
});
|
|
3881
|
-
}
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3542
|
+
}));
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
ZodPromise.create = (schema, params) => {
|
|
3546
|
+
return new ZodPromise({
|
|
3547
|
+
type: schema,
|
|
3548
|
+
typeName: ZodFirstPartyTypeKind.ZodPromise,
|
|
3549
|
+
...processCreateParams(params)
|
|
3550
|
+
});
|
|
3551
|
+
};
|
|
3552
|
+
|
|
3553
|
+
class ZodEffects extends ZodType {
|
|
3554
|
+
innerType() {
|
|
3555
|
+
return this._def.schema;
|
|
3556
|
+
}
|
|
3557
|
+
sourceType() {
|
|
3558
|
+
return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects ? this._def.schema.sourceType() : this._def.schema;
|
|
3559
|
+
}
|
|
3560
|
+
_parse(input) {
|
|
3561
|
+
const { status, ctx } = this._processInputParams(input);
|
|
3562
|
+
const effect = this._def.effect || null;
|
|
3563
|
+
const checkCtx = {
|
|
3564
|
+
addIssue: (arg) => {
|
|
3565
|
+
addIssueToContext(ctx, arg);
|
|
3566
|
+
if (arg.fatal) {
|
|
3567
|
+
status.abort();
|
|
3568
|
+
} else {
|
|
3569
|
+
status.dirty();
|
|
3890
3570
|
}
|
|
3891
|
-
}
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3571
|
+
},
|
|
3572
|
+
get path() {
|
|
3573
|
+
return ctx.path;
|
|
3574
|
+
}
|
|
3575
|
+
};
|
|
3576
|
+
checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx);
|
|
3577
|
+
if (effect.type === "preprocess") {
|
|
3578
|
+
const processed = effect.transform(ctx.data, checkCtx);
|
|
3579
|
+
if (ctx.common.async) {
|
|
3580
|
+
return Promise.resolve(processed).then(async (processed2) => {
|
|
3581
|
+
if (status.value === "aborted")
|
|
3582
|
+
return INVALID;
|
|
3583
|
+
const result = await this._def.schema._parseAsync({
|
|
3584
|
+
data: processed2,
|
|
3585
|
+
path: ctx.path,
|
|
3586
|
+
parent: ctx
|
|
3587
|
+
});
|
|
3588
|
+
if (result.status === "aborted")
|
|
3589
|
+
return INVALID;
|
|
3590
|
+
if (result.status === "dirty")
|
|
3591
|
+
return DIRTY(result.value);
|
|
3592
|
+
if (status.value === "dirty")
|
|
3593
|
+
return DIRTY(result.value);
|
|
3594
|
+
return result;
|
|
3902
3595
|
});
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3596
|
+
} else {
|
|
3597
|
+
if (status.value === "aborted")
|
|
3598
|
+
return INVALID;
|
|
3599
|
+
const result = this._def.schema._parseSync({
|
|
3600
|
+
data: processed,
|
|
3601
|
+
path: ctx.path,
|
|
3602
|
+
parent: ctx
|
|
3907
3603
|
});
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3604
|
+
if (result.status === "aborted")
|
|
3605
|
+
return INVALID;
|
|
3606
|
+
if (result.status === "dirty")
|
|
3607
|
+
return DIRTY(result.value);
|
|
3608
|
+
if (status.value === "dirty")
|
|
3609
|
+
return DIRTY(result.value);
|
|
3610
|
+
return result;
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
if (effect.type === "refinement") {
|
|
3614
|
+
const executeRefinement = (acc) => {
|
|
3615
|
+
const result = effect.refinement(acc, checkCtx);
|
|
3616
|
+
if (ctx.common.async) {
|
|
3617
|
+
return Promise.resolve(result);
|
|
3916
3618
|
}
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
if (!parsedReturns.success) {
|
|
3920
|
-
throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]);
|
|
3619
|
+
if (result instanceof Promise) {
|
|
3620
|
+
throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");
|
|
3921
3621
|
}
|
|
3922
|
-
return
|
|
3923
|
-
}
|
|
3622
|
+
return acc;
|
|
3623
|
+
};
|
|
3624
|
+
if (ctx.common.async === false) {
|
|
3625
|
+
const inner = this._def.schema._parseSync({
|
|
3626
|
+
data: ctx.data,
|
|
3627
|
+
path: ctx.path,
|
|
3628
|
+
parent: ctx
|
|
3629
|
+
});
|
|
3630
|
+
if (inner.status === "aborted")
|
|
3631
|
+
return INVALID;
|
|
3632
|
+
if (inner.status === "dirty")
|
|
3633
|
+
status.dirty();
|
|
3634
|
+
executeRefinement(inner.value);
|
|
3635
|
+
return { status: status.value, value: inner.value };
|
|
3636
|
+
} else {
|
|
3637
|
+
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => {
|
|
3638
|
+
if (inner.status === "aborted")
|
|
3639
|
+
return INVALID;
|
|
3640
|
+
if (inner.status === "dirty")
|
|
3641
|
+
status.dirty();
|
|
3642
|
+
return executeRefinement(inner.value).then(() => {
|
|
3643
|
+
return { status: status.value, value: inner.value };
|
|
3644
|
+
});
|
|
3645
|
+
});
|
|
3646
|
+
}
|
|
3924
3647
|
}
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
}
|
|
3952
|
-
static create(args, returns, params) {
|
|
3953
|
-
return new ZodFunction({
|
|
3954
|
-
args: args ? args : ZodTuple.create([]).rest(ZodUnknown.create()),
|
|
3955
|
-
returns: returns || ZodUnknown.create(),
|
|
3956
|
-
typeName: ZodFirstPartyTypeKind.ZodFunction,
|
|
3957
|
-
...processCreateParams(params)
|
|
3958
|
-
});
|
|
3648
|
+
if (effect.type === "transform") {
|
|
3649
|
+
if (ctx.common.async === false) {
|
|
3650
|
+
const base = this._def.schema._parseSync({
|
|
3651
|
+
data: ctx.data,
|
|
3652
|
+
path: ctx.path,
|
|
3653
|
+
parent: ctx
|
|
3654
|
+
});
|
|
3655
|
+
if (!isValid(base))
|
|
3656
|
+
return INVALID;
|
|
3657
|
+
const result = effect.transform(base.value, checkCtx);
|
|
3658
|
+
if (result instanceof Promise) {
|
|
3659
|
+
throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
|
|
3660
|
+
}
|
|
3661
|
+
return { status: status.value, value: result };
|
|
3662
|
+
} else {
|
|
3663
|
+
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => {
|
|
3664
|
+
if (!isValid(base))
|
|
3665
|
+
return INVALID;
|
|
3666
|
+
return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({
|
|
3667
|
+
status: status.value,
|
|
3668
|
+
value: result
|
|
3669
|
+
}));
|
|
3670
|
+
});
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
util.assertNever(effect);
|
|
3959
3674
|
}
|
|
3960
3675
|
}
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3676
|
+
ZodEffects.create = (schema, effect, params) => {
|
|
3677
|
+
return new ZodEffects({
|
|
3678
|
+
schema,
|
|
3679
|
+
typeName: ZodFirstPartyTypeKind.ZodEffects,
|
|
3680
|
+
effect,
|
|
3681
|
+
...processCreateParams(params)
|
|
3682
|
+
});
|
|
3683
|
+
};
|
|
3684
|
+
ZodEffects.createWithPreprocess = (preprocess, schema, params) => {
|
|
3685
|
+
return new ZodEffects({
|
|
3686
|
+
schema,
|
|
3687
|
+
effect: { type: "preprocess", transform: preprocess },
|
|
3688
|
+
typeName: ZodFirstPartyTypeKind.ZodEffects,
|
|
3689
|
+
...processCreateParams(params)
|
|
3690
|
+
});
|
|
3691
|
+
};
|
|
3692
|
+
class ZodOptional extends ZodType {
|
|
3693
|
+
_parse(input) {
|
|
3694
|
+
const parsedType = this._getType(input);
|
|
3695
|
+
if (parsedType === ZodParsedType.undefined) {
|
|
3696
|
+
return OK(undefined);
|
|
3697
|
+
}
|
|
3698
|
+
return this._def.innerType._parse(input);
|
|
3965
3699
|
}
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
const lazySchema = this._def.getter();
|
|
3969
|
-
return lazySchema._parse({ data: ctx.data, path: ctx.path, parent: ctx });
|
|
3700
|
+
unwrap() {
|
|
3701
|
+
return this._def.innerType;
|
|
3970
3702
|
}
|
|
3971
3703
|
}
|
|
3972
|
-
|
|
3973
|
-
return new
|
|
3974
|
-
|
|
3975
|
-
typeName: ZodFirstPartyTypeKind.
|
|
3704
|
+
ZodOptional.create = (type, params) => {
|
|
3705
|
+
return new ZodOptional({
|
|
3706
|
+
innerType: type,
|
|
3707
|
+
typeName: ZodFirstPartyTypeKind.ZodOptional,
|
|
3976
3708
|
...processCreateParams(params)
|
|
3977
3709
|
});
|
|
3978
3710
|
};
|
|
3979
3711
|
|
|
3980
|
-
class
|
|
3712
|
+
class ZodNullable extends ZodType {
|
|
3981
3713
|
_parse(input) {
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
received: ctx.data,
|
|
3986
|
-
code: ZodIssueCode.invalid_literal,
|
|
3987
|
-
expected: this._def.value
|
|
3988
|
-
});
|
|
3989
|
-
return INVALID;
|
|
3714
|
+
const parsedType = this._getType(input);
|
|
3715
|
+
if (parsedType === ZodParsedType.null) {
|
|
3716
|
+
return OK(null);
|
|
3990
3717
|
}
|
|
3991
|
-
return
|
|
3718
|
+
return this._def.innerType._parse(input);
|
|
3992
3719
|
}
|
|
3993
|
-
|
|
3994
|
-
return this._def.
|
|
3720
|
+
unwrap() {
|
|
3721
|
+
return this._def.innerType;
|
|
3995
3722
|
}
|
|
3996
3723
|
}
|
|
3997
|
-
|
|
3998
|
-
return new
|
|
3999
|
-
|
|
4000
|
-
typeName: ZodFirstPartyTypeKind.
|
|
3724
|
+
ZodNullable.create = (type, params) => {
|
|
3725
|
+
return new ZodNullable({
|
|
3726
|
+
innerType: type,
|
|
3727
|
+
typeName: ZodFirstPartyTypeKind.ZodNullable,
|
|
4001
3728
|
...processCreateParams(params)
|
|
4002
3729
|
});
|
|
4003
3730
|
};
|
|
4004
|
-
function createZodEnum(values, params) {
|
|
4005
|
-
return new ZodEnum({
|
|
4006
|
-
values,
|
|
4007
|
-
typeName: ZodFirstPartyTypeKind.ZodEnum,
|
|
4008
|
-
...processCreateParams(params)
|
|
4009
|
-
});
|
|
4010
|
-
}
|
|
4011
3731
|
|
|
4012
|
-
class
|
|
3732
|
+
class ZodDefault extends ZodType {
|
|
4013
3733
|
_parse(input) {
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
expected: util.joinValues(expectedValues),
|
|
4019
|
-
received: ctx.parsedType,
|
|
4020
|
-
code: ZodIssueCode.invalid_type
|
|
4021
|
-
});
|
|
4022
|
-
return INVALID;
|
|
4023
|
-
}
|
|
4024
|
-
if (!this._cache) {
|
|
4025
|
-
this._cache = new Set(this._def.values);
|
|
4026
|
-
}
|
|
4027
|
-
if (!this._cache.has(input.data)) {
|
|
4028
|
-
const ctx = this._getOrReturnCtx(input);
|
|
4029
|
-
const expectedValues = this._def.values;
|
|
4030
|
-
addIssueToContext(ctx, {
|
|
4031
|
-
received: ctx.data,
|
|
4032
|
-
code: ZodIssueCode.invalid_enum_value,
|
|
4033
|
-
options: expectedValues
|
|
4034
|
-
});
|
|
4035
|
-
return INVALID;
|
|
4036
|
-
}
|
|
4037
|
-
return OK(input.data);
|
|
4038
|
-
}
|
|
4039
|
-
get options() {
|
|
4040
|
-
return this._def.values;
|
|
4041
|
-
}
|
|
4042
|
-
get enum() {
|
|
4043
|
-
const enumValues = {};
|
|
4044
|
-
for (const val of this._def.values) {
|
|
4045
|
-
enumValues[val] = val;
|
|
4046
|
-
}
|
|
4047
|
-
return enumValues;
|
|
4048
|
-
}
|
|
4049
|
-
get Values() {
|
|
4050
|
-
const enumValues = {};
|
|
4051
|
-
for (const val of this._def.values) {
|
|
4052
|
-
enumValues[val] = val;
|
|
4053
|
-
}
|
|
4054
|
-
return enumValues;
|
|
4055
|
-
}
|
|
4056
|
-
get Enum() {
|
|
4057
|
-
const enumValues = {};
|
|
4058
|
-
for (const val of this._def.values) {
|
|
4059
|
-
enumValues[val] = val;
|
|
3734
|
+
const { ctx } = this._processInputParams(input);
|
|
3735
|
+
let data = ctx.data;
|
|
3736
|
+
if (ctx.parsedType === ZodParsedType.undefined) {
|
|
3737
|
+
data = this._def.defaultValue();
|
|
4060
3738
|
}
|
|
4061
|
-
return
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
...this._def,
|
|
4066
|
-
...newDef
|
|
3739
|
+
return this._def.innerType._parse({
|
|
3740
|
+
data,
|
|
3741
|
+
path: ctx.path,
|
|
3742
|
+
parent: ctx
|
|
4067
3743
|
});
|
|
4068
3744
|
}
|
|
4069
|
-
|
|
4070
|
-
return
|
|
4071
|
-
...this._def,
|
|
4072
|
-
...newDef
|
|
4073
|
-
});
|
|
3745
|
+
removeDefault() {
|
|
3746
|
+
return this._def.innerType;
|
|
4074
3747
|
}
|
|
4075
3748
|
}
|
|
4076
|
-
|
|
3749
|
+
ZodDefault.create = (type, params) => {
|
|
3750
|
+
return new ZodDefault({
|
|
3751
|
+
innerType: type,
|
|
3752
|
+
typeName: ZodFirstPartyTypeKind.ZodDefault,
|
|
3753
|
+
defaultValue: typeof params.default === "function" ? params.default : () => params.default,
|
|
3754
|
+
...processCreateParams(params)
|
|
3755
|
+
});
|
|
3756
|
+
};
|
|
4077
3757
|
|
|
4078
|
-
class
|
|
3758
|
+
class ZodCatch extends ZodType {
|
|
4079
3759
|
_parse(input) {
|
|
4080
|
-
const
|
|
4081
|
-
const
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
3760
|
+
const { ctx } = this._processInputParams(input);
|
|
3761
|
+
const newCtx = {
|
|
3762
|
+
...ctx,
|
|
3763
|
+
common: {
|
|
3764
|
+
...ctx.common,
|
|
3765
|
+
issues: []
|
|
3766
|
+
}
|
|
3767
|
+
};
|
|
3768
|
+
const result = this._def.innerType._parse({
|
|
3769
|
+
data: newCtx.data,
|
|
3770
|
+
path: newCtx.path,
|
|
3771
|
+
parent: {
|
|
3772
|
+
...newCtx
|
|
3773
|
+
}
|
|
3774
|
+
});
|
|
3775
|
+
if (isAsync(result)) {
|
|
3776
|
+
return result.then((result2) => {
|
|
3777
|
+
return {
|
|
3778
|
+
status: "valid",
|
|
3779
|
+
value: result2.status === "valid" ? result2.value : this._def.catchValue({
|
|
3780
|
+
get error() {
|
|
3781
|
+
return new ZodError(newCtx.common.issues);
|
|
3782
|
+
},
|
|
3783
|
+
input: newCtx.data
|
|
3784
|
+
})
|
|
3785
|
+
};
|
|
4100
3786
|
});
|
|
4101
|
-
|
|
3787
|
+
} else {
|
|
3788
|
+
return {
|
|
3789
|
+
status: "valid",
|
|
3790
|
+
value: result.status === "valid" ? result.value : this._def.catchValue({
|
|
3791
|
+
get error() {
|
|
3792
|
+
return new ZodError(newCtx.common.issues);
|
|
3793
|
+
},
|
|
3794
|
+
input: newCtx.data
|
|
3795
|
+
})
|
|
3796
|
+
};
|
|
4102
3797
|
}
|
|
4103
|
-
return OK(input.data);
|
|
4104
3798
|
}
|
|
4105
|
-
|
|
4106
|
-
return this._def.
|
|
3799
|
+
removeCatch() {
|
|
3800
|
+
return this._def.innerType;
|
|
4107
3801
|
}
|
|
4108
3802
|
}
|
|
4109
|
-
|
|
4110
|
-
return new
|
|
4111
|
-
|
|
4112
|
-
typeName: ZodFirstPartyTypeKind.
|
|
3803
|
+
ZodCatch.create = (type, params) => {
|
|
3804
|
+
return new ZodCatch({
|
|
3805
|
+
innerType: type,
|
|
3806
|
+
typeName: ZodFirstPartyTypeKind.ZodCatch,
|
|
3807
|
+
catchValue: typeof params.catch === "function" ? params.catch : () => params.catch,
|
|
4113
3808
|
...processCreateParams(params)
|
|
4114
3809
|
});
|
|
4115
3810
|
};
|
|
4116
3811
|
|
|
4117
|
-
class
|
|
4118
|
-
unwrap() {
|
|
4119
|
-
return this._def.type;
|
|
4120
|
-
}
|
|
3812
|
+
class ZodNaN extends ZodType {
|
|
4121
3813
|
_parse(input) {
|
|
4122
|
-
const
|
|
4123
|
-
if (
|
|
3814
|
+
const parsedType = this._getType(input);
|
|
3815
|
+
if (parsedType !== ZodParsedType.nan) {
|
|
3816
|
+
const ctx = this._getOrReturnCtx(input);
|
|
4124
3817
|
addIssueToContext(ctx, {
|
|
4125
3818
|
code: ZodIssueCode.invalid_type,
|
|
4126
|
-
expected: ZodParsedType.
|
|
3819
|
+
expected: ZodParsedType.nan,
|
|
4127
3820
|
received: ctx.parsedType
|
|
4128
3821
|
});
|
|
4129
3822
|
return INVALID;
|
|
4130
3823
|
}
|
|
4131
|
-
|
|
4132
|
-
return OK(promisified.then((data) => {
|
|
4133
|
-
return this._def.type.parseAsync(data, {
|
|
4134
|
-
path: ctx.path,
|
|
4135
|
-
errorMap: ctx.common.contextualErrorMap
|
|
4136
|
-
});
|
|
4137
|
-
}));
|
|
3824
|
+
return { status: "valid", value: input.data };
|
|
4138
3825
|
}
|
|
4139
3826
|
}
|
|
4140
|
-
|
|
4141
|
-
return new
|
|
4142
|
-
|
|
4143
|
-
typeName: ZodFirstPartyTypeKind.ZodPromise,
|
|
3827
|
+
ZodNaN.create = (params) => {
|
|
3828
|
+
return new ZodNaN({
|
|
3829
|
+
typeName: ZodFirstPartyTypeKind.ZodNaN,
|
|
4144
3830
|
...processCreateParams(params)
|
|
4145
3831
|
});
|
|
4146
3832
|
};
|
|
3833
|
+
var BRAND = Symbol("zod_brand");
|
|
4147
3834
|
|
|
4148
|
-
class
|
|
4149
|
-
|
|
4150
|
-
|
|
3835
|
+
class ZodBranded extends ZodType {
|
|
3836
|
+
_parse(input) {
|
|
3837
|
+
const { ctx } = this._processInputParams(input);
|
|
3838
|
+
const data = ctx.data;
|
|
3839
|
+
return this._def.type._parse({
|
|
3840
|
+
data,
|
|
3841
|
+
path: ctx.path,
|
|
3842
|
+
parent: ctx
|
|
3843
|
+
});
|
|
4151
3844
|
}
|
|
4152
|
-
|
|
4153
|
-
return this._def.
|
|
3845
|
+
unwrap() {
|
|
3846
|
+
return this._def.type;
|
|
4154
3847
|
}
|
|
3848
|
+
}
|
|
3849
|
+
|
|
3850
|
+
class ZodPipeline extends ZodType {
|
|
4155
3851
|
_parse(input) {
|
|
4156
3852
|
const { status, ctx } = this._processInputParams(input);
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
}
|
|
3853
|
+
if (ctx.common.async) {
|
|
3854
|
+
const handleAsync = async () => {
|
|
3855
|
+
const inResult = await this._def.in._parseAsync({
|
|
3856
|
+
data: ctx.data,
|
|
3857
|
+
path: ctx.path,
|
|
3858
|
+
parent: ctx
|
|
3859
|
+
});
|
|
3860
|
+
if (inResult.status === "aborted")
|
|
3861
|
+
return INVALID;
|
|
3862
|
+
if (inResult.status === "dirty") {
|
|
4164
3863
|
status.dirty();
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
}
|
|
4170
|
-
};
|
|
4171
|
-
checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx);
|
|
4172
|
-
if (effect.type === "preprocess") {
|
|
4173
|
-
const processed = effect.transform(ctx.data, checkCtx);
|
|
4174
|
-
if (ctx.common.async) {
|
|
4175
|
-
return Promise.resolve(processed).then(async (processed2) => {
|
|
4176
|
-
if (status.value === "aborted")
|
|
4177
|
-
return INVALID;
|
|
4178
|
-
const result = await this._def.schema._parseAsync({
|
|
4179
|
-
data: processed2,
|
|
3864
|
+
return DIRTY(inResult.value);
|
|
3865
|
+
} else {
|
|
3866
|
+
return this._def.out._parseAsync({
|
|
3867
|
+
data: inResult.value,
|
|
4180
3868
|
path: ctx.path,
|
|
4181
3869
|
parent: ctx
|
|
4182
3870
|
});
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
3871
|
+
}
|
|
3872
|
+
};
|
|
3873
|
+
return handleAsync();
|
|
3874
|
+
} else {
|
|
3875
|
+
const inResult = this._def.in._parseSync({
|
|
3876
|
+
data: ctx.data,
|
|
3877
|
+
path: ctx.path,
|
|
3878
|
+
parent: ctx
|
|
3879
|
+
});
|
|
3880
|
+
if (inResult.status === "aborted")
|
|
3881
|
+
return INVALID;
|
|
3882
|
+
if (inResult.status === "dirty") {
|
|
3883
|
+
status.dirty();
|
|
3884
|
+
return {
|
|
3885
|
+
status: "dirty",
|
|
3886
|
+
value: inResult.value
|
|
3887
|
+
};
|
|
4191
3888
|
} else {
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
const result = this._def.schema._parseSync({
|
|
4195
|
-
data: processed,
|
|
3889
|
+
return this._def.out._parseSync({
|
|
3890
|
+
data: inResult.value,
|
|
4196
3891
|
path: ctx.path,
|
|
4197
3892
|
parent: ctx
|
|
4198
3893
|
});
|
|
4199
|
-
if (result.status === "aborted")
|
|
4200
|
-
return INVALID;
|
|
4201
|
-
if (result.status === "dirty")
|
|
4202
|
-
return DIRTY(result.value);
|
|
4203
|
-
if (status.value === "dirty")
|
|
4204
|
-
return DIRTY(result.value);
|
|
4205
|
-
return result;
|
|
4206
3894
|
}
|
|
4207
3895
|
}
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
3896
|
+
}
|
|
3897
|
+
static create(a, b) {
|
|
3898
|
+
return new ZodPipeline({
|
|
3899
|
+
in: a,
|
|
3900
|
+
out: b,
|
|
3901
|
+
typeName: ZodFirstPartyTypeKind.ZodPipeline
|
|
3902
|
+
});
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
|
|
3906
|
+
class ZodReadonly extends ZodType {
|
|
3907
|
+
_parse(input) {
|
|
3908
|
+
const result = this._def.innerType._parse(input);
|
|
3909
|
+
const freeze = (data) => {
|
|
3910
|
+
if (isValid(data)) {
|
|
3911
|
+
data.value = Object.freeze(data.value);
|
|
3912
|
+
}
|
|
3913
|
+
return data;
|
|
3914
|
+
};
|
|
3915
|
+
return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result);
|
|
3916
|
+
}
|
|
3917
|
+
unwrap() {
|
|
3918
|
+
return this._def.innerType;
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
ZodReadonly.create = (type, params) => {
|
|
3922
|
+
return new ZodReadonly({
|
|
3923
|
+
innerType: type,
|
|
3924
|
+
typeName: ZodFirstPartyTypeKind.ZodReadonly,
|
|
3925
|
+
...processCreateParams(params)
|
|
3926
|
+
});
|
|
3927
|
+
};
|
|
3928
|
+
function cleanParams(params, data) {
|
|
3929
|
+
const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params;
|
|
3930
|
+
const p2 = typeof p === "string" ? { message: p } : p;
|
|
3931
|
+
return p2;
|
|
3932
|
+
}
|
|
3933
|
+
function custom(check, _params = {}, fatal) {
|
|
3934
|
+
if (check)
|
|
3935
|
+
return ZodAny.create().superRefine((data, ctx) => {
|
|
3936
|
+
const r = check(data);
|
|
3937
|
+
if (r instanceof Promise) {
|
|
3938
|
+
return r.then((r2) => {
|
|
3939
|
+
if (!r2) {
|
|
3940
|
+
const params = cleanParams(_params, data);
|
|
3941
|
+
const _fatal = params.fatal ?? fatal ?? true;
|
|
3942
|
+
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
|
|
3943
|
+
}
|
|
4240
3944
|
});
|
|
4241
3945
|
}
|
|
3946
|
+
if (!r) {
|
|
3947
|
+
const params = cleanParams(_params, data);
|
|
3948
|
+
const _fatal = params.fatal ?? fatal ?? true;
|
|
3949
|
+
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
|
|
3950
|
+
}
|
|
3951
|
+
return;
|
|
3952
|
+
});
|
|
3953
|
+
return ZodAny.create();
|
|
3954
|
+
}
|
|
3955
|
+
var late = {
|
|
3956
|
+
object: ZodObject.lazycreate
|
|
3957
|
+
};
|
|
3958
|
+
var ZodFirstPartyTypeKind;
|
|
3959
|
+
(function(ZodFirstPartyTypeKind2) {
|
|
3960
|
+
ZodFirstPartyTypeKind2["ZodString"] = "ZodString";
|
|
3961
|
+
ZodFirstPartyTypeKind2["ZodNumber"] = "ZodNumber";
|
|
3962
|
+
ZodFirstPartyTypeKind2["ZodNaN"] = "ZodNaN";
|
|
3963
|
+
ZodFirstPartyTypeKind2["ZodBigInt"] = "ZodBigInt";
|
|
3964
|
+
ZodFirstPartyTypeKind2["ZodBoolean"] = "ZodBoolean";
|
|
3965
|
+
ZodFirstPartyTypeKind2["ZodDate"] = "ZodDate";
|
|
3966
|
+
ZodFirstPartyTypeKind2["ZodSymbol"] = "ZodSymbol";
|
|
3967
|
+
ZodFirstPartyTypeKind2["ZodUndefined"] = "ZodUndefined";
|
|
3968
|
+
ZodFirstPartyTypeKind2["ZodNull"] = "ZodNull";
|
|
3969
|
+
ZodFirstPartyTypeKind2["ZodAny"] = "ZodAny";
|
|
3970
|
+
ZodFirstPartyTypeKind2["ZodUnknown"] = "ZodUnknown";
|
|
3971
|
+
ZodFirstPartyTypeKind2["ZodNever"] = "ZodNever";
|
|
3972
|
+
ZodFirstPartyTypeKind2["ZodVoid"] = "ZodVoid";
|
|
3973
|
+
ZodFirstPartyTypeKind2["ZodArray"] = "ZodArray";
|
|
3974
|
+
ZodFirstPartyTypeKind2["ZodObject"] = "ZodObject";
|
|
3975
|
+
ZodFirstPartyTypeKind2["ZodUnion"] = "ZodUnion";
|
|
3976
|
+
ZodFirstPartyTypeKind2["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion";
|
|
3977
|
+
ZodFirstPartyTypeKind2["ZodIntersection"] = "ZodIntersection";
|
|
3978
|
+
ZodFirstPartyTypeKind2["ZodTuple"] = "ZodTuple";
|
|
3979
|
+
ZodFirstPartyTypeKind2["ZodRecord"] = "ZodRecord";
|
|
3980
|
+
ZodFirstPartyTypeKind2["ZodMap"] = "ZodMap";
|
|
3981
|
+
ZodFirstPartyTypeKind2["ZodSet"] = "ZodSet";
|
|
3982
|
+
ZodFirstPartyTypeKind2["ZodFunction"] = "ZodFunction";
|
|
3983
|
+
ZodFirstPartyTypeKind2["ZodLazy"] = "ZodLazy";
|
|
3984
|
+
ZodFirstPartyTypeKind2["ZodLiteral"] = "ZodLiteral";
|
|
3985
|
+
ZodFirstPartyTypeKind2["ZodEnum"] = "ZodEnum";
|
|
3986
|
+
ZodFirstPartyTypeKind2["ZodEffects"] = "ZodEffects";
|
|
3987
|
+
ZodFirstPartyTypeKind2["ZodNativeEnum"] = "ZodNativeEnum";
|
|
3988
|
+
ZodFirstPartyTypeKind2["ZodOptional"] = "ZodOptional";
|
|
3989
|
+
ZodFirstPartyTypeKind2["ZodNullable"] = "ZodNullable";
|
|
3990
|
+
ZodFirstPartyTypeKind2["ZodDefault"] = "ZodDefault";
|
|
3991
|
+
ZodFirstPartyTypeKind2["ZodCatch"] = "ZodCatch";
|
|
3992
|
+
ZodFirstPartyTypeKind2["ZodPromise"] = "ZodPromise";
|
|
3993
|
+
ZodFirstPartyTypeKind2["ZodBranded"] = "ZodBranded";
|
|
3994
|
+
ZodFirstPartyTypeKind2["ZodPipeline"] = "ZodPipeline";
|
|
3995
|
+
ZodFirstPartyTypeKind2["ZodReadonly"] = "ZodReadonly";
|
|
3996
|
+
})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
3997
|
+
var instanceOfType = (cls, params = {
|
|
3998
|
+
message: `Input not instance of ${cls.name}`
|
|
3999
|
+
}) => custom((data) => data instanceof cls, params);
|
|
4000
|
+
var stringType = ZodString.create;
|
|
4001
|
+
var numberType = ZodNumber.create;
|
|
4002
|
+
var nanType = ZodNaN.create;
|
|
4003
|
+
var bigIntType = ZodBigInt.create;
|
|
4004
|
+
var booleanType = ZodBoolean.create;
|
|
4005
|
+
var dateType = ZodDate.create;
|
|
4006
|
+
var symbolType = ZodSymbol.create;
|
|
4007
|
+
var undefinedType = ZodUndefined.create;
|
|
4008
|
+
var nullType = ZodNull.create;
|
|
4009
|
+
var anyType = ZodAny.create;
|
|
4010
|
+
var unknownType = ZodUnknown.create;
|
|
4011
|
+
var neverType = ZodNever.create;
|
|
4012
|
+
var voidType = ZodVoid.create;
|
|
4013
|
+
var arrayType = ZodArray.create;
|
|
4014
|
+
var objectType = ZodObject.create;
|
|
4015
|
+
var strictObjectType = ZodObject.strictCreate;
|
|
4016
|
+
var unionType = ZodUnion.create;
|
|
4017
|
+
var discriminatedUnionType = ZodDiscriminatedUnion.create;
|
|
4018
|
+
var intersectionType = ZodIntersection.create;
|
|
4019
|
+
var tupleType = ZodTuple.create;
|
|
4020
|
+
var recordType = ZodRecord.create;
|
|
4021
|
+
var mapType = ZodMap.create;
|
|
4022
|
+
var setType = ZodSet.create;
|
|
4023
|
+
var functionType = ZodFunction.create;
|
|
4024
|
+
var lazyType = ZodLazy.create;
|
|
4025
|
+
var literalType = ZodLiteral.create;
|
|
4026
|
+
var enumType = ZodEnum.create;
|
|
4027
|
+
var nativeEnumType = ZodNativeEnum.create;
|
|
4028
|
+
var promiseType = ZodPromise.create;
|
|
4029
|
+
var effectsType = ZodEffects.create;
|
|
4030
|
+
var optionalType = ZodOptional.create;
|
|
4031
|
+
var nullableType = ZodNullable.create;
|
|
4032
|
+
var preprocessType = ZodEffects.createWithPreprocess;
|
|
4033
|
+
var pipelineType = ZodPipeline.create;
|
|
4034
|
+
var ostring = () => stringType().optional();
|
|
4035
|
+
var onumber = () => numberType().optional();
|
|
4036
|
+
var oboolean = () => booleanType().optional();
|
|
4037
|
+
var coerce = {
|
|
4038
|
+
string: (arg) => ZodString.create({ ...arg, coerce: true }),
|
|
4039
|
+
number: (arg) => ZodNumber.create({ ...arg, coerce: true }),
|
|
4040
|
+
boolean: (arg) => ZodBoolean.create({
|
|
4041
|
+
...arg,
|
|
4042
|
+
coerce: true
|
|
4043
|
+
}),
|
|
4044
|
+
bigint: (arg) => ZodBigInt.create({ ...arg, coerce: true }),
|
|
4045
|
+
date: (arg) => ZodDate.create({ ...arg, coerce: true })
|
|
4046
|
+
};
|
|
4047
|
+
var NEVER = INVALID;
|
|
4048
|
+
// src/types.ts
|
|
4049
|
+
var asZodObject = (s) => s;
|
|
4050
|
+
|
|
4051
|
+
// src/schema.ts
|
|
4052
|
+
function parseRelationsConfig(relations, schemas) {
|
|
4053
|
+
const relationships = [];
|
|
4054
|
+
const added = new Set;
|
|
4055
|
+
for (const [fromTable, rels] of Object.entries(relations)) {
|
|
4056
|
+
if (!schemas[fromTable]) {
|
|
4057
|
+
throw new Error(`relations: unknown table '${fromTable}'`);
|
|
4242
4058
|
}
|
|
4243
|
-
|
|
4244
|
-
if (
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4059
|
+
for (const [fkColumn, toTable] of Object.entries(rels)) {
|
|
4060
|
+
if (!schemas[toTable]) {
|
|
4061
|
+
throw new Error(`relations: unknown target table '${toTable}' in ${fromTable}.${fkColumn}`);
|
|
4062
|
+
}
|
|
4063
|
+
const navField = fkColumn.replace(/_id$/, "");
|
|
4064
|
+
const btKey = `${fromTable}.${fkColumn}:belongs-to`;
|
|
4065
|
+
if (!added.has(btKey)) {
|
|
4066
|
+
relationships.push({
|
|
4067
|
+
type: "belongs-to",
|
|
4068
|
+
from: fromTable,
|
|
4069
|
+
to: toTable,
|
|
4070
|
+
relationshipField: navField,
|
|
4071
|
+
foreignKey: fkColumn
|
|
4249
4072
|
});
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
return INVALID;
|
|
4261
|
-
return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({
|
|
4262
|
-
status: status.value,
|
|
4263
|
-
value: result
|
|
4264
|
-
}));
|
|
4073
|
+
added.add(btKey);
|
|
4074
|
+
}
|
|
4075
|
+
const otmKey = `${toTable}.${fromTable}:one-to-many`;
|
|
4076
|
+
if (!added.has(otmKey)) {
|
|
4077
|
+
relationships.push({
|
|
4078
|
+
type: "one-to-many",
|
|
4079
|
+
from: toTable,
|
|
4080
|
+
to: fromTable,
|
|
4081
|
+
relationshipField: fromTable,
|
|
4082
|
+
foreignKey: ""
|
|
4265
4083
|
});
|
|
4084
|
+
added.add(otmKey);
|
|
4266
4085
|
}
|
|
4267
4086
|
}
|
|
4268
|
-
util.assertNever(effect);
|
|
4269
4087
|
}
|
|
4088
|
+
return relationships;
|
|
4270
4089
|
}
|
|
4271
|
-
|
|
4272
|
-
return
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
});
|
|
4278
|
-
};
|
|
4279
|
-
ZodEffects.createWithPreprocess = (preprocess, schema, params) => {
|
|
4280
|
-
return new ZodEffects({
|
|
4281
|
-
schema,
|
|
4282
|
-
effect: { type: "preprocess", transform: preprocess },
|
|
4283
|
-
typeName: ZodFirstPartyTypeKind.ZodEffects,
|
|
4284
|
-
...processCreateParams(params)
|
|
4285
|
-
});
|
|
4286
|
-
};
|
|
4287
|
-
class ZodOptional extends ZodType {
|
|
4288
|
-
_parse(input) {
|
|
4289
|
-
const parsedType = this._getType(input);
|
|
4290
|
-
if (parsedType === ZodParsedType.undefined) {
|
|
4291
|
-
return OK(undefined);
|
|
4292
|
-
}
|
|
4293
|
-
return this._def.innerType._parse(input);
|
|
4090
|
+
function getStorableFields(schema) {
|
|
4091
|
+
return Object.entries(asZodObject(schema).shape).filter(([key]) => key !== "id").map(([name, type]) => ({ name, type }));
|
|
4092
|
+
}
|
|
4093
|
+
function zodTypeToSqlType(zodType) {
|
|
4094
|
+
if (zodType instanceof exports_external.ZodOptional) {
|
|
4095
|
+
zodType = zodType._def.innerType;
|
|
4294
4096
|
}
|
|
4295
|
-
|
|
4296
|
-
|
|
4097
|
+
if (zodType instanceof exports_external.ZodDefault) {
|
|
4098
|
+
zodType = zodType._def.innerType;
|
|
4297
4099
|
}
|
|
4100
|
+
if (zodType instanceof exports_external.ZodString || zodType instanceof exports_external.ZodDate)
|
|
4101
|
+
return "TEXT";
|
|
4102
|
+
if (zodType instanceof exports_external.ZodNumber || zodType instanceof exports_external.ZodBoolean)
|
|
4103
|
+
return "INTEGER";
|
|
4104
|
+
if (zodType._def.typeName === "ZodInstanceOf" && zodType._def.type === Buffer)
|
|
4105
|
+
return "BLOB";
|
|
4106
|
+
return "TEXT";
|
|
4298
4107
|
}
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
_parse(input) {
|
|
4309
|
-
const parsedType = this._getType(input);
|
|
4310
|
-
if (parsedType === ZodParsedType.null) {
|
|
4311
|
-
return OK(null);
|
|
4108
|
+
function transformForStorage(data) {
|
|
4109
|
+
const transformed = {};
|
|
4110
|
+
for (const [key, value] of Object.entries(data)) {
|
|
4111
|
+
if (value instanceof Date) {
|
|
4112
|
+
transformed[key] = value.toISOString();
|
|
4113
|
+
} else if (typeof value === "boolean") {
|
|
4114
|
+
transformed[key] = value ? 1 : 0;
|
|
4115
|
+
} else {
|
|
4116
|
+
transformed[key] = value;
|
|
4312
4117
|
}
|
|
4313
|
-
return this._def.innerType._parse(input);
|
|
4314
4118
|
}
|
|
4315
|
-
|
|
4316
|
-
|
|
4119
|
+
return transformed;
|
|
4120
|
+
}
|
|
4121
|
+
function transformFromStorage(row, schema) {
|
|
4122
|
+
const transformed = {};
|
|
4123
|
+
for (const [key, value] of Object.entries(row)) {
|
|
4124
|
+
let fieldSchema = asZodObject(schema).shape[key];
|
|
4125
|
+
if (fieldSchema instanceof exports_external.ZodOptional) {
|
|
4126
|
+
fieldSchema = fieldSchema._def.innerType;
|
|
4127
|
+
}
|
|
4128
|
+
if (fieldSchema instanceof exports_external.ZodDefault) {
|
|
4129
|
+
fieldSchema = fieldSchema._def.innerType;
|
|
4130
|
+
}
|
|
4131
|
+
if (fieldSchema instanceof exports_external.ZodDate && typeof value === "string") {
|
|
4132
|
+
transformed[key] = new Date(value);
|
|
4133
|
+
} else if (fieldSchema instanceof exports_external.ZodBoolean && typeof value === "number") {
|
|
4134
|
+
transformed[key] = value === 1;
|
|
4135
|
+
} else {
|
|
4136
|
+
transformed[key] = value;
|
|
4137
|
+
}
|
|
4317
4138
|
}
|
|
4139
|
+
return transformed;
|
|
4318
4140
|
}
|
|
4319
|
-
ZodNullable.create = (type, params) => {
|
|
4320
|
-
return new ZodNullable({
|
|
4321
|
-
innerType: type,
|
|
4322
|
-
typeName: ZodFirstPartyTypeKind.ZodNullable,
|
|
4323
|
-
...processCreateParams(params)
|
|
4324
|
-
});
|
|
4325
|
-
};
|
|
4326
4141
|
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4142
|
+
// src/query.ts
|
|
4143
|
+
var OPERATOR_MAP = {
|
|
4144
|
+
$gt: ">",
|
|
4145
|
+
$gte: ">=",
|
|
4146
|
+
$lt: "<",
|
|
4147
|
+
$lte: "<=",
|
|
4148
|
+
$ne: "!=",
|
|
4149
|
+
$in: "IN",
|
|
4150
|
+
$like: "LIKE",
|
|
4151
|
+
$notIn: "NOT IN",
|
|
4152
|
+
$between: "BETWEEN"
|
|
4153
|
+
};
|
|
4154
|
+
function transformValueForStorage(value) {
|
|
4155
|
+
if (value instanceof Date)
|
|
4156
|
+
return value.toISOString();
|
|
4157
|
+
if (typeof value === "boolean")
|
|
4158
|
+
return value ? 1 : 0;
|
|
4159
|
+
return value;
|
|
4160
|
+
}
|
|
4161
|
+
function compileIQO(tableName, iqo) {
|
|
4162
|
+
const params = [];
|
|
4163
|
+
const selectParts = [];
|
|
4164
|
+
if (iqo.selects.length > 0) {
|
|
4165
|
+
selectParts.push(...iqo.selects.map((s) => `${tableName}.${s}`));
|
|
4166
|
+
} else {
|
|
4167
|
+
selectParts.push(`${tableName}.*`);
|
|
4168
|
+
}
|
|
4169
|
+
for (const j of iqo.joins) {
|
|
4170
|
+
if (j.columns.length > 0) {
|
|
4171
|
+
selectParts.push(...j.columns.map((c) => `${j.table}.${c} AS ${j.table}_${c}`));
|
|
4172
|
+
} else {
|
|
4173
|
+
selectParts.push(`${j.table}.*`);
|
|
4333
4174
|
}
|
|
4334
|
-
return this._def.innerType._parse({
|
|
4335
|
-
data,
|
|
4336
|
-
path: ctx.path,
|
|
4337
|
-
parent: ctx
|
|
4338
|
-
});
|
|
4339
4175
|
}
|
|
4340
|
-
|
|
4341
|
-
|
|
4176
|
+
let sql = `SELECT ${selectParts.join(", ")} FROM ${tableName}`;
|
|
4177
|
+
for (const j of iqo.joins) {
|
|
4178
|
+
sql += ` JOIN ${j.table} ON ${tableName}.${j.fromCol} = ${j.table}.${j.toCol}`;
|
|
4342
4179
|
}
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4180
|
+
if (iqo.whereAST) {
|
|
4181
|
+
const compiled = compileAST(iqo.whereAST);
|
|
4182
|
+
sql += ` WHERE ${compiled.sql}`;
|
|
4183
|
+
params.push(...compiled.params);
|
|
4184
|
+
} else if (iqo.wheres.length > 0) {
|
|
4185
|
+
const hasJoins = iqo.joins.length > 0;
|
|
4186
|
+
const qualify = (field) => hasJoins && !field.includes(".") ? `${tableName}.${field}` : field;
|
|
4187
|
+
const whereParts = [];
|
|
4188
|
+
for (const w of iqo.wheres) {
|
|
4189
|
+
if (w.operator === "IN") {
|
|
4190
|
+
const arr = w.value;
|
|
4191
|
+
if (arr.length === 0) {
|
|
4192
|
+
whereParts.push("1 = 0");
|
|
4193
|
+
} else {
|
|
4194
|
+
const placeholders = arr.map(() => "?").join(", ");
|
|
4195
|
+
whereParts.push(`${qualify(w.field)} IN (${placeholders})`);
|
|
4196
|
+
params.push(...arr.map(transformValueForStorage));
|
|
4197
|
+
}
|
|
4198
|
+
} else if (w.operator === "NOT IN") {
|
|
4199
|
+
const arr = w.value;
|
|
4200
|
+
if (arr.length === 0)
|
|
4201
|
+
continue;
|
|
4202
|
+
const placeholders = arr.map(() => "?").join(", ");
|
|
4203
|
+
whereParts.push(`${qualify(w.field)} NOT IN (${placeholders})`);
|
|
4204
|
+
params.push(...arr.map(transformValueForStorage));
|
|
4205
|
+
} else if (w.operator === "BETWEEN") {
|
|
4206
|
+
const [min, max] = w.value;
|
|
4207
|
+
whereParts.push(`${qualify(w.field)} BETWEEN ? AND ?`);
|
|
4208
|
+
params.push(transformValueForStorage(min), transformValueForStorage(max));
|
|
4209
|
+
} else {
|
|
4210
|
+
whereParts.push(`${qualify(w.field)} ${w.operator} ?`);
|
|
4211
|
+
params.push(transformValueForStorage(w.value));
|
|
4361
4212
|
}
|
|
4362
|
-
}
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4213
|
+
}
|
|
4214
|
+
if (whereParts.length > 0) {
|
|
4215
|
+
sql += ` WHERE ${whereParts.join(" AND ")}`;
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
if (iqo.whereOrs.length > 0) {
|
|
4219
|
+
for (const orGroup of iqo.whereOrs) {
|
|
4220
|
+
const orParts = [];
|
|
4221
|
+
for (const w of orGroup) {
|
|
4222
|
+
if (w.operator === "IN") {
|
|
4223
|
+
const arr = w.value;
|
|
4224
|
+
if (arr.length === 0) {
|
|
4225
|
+
orParts.push("1 = 0");
|
|
4226
|
+
} else {
|
|
4227
|
+
orParts.push(`${w.field} IN (${arr.map(() => "?").join(", ")})`);
|
|
4228
|
+
params.push(...arr.map(transformValueForStorage));
|
|
4229
|
+
}
|
|
4230
|
+
} else {
|
|
4231
|
+
orParts.push(`${w.field} ${w.operator} ?`);
|
|
4232
|
+
params.push(transformValueForStorage(w.value));
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
if (orParts.length > 0) {
|
|
4236
|
+
const orClause = `(${orParts.join(" OR ")})`;
|
|
4237
|
+
sql += sql.includes(" WHERE ") ? ` AND ${orClause}` : ` WHERE ${orClause}`;
|
|
4368
4238
|
}
|
|
4369
|
-
});
|
|
4370
|
-
if (isAsync(result)) {
|
|
4371
|
-
return result.then((result2) => {
|
|
4372
|
-
return {
|
|
4373
|
-
status: "valid",
|
|
4374
|
-
value: result2.status === "valid" ? result2.value : this._def.catchValue({
|
|
4375
|
-
get error() {
|
|
4376
|
-
return new ZodError(newCtx.common.issues);
|
|
4377
|
-
},
|
|
4378
|
-
input: newCtx.data
|
|
4379
|
-
})
|
|
4380
|
-
};
|
|
4381
|
-
});
|
|
4382
|
-
} else {
|
|
4383
|
-
return {
|
|
4384
|
-
status: "valid",
|
|
4385
|
-
value: result.status === "valid" ? result.value : this._def.catchValue({
|
|
4386
|
-
get error() {
|
|
4387
|
-
return new ZodError(newCtx.common.issues);
|
|
4388
|
-
},
|
|
4389
|
-
input: newCtx.data
|
|
4390
|
-
})
|
|
4391
|
-
};
|
|
4392
4239
|
}
|
|
4393
4240
|
}
|
|
4394
|
-
|
|
4395
|
-
|
|
4241
|
+
if (iqo.groupBy.length > 0) {
|
|
4242
|
+
sql += ` GROUP BY ${iqo.groupBy.join(", ")}`;
|
|
4396
4243
|
}
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
innerType: type,
|
|
4401
|
-
typeName: ZodFirstPartyTypeKind.ZodCatch,
|
|
4402
|
-
catchValue: typeof params.catch === "function" ? params.catch : () => params.catch,
|
|
4403
|
-
...processCreateParams(params)
|
|
4404
|
-
});
|
|
4405
|
-
};
|
|
4406
|
-
|
|
4407
|
-
class ZodNaN extends ZodType {
|
|
4408
|
-
_parse(input) {
|
|
4409
|
-
const parsedType = this._getType(input);
|
|
4410
|
-
if (parsedType !== ZodParsedType.nan) {
|
|
4411
|
-
const ctx = this._getOrReturnCtx(input);
|
|
4412
|
-
addIssueToContext(ctx, {
|
|
4413
|
-
code: ZodIssueCode.invalid_type,
|
|
4414
|
-
expected: ZodParsedType.nan,
|
|
4415
|
-
received: ctx.parsedType
|
|
4416
|
-
});
|
|
4417
|
-
return INVALID;
|
|
4418
|
-
}
|
|
4419
|
-
return { status: "valid", value: input.data };
|
|
4244
|
+
if (iqo.orderBy.length > 0) {
|
|
4245
|
+
const parts = iqo.orderBy.map((o) => `${o.field} ${o.direction.toUpperCase()}`);
|
|
4246
|
+
sql += ` ORDER BY ${parts.join(", ")}`;
|
|
4420
4247
|
}
|
|
4248
|
+
if (iqo.limit !== null)
|
|
4249
|
+
sql += ` LIMIT ${iqo.limit}`;
|
|
4250
|
+
if (iqo.offset !== null)
|
|
4251
|
+
sql += ` OFFSET ${iqo.offset}`;
|
|
4252
|
+
return { sql, params };
|
|
4421
4253
|
}
|
|
4422
|
-
ZodNaN.create = (params) => {
|
|
4423
|
-
return new ZodNaN({
|
|
4424
|
-
typeName: ZodFirstPartyTypeKind.ZodNaN,
|
|
4425
|
-
...processCreateParams(params)
|
|
4426
|
-
});
|
|
4427
|
-
};
|
|
4428
|
-
var BRAND = Symbol("zod_brand");
|
|
4429
4254
|
|
|
4430
|
-
class
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4255
|
+
class QueryBuilder {
|
|
4256
|
+
iqo;
|
|
4257
|
+
tableName;
|
|
4258
|
+
executor;
|
|
4259
|
+
singleExecutor;
|
|
4260
|
+
joinResolver;
|
|
4261
|
+
conditionResolver;
|
|
4262
|
+
eagerLoader;
|
|
4263
|
+
constructor(tableName, executor, singleExecutor, joinResolver, conditionResolver, eagerLoader) {
|
|
4264
|
+
this.tableName = tableName;
|
|
4265
|
+
this.executor = executor;
|
|
4266
|
+
this.singleExecutor = singleExecutor;
|
|
4267
|
+
this.joinResolver = joinResolver ?? null;
|
|
4268
|
+
this.conditionResolver = conditionResolver ?? null;
|
|
4269
|
+
this.eagerLoader = eagerLoader ?? null;
|
|
4270
|
+
this.iqo = {
|
|
4271
|
+
selects: [],
|
|
4272
|
+
wheres: [],
|
|
4273
|
+
whereOrs: [],
|
|
4274
|
+
whereAST: null,
|
|
4275
|
+
joins: [],
|
|
4276
|
+
groupBy: [],
|
|
4277
|
+
limit: null,
|
|
4278
|
+
offset: null,
|
|
4279
|
+
orderBy: [],
|
|
4280
|
+
includes: [],
|
|
4281
|
+
raw: false
|
|
4282
|
+
};
|
|
4439
4283
|
}
|
|
4440
|
-
|
|
4441
|
-
|
|
4284
|
+
select(...cols) {
|
|
4285
|
+
this.iqo.selects.push(...cols);
|
|
4286
|
+
return this;
|
|
4442
4287
|
}
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4288
|
+
where(criteriaOrCallback) {
|
|
4289
|
+
if (typeof criteriaOrCallback === "function") {
|
|
4290
|
+
const ast = criteriaOrCallback(createColumnProxy(), createFunctionProxy(), op);
|
|
4291
|
+
if (this.iqo.whereAST) {
|
|
4292
|
+
this.iqo.whereAST = { type: "operator", op: "AND", left: this.iqo.whereAST, right: ast };
|
|
4293
|
+
} else {
|
|
4294
|
+
this.iqo.whereAST = ast;
|
|
4295
|
+
}
|
|
4296
|
+
} else {
|
|
4297
|
+
const resolved = this.conditionResolver ? this.conditionResolver(criteriaOrCallback) : criteriaOrCallback;
|
|
4298
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
4299
|
+
if (key === "$or" && Array.isArray(value)) {
|
|
4300
|
+
const orConditions = [];
|
|
4301
|
+
for (const branch of value) {
|
|
4302
|
+
const resolvedBranch = this.conditionResolver ? this.conditionResolver(branch) : branch;
|
|
4303
|
+
for (const [bKey, bValue] of Object.entries(resolvedBranch)) {
|
|
4304
|
+
if (typeof bValue === "object" && bValue !== null && !Array.isArray(bValue) && !(bValue instanceof Date)) {
|
|
4305
|
+
for (const [opKey, operand] of Object.entries(bValue)) {
|
|
4306
|
+
const sqlOp = OPERATOR_MAP[opKey];
|
|
4307
|
+
if (sqlOp)
|
|
4308
|
+
orConditions.push({ field: bKey, operator: sqlOp, value: operand });
|
|
4309
|
+
}
|
|
4310
|
+
} else {
|
|
4311
|
+
orConditions.push({ field: bKey, operator: "=", value: bValue });
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
if (orConditions.length > 0)
|
|
4316
|
+
this.iqo.whereOrs.push(orConditions);
|
|
4317
|
+
continue;
|
|
4318
|
+
}
|
|
4319
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
|
|
4320
|
+
for (const [opKey, operand] of Object.entries(value)) {
|
|
4321
|
+
const sqlOp = OPERATOR_MAP[opKey];
|
|
4322
|
+
if (!sqlOp)
|
|
4323
|
+
throw new Error(`Unsupported query operator: '${opKey}' on field '${key}'.`);
|
|
4324
|
+
if (opKey === "$between") {
|
|
4325
|
+
if (!Array.isArray(operand) || operand.length !== 2)
|
|
4326
|
+
throw new Error(`$between for '${key}' requires [min, max]`);
|
|
4327
|
+
}
|
|
4328
|
+
this.iqo.wheres.push({
|
|
4329
|
+
field: key,
|
|
4330
|
+
operator: sqlOp,
|
|
4331
|
+
value: operand
|
|
4332
|
+
});
|
|
4333
|
+
}
|
|
4460
4334
|
} else {
|
|
4461
|
-
|
|
4462
|
-
data: inResult.value,
|
|
4463
|
-
path: ctx.path,
|
|
4464
|
-
parent: ctx
|
|
4465
|
-
});
|
|
4335
|
+
this.iqo.wheres.push({ field: key, operator: "=", value });
|
|
4466
4336
|
}
|
|
4467
|
-
}
|
|
4468
|
-
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
return this;
|
|
4340
|
+
}
|
|
4341
|
+
limit(n) {
|
|
4342
|
+
this.iqo.limit = n;
|
|
4343
|
+
return this;
|
|
4344
|
+
}
|
|
4345
|
+
offset(n) {
|
|
4346
|
+
this.iqo.offset = n;
|
|
4347
|
+
return this;
|
|
4348
|
+
}
|
|
4349
|
+
orderBy(field, direction = "asc") {
|
|
4350
|
+
this.iqo.orderBy.push({ field, direction });
|
|
4351
|
+
return this;
|
|
4352
|
+
}
|
|
4353
|
+
join(tableOrAccessor, fkOrCols, colsOrPk, pk) {
|
|
4354
|
+
let table;
|
|
4355
|
+
let fromCol;
|
|
4356
|
+
let toCol;
|
|
4357
|
+
let columns;
|
|
4358
|
+
if (typeof tableOrAccessor === "object" && "_tableName" in tableOrAccessor) {
|
|
4359
|
+
table = tableOrAccessor._tableName;
|
|
4360
|
+
columns = Array.isArray(fkOrCols) ? fkOrCols : [];
|
|
4361
|
+
if (!this.joinResolver)
|
|
4362
|
+
throw new Error(`Cannot auto-resolve join: no relationship data available`);
|
|
4363
|
+
const resolved = this.joinResolver(this.tableName, table);
|
|
4364
|
+
if (!resolved)
|
|
4365
|
+
throw new Error(`No relationship found between '${this.tableName}' and '${table}'`);
|
|
4366
|
+
fromCol = resolved.fk;
|
|
4367
|
+
toCol = resolved.pk;
|
|
4469
4368
|
} else {
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4369
|
+
table = tableOrAccessor;
|
|
4370
|
+
fromCol = fkOrCols;
|
|
4371
|
+
columns = Array.isArray(colsOrPk) ? colsOrPk : [];
|
|
4372
|
+
toCol = (typeof colsOrPk === "string" ? colsOrPk : pk) ?? "id";
|
|
4373
|
+
}
|
|
4374
|
+
this.iqo.joins.push({ table, fromCol, toCol, columns });
|
|
4375
|
+
this.iqo.raw = true;
|
|
4376
|
+
return this;
|
|
4377
|
+
}
|
|
4378
|
+
raw() {
|
|
4379
|
+
this.iqo.raw = true;
|
|
4380
|
+
return this;
|
|
4381
|
+
}
|
|
4382
|
+
with(...relations) {
|
|
4383
|
+
this.iqo.includes.push(...relations);
|
|
4384
|
+
return this;
|
|
4385
|
+
}
|
|
4386
|
+
_applyEagerLoads(results) {
|
|
4387
|
+
if (this.iqo.includes.length === 0 || !this.eagerLoader || results.length === 0) {
|
|
4388
|
+
return results;
|
|
4389
|
+
}
|
|
4390
|
+
const parentIds = results.map((r) => r.id).filter((id) => typeof id === "number");
|
|
4391
|
+
if (parentIds.length === 0)
|
|
4392
|
+
return results;
|
|
4393
|
+
for (const relation of this.iqo.includes) {
|
|
4394
|
+
const loaded = this.eagerLoader(this.tableName, relation, parentIds);
|
|
4395
|
+
if (!loaded)
|
|
4396
|
+
continue;
|
|
4397
|
+
for (const row of results) {
|
|
4398
|
+
row[loaded.key] = loaded.groups.get(row.id) ?? [];
|
|
4489
4399
|
}
|
|
4490
4400
|
}
|
|
4401
|
+
return results;
|
|
4402
|
+
}
|
|
4403
|
+
all() {
|
|
4404
|
+
const { sql, params } = compileIQO(this.tableName, this.iqo);
|
|
4405
|
+
const results = this.executor(sql, params, this.iqo.raw);
|
|
4406
|
+
return this._applyEagerLoads(results);
|
|
4407
|
+
}
|
|
4408
|
+
get() {
|
|
4409
|
+
this.iqo.limit = 1;
|
|
4410
|
+
const { sql, params } = compileIQO(this.tableName, this.iqo);
|
|
4411
|
+
const result = this.singleExecutor(sql, params, this.iqo.raw);
|
|
4412
|
+
if (!result)
|
|
4413
|
+
return null;
|
|
4414
|
+
const [loaded] = this._applyEagerLoads([result]);
|
|
4415
|
+
return loaded ?? null;
|
|
4491
4416
|
}
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4417
|
+
count() {
|
|
4418
|
+
const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
|
|
4419
|
+
const countSql = selectSql.replace(/^SELECT .+? FROM/, "SELECT COUNT(*) as count FROM");
|
|
4420
|
+
const results = this.executor(countSql, params, true);
|
|
4421
|
+
return results[0]?.count ?? 0;
|
|
4422
|
+
}
|
|
4423
|
+
first() {
|
|
4424
|
+
return this.get();
|
|
4425
|
+
}
|
|
4426
|
+
exists() {
|
|
4427
|
+
const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
|
|
4428
|
+
const existsSql = selectSql.replace(/^SELECT .+? FROM/, "SELECT 1 FROM").replace(/ LIMIT \d+/, "") + " LIMIT 1";
|
|
4429
|
+
const results = this.executor(existsSql, params, true);
|
|
4430
|
+
return results.length > 0;
|
|
4431
|
+
}
|
|
4432
|
+
groupBy(...fields) {
|
|
4433
|
+
this.iqo.groupBy.push(...fields);
|
|
4434
|
+
return this;
|
|
4435
|
+
}
|
|
4436
|
+
then(onfulfilled, onrejected) {
|
|
4437
|
+
try {
|
|
4438
|
+
const result = this.all();
|
|
4439
|
+
return Promise.resolve(result).then(onfulfilled, onrejected);
|
|
4440
|
+
} catch (err) {
|
|
4441
|
+
return Promise.reject(err).then(onfulfilled, onrejected);
|
|
4442
|
+
}
|
|
4498
4443
|
}
|
|
4499
4444
|
}
|
|
4500
4445
|
|
|
4501
|
-
class
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result);
|
|
4446
|
+
class ColumnNode {
|
|
4447
|
+
table;
|
|
4448
|
+
column;
|
|
4449
|
+
alias;
|
|
4450
|
+
_type = "COL";
|
|
4451
|
+
constructor(table, column, alias) {
|
|
4452
|
+
this.table = table;
|
|
4453
|
+
this.column = column;
|
|
4454
|
+
this.alias = alias;
|
|
4511
4455
|
}
|
|
4512
|
-
|
|
4513
|
-
return this.
|
|
4456
|
+
toString() {
|
|
4457
|
+
return `"${this.alias}"."${this.column}"`;
|
|
4458
|
+
}
|
|
4459
|
+
[Symbol.toPrimitive]() {
|
|
4460
|
+
return this.toString();
|
|
4514
4461
|
}
|
|
4515
4462
|
}
|
|
4516
|
-
|
|
4517
|
-
return
|
|
4518
|
-
innerType: type,
|
|
4519
|
-
typeName: ZodFirstPartyTypeKind.ZodReadonly,
|
|
4520
|
-
...processCreateParams(params)
|
|
4521
|
-
});
|
|
4522
|
-
};
|
|
4523
|
-
function cleanParams(params, data) {
|
|
4524
|
-
const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params;
|
|
4525
|
-
const p2 = typeof p === "string" ? { message: p } : p;
|
|
4526
|
-
return p2;
|
|
4463
|
+
function q(name) {
|
|
4464
|
+
return `"${name}"`;
|
|
4527
4465
|
}
|
|
4528
|
-
function
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
const _fatal = params.fatal ?? fatal ?? true;
|
|
4537
|
-
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
|
|
4538
|
-
}
|
|
4539
|
-
});
|
|
4466
|
+
function qRef(alias, column) {
|
|
4467
|
+
return `"${alias}"."${column}"`;
|
|
4468
|
+
}
|
|
4469
|
+
function createTableProxy(tableName, alias, columns) {
|
|
4470
|
+
return new Proxy({}, {
|
|
4471
|
+
get(_target, prop) {
|
|
4472
|
+
if (prop === Symbol.toPrimitive || prop === "toString" || prop === "valueOf") {
|
|
4473
|
+
return;
|
|
4540
4474
|
}
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4475
|
+
return new ColumnNode(tableName, prop, alias);
|
|
4476
|
+
},
|
|
4477
|
+
ownKeys() {
|
|
4478
|
+
return [...columns];
|
|
4479
|
+
},
|
|
4480
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
4481
|
+
if (columns.has(prop)) {
|
|
4482
|
+
return { configurable: true, enumerable: true, value: new ColumnNode(tableName, prop, alias) };
|
|
4545
4483
|
}
|
|
4546
4484
|
return;
|
|
4547
|
-
}
|
|
4548
|
-
|
|
4485
|
+
}
|
|
4486
|
+
});
|
|
4549
4487
|
}
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
(
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
}
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
var objectType = ZodObject.create;
|
|
4610
|
-
var strictObjectType = ZodObject.strictCreate;
|
|
4611
|
-
var unionType = ZodUnion.create;
|
|
4612
|
-
var discriminatedUnionType = ZodDiscriminatedUnion.create;
|
|
4613
|
-
var intersectionType = ZodIntersection.create;
|
|
4614
|
-
var tupleType = ZodTuple.create;
|
|
4615
|
-
var recordType = ZodRecord.create;
|
|
4616
|
-
var mapType = ZodMap.create;
|
|
4617
|
-
var setType = ZodSet.create;
|
|
4618
|
-
var functionType = ZodFunction.create;
|
|
4619
|
-
var lazyType = ZodLazy.create;
|
|
4620
|
-
var literalType = ZodLiteral.create;
|
|
4621
|
-
var enumType = ZodEnum.create;
|
|
4622
|
-
var nativeEnumType = ZodNativeEnum.create;
|
|
4623
|
-
var promiseType = ZodPromise.create;
|
|
4624
|
-
var effectsType = ZodEffects.create;
|
|
4625
|
-
var optionalType = ZodOptional.create;
|
|
4626
|
-
var nullableType = ZodNullable.create;
|
|
4627
|
-
var preprocessType = ZodEffects.createWithPreprocess;
|
|
4628
|
-
var pipelineType = ZodPipeline.create;
|
|
4629
|
-
var ostring = () => stringType().optional();
|
|
4630
|
-
var onumber = () => numberType().optional();
|
|
4631
|
-
var oboolean = () => booleanType().optional();
|
|
4632
|
-
var coerce = {
|
|
4633
|
-
string: (arg) => ZodString.create({ ...arg, coerce: true }),
|
|
4634
|
-
number: (arg) => ZodNumber.create({ ...arg, coerce: true }),
|
|
4635
|
-
boolean: (arg) => ZodBoolean.create({
|
|
4636
|
-
...arg,
|
|
4637
|
-
coerce: true
|
|
4638
|
-
}),
|
|
4639
|
-
bigint: (arg) => ZodBigInt.create({ ...arg, coerce: true }),
|
|
4640
|
-
date: (arg) => ZodDate.create({ ...arg, coerce: true })
|
|
4641
|
-
};
|
|
4642
|
-
var NEVER = INVALID;
|
|
4643
|
-
// src/schema.ts
|
|
4644
|
-
function parseRelationsConfig(relations, schemas) {
|
|
4645
|
-
const relationships = [];
|
|
4646
|
-
const added = new Set;
|
|
4647
|
-
for (const [fromTable, rels] of Object.entries(relations)) {
|
|
4648
|
-
if (!schemas[fromTable]) {
|
|
4649
|
-
throw new Error(`relations: unknown table '${fromTable}'`);
|
|
4488
|
+
function createContextProxy(schemas) {
|
|
4489
|
+
const aliases = new Map;
|
|
4490
|
+
let aliasCounter = 0;
|
|
4491
|
+
const proxy = new Proxy({}, {
|
|
4492
|
+
get(_target, tableName) {
|
|
4493
|
+
if (typeof tableName !== "string")
|
|
4494
|
+
return;
|
|
4495
|
+
const schema = schemas[tableName];
|
|
4496
|
+
const shape = schema ? schema.shape : {};
|
|
4497
|
+
const columns = new Set(Object.keys(shape));
|
|
4498
|
+
aliasCounter++;
|
|
4499
|
+
const alias = `t${aliasCounter}`;
|
|
4500
|
+
const tableProxy = createTableProxy(tableName, alias, columns);
|
|
4501
|
+
const entries = aliases.get(tableName) || [];
|
|
4502
|
+
entries.push({ tableName, alias, proxy: tableProxy });
|
|
4503
|
+
aliases.set(tableName, entries);
|
|
4504
|
+
return tableProxy;
|
|
4505
|
+
}
|
|
4506
|
+
});
|
|
4507
|
+
return { proxy, aliasMap: aliases };
|
|
4508
|
+
}
|
|
4509
|
+
function isColumnNode(val) {
|
|
4510
|
+
return val && typeof val === "object" && val._type === "COL";
|
|
4511
|
+
}
|
|
4512
|
+
function compileProxyQuery(queryResult, aliasMap) {
|
|
4513
|
+
const params = [];
|
|
4514
|
+
const tablesUsed = new Map;
|
|
4515
|
+
for (const [tableName, entries] of aliasMap) {
|
|
4516
|
+
for (const entry of entries) {
|
|
4517
|
+
tablesUsed.set(entry.alias, { tableName, alias: entry.alias });
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
const selectParts = [];
|
|
4521
|
+
for (const [outputName, colOrValue] of Object.entries(queryResult.select)) {
|
|
4522
|
+
if (isColumnNode(colOrValue)) {
|
|
4523
|
+
if (outputName === colOrValue.column) {
|
|
4524
|
+
selectParts.push(qRef(colOrValue.alias, colOrValue.column));
|
|
4525
|
+
} else {
|
|
4526
|
+
selectParts.push(`${qRef(colOrValue.alias, colOrValue.column)} AS ${q(outputName)}`);
|
|
4527
|
+
}
|
|
4528
|
+
} else {
|
|
4529
|
+
selectParts.push(`? AS ${q(outputName)}`);
|
|
4530
|
+
params.push(colOrValue);
|
|
4531
|
+
}
|
|
4532
|
+
}
|
|
4533
|
+
const allAliases = [...tablesUsed.values()];
|
|
4534
|
+
if (allAliases.length === 0)
|
|
4535
|
+
throw new Error("No tables referenced in query.");
|
|
4536
|
+
const primaryAlias = allAliases[0];
|
|
4537
|
+
let sql = `SELECT ${selectParts.join(", ")} FROM ${q(primaryAlias.tableName)} ${q(primaryAlias.alias)}`;
|
|
4538
|
+
if (queryResult.join) {
|
|
4539
|
+
const joins = Array.isArray(queryResult.join[0]) ? queryResult.join : [queryResult.join];
|
|
4540
|
+
for (const [left, right] of joins) {
|
|
4541
|
+
const leftTable = tablesUsed.get(left.alias);
|
|
4542
|
+
const rightTable = tablesUsed.get(right.alias);
|
|
4543
|
+
if (!leftTable || !rightTable)
|
|
4544
|
+
throw new Error("Join references unknown table alias.");
|
|
4545
|
+
const joinAlias = leftTable.alias === primaryAlias.alias ? rightTable : leftTable;
|
|
4546
|
+
sql += ` JOIN ${q(joinAlias.tableName)} ${q(joinAlias.alias)} ON ${qRef(left.alias, left.column)} = ${qRef(right.alias, right.column)}`;
|
|
4650
4547
|
}
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4548
|
+
}
|
|
4549
|
+
if (queryResult.where && Object.keys(queryResult.where).length > 0) {
|
|
4550
|
+
const whereParts = [];
|
|
4551
|
+
for (const [key, value] of Object.entries(queryResult.where)) {
|
|
4552
|
+
let fieldRef;
|
|
4553
|
+
const quotedMatch = key.match(/^"([^"]+)"\.\"([^"]+)"$/);
|
|
4554
|
+
if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
|
|
4555
|
+
fieldRef = key;
|
|
4556
|
+
} else {
|
|
4557
|
+
fieldRef = qRef(primaryAlias.alias, key);
|
|
4654
4558
|
}
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
if (
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
}
|
|
4665
|
-
|
|
4559
|
+
if (isColumnNode(value)) {
|
|
4560
|
+
whereParts.push(`${fieldRef} = ${qRef(value.alias, value.column)}`);
|
|
4561
|
+
} else if (Array.isArray(value)) {
|
|
4562
|
+
if (value.length === 0) {
|
|
4563
|
+
whereParts.push("1 = 0");
|
|
4564
|
+
} else {
|
|
4565
|
+
const placeholders = value.map(() => "?").join(", ");
|
|
4566
|
+
whereParts.push(`${fieldRef} IN (${placeholders})`);
|
|
4567
|
+
params.push(...value);
|
|
4568
|
+
}
|
|
4569
|
+
} else if (typeof value === "object" && value !== null && !(value instanceof Date)) {
|
|
4570
|
+
for (const [pOp, operand] of Object.entries(value)) {
|
|
4571
|
+
if (pOp === "$in") {
|
|
4572
|
+
const arr = operand;
|
|
4573
|
+
if (arr.length === 0) {
|
|
4574
|
+
whereParts.push("1 = 0");
|
|
4575
|
+
} else {
|
|
4576
|
+
const placeholders = arr.map(() => "?").join(", ");
|
|
4577
|
+
whereParts.push(`${fieldRef} IN (${placeholders})`);
|
|
4578
|
+
params.push(...arr);
|
|
4579
|
+
}
|
|
4580
|
+
continue;
|
|
4581
|
+
}
|
|
4582
|
+
const opMap = {
|
|
4583
|
+
$gt: ">",
|
|
4584
|
+
$gte: ">=",
|
|
4585
|
+
$lt: "<",
|
|
4586
|
+
$lte: "<=",
|
|
4587
|
+
$ne: "!="
|
|
4588
|
+
};
|
|
4589
|
+
const sqlOp = opMap[pOp];
|
|
4590
|
+
if (!sqlOp)
|
|
4591
|
+
throw new Error(`Unsupported where operator: ${pOp}`);
|
|
4592
|
+
whereParts.push(`${fieldRef} ${sqlOp} ?`);
|
|
4593
|
+
params.push(operand);
|
|
4594
|
+
}
|
|
4595
|
+
} else {
|
|
4596
|
+
whereParts.push(`${fieldRef} = ?`);
|
|
4597
|
+
params.push(value instanceof Date ? value.toISOString() : value);
|
|
4666
4598
|
}
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4599
|
+
}
|
|
4600
|
+
if (whereParts.length > 0) {
|
|
4601
|
+
sql += ` WHERE ${whereParts.join(" AND ")}`;
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
if (queryResult.orderBy) {
|
|
4605
|
+
const parts = [];
|
|
4606
|
+
for (const [key, dir] of Object.entries(queryResult.orderBy)) {
|
|
4607
|
+
let fieldRef;
|
|
4608
|
+
const quotedMatch = key.match(/^"([^"]+)"\.\"([^"]+)"$/);
|
|
4609
|
+
if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
|
|
4610
|
+
fieldRef = key;
|
|
4611
|
+
} else {
|
|
4612
|
+
fieldRef = qRef(primaryAlias.alias, key);
|
|
4677
4613
|
}
|
|
4614
|
+
parts.push(`${fieldRef} ${dir.toUpperCase()}`);
|
|
4615
|
+
}
|
|
4616
|
+
if (parts.length > 0) {
|
|
4617
|
+
sql += ` ORDER BY ${parts.join(", ")}`;
|
|
4678
4618
|
}
|
|
4679
4619
|
}
|
|
4680
|
-
|
|
4620
|
+
if (queryResult.groupBy && queryResult.groupBy.length > 0) {
|
|
4621
|
+
const parts = queryResult.groupBy.filter(Boolean).map((col) => qRef(col.alias, col.column));
|
|
4622
|
+
sql += ` GROUP BY ${parts.join(", ")}`;
|
|
4623
|
+
}
|
|
4624
|
+
if (queryResult.limit !== undefined)
|
|
4625
|
+
sql += ` LIMIT ${queryResult.limit}`;
|
|
4626
|
+
if (queryResult.offset !== undefined)
|
|
4627
|
+
sql += ` OFFSET ${queryResult.offset}`;
|
|
4628
|
+
return { sql, params };
|
|
4681
4629
|
}
|
|
4682
|
-
function
|
|
4683
|
-
|
|
4630
|
+
function executeProxyQuery(schemas, callback, executor) {
|
|
4631
|
+
const { proxy, aliasMap } = createContextProxy(schemas);
|
|
4632
|
+
const queryResult = callback(proxy);
|
|
4633
|
+
const { sql, params } = compileProxyQuery(queryResult, aliasMap);
|
|
4634
|
+
return executor(sql, params);
|
|
4684
4635
|
}
|
|
4685
|
-
function
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
return
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4636
|
+
function createQueryBuilder(ctx, entityName, initialCols) {
|
|
4637
|
+
const schema = ctx.schemas[entityName];
|
|
4638
|
+
const executor = (sql, params, raw) => {
|
|
4639
|
+
const rows = ctx.db.query(sql).all(...params);
|
|
4640
|
+
if (raw)
|
|
4641
|
+
return rows;
|
|
4642
|
+
return rows.map((row) => ctx.attachMethods(entityName, transformFromStorage(row, schema)));
|
|
4643
|
+
};
|
|
4644
|
+
const singleExecutor = (sql, params, raw) => {
|
|
4645
|
+
const results = executor(sql, params, raw);
|
|
4646
|
+
return results.length > 0 ? results[0] : null;
|
|
4647
|
+
};
|
|
4648
|
+
const joinResolver = (fromTable, toTable) => {
|
|
4649
|
+
const belongsTo = ctx.relationships.find((r) => r.type === "belongs-to" && r.from === fromTable && r.to === toTable);
|
|
4650
|
+
if (belongsTo)
|
|
4651
|
+
return { fk: belongsTo.foreignKey, pk: "id" };
|
|
4652
|
+
const reverse = ctx.relationships.find((r) => r.type === "belongs-to" && r.from === toTable && r.to === fromTable);
|
|
4653
|
+
if (reverse)
|
|
4654
|
+
return { fk: "id", pk: reverse.foreignKey };
|
|
4655
|
+
return null;
|
|
4656
|
+
};
|
|
4657
|
+
const conditionResolver = (conditions) => {
|
|
4658
|
+
const resolved = {};
|
|
4659
|
+
for (const [key, value] of Object.entries(conditions)) {
|
|
4660
|
+
if (value && typeof value === "object" && typeof value.id === "number" && typeof value.delete === "function") {
|
|
4661
|
+
const fkCol = key + "_id";
|
|
4662
|
+
const rel = ctx.relationships.find((r) => r.type === "belongs-to" && r.from === entityName && r.foreignKey === fkCol);
|
|
4663
|
+
if (rel) {
|
|
4664
|
+
resolved[fkCol] = value.id;
|
|
4665
|
+
} else {
|
|
4666
|
+
const relByNav = ctx.relationships.find((r) => r.type === "belongs-to" && r.from === entityName && r.to === key + "s") || ctx.relationships.find((r) => r.type === "belongs-to" && r.from === entityName && r.to === key);
|
|
4667
|
+
if (relByNav) {
|
|
4668
|
+
resolved[relByNav.foreignKey] = value.id;
|
|
4669
|
+
} else {
|
|
4670
|
+
resolved[key] = value;
|
|
4671
|
+
}
|
|
4672
|
+
}
|
|
4673
|
+
} else {
|
|
4674
|
+
resolved[key] = value;
|
|
4675
|
+
}
|
|
4676
|
+
}
|
|
4677
|
+
return resolved;
|
|
4678
|
+
};
|
|
4679
|
+
const eagerLoader = (parentTable, relation, parentIds) => {
|
|
4680
|
+
const hasMany = ctx.relationships.find((r) => r.type === "one-to-many" && r.from === parentTable && r.relationshipField === relation);
|
|
4681
|
+
if (hasMany) {
|
|
4682
|
+
const belongsTo2 = ctx.relationships.find((r) => r.type === "belongs-to" && r.from === hasMany.to && r.to === parentTable);
|
|
4683
|
+
if (belongsTo2) {
|
|
4684
|
+
const fk = belongsTo2.foreignKey;
|
|
4685
|
+
const placeholders = parentIds.map(() => "?").join(", ");
|
|
4686
|
+
const childRows = ctx.db.query(`SELECT * FROM ${hasMany.to} WHERE ${fk} IN (${placeholders})`).all(...parentIds);
|
|
4687
|
+
const groups = new Map;
|
|
4688
|
+
const childSchema = ctx.schemas[hasMany.to];
|
|
4689
|
+
for (const rawRow of childRows) {
|
|
4690
|
+
const entity = ctx.attachMethods(hasMany.to, transformFromStorage(rawRow, childSchema));
|
|
4691
|
+
const parentId = rawRow[fk];
|
|
4692
|
+
if (!groups.has(parentId))
|
|
4693
|
+
groups.set(parentId, []);
|
|
4694
|
+
groups.get(parentId).push(entity);
|
|
4695
|
+
}
|
|
4696
|
+
return { key: relation, groups };
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
const belongsTo = ctx.relationships.find((r) => r.type === "belongs-to" && r.from === parentTable && r.relationshipField === relation);
|
|
4700
|
+
if (belongsTo) {
|
|
4701
|
+
return null;
|
|
4702
|
+
}
|
|
4703
|
+
return null;
|
|
4704
|
+
};
|
|
4705
|
+
const builder = new QueryBuilder(entityName, executor, singleExecutor, joinResolver, conditionResolver, eagerLoader);
|
|
4706
|
+
if (initialCols.length > 0)
|
|
4707
|
+
builder.select(...initialCols);
|
|
4708
|
+
return builder;
|
|
4699
4709
|
}
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4710
|
+
|
|
4711
|
+
// src/helpers.ts
|
|
4712
|
+
function buildWhereClause(conditions, tablePrefix) {
|
|
4713
|
+
const parts = [];
|
|
4714
|
+
const values = [];
|
|
4715
|
+
for (const key in conditions) {
|
|
4716
|
+
if (key.startsWith("$")) {
|
|
4717
|
+
if (key === "$or" && Array.isArray(conditions[key])) {
|
|
4718
|
+
const orBranches = conditions[key];
|
|
4719
|
+
const orParts = [];
|
|
4720
|
+
for (const branch of orBranches) {
|
|
4721
|
+
const sub = buildWhereClause(branch, tablePrefix);
|
|
4722
|
+
if (sub.clause) {
|
|
4723
|
+
orParts.push(`(${sub.clause.replace(/^WHERE /, "")})`);
|
|
4724
|
+
values.push(...sub.values);
|
|
4725
|
+
}
|
|
4726
|
+
}
|
|
4727
|
+
if (orParts.length > 0)
|
|
4728
|
+
parts.push(`(${orParts.join(" OR ")})`);
|
|
4729
|
+
}
|
|
4730
|
+
continue;
|
|
4731
|
+
}
|
|
4732
|
+
const value = conditions[key];
|
|
4733
|
+
const fieldName = tablePrefix ? `"${tablePrefix}"."${key}"` : `"${key}"`;
|
|
4734
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
|
|
4735
|
+
const operator = Object.keys(value)[0];
|
|
4736
|
+
if (!operator?.startsWith("$")) {
|
|
4737
|
+
throw new Error(`Querying on nested object '${key}' not supported. Use operators like $gt.`);
|
|
4738
|
+
}
|
|
4739
|
+
const operand = value[operator];
|
|
4740
|
+
if (operator === "$in") {
|
|
4741
|
+
if (!Array.isArray(operand))
|
|
4742
|
+
throw new Error(`$in for '${key}' requires an array`);
|
|
4743
|
+
if (operand.length === 0) {
|
|
4744
|
+
parts.push("1 = 0");
|
|
4745
|
+
continue;
|
|
4746
|
+
}
|
|
4747
|
+
parts.push(`${fieldName} IN (${operand.map(() => "?").join(", ")})`);
|
|
4748
|
+
values.push(...operand.map((v) => transformForStorage({ v }).v));
|
|
4749
|
+
continue;
|
|
4750
|
+
}
|
|
4751
|
+
if (operator === "$notIn") {
|
|
4752
|
+
if (!Array.isArray(operand))
|
|
4753
|
+
throw new Error(`$notIn for '${key}' requires an array`);
|
|
4754
|
+
if (operand.length === 0)
|
|
4755
|
+
continue;
|
|
4756
|
+
parts.push(`${fieldName} NOT IN (${operand.map(() => "?").join(", ")})`);
|
|
4757
|
+
values.push(...operand.map((v) => transformForStorage({ v }).v));
|
|
4758
|
+
continue;
|
|
4759
|
+
}
|
|
4760
|
+
if (operator === "$like") {
|
|
4761
|
+
parts.push(`${fieldName} LIKE ?`);
|
|
4762
|
+
values.push(operand);
|
|
4763
|
+
continue;
|
|
4764
|
+
}
|
|
4765
|
+
if (operator === "$between") {
|
|
4766
|
+
if (!Array.isArray(operand) || operand.length !== 2)
|
|
4767
|
+
throw new Error(`$between for '${key}' requires [min, max]`);
|
|
4768
|
+
parts.push(`${fieldName} BETWEEN ? AND ?`);
|
|
4769
|
+
values.push(transformForStorage({ v: operand[0] }).v, transformForStorage({ v: operand[1] }).v);
|
|
4770
|
+
continue;
|
|
4771
|
+
}
|
|
4772
|
+
const sqlOp = { $gt: ">", $gte: ">=", $lt: "<", $lte: "<=", $ne: "!=" }[operator];
|
|
4773
|
+
if (!sqlOp)
|
|
4774
|
+
throw new Error(`Unsupported operator '${operator}' on '${key}'`);
|
|
4775
|
+
parts.push(`${fieldName} ${sqlOp} ?`);
|
|
4776
|
+
values.push(transformForStorage({ operand }).operand);
|
|
4707
4777
|
} else {
|
|
4708
|
-
|
|
4778
|
+
parts.push(`${fieldName} = ?`);
|
|
4779
|
+
values.push(transformForStorage({ value }).value);
|
|
4709
4780
|
}
|
|
4710
4781
|
}
|
|
4711
|
-
return
|
|
4782
|
+
return { clause: parts.length > 0 ? `WHERE ${parts.join(" AND ")}` : "", values };
|
|
4712
4783
|
}
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4784
|
+
|
|
4785
|
+
// src/crud.ts
|
|
4786
|
+
function getById(ctx, entityName, id) {
|
|
4787
|
+
const row = ctx.db.query(`SELECT * FROM "${entityName}" WHERE id = ?`).get(id);
|
|
4788
|
+
if (!row)
|
|
4789
|
+
return null;
|
|
4790
|
+
return ctx.attachMethods(entityName, transformFromStorage(row, ctx.schemas[entityName]));
|
|
4791
|
+
}
|
|
4792
|
+
function getOne(ctx, entityName, conditions) {
|
|
4793
|
+
const { clause, values } = ctx.buildWhereClause(conditions);
|
|
4794
|
+
const row = ctx.db.query(`SELECT * FROM "${entityName}" ${clause} LIMIT 1`).get(...values);
|
|
4795
|
+
if (!row)
|
|
4796
|
+
return null;
|
|
4797
|
+
return ctx.attachMethods(entityName, transformFromStorage(row, ctx.schemas[entityName]));
|
|
4798
|
+
}
|
|
4799
|
+
function findMany(ctx, entityName, conditions = {}) {
|
|
4800
|
+
const { clause, values } = ctx.buildWhereClause(conditions);
|
|
4801
|
+
const rows = ctx.db.query(`SELECT * FROM "${entityName}" ${clause}`).all(...values);
|
|
4802
|
+
return rows.map((row) => ctx.attachMethods(entityName, transformFromStorage(row, ctx.schemas[entityName])));
|
|
4803
|
+
}
|
|
4804
|
+
function insert(ctx, entityName, data) {
|
|
4805
|
+
const schema = ctx.schemas[entityName];
|
|
4806
|
+
const validatedData = asZodObject(schema).passthrough().parse(data);
|
|
4807
|
+
const transformed = transformForStorage(validatedData);
|
|
4808
|
+
const columns = Object.keys(transformed);
|
|
4809
|
+
const quotedCols = columns.map((c) => `"${c}"`);
|
|
4810
|
+
const sql = columns.length === 0 ? `INSERT INTO "${entityName}" DEFAULT VALUES` : `INSERT INTO "${entityName}" (${quotedCols.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
|
|
4811
|
+
const result = ctx.db.query(sql).run(...Object.values(transformed));
|
|
4812
|
+
const newEntity = getById(ctx, entityName, result.lastInsertRowid);
|
|
4813
|
+
if (!newEntity)
|
|
4814
|
+
throw new Error("Failed to retrieve entity after insertion");
|
|
4815
|
+
return newEntity;
|
|
4816
|
+
}
|
|
4817
|
+
function update(ctx, entityName, id, data) {
|
|
4818
|
+
const schema = ctx.schemas[entityName];
|
|
4819
|
+
const validatedData = asZodObject(schema).partial().parse(data);
|
|
4820
|
+
const transformed = transformForStorage(validatedData);
|
|
4821
|
+
if (Object.keys(transformed).length === 0)
|
|
4822
|
+
return getById(ctx, entityName, id);
|
|
4823
|
+
const setClause = Object.keys(transformed).map((key) => `"${key}" = ?`).join(", ");
|
|
4824
|
+
ctx.db.query(`UPDATE "${entityName}" SET ${setClause} WHERE id = ?`).run(...Object.values(transformed), id);
|
|
4825
|
+
return getById(ctx, entityName, id);
|
|
4826
|
+
}
|
|
4827
|
+
function updateWhere(ctx, entityName, data, conditions) {
|
|
4828
|
+
const schema = ctx.schemas[entityName];
|
|
4829
|
+
const validatedData = asZodObject(schema).partial().parse(data);
|
|
4830
|
+
const transformed = transformForStorage(validatedData);
|
|
4831
|
+
if (Object.keys(transformed).length === 0)
|
|
4832
|
+
return 0;
|
|
4833
|
+
const { clause, values: whereValues } = ctx.buildWhereClause(conditions);
|
|
4834
|
+
if (!clause)
|
|
4835
|
+
throw new Error("update().where() requires at least one condition");
|
|
4836
|
+
const setCols = Object.keys(transformed);
|
|
4837
|
+
const setClause = setCols.map((key) => `"${key}" = ?`).join(", ");
|
|
4838
|
+
const result = ctx.db.query(`UPDATE "${entityName}" SET ${setClause} ${clause}`).run(...setCols.map((key) => transformed[key]), ...whereValues);
|
|
4839
|
+
return result.changes ?? 0;
|
|
4840
|
+
}
|
|
4841
|
+
function createUpdateBuilder(ctx, entityName, data) {
|
|
4842
|
+
let _conditions = {};
|
|
4843
|
+
const builder = {
|
|
4844
|
+
where: (conditions) => {
|
|
4845
|
+
_conditions = { ..._conditions, ...conditions };
|
|
4846
|
+
return builder;
|
|
4847
|
+
},
|
|
4848
|
+
exec: () => updateWhere(ctx, entityName, data, _conditions)
|
|
4849
|
+
};
|
|
4850
|
+
return builder;
|
|
4851
|
+
}
|
|
4852
|
+
function upsert(ctx, entityName, data, conditions = {}) {
|
|
4853
|
+
const hasId = data?.id && typeof data.id === "number";
|
|
4854
|
+
const existing = hasId ? getById(ctx, entityName, data.id) : Object.keys(conditions ?? {}).length > 0 ? getOne(ctx, entityName, conditions) : null;
|
|
4855
|
+
if (existing) {
|
|
4856
|
+
const updateData = { ...data };
|
|
4857
|
+
delete updateData.id;
|
|
4858
|
+
return update(ctx, entityName, existing.id, updateData);
|
|
4859
|
+
}
|
|
4860
|
+
const insertData = { ...conditions ?? {}, ...data ?? {} };
|
|
4861
|
+
delete insertData.id;
|
|
4862
|
+
return insert(ctx, entityName, insertData);
|
|
4863
|
+
}
|
|
4864
|
+
function deleteEntity(ctx, entityName, id) {
|
|
4865
|
+
ctx.db.query(`DELETE FROM "${entityName}" WHERE id = ?`).run(id);
|
|
4866
|
+
}
|
|
4867
|
+
function insertMany(ctx, entityName, rows) {
|
|
4868
|
+
if (rows.length === 0)
|
|
4869
|
+
return [];
|
|
4870
|
+
const schema = ctx.schemas[entityName];
|
|
4871
|
+
const zodSchema = asZodObject(schema).passthrough();
|
|
4872
|
+
const txn = ctx.db.transaction(() => {
|
|
4873
|
+
const ids2 = [];
|
|
4874
|
+
for (const data of rows) {
|
|
4875
|
+
const validatedData = zodSchema.parse(data);
|
|
4876
|
+
const transformed = transformForStorage(validatedData);
|
|
4877
|
+
const columns = Object.keys(transformed);
|
|
4878
|
+
const quotedCols = columns.map((c) => `"${c}"`);
|
|
4879
|
+
const sql = columns.length === 0 ? `INSERT INTO "${entityName}" DEFAULT VALUES` : `INSERT INTO "${entityName}" (${quotedCols.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
|
|
4880
|
+
const result = ctx.db.query(sql).run(...Object.values(transformed));
|
|
4881
|
+
ids2.push(result.lastInsertRowid);
|
|
4882
|
+
}
|
|
4883
|
+
return ids2;
|
|
4884
|
+
});
|
|
4885
|
+
const ids = txn();
|
|
4886
|
+
return ids.map((id) => getById(ctx, entityName, id)).filter(Boolean);
|
|
4887
|
+
}
|
|
4888
|
+
|
|
4889
|
+
// src/entity.ts
|
|
4890
|
+
function attachMethods(ctx, entityName, entity) {
|
|
4891
|
+
const augmented = entity;
|
|
4892
|
+
augmented.update = (data) => update(ctx, entityName, entity.id, data);
|
|
4893
|
+
augmented.delete = () => deleteEntity(ctx, entityName, entity.id);
|
|
4894
|
+
for (const rel of ctx.relationships) {
|
|
4895
|
+
if (rel.from === entityName && rel.type === "belongs-to") {
|
|
4896
|
+
augmented[rel.relationshipField] = () => {
|
|
4897
|
+
const fkValue = entity[rel.foreignKey];
|
|
4898
|
+
return fkValue ? getById(ctx, rel.to, fkValue) : null;
|
|
4899
|
+
};
|
|
4900
|
+
} else if (rel.from === entityName && rel.type === "one-to-many") {
|
|
4901
|
+
const belongsToRel = ctx.relationships.find((r) => r.type === "belongs-to" && r.from === rel.to && r.to === rel.from);
|
|
4902
|
+
if (belongsToRel) {
|
|
4903
|
+
const fk = belongsToRel.foreignKey;
|
|
4904
|
+
augmented[rel.relationshipField] = () => {
|
|
4905
|
+
return findMany(ctx, rel.to, { [fk]: entity.id });
|
|
4906
|
+
};
|
|
4907
|
+
}
|
|
4729
4908
|
}
|
|
4730
4909
|
}
|
|
4731
|
-
|
|
4910
|
+
const storableFieldNames = new Set(getStorableFields(ctx.schemas[entityName]).map((f) => f.name));
|
|
4911
|
+
return new Proxy(augmented, {
|
|
4912
|
+
set: (target, prop, value) => {
|
|
4913
|
+
if (storableFieldNames.has(prop) && target[prop] !== value) {
|
|
4914
|
+
update(ctx, entityName, target.id, { [prop]: value });
|
|
4915
|
+
}
|
|
4916
|
+
target[prop] = value;
|
|
4917
|
+
return true;
|
|
4918
|
+
},
|
|
4919
|
+
get: (target, prop, receiver) => Reflect.get(target, prop, receiver)
|
|
4920
|
+
});
|
|
4732
4921
|
}
|
|
4733
4922
|
|
|
4734
4923
|
// src/database.ts
|
|
4735
4924
|
class _Database {
|
|
4736
4925
|
db;
|
|
4926
|
+
_reactive;
|
|
4737
4927
|
schemas;
|
|
4738
4928
|
relationships;
|
|
4739
4929
|
options;
|
|
4740
|
-
|
|
4741
|
-
|
|
4930
|
+
_ctx;
|
|
4931
|
+
_listeners = [];
|
|
4932
|
+
_changeWatermark = 0;
|
|
4933
|
+
_pollTimer = null;
|
|
4934
|
+
_pollInterval;
|
|
4742
4935
|
constructor(dbFile, schemas, options = {}) {
|
|
4743
4936
|
this.db = new SqliteDatabase(dbFile);
|
|
4744
4937
|
this.db.run("PRAGMA journal_mode = WAL");
|
|
4745
4938
|
this.db.run("PRAGMA foreign_keys = ON");
|
|
4746
4939
|
this.schemas = schemas;
|
|
4747
4940
|
this.options = options;
|
|
4748
|
-
this.
|
|
4941
|
+
this._reactive = options.reactive !== false;
|
|
4942
|
+
this._pollInterval = options.pollInterval ?? 100;
|
|
4749
4943
|
this.relationships = options.relations ? parseRelationsConfig(options.relations, schemas) : [];
|
|
4944
|
+
this._ctx = {
|
|
4945
|
+
db: this.db,
|
|
4946
|
+
schemas: this.schemas,
|
|
4947
|
+
relationships: this.relationships,
|
|
4948
|
+
attachMethods: (name, entity) => attachMethods(this._ctx, name, entity),
|
|
4949
|
+
buildWhereClause: (conds, prefix) => buildWhereClause(conds, prefix)
|
|
4950
|
+
};
|
|
4750
4951
|
this.initializeTables();
|
|
4952
|
+
if (this._reactive)
|
|
4953
|
+
this.initializeChangeTracking();
|
|
4751
4954
|
this.runMigrations();
|
|
4752
4955
|
if (options.indexes)
|
|
4753
4956
|
this.createIndexes(options.indexes);
|
|
4754
4957
|
for (const entityName of Object.keys(schemas)) {
|
|
4755
4958
|
const key = entityName;
|
|
4756
4959
|
const accessor = {
|
|
4757
|
-
insert: (data) => this.
|
|
4960
|
+
insert: (data) => insert(this._ctx, entityName, data),
|
|
4961
|
+
insertMany: (rows) => insertMany(this._ctx, entityName, rows),
|
|
4758
4962
|
update: (idOrData, data) => {
|
|
4759
4963
|
if (typeof idOrData === "number")
|
|
4760
|
-
return this.
|
|
4761
|
-
return this.
|
|
4964
|
+
return update(this._ctx, entityName, idOrData, data);
|
|
4965
|
+
return createUpdateBuilder(this._ctx, entityName, idOrData);
|
|
4966
|
+
},
|
|
4967
|
+
upsert: (conditions, data) => upsert(this._ctx, entityName, data, conditions),
|
|
4968
|
+
delete: (id) => deleteEntity(this._ctx, entityName, id),
|
|
4969
|
+
select: (...cols) => createQueryBuilder(this._ctx, entityName, cols),
|
|
4970
|
+
on: (event, callback) => {
|
|
4971
|
+
return this._registerListener(entityName, event, callback);
|
|
4762
4972
|
},
|
|
4763
|
-
upsert: (conditions, data) => this.upsert(entityName, data, conditions),
|
|
4764
|
-
delete: (id) => this.delete(entityName, id),
|
|
4765
|
-
select: (...cols) => this._createQueryBuilder(entityName, cols),
|
|
4766
4973
|
_tableName: entityName
|
|
4767
4974
|
};
|
|
4768
4975
|
this[key] = accessor;
|
|
@@ -4771,26 +4978,53 @@ class _Database {
|
|
|
4771
4978
|
initializeTables() {
|
|
4772
4979
|
for (const [entityName, schema] of Object.entries(this.schemas)) {
|
|
4773
4980
|
const storableFields = getStorableFields(schema);
|
|
4774
|
-
const columnDefs = storableFields.map((f) =>
|
|
4981
|
+
const columnDefs = storableFields.map((f) => `"${f.name}" ${zodTypeToSqlType(f.type)}`);
|
|
4775
4982
|
const constraints = [];
|
|
4776
4983
|
const belongsToRels = this.relationships.filter((rel) => rel.type === "belongs-to" && rel.from === entityName);
|
|
4777
4984
|
for (const rel of belongsToRels) {
|
|
4778
|
-
constraints.push(`FOREIGN KEY (${rel.foreignKey}) REFERENCES ${rel.to}(id) ON DELETE SET NULL`);
|
|
4985
|
+
constraints.push(`FOREIGN KEY ("${rel.foreignKey}") REFERENCES "${rel.to}"(id) ON DELETE SET NULL`);
|
|
4779
4986
|
}
|
|
4780
4987
|
const allCols = columnDefs.join(", ");
|
|
4781
4988
|
const allConstraints = constraints.length > 0 ? ", " + constraints.join(", ") : "";
|
|
4782
|
-
this.db.run(`CREATE TABLE IF NOT EXISTS ${entityName} (id INTEGER PRIMARY KEY AUTOINCREMENT, ${allCols}${allConstraints})`);
|
|
4783
|
-
}
|
|
4989
|
+
this.db.run(`CREATE TABLE IF NOT EXISTS "${entityName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, ${allCols}${allConstraints})`);
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
initializeChangeTracking() {
|
|
4993
|
+
this.db.run(`CREATE TABLE IF NOT EXISTS "_changes" (
|
|
4994
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4995
|
+
tbl TEXT NOT NULL,
|
|
4996
|
+
op TEXT NOT NULL,
|
|
4997
|
+
row_id INTEGER NOT NULL
|
|
4998
|
+
)`);
|
|
4999
|
+
for (const entityName of Object.keys(this.schemas)) {
|
|
5000
|
+
this.db.run(`CREATE TRIGGER IF NOT EXISTS "_trg_${entityName}_insert"
|
|
5001
|
+
AFTER INSERT ON "${entityName}"
|
|
5002
|
+
BEGIN
|
|
5003
|
+
INSERT INTO "_changes" (tbl, op, row_id) VALUES ('${entityName}', 'insert', NEW.id);
|
|
5004
|
+
END`);
|
|
5005
|
+
this.db.run(`CREATE TRIGGER IF NOT EXISTS "_trg_${entityName}_update"
|
|
5006
|
+
AFTER UPDATE ON "${entityName}"
|
|
5007
|
+
BEGIN
|
|
5008
|
+
INSERT INTO "_changes" (tbl, op, row_id) VALUES ('${entityName}', 'update', NEW.id);
|
|
5009
|
+
END`);
|
|
5010
|
+
this.db.run(`CREATE TRIGGER IF NOT EXISTS "_trg_${entityName}_delete"
|
|
5011
|
+
AFTER DELETE ON "${entityName}"
|
|
5012
|
+
BEGIN
|
|
5013
|
+
INSERT INTO "_changes" (tbl, op, row_id) VALUES ('${entityName}', 'delete', OLD.id);
|
|
5014
|
+
END`);
|
|
5015
|
+
}
|
|
5016
|
+
const row = this.db.query('SELECT MAX(id) as maxId FROM "_changes"').get();
|
|
5017
|
+
this._changeWatermark = row?.maxId ?? 0;
|
|
4784
5018
|
}
|
|
4785
5019
|
runMigrations() {
|
|
4786
5020
|
for (const [entityName, schema] of Object.entries(this.schemas)) {
|
|
4787
|
-
const existingColumns = this.db.query(`PRAGMA table_info(${entityName})`).all();
|
|
5021
|
+
const existingColumns = this.db.query(`PRAGMA table_info("${entityName}")`).all();
|
|
4788
5022
|
const existingNames = new Set(existingColumns.map((c) => c.name));
|
|
4789
5023
|
const storableFields = getStorableFields(schema);
|
|
4790
5024
|
for (const field of storableFields) {
|
|
4791
5025
|
if (!existingNames.has(field.name)) {
|
|
4792
5026
|
const sqlType = zodTypeToSqlType(field.type);
|
|
4793
|
-
this.db.run(`ALTER TABLE ${entityName} ADD COLUMN ${field.name} ${sqlType}`);
|
|
5027
|
+
this.db.run(`ALTER TABLE "${entityName}" ADD COLUMN "${field.name}" ${sqlType}`);
|
|
4794
5028
|
}
|
|
4795
5029
|
}
|
|
4796
5030
|
}
|
|
@@ -4800,277 +5034,73 @@ class _Database {
|
|
|
4800
5034
|
for (const def of indexDefs) {
|
|
4801
5035
|
const cols = Array.isArray(def) ? def : [def];
|
|
4802
5036
|
const idxName = `idx_${tableName}_${cols.join("_")}`;
|
|
4803
|
-
this.db.run(`CREATE INDEX IF NOT EXISTS ${idxName} ON ${tableName} (${cols.join(", ")})`);
|
|
5037
|
+
this.db.run(`CREATE INDEX IF NOT EXISTS "${idxName}" ON "${tableName}" (${cols.map((c) => `"${c}"`).join(", ")})`);
|
|
4804
5038
|
}
|
|
4805
5039
|
}
|
|
4806
5040
|
}
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
const
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
const sql = columns.length === 0 ? `INSERT INTO ${entityName} DEFAULT VALUES` : `INSERT INTO ${entityName} (${columns.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
|
|
4821
|
-
const result = this.db.query(sql).run(...Object.values(transformed));
|
|
4822
|
-
const newEntity = this._getById(entityName, result.lastInsertRowid);
|
|
4823
|
-
if (!newEntity)
|
|
4824
|
-
throw new Error("Failed to retrieve entity after insertion");
|
|
4825
|
-
this._bumpRevision(entityName);
|
|
4826
|
-
return newEntity;
|
|
4827
|
-
}
|
|
4828
|
-
_getById(entityName, id) {
|
|
4829
|
-
const row = this.db.query(`SELECT * FROM ${entityName} WHERE id = ?`).get(id);
|
|
4830
|
-
if (!row)
|
|
4831
|
-
return null;
|
|
4832
|
-
return this._attachMethods(entityName, transformFromStorage(row, this.schemas[entityName]));
|
|
4833
|
-
}
|
|
4834
|
-
_getOne(entityName, conditions) {
|
|
4835
|
-
const { clause, values } = this.buildWhereClause(conditions);
|
|
4836
|
-
const row = this.db.query(`SELECT * FROM ${entityName} ${clause} LIMIT 1`).get(...values);
|
|
4837
|
-
if (!row)
|
|
4838
|
-
return null;
|
|
4839
|
-
return this._attachMethods(entityName, transformFromStorage(row, this.schemas[entityName]));
|
|
4840
|
-
}
|
|
4841
|
-
_findMany(entityName, conditions = {}) {
|
|
4842
|
-
const { clause, values } = this.buildWhereClause(conditions);
|
|
4843
|
-
const rows = this.db.query(`SELECT * FROM ${entityName} ${clause}`).all(...values);
|
|
4844
|
-
return rows.map((row) => this._attachMethods(entityName, transformFromStorage(row, this.schemas[entityName])));
|
|
4845
|
-
}
|
|
4846
|
-
update(entityName, id, data) {
|
|
4847
|
-
const schema = this.schemas[entityName];
|
|
4848
|
-
const validatedData = asZodObject(schema).partial().parse(data);
|
|
4849
|
-
const transformed = transformForStorage(validatedData);
|
|
4850
|
-
if (Object.keys(transformed).length === 0)
|
|
4851
|
-
return this._getById(entityName, id);
|
|
4852
|
-
const setClause = Object.keys(transformed).map((key) => `${key} = ?`).join(", ");
|
|
4853
|
-
this.db.query(`UPDATE ${entityName} SET ${setClause} WHERE id = ?`).run(...Object.values(transformed), id);
|
|
4854
|
-
this._bumpRevision(entityName);
|
|
4855
|
-
const updatedEntity = this._getById(entityName, id);
|
|
4856
|
-
return updatedEntity;
|
|
4857
|
-
}
|
|
4858
|
-
_updateWhere(entityName, data, conditions) {
|
|
4859
|
-
const schema = this.schemas[entityName];
|
|
4860
|
-
const validatedData = asZodObject(schema).partial().parse(data);
|
|
4861
|
-
const transformed = transformForStorage(validatedData);
|
|
4862
|
-
if (Object.keys(transformed).length === 0)
|
|
4863
|
-
return 0;
|
|
4864
|
-
const { clause, values: whereValues } = this.buildWhereClause(conditions);
|
|
4865
|
-
if (!clause)
|
|
4866
|
-
throw new Error("update().where() requires at least one condition");
|
|
4867
|
-
const setCols = Object.keys(transformed);
|
|
4868
|
-
const setClause = setCols.map((key) => `${key} = ?`).join(", ");
|
|
4869
|
-
const result = this.db.query(`UPDATE ${entityName} SET ${setClause} ${clause}`).run(...setCols.map((key) => transformed[key]), ...whereValues);
|
|
4870
|
-
const affected = result.changes ?? 0;
|
|
4871
|
-
if (affected > 0)
|
|
4872
|
-
this._bumpRevision(entityName);
|
|
4873
|
-
return affected;
|
|
4874
|
-
}
|
|
4875
|
-
_createUpdateBuilder(entityName, data) {
|
|
4876
|
-
let _conditions = {};
|
|
4877
|
-
const builder = {
|
|
4878
|
-
where: (conditions) => {
|
|
4879
|
-
_conditions = { ..._conditions, ...conditions };
|
|
4880
|
-
return builder;
|
|
4881
|
-
},
|
|
4882
|
-
exec: () => this._updateWhere(entityName, data, _conditions)
|
|
5041
|
+
_registerListener(table, event, callback) {
|
|
5042
|
+
if (!this._reactive) {
|
|
5043
|
+
throw new Error("Change listeners are disabled. Set { reactive: true } (or omit it) in Database options to enable .on().");
|
|
5044
|
+
}
|
|
5045
|
+
const listener = { table, event, callback };
|
|
5046
|
+
this._listeners.push(listener);
|
|
5047
|
+
this._startPolling();
|
|
5048
|
+
return () => {
|
|
5049
|
+
const idx = this._listeners.indexOf(listener);
|
|
5050
|
+
if (idx >= 0)
|
|
5051
|
+
this._listeners.splice(idx, 1);
|
|
5052
|
+
if (this._listeners.length === 0)
|
|
5053
|
+
this._stopPolling();
|
|
4883
5054
|
};
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
const insertData = { ...conditions ?? {}, ...data ?? {} };
|
|
4895
|
-
delete insertData.id;
|
|
4896
|
-
return this.insert(entityName, insertData);
|
|
4897
|
-
}
|
|
4898
|
-
delete(entityName, id) {
|
|
4899
|
-
const entity = this._getById(entityName, id);
|
|
4900
|
-
if (entity) {
|
|
4901
|
-
this.db.query(`DELETE FROM ${entityName} WHERE id = ?`).run(id);
|
|
4902
|
-
this._bumpRevision(entityName);
|
|
4903
|
-
}
|
|
4904
|
-
}
|
|
4905
|
-
_attachMethods(entityName, entity) {
|
|
4906
|
-
const augmented = entity;
|
|
4907
|
-
augmented.update = (data) => this.update(entityName, entity.id, data);
|
|
4908
|
-
augmented.delete = () => this.delete(entityName, entity.id);
|
|
4909
|
-
for (const rel of this.relationships) {
|
|
4910
|
-
if (rel.from === entityName && rel.type === "belongs-to") {
|
|
4911
|
-
augmented[rel.relationshipField] = () => {
|
|
4912
|
-
const fkValue = entity[rel.foreignKey];
|
|
4913
|
-
return fkValue ? this._getById(rel.to, fkValue) : null;
|
|
4914
|
-
};
|
|
4915
|
-
} else if (rel.from === entityName && rel.type === "one-to-many") {
|
|
4916
|
-
const belongsToRel = this.relationships.find((r) => r.type === "belongs-to" && r.from === rel.to && r.to === rel.from);
|
|
4917
|
-
if (belongsToRel) {
|
|
4918
|
-
const fk = belongsToRel.foreignKey;
|
|
4919
|
-
augmented[rel.relationshipField] = () => {
|
|
4920
|
-
return this._findMany(rel.to, { [fk]: entity.id });
|
|
4921
|
-
};
|
|
4922
|
-
}
|
|
4923
|
-
}
|
|
5055
|
+
}
|
|
5056
|
+
_startPolling() {
|
|
5057
|
+
if (this._pollTimer)
|
|
5058
|
+
return;
|
|
5059
|
+
this._pollTimer = setInterval(() => this._processChanges(), this._pollInterval);
|
|
5060
|
+
}
|
|
5061
|
+
_stopPolling() {
|
|
5062
|
+
if (this._pollTimer) {
|
|
5063
|
+
clearInterval(this._pollTimer);
|
|
5064
|
+
this._pollTimer = null;
|
|
4924
5065
|
}
|
|
4925
|
-
const storableFieldNames = new Set(getStorableFields(this.schemas[entityName]).map((f) => f.name));
|
|
4926
|
-
return new Proxy(augmented, {
|
|
4927
|
-
set: (target, prop, value) => {
|
|
4928
|
-
if (storableFieldNames.has(prop) && target[prop] !== value) {
|
|
4929
|
-
this.update(entityName, target.id, { [prop]: value });
|
|
4930
|
-
}
|
|
4931
|
-
target[prop] = value;
|
|
4932
|
-
return true;
|
|
4933
|
-
},
|
|
4934
|
-
get: (target, prop, receiver) => Reflect.get(target, prop, receiver)
|
|
4935
|
-
});
|
|
4936
5066
|
}
|
|
4937
|
-
|
|
4938
|
-
const
|
|
4939
|
-
const
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
5067
|
+
_processChanges() {
|
|
5068
|
+
const head = this.db.query('SELECT MAX(id) as m FROM "_changes"').get();
|
|
5069
|
+
const maxId = head?.m ?? 0;
|
|
5070
|
+
if (maxId <= this._changeWatermark)
|
|
5071
|
+
return;
|
|
5072
|
+
const changes = this.db.query('SELECT id, tbl, op, row_id FROM "_changes" WHERE id > ? ORDER BY id').all(this._changeWatermark);
|
|
5073
|
+
for (const change of changes) {
|
|
5074
|
+
const listeners = this._listeners.filter((l) => l.table === change.tbl && l.event === change.op);
|
|
5075
|
+
if (listeners.length > 0) {
|
|
5076
|
+
if (change.op === "delete") {
|
|
5077
|
+
const payload = { id: change.row_id };
|
|
5078
|
+
for (const l of listeners) {
|
|
5079
|
+
try {
|
|
5080
|
+
l.callback(payload);
|
|
5081
|
+
} catch {}
|
|
4951
5082
|
}
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
const operator = Object.keys(value)[0];
|
|
4961
|
-
if (!operator?.startsWith("$")) {
|
|
4962
|
-
throw new Error(`Querying on nested object '${key}' not supported. Use operators like $gt.`);
|
|
4963
|
-
}
|
|
4964
|
-
const operand = value[operator];
|
|
4965
|
-
if (operator === "$in") {
|
|
4966
|
-
if (!Array.isArray(operand))
|
|
4967
|
-
throw new Error(`$in for '${key}' requires an array`);
|
|
4968
|
-
if (operand.length === 0) {
|
|
4969
|
-
parts.push("1 = 0");
|
|
4970
|
-
continue;
|
|
5083
|
+
} else {
|
|
5084
|
+
const row = getById(this._ctx, change.tbl, change.row_id);
|
|
5085
|
+
if (row) {
|
|
5086
|
+
for (const l of listeners) {
|
|
5087
|
+
try {
|
|
5088
|
+
l.callback(row);
|
|
5089
|
+
} catch {}
|
|
5090
|
+
}
|
|
4971
5091
|
}
|
|
4972
|
-
parts.push(`${fieldName} IN (${operand.map(() => "?").join(", ")})`);
|
|
4973
|
-
values.push(...operand.map((v) => transformForStorage({ v }).v));
|
|
4974
|
-
continue;
|
|
4975
5092
|
}
|
|
4976
|
-
const sqlOp = { $gt: ">", $gte: ">=", $lt: "<", $lte: "<=", $ne: "!=" }[operator];
|
|
4977
|
-
if (!sqlOp)
|
|
4978
|
-
throw new Error(`Unsupported operator '${operator}' on '${key}'`);
|
|
4979
|
-
parts.push(`${fieldName} ${sqlOp} ?`);
|
|
4980
|
-
values.push(transformForStorage({ operand }).operand);
|
|
4981
|
-
} else {
|
|
4982
|
-
parts.push(`${fieldName} = ?`);
|
|
4983
|
-
values.push(transformForStorage({ value }).value);
|
|
4984
5093
|
}
|
|
5094
|
+
this._changeWatermark = change.id;
|
|
4985
5095
|
}
|
|
4986
|
-
|
|
5096
|
+
this.db.run('DELETE FROM "_changes" WHERE id <= ?', this._changeWatermark);
|
|
4987
5097
|
}
|
|
4988
5098
|
transaction(callback) {
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
} catch (error) {
|
|
4995
|
-
this.db.run("ROLLBACK");
|
|
4996
|
-
throw new Error(`Transaction failed: ${error.message}`);
|
|
4997
|
-
}
|
|
4998
|
-
}
|
|
4999
|
-
_createQueryBuilder(entityName, initialCols) {
|
|
5000
|
-
const schema = this.schemas[entityName];
|
|
5001
|
-
const executor = (sql, params, raw) => {
|
|
5002
|
-
const rows = this.db.query(sql).all(...params);
|
|
5003
|
-
if (raw)
|
|
5004
|
-
return rows;
|
|
5005
|
-
return rows.map((row) => this._attachMethods(entityName, transformFromStorage(row, schema)));
|
|
5006
|
-
};
|
|
5007
|
-
const singleExecutor = (sql, params, raw) => {
|
|
5008
|
-
const results = executor(sql, params, raw);
|
|
5009
|
-
return results.length > 0 ? results[0] : null;
|
|
5010
|
-
};
|
|
5011
|
-
const joinResolver = (fromTable, toTable) => {
|
|
5012
|
-
const belongsTo = this.relationships.find((r) => r.type === "belongs-to" && r.from === fromTable && r.to === toTable);
|
|
5013
|
-
if (belongsTo)
|
|
5014
|
-
return { fk: belongsTo.foreignKey, pk: "id" };
|
|
5015
|
-
const reverse = this.relationships.find((r) => r.type === "belongs-to" && r.from === toTable && r.to === fromTable);
|
|
5016
|
-
if (reverse)
|
|
5017
|
-
return { fk: "id", pk: reverse.foreignKey };
|
|
5018
|
-
return null;
|
|
5019
|
-
};
|
|
5020
|
-
const revisionGetter = () => this._getRevision(entityName);
|
|
5021
|
-
const conditionResolver = (conditions) => {
|
|
5022
|
-
const resolved = {};
|
|
5023
|
-
for (const [key, value] of Object.entries(conditions)) {
|
|
5024
|
-
if (value && typeof value === "object" && typeof value.id === "number" && typeof value.delete === "function") {
|
|
5025
|
-
const fkCol = key + "_id";
|
|
5026
|
-
const rel = this.relationships.find((r) => r.type === "belongs-to" && r.from === entityName && r.foreignKey === fkCol);
|
|
5027
|
-
if (rel) {
|
|
5028
|
-
resolved[fkCol] = value.id;
|
|
5029
|
-
} else {
|
|
5030
|
-
const relByNav = this.relationships.find((r) => r.type === "belongs-to" && r.from === entityName && r.to === key + "s") || this.relationships.find((r) => r.type === "belongs-to" && r.from === entityName && r.to === key);
|
|
5031
|
-
if (relByNav) {
|
|
5032
|
-
resolved[relByNav.foreignKey] = value.id;
|
|
5033
|
-
} else {
|
|
5034
|
-
resolved[key] = value;
|
|
5035
|
-
}
|
|
5036
|
-
}
|
|
5037
|
-
} else {
|
|
5038
|
-
resolved[key] = value;
|
|
5039
|
-
}
|
|
5040
|
-
}
|
|
5041
|
-
return resolved;
|
|
5042
|
-
};
|
|
5043
|
-
const eagerLoader = (parentTable, relation, parentIds) => {
|
|
5044
|
-
const hasMany = this.relationships.find((r) => r.type === "one-to-many" && r.from === parentTable && r.relationshipField === relation);
|
|
5045
|
-
if (hasMany) {
|
|
5046
|
-
const belongsTo2 = this.relationships.find((r) => r.type === "belongs-to" && r.from === hasMany.to && r.to === parentTable);
|
|
5047
|
-
if (belongsTo2) {
|
|
5048
|
-
const fk = belongsTo2.foreignKey;
|
|
5049
|
-
const placeholders = parentIds.map(() => "?").join(", ");
|
|
5050
|
-
const childRows = this.db.query(`SELECT * FROM ${hasMany.to} WHERE ${fk} IN (${placeholders})`).all(...parentIds);
|
|
5051
|
-
const groups = new Map;
|
|
5052
|
-
const childSchema = this.schemas[hasMany.to];
|
|
5053
|
-
for (const rawRow of childRows) {
|
|
5054
|
-
const entity = this._attachMethods(hasMany.to, transformFromStorage(rawRow, childSchema));
|
|
5055
|
-
const parentId = rawRow[fk];
|
|
5056
|
-
if (!groups.has(parentId))
|
|
5057
|
-
groups.set(parentId, []);
|
|
5058
|
-
groups.get(parentId).push(entity);
|
|
5059
|
-
}
|
|
5060
|
-
return { key: relation, groups };
|
|
5061
|
-
}
|
|
5062
|
-
}
|
|
5063
|
-
const belongsTo = this.relationships.find((r) => r.type === "belongs-to" && r.from === parentTable && r.relationshipField === relation);
|
|
5064
|
-
if (belongsTo) {
|
|
5065
|
-
const fkValues = [...new Set(parentIds)];
|
|
5066
|
-
return null;
|
|
5067
|
-
}
|
|
5068
|
-
return null;
|
|
5069
|
-
};
|
|
5070
|
-
const builder = new QueryBuilder(entityName, executor, singleExecutor, joinResolver, conditionResolver, revisionGetter, eagerLoader, this.pollInterval);
|
|
5071
|
-
if (initialCols.length > 0)
|
|
5072
|
-
builder.select(...initialCols);
|
|
5073
|
-
return builder;
|
|
5099
|
+
return this.db.transaction(callback)();
|
|
5100
|
+
}
|
|
5101
|
+
close() {
|
|
5102
|
+
this._stopPolling();
|
|
5103
|
+
this.db.close();
|
|
5074
5104
|
}
|
|
5075
5105
|
query(callback) {
|
|
5076
5106
|
return executeProxyQuery(this.schemas, callback, (sql, params) => this.db.query(sql).all(...params));
|
|
@@ -5083,6 +5113,7 @@ export {
|
|
|
5083
5113
|
op,
|
|
5084
5114
|
createFunctionProxy,
|
|
5085
5115
|
createColumnProxy,
|
|
5116
|
+
compileIQO,
|
|
5086
5117
|
compileAST,
|
|
5087
5118
|
QueryBuilder,
|
|
5088
5119
|
Database,
|