semola 0.5.4 → 0.6.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.
Files changed (36) hide show
  1. package/README.md +18 -45
  2. package/dist/chunk-CKQMccvm.cjs +28 -0
  3. package/dist/lib/api/index.cjs +29 -15
  4. package/dist/lib/api/index.mjs +30 -16
  5. package/dist/lib/cache/index.cjs +47 -22
  6. package/dist/lib/cache/index.d.cts +3 -24
  7. package/dist/lib/cache/index.d.mts +3 -24
  8. package/dist/lib/cache/index.mjs +48 -23
  9. package/dist/lib/cron/index.cjs +117 -117
  10. package/dist/lib/cron/index.mjs +118 -118
  11. package/dist/lib/errors/index.d.cts +12 -1
  12. package/dist/lib/errors/index.d.mts +12 -1
  13. package/dist/lib/logging/index.cjs +1 -0
  14. package/dist/lib/orm/index.cjs +1642 -0
  15. package/dist/lib/orm/index.d.cts +402 -0
  16. package/dist/lib/orm/index.d.mts +402 -0
  17. package/dist/lib/orm/index.mjs +1630 -0
  18. package/dist/lib/prompts/index.cjs +89 -89
  19. package/dist/lib/prompts/index.d.cts +12 -33
  20. package/dist/lib/prompts/index.d.mts +12 -33
  21. package/dist/lib/prompts/index.mjs +89 -90
  22. package/dist/lib/pubsub/index.cjs +43 -19
  23. package/dist/lib/pubsub/index.d.cts +3 -18
  24. package/dist/lib/pubsub/index.d.mts +3 -18
  25. package/dist/lib/pubsub/index.mjs +44 -20
  26. package/dist/lib/queue/index.cjs +40 -10
  27. package/dist/lib/queue/index.d.cts +11 -4
  28. package/dist/lib/queue/index.d.mts +11 -4
  29. package/dist/lib/queue/index.mjs +39 -11
  30. package/dist/lib/workflow/index.cjs +285 -282
  31. package/dist/lib/workflow/index.d.cts +76 -11
  32. package/dist/lib/workflow/index.d.mts +76 -11
  33. package/dist/lib/workflow/index.mjs +278 -284
  34. package/package.json +11 -1
  35. package/dist/index-BhGNDjPq.d.mts +0 -13
  36. package/dist/index-DxSbeGP-.d.cts +0 -13
@@ -0,0 +1,1642 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/lib/orm/column/index.ts
3
+ const createColumnBuilder = (column) => {
4
+ const primaryKey = () => {
5
+ return createColumnBuilder({
6
+ ...column,
7
+ _meta: {
8
+ ...column._meta,
9
+ isNullable: false,
10
+ isPrimaryKey: true
11
+ }
12
+ });
13
+ };
14
+ const notNull = () => {
15
+ return createColumnBuilder({
16
+ ...column,
17
+ _meta: {
18
+ ...column._meta,
19
+ isNullable: false
20
+ }
21
+ });
22
+ };
23
+ const nullable = (() => {
24
+ if (column._meta.isPrimaryKey) return createColumnBuilder({
25
+ ...column,
26
+ _meta: {
27
+ ...column._meta,
28
+ isNullable: false
29
+ }
30
+ });
31
+ return createColumnBuilder({
32
+ ...column,
33
+ _meta: {
34
+ ...column._meta,
35
+ isNullable: true
36
+ }
37
+ });
38
+ });
39
+ const unique = () => {
40
+ return createColumnBuilder({
41
+ ...column,
42
+ _meta: {
43
+ ...column._meta,
44
+ isUnique: true
45
+ }
46
+ });
47
+ };
48
+ const defaultHandler = (value) => {
49
+ return createColumnBuilder({
50
+ ...column,
51
+ _meta: {
52
+ ...column._meta,
53
+ hasDefault: true
54
+ },
55
+ _default: value
56
+ });
57
+ };
58
+ const referencesBuilder = (tableColumn) => {
59
+ return createColumnBuilder({
60
+ ...column,
61
+ references: { tableColumn }
62
+ });
63
+ };
64
+ const references = referencesBuilder;
65
+ references.tableColumn = column.references?.tableColumn;
66
+ return {
67
+ ...column,
68
+ primaryKey,
69
+ notNull,
70
+ nullable,
71
+ unique,
72
+ default: defaultHandler,
73
+ references
74
+ };
75
+ };
76
+ const createBaseColumn = (sqlName, type, enumValues) => {
77
+ return createColumnBuilder({
78
+ sqlName,
79
+ type,
80
+ enumValues,
81
+ _meta: {
82
+ isNullable: true,
83
+ isPrimaryKey: false,
84
+ isUnique: false,
85
+ hasDefault: false
86
+ }
87
+ });
88
+ };
89
+ const string = (sqlName) => {
90
+ return createBaseColumn(sqlName, "string");
91
+ };
92
+ const uuid = (sqlName) => {
93
+ return string(sqlName);
94
+ };
95
+ const number = (sqlName) => {
96
+ return createBaseColumn(sqlName, "number");
97
+ };
98
+ const boolean = (sqlName) => {
99
+ return createBaseColumn(sqlName, "boolean");
100
+ };
101
+ const date = (sqlName) => {
102
+ return createBaseColumn(sqlName, "date");
103
+ };
104
+ const enumType = (sqlName, values) => {
105
+ return createBaseColumn(sqlName, "enum", values);
106
+ };
107
+ const json = (sqlName) => {
108
+ return createBaseColumn(sqlName, "json");
109
+ };
110
+ const jsonb = (sqlName) => {
111
+ return createBaseColumn(sqlName, "jsonb");
112
+ };
113
+ //#endregion
114
+ //#region src/lib/orm/utils.ts
115
+ const quoteIdentifier = (identifier) => {
116
+ identifier = identifier.replaceAll("\"", "\"\"");
117
+ return `"${identifier}"`;
118
+ };
119
+ //#endregion
120
+ //#region src/lib/orm/dialect/relation-fk.ts
121
+ const resolveHasManyForeignKeyColumn = (sourceTable, targetTable) => {
122
+ const sourceColumnValues = Object.values(sourceTable.columns);
123
+ const candidates = [];
124
+ for (const [, column] of Object.entries(targetTable.columns)) {
125
+ if (!column.references) continue;
126
+ const getReferencedColumn = column.references.tableColumn;
127
+ if (!getReferencedColumn) continue;
128
+ const referencedColumn = getReferencedColumn();
129
+ if (sourceColumnValues.some((sourceCol) => {
130
+ return sourceCol === referencedColumn;
131
+ })) candidates.push({
132
+ fk: column,
133
+ source: referencedColumn
134
+ });
135
+ }
136
+ if (candidates.length > 1) throw new Error(`Ambiguous hasMany foreign key from ${targetTable.sqlName} to ${sourceTable.sqlName}`);
137
+ const [candidate] = candidates;
138
+ if (!candidate) throw new Error(`Missing hasMany foreign key from ${targetTable.sqlName} to ${sourceTable.sqlName}`);
139
+ return candidate;
140
+ };
141
+ const resolveHasOneForeignKeyColumn = (input) => {
142
+ const { sourceTable, relationTable, relationForeignKey } = input;
143
+ const localForeignKey = sourceTable.columns[relationForeignKey];
144
+ if (!localForeignKey) throw new Error(`Missing hasOne foreign key column ${relationForeignKey} on ${sourceTable.sqlName}`);
145
+ if (!localForeignKey.references?.tableColumn) throw new Error(`Column ${relationForeignKey} on ${sourceTable.sqlName} is not a foreign key - call .references() on it`);
146
+ const referencedColumn = localForeignKey.references.tableColumn();
147
+ if (!Object.values(relationTable.columns).some((column) => {
148
+ return column === referencedColumn;
149
+ })) throw new Error(`Column ${relationForeignKey} on ${sourceTable.sqlName} does not reference ${relationTable.sqlName}`);
150
+ return {
151
+ localForeignKey,
152
+ target: referencedColumn
153
+ };
154
+ };
155
+ //#endregion
156
+ //#region src/lib/orm/dialect/clauses.ts
157
+ const FALSE_WHERE_SQL = "(1 = 0)";
158
+ const TRUE_WHERE_SQL = "(1 = 1)";
159
+ const RELATION_FILTER_KEYS = [
160
+ "every",
161
+ "some",
162
+ "none"
163
+ ];
164
+ const EMPTY_INCLUDE = {
165
+ sql: "",
166
+ params: [],
167
+ descriptors: []
168
+ };
169
+ const serializeParam = (value) => {
170
+ if (value instanceof Date) return value.toISOString();
171
+ return value;
172
+ };
173
+ const escapeLikeValue = (value) => {
174
+ return serializeParam(`${serializeParam(value)}`.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_"));
175
+ };
176
+ const OPERATORS = {
177
+ equals: {
178
+ sql: (ph) => `= ${ph}`,
179
+ transform: (v) => serializeParam(v)
180
+ },
181
+ gt: {
182
+ sql: (ph) => `> ${ph}`,
183
+ transform: (v) => serializeParam(v)
184
+ },
185
+ gte: {
186
+ sql: (ph) => `>= ${ph}`,
187
+ transform: (v) => serializeParam(v)
188
+ },
189
+ lt: {
190
+ sql: (ph) => `< ${ph}`,
191
+ transform: (v) => serializeParam(v)
192
+ },
193
+ lte: {
194
+ sql: (ph) => `<= ${ph}`,
195
+ transform: (v) => serializeParam(v)
196
+ },
197
+ startsWith: {
198
+ sql: (ph) => `LIKE ${ph} ESCAPE '\\'`,
199
+ transform: (v) => serializeParam(`${escapeLikeValue(v)}%`)
200
+ },
201
+ endsWith: {
202
+ sql: (ph) => `LIKE ${ph} ESCAPE '\\'`,
203
+ transform: (v) => serializeParam(`%${escapeLikeValue(v)}`)
204
+ },
205
+ contains: {
206
+ sql: (ph) => `LIKE ${ph} ESCAPE '\\'`,
207
+ transform: (v) => serializeParam(`%${escapeLikeValue(v)}%`)
208
+ }
209
+ };
210
+ const createNextPlaceholder = (spec) => {
211
+ let index = 0;
212
+ return () => {
213
+ index += 1;
214
+ return spec.formatPlaceholder(index);
215
+ };
216
+ };
217
+ const buildSelectList = (columns, include) => {
218
+ if (include.sql) return `${columns}, ${include.sql}`;
219
+ return columns;
220
+ };
221
+ const serializeColumnValue = (column, value) => {
222
+ if (column.type !== "json" && column.type !== "jsonb") return serializeParam(value);
223
+ if (value === null) return value;
224
+ if (value === void 0) return null;
225
+ return JSON.stringify(value);
226
+ };
227
+ const isPlainObject = (value) => {
228
+ if (value === null) return false;
229
+ if (typeof value !== "object") return false;
230
+ if (Array.isArray(value)) return false;
231
+ if (value instanceof Date) return false;
232
+ const prototype = Object.getPrototypeOf(value);
233
+ if (prototype === null) return true;
234
+ if (prototype === Object.prototype) return true;
235
+ return false;
236
+ };
237
+ const appendDirectWhereClause = (input) => {
238
+ const { clauses, params, nextPlaceholder, column, sqlName, value } = input;
239
+ if (value === null) {
240
+ clauses.push(`${sqlName} IS NULL`);
241
+ return;
242
+ }
243
+ clauses.push(`${sqlName} = ${nextPlaceholder()}`);
244
+ params.push(serializeColumnValue(column, value));
245
+ };
246
+ const appendOperatorWhereClauses = (input) => {
247
+ const { clauses, params, nextPlaceholder, column, sqlName, jsKey, value } = input;
248
+ const entries = Object.entries(value);
249
+ if (!entries.length) throw new Error(`Missing where operator for field ${jsKey}`);
250
+ for (const [op, operand] of entries) {
251
+ if (op === "in" || op === "notIn") {
252
+ if (!Array.isArray(operand)) throw new Error(`Expected array for where operator: ${op} for field ${jsKey}`);
253
+ if (op === "in" && operand.length === 0) {
254
+ clauses.push(FALSE_WHERE_SQL);
255
+ continue;
256
+ }
257
+ if (op === "notIn" && operand.length === 0) continue;
258
+ const placeholders = operand.map(() => nextPlaceholder());
259
+ const keyword = op === "in" ? "IN" : "NOT IN";
260
+ clauses.push(`${sqlName} ${keyword} (${placeholders.join(", ")})`);
261
+ for (const item of operand) params.push(serializeColumnValue(column, item));
262
+ continue;
263
+ }
264
+ if (op === "between") {
265
+ if (!Array.isArray(operand)) throw new Error(`Expected array for where operator: ${op} for field ${jsKey}`);
266
+ if (operand.length !== 2) throw new Error(`Expected 2-element array for where operator: ${op} for field ${jsKey}`);
267
+ const [min, max] = operand;
268
+ const ph1 = nextPlaceholder();
269
+ const ph2 = nextPlaceholder();
270
+ clauses.push(`${sqlName} BETWEEN ${ph1} AND ${ph2}`);
271
+ params.push(serializeColumnValue(column, min), serializeColumnValue(column, max));
272
+ continue;
273
+ }
274
+ const operator = OPERATORS[op];
275
+ if (!operator) throw new Error(`Unknown where operator: ${op} for field ${jsKey}`);
276
+ if (op === "equals" && operand === null) {
277
+ clauses.push(`${sqlName} IS NULL`);
278
+ continue;
279
+ }
280
+ clauses.push(`${sqlName} ${operator.sql(nextPlaceholder())}`);
281
+ params.push(operator.transform(serializeColumnValue(column, operand)));
282
+ }
283
+ };
284
+ const parseRelationFilters = (relationName, value) => {
285
+ if (!isPlainObject(value)) throw new Error(`Relation where filter for ${relationName} must be an object`);
286
+ const filter = value;
287
+ const filters = [];
288
+ for (const filterKey of RELATION_FILTER_KEYS) {
289
+ if (!(filterKey in filter)) continue;
290
+ const nestedWhere = filter[filterKey];
291
+ if (!isPlainObject(nestedWhere)) throw new Error(`Relation where filter ${filterKey} must be an object`);
292
+ filters.push({
293
+ key: filterKey,
294
+ where: nestedWhere
295
+ });
296
+ }
297
+ if (filters.length === 0) throw new Error(`Relation where filter for ${relationName} must include at least one of every, some, or none`);
298
+ return filters;
299
+ };
300
+ const isRelationFilterValue = (value) => {
301
+ if (!isPlainObject(value)) return false;
302
+ const filter = value;
303
+ for (const key of RELATION_FILTER_KEYS) if (key in filter) return true;
304
+ return Object.keys(filter).length === 0;
305
+ };
306
+ const buildRelationForeignKeyCondition = (input) => {
307
+ const { parentTable, parentAlias, relation, relationTable, relationAlias } = input;
308
+ if (relation._type === "hasMany") {
309
+ const { fk: foreignKey, source: sourceColumn } = resolveHasManyForeignKeyColumn(parentTable, relationTable);
310
+ return `${relationAlias}.${quoteIdentifier(foreignKey.sqlName)} = ${parentAlias}.${quoteIdentifier(sourceColumn.sqlName)}`;
311
+ }
312
+ if (relation._type !== "hasOne") throw new Error("Expected hasOne relation");
313
+ const { localForeignKey, target } = resolveHasOneForeignKeyColumn({
314
+ sourceTable: parentTable,
315
+ relationTable,
316
+ relationForeignKey: relation._foreignKey
317
+ });
318
+ return `${relationAlias}.${quoteIdentifier(target.sqlName)} = ${parentAlias}.${quoteIdentifier(localForeignKey.sqlName)}`;
319
+ };
320
+ const appendRelationFilterClause = (input) => {
321
+ const { clauses, params, nextPlaceholder, parentAlias, table, relation, relationName, key, where: nestedWhere } = input;
322
+ if (!parentAlias) throw new Error("parentAlias is required for relation where filters");
323
+ const relationTable = relation._table;
324
+ const relationAlias = `where_${relationName}__${relationTable.sqlName}`;
325
+ const fkCondition = buildRelationForeignKeyCondition({
326
+ parentTable: table,
327
+ parentAlias,
328
+ relation,
329
+ relationTable,
330
+ relationAlias
331
+ });
332
+ const nested = buildWhereClause({
333
+ nextPlaceholder,
334
+ table: relationTable,
335
+ where: nestedWhere
336
+ });
337
+ const nestedCondition = nested.sql ? nested.sql : TRUE_WHERE_SQL;
338
+ params.push(...nested.params);
339
+ const relationFrom = `${quoteIdentifier(relationTable.sqlName)} AS ${relationAlias}`;
340
+ if (key === "some") {
341
+ clauses.push(`EXISTS (SELECT 1 FROM ${relationFrom} WHERE ${fkCondition} AND (${nestedCondition}))`);
342
+ return;
343
+ }
344
+ if (key === "none") {
345
+ clauses.push(`NOT EXISTS (SELECT 1 FROM ${relationFrom} WHERE ${fkCondition} AND (${nestedCondition}))`);
346
+ return;
347
+ }
348
+ clauses.push(`NOT EXISTS (SELECT 1 FROM ${relationFrom} WHERE ${fkCondition} AND NOT (${nestedCondition}))`);
349
+ };
350
+ const appendRelationWhereClause = (input) => {
351
+ const { parentAlias, relationName, value } = input;
352
+ if (!parentAlias) throw new Error("parentAlias is required for relation where filters");
353
+ const filters = parseRelationFilters(relationName, value);
354
+ for (const filter of filters) appendRelationFilterClause({
355
+ ...input,
356
+ ...filter,
357
+ parentAlias
358
+ });
359
+ };
360
+ const appendWhereClause = (input) => {
361
+ const { clauses, params, nextPlaceholder, table, jsKey, value } = input;
362
+ if (!(jsKey in table.columns)) throw new Error(`Unknown where key "${jsKey}" on table ${table.sqlName}`);
363
+ const column = table.columns[jsKey];
364
+ if (!column) throw new Error(`Unknown where key "${jsKey}" on table ${table.sqlName}`);
365
+ const sqlName = quoteIdentifier(column.sqlName);
366
+ if (!isPlainObject(value)) {
367
+ appendDirectWhereClause({
368
+ clauses,
369
+ params,
370
+ nextPlaceholder,
371
+ column,
372
+ sqlName,
373
+ value
374
+ });
375
+ return;
376
+ }
377
+ appendOperatorWhereClauses({
378
+ clauses,
379
+ params,
380
+ nextPlaceholder,
381
+ column,
382
+ sqlName,
383
+ jsKey,
384
+ value
385
+ });
386
+ };
387
+ const buildWhereClause = (input) => {
388
+ const { where, relations, parentAlias } = input;
389
+ const clauses = [];
390
+ const params = [];
391
+ if (!where) return {
392
+ sql: "",
393
+ params
394
+ };
395
+ for (const [jsKey, value] of Object.entries(where)) {
396
+ if (value === void 0) continue;
397
+ const logicalWhereKey = getLogicalWhereKey(jsKey);
398
+ if (logicalWhereKey) {
399
+ appendLogicalWhereClause({
400
+ ...input,
401
+ clauses,
402
+ params,
403
+ jsKey: logicalWhereKey,
404
+ value
405
+ });
406
+ continue;
407
+ }
408
+ const relation = relations?.[jsKey];
409
+ if (relation && isRelationFilterValue(value)) {
410
+ appendRelationWhereClause({
411
+ ...input,
412
+ clauses,
413
+ params,
414
+ jsKey,
415
+ value,
416
+ relation,
417
+ relationName: jsKey,
418
+ parentAlias: parentAlias ?? quoteIdentifier(input.table.sqlName)
419
+ });
420
+ continue;
421
+ }
422
+ appendWhereClause({
423
+ ...input,
424
+ clauses,
425
+ params,
426
+ jsKey,
427
+ value
428
+ });
429
+ }
430
+ return {
431
+ sql: clauses.join(` AND `),
432
+ params
433
+ };
434
+ };
435
+ const getLogicalWhereKey = (jsKey) => {
436
+ if (jsKey === "$and") return jsKey;
437
+ if (jsKey === "$not") return jsKey;
438
+ if (jsKey === "$or") return jsKey;
439
+ return null;
440
+ };
441
+ const getLogicalOperator = (jsKey) => {
442
+ if (jsKey === "$or") return "OR";
443
+ return "AND";
444
+ };
445
+ const getLogicalWhereValues = (jsKey, value) => {
446
+ if (jsKey === "$or" && !Array.isArray(value)) throw new Error("$or where value must be an array");
447
+ if (Array.isArray(value)) return value;
448
+ return [value];
449
+ };
450
+ const appendLogicalWhereClause = (input) => {
451
+ const { clauses, params, jsKey } = input;
452
+ const collected = collectLogicalWhereClauses(input);
453
+ if (typeof collected === "string") {
454
+ clauses.push(collected);
455
+ return;
456
+ }
457
+ if (!collected.nestedClauses.length) return;
458
+ params.push(...collected.nestedParams);
459
+ if (jsKey === "$not") {
460
+ const operator = "NOT";
461
+ const combinedNegatedClause = collected.nestedClauses.map((nestedClause) => `${operator} (${nestedClause})`).join(` AND `);
462
+ clauses.push(combinedNegatedClause);
463
+ return;
464
+ }
465
+ const operator = getLogicalOperator(jsKey);
466
+ clauses.push(`(${collected.nestedClauses.join(` ${operator} `)})`);
467
+ };
468
+ const collectLogicalWhereClauses = (input) => {
469
+ const { jsKey, value } = input;
470
+ const values = getLogicalWhereValues(jsKey, value);
471
+ const nestedClauses = [];
472
+ const nestedParams = [];
473
+ for (const nestedValue of values) {
474
+ if (!isPlainObject(nestedValue)) throw new Error(`${jsKey} where value must contain object filters`);
475
+ const nested = buildWhereClause({
476
+ ...input,
477
+ where: nestedValue
478
+ });
479
+ if (!nested.sql) {
480
+ if (jsKey === "$or") return TRUE_WHERE_SQL;
481
+ continue;
482
+ }
483
+ nestedClauses.push(`(${nested.sql})`);
484
+ nestedParams.push(...nested.params);
485
+ }
486
+ if (jsKey === "$or" && !nestedClauses.length) return FALSE_WHERE_SQL;
487
+ return {
488
+ nestedClauses,
489
+ nestedParams
490
+ };
491
+ };
492
+ const getColumnAlias = (sqlName, jsKey) => {
493
+ return `${quoteIdentifier(sqlName)} AS ${quoteIdentifier(jsKey)}`;
494
+ };
495
+ const buildSelectColumns = (table, select) => {
496
+ if (!select || Object.keys(select).length === 0) return Object.entries(table.columns).map(([key, column]) => getColumnAlias(column.sqlName, key)).join(", ");
497
+ const selectedColumns = [];
498
+ const keys = Object.keys(select);
499
+ for (const key of keys) {
500
+ const column = table.columns[key];
501
+ if (!column) throw new Error(`Unknown select key "${key}" on table ${table.sqlName}`);
502
+ selectedColumns.push(getColumnAlias(column.sqlName, key));
503
+ }
504
+ return selectedColumns.join(", ");
505
+ };
506
+ const buildOrderByClause = (table, orderBy) => {
507
+ if (!orderBy) return "";
508
+ const clauses = [];
509
+ for (const [jsKey, direction] of Object.entries(orderBy)) {
510
+ const column = table.columns[jsKey];
511
+ if (!column) throw new Error(`Unknown orderBy key "${jsKey}" on table ${table.sqlName}`);
512
+ if (direction === "desc") {
513
+ clauses.push(`${quoteIdentifier(column.sqlName)} DESC`);
514
+ continue;
515
+ }
516
+ if (direction === "asc") {
517
+ clauses.push(`${quoteIdentifier(column.sqlName)} ASC`);
518
+ continue;
519
+ }
520
+ throw new Error(`Unknown orderBy direction "${direction}" for key "${jsKey}" on table ${table.sqlName}`);
521
+ }
522
+ if (!clauses.length) return "";
523
+ return clauses.join(", ");
524
+ };
525
+ const buildPaginationClause = (input) => {
526
+ const { spec, nextPlaceholder, take, skip } = input;
527
+ const params = [];
528
+ if (take === void 0) {
529
+ if (skip === void 0) return {
530
+ sql: "",
531
+ params
532
+ };
533
+ const skipPh = nextPlaceholder();
534
+ params.push(skip);
535
+ return {
536
+ sql: `${spec.unlimitedOffsetKeyword} ${skipPh}`,
537
+ params
538
+ };
539
+ }
540
+ const takePh = nextPlaceholder();
541
+ params.push(take);
542
+ if (skip === void 0) return {
543
+ sql: `LIMIT ${takePh}`,
544
+ params
545
+ };
546
+ const skipPh = nextPlaceholder();
547
+ params.push(skip);
548
+ return {
549
+ sql: `LIMIT ${takePh} OFFSET ${skipPh}`,
550
+ params
551
+ };
552
+ };
553
+ const buildSelectStatement = (input) => {
554
+ const { tableName, columns, where, orderBy, pagination } = input;
555
+ let query = `SELECT ${columns} FROM ${tableName}`;
556
+ if (where) query = `${query} WHERE ${where}`;
557
+ if (orderBy) query = `${query} ORDER BY ${orderBy}`;
558
+ if (pagination) query = `${query} ${pagination}`;
559
+ return query;
560
+ };
561
+ const validateFindUniqueWhere = (table, where) => {
562
+ const entries = Object.entries(where).filter(([, value]) => value !== void 0);
563
+ if (!entries.map(([key]) => key).length) throw new Error("findUnique requires at least one where key");
564
+ let hasUniqueKey = false;
565
+ for (const [key] of entries) {
566
+ const column = table.columns[key];
567
+ if (!column) throw new Error(`Unknown where key ${key} on table ${table.sqlName}`);
568
+ if (column._meta.isPrimaryKey || column._meta.isUnique) hasUniqueKey = true;
569
+ }
570
+ if (!hasUniqueKey) throw new Error("findUnique where must include at least one unique or primary key column");
571
+ };
572
+ const resolveCreateValue = (column, provided) => {
573
+ if (provided !== void 0) return provided;
574
+ if (column._default) return column._default();
575
+ return null;
576
+ };
577
+ const buildSetClauses = (input) => {
578
+ const { nextPlaceholder, table, data } = input;
579
+ const setClauses = [];
580
+ const params = [];
581
+ for (const [jsKey, value] of Object.entries(data)) {
582
+ if (value === void 0) continue;
583
+ const column = table.columns[jsKey];
584
+ if (!column) continue;
585
+ setClauses.push(`${quoteIdentifier(column.sqlName)} = ${nextPlaceholder()}`);
586
+ params.push(serializeColumnValue(column, value));
587
+ }
588
+ return {
589
+ setClauses,
590
+ params
591
+ };
592
+ };
593
+ //#endregion
594
+ //#region src/lib/orm/dialect/relations.ts
595
+ const buildJsonObjectExpression = (input) => {
596
+ const { spec, alias, table, extraPairs = [], select } = input;
597
+ const allEntries = Object.entries(table.columns);
598
+ const hasSelect = select !== void 0 && Object.keys(select).length > 0;
599
+ let visibleEntries = allEntries;
600
+ if (hasSelect) {
601
+ for (const key of Object.keys(select)) if (!(key in table.columns)) throw new Error(`Unknown select key "${key}" on table ${table.sqlName}`);
602
+ visibleEntries = allEntries.filter(([key]) => key in select);
603
+ }
604
+ const pairs = visibleEntries.flatMap(([jsKey, column]) => [`'${jsKey}'`, `${alias}.${quoteIdentifier(column.sqlName)}`]);
605
+ return `${spec.jsonObjectFunctionName}(${[...pairs, ...extraPairs].join(", ")})`;
606
+ };
607
+ const getRelationOptions = (includeValue) => {
608
+ let options = {};
609
+ if (typeof includeValue === "object" && includeValue !== null) options = includeValue;
610
+ return options;
611
+ };
612
+ const buildNestedIncludePairs = (input) => {
613
+ const { spec, nextPlaceholder, relationTable, relationAlias, tableRelationsMap, options } = input;
614
+ const nestedRelations = tableRelationsMap.get(relationTable) ?? {};
615
+ const nestedExtraPairs = [];
616
+ const nestedParams = [];
617
+ const nestedDescriptors = [];
618
+ if (!options.include) return {
619
+ nestedExtraPairs,
620
+ nestedParams,
621
+ nestedDescriptors
622
+ };
623
+ for (const [nestedName, nestedValue] of Object.entries(options.include)) {
624
+ if (!nestedValue) continue;
625
+ const nestedRelation = nestedRelations[nestedName];
626
+ if (!nestedRelation) throw new Error(`Unknown relation ${nestedName} on table ${relationTable.sqlName}`);
627
+ const result = buildRelationSubquery({
628
+ spec,
629
+ nextPlaceholder,
630
+ parentTable: relationTable,
631
+ parentAlias: relationAlias,
632
+ relation: nestedRelation,
633
+ relationName: nestedName,
634
+ includeValue: nestedValue,
635
+ tableRelationsMap
636
+ });
637
+ nestedExtraPairs.push(`'${nestedName}'`, result.sql);
638
+ nestedParams.push(...result.params);
639
+ nestedDescriptors.push(result.descriptor);
640
+ }
641
+ return {
642
+ nestedExtraPairs,
643
+ nestedParams,
644
+ nestedDescriptors
645
+ };
646
+ };
647
+ const joinWhereSql = (fkCondition, whereSql) => {
648
+ if (whereSql) return `${fkCondition} AND ${whereSql}`;
649
+ return fkCondition;
650
+ };
651
+ const buildNestedHasManySubquery = (input) => {
652
+ const { spec, relationTable, relationAlias, whereSql, orderBy, paginationSql, jsonObj } = input;
653
+ if (!orderBy && !paginationSql) return `SELECT ${spec.jsonArrayAggregateFunctionName}(${jsonObj}) FROM ${quoteIdentifier(relationTable.sqlName)} AS ${relationAlias} WHERE ${whereSql}`;
654
+ let innerQuery = `SELECT * FROM ${quoteIdentifier(relationTable.sqlName)} AS ${relationAlias} WHERE ${whereSql}`;
655
+ if (orderBy) innerQuery = `${innerQuery} ORDER BY ${orderBy}`;
656
+ if (paginationSql) innerQuery = `${innerQuery} ${paginationSql}`;
657
+ return `SELECT ${spec.jsonArrayAggregateFunctionName}(${jsonObj}) FROM (${innerQuery}) AS ${relationAlias}`;
658
+ };
659
+ const buildHasManyRelationSubquery = (input) => {
660
+ const { spec, parentTable, parentAlias, relationTable, relationAlias, relationName, jsonObj, nestedDescriptors, whereSql, orderBy, paginationSql, allParams } = input;
661
+ const { fk: foreignKey, source: sourceColumn } = resolveHasManyForeignKeyColumn(parentTable, relationTable);
662
+ return {
663
+ sql: `COALESCE((${buildNestedHasManySubquery({
664
+ spec,
665
+ relationTable,
666
+ relationAlias,
667
+ whereSql: joinWhereSql(`${relationAlias}.${quoteIdentifier(foreignKey.sqlName)} = ${parentAlias}.${quoteIdentifier(sourceColumn.sqlName)}`, whereSql),
668
+ orderBy,
669
+ paginationSql,
670
+ jsonObj
671
+ })}), ${spec.emptyJsonArrayLiteral})`,
672
+ params: allParams,
673
+ descriptor: {
674
+ name: relationName,
675
+ type: "hasMany",
676
+ table: relationTable,
677
+ nested: nestedDescriptors
678
+ }
679
+ };
680
+ };
681
+ const buildHasOneRelationSubquery = (input) => {
682
+ const { parentTable, parentAlias, relation, relationTable, relationAlias, relationName, jsonObj, nestedDescriptors, whereSql, allParams } = input;
683
+ if (relation._type !== "hasOne") throw new Error(`Expected hasOne relation for ${relationName}`);
684
+ const { localForeignKey, target } = resolveHasOneForeignKeyColumn({
685
+ sourceTable: parentTable,
686
+ relationTable,
687
+ relationForeignKey: relation._foreignKey
688
+ });
689
+ const combinedWhereSql = joinWhereSql(`${relationAlias}.${quoteIdentifier(target.sqlName)} = ${parentAlias}.${quoteIdentifier(localForeignKey.sqlName)}`, whereSql);
690
+ return {
691
+ sql: `(${`SELECT ${jsonObj} FROM ${quoteIdentifier(relationTable.sqlName)} AS ${relationAlias} WHERE ${combinedWhereSql} LIMIT 1`})`,
692
+ params: allParams,
693
+ descriptor: {
694
+ name: relationName,
695
+ type: "hasOne",
696
+ table: relationTable,
697
+ nested: nestedDescriptors
698
+ }
699
+ };
700
+ };
701
+ const buildRelationSubquery = (input) => {
702
+ const { spec, nextPlaceholder, relation, relationName } = input;
703
+ const options = getRelationOptions(input.includeValue);
704
+ const relationTable = relation._table;
705
+ const relationAlias = `${relationName}__${relationTable.sqlName}`;
706
+ const { nestedExtraPairs, nestedParams, nestedDescriptors } = buildNestedIncludePairs({
707
+ ...input,
708
+ relationTable,
709
+ relationAlias,
710
+ options
711
+ });
712
+ const jsonObj = buildJsonObjectExpression({
713
+ spec,
714
+ alias: relationAlias,
715
+ table: relationTable,
716
+ extraPairs: nestedExtraPairs,
717
+ select: options.select
718
+ });
719
+ const where = buildWhereClause({
720
+ nextPlaceholder,
721
+ table: relationTable,
722
+ where: options.where
723
+ });
724
+ const orderBy = buildOrderByClause(relationTable, options.orderBy);
725
+ const pagination = buildPaginationClause({
726
+ spec,
727
+ nextPlaceholder,
728
+ take: options.take,
729
+ skip: options.skip
730
+ });
731
+ const allParams = [
732
+ ...nestedParams,
733
+ ...where.params,
734
+ ...pagination.params
735
+ ];
736
+ if (relation._type === "hasMany") return buildHasManyRelationSubquery({
737
+ ...input,
738
+ relationTable,
739
+ relationAlias,
740
+ jsonObj,
741
+ nestedDescriptors,
742
+ whereSql: where.sql,
743
+ orderBy,
744
+ paginationSql: pagination.sql,
745
+ allParams
746
+ });
747
+ return buildHasOneRelationSubquery({
748
+ ...input,
749
+ relationTable,
750
+ relationAlias,
751
+ jsonObj,
752
+ nestedDescriptors,
753
+ whereSql: where.sql,
754
+ allParams
755
+ });
756
+ };
757
+ const buildIncludeClause = (input) => {
758
+ const { spec, nextPlaceholder, table, parentAlias, relations, tableRelationsMap, include } = input;
759
+ if (!include) return EMPTY_INCLUDE;
760
+ const enabledRelations = Object.entries(include).filter(([, v]) => Boolean(v));
761
+ if (!enabledRelations.length) return EMPTY_INCLUDE;
762
+ const clauses = [];
763
+ const params = [];
764
+ const descriptors = [];
765
+ for (const [relationName, includeValue] of enabledRelations) {
766
+ const relation = relations[relationName];
767
+ if (!relation) throw new Error(`Unknown relation ${relationName} on table ${table.sqlName}`);
768
+ const result = buildRelationSubquery({
769
+ spec,
770
+ nextPlaceholder,
771
+ parentTable: table,
772
+ parentAlias,
773
+ relation,
774
+ relationName,
775
+ includeValue,
776
+ tableRelationsMap
777
+ });
778
+ clauses.push(`${result.sql} AS ${quoteIdentifier(relationName)}`);
779
+ params.push(...result.params);
780
+ descriptors.push(result.descriptor);
781
+ }
782
+ return {
783
+ sql: clauses.join(", "),
784
+ params,
785
+ descriptors
786
+ };
787
+ };
788
+ //#endregion
789
+ //#region src/lib/orm/dialect/query-builder.ts
790
+ var DialectQueryBuilder = class {
791
+ spec;
792
+ table;
793
+ relations;
794
+ tableRelationsMap;
795
+ constructor(input) {
796
+ this.spec = input.spec;
797
+ this.table = input.table;
798
+ this.relations = input.relations;
799
+ this.tableRelationsMap = input.tableRelationsMap ?? /* @__PURE__ */ new Map();
800
+ }
801
+ buildFindMany(options) {
802
+ const nextPlaceholder = createNextPlaceholder(this.spec);
803
+ const { include, where, selectColumns } = this.buildSelectIncludeWhere(nextPlaceholder, {
804
+ where: options?.where,
805
+ select: options?.select,
806
+ include: options?.include
807
+ });
808
+ const orderBy = buildOrderByClause(this.table, options?.orderBy);
809
+ const pagination = buildPaginationClause({
810
+ spec: this.spec,
811
+ nextPlaceholder,
812
+ take: options?.take,
813
+ skip: options?.skip
814
+ });
815
+ const params = [
816
+ ...include.params,
817
+ ...where.params,
818
+ ...pagination.params
819
+ ];
820
+ return {
821
+ statement: buildSelectStatement({
822
+ tableName: quoteIdentifier(this.table.sqlName),
823
+ columns: selectColumns,
824
+ where: where.sql,
825
+ orderBy,
826
+ pagination: pagination.sql
827
+ }),
828
+ params,
829
+ includeDescriptors: include.descriptors
830
+ };
831
+ }
832
+ buildFindFirst(options) {
833
+ return this.buildFindMany({
834
+ ...options,
835
+ take: 1
836
+ });
837
+ }
838
+ buildFindUnique(options) {
839
+ validateFindUniqueWhere(this.table, options.where);
840
+ const nextPlaceholder = createNextPlaceholder(this.spec);
841
+ const { include, where, selectColumns } = this.buildSelectIncludeWhere(nextPlaceholder, {
842
+ where: options.where,
843
+ select: options.select,
844
+ include: options.include
845
+ });
846
+ return {
847
+ statement: buildSelectStatement({
848
+ tableName: quoteIdentifier(this.table.sqlName),
849
+ columns: selectColumns,
850
+ where: where.sql,
851
+ orderBy: "",
852
+ pagination: "LIMIT 1"
853
+ }),
854
+ params: [...include.params, ...where.params],
855
+ includeDescriptors: include.descriptors
856
+ };
857
+ }
858
+ buildCreate(options) {
859
+ const nextPlaceholder = createNextPlaceholder(this.spec);
860
+ const provided = new Map(Object.entries(options.data));
861
+ const sqlNames = [];
862
+ const placeholders = [];
863
+ const params = [];
864
+ for (const [jsKey, column] of Object.entries(this.table.columns)) {
865
+ const value = resolveCreateValue(column, provided.get(jsKey));
866
+ sqlNames.push(quoteIdentifier(column.sqlName));
867
+ placeholders.push(nextPlaceholder());
868
+ params.push(serializeColumnValue(column, value));
869
+ }
870
+ const columns = buildSelectColumns(this.table, options.select);
871
+ const include = this.buildInclude(nextPlaceholder, options.include);
872
+ const returning = buildSelectList(columns, include);
873
+ return {
874
+ statement: `INSERT INTO ${quoteIdentifier(this.table.sqlName)} (${sqlNames.join(", ")}) VALUES (${placeholders.join(", ")}) RETURNING ${returning}`,
875
+ params: [...params, ...include.params],
876
+ includeDescriptors: include.descriptors
877
+ };
878
+ }
879
+ buildUpdate(options) {
880
+ validateFindUniqueWhere(this.table, options.where);
881
+ const nextPlaceholder = createNextPlaceholder(this.spec);
882
+ const { setClauses, params } = buildSetClauses({
883
+ nextPlaceholder,
884
+ table: this.table,
885
+ data: options.data
886
+ });
887
+ if (!setClauses.length) throw new Error("update requires at least one field in data");
888
+ const { where, include, returning } = this.buildWhereIncludeReturning(nextPlaceholder, {
889
+ where: options.where,
890
+ select: options.select,
891
+ include: options.include
892
+ });
893
+ let statement = `UPDATE ${quoteIdentifier(this.table.sqlName)} SET ${setClauses.join(", ")}`;
894
+ if (where.sql) statement = `${statement} WHERE ${where.sql}`;
895
+ statement = `${statement} RETURNING ${returning}`;
896
+ params.push(...where.params, ...include.params);
897
+ return {
898
+ statement,
899
+ params,
900
+ includeDescriptors: include.descriptors
901
+ };
902
+ }
903
+ buildDelete(options) {
904
+ validateFindUniqueWhere(this.table, options.where);
905
+ const nextPlaceholder = createNextPlaceholder(this.spec);
906
+ const { where, include, returning } = this.buildWhereIncludeReturning(nextPlaceholder, {
907
+ where: options.where,
908
+ select: options.select,
909
+ include: options.include
910
+ });
911
+ let statement = `DELETE FROM ${quoteIdentifier(this.table.sqlName)}`;
912
+ if (where.sql) statement = `${statement} WHERE ${where.sql}`;
913
+ statement = `${statement} RETURNING ${returning}`;
914
+ return {
915
+ statement,
916
+ params: [...where.params, ...include.params],
917
+ includeDescriptors: include.descriptors
918
+ };
919
+ }
920
+ buildCreateMany(options) {
921
+ if (!options.data.length) return {
922
+ statement: "",
923
+ params: [],
924
+ includeDescriptors: []
925
+ };
926
+ const nextPlaceholder = createNextPlaceholder(this.spec);
927
+ const columnEntries = Object.entries(this.table.columns);
928
+ const sqlNames = columnEntries.map(([, col]) => {
929
+ return quoteIdentifier(col.sqlName);
930
+ });
931
+ const params = [];
932
+ const rowPlaceholders = [];
933
+ for (const row of options.data) {
934
+ const rowRecord = row;
935
+ const placeholders = [];
936
+ for (const [jsKey, column] of columnEntries) {
937
+ const value = resolveCreateValue(column, rowRecord[jsKey]);
938
+ placeholders.push(nextPlaceholder());
939
+ params.push(serializeColumnValue(column, value));
940
+ }
941
+ rowPlaceholders.push(`(${placeholders.join(", ")})`);
942
+ }
943
+ const returning = buildSelectColumns(this.table, void 0);
944
+ return {
945
+ statement: `INSERT INTO ${quoteIdentifier(this.table.sqlName)} (${sqlNames.join(", ")}) VALUES ${rowPlaceholders.join(", ")} RETURNING ${returning}`,
946
+ params,
947
+ includeDescriptors: []
948
+ };
949
+ }
950
+ buildUpdateMany(options) {
951
+ const nextPlaceholder = createNextPlaceholder(this.spec);
952
+ const { setClauses, params } = buildSetClauses({
953
+ nextPlaceholder,
954
+ table: this.table,
955
+ data: options.data
956
+ });
957
+ if (!setClauses.length) throw new Error("updateMany requires at least one field in data");
958
+ const where = buildWhereClause({
959
+ nextPlaceholder,
960
+ table: this.table,
961
+ where: options.where,
962
+ relations: this.relations,
963
+ parentAlias: quoteIdentifier(this.table.sqlName)
964
+ });
965
+ let statement = `UPDATE ${quoteIdentifier(this.table.sqlName)} SET ${setClauses.join(", ")}`;
966
+ if (where.sql) statement = `${statement} WHERE ${where.sql}`;
967
+ params.push(...where.params);
968
+ const returning = buildSelectColumns(this.table, void 0);
969
+ statement = `${statement} RETURNING ${returning}`;
970
+ return {
971
+ statement,
972
+ params,
973
+ includeDescriptors: []
974
+ };
975
+ }
976
+ buildDeleteMany(options) {
977
+ const where = buildWhereClause({
978
+ nextPlaceholder: createNextPlaceholder(this.spec),
979
+ table: this.table,
980
+ where: options.where,
981
+ relations: this.relations,
982
+ parentAlias: quoteIdentifier(this.table.sqlName)
983
+ });
984
+ let statement = `DELETE FROM ${quoteIdentifier(this.table.sqlName)}`;
985
+ if (where.sql) statement = `${statement} WHERE ${where.sql}`;
986
+ const returning = buildSelectColumns(this.table, void 0);
987
+ statement = `${statement} RETURNING ${returning}`;
988
+ return {
989
+ statement,
990
+ params: where.params,
991
+ includeDescriptors: []
992
+ };
993
+ }
994
+ buildInclude(nextPlaceholder, include) {
995
+ return buildIncludeClause({
996
+ spec: this.spec,
997
+ nextPlaceholder,
998
+ table: this.table,
999
+ parentAlias: quoteIdentifier(this.table.sqlName),
1000
+ relations: this.relations,
1001
+ tableRelationsMap: this.tableRelationsMap,
1002
+ include
1003
+ });
1004
+ }
1005
+ buildSelectIncludeWhere(nextPlaceholder, input) {
1006
+ const include = this.buildInclude(nextPlaceholder, input.include);
1007
+ return {
1008
+ include,
1009
+ where: buildWhereClause({
1010
+ nextPlaceholder,
1011
+ table: this.table,
1012
+ where: input.where,
1013
+ relations: this.relations,
1014
+ parentAlias: quoteIdentifier(this.table.sqlName)
1015
+ }),
1016
+ selectColumns: buildSelectList(buildSelectColumns(this.table, input.select), include)
1017
+ };
1018
+ }
1019
+ buildWhereIncludeReturning(nextPlaceholder, input) {
1020
+ const where = buildWhereClause({
1021
+ nextPlaceholder,
1022
+ table: this.table,
1023
+ where: input.where,
1024
+ relations: this.relations,
1025
+ parentAlias: quoteIdentifier(this.table.sqlName)
1026
+ });
1027
+ const columns = buildSelectColumns(this.table, input.select);
1028
+ const include = this.buildInclude(nextPlaceholder, input.include);
1029
+ return {
1030
+ where,
1031
+ include,
1032
+ returning: buildSelectList(columns, include)
1033
+ };
1034
+ }
1035
+ };
1036
+ //#endregion
1037
+ //#region src/lib/orm/dialect/rows.ts
1038
+ const coerceBooleanValue = (val) => {
1039
+ if (val === null) return val;
1040
+ if (val === void 0) return val;
1041
+ return Boolean(val);
1042
+ };
1043
+ const coerceRelationItems = (input) => {
1044
+ const { value, table, nested } = input;
1045
+ if (Array.isArray(value)) {
1046
+ for (const item of value) if (typeof item === "object" && item !== null) coerceRow({
1047
+ row: item,
1048
+ table,
1049
+ descriptors: nested
1050
+ });
1051
+ return;
1052
+ }
1053
+ if (typeof value === "object" && value !== null) coerceRow({
1054
+ row: value,
1055
+ table,
1056
+ descriptors: nested
1057
+ });
1058
+ };
1059
+ const getColumnKeysByType = (table) => {
1060
+ const boolKeys = /* @__PURE__ */ new Set();
1061
+ const jsonKeys = /* @__PURE__ */ new Set();
1062
+ for (const [key, col] of Object.entries(table.columns)) {
1063
+ if (col.type === "boolean") boolKeys.add(key);
1064
+ if (col.type === "json") jsonKeys.add(key);
1065
+ if (col.type === "jsonb") jsonKeys.add(key);
1066
+ }
1067
+ return {
1068
+ boolKeys,
1069
+ jsonKeys
1070
+ };
1071
+ };
1072
+ const coerceColumnValues = (row, table) => {
1073
+ const { boolKeys, jsonKeys } = getColumnKeysByType(table);
1074
+ for (const key of boolKeys) if (key in row) row[key] = coerceBooleanValue(row[key]);
1075
+ for (const key of jsonKeys) {
1076
+ if (!(key in row)) continue;
1077
+ const val = row[key];
1078
+ if (typeof val !== "string") continue;
1079
+ row[key] = JSON.parse(val);
1080
+ }
1081
+ };
1082
+ const coerceRelationValue = (input) => {
1083
+ const { row, descriptor } = input;
1084
+ const value = row[descriptor.name];
1085
+ if (value === null) {
1086
+ if (descriptor.type === "hasMany") row[descriptor.name] = [];
1087
+ return;
1088
+ }
1089
+ const nested = descriptor.nested ?? [];
1090
+ if (typeof value === "string") {
1091
+ const parsed = JSON.parse(value);
1092
+ coerceRelationItems({
1093
+ value: parsed,
1094
+ table: descriptor.table,
1095
+ nested
1096
+ });
1097
+ row[descriptor.name] = parsed;
1098
+ return;
1099
+ }
1100
+ coerceRelationItems({
1101
+ value,
1102
+ table: descriptor.table,
1103
+ nested
1104
+ });
1105
+ };
1106
+ const coerceRelationValues = (row, descriptors) => {
1107
+ for (const descriptor of descriptors) coerceRelationValue({
1108
+ row,
1109
+ descriptor
1110
+ });
1111
+ };
1112
+ const coerceRow = (input) => {
1113
+ const { row, table, descriptors } = input;
1114
+ coerceColumnValues(row, table);
1115
+ coerceRelationValues(row, descriptors);
1116
+ };
1117
+ const parseIncludeRows = (input) => {
1118
+ const { table, rows, descriptors } = input;
1119
+ for (const row of rows) coerceRow({
1120
+ row,
1121
+ table,
1122
+ descriptors
1123
+ });
1124
+ };
1125
+ const executeQuery = async (sql, table, query) => {
1126
+ const rows = [...await sql.unsafe(query.statement, query.params)];
1127
+ parseIncludeRows({
1128
+ table,
1129
+ rows,
1130
+ descriptors: query.includeDescriptors
1131
+ });
1132
+ return rows;
1133
+ };
1134
+ //#endregion
1135
+ //#region src/lib/orm/dialect/shared.ts
1136
+ const createDialect = (input) => {
1137
+ const { spec, table, relations, tableRelationsMap = /* @__PURE__ */ new Map() } = input;
1138
+ const builder = new DialectQueryBuilder({
1139
+ spec,
1140
+ table,
1141
+ relations,
1142
+ tableRelationsMap
1143
+ });
1144
+ const executeAndUnwrap = async (sql, query, operation) => {
1145
+ const [row] = await executeQuery(sql, table, query);
1146
+ if (!row) throw new Error(`Record not found after ${operation} on table ${table.sqlName}`);
1147
+ return row;
1148
+ };
1149
+ return {
1150
+ name: spec.name,
1151
+ findMany: async (sql, options) => {
1152
+ return await executeQuery(sql, table, builder.buildFindMany(options));
1153
+ },
1154
+ findFirst: async (sql, options) => {
1155
+ const [row] = await executeQuery(sql, table, builder.buildFindFirst(options));
1156
+ return row ?? null;
1157
+ },
1158
+ findUnique: async (sql, options) => {
1159
+ const [row] = await executeQuery(sql, table, builder.buildFindUnique(options));
1160
+ return row ?? null;
1161
+ },
1162
+ create: async (sql, options) => {
1163
+ return executeAndUnwrap(sql, builder.buildCreate(options), "insert");
1164
+ },
1165
+ createMany: async (sql, options) => {
1166
+ if (!options.data.length) return [];
1167
+ return await executeQuery(sql, table, builder.buildCreateMany(options));
1168
+ },
1169
+ update: async (sql, options) => {
1170
+ return executeAndUnwrap(sql, builder.buildUpdate(options), "update");
1171
+ },
1172
+ updateMany: async (sql, options) => {
1173
+ return await executeQuery(sql, table, builder.buildUpdateMany(options));
1174
+ },
1175
+ delete: async (sql, options) => {
1176
+ return executeAndUnwrap(sql, builder.buildDelete(options), "delete");
1177
+ },
1178
+ deleteMany: async (sql, options) => {
1179
+ return await executeQuery(sql, table, builder.buildDeleteMany(options));
1180
+ }
1181
+ };
1182
+ };
1183
+ //#endregion
1184
+ //#region src/lib/orm/dialect/postgres.ts
1185
+ const POSTGRES_SPEC = {
1186
+ name: "postgres",
1187
+ formatPlaceholder: (index) => `$${index}`,
1188
+ unlimitedOffsetKeyword: "LIMIT ALL OFFSET",
1189
+ jsonObjectFunctionName: "jsonb_build_object",
1190
+ jsonArrayAggregateFunctionName: "jsonb_agg",
1191
+ emptyJsonArrayLiteral: "'[]'::jsonb"
1192
+ };
1193
+ const createPostgresDialect = (input) => createDialect({
1194
+ spec: POSTGRES_SPEC,
1195
+ ...input
1196
+ });
1197
+ //#endregion
1198
+ //#region src/lib/orm/dialect/sqlite.ts
1199
+ const SQLITE_SPEC = {
1200
+ name: "sqlite",
1201
+ formatPlaceholder: () => "?",
1202
+ unlimitedOffsetKeyword: "LIMIT -1 OFFSET",
1203
+ jsonObjectFunctionName: "json_object",
1204
+ jsonArrayAggregateFunctionName: "json_group_array",
1205
+ emptyJsonArrayLiteral: "'[]'"
1206
+ };
1207
+ const createSqliteDialect = (input) => createDialect({
1208
+ spec: SQLITE_SPEC,
1209
+ ...input
1210
+ });
1211
+ //#endregion
1212
+ //#region src/lib/orm/dialect/index.ts
1213
+ const getDialect = (input) => {
1214
+ const { adapter, table, relations, tableRelationsMap = /* @__PURE__ */ new Map() } = input;
1215
+ switch (adapter) {
1216
+ case "sqlite": return createSqliteDialect({
1217
+ table,
1218
+ relations,
1219
+ tableRelationsMap
1220
+ });
1221
+ case "postgres": return createPostgresDialect({
1222
+ table,
1223
+ relations,
1224
+ tableRelationsMap
1225
+ });
1226
+ default: throw new Error(`Unsupported adapter: ${adapter}`);
1227
+ }
1228
+ };
1229
+ //#endregion
1230
+ //#region src/lib/orm/orm/index.ts
1231
+ const many = (table) => {
1232
+ return {
1233
+ _type: "hasMany",
1234
+ _table: table()
1235
+ };
1236
+ };
1237
+ const one = (foreignKey, table) => {
1238
+ return {
1239
+ _type: "hasOne",
1240
+ _table: table(),
1241
+ _foreignKey: foreignKey
1242
+ };
1243
+ };
1244
+ const shouldSkipHooks = (options) => {
1245
+ return options?.$skipHooks === true;
1246
+ };
1247
+ const withoutSkipHooks = (options) => {
1248
+ const { $skipHooks, ...queryOptions } = options;
1249
+ return queryOptions;
1250
+ };
1251
+ const toHookOptions = (options) => {
1252
+ if (!options) return;
1253
+ return withoutSkipHooks(options);
1254
+ };
1255
+ const pickGlobalHooks = (hooksConfig) => {
1256
+ const { tables, ...globalHooks } = hooksConfig;
1257
+ return globalHooks;
1258
+ };
1259
+ const runHook = async (hook, ctx) => {
1260
+ await hook?.(ctx);
1261
+ };
1262
+ const runReadHooks = async (globalHook, tableHook, ctx) => {
1263
+ await runHook(globalHook, ctx);
1264
+ await runHook(tableHook, ctx);
1265
+ };
1266
+ const withReadHooks = async (input) => {
1267
+ const beforeCtx = {
1268
+ tableName: input.tableName,
1269
+ table: input.table,
1270
+ options: input.hookOptions
1271
+ };
1272
+ if (!input.skipHooks) await runReadHooks(input.beforeGlobal, input.beforeTable, beforeCtx);
1273
+ const result = await input.query();
1274
+ if (!input.skipHooks) await runReadHooks(input.afterGlobal, input.afterTable, {
1275
+ ...beforeCtx,
1276
+ result
1277
+ });
1278
+ return result;
1279
+ };
1280
+ const createTableClient = (input) => {
1281
+ const { sql, tableName, table, adapter, relations, tableRelationsMap, globalHooks, tableHooks } = input;
1282
+ const dialect = getDialect({
1283
+ adapter,
1284
+ table,
1285
+ relations,
1286
+ tableRelationsMap
1287
+ });
1288
+ return {
1289
+ findMany: async (options) => {
1290
+ const skipHooks = shouldSkipHooks(options);
1291
+ const hookOptions = toHookOptions(options);
1292
+ return withReadHooks({
1293
+ skipHooks,
1294
+ tableName,
1295
+ table,
1296
+ hookOptions,
1297
+ beforeGlobal: globalHooks?.beforeFindMany,
1298
+ beforeTable: tableHooks?.beforeFindMany,
1299
+ afterGlobal: globalHooks?.afterFindMany,
1300
+ afterTable: tableHooks?.afterFindMany,
1301
+ query: () => dialect.findMany(sql, hookOptions)
1302
+ });
1303
+ },
1304
+ findFirst: async (options) => {
1305
+ const skipHooks = shouldSkipHooks(options);
1306
+ const hookOptions = toHookOptions(options);
1307
+ return withReadHooks({
1308
+ skipHooks,
1309
+ tableName,
1310
+ table,
1311
+ hookOptions,
1312
+ beforeGlobal: globalHooks?.beforeFindFirst,
1313
+ beforeTable: tableHooks?.beforeFindFirst,
1314
+ afterGlobal: globalHooks?.afterFindFirst,
1315
+ afterTable: tableHooks?.afterFindFirst,
1316
+ query: () => dialect.findFirst(sql, hookOptions)
1317
+ });
1318
+ },
1319
+ findUnique: async (options) => {
1320
+ const skipHooks = shouldSkipHooks(options);
1321
+ const hookOptions = withoutSkipHooks(options);
1322
+ return withReadHooks({
1323
+ skipHooks,
1324
+ tableName,
1325
+ table,
1326
+ hookOptions,
1327
+ beforeGlobal: globalHooks?.beforeFindUnique,
1328
+ beforeTable: tableHooks?.beforeFindUnique,
1329
+ afterGlobal: globalHooks?.afterFindUnique,
1330
+ afterTable: tableHooks?.afterFindUnique,
1331
+ query: () => dialect.findUnique(sql, hookOptions)
1332
+ });
1333
+ },
1334
+ create: async (options) => {
1335
+ const skipHooks = shouldSkipHooks(options);
1336
+ const hookOptions = withoutSkipHooks(options);
1337
+ let queryOptions = hookOptions;
1338
+ if (!skipHooks) {
1339
+ const createHookResult = await globalHooks?.beforeCreate?.({
1340
+ tableName,
1341
+ table,
1342
+ options: hookOptions
1343
+ });
1344
+ queryOptions = {
1345
+ ...hookOptions,
1346
+ ...createHookResult
1347
+ };
1348
+ const tableCreateHookResult = await tableHooks?.beforeCreate?.({
1349
+ tableName,
1350
+ table,
1351
+ options: queryOptions
1352
+ });
1353
+ queryOptions = {
1354
+ ...queryOptions,
1355
+ ...tableCreateHookResult
1356
+ };
1357
+ }
1358
+ const result = await dialect.create(sql, queryOptions);
1359
+ if (!skipHooks) await runReadHooks(globalHooks?.afterCreate, tableHooks?.afterCreate, {
1360
+ tableName,
1361
+ table,
1362
+ options: queryOptions,
1363
+ result
1364
+ });
1365
+ return result;
1366
+ },
1367
+ createMany: async (options) => {
1368
+ const skipHooks = shouldSkipHooks(options);
1369
+ const hookOptions = withoutSkipHooks(options);
1370
+ let queryOptions = hookOptions;
1371
+ if (!skipHooks) {
1372
+ const createManyHookResult = await globalHooks?.beforeCreateMany?.({
1373
+ tableName,
1374
+ table,
1375
+ options: hookOptions
1376
+ });
1377
+ queryOptions = {
1378
+ ...hookOptions,
1379
+ ...createManyHookResult
1380
+ };
1381
+ const tableCreateManyHookResult = await tableHooks?.beforeCreateMany?.({
1382
+ tableName,
1383
+ table,
1384
+ options: queryOptions
1385
+ });
1386
+ queryOptions = {
1387
+ ...queryOptions,
1388
+ ...tableCreateManyHookResult
1389
+ };
1390
+ }
1391
+ const result = await dialect.createMany(sql, queryOptions);
1392
+ if (!skipHooks) {
1393
+ const hookCtx = {
1394
+ tableName,
1395
+ table,
1396
+ options: queryOptions,
1397
+ result
1398
+ };
1399
+ await runHook(globalHooks?.afterCreateMany, hookCtx);
1400
+ await runHook(tableHooks?.afterCreateMany, hookCtx);
1401
+ }
1402
+ return result;
1403
+ },
1404
+ update: async (options) => {
1405
+ const skipHooks = shouldSkipHooks(options);
1406
+ const hookOptions = withoutSkipHooks(options);
1407
+ let queryOptions = hookOptions;
1408
+ if (!skipHooks) {
1409
+ const updateHookResult = await globalHooks?.beforeUpdate?.({
1410
+ tableName,
1411
+ table,
1412
+ options: hookOptions
1413
+ });
1414
+ queryOptions = {
1415
+ ...hookOptions,
1416
+ ...updateHookResult
1417
+ };
1418
+ const tableUpdateHookResult = await tableHooks?.beforeUpdate?.({
1419
+ tableName,
1420
+ table,
1421
+ options: queryOptions
1422
+ });
1423
+ queryOptions = {
1424
+ ...queryOptions,
1425
+ ...tableUpdateHookResult
1426
+ };
1427
+ }
1428
+ const result = await dialect.update(sql, queryOptions);
1429
+ if (!skipHooks) await runReadHooks(globalHooks?.afterUpdate, tableHooks?.afterUpdate, {
1430
+ tableName,
1431
+ table,
1432
+ options: queryOptions,
1433
+ result
1434
+ });
1435
+ return result;
1436
+ },
1437
+ updateMany: async (options) => {
1438
+ const skipHooks = shouldSkipHooks(options);
1439
+ const hookOptions = withoutSkipHooks(options);
1440
+ let queryOptions = hookOptions;
1441
+ if (!skipHooks) {
1442
+ const updateManyHookResult = await globalHooks?.beforeUpdateMany?.({
1443
+ tableName,
1444
+ table,
1445
+ options: hookOptions
1446
+ });
1447
+ queryOptions = {
1448
+ ...hookOptions,
1449
+ ...updateManyHookResult
1450
+ };
1451
+ const tableUpdateManyHookResult = await tableHooks?.beforeUpdateMany?.({
1452
+ tableName,
1453
+ table,
1454
+ options: queryOptions
1455
+ });
1456
+ queryOptions = {
1457
+ ...queryOptions,
1458
+ ...tableUpdateManyHookResult
1459
+ };
1460
+ }
1461
+ const result = await dialect.updateMany(sql, queryOptions);
1462
+ if (!skipHooks) {
1463
+ const hookCtx = {
1464
+ tableName,
1465
+ table,
1466
+ options: queryOptions,
1467
+ result
1468
+ };
1469
+ await runHook(globalHooks?.afterUpdateMany, hookCtx);
1470
+ await runHook(tableHooks?.afterUpdateMany, hookCtx);
1471
+ }
1472
+ return result;
1473
+ },
1474
+ delete: async (options) => {
1475
+ const skipHooks = shouldSkipHooks(options);
1476
+ const hookOptions = withoutSkipHooks(options);
1477
+ let queryOptions = hookOptions;
1478
+ if (!skipHooks) {
1479
+ const deleteHookResult = await globalHooks?.beforeDelete?.({
1480
+ tableName,
1481
+ table,
1482
+ options: hookOptions
1483
+ });
1484
+ queryOptions = {
1485
+ ...hookOptions,
1486
+ ...deleteHookResult
1487
+ };
1488
+ const tableDeleteHookResult = await tableHooks?.beforeDelete?.({
1489
+ tableName,
1490
+ table,
1491
+ options: queryOptions
1492
+ });
1493
+ queryOptions = {
1494
+ ...queryOptions,
1495
+ ...tableDeleteHookResult
1496
+ };
1497
+ }
1498
+ const result = await dialect.delete(sql, queryOptions);
1499
+ if (!skipHooks) await runReadHooks(globalHooks?.afterDelete, tableHooks?.afterDelete, {
1500
+ tableName,
1501
+ table,
1502
+ options: queryOptions,
1503
+ result
1504
+ });
1505
+ return result;
1506
+ },
1507
+ deleteMany: async (options) => {
1508
+ const skipHooks = shouldSkipHooks(options);
1509
+ const hookOptions = withoutSkipHooks(options);
1510
+ let queryOptions = hookOptions;
1511
+ if (!skipHooks) {
1512
+ const deleteManyHookResult = await globalHooks?.beforeDeleteMany?.({
1513
+ tableName,
1514
+ table,
1515
+ options: hookOptions
1516
+ });
1517
+ queryOptions = {
1518
+ ...hookOptions,
1519
+ ...deleteManyHookResult
1520
+ };
1521
+ const tableDeleteManyHookResult = await tableHooks?.beforeDeleteMany?.({
1522
+ tableName,
1523
+ table,
1524
+ options: queryOptions
1525
+ });
1526
+ queryOptions = {
1527
+ ...queryOptions,
1528
+ ...tableDeleteManyHookResult
1529
+ };
1530
+ }
1531
+ const result = await dialect.deleteMany(sql, queryOptions);
1532
+ if (!skipHooks) {
1533
+ const hookCtx = {
1534
+ tableName,
1535
+ table,
1536
+ options: queryOptions,
1537
+ result
1538
+ };
1539
+ await runHook(globalHooks?.afterDeleteMany, hookCtx);
1540
+ await runHook(tableHooks?.afterDeleteMany, hookCtx);
1541
+ }
1542
+ return result;
1543
+ }
1544
+ };
1545
+ };
1546
+ const toObjectEntries = (object) => {
1547
+ const result = [];
1548
+ for (const key in object) {
1549
+ if (!Object.hasOwn(object, key)) continue;
1550
+ result.push([key, object[key]]);
1551
+ }
1552
+ return result;
1553
+ };
1554
+ const getTableRelations = (relations, tableName) => {
1555
+ if (!relations) return Object.create(null);
1556
+ if (!Object.hasOwn(relations, tableName)) return Object.create(null);
1557
+ const tableRelations = relations[tableName];
1558
+ if (!tableRelations) return Object.create(null);
1559
+ return tableRelations;
1560
+ };
1561
+ const buildTableClients = (input) => {
1562
+ const { tables, relations, sql, adapter, tableRelationsMap, hooks } = input;
1563
+ const clients = Object.create(null);
1564
+ for (const entry of toObjectEntries(tables)) {
1565
+ const setTableClient = (tableName, table) => {
1566
+ const tableRelations = getTableRelations(relations, tableName);
1567
+ tableRelationsMap.set(table, tableRelations);
1568
+ clients[tableName] = createTableClient({
1569
+ sql,
1570
+ tableName,
1571
+ table,
1572
+ adapter,
1573
+ relations: tableRelations,
1574
+ tableRelationsMap,
1575
+ globalHooks: hooks ? pickGlobalHooks(hooks) : void 0,
1576
+ tableHooks: hooks?.tables?.[tableName]
1577
+ });
1578
+ };
1579
+ setTableClient(entry[0], entry[1]);
1580
+ }
1581
+ return clients;
1582
+ };
1583
+ const buildOrmClient = (input) => {
1584
+ const { tableClients, sql, transaction } = input;
1585
+ return {
1586
+ ...tableClients,
1587
+ $raw: sql,
1588
+ $transaction: transaction
1589
+ };
1590
+ };
1591
+ const buildTransactionClient = (tableClients, sql) => ({
1592
+ ...tableClients,
1593
+ $raw: sql
1594
+ });
1595
+ const createOrm = (options) => {
1596
+ const sql = new Bun.SQL(options.url, { adapter: options.adapter });
1597
+ const tableRelationsMap = /* @__PURE__ */ new Map();
1598
+ return buildOrmClient({
1599
+ tableClients: buildTableClients({
1600
+ tables: options.tables,
1601
+ relations: options.relations,
1602
+ sql,
1603
+ adapter: options.adapter,
1604
+ tableRelationsMap,
1605
+ hooks: options.hooks
1606
+ }),
1607
+ sql,
1608
+ transaction: async (callback) => {
1609
+ return await sql.begin(async (txSql) => {
1610
+ return await callback(buildTransactionClient(buildTableClients({
1611
+ tables: options.tables,
1612
+ relations: options.relations,
1613
+ sql: txSql,
1614
+ adapter: options.adapter,
1615
+ tableRelationsMap,
1616
+ hooks: options.hooks
1617
+ }), txSql));
1618
+ });
1619
+ }
1620
+ });
1621
+ };
1622
+ //#endregion
1623
+ //#region src/lib/orm/table/index.ts
1624
+ const defineTable = (sqlName, columns) => {
1625
+ return {
1626
+ sqlName,
1627
+ columns
1628
+ };
1629
+ };
1630
+ //#endregion
1631
+ exports.boolean = boolean;
1632
+ exports.createOrm = createOrm;
1633
+ exports.date = date;
1634
+ exports.defineTable = defineTable;
1635
+ exports.enumType = enumType;
1636
+ exports.json = json;
1637
+ exports.jsonb = jsonb;
1638
+ exports.many = many;
1639
+ exports.number = number;
1640
+ exports.one = one;
1641
+ exports.string = string;
1642
+ exports.uuid = uuid;