sqlite-zod-orm 3.7.3 → 3.9.0

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