sqlite-zod-orm 3.8.0 → 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/dist/index.js CHANGED
@@ -72,585 +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
- let lastRevision = null;
364
- let stopped = false;
365
- const poll = async () => {
366
- if (stopped)
367
- return;
368
- try {
369
- const rev = this.revisionGetter?.() ?? "0";
370
- if (rev !== lastRevision) {
371
- lastRevision = rev;
372
- const rows = this.all();
373
- await callback(rows);
374
- }
375
- } catch {}
376
- if (!stopped)
377
- setTimeout(poll, interval);
378
- };
379
- if (immediate) {
380
- poll();
381
- } else {
382
- setTimeout(poll, interval);
383
- }
384
- return () => {
385
- stopped = true;
386
- };
387
- }
388
- each(callback, options = {}) {
389
- const { interval = this.defaultPollInterval } = options;
390
- const userWhere = this.buildWhereClause();
391
- const maxRows = this.executor(`SELECT MAX(id) as _max FROM ${this.tableName} ${userWhere.sql ? `WHERE ${userWhere.sql}` : ""}`, userWhere.params, true);
392
- let lastMaxId = maxRows[0]?._max ?? 0;
393
- let lastRevision = this.revisionGetter?.() ?? "0";
394
- let stopped = false;
395
- const poll = async () => {
396
- if (stopped)
397
- return;
398
- const rev = this.revisionGetter?.() ?? "0";
399
- if (rev !== lastRevision) {
400
- lastRevision = rev;
401
- const params = [...userWhere.params, lastMaxId];
402
- const whereClause = userWhere.sql ? `WHERE ${userWhere.sql} AND id > ? ORDER BY id ASC` : `WHERE id > ? ORDER BY id ASC`;
403
- const sql = `SELECT * FROM ${this.tableName} ${whereClause}`;
404
- const newRows = this.executor(sql, params, false);
405
- for (const row of newRows) {
406
- if (stopped)
407
- return;
408
- await callback(row);
409
- lastMaxId = row.id;
410
- }
411
- }
412
- if (!stopped)
413
- setTimeout(poll, interval);
414
- };
415
- setTimeout(poll, interval);
416
- return () => {
417
- stopped = true;
418
- };
419
- }
420
- buildWhereClause() {
421
- const params = [];
422
- if (this.iqo.whereAST) {
423
- const compiled = compileAST(this.iqo.whereAST);
424
- return { sql: compiled.sql, params: compiled.params };
425
- }
426
- if (this.iqo.wheres.length > 0) {
427
- const whereParts = [];
428
- for (const w of this.iqo.wheres) {
429
- if (w.operator === "IN") {
430
- const arr = w.value;
431
- if (arr.length === 0) {
432
- whereParts.push("1 = 0");
433
- } else {
434
- const placeholders = arr.map(() => "?").join(", ");
435
- whereParts.push(`${w.field} IN (${placeholders})`);
436
- params.push(...arr.map(transformValueForStorage));
437
- }
438
- } else {
439
- whereParts.push(`${w.field} ${w.operator} ?`);
440
- params.push(transformValueForStorage(w.value));
441
- }
442
- }
443
- return { sql: whereParts.join(" AND "), params };
444
- }
445
- return { sql: "", params: [] };
446
- }
447
- then(onfulfilled, onrejected) {
448
- try {
449
- const result = this.all();
450
- return Promise.resolve(result).then(onfulfilled, onrejected);
451
- } catch (err) {
452
- return Promise.reject(err).then(onfulfilled, onrejected);
453
- }
454
- }
455
- }
456
-
457
- // src/proxy-query.ts
458
- class ColumnNode {
459
- table;
460
- column;
461
- alias;
462
- _type = "COL";
463
- constructor(table, column, alias) {
464
- this.table = table;
465
- this.column = column;
466
- this.alias = alias;
467
- }
468
- toString() {
469
- return `"${this.alias}"."${this.column}"`;
470
- }
471
- [Symbol.toPrimitive]() {
472
- return this.toString();
473
- }
474
- }
475
- function q(name) {
476
- return `"${name}"`;
477
- }
478
- function qRef(alias, column) {
479
- return `"${alias}"."${column}"`;
480
- }
481
- function createTableProxy(tableName, alias, columns) {
482
- return new Proxy({}, {
483
- get(_target, prop) {
484
- if (prop === Symbol.toPrimitive || prop === "toString" || prop === "valueOf") {
485
- return;
486
- }
487
- return new ColumnNode(tableName, prop, alias);
488
- },
489
- ownKeys() {
490
- return [...columns];
491
- },
492
- getOwnPropertyDescriptor(_target, prop) {
493
- if (columns.has(prop)) {
494
- return { configurable: true, enumerable: true, value: new ColumnNode(tableName, prop, alias) };
495
- }
496
- return;
497
- }
498
- });
499
- }
500
- function createContextProxy(schemas) {
501
- const aliases = new Map;
502
- let aliasCounter = 0;
503
- const proxy = new Proxy({}, {
504
- get(_target, tableName) {
505
- if (typeof tableName !== "string")
506
- return;
507
- const schema = schemas[tableName];
508
- const shape = schema ? schema.shape : {};
509
- const columns = new Set(Object.keys(shape));
510
- aliasCounter++;
511
- const alias = `t${aliasCounter}`;
512
- const tableProxy = createTableProxy(tableName, alias, columns);
513
- const entries = aliases.get(tableName) || [];
514
- entries.push({ tableName, alias, proxy: tableProxy });
515
- aliases.set(tableName, entries);
516
- return tableProxy;
517
- }
518
- });
519
- return { proxy, aliasMap: aliases };
520
- }
521
- function isColumnNode(val) {
522
- return val && typeof val === "object" && val._type === "COL";
523
- }
524
- function compileProxyQuery(queryResult, aliasMap) {
525
- const params = [];
526
- const tablesUsed = new Map;
527
- for (const [tableName, entries] of aliasMap) {
528
- for (const entry of entries) {
529
- tablesUsed.set(entry.alias, { tableName, alias: entry.alias });
530
- }
531
- }
532
- const selectParts = [];
533
- for (const [outputName, colOrValue] of Object.entries(queryResult.select)) {
534
- if (isColumnNode(colOrValue)) {
535
- if (outputName === colOrValue.column) {
536
- selectParts.push(qRef(colOrValue.alias, colOrValue.column));
537
- } else {
538
- selectParts.push(`${qRef(colOrValue.alias, colOrValue.column)} AS ${q(outputName)}`);
539
- }
540
- } else {
541
- selectParts.push(`? AS ${q(outputName)}`);
542
- params.push(colOrValue);
543
- }
544
- }
545
- const allAliases = [...tablesUsed.values()];
546
- if (allAliases.length === 0)
547
- throw new Error("No tables referenced in query.");
548
- const primaryAlias = allAliases[0];
549
- let sql = `SELECT ${selectParts.join(", ")} FROM ${q(primaryAlias.tableName)} ${q(primaryAlias.alias)}`;
550
- if (queryResult.join) {
551
- const joins = Array.isArray(queryResult.join[0]) ? queryResult.join : [queryResult.join];
552
- for (const [left, right] of joins) {
553
- const leftTable = tablesUsed.get(left.alias);
554
- const rightTable = tablesUsed.get(right.alias);
555
- if (!leftTable || !rightTable)
556
- throw new Error("Join references unknown table alias.");
557
- const joinAlias = leftTable.alias === primaryAlias.alias ? rightTable : leftTable;
558
- sql += ` JOIN ${q(joinAlias.tableName)} ${q(joinAlias.alias)} ON ${qRef(left.alias, left.column)} = ${qRef(right.alias, right.column)}`;
559
- }
560
- }
561
- if (queryResult.where && Object.keys(queryResult.where).length > 0) {
562
- const whereParts = [];
563
- for (const [key, value] of Object.entries(queryResult.where)) {
564
- let fieldRef;
565
- const quotedMatch = key.match(/^"([^"]+)"\."([^"]+)"$/);
566
- if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
567
- fieldRef = key;
568
- } else {
569
- fieldRef = qRef(primaryAlias.alias, key);
570
- }
571
- if (isColumnNode(value)) {
572
- whereParts.push(`${fieldRef} = ${qRef(value.alias, value.column)}`);
573
- } else if (Array.isArray(value)) {
574
- if (value.length === 0) {
575
- whereParts.push("1 = 0");
576
- } else {
577
- const placeholders = value.map(() => "?").join(", ");
578
- whereParts.push(`${fieldRef} IN (${placeholders})`);
579
- params.push(...value);
580
- }
581
- } else if (typeof value === "object" && value !== null && !(value instanceof Date)) {
582
- for (const [op2, operand] of Object.entries(value)) {
583
- if (op2 === "$in") {
584
- const arr = operand;
585
- if (arr.length === 0) {
586
- whereParts.push("1 = 0");
587
- } else {
588
- const placeholders = arr.map(() => "?").join(", ");
589
- whereParts.push(`${fieldRef} IN (${placeholders})`);
590
- params.push(...arr);
591
- }
592
- continue;
593
- }
594
- const opMap = {
595
- $gt: ">",
596
- $gte: ">=",
597
- $lt: "<",
598
- $lte: "<=",
599
- $ne: "!="
600
- };
601
- const sqlOp = opMap[op2];
602
- if (!sqlOp)
603
- throw new Error(`Unsupported where operator: ${op2}`);
604
- whereParts.push(`${fieldRef} ${sqlOp} ?`);
605
- params.push(operand);
606
- }
607
- } else {
608
- whereParts.push(`${fieldRef} = ?`);
609
- params.push(value instanceof Date ? value.toISOString() : value);
610
- }
611
- }
612
- if (whereParts.length > 0) {
613
- sql += ` WHERE ${whereParts.join(" AND ")}`;
614
- }
615
- }
616
- if (queryResult.orderBy) {
617
- const parts = [];
618
- for (const [key, dir] of Object.entries(queryResult.orderBy)) {
619
- let fieldRef;
620
- const quotedMatch = key.match(/^"([^"]+)"\."([^"]+)"$/);
621
- if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
622
- fieldRef = key;
623
- } else {
624
- fieldRef = qRef(primaryAlias.alias, key);
625
- }
626
- parts.push(`${fieldRef} ${dir.toUpperCase()}`);
627
- }
628
- if (parts.length > 0) {
629
- sql += ` ORDER BY ${parts.join(", ")}`;
630
- }
631
- }
632
- if (queryResult.groupBy && queryResult.groupBy.length > 0) {
633
- const parts = queryResult.groupBy.filter(Boolean).map((col) => qRef(col.alias, col.column));
634
- sql += ` GROUP BY ${parts.join(", ")}`;
635
- }
636
- if (queryResult.limit !== undefined) {
637
- sql += ` LIMIT ${queryResult.limit}`;
638
- }
639
- if (queryResult.offset !== undefined) {
640
- sql += ` OFFSET ${queryResult.offset}`;
641
- }
642
- return { sql, params };
643
- }
644
- function executeProxyQuery(schemas, callback, executor) {
645
- const { proxy, aliasMap } = createContextProxy(schemas);
646
- const queryResult = callback(proxy);
647
- const { sql, params } = compileProxyQuery(queryResult, aliasMap);
648
- return executor(sql, params);
649
- }
650
-
651
- // src/types.ts
652
- var asZodObject = (s) => s;
653
-
654
75
  // node_modules/zod/v3/external.js
655
76
  var exports_external = {};
656
77
  __export(exports_external, {
@@ -3837,917 +3258,1718 @@ ZodSet.create = (valueType, params) => {
3837
3258
  });
3838
3259
  };
3839
3260
 
3840
- class ZodFunction extends ZodType {
3841
- constructor() {
3842
- super(...arguments);
3843
- this.validate = this.implement;
3261
+ class ZodFunction extends ZodType {
3262
+ constructor() {
3263
+ super(...arguments);
3264
+ this.validate = this.implement;
3265
+ }
3266
+ _parse(input) {
3267
+ const { ctx } = this._processInputParams(input);
3268
+ if (ctx.parsedType !== ZodParsedType.function) {
3269
+ addIssueToContext(ctx, {
3270
+ code: ZodIssueCode.invalid_type,
3271
+ expected: ZodParsedType.function,
3272
+ received: ctx.parsedType
3273
+ });
3274
+ return INVALID;
3275
+ }
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
+ }
3285
+ });
3286
+ }
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
+ });
3315
+ } else {
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
+ });
3329
+ }
3330
+ }
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;
3352
+ }
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)
3363
+ });
3364
+ }
3365
+ }
3366
+
3367
+ class ZodLazy extends ZodType {
3368
+ get schema() {
3369
+ return this._def.getter();
3370
+ }
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 });
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 {
3386
+ _parse(input) {
3387
+ if (input.data !== this._def.value) {
3388
+ const ctx = this._getOrReturnCtx(input);
3389
+ addIssueToContext(ctx, {
3390
+ received: ctx.data,
3391
+ code: ZodIssueCode.invalid_literal,
3392
+ expected: this._def.value
3393
+ });
3394
+ return INVALID;
3395
+ }
3396
+ return { status: "valid", value: input.data };
3397
+ }
3398
+ get value() {
3399
+ return this._def.value;
3400
+ }
3401
+ }
3402
+ ZodLiteral.create = (value, params) => {
3403
+ return new ZodLiteral({
3404
+ value,
3405
+ typeName: ZodFirstPartyTypeKind.ZodLiteral,
3406
+ ...processCreateParams(params)
3407
+ });
3408
+ };
3409
+ function createZodEnum(values, params) {
3410
+ return new ZodEnum({
3411
+ values,
3412
+ typeName: ZodFirstPartyTypeKind.ZodEnum,
3413
+ ...processCreateParams(params)
3414
+ });
3415
+ }
3416
+
3417
+ class ZodEnum extends ZodType {
3418
+ _parse(input) {
3419
+ if (typeof input.data !== "string") {
3420
+ const ctx = this._getOrReturnCtx(input);
3421
+ const expectedValues = this._def.values;
3422
+ addIssueToContext(ctx, {
3423
+ expected: util.joinValues(expectedValues),
3424
+ received: ctx.parsedType,
3425
+ code: ZodIssueCode.invalid_type
3426
+ });
3427
+ return INVALID;
3428
+ }
3429
+ if (!this._cache) {
3430
+ this._cache = new Set(this._def.values);
3431
+ }
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;
3441
+ }
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;
3451
+ }
3452
+ return enumValues;
3453
+ }
3454
+ get Values() {
3455
+ const enumValues = {};
3456
+ for (const val of this._def.values) {
3457
+ enumValues[val] = val;
3458
+ }
3459
+ return enumValues;
3460
+ }
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, {
3470
+ ...this._def,
3471
+ ...newDef
3472
+ });
3473
+ }
3474
+ exclude(values, newDef = this._def) {
3475
+ return ZodEnum.create(this.options.filter((opt) => !values.includes(opt)), {
3476
+ ...this._def,
3477
+ ...newDef
3478
+ });
3479
+ }
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);
3509
+ }
3510
+ get enum() {
3511
+ return this._def.values;
3512
+ }
3513
+ }
3514
+ ZodNativeEnum.create = (values, params) => {
3515
+ return new ZodNativeEnum({
3516
+ values,
3517
+ typeName: ZodFirstPartyTypeKind.ZodNativeEnum,
3518
+ ...processCreateParams(params)
3519
+ });
3520
+ };
3521
+
3522
+ class ZodPromise extends ZodType {
3523
+ unwrap() {
3524
+ return this._def.type;
3844
3525
  }
3845
3526
  _parse(input) {
3846
3527
  const { ctx } = this._processInputParams(input);
3847
- if (ctx.parsedType !== ZodParsedType.function) {
3528
+ if (ctx.parsedType !== ZodParsedType.promise && ctx.common.async === false) {
3848
3529
  addIssueToContext(ctx, {
3849
3530
  code: ZodIssueCode.invalid_type,
3850
- expected: ZodParsedType.function,
3531
+ expected: ZodParsedType.promise,
3851
3532
  received: ctx.parsedType
3852
3533
  });
3853
3534
  return INVALID;
3854
3535
  }
3855
- function makeArgsIssue(args, error) {
3856
- return makeIssue({
3857
- data: args,
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, {
3858
3539
  path: ctx.path,
3859
- errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), en_default].filter((x) => !!x),
3860
- issueData: {
3861
- code: ZodIssueCode.invalid_arguments,
3862
- argumentsError: error
3863
- }
3540
+ errorMap: ctx.common.contextualErrorMap
3864
3541
  });
3865
- }
3866
- function makeReturnsIssue(returns, error) {
3867
- return makeIssue({
3868
- data: returns,
3869
- path: ctx.path,
3870
- errorMaps: [ctx.common.contextualErrorMap, ctx.schemaErrorMap, getErrorMap(), en_default].filter((x) => !!x),
3871
- issueData: {
3872
- code: ZodIssueCode.invalid_return_type,
3873
- returnTypeError: error
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();
3874
3570
  }
3875
- });
3876
- }
3877
- const params = { errorMap: ctx.common.contextualErrorMap };
3878
- const fn = ctx.data;
3879
- if (this._def.returns instanceof ZodPromise) {
3880
- const me = this;
3881
- return OK(async function(...args) {
3882
- const error = new ZodError([]);
3883
- const parsedArgs = await me._def.args.parseAsync(args, params).catch((e) => {
3884
- error.addIssue(makeArgsIssue(args, e));
3885
- throw error;
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;
3886
3595
  });
3887
- const result = await Reflect.apply(fn, this, parsedArgs);
3888
- const parsedReturns = await me._def.returns._def.type.parseAsync(result, params).catch((e) => {
3889
- error.addIssue(makeReturnsIssue(result, e));
3890
- throw error;
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
3891
3603
  });
3892
- return parsedReturns;
3893
- });
3894
- } else {
3895
- const me = this;
3896
- return OK(function(...args) {
3897
- const parsedArgs = me._def.args.safeParse(args, params);
3898
- if (!parsedArgs.success) {
3899
- throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
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);
3900
3618
  }
3901
- const result = Reflect.apply(fn, this, parsedArgs.data);
3902
- const parsedReturns = me._def.returns.safeParse(result, params);
3903
- if (!parsedReturns.success) {
3904
- 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.");
3905
3621
  }
3906
- return parsedReturns.data;
3907
- });
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
+ }
3908
3647
  }
3909
- }
3910
- parameters() {
3911
- return this._def.args;
3912
- }
3913
- returnType() {
3914
- return this._def.returns;
3915
- }
3916
- args(...items) {
3917
- return new ZodFunction({
3918
- ...this._def,
3919
- args: ZodTuple.create(items).rest(ZodUnknown.create())
3920
- });
3921
- }
3922
- returns(returnType) {
3923
- return new ZodFunction({
3924
- ...this._def,
3925
- returns: returnType
3926
- });
3927
- }
3928
- implement(func) {
3929
- const validatedFunc = this.parse(func);
3930
- return validatedFunc;
3931
- }
3932
- strictImplement(func) {
3933
- const validatedFunc = this.parse(func);
3934
- return validatedFunc;
3935
- }
3936
- static create(args, returns, params) {
3937
- return new ZodFunction({
3938
- args: args ? args : ZodTuple.create([]).rest(ZodUnknown.create()),
3939
- returns: returns || ZodUnknown.create(),
3940
- typeName: ZodFirstPartyTypeKind.ZodFunction,
3941
- ...processCreateParams(params)
3942
- });
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);
3943
3674
  }
3944
3675
  }
3945
-
3946
- class ZodLazy extends ZodType {
3947
- get schema() {
3948
- return this._def.getter();
3949
- }
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 {
3950
3693
  _parse(input) {
3951
- const { ctx } = this._processInputParams(input);
3952
- const lazySchema = this._def.getter();
3953
- return lazySchema._parse({ data: ctx.data, path: ctx.path, parent: ctx });
3694
+ const parsedType = this._getType(input);
3695
+ if (parsedType === ZodParsedType.undefined) {
3696
+ return OK(undefined);
3697
+ }
3698
+ return this._def.innerType._parse(input);
3699
+ }
3700
+ unwrap() {
3701
+ return this._def.innerType;
3954
3702
  }
3955
3703
  }
3956
- ZodLazy.create = (getter, params) => {
3957
- return new ZodLazy({
3958
- getter,
3959
- typeName: ZodFirstPartyTypeKind.ZodLazy,
3704
+ ZodOptional.create = (type, params) => {
3705
+ return new ZodOptional({
3706
+ innerType: type,
3707
+ typeName: ZodFirstPartyTypeKind.ZodOptional,
3960
3708
  ...processCreateParams(params)
3961
3709
  });
3962
3710
  };
3963
3711
 
3964
- class ZodLiteral extends ZodType {
3712
+ class ZodNullable extends ZodType {
3965
3713
  _parse(input) {
3966
- if (input.data !== this._def.value) {
3967
- const ctx = this._getOrReturnCtx(input);
3968
- addIssueToContext(ctx, {
3969
- received: ctx.data,
3970
- code: ZodIssueCode.invalid_literal,
3971
- expected: this._def.value
3972
- });
3973
- return INVALID;
3714
+ const parsedType = this._getType(input);
3715
+ if (parsedType === ZodParsedType.null) {
3716
+ return OK(null);
3974
3717
  }
3975
- return { status: "valid", value: input.data };
3718
+ return this._def.innerType._parse(input);
3976
3719
  }
3977
- get value() {
3978
- return this._def.value;
3720
+ unwrap() {
3721
+ return this._def.innerType;
3979
3722
  }
3980
3723
  }
3981
- ZodLiteral.create = (value, params) => {
3982
- return new ZodLiteral({
3983
- value,
3984
- typeName: ZodFirstPartyTypeKind.ZodLiteral,
3724
+ ZodNullable.create = (type, params) => {
3725
+ return new ZodNullable({
3726
+ innerType: type,
3727
+ typeName: ZodFirstPartyTypeKind.ZodNullable,
3985
3728
  ...processCreateParams(params)
3986
3729
  });
3987
3730
  };
3988
- function createZodEnum(values, params) {
3989
- return new ZodEnum({
3990
- values,
3991
- typeName: ZodFirstPartyTypeKind.ZodEnum,
3992
- ...processCreateParams(params)
3993
- });
3994
- }
3995
3731
 
3996
- class ZodEnum extends ZodType {
3732
+ class ZodDefault extends ZodType {
3997
3733
  _parse(input) {
3998
- if (typeof input.data !== "string") {
3999
- const ctx = this._getOrReturnCtx(input);
4000
- const expectedValues = this._def.values;
4001
- addIssueToContext(ctx, {
4002
- expected: util.joinValues(expectedValues),
4003
- received: ctx.parsedType,
4004
- code: ZodIssueCode.invalid_type
4005
- });
4006
- return INVALID;
4007
- }
4008
- if (!this._cache) {
4009
- this._cache = new Set(this._def.values);
4010
- }
4011
- if (!this._cache.has(input.data)) {
4012
- const ctx = this._getOrReturnCtx(input);
4013
- const expectedValues = this._def.values;
4014
- addIssueToContext(ctx, {
4015
- received: ctx.data,
4016
- code: ZodIssueCode.invalid_enum_value,
4017
- options: expectedValues
4018
- });
4019
- return INVALID;
4020
- }
4021
- return OK(input.data);
4022
- }
4023
- get options() {
4024
- return this._def.values;
4025
- }
4026
- get enum() {
4027
- const enumValues = {};
4028
- for (const val of this._def.values) {
4029
- enumValues[val] = val;
4030
- }
4031
- return enumValues;
4032
- }
4033
- get Values() {
4034
- const enumValues = {};
4035
- for (const val of this._def.values) {
4036
- enumValues[val] = val;
4037
- }
4038
- return enumValues;
4039
- }
4040
- get Enum() {
4041
- const enumValues = {};
4042
- for (const val of this._def.values) {
4043
- 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();
4044
3738
  }
4045
- return enumValues;
4046
- }
4047
- extract(values, newDef = this._def) {
4048
- return ZodEnum.create(values, {
4049
- ...this._def,
4050
- ...newDef
3739
+ return this._def.innerType._parse({
3740
+ data,
3741
+ path: ctx.path,
3742
+ parent: ctx
4051
3743
  });
4052
3744
  }
4053
- exclude(values, newDef = this._def) {
4054
- return ZodEnum.create(this.options.filter((opt) => !values.includes(opt)), {
4055
- ...this._def,
4056
- ...newDef
4057
- });
3745
+ removeDefault() {
3746
+ return this._def.innerType;
4058
3747
  }
4059
3748
  }
4060
- ZodEnum.create = createZodEnum;
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
+ };
4061
3757
 
4062
- class ZodNativeEnum extends ZodType {
3758
+ class ZodCatch extends ZodType {
4063
3759
  _parse(input) {
4064
- const nativeEnumValues = util.getValidEnumValues(this._def.values);
4065
- const ctx = this._getOrReturnCtx(input);
4066
- if (ctx.parsedType !== ZodParsedType.string && ctx.parsedType !== ZodParsedType.number) {
4067
- const expectedValues = util.objectValues(nativeEnumValues);
4068
- addIssueToContext(ctx, {
4069
- expected: util.joinValues(expectedValues),
4070
- received: ctx.parsedType,
4071
- code: ZodIssueCode.invalid_type
4072
- });
4073
- return INVALID;
4074
- }
4075
- if (!this._cache) {
4076
- this._cache = new Set(util.getValidEnumValues(this._def.values));
4077
- }
4078
- if (!this._cache.has(input.data)) {
4079
- const expectedValues = util.objectValues(nativeEnumValues);
4080
- addIssueToContext(ctx, {
4081
- received: ctx.data,
4082
- code: ZodIssueCode.invalid_enum_value,
4083
- options: expectedValues
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
+ };
4084
3786
  });
4085
- return INVALID;
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
+ };
4086
3797
  }
4087
- return OK(input.data);
4088
3798
  }
4089
- get enum() {
4090
- return this._def.values;
3799
+ removeCatch() {
3800
+ return this._def.innerType;
4091
3801
  }
4092
3802
  }
4093
- ZodNativeEnum.create = (values, params) => {
4094
- return new ZodNativeEnum({
4095
- values,
4096
- typeName: ZodFirstPartyTypeKind.ZodNativeEnum,
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,
4097
3808
  ...processCreateParams(params)
4098
3809
  });
4099
3810
  };
4100
3811
 
4101
- class ZodPromise extends ZodType {
4102
- unwrap() {
4103
- return this._def.type;
4104
- }
3812
+ class ZodNaN extends ZodType {
4105
3813
  _parse(input) {
4106
- const { ctx } = this._processInputParams(input);
4107
- if (ctx.parsedType !== ZodParsedType.promise && ctx.common.async === false) {
3814
+ const parsedType = this._getType(input);
3815
+ if (parsedType !== ZodParsedType.nan) {
3816
+ const ctx = this._getOrReturnCtx(input);
4108
3817
  addIssueToContext(ctx, {
4109
3818
  code: ZodIssueCode.invalid_type,
4110
- expected: ZodParsedType.promise,
3819
+ expected: ZodParsedType.nan,
4111
3820
  received: ctx.parsedType
4112
3821
  });
4113
3822
  return INVALID;
4114
3823
  }
4115
- const promisified = ctx.parsedType === ZodParsedType.promise ? ctx.data : Promise.resolve(ctx.data);
4116
- return OK(promisified.then((data) => {
4117
- return this._def.type.parseAsync(data, {
4118
- path: ctx.path,
4119
- errorMap: ctx.common.contextualErrorMap
4120
- });
4121
- }));
3824
+ return { status: "valid", value: input.data };
4122
3825
  }
4123
3826
  }
4124
- ZodPromise.create = (schema, params) => {
4125
- return new ZodPromise({
4126
- type: schema,
4127
- typeName: ZodFirstPartyTypeKind.ZodPromise,
3827
+ ZodNaN.create = (params) => {
3828
+ return new ZodNaN({
3829
+ typeName: ZodFirstPartyTypeKind.ZodNaN,
4128
3830
  ...processCreateParams(params)
4129
3831
  });
4130
3832
  };
3833
+ var BRAND = Symbol("zod_brand");
4131
3834
 
4132
- class ZodEffects extends ZodType {
4133
- innerType() {
4134
- return this._def.schema;
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
+ });
4135
3844
  }
4136
- sourceType() {
4137
- return this._def.schema._def.typeName === ZodFirstPartyTypeKind.ZodEffects ? this._def.schema.sourceType() : this._def.schema;
3845
+ unwrap() {
3846
+ return this._def.type;
4138
3847
  }
3848
+ }
3849
+
3850
+ class ZodPipeline extends ZodType {
4139
3851
  _parse(input) {
4140
3852
  const { status, ctx } = this._processInputParams(input);
4141
- const effect = this._def.effect || null;
4142
- const checkCtx = {
4143
- addIssue: (arg) => {
4144
- addIssueToContext(ctx, arg);
4145
- if (arg.fatal) {
4146
- status.abort();
4147
- } else {
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") {
4148
3863
  status.dirty();
4149
- }
4150
- },
4151
- get path() {
4152
- return ctx.path;
4153
- }
4154
- };
4155
- checkCtx.addIssue = checkCtx.addIssue.bind(checkCtx);
4156
- if (effect.type === "preprocess") {
4157
- const processed = effect.transform(ctx.data, checkCtx);
4158
- if (ctx.common.async) {
4159
- return Promise.resolve(processed).then(async (processed2) => {
4160
- if (status.value === "aborted")
4161
- return INVALID;
4162
- const result = await this._def.schema._parseAsync({
4163
- data: processed2,
3864
+ return DIRTY(inResult.value);
3865
+ } else {
3866
+ return this._def.out._parseAsync({
3867
+ data: inResult.value,
4164
3868
  path: ctx.path,
4165
3869
  parent: ctx
4166
3870
  });
4167
- if (result.status === "aborted")
4168
- return INVALID;
4169
- if (result.status === "dirty")
4170
- return DIRTY(result.value);
4171
- if (status.value === "dirty")
4172
- return DIRTY(result.value);
4173
- return result;
4174
- });
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
+ };
4175
3888
  } else {
4176
- if (status.value === "aborted")
4177
- return INVALID;
4178
- const result = this._def.schema._parseSync({
4179
- data: processed,
3889
+ return this._def.out._parseSync({
3890
+ data: inResult.value,
4180
3891
  path: ctx.path,
4181
3892
  parent: ctx
4182
3893
  });
4183
- if (result.status === "aborted")
4184
- return INVALID;
4185
- if (result.status === "dirty")
4186
- return DIRTY(result.value);
4187
- if (status.value === "dirty")
4188
- return DIRTY(result.value);
4189
- return result;
4190
3894
  }
4191
3895
  }
4192
- if (effect.type === "refinement") {
4193
- const executeRefinement = (acc) => {
4194
- const result = effect.refinement(acc, checkCtx);
4195
- if (ctx.common.async) {
4196
- return Promise.resolve(result);
4197
- }
4198
- if (result instanceof Promise) {
4199
- throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");
4200
- }
4201
- return acc;
4202
- };
4203
- if (ctx.common.async === false) {
4204
- const inner = this._def.schema._parseSync({
4205
- data: ctx.data,
4206
- path: ctx.path,
4207
- parent: ctx
4208
- });
4209
- if (inner.status === "aborted")
4210
- return INVALID;
4211
- if (inner.status === "dirty")
4212
- status.dirty();
4213
- executeRefinement(inner.value);
4214
- return { status: status.value, value: inner.value };
4215
- } else {
4216
- return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => {
4217
- if (inner.status === "aborted")
4218
- return INVALID;
4219
- if (inner.status === "dirty")
4220
- status.dirty();
4221
- return executeRefinement(inner.value).then(() => {
4222
- return { status: status.value, value: inner.value };
4223
- });
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
+ }
4224
3944
  });
4225
3945
  }
4226
- }
4227
- if (effect.type === "transform") {
4228
- if (ctx.common.async === false) {
4229
- const base = this._def.schema._parseSync({
4230
- data: ctx.data,
4231
- path: ctx.path,
4232
- parent: ctx
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}'`);
4058
+ }
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
4233
4072
  });
4234
- if (!isValid(base))
4235
- return INVALID;
4236
- const result = effect.transform(base.value, checkCtx);
4237
- if (result instanceof Promise) {
4238
- throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
4239
- }
4240
- return { status: status.value, value: result };
4241
- } else {
4242
- return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => {
4243
- if (!isValid(base))
4244
- return INVALID;
4245
- return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({
4246
- status: status.value,
4247
- value: result
4248
- }));
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: ""
4249
4083
  });
4084
+ added.add(otmKey);
4250
4085
  }
4251
4086
  }
4252
- util.assertNever(effect);
4253
4087
  }
4088
+ return relationships;
4254
4089
  }
4255
- ZodEffects.create = (schema, effect, params) => {
4256
- return new ZodEffects({
4257
- schema,
4258
- typeName: ZodFirstPartyTypeKind.ZodEffects,
4259
- effect,
4260
- ...processCreateParams(params)
4261
- });
4262
- };
4263
- ZodEffects.createWithPreprocess = (preprocess, schema, params) => {
4264
- return new ZodEffects({
4265
- schema,
4266
- effect: { type: "preprocess", transform: preprocess },
4267
- typeName: ZodFirstPartyTypeKind.ZodEffects,
4268
- ...processCreateParams(params)
4269
- });
4270
- };
4271
- class ZodOptional extends ZodType {
4272
- _parse(input) {
4273
- const parsedType = this._getType(input);
4274
- if (parsedType === ZodParsedType.undefined) {
4275
- return OK(undefined);
4276
- }
4277
- 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;
4278
4096
  }
4279
- unwrap() {
4280
- return this._def.innerType;
4097
+ if (zodType instanceof exports_external.ZodDefault) {
4098
+ zodType = zodType._def.innerType;
4281
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";
4282
4107
  }
4283
- ZodOptional.create = (type, params) => {
4284
- return new ZodOptional({
4285
- innerType: type,
4286
- typeName: ZodFirstPartyTypeKind.ZodOptional,
4287
- ...processCreateParams(params)
4288
- });
4289
- };
4290
-
4291
- class ZodNullable extends ZodType {
4292
- _parse(input) {
4293
- const parsedType = this._getType(input);
4294
- if (parsedType === ZodParsedType.null) {
4295
- 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;
4296
4117
  }
4297
- return this._def.innerType._parse(input);
4298
4118
  }
4299
- unwrap() {
4300
- return this._def.innerType;
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
+ }
4301
4138
  }
4139
+ return transformed;
4302
4140
  }
4303
- ZodNullable.create = (type, params) => {
4304
- return new ZodNullable({
4305
- innerType: type,
4306
- typeName: ZodFirstPartyTypeKind.ZodNullable,
4307
- ...processCreateParams(params)
4308
- });
4309
- };
4310
4141
 
4311
- class ZodDefault extends ZodType {
4312
- _parse(input) {
4313
- const { ctx } = this._processInputParams(input);
4314
- let data = ctx.data;
4315
- if (ctx.parsedType === ZodParsedType.undefined) {
4316
- data = this._def.defaultValue();
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}.*`);
4317
4174
  }
4318
- return this._def.innerType._parse({
4319
- data,
4320
- path: ctx.path,
4321
- parent: ctx
4322
- });
4323
4175
  }
4324
- removeDefault() {
4325
- return this._def.innerType;
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}`;
4326
4179
  }
4327
- }
4328
- ZodDefault.create = (type, params) => {
4329
- return new ZodDefault({
4330
- innerType: type,
4331
- typeName: ZodFirstPartyTypeKind.ZodDefault,
4332
- defaultValue: typeof params.default === "function" ? params.default : () => params.default,
4333
- ...processCreateParams(params)
4334
- });
4335
- };
4336
-
4337
- class ZodCatch extends ZodType {
4338
- _parse(input) {
4339
- const { ctx } = this._processInputParams(input);
4340
- const newCtx = {
4341
- ...ctx,
4342
- common: {
4343
- ...ctx.common,
4344
- issues: []
4345
- }
4346
- };
4347
- const result = this._def.innerType._parse({
4348
- data: newCtx.data,
4349
- path: newCtx.path,
4350
- parent: {
4351
- ...newCtx
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));
4212
+ }
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}`;
4352
4238
  }
4353
- });
4354
- if (isAsync(result)) {
4355
- return result.then((result2) => {
4356
- return {
4357
- status: "valid",
4358
- value: result2.status === "valid" ? result2.value : this._def.catchValue({
4359
- get error() {
4360
- return new ZodError(newCtx.common.issues);
4361
- },
4362
- input: newCtx.data
4363
- })
4364
- };
4365
- });
4366
- } else {
4367
- return {
4368
- status: "valid",
4369
- value: result.status === "valid" ? result.value : this._def.catchValue({
4370
- get error() {
4371
- return new ZodError(newCtx.common.issues);
4372
- },
4373
- input: newCtx.data
4374
- })
4375
- };
4376
4239
  }
4377
4240
  }
4378
- removeCatch() {
4379
- return this._def.innerType;
4241
+ if (iqo.groupBy.length > 0) {
4242
+ sql += ` GROUP BY ${iqo.groupBy.join(", ")}`;
4380
4243
  }
4381
- }
4382
- ZodCatch.create = (type, params) => {
4383
- return new ZodCatch({
4384
- innerType: type,
4385
- typeName: ZodFirstPartyTypeKind.ZodCatch,
4386
- catchValue: typeof params.catch === "function" ? params.catch : () => params.catch,
4387
- ...processCreateParams(params)
4388
- });
4389
- };
4390
-
4391
- class ZodNaN extends ZodType {
4392
- _parse(input) {
4393
- const parsedType = this._getType(input);
4394
- if (parsedType !== ZodParsedType.nan) {
4395
- const ctx = this._getOrReturnCtx(input);
4396
- addIssueToContext(ctx, {
4397
- code: ZodIssueCode.invalid_type,
4398
- expected: ZodParsedType.nan,
4399
- received: ctx.parsedType
4400
- });
4401
- return INVALID;
4402
- }
4403
- 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(", ")}`;
4404
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 };
4405
4253
  }
4406
- ZodNaN.create = (params) => {
4407
- return new ZodNaN({
4408
- typeName: ZodFirstPartyTypeKind.ZodNaN,
4409
- ...processCreateParams(params)
4410
- });
4411
- };
4412
- var BRAND = Symbol("zod_brand");
4413
4254
 
4414
- class ZodBranded extends ZodType {
4415
- _parse(input) {
4416
- const { ctx } = this._processInputParams(input);
4417
- const data = ctx.data;
4418
- return this._def.type._parse({
4419
- data,
4420
- path: ctx.path,
4421
- parent: ctx
4422
- });
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
+ };
4423
4283
  }
4424
- unwrap() {
4425
- return this._def.type;
4284
+ select(...cols) {
4285
+ this.iqo.selects.push(...cols);
4286
+ return this;
4426
4287
  }
4427
- }
4428
-
4429
- class ZodPipeline extends ZodType {
4430
- _parse(input) {
4431
- const { status, ctx } = this._processInputParams(input);
4432
- if (ctx.common.async) {
4433
- const handleAsync = async () => {
4434
- const inResult = await this._def.in._parseAsync({
4435
- data: ctx.data,
4436
- path: ctx.path,
4437
- parent: ctx
4438
- });
4439
- if (inResult.status === "aborted")
4440
- return INVALID;
4441
- if (inResult.status === "dirty") {
4442
- status.dirty();
4443
- return DIRTY(inResult.value);
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
+ }
4444
4334
  } else {
4445
- return this._def.out._parseAsync({
4446
- data: inResult.value,
4447
- path: ctx.path,
4448
- parent: ctx
4449
- });
4335
+ this.iqo.wheres.push({ field: key, operator: "=", value });
4450
4336
  }
4451
- };
4452
- return handleAsync();
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;
4453
4368
  } else {
4454
- const inResult = this._def.in._parseSync({
4455
- data: ctx.data,
4456
- path: ctx.path,
4457
- parent: ctx
4458
- });
4459
- if (inResult.status === "aborted")
4460
- return INVALID;
4461
- if (inResult.status === "dirty") {
4462
- status.dirty();
4463
- return {
4464
- status: "dirty",
4465
- value: inResult.value
4466
- };
4467
- } else {
4468
- return this._def.out._parseSync({
4469
- data: inResult.value,
4470
- path: ctx.path,
4471
- parent: ctx
4472
- });
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) ?? [];
4473
4399
  }
4474
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;
4475
4416
  }
4476
- static create(a, b) {
4477
- return new ZodPipeline({
4478
- in: a,
4479
- out: b,
4480
- typeName: ZodFirstPartyTypeKind.ZodPipeline
4481
- });
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
+ }
4482
4443
  }
4483
4444
  }
4484
4445
 
4485
- class ZodReadonly extends ZodType {
4486
- _parse(input) {
4487
- const result = this._def.innerType._parse(input);
4488
- const freeze = (data) => {
4489
- if (isValid(data)) {
4490
- data.value = Object.freeze(data.value);
4491
- }
4492
- return data;
4493
- };
4494
- 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;
4495
4455
  }
4496
- unwrap() {
4497
- return this._def.innerType;
4456
+ toString() {
4457
+ return `"${this.alias}"."${this.column}"`;
4458
+ }
4459
+ [Symbol.toPrimitive]() {
4460
+ return this.toString();
4498
4461
  }
4499
4462
  }
4500
- ZodReadonly.create = (type, params) => {
4501
- return new ZodReadonly({
4502
- innerType: type,
4503
- typeName: ZodFirstPartyTypeKind.ZodReadonly,
4504
- ...processCreateParams(params)
4505
- });
4506
- };
4507
- function cleanParams(params, data) {
4508
- const p = typeof params === "function" ? params(data) : typeof params === "string" ? { message: params } : params;
4509
- const p2 = typeof p === "string" ? { message: p } : p;
4510
- return p2;
4463
+ function q(name) {
4464
+ return `"${name}"`;
4511
4465
  }
4512
- function custom(check, _params = {}, fatal) {
4513
- if (check)
4514
- return ZodAny.create().superRefine((data, ctx) => {
4515
- const r = check(data);
4516
- if (r instanceof Promise) {
4517
- return r.then((r2) => {
4518
- if (!r2) {
4519
- const params = cleanParams(_params, data);
4520
- const _fatal = params.fatal ?? fatal ?? true;
4521
- ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
4522
- }
4523
- });
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;
4524
4474
  }
4525
- if (!r) {
4526
- const params = cleanParams(_params, data);
4527
- const _fatal = params.fatal ?? fatal ?? true;
4528
- ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
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) };
4529
4483
  }
4530
4484
  return;
4531
- });
4532
- return ZodAny.create();
4485
+ }
4486
+ });
4533
4487
  }
4534
- var late = {
4535
- object: ZodObject.lazycreate
4536
- };
4537
- var ZodFirstPartyTypeKind;
4538
- (function(ZodFirstPartyTypeKind2) {
4539
- ZodFirstPartyTypeKind2["ZodString"] = "ZodString";
4540
- ZodFirstPartyTypeKind2["ZodNumber"] = "ZodNumber";
4541
- ZodFirstPartyTypeKind2["ZodNaN"] = "ZodNaN";
4542
- ZodFirstPartyTypeKind2["ZodBigInt"] = "ZodBigInt";
4543
- ZodFirstPartyTypeKind2["ZodBoolean"] = "ZodBoolean";
4544
- ZodFirstPartyTypeKind2["ZodDate"] = "ZodDate";
4545
- ZodFirstPartyTypeKind2["ZodSymbol"] = "ZodSymbol";
4546
- ZodFirstPartyTypeKind2["ZodUndefined"] = "ZodUndefined";
4547
- ZodFirstPartyTypeKind2["ZodNull"] = "ZodNull";
4548
- ZodFirstPartyTypeKind2["ZodAny"] = "ZodAny";
4549
- ZodFirstPartyTypeKind2["ZodUnknown"] = "ZodUnknown";
4550
- ZodFirstPartyTypeKind2["ZodNever"] = "ZodNever";
4551
- ZodFirstPartyTypeKind2["ZodVoid"] = "ZodVoid";
4552
- ZodFirstPartyTypeKind2["ZodArray"] = "ZodArray";
4553
- ZodFirstPartyTypeKind2["ZodObject"] = "ZodObject";
4554
- ZodFirstPartyTypeKind2["ZodUnion"] = "ZodUnion";
4555
- ZodFirstPartyTypeKind2["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion";
4556
- ZodFirstPartyTypeKind2["ZodIntersection"] = "ZodIntersection";
4557
- ZodFirstPartyTypeKind2["ZodTuple"] = "ZodTuple";
4558
- ZodFirstPartyTypeKind2["ZodRecord"] = "ZodRecord";
4559
- ZodFirstPartyTypeKind2["ZodMap"] = "ZodMap";
4560
- ZodFirstPartyTypeKind2["ZodSet"] = "ZodSet";
4561
- ZodFirstPartyTypeKind2["ZodFunction"] = "ZodFunction";
4562
- ZodFirstPartyTypeKind2["ZodLazy"] = "ZodLazy";
4563
- ZodFirstPartyTypeKind2["ZodLiteral"] = "ZodLiteral";
4564
- ZodFirstPartyTypeKind2["ZodEnum"] = "ZodEnum";
4565
- ZodFirstPartyTypeKind2["ZodEffects"] = "ZodEffects";
4566
- ZodFirstPartyTypeKind2["ZodNativeEnum"] = "ZodNativeEnum";
4567
- ZodFirstPartyTypeKind2["ZodOptional"] = "ZodOptional";
4568
- ZodFirstPartyTypeKind2["ZodNullable"] = "ZodNullable";
4569
- ZodFirstPartyTypeKind2["ZodDefault"] = "ZodDefault";
4570
- ZodFirstPartyTypeKind2["ZodCatch"] = "ZodCatch";
4571
- ZodFirstPartyTypeKind2["ZodPromise"] = "ZodPromise";
4572
- ZodFirstPartyTypeKind2["ZodBranded"] = "ZodBranded";
4573
- ZodFirstPartyTypeKind2["ZodPipeline"] = "ZodPipeline";
4574
- ZodFirstPartyTypeKind2["ZodReadonly"] = "ZodReadonly";
4575
- })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
4576
- var instanceOfType = (cls, params = {
4577
- message: `Input not instance of ${cls.name}`
4578
- }) => custom((data) => data instanceof cls, params);
4579
- var stringType = ZodString.create;
4580
- var numberType = ZodNumber.create;
4581
- var nanType = ZodNaN.create;
4582
- var bigIntType = ZodBigInt.create;
4583
- var booleanType = ZodBoolean.create;
4584
- var dateType = ZodDate.create;
4585
- var symbolType = ZodSymbol.create;
4586
- var undefinedType = ZodUndefined.create;
4587
- var nullType = ZodNull.create;
4588
- var anyType = ZodAny.create;
4589
- var unknownType = ZodUnknown.create;
4590
- var neverType = ZodNever.create;
4591
- var voidType = ZodVoid.create;
4592
- var arrayType = ZodArray.create;
4593
- var objectType = ZodObject.create;
4594
- var strictObjectType = ZodObject.strictCreate;
4595
- var unionType = ZodUnion.create;
4596
- var discriminatedUnionType = ZodDiscriminatedUnion.create;
4597
- var intersectionType = ZodIntersection.create;
4598
- var tupleType = ZodTuple.create;
4599
- var recordType = ZodRecord.create;
4600
- var mapType = ZodMap.create;
4601
- var setType = ZodSet.create;
4602
- var functionType = ZodFunction.create;
4603
- var lazyType = ZodLazy.create;
4604
- var literalType = ZodLiteral.create;
4605
- var enumType = ZodEnum.create;
4606
- var nativeEnumType = ZodNativeEnum.create;
4607
- var promiseType = ZodPromise.create;
4608
- var effectsType = ZodEffects.create;
4609
- var optionalType = ZodOptional.create;
4610
- var nullableType = ZodNullable.create;
4611
- var preprocessType = ZodEffects.createWithPreprocess;
4612
- var pipelineType = ZodPipeline.create;
4613
- var ostring = () => stringType().optional();
4614
- var onumber = () => numberType().optional();
4615
- var oboolean = () => booleanType().optional();
4616
- var coerce = {
4617
- string: (arg) => ZodString.create({ ...arg, coerce: true }),
4618
- number: (arg) => ZodNumber.create({ ...arg, coerce: true }),
4619
- boolean: (arg) => ZodBoolean.create({
4620
- ...arg,
4621
- coerce: true
4622
- }),
4623
- bigint: (arg) => ZodBigInt.create({ ...arg, coerce: true }),
4624
- date: (arg) => ZodDate.create({ ...arg, coerce: true })
4625
- };
4626
- var NEVER = INVALID;
4627
- // src/schema.ts
4628
- function parseRelationsConfig(relations, schemas) {
4629
- const relationships = [];
4630
- const added = new Set;
4631
- for (const [fromTable, rels] of Object.entries(relations)) {
4632
- if (!schemas[fromTable]) {
4633
- 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)}`;
4634
4547
  }
4635
- for (const [fkColumn, toTable] of Object.entries(rels)) {
4636
- if (!schemas[toTable]) {
4637
- throw new Error(`relations: unknown target table '${toTable}' in ${fromTable}.${fkColumn}`);
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);
4638
4558
  }
4639
- const navField = fkColumn.replace(/_id$/, "");
4640
- const btKey = `${fromTable}.${fkColumn}:belongs-to`;
4641
- if (!added.has(btKey)) {
4642
- relationships.push({
4643
- type: "belongs-to",
4644
- from: fromTable,
4645
- to: toTable,
4646
- relationshipField: navField,
4647
- foreignKey: fkColumn
4648
- });
4649
- added.add(btKey);
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);
4650
4598
  }
4651
- const otmKey = `${toTable}.${fromTable}:one-to-many`;
4652
- if (!added.has(otmKey)) {
4653
- relationships.push({
4654
- type: "one-to-many",
4655
- from: toTable,
4656
- to: fromTable,
4657
- relationshipField: fromTable,
4658
- foreignKey: ""
4659
- });
4660
- added.add(otmKey);
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);
4661
4613
  }
4614
+ parts.push(`${fieldRef} ${dir.toUpperCase()}`);
4615
+ }
4616
+ if (parts.length > 0) {
4617
+ sql += ` ORDER BY ${parts.join(", ")}`;
4662
4618
  }
4663
4619
  }
4664
- return relationships;
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 };
4665
4629
  }
4666
- function getStorableFields(schema) {
4667
- return Object.entries(asZodObject(schema).shape).filter(([key]) => key !== "id").map(([name, type]) => ({ name, type }));
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);
4668
4635
  }
4669
- function zodTypeToSqlType(zodType) {
4670
- if (zodType instanceof exports_external.ZodOptional) {
4671
- zodType = zodType._def.innerType;
4672
- }
4673
- if (zodType instanceof exports_external.ZodDefault) {
4674
- zodType = zodType._def.innerType;
4675
- }
4676
- if (zodType instanceof exports_external.ZodString || zodType instanceof exports_external.ZodDate)
4677
- return "TEXT";
4678
- if (zodType instanceof exports_external.ZodNumber || zodType instanceof exports_external.ZodBoolean)
4679
- return "INTEGER";
4680
- if (zodType._def.typeName === "ZodInstanceOf" && zodType._def.type === Buffer)
4681
- return "BLOB";
4682
- return "TEXT";
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;
4683
4709
  }
4684
- function transformForStorage(data) {
4685
- const transformed = {};
4686
- for (const [key, value] of Object.entries(data)) {
4687
- if (value instanceof Date) {
4688
- transformed[key] = value.toISOString();
4689
- } else if (typeof value === "boolean") {
4690
- transformed[key] = value ? 1 : 0;
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);
4691
4777
  } else {
4692
- transformed[key] = value;
4778
+ parts.push(`${fieldName} = ?`);
4779
+ values.push(transformForStorage({ value }).value);
4693
4780
  }
4694
4781
  }
4695
- return transformed;
4782
+ return { clause: parts.length > 0 ? `WHERE ${parts.join(" AND ")}` : "", values };
4696
4783
  }
4697
- function transformFromStorage(row, schema) {
4698
- const transformed = {};
4699
- for (const [key, value] of Object.entries(row)) {
4700
- let fieldSchema = asZodObject(schema).shape[key];
4701
- if (fieldSchema instanceof exports_external.ZodOptional) {
4702
- fieldSchema = fieldSchema._def.innerType;
4703
- }
4704
- if (fieldSchema instanceof exports_external.ZodDefault) {
4705
- fieldSchema = fieldSchema._def.innerType;
4706
- }
4707
- if (fieldSchema instanceof exports_external.ZodDate && typeof value === "string") {
4708
- transformed[key] = new Date(value);
4709
- } else if (fieldSchema instanceof exports_external.ZodBoolean && typeof value === "number") {
4710
- transformed[key] = value === 1;
4711
- } else {
4712
- transformed[key] = value;
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
+ }
4713
4908
  }
4714
4909
  }
4715
- return transformed;
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
+ });
4716
4921
  }
4717
4922
 
4718
4923
  // src/database.ts
4719
4924
  class _Database {
4720
4925
  db;
4926
+ _reactive;
4721
4927
  schemas;
4722
4928
  relationships;
4723
4929
  options;
4724
- pollInterval;
4725
- _revisions = {};
4930
+ _ctx;
4931
+ _listeners = [];
4932
+ _changeWatermark = 0;
4933
+ _pollTimer = null;
4934
+ _pollInterval;
4726
4935
  constructor(dbFile, schemas, options = {}) {
4727
4936
  this.db = new SqliteDatabase(dbFile);
4728
4937
  this.db.run("PRAGMA journal_mode = WAL");
4729
4938
  this.db.run("PRAGMA foreign_keys = ON");
4730
4939
  this.schemas = schemas;
4731
4940
  this.options = options;
4732
- this.pollInterval = options.pollInterval ?? 500;
4941
+ this._reactive = options.reactive !== false;
4942
+ this._pollInterval = options.pollInterval ?? 100;
4733
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
+ };
4734
4951
  this.initializeTables();
4735
- this.initializeChangeTracking();
4952
+ if (this._reactive)
4953
+ this.initializeChangeTracking();
4736
4954
  this.runMigrations();
4737
4955
  if (options.indexes)
4738
4956
  this.createIndexes(options.indexes);
4739
4957
  for (const entityName of Object.keys(schemas)) {
4740
4958
  const key = entityName;
4741
4959
  const accessor = {
4742
- insert: (data) => this.insert(entityName, data),
4960
+ insert: (data) => insert(this._ctx, entityName, data),
4961
+ insertMany: (rows) => insertMany(this._ctx, entityName, rows),
4743
4962
  update: (idOrData, data) => {
4744
4963
  if (typeof idOrData === "number")
4745
- return this.update(entityName, idOrData, data);
4746
- return this._createUpdateBuilder(entityName, idOrData);
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);
4747
4972
  },
4748
- upsert: (conditions, data) => this.upsert(entityName, data, conditions),
4749
- delete: (id) => this.delete(entityName, id),
4750
- select: (...cols) => this._createQueryBuilder(entityName, cols),
4751
4973
  _tableName: entityName
4752
4974
  };
4753
4975
  this[key] = accessor;
@@ -4756,44 +4978,53 @@ class _Database {
4756
4978
  initializeTables() {
4757
4979
  for (const [entityName, schema] of Object.entries(this.schemas)) {
4758
4980
  const storableFields = getStorableFields(schema);
4759
- const columnDefs = storableFields.map((f) => `${f.name} ${zodTypeToSqlType(f.type)}`);
4981
+ const columnDefs = storableFields.map((f) => `"${f.name}" ${zodTypeToSqlType(f.type)}`);
4760
4982
  const constraints = [];
4761
4983
  const belongsToRels = this.relationships.filter((rel) => rel.type === "belongs-to" && rel.from === entityName);
4762
4984
  for (const rel of belongsToRels) {
4763
- 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`);
4764
4986
  }
4765
4987
  const allCols = columnDefs.join(", ");
4766
4988
  const allConstraints = constraints.length > 0 ? ", " + constraints.join(", ") : "";
4767
- this.db.run(`CREATE TABLE IF NOT EXISTS ${entityName} (id INTEGER PRIMARY KEY AUTOINCREMENT, ${allCols}${allConstraints})`);
4989
+ this.db.run(`CREATE TABLE IF NOT EXISTS "${entityName}" (id INTEGER PRIMARY KEY AUTOINCREMENT, ${allCols}${allConstraints})`);
4768
4990
  }
4769
4991
  }
4770
4992
  initializeChangeTracking() {
4771
- this.db.run(`CREATE TABLE IF NOT EXISTS _satidb_changes (
4772
- tbl TEXT PRIMARY KEY,
4773
- seq INTEGER NOT NULL DEFAULT 0
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
4774
4998
  )`);
4775
4999
  for (const entityName of Object.keys(this.schemas)) {
4776
- this.db.run(`INSERT OR IGNORE INTO _satidb_changes (tbl, seq) VALUES (?, 0)`, entityName);
4777
- for (const op2 of ["insert", "update", "delete"]) {
4778
- const triggerName = `_satidb_${entityName}_${op2}`;
4779
- const event = op2.toUpperCase();
4780
- this.db.run(`CREATE TRIGGER IF NOT EXISTS ${triggerName}
4781
- AFTER ${event} ON ${entityName}
4782
- BEGIN
4783
- UPDATE _satidb_changes SET seq = seq + 1 WHERE tbl = '${entityName}';
4784
- END`);
4785
- }
4786
- }
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;
4787
5018
  }
4788
5019
  runMigrations() {
4789
5020
  for (const [entityName, schema] of Object.entries(this.schemas)) {
4790
- const existingColumns = this.db.query(`PRAGMA table_info(${entityName})`).all();
5021
+ const existingColumns = this.db.query(`PRAGMA table_info("${entityName}")`).all();
4791
5022
  const existingNames = new Set(existingColumns.map((c) => c.name));
4792
5023
  const storableFields = getStorableFields(schema);
4793
5024
  for (const field of storableFields) {
4794
5025
  if (!existingNames.has(field.name)) {
4795
5026
  const sqlType = zodTypeToSqlType(field.type);
4796
- this.db.run(`ALTER TABLE ${entityName} ADD COLUMN ${field.name} ${sqlType}`);
5027
+ this.db.run(`ALTER TABLE "${entityName}" ADD COLUMN "${field.name}" ${sqlType}`);
4797
5028
  }
4798
5029
  }
4799
5030
  }
@@ -4803,278 +5034,73 @@ class _Database {
4803
5034
  for (const def of indexDefs) {
4804
5035
  const cols = Array.isArray(def) ? def : [def];
4805
5036
  const idxName = `idx_${tableName}_${cols.join("_")}`;
4806
- 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(", ")})`);
4807
5038
  }
4808
5039
  }
4809
5040
  }
4810
- _bumpRevision(entityName) {
4811
- this._revisions[entityName] = (this._revisions[entityName] ?? 0) + 1;
4812
- }
4813
- _getRevision(entityName) {
4814
- const rev = this._revisions[entityName] ?? 0;
4815
- const row = this.db.query("SELECT seq FROM _satidb_changes WHERE tbl = ?").get(entityName);
4816
- const seq = row?.seq ?? 0;
4817
- return `${rev}:${seq}`;
4818
- }
4819
- insert(entityName, data) {
4820
- const schema = this.schemas[entityName];
4821
- const validatedData = asZodObject(schema).passthrough().parse(data);
4822
- const transformed = transformForStorage(validatedData);
4823
- const columns = Object.keys(transformed);
4824
- const sql = columns.length === 0 ? `INSERT INTO ${entityName} DEFAULT VALUES` : `INSERT INTO ${entityName} (${columns.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
4825
- const result = this.db.query(sql).run(...Object.values(transformed));
4826
- const newEntity = this._getById(entityName, result.lastInsertRowid);
4827
- if (!newEntity)
4828
- throw new Error("Failed to retrieve entity after insertion");
4829
- this._bumpRevision(entityName);
4830
- return newEntity;
4831
- }
4832
- _getById(entityName, id) {
4833
- const row = this.db.query(`SELECT * FROM ${entityName} WHERE id = ?`).get(id);
4834
- if (!row)
4835
- return null;
4836
- return this._attachMethods(entityName, transformFromStorage(row, this.schemas[entityName]));
4837
- }
4838
- _getOne(entityName, conditions) {
4839
- const { clause, values } = this.buildWhereClause(conditions);
4840
- const row = this.db.query(`SELECT * FROM ${entityName} ${clause} LIMIT 1`).get(...values);
4841
- if (!row)
4842
- return null;
4843
- return this._attachMethods(entityName, transformFromStorage(row, this.schemas[entityName]));
4844
- }
4845
- _findMany(entityName, conditions = {}) {
4846
- const { clause, values } = this.buildWhereClause(conditions);
4847
- const rows = this.db.query(`SELECT * FROM ${entityName} ${clause}`).all(...values);
4848
- return rows.map((row) => this._attachMethods(entityName, transformFromStorage(row, this.schemas[entityName])));
4849
- }
4850
- update(entityName, id, data) {
4851
- const schema = this.schemas[entityName];
4852
- const validatedData = asZodObject(schema).partial().parse(data);
4853
- const transformed = transformForStorage(validatedData);
4854
- if (Object.keys(transformed).length === 0)
4855
- return this._getById(entityName, id);
4856
- const setClause = Object.keys(transformed).map((key) => `${key} = ?`).join(", ");
4857
- this.db.query(`UPDATE ${entityName} SET ${setClause} WHERE id = ?`).run(...Object.values(transformed), id);
4858
- this._bumpRevision(entityName);
4859
- const updatedEntity = this._getById(entityName, id);
4860
- return updatedEntity;
4861
- }
4862
- _updateWhere(entityName, data, conditions) {
4863
- const schema = this.schemas[entityName];
4864
- const validatedData = asZodObject(schema).partial().parse(data);
4865
- const transformed = transformForStorage(validatedData);
4866
- if (Object.keys(transformed).length === 0)
4867
- return 0;
4868
- const { clause, values: whereValues } = this.buildWhereClause(conditions);
4869
- if (!clause)
4870
- throw new Error("update().where() requires at least one condition");
4871
- const setCols = Object.keys(transformed);
4872
- const setClause = setCols.map((key) => `${key} = ?`).join(", ");
4873
- const result = this.db.query(`UPDATE ${entityName} SET ${setClause} ${clause}`).run(...setCols.map((key) => transformed[key]), ...whereValues);
4874
- const affected = result.changes ?? 0;
4875
- if (affected > 0)
4876
- this._bumpRevision(entityName);
4877
- return affected;
4878
- }
4879
- _createUpdateBuilder(entityName, data) {
4880
- let _conditions = {};
4881
- const builder = {
4882
- where: (conditions) => {
4883
- _conditions = { ..._conditions, ...conditions };
4884
- return builder;
4885
- },
4886
- 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();
4887
5054
  };
4888
- return builder;
4889
- }
4890
- upsert(entityName, data, conditions = {}) {
4891
- const hasId = data?.id && typeof data.id === "number";
4892
- const existing = hasId ? this._getById(entityName, data.id) : Object.keys(conditions ?? {}).length > 0 ? this._getOne(entityName, conditions) : null;
4893
- if (existing) {
4894
- const updateData = { ...data };
4895
- delete updateData.id;
4896
- return this.update(entityName, existing.id, updateData);
4897
- }
4898
- const insertData = { ...conditions ?? {}, ...data ?? {} };
4899
- delete insertData.id;
4900
- return this.insert(entityName, insertData);
4901
- }
4902
- delete(entityName, id) {
4903
- const entity = this._getById(entityName, id);
4904
- if (entity) {
4905
- this.db.query(`DELETE FROM ${entityName} WHERE id = ?`).run(id);
4906
- this._bumpRevision(entityName);
4907
- }
4908
- }
4909
- _attachMethods(entityName, entity) {
4910
- const augmented = entity;
4911
- augmented.update = (data) => this.update(entityName, entity.id, data);
4912
- augmented.delete = () => this.delete(entityName, entity.id);
4913
- for (const rel of this.relationships) {
4914
- if (rel.from === entityName && rel.type === "belongs-to") {
4915
- augmented[rel.relationshipField] = () => {
4916
- const fkValue = entity[rel.foreignKey];
4917
- return fkValue ? this._getById(rel.to, fkValue) : null;
4918
- };
4919
- } else if (rel.from === entityName && rel.type === "one-to-many") {
4920
- const belongsToRel = this.relationships.find((r) => r.type === "belongs-to" && r.from === rel.to && r.to === rel.from);
4921
- if (belongsToRel) {
4922
- const fk = belongsToRel.foreignKey;
4923
- augmented[rel.relationshipField] = () => {
4924
- return this._findMany(rel.to, { [fk]: entity.id });
4925
- };
4926
- }
4927
- }
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;
4928
5065
  }
4929
- const storableFieldNames = new Set(getStorableFields(this.schemas[entityName]).map((f) => f.name));
4930
- return new Proxy(augmented, {
4931
- set: (target, prop, value) => {
4932
- if (storableFieldNames.has(prop) && target[prop] !== value) {
4933
- this.update(entityName, target.id, { [prop]: value });
4934
- }
4935
- target[prop] = value;
4936
- return true;
4937
- },
4938
- get: (target, prop, receiver) => Reflect.get(target, prop, receiver)
4939
- });
4940
5066
  }
4941
- buildWhereClause(conditions, tablePrefix) {
4942
- const parts = [];
4943
- const values = [];
4944
- for (const key in conditions) {
4945
- if (key.startsWith("$")) {
4946
- if (key === "$or" && Array.isArray(conditions[key])) {
4947
- const orBranches = conditions[key];
4948
- const orParts = [];
4949
- for (const branch of orBranches) {
4950
- const sub = this.buildWhereClause(branch, tablePrefix);
4951
- if (sub.clause) {
4952
- orParts.push(`(${sub.clause.replace(/^WHERE /, "")})`);
4953
- values.push(...sub.values);
4954
- }
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 {}
4955
5082
  }
4956
- if (orParts.length > 0)
4957
- parts.push(`(${orParts.join(" OR ")})`);
4958
- }
4959
- continue;
4960
- }
4961
- const value = conditions[key];
4962
- const fieldName = tablePrefix ? `${tablePrefix}.${key}` : key;
4963
- if (typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
4964
- const operator = Object.keys(value)[0];
4965
- if (!operator?.startsWith("$")) {
4966
- throw new Error(`Querying on nested object '${key}' not supported. Use operators like $gt.`);
4967
- }
4968
- const operand = value[operator];
4969
- if (operator === "$in") {
4970
- if (!Array.isArray(operand))
4971
- throw new Error(`$in for '${key}' requires an array`);
4972
- if (operand.length === 0) {
4973
- parts.push("1 = 0");
4974
- 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
+ }
4975
5091
  }
4976
- parts.push(`${fieldName} IN (${operand.map(() => "?").join(", ")})`);
4977
- values.push(...operand.map((v) => transformForStorage({ v }).v));
4978
- continue;
4979
5092
  }
4980
- const sqlOp = { $gt: ">", $gte: ">=", $lt: "<", $lte: "<=", $ne: "!=" }[operator];
4981
- if (!sqlOp)
4982
- throw new Error(`Unsupported operator '${operator}' on '${key}'`);
4983
- parts.push(`${fieldName} ${sqlOp} ?`);
4984
- values.push(transformForStorage({ operand }).operand);
4985
- } else {
4986
- parts.push(`${fieldName} = ?`);
4987
- values.push(transformForStorage({ value }).value);
4988
5093
  }
5094
+ this._changeWatermark = change.id;
4989
5095
  }
4990
- return { clause: parts.length > 0 ? `WHERE ${parts.join(" AND ")}` : "", values };
5096
+ this.db.run('DELETE FROM "_changes" WHERE id <= ?', this._changeWatermark);
4991
5097
  }
4992
5098
  transaction(callback) {
4993
- try {
4994
- this.db.run("BEGIN TRANSACTION");
4995
- const result = callback();
4996
- this.db.run("COMMIT");
4997
- return result;
4998
- } catch (error) {
4999
- this.db.run("ROLLBACK");
5000
- throw new Error(`Transaction failed: ${error.message}`);
5001
- }
5002
- }
5003
- _createQueryBuilder(entityName, initialCols) {
5004
- const schema = this.schemas[entityName];
5005
- const executor = (sql, params, raw) => {
5006
- const rows = this.db.query(sql).all(...params);
5007
- if (raw)
5008
- return rows;
5009
- return rows.map((row) => this._attachMethods(entityName, transformFromStorage(row, schema)));
5010
- };
5011
- const singleExecutor = (sql, params, raw) => {
5012
- const results = executor(sql, params, raw);
5013
- return results.length > 0 ? results[0] : null;
5014
- };
5015
- const joinResolver = (fromTable, toTable) => {
5016
- const belongsTo = this.relationships.find((r) => r.type === "belongs-to" && r.from === fromTable && r.to === toTable);
5017
- if (belongsTo)
5018
- return { fk: belongsTo.foreignKey, pk: "id" };
5019
- const reverse = this.relationships.find((r) => r.type === "belongs-to" && r.from === toTable && r.to === fromTable);
5020
- if (reverse)
5021
- return { fk: "id", pk: reverse.foreignKey };
5022
- return null;
5023
- };
5024
- const revisionGetter = () => this._getRevision(entityName);
5025
- const conditionResolver = (conditions) => {
5026
- const resolved = {};
5027
- for (const [key, value] of Object.entries(conditions)) {
5028
- if (value && typeof value === "object" && typeof value.id === "number" && typeof value.delete === "function") {
5029
- const fkCol = key + "_id";
5030
- const rel = this.relationships.find((r) => r.type === "belongs-to" && r.from === entityName && r.foreignKey === fkCol);
5031
- if (rel) {
5032
- resolved[fkCol] = value.id;
5033
- } else {
5034
- 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);
5035
- if (relByNav) {
5036
- resolved[relByNav.foreignKey] = value.id;
5037
- } else {
5038
- resolved[key] = value;
5039
- }
5040
- }
5041
- } else {
5042
- resolved[key] = value;
5043
- }
5044
- }
5045
- return resolved;
5046
- };
5047
- const eagerLoader = (parentTable, relation, parentIds) => {
5048
- const hasMany = this.relationships.find((r) => r.type === "one-to-many" && r.from === parentTable && r.relationshipField === relation);
5049
- if (hasMany) {
5050
- const belongsTo2 = this.relationships.find((r) => r.type === "belongs-to" && r.from === hasMany.to && r.to === parentTable);
5051
- if (belongsTo2) {
5052
- const fk = belongsTo2.foreignKey;
5053
- const placeholders = parentIds.map(() => "?").join(", ");
5054
- const childRows = this.db.query(`SELECT * FROM ${hasMany.to} WHERE ${fk} IN (${placeholders})`).all(...parentIds);
5055
- const groups = new Map;
5056
- const childSchema = this.schemas[hasMany.to];
5057
- for (const rawRow of childRows) {
5058
- const entity = this._attachMethods(hasMany.to, transformFromStorage(rawRow, childSchema));
5059
- const parentId = rawRow[fk];
5060
- if (!groups.has(parentId))
5061
- groups.set(parentId, []);
5062
- groups.get(parentId).push(entity);
5063
- }
5064
- return { key: relation, groups };
5065
- }
5066
- }
5067
- const belongsTo = this.relationships.find((r) => r.type === "belongs-to" && r.from === parentTable && r.relationshipField === relation);
5068
- if (belongsTo) {
5069
- const fkValues = [...new Set(parentIds)];
5070
- return null;
5071
- }
5072
- return null;
5073
- };
5074
- const builder = new QueryBuilder(entityName, executor, singleExecutor, joinResolver, conditionResolver, revisionGetter, eagerLoader, this.pollInterval);
5075
- if (initialCols.length > 0)
5076
- builder.select(...initialCols);
5077
- return builder;
5099
+ return this.db.transaction(callback)();
5100
+ }
5101
+ close() {
5102
+ this._stopPolling();
5103
+ this.db.close();
5078
5104
  }
5079
5105
  query(callback) {
5080
5106
  return executeProxyQuery(this.schemas, callback, (sql, params) => this.db.query(sql).all(...params));
@@ -5087,6 +5113,7 @@ export {
5087
5113
  op,
5088
5114
  createFunctionProxy,
5089
5115
  createColumnProxy,
5116
+ compileIQO,
5090
5117
  compileAST,
5091
5118
  QueryBuilder,
5092
5119
  Database,