peta-orm 0.2.6 → 0.3.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 (97) hide show
  1. package/README.md +23 -1
  2. package/bin/peta +1 -1
  3. package/dist/collection-Dv3sQPMx.mjs +173 -0
  4. package/dist/crud-BCWvg5MI.mjs +101 -0
  5. package/dist/errors-sfFJolfu.mjs +69 -0
  6. package/dist/factory-rIbPGjRg.mjs +173 -0
  7. package/dist/hooks-BD0xy7uw.mjs +77 -0
  8. package/dist/index-BdJnSMYi.d.mts +480 -0
  9. package/dist/index.d.mts +215 -0
  10. package/dist/index.mjs +2601 -0
  11. package/dist/migrations/cli.d.mts +4 -0
  12. package/dist/migrations/cli.mjs +74 -0
  13. package/dist/migrations/index.d.mts +53 -0
  14. package/dist/migrations/index.mjs +2 -0
  15. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  16. package/dist/runner-DQ7uT6LC.mjs +180 -0
  17. package/dist/save-B8rudcT5.mjs +331 -0
  18. package/dist/state-LtlHp6XV.mjs +56 -0
  19. package/package.json +25 -15
  20. package/dist/builder/delete-builder.d.ts +0 -9
  21. package/dist/builder/delete-builder.d.ts.map +0 -1
  22. package/dist/builder/eager-loader.d.ts +0 -13
  23. package/dist/builder/eager-loader.d.ts.map +0 -1
  24. package/dist/builder/index.d.ts +0 -6
  25. package/dist/builder/index.d.ts.map +0 -1
  26. package/dist/builder/query-builder.d.ts +0 -57
  27. package/dist/builder/query-builder.d.ts.map +0 -1
  28. package/dist/builder/update-builder.d.ts +0 -9
  29. package/dist/builder/update-builder.d.ts.map +0 -1
  30. package/dist/collection/collection.d.ts +0 -48
  31. package/dist/collection/collection.d.ts.map +0 -1
  32. package/dist/collection-wwtv7qmv.js +0 -8
  33. package/dist/columns/arktype-config.d.ts +0 -8
  34. package/dist/columns/arktype-config.d.ts.map +0 -1
  35. package/dist/columns/column-types.d.ts +0 -27
  36. package/dist/columns/column-types.d.ts.map +0 -1
  37. package/dist/columns/column.d.ts +0 -30
  38. package/dist/columns/column.d.ts.map +0 -1
  39. package/dist/columns/schema-config.d.ts +0 -10
  40. package/dist/columns/schema-config.d.ts.map +0 -1
  41. package/dist/errors/errors.d.ts +0 -26
  42. package/dist/errors/errors.d.ts.map +0 -1
  43. package/dist/hooks/lifecycle.d.ts +0 -11
  44. package/dist/hooks/lifecycle.d.ts.map +0 -1
  45. package/dist/index-4xnrys72.js +0 -56
  46. package/dist/index-ddxdqxz6.js +0 -636
  47. package/dist/index-k18nf2r7.js +0 -18
  48. package/dist/index-qb301480.js +0 -2424
  49. package/dist/index-sm1xx8gs.js +0 -7828
  50. package/dist/index.d.ts +0 -24
  51. package/dist/index.d.ts.map +0 -1
  52. package/dist/index.js +0 -9229
  53. package/dist/integrations/elysia.d.ts +0 -12
  54. package/dist/integrations/elysia.d.ts.map +0 -1
  55. package/dist/integrations/hono.d.ts +0 -7
  56. package/dist/integrations/hono.d.ts.map +0 -1
  57. package/dist/migrations/cli.d.ts +0 -2
  58. package/dist/migrations/cli.d.ts.map +0 -1
  59. package/dist/migrations/cli.js +0 -4079
  60. package/dist/migrations/config.d.ts +0 -5
  61. package/dist/migrations/config.d.ts.map +0 -1
  62. package/dist/migrations/generator.d.ts +0 -9
  63. package/dist/migrations/generator.d.ts.map +0 -1
  64. package/dist/migrations/index.d.ts +0 -5
  65. package/dist/migrations/index.d.ts.map +0 -1
  66. package/dist/migrations/index.js +0 -17
  67. package/dist/migrations/runner.d.ts +0 -12
  68. package/dist/migrations/runner.d.ts.map +0 -1
  69. package/dist/migrations/types.d.ts +0 -26
  70. package/dist/migrations/types.d.ts.map +0 -1
  71. package/dist/model/model-delete.d.ts +0 -7
  72. package/dist/model/model-delete.d.ts.map +0 -1
  73. package/dist/model/model-hooks.d.ts +0 -10
  74. package/dist/model/model-hooks.d.ts.map +0 -1
  75. package/dist/model/model-relation.d.ts +0 -7
  76. package/dist/model/model-relation.d.ts.map +0 -1
  77. package/dist/model/model-save.d.ts +0 -6
  78. package/dist/model/model-save.d.ts.map +0 -1
  79. package/dist/model/model-scope.d.ts +0 -6
  80. package/dist/model/model-scope.d.ts.map +0 -1
  81. package/dist/model/model-serialize.d.ts +0 -3
  82. package/dist/model/model-serialize.d.ts.map +0 -1
  83. package/dist/model/model-state.d.ts +0 -27
  84. package/dist/model/model-state.d.ts.map +0 -1
  85. package/dist/model/model.d.ts +0 -88
  86. package/dist/model/model.d.ts.map +0 -1
  87. package/dist/pagination/paginator.d.ts +0 -30
  88. package/dist/pagination/paginator.d.ts.map +0 -1
  89. package/dist/paginator-tmp4hxj5.js +0 -9
  90. package/dist/peta.d.ts +0 -20
  91. package/dist/peta.d.ts.map +0 -1
  92. package/dist/relations/morph.d.ts +0 -44
  93. package/dist/relations/morph.d.ts.map +0 -1
  94. package/dist/relations/relation.d.ts +0 -85
  95. package/dist/relations/relation.d.ts.map +0 -1
  96. package/dist/types.d.ts +0 -18
  97. package/dist/types.d.ts.map +0 -1
package/dist/index.mjs ADDED
@@ -0,0 +1,2601 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { n as createCollection } from "./collection-Dv3sQPMx.mjs";
3
+ import { a as ModelNotRegisteredError, c as ValidationError, i as ModelNotFoundError, n as normalizeError, o as RelationNotAllowedError, r as DatabaseError, s as RelationNotFoundError } from "./errors-sfFJolfu.mjs";
4
+ import { a as registerSoftDeletesFor, n as getSoftDeleteConfig, o as registerTimestampsFor, r as hasSoftDelete, s as createHookManager, t as getHooksFor } from "./hooks-BD0xy7uw.mjs";
5
+ import { a as castValue, r as initRuntime, t as createInstance } from "./factory-rIbPGjRg.mjs";
6
+ import { a as getRawRelations, d as setExists, o as getState } from "./state-LtlHp6XV.mjs";
7
+ import { a as setConfig$1, n as reloadModel, r as saveModel, t as getConfig$1 } from "./save-B8rudcT5.mjs";
8
+ import { type } from "arktype";
9
+ import { Kysely, sql } from "kysely";
10
+ import { ulid as ulid$1 } from "ulid";
11
+ //#region src/columns/arktype.ts
12
+ function createArkTypeSchemaConfig() {
13
+ function compile(dataType, args, constraints) {
14
+ return type(buildDef(dataType, args, constraints));
15
+ }
16
+ function parse(schema, value) {
17
+ const result = schema(value);
18
+ if (result instanceof type.errors) throw new ValidationError([...extractProblems(result).entries()].map(([path, msgs]) => `${path}: ${msgs.join(", ")}`).join("; "));
19
+ return result;
20
+ }
21
+ function assert(schema, value) {
22
+ const t = schema;
23
+ try {
24
+ return t.assert(value);
25
+ } catch (e) {
26
+ if (isArkError(e)) throw new ValidationError([...extractProblems(e.arkErrors).entries()].map(([path, msgs]) => `${path}: ${msgs.join(", ")}`).join("; "));
27
+ throw e;
28
+ }
29
+ }
30
+ return {
31
+ compile,
32
+ parse,
33
+ assert
34
+ };
35
+ }
36
+ function buildDef(dataType, args, constraints) {
37
+ let lower, upper, nullable = false, hasEmail = false, hasUrl = false, pattern;
38
+ for (const c of constraints) switch (c.type) {
39
+ case "min":
40
+ lower = c.args[0];
41
+ break;
42
+ case "max":
43
+ upper = c.args[0];
44
+ break;
45
+ case "email":
46
+ hasEmail = true;
47
+ break;
48
+ case "url":
49
+ hasUrl = true;
50
+ break;
51
+ case "pattern":
52
+ pattern = c.args[0];
53
+ break;
54
+ case "nullable":
55
+ nullable = true;
56
+ break;
57
+ }
58
+ let def = "";
59
+ const typeWithSub = typeNameFor(dataType, args) + subTypeModifier(dataType, hasEmail, hasUrl);
60
+ if (lower !== void 0 && upper !== void 0) def += `${lower} <= ${typeWithSub} <= ${upper}`;
61
+ else {
62
+ def += typeWithSub;
63
+ if (lower !== void 0) def += ` >= ${lower}`;
64
+ if (upper !== void 0) def += ` <= ${upper}`;
65
+ }
66
+ if (pattern) def += ` & /${pattern}/`;
67
+ if (nullable) def += " | null";
68
+ return def;
69
+ }
70
+ function typeNameFor(dataType, args) {
71
+ switch (dataType) {
72
+ case "integer":
73
+ case "smallint":
74
+ case "bigint": return "number.integer";
75
+ case "float":
76
+ case "double":
77
+ case "decimal": return "number";
78
+ case "string":
79
+ case "varchar":
80
+ case "text": return "string";
81
+ case "boolean": return "boolean";
82
+ case "timestamp":
83
+ case "date": return "string.date.iso";
84
+ case "json":
85
+ case "jsonb": return "unknown";
86
+ case "uuid": return "string.uuid";
87
+ case "enum": return args.map((v) => JSON.stringify(v)).join(" | ");
88
+ default: return "unknown";
89
+ }
90
+ }
91
+ function subTypeModifier(dataType, hasEmail, hasUrl) {
92
+ if (dataType !== "string" && dataType !== "varchar" && dataType !== "text") return "";
93
+ if (hasEmail) return ".email";
94
+ if (hasUrl) return ".url";
95
+ return "";
96
+ }
97
+ function isArkError(e) {
98
+ return typeof e === "object" && e !== null && "arkErrors" in e;
99
+ }
100
+ function extractProblems(result) {
101
+ const problems = /* @__PURE__ */ new Map();
102
+ const raw = result.flatProblemsByPath;
103
+ if (raw) for (const [path, msgs] of Object.entries(raw)) problems.set(path, msgs);
104
+ return problems;
105
+ }
106
+ //#endregion
107
+ //#region src/columns/column.ts
108
+ function createColumn(schema, dataType, args = [], constraints = []) {
109
+ let compiled = null;
110
+ function withConstraint(type, extraArgs = []) {
111
+ return createColumn(schema, dataType, args, [...constraints, {
112
+ type,
113
+ args: extraArgs
114
+ }]);
115
+ }
116
+ const col = {
117
+ get arkType() {
118
+ if (compiled === null) compiled = schema.compile(dataType, args, constraints);
119
+ return compiled;
120
+ },
121
+ get dataType() {
122
+ return dataType;
123
+ },
124
+ get args() {
125
+ return args;
126
+ },
127
+ get constraints() {
128
+ return constraints;
129
+ },
130
+ get isNullable() {
131
+ return constraints.some((c) => c.type === "nullable");
132
+ },
133
+ get isPrimaryKey() {
134
+ return constraints.some((c) => c.type === "primaryKey");
135
+ },
136
+ get isUnique() {
137
+ return constraints.some((c) => c.type === "unique");
138
+ },
139
+ get defaultValue() {
140
+ const c = constraints.find((c) => c.type === "default");
141
+ if (!c) return void 0;
142
+ const val = c.args[0];
143
+ return typeof val === "function" ? val : val;
144
+ },
145
+ hasConstraint(type) {
146
+ return constraints.some((c) => c.type === type);
147
+ },
148
+ parse(value) {
149
+ return schema.parse(col.arkType, value);
150
+ },
151
+ assert(value) {
152
+ return schema.assert(col.arkType, value);
153
+ },
154
+ primaryKey() {
155
+ return withConstraint("primaryKey");
156
+ },
157
+ nullable() {
158
+ return withConstraint("nullable");
159
+ },
160
+ default(value) {
161
+ return withConstraint("default", [value]);
162
+ },
163
+ unique() {
164
+ return withConstraint("unique");
165
+ },
166
+ index() {
167
+ return withConstraint("index");
168
+ },
169
+ min(n) {
170
+ return withConstraint("min", [n]);
171
+ },
172
+ max(n) {
173
+ return withConstraint("max", [n]);
174
+ },
175
+ email() {
176
+ return withConstraint("email");
177
+ },
178
+ url() {
179
+ return withConstraint("url");
180
+ },
181
+ pattern(regex) {
182
+ return withConstraint("pattern", [typeof regex === "string" ? regex : regex.source]);
183
+ },
184
+ references(table, refColumns) {
185
+ return withConstraint("references", [table, refColumns]);
186
+ }
187
+ };
188
+ return col;
189
+ }
190
+ //#endregion
191
+ //#region src/columns/types.ts
192
+ function t(config) {
193
+ const schema = config.schema;
194
+ function col(dataType, args) {
195
+ return createColumn(schema, dataType, args);
196
+ }
197
+ return {
198
+ integer: () => col("integer"),
199
+ smallint: () => col("smallint"),
200
+ bigint: () => col("bigint"),
201
+ string: (maxLength) => maxLength !== void 0 ? col("string", [maxLength]) : col("string"),
202
+ text: () => col("text"),
203
+ boolean: () => col("boolean"),
204
+ timestamp: () => col("timestamp"),
205
+ date: () => col("date"),
206
+ json: () => col("json"),
207
+ jsonb: () => col("jsonb"),
208
+ float: () => col("float"),
209
+ double: () => col("double"),
210
+ decimal: (precision, scale) => precision !== void 0 ? col("decimal", [precision, scale ?? 0]) : col("decimal"),
211
+ uuid: () => col("uuid"),
212
+ enum: (...values) => col("enum", values),
213
+ timestamps: () => ({
214
+ createdAt: col("timestamp").default(() => (/* @__PURE__ */ new Date()).toISOString()),
215
+ updatedAt: col("timestamp").default(() => (/* @__PURE__ */ new Date()).toISOString())
216
+ })
217
+ };
218
+ }
219
+ //#endregion
220
+ //#region src/hooks/static.ts
221
+ var static_exports = /* @__PURE__ */ __exportAll({
222
+ addStaticHook: () => addStaticHook,
223
+ getStaticHooks: () => getStaticHooks,
224
+ hasStaticHooks: () => hasStaticHooks
225
+ });
226
+ const staticHooks = /* @__PURE__ */ new WeakMap();
227
+ function addStaticHook(def, event, callback) {
228
+ let hooks = staticHooks.get(def);
229
+ if (!hooks) {
230
+ hooks = /* @__PURE__ */ new Map();
231
+ staticHooks.set(def, hooks);
232
+ }
233
+ let cbs = hooks.get(event);
234
+ if (!cbs) {
235
+ cbs = [];
236
+ hooks.set(event, cbs);
237
+ }
238
+ cbs.push(callback);
239
+ return () => {
240
+ const idx = cbs.indexOf(callback);
241
+ if (idx !== -1) cbs.splice(idx, 1);
242
+ };
243
+ }
244
+ function getStaticHooks(def, event) {
245
+ return staticHooks.get(def)?.get(event) ?? [];
246
+ }
247
+ function hasStaticHooks(def, event) {
248
+ return (staticHooks.get(def)?.get(event)?.length ?? 0) > 0;
249
+ }
250
+ //#endregion
251
+ //#region src/relations/eager.ts
252
+ var eager_exports = /* @__PURE__ */ __exportAll({ EagerLoader: () => EagerLoader });
253
+ function isMorphRelation(relation) {
254
+ return relation._morphMap !== void 0;
255
+ }
256
+ var EagerLoader = class {
257
+ async loadRelated(models, eagerLoad, def) {
258
+ const { name, constraints } = eagerLoad;
259
+ const dotIdx = name.indexOf(".");
260
+ if (dotIdx === -1) {
261
+ const relation = def.relations[name];
262
+ if (!relation) throw new Error(`Relation "${name}" not found on ${def.name}`);
263
+ await relation.loadEager(models, name, constraints);
264
+ } else {
265
+ const baseName = name.slice(0, dotIdx);
266
+ const nestedName = name.slice(dotIdx + 1);
267
+ const relation = def.relations[baseName];
268
+ if (!relation) throw new Error(`Relation "${baseName}" not found on ${def.name}`);
269
+ if (isMorphRelation(relation)) throw new Error(`Cannot eagerly load nested relation "${nestedName}" through polymorphic relation "${baseName}" on ${def.name}. Nested eager loading through polymorphic belongsTo is not supported.`);
270
+ await relation.loadEager(models, baseName, null);
271
+ const relatedModels = [];
272
+ for (const model of models) {
273
+ const related = model.$getRelation(baseName);
274
+ if (Array.isArray(related)) relatedModels.push(...related);
275
+ else if (related) relatedModels.push(related);
276
+ }
277
+ if (relatedModels.length > 0) {
278
+ const nestedDef = relation.relatedModelClass;
279
+ if (!nestedDef) throw new Error(`Cannot load nested relation "${nestedName}": "${baseName}" on ${def.name} has no relatedModelClass (morphTo without a morphMap?).`);
280
+ const nestedRelation = nestedDef.relations[nestedName];
281
+ if (!nestedRelation) throw new Error(`Relation "${nestedName}" not found on ${nestedDef.name}`);
282
+ await nestedRelation.loadEager(relatedModels, nestedName, constraints);
283
+ }
284
+ }
285
+ }
286
+ async loadRelatedForModel(model, name, def) {
287
+ await this.loadRelated([model], { name }, def);
288
+ }
289
+ };
290
+ //#endregion
291
+ //#region src/relations/graph/morph.ts
292
+ /** Whether this relation is a MorphTo (polymorphic belongsTo) */
293
+ function isMorphToRelation(relation) {
294
+ return relation._morphMap !== void 0;
295
+ }
296
+ /** Whether this relation is a MorphMany or MorphOne (polymorphic hasMany/hasOne) */
297
+ function isMorphManyRelation(relation) {
298
+ return relation._morphType !== void 0 && !isMorphToRelation(relation);
299
+ }
300
+ /** Get the morph type column name (e.g. "commentableType") from a morph relation */
301
+ function getMorphType(relation) {
302
+ return relation._morphType;
303
+ }
304
+ /** Get the morph type value (e.g. "morph_posts") from a MorphMany/MorphOne relation */
305
+ function getMorphTypeValue(relation) {
306
+ return relation._morphTypeValue;
307
+ }
308
+ /** Get the morph id column name (e.g. "commentableId") from a morph relation */
309
+ function getMorphId(relation) {
310
+ return relation._morphId;
311
+ }
312
+ const THUNK_CACHE$3 = /* @__PURE__ */ new WeakMap();
313
+ function resolveThunk$3(thunk) {
314
+ let cls = THUNK_CACHE$3.get(thunk);
315
+ if (!cls) {
316
+ cls = thunk();
317
+ THUNK_CACHE$3.set(thunk, cls);
318
+ }
319
+ return cls;
320
+ }
321
+ //#endregion
322
+ //#region src/relations/graph/parser.ts
323
+ function getPrimaryKeyColumn$2(def) {
324
+ const cols = def.columns;
325
+ for (const [name, col] of Object.entries(cols)) if (col.isPrimaryKey) return name;
326
+ return "id";
327
+ }
328
+ function getDb$1(def) {
329
+ if (!def._orm) throw new Error("Model not registered");
330
+ return def._orm.kysely;
331
+ }
332
+ function getPivotInfo(relation) {
333
+ if (relation.type !== "manyToMany" || !relation.throughTable) throw new Error("Not a many-to-many relation");
334
+ return {
335
+ throughTable: relation.throughTable,
336
+ foreignPivotKey: relation.foreignPivotKey ?? "",
337
+ relatedPivotKey: relation.relatedPivotKey ?? ""
338
+ };
339
+ }
340
+ async function findRelated(def, conditions) {
341
+ const key = Object.keys(conditions)[0];
342
+ return def.query().where(key, "=", conditions[key]).executeTakeFirst();
343
+ }
344
+ async function resolveTargetId(def, target) {
345
+ if (typeof target === "number" || typeof target === "string") return target;
346
+ const found = await findRelated(def, target);
347
+ if (found) return found.get("id");
348
+ }
349
+ /**
350
+ * Splits a graph node's keys into column data and relation operations.
351
+ * Handles both the old-style { create: ..., connect: ... } wrappers and
352
+ * the new graph-style where nested objects/arrays represent relations directly.
353
+ */
354
+ function extractGraphRelationData(def, node) {
355
+ const columnData = {};
356
+ const relationOps = {};
357
+ for (const [key, value] of Object.entries(node)) {
358
+ if (key === "#id" || key === "#ref" || key === "#dbRef") continue;
359
+ if (def.relations[key]) relationOps[key] = value;
360
+ else columnData[key] = value;
361
+ }
362
+ return {
363
+ columnData,
364
+ relationOps
365
+ };
366
+ }
367
+ function collectRefs(node, def, refMap) {
368
+ const id = node["#id"];
369
+ if (id && typeof id === "string") {
370
+ if (refMap.has(id)) throw new Error(`Duplicate #id "${id}" in graph`);
371
+ refMap.set(id, {
372
+ node,
373
+ def
374
+ });
375
+ }
376
+ for (const [key, value] of Object.entries(node)) {
377
+ if (key === "#id" || key === "#ref" || key === "#dbRef") continue;
378
+ if (def.relations[key]) {
379
+ const relatedDef = def.relations[key].relatedModelClass;
380
+ if (Array.isArray(value)) {
381
+ for (const item of value) if (item && typeof item === "object") collectRefs(item, relatedDef, refMap);
382
+ } else if (value && typeof value === "object") {
383
+ const inner = value.create;
384
+ if (inner && typeof inner === "object") collectRefs(inner, relatedDef, refMap);
385
+ else collectRefs(value, relatedDef, refMap);
386
+ }
387
+ }
388
+ }
389
+ }
390
+ function resolveRefs(node, context) {
391
+ for (const [key, value] of Object.entries(node)) {
392
+ if (key === "#id" || key === "#ref" || key === "#dbRef") continue;
393
+ if (value && typeof value === "object") if (Array.isArray(value)) for (let i = 0; i < value.length; i++) {
394
+ const item = value[i];
395
+ if (item && typeof item === "object") if ("#ref" in item) {
396
+ const refId = item["#ref"];
397
+ if (!context.allowRefs) throw new Error(`#ref is used but allowRefs option is not enabled. Set { allowRefs: true } to use #ref.`);
398
+ const entry = context.refMap.get(refId);
399
+ if (!entry) throw new Error(`#ref "${refId}" not found in graph`);
400
+ value[i] = entry.node;
401
+ } else resolveRefs(item, context);
402
+ }
403
+ else {
404
+ const obj = value;
405
+ if (obj.create && typeof obj.create === "object") resolveRefs(obj.create, context);
406
+ resolveRefs(obj, context);
407
+ }
408
+ }
409
+ }
410
+ //#endregion
411
+ //#region src/relations/graph/security.ts
412
+ function isRelationAllowed(relName, allowedSet) {
413
+ const parts = relName.split(".");
414
+ for (let i = 0; i < parts.length; i++) if (allowedSet.has(parts.slice(0, i + 1).join("."))) return true;
415
+ return false;
416
+ }
417
+ function isRelPathAllowed(relName, option) {
418
+ if (option === void 0 || option === false) return false;
419
+ if (option === true) return true;
420
+ return option.includes(relName);
421
+ }
422
+ /**
423
+ * Resolve allowGraph from options (supports both string[] and Set<string>).
424
+ */
425
+ function resolveAllowGraph(options) {
426
+ if (!options.allowGraph) return void 0;
427
+ return options.allowGraph instanceof Set ? options.allowGraph : new Set(options.allowGraph);
428
+ }
429
+ /**
430
+ * Assert that a relation path is allowed by the allowGraph set.
431
+ * Throws RelationNotAllowedError if the path is not permitted.
432
+ * Does nothing if allowedSet is undefined (no restriction).
433
+ */
434
+ function assertRelationAllowed(def, fullPath, allowedSet) {
435
+ if (!allowedSet || allowedSet.size === 0) return;
436
+ if (!isRelationAllowed(fullPath, allowedSet)) throw new RelationNotAllowedError(def.name, fullPath);
437
+ }
438
+ /**
439
+ * Build the full dotted path for a nested relation.
440
+ * If parentPath is empty, returns just relName. Otherwise parentPath + "." + relName.
441
+ */
442
+ function joinPath(parentPath, relName) {
443
+ return parentPath ? `${parentPath}.${relName}` : relName;
444
+ }
445
+ function relNameFromPath(path) {
446
+ const parts = path.split(".");
447
+ return parts[parts.length - 1] ?? "";
448
+ }
449
+ //#endregion
450
+ //#region src/relations/graph/insert.ts
451
+ /**
452
+ * Insert a graph of related models.
453
+ *
454
+ * Supports:
455
+ * - Nested relation objects (belongsTo/hasOne)
456
+ * - Nested relation arrays (hasMany/manyToMany)
457
+ * - `#id` / `#ref` for shared references (requires `allowRefs: true`)
458
+ * - `#dbRef` for relating to existing records
459
+ *
460
+ * Returns the root node(s) as ModelInstance(s) with IDs populated.
461
+ */
462
+ async function insertGraph(def, data, options = {}) {
463
+ const context = {
464
+ refMap: /* @__PURE__ */ new Map(),
465
+ processedRefs: /* @__PURE__ */ new Map(),
466
+ allowRefs: options.allowRefs ?? false,
467
+ allowedGraphSet: resolveAllowGraph(options)
468
+ };
469
+ const nodes = Array.isArray(data) ? data : [data];
470
+ for (const node of nodes) collectRefs(node, def, context.refMap);
471
+ for (let i = 0; i < nodes.length; i++) {
472
+ const node = nodes[i];
473
+ if (typeof node === "object" && node !== null && "#ref" in node) {
474
+ if (!context.allowRefs) throw new Error(`#ref is used but allowRefs option is not enabled. Set { allowRefs: true } to use #ref.`);
475
+ const refId = node["#ref"];
476
+ if (!refId) throw new Error(`#ref must be a string`);
477
+ const entry = context.refMap.get(refId);
478
+ if (!entry) throw new Error(`#ref "${refId}" not found in graph`);
479
+ nodes[i] = entry.node;
480
+ } else if (node) resolveRefs(node, context);
481
+ }
482
+ const results = [];
483
+ for (const node of nodes) {
484
+ const result = await processNode(node, def, null, options, context, "");
485
+ results.push(result);
486
+ }
487
+ return Array.isArray(data) ? results : results[0];
488
+ }
489
+ async function processNode(node, def, parentFK, options, context, path) {
490
+ const nodeId = node["#id"];
491
+ if (nodeId && typeof nodeId === "string" && context.processedRefs.has(nodeId)) return context.processedRefs.get(nodeId);
492
+ const { columnData, relationOps } = extractGraphRelationData(def, node);
493
+ if (parentFK) Object.assign(columnData, parentFK);
494
+ for (const [relName, op] of Object.entries(relationOps)) {
495
+ const relation = def.relations[relName];
496
+ if (relation?.type === "belongsTo") {
497
+ const relPath = joinPath(path, relName);
498
+ assertRelationAllowed(def, relPath, context.allowedGraphSet);
499
+ const relatedInstance = await processBelongsTo(relation, op, options, context, relPath, columnData);
500
+ if (relatedInstance) columnData[relation.foreignKey] = relatedInstance.get(relation.localKey);
501
+ }
502
+ }
503
+ if (node["#dbRef"] != null) {
504
+ const id = node["#dbRef"];
505
+ const existing = await def.find(id);
506
+ if (!existing) throw new DatabaseError(`#dbRef ${id} not found on ${def.name}`, "UNKNOWN");
507
+ if (nodeId && typeof nodeId === "string") context.processedRefs.set(nodeId, existing);
508
+ return existing;
509
+ }
510
+ const instance = await def.insert(columnData);
511
+ if (nodeId && typeof nodeId === "string") context.processedRefs.set(nodeId, instance);
512
+ const pkCol = getPrimaryKeyColumn$2(def);
513
+ const pkValue = instance.get(pkCol);
514
+ if (pkValue == null) throw new DatabaseError("Cannot process relations without primary key", "MISSING_ID");
515
+ for (const [relName, op] of Object.entries(relationOps)) {
516
+ const relation = def.relations[relName];
517
+ if (!relation) continue;
518
+ if (relation.type === "belongsTo") continue;
519
+ const relPath = joinPath(path, relName);
520
+ assertRelationAllowed(def, relPath, context.allowedGraphSet);
521
+ const relOptions = {
522
+ ...options,
523
+ relate: options.relate
524
+ };
525
+ if (relation.type === "hasMany" || relation.type === "hasOne") await processHasMany(instance, relation, op, pkValue, relOptions, context, relPath);
526
+ else if (relation.type === "manyToMany") await processManyToMany(instance, relation, op, pkValue, relOptions, context, relPath);
527
+ }
528
+ return instance;
529
+ }
530
+ async function processBelongsTo(relation, op, options, context, path, parentColumnData) {
531
+ if (isMorphToRelation(relation)) return processMorphTo(relation, op, options, context, path, parentColumnData);
532
+ const relatedDef = relation.relatedModelClass;
533
+ if (op["#dbRef"] != null) {
534
+ const id = op["#dbRef"];
535
+ const existing = await relatedDef.find(id);
536
+ if (!existing) throw new DatabaseError(`#dbRef ${id} not found on ${relatedDef.name}`, "UNKNOWN");
537
+ return existing;
538
+ }
539
+ if (op.connect && typeof op.connect === "object") {
540
+ const conditions = op.connect;
541
+ const existing = await findRelated(relatedDef, conditions);
542
+ if (existing) return existing;
543
+ throw new DatabaseError(`Cannot connect: ${JSON.stringify(conditions)} not found on ${relatedDef.name}`, "UNKNOWN");
544
+ }
545
+ if (op.create && typeof op.create === "object") return processNode(op.create, relatedDef, null, options, context, path);
546
+ return processNode({ ...op }, relatedDef, null, options, context, path);
547
+ }
548
+ /**
549
+ * Process a MorphTo (polymorphic belongsTo) relation in a graph operation.
550
+ *
551
+ * The user must specify which polymorphic type to create via a `type` key
552
+ * in the operation data:
553
+ * { commentable: { create: { title: "..." }, type: "morph_posts" } }
554
+ *
555
+ * If the morphMap has only one entry, `type` is optional (auto-detected).
556
+ */
557
+ async function processMorphTo(relation, op, options, context, path, parentColumnData) {
558
+ const morphMap = relation._morphMap;
559
+ const morphType = getMorphType(relation);
560
+ const morphId = getMorphId(relation);
561
+ if (!morphMap || Object.keys(morphMap).length === 0) throw new Error("Cannot process MorphTo relation: no morphMap provided. Define a morphMap with model thunks when calling defineMorphTo().");
562
+ let typeValue = op.type;
563
+ if (!typeValue) {
564
+ const keys = Object.keys(morphMap);
565
+ if (keys.length === 1) typeValue = keys[0];
566
+ }
567
+ if (!typeValue) throw new Error(`Cannot resolve MorphTo: no type specified. Provide a "type" key in the relation data (e.g., { type: "${Object.keys(morphMap)[0]}" }). Available types: ${Object.keys(morphMap).join(", ")}`);
568
+ const thunk = morphMap[typeValue];
569
+ if (!thunk) throw new Error(`No model registered for morph type "${typeValue}" in MorphTo. Available types: ${Object.keys(morphMap).join(", ")}`);
570
+ const relatedDef = resolveThunk$3(thunk);
571
+ let instance = null;
572
+ if (op["#dbRef"] != null) {
573
+ const id = op["#dbRef"];
574
+ const existing = await relatedDef.find(id);
575
+ if (!existing) throw new DatabaseError(`#dbRef ${id} not found on ${relatedDef.name}`, "UNKNOWN");
576
+ instance = existing;
577
+ } else if (op.connect && typeof op.connect === "object") {
578
+ const conditions = op.connect;
579
+ const existing = await findRelated(relatedDef, conditions);
580
+ if (existing) instance = existing;
581
+ else throw new DatabaseError(`Cannot connect: ${JSON.stringify(conditions)} not found on ${relatedDef.name}`, "UNKNOWN");
582
+ } else if (op.create && typeof op.create === "object") instance = await processNode(op.create, relatedDef, null, options, context, path);
583
+ else {
584
+ const createData = { ...op };
585
+ delete createData.type;
586
+ delete createData[morphType];
587
+ delete createData[morphId];
588
+ instance = await processNode(createData, relatedDef, null, options, context, path);
589
+ }
590
+ if (instance && parentColumnData && typeValue) parentColumnData[morphType] = typeValue;
591
+ return instance;
592
+ }
593
+ async function processHasMany(_instance, relation, op, pkValue, options, context, path) {
594
+ const relatedDef = relation.relatedModelClass;
595
+ const fk = relation.foreignKey;
596
+ let items;
597
+ if (op == null) items = [];
598
+ else if (Array.isArray(op)) items = op;
599
+ else if (op?.create && Array.isArray(op.create)) items = op.create;
600
+ else if (typeof op === "object" && !("connect" in op)) items = [op];
601
+ else items = [];
602
+ for (const item of items) {
603
+ if (item["#dbRef"] != null) {
604
+ const id = item["#dbRef"];
605
+ const existing = await relatedDef.find(id);
606
+ if (!existing) throw new DatabaseError(`#dbRef ${id} not found on ${relatedDef.name}`, "UNKNOWN");
607
+ existing.set(fk, pkValue);
608
+ await existing.$save();
609
+ continue;
610
+ }
611
+ const parentData = { [fk]: pkValue };
612
+ if (isMorphManyRelation(relation)) {
613
+ const typeCol = getMorphType(relation);
614
+ const typeVal = getMorphTypeValue(relation);
615
+ if (typeVal !== void 0) parentData[typeCol] = typeVal;
616
+ }
617
+ await processNode(item, relatedDef, parentData, options, context, path);
618
+ }
619
+ const connectItems = !Array.isArray(op) ? op?.connect ?? [] : [];
620
+ for (const target of connectItems) {
621
+ const targetId = await resolveTargetId(relatedDef, target);
622
+ if (targetId != null) {
623
+ const existing = await relatedDef.find(targetId);
624
+ if (existing) {
625
+ existing.set(fk, pkValue);
626
+ await existing.$save();
627
+ }
628
+ }
629
+ }
630
+ }
631
+ async function processManyToMany(_instance, relation, op, pkValue, options, context, path) {
632
+ const relatedDef = relation.relatedModelClass;
633
+ const { throughTable, foreignPivotKey, relatedPivotKey } = getPivotInfo(relation);
634
+ const db = getDb$1(relatedDef);
635
+ const items = Array.isArray(op) ? op : Array.isArray(op?.create) ? op.create : [];
636
+ for (const item of items) {
637
+ if (item["#dbRef"] != null) {
638
+ const id = item["#dbRef"];
639
+ try {
640
+ await db.insertInto(throughTable).values({
641
+ [foreignPivotKey]: pkValue,
642
+ [relatedPivotKey]: id
643
+ }).execute();
644
+ } catch {}
645
+ continue;
646
+ }
647
+ const relatedId = (await processNode(item, relatedDef, null, options, context, path)).get(relation.localKey ?? "id");
648
+ if (relatedId != null) try {
649
+ await db.insertInto(throughTable).values({
650
+ [foreignPivotKey]: pkValue,
651
+ [relatedPivotKey]: relatedId
652
+ }).execute();
653
+ } catch {}
654
+ }
655
+ const connectItems = !Array.isArray(op) ? op?.connect ?? [] : [];
656
+ for (const target of connectItems) {
657
+ const targetId = await resolveTargetId(relatedDef, target);
658
+ if (targetId != null) try {
659
+ await db.insertInto(throughTable).values({
660
+ [foreignPivotKey]: pkValue,
661
+ [relatedPivotKey]: targetId
662
+ }).execute();
663
+ } catch {}
664
+ }
665
+ }
666
+ //#endregion
667
+ //#region src/relations/graph/upsert.ts
668
+ /**
669
+ * Upsert a graph of related models.
670
+ *
671
+ * Models with an `id` get updated, models without an `id` get inserted.
672
+ * Models in relation arrays that were not included get deleted (or unrelated).
673
+ *
674
+ * See {@link UpsertGraphOptions} for fine-grained control.
675
+ */
676
+ async function upsertGraph(def, data, options = {}) {
677
+ const context = {
678
+ refMap: /* @__PURE__ */ new Map(),
679
+ processedRefs: /* @__PURE__ */ new Map(),
680
+ allowRefs: options.allowRefs ?? false,
681
+ allowedGraphSet: resolveAllowGraph(options)
682
+ };
683
+ const nodes = Array.isArray(data) ? data : [data];
684
+ for (const node of nodes) collectRefs(node, def, context.refMap);
685
+ for (const node of nodes) resolveRefs(node, context);
686
+ const results = [];
687
+ for (const node of nodes) {
688
+ const result = await upsertNode(node, def, null, options, context, "");
689
+ results.push(result);
690
+ }
691
+ return Array.isArray(data) ? results : results[0];
692
+ }
693
+ async function upsertNode(node, def, parentFK, options, context, _path) {
694
+ const nodeId = node["#id"];
695
+ if (nodeId && typeof nodeId === "string" && context.processedRefs.has(nodeId)) return context.processedRefs.get(nodeId);
696
+ const { columnData, relationOps } = extractGraphRelationData(def, node);
697
+ if (parentFK) Object.assign(columnData, parentFK);
698
+ for (const [relName, op] of Object.entries(relationOps)) {
699
+ const relation = def.relations[relName];
700
+ if (relation?.type === "belongsTo") {
701
+ const relPath = joinPath(_path, relName);
702
+ assertRelationAllowed(def, relPath, context.allowedGraphSet);
703
+ const relatedInstance = await processBelongsTo(relation, op, options, context, relPath, columnData);
704
+ if (relatedInstance) columnData[relation.foreignKey] = relatedInstance.get(relation.localKey);
705
+ }
706
+ }
707
+ const pkCol = getPrimaryKeyColumn$2(def);
708
+ const idValue = columnData[pkCol] ?? node[pkCol];
709
+ let instance;
710
+ if (idValue != null) if (isRelPathAllowed(pkCol, options.noUpdate)) {
711
+ const existing = await def.find(idValue);
712
+ if (!existing) throw new DatabaseError(`Cannot find ${def.name} with id ${idValue}`, "UNKNOWN");
713
+ instance = existing;
714
+ } else {
715
+ const existing = await def.find(idValue);
716
+ if (existing) {
717
+ existing.fill(columnData);
718
+ await existing.$save();
719
+ instance = existing;
720
+ } else instance = await def.insert(columnData);
721
+ }
722
+ else instance = await def.insert(columnData);
723
+ if (nodeId && typeof nodeId === "string") context.processedRefs.set(nodeId, instance);
724
+ const pkValue = instance.get(pkCol);
725
+ if (pkValue == null) throw new DatabaseError("Cannot process relations without primary key", "MISSING_ID");
726
+ for (const [relName, op] of Object.entries(relationOps)) {
727
+ const relation = def.relations[relName];
728
+ if (!relation) continue;
729
+ if (relation.type === "belongsTo") continue;
730
+ const relPath = joinPath(_path, relName);
731
+ assertRelationAllowed(def, relPath, context.allowedGraphSet);
732
+ if (relation.type === "hasMany" || relation.type === "hasOne") await upsertHasMany(instance, relation, op, pkValue, options, context, relPath);
733
+ else if (relation.type === "manyToMany") await upsertManyToMany(instance, relation, op, pkValue, options, context, relPath);
734
+ }
735
+ return instance;
736
+ }
737
+ async function upsertHasMany(_instance, relation, op, pkValue, options, context, path) {
738
+ const relatedDef = relation.relatedModelClass;
739
+ const fk = relation.foreignKey;
740
+ const existingChildren = await relatedDef.query().where(fk, "=", pkValue).execute();
741
+ const existingMap = /* @__PURE__ */ new Map();
742
+ for (const child of existingChildren) {
743
+ const pkCol = getPrimaryKeyColumn$2(relatedDef);
744
+ existingMap.set(child.get(pkCol), child);
745
+ }
746
+ const items = Array.isArray(op) ? op : Array.isArray(op?.create) ? op.create : [];
747
+ const incomingIds = /* @__PURE__ */ new Set();
748
+ for (const item of items) {
749
+ const itemId = item[getPrimaryKeyColumn$2(relatedDef)] ?? item.id;
750
+ if (itemId != null) {
751
+ incomingIds.add(itemId);
752
+ if (!isRelPathAllowed(relNameFromPath(path), options.noUpdate)) {
753
+ const existing = existingMap.get(itemId);
754
+ if (existing) {
755
+ const { columnData: colData, relationOps: nestedOps } = extractGraphRelationData(relatedDef, item);
756
+ existing.fill(colData);
757
+ await existing.$save();
758
+ if (item["#id"]) context.processedRefs.set(item["#id"], existing);
759
+ existingMap.delete(itemId);
760
+ for (const [relName, relOp] of Object.entries(nestedOps)) {
761
+ const rel = relatedDef.relations[relName];
762
+ if (!rel) continue;
763
+ const nestedPath = `${path}.${relName}`;
764
+ assertRelationAllowed(relatedDef, nestedPath, context.allowedGraphSet);
765
+ const childPk = existing.get(getPrimaryKeyColumn$2(relatedDef));
766
+ if (rel.type === "hasMany" || rel.type === "hasOne") await upsertHasMany(existing, rel, relOp, childPk, options, context, nestedPath);
767
+ else if (rel.type === "manyToMany") await upsertManyToMany(existing, rel, relOp, childPk, options, context, nestedPath);
768
+ }
769
+ continue;
770
+ }
771
+ }
772
+ }
773
+ const parentData = { [fk]: pkValue };
774
+ if (isMorphManyRelation(relation)) {
775
+ const typeCol = getMorphType(relation);
776
+ const typeVal = getMorphTypeValue(relation);
777
+ if (typeVal !== void 0) parentData[typeCol] = typeVal;
778
+ }
779
+ await processNode(item, relatedDef, parentData, options, context, path);
780
+ }
781
+ const relName = relNameFromPath(path);
782
+ const shouldDelete = !isRelPathAllowed(relName, options.noDelete);
783
+ const shouldUnrelate = isRelPathAllowed(relName, options.unrelate);
784
+ if (shouldDelete || shouldUnrelate) {
785
+ for (const [existingId, existing] of existingMap) if (!incomingIds.has(existingId)) {
786
+ if (shouldUnrelate) {
787
+ existing.set(fk, null);
788
+ await existing.$save();
789
+ } else if (shouldDelete) await existing.$delete();
790
+ }
791
+ }
792
+ }
793
+ async function upsertManyToMany(_instance, relation, op, pkValue, options, context, path) {
794
+ const relatedDef = relation.relatedModelClass;
795
+ const { throughTable, foreignPivotKey, relatedPivotKey } = getPivotInfo(relation);
796
+ const db = getDb$1(relatedDef);
797
+ let existingPivotIds = /* @__PURE__ */ new Set();
798
+ try {
799
+ const pivots = await db.selectFrom(throughTable).select(relatedPivotKey).where(foreignPivotKey, "=", pkValue).execute();
800
+ existingPivotIds = new Set(pivots.map((p) => p[relatedPivotKey]));
801
+ } catch {}
802
+ const incomingIds = /* @__PURE__ */ new Set();
803
+ const items = Array.isArray(op) ? op : Array.isArray(op?.create) ? op.create : [];
804
+ for (const item of items) {
805
+ if (item["#dbRef"] != null) {
806
+ const id = item["#dbRef"];
807
+ incomingIds.add(id);
808
+ if (!existingPivotIds.has(id)) try {
809
+ await db.insertInto(throughTable).values({
810
+ [foreignPivotKey]: pkValue,
811
+ [relatedPivotKey]: id
812
+ }).execute();
813
+ } catch {}
814
+ continue;
815
+ }
816
+ const itemId = item[getPrimaryKeyColumn$2(relatedDef)] ?? item.id;
817
+ if (itemId != null) {
818
+ incomingIds.add(itemId);
819
+ if (!isRelPathAllowed(relNameFromPath(path), options.noUpdate)) {
820
+ const existing = await relatedDef.find(itemId);
821
+ if (existing) {
822
+ existing.fill(item);
823
+ await existing.$save();
824
+ }
825
+ }
826
+ if (!existingPivotIds.has(itemId)) try {
827
+ await db.insertInto(throughTable).values({
828
+ [foreignPivotKey]: pkValue,
829
+ [relatedPivotKey]: itemId
830
+ }).execute();
831
+ } catch {}
832
+ } else {
833
+ const relatedId = (await processNode(item, relatedDef, null, options, context, path)).get(relation.localKey ?? "id");
834
+ if (relatedId != null) {
835
+ incomingIds.add(relatedId);
836
+ try {
837
+ await db.insertInto(throughTable).values({
838
+ [foreignPivotKey]: pkValue,
839
+ [relatedPivotKey]: relatedId
840
+ }).execute();
841
+ } catch {}
842
+ }
843
+ }
844
+ }
845
+ const connectItems = !Array.isArray(op) ? op?.connect ?? [] : [];
846
+ for (const target of connectItems) {
847
+ const targetId = await resolveTargetId(relatedDef, target);
848
+ if (targetId != null) {
849
+ incomingIds.add(targetId);
850
+ if (!existingPivotIds.has(targetId)) try {
851
+ await db.insertInto(throughTable).values({
852
+ [foreignPivotKey]: pkValue,
853
+ [relatedPivotKey]: targetId
854
+ }).execute();
855
+ } catch {}
856
+ }
857
+ }
858
+ const relName = relNameFromPath(path);
859
+ const shouldDelete = !isRelPathAllowed(relName, options.noDelete);
860
+ const shouldUnrelate = isRelPathAllowed(relName, options.unrelate);
861
+ if (shouldDelete || shouldUnrelate) {
862
+ for (const pivotId of existingPivotIds) if (!incomingIds.has(pivotId)) {
863
+ if (shouldUnrelate) try {
864
+ await db.deleteFrom(throughTable).where(foreignPivotKey, "=", pkValue).where(relatedPivotKey, "=", pivotId).execute();
865
+ } catch {}
866
+ else if (shouldDelete) {
867
+ await (await relatedDef.find(pivotId))?.$delete();
868
+ try {
869
+ await db.deleteFrom(throughTable).where(foreignPivotKey, "=", pkValue).where(relatedPivotKey, "=", pivotId).execute();
870
+ } catch {}
871
+ }
872
+ }
873
+ }
874
+ }
875
+ //#endregion
876
+ //#region src/relations/graph/index.ts
877
+ var graph_exports = /* @__PURE__ */ __exportAll({
878
+ insertGraph: () => insertGraph,
879
+ upsertGraph: () => upsertGraph
880
+ });
881
+ //#endregion
882
+ //#region src/query/builder.ts
883
+ function rawSql(str) {
884
+ return sql([str]);
885
+ }
886
+ const SAFE_COLUMN = /^[a-zA-Z_*][a-zA-Z0-9_.*]*$/;
887
+ function createQueryBuilder(def, peta) {
888
+ const db = peta?.kysely ?? def._orm?.kysely;
889
+ if (!db) throw new Error("Model not registered with an ORM instance");
890
+ let qb = db.selectFrom(def.table);
891
+ let hasAll = false;
892
+ const eagerLoads = [];
893
+ let withTrashed = false;
894
+ let onlyTrashedMode = false;
895
+ const omitScopes = /* @__PURE__ */ new Set();
896
+ let scopesApplied = false;
897
+ let hasEffectiveWhere = false;
898
+ let selectedColumns = null;
899
+ const aggregateColumns = [];
900
+ const aggregateAliases = [];
901
+ const whereOps = [];
902
+ let allowedGraphSet = null;
903
+ function validateColumn(ref) {
904
+ if (!SAFE_COLUMN.test(ref)) throw new Error(`Invalid column reference: ${ref}`);
905
+ return ref;
906
+ }
907
+ function applyScopes() {
908
+ if (scopesApplied) return;
909
+ scopesApplied = true;
910
+ const scopes = def.getGlobalScopes?.();
911
+ if (scopes) {
912
+ for (const [name, fn] of scopes) if (!omitScopes.has(name)) fn(self);
913
+ }
914
+ const cols = def.columns;
915
+ if ("deletedAt" in cols || Object.values(cols).some((c) => c.dataType === "timestamp" && c.isNullable)) {
916
+ if (onlyTrashedMode) qb = qb.where("deletedAt", "is not", null);
917
+ else if (!withTrashed) qb = qb.where("deletedAt", "is", null);
918
+ }
919
+ }
920
+ function assertWhereForMutation() {
921
+ if (!hasEffectiveWhere && !hasAll) throw new Error("Mutation requires an explicit WHERE condition or .all(). Use .all() to target all rows, or add a WHERE clause.");
922
+ }
923
+ async function runExecute() {
924
+ applyScopes();
925
+ const { getComputedConfig, applyComputedColumnsAsync } = await Promise.resolve().then(() => computed_exports);
926
+ const computedConfig = getComputedConfig(def);
927
+ const sqlColumns = selectedColumns?.filter((col) => !computedConfig?.[col]);
928
+ const allSelectedAreComputed = selectedColumns !== null && sqlColumns !== void 0 && sqlColumns.length === 0 && selectedColumns.length > 0;
929
+ let currentQb = sqlColumns && sqlColumns.length > 0 ? qb.select(sqlColumns.map(validateColumn)) : allSelectedAreComputed ? qb.selectAll() : selectedColumns ? qb.select(selectedColumns.map(validateColumn)) : qb.selectAll();
930
+ for (let i = 0; i < aggregateColumns.length; i++) {
931
+ const col = aggregateColumns[i];
932
+ if (col) currentQb = currentQb.select(sql([col]));
933
+ }
934
+ const models = (await currentQb.execute()).map((row) => def.hydrate(row));
935
+ if (models.length > 0) {
936
+ if (computedConfig) await applyComputedColumnsAsync(models, computedConfig, selectedColumns);
937
+ }
938
+ if (eagerLoads.length > 0) {
939
+ const loader = new EagerLoader();
940
+ for (const el of eagerLoads) await loader.loadRelated(models, el, def);
941
+ }
942
+ return models;
943
+ }
944
+ const self = {
945
+ then(onfulfilled, onrejected) {
946
+ return runExecute().then(onfulfilled, onrejected);
947
+ },
948
+ execute: runExecute,
949
+ async collect() {
950
+ const items = await runExecute();
951
+ const { createCollection } = await import("./collection-Dv3sQPMx.mjs").then((n) => n.t);
952
+ return createCollection(items);
953
+ },
954
+ async executeTakeFirst() {
955
+ return (await self.limit(1).execute())[0];
956
+ },
957
+ async executeTakeFirstOrThrow() {
958
+ const item = await self.executeTakeFirst();
959
+ if (!item) throw new ModelNotFoundError(def.name, "query");
960
+ return item;
961
+ },
962
+ async find(id) {
963
+ return self.where("id", "=", id).executeTakeFirst();
964
+ },
965
+ async findOrFail(id) {
966
+ const item = await self.find(id);
967
+ if (!item) throw new ModelNotFoundError(def.name, id);
968
+ return item;
969
+ },
970
+ async first() {
971
+ return self.limit(1).executeTakeFirst();
972
+ },
973
+ toSQL() {
974
+ applyScopes();
975
+ const compiled = qb.selectAll().compile();
976
+ return {
977
+ sql: compiled.sql,
978
+ parameters: compiled.parameters
979
+ };
980
+ },
981
+ async count() {
982
+ applyScopes();
983
+ const result = await qb.clearOrderBy().select((eb) => eb.fn.countAll().as("count")).executeTakeFirst();
984
+ return Number(result?.count ?? 0);
985
+ },
986
+ async sum(column) {
987
+ applyScopes();
988
+ const result = await qb.select((eb) => eb.fn.sum(validateColumn(column)).as("sum")).executeTakeFirst();
989
+ return Number(result?.sum ?? 0);
990
+ },
991
+ async avg(column) {
992
+ applyScopes();
993
+ const result = await qb.select((eb) => eb.fn.avg(validateColumn(column)).as("avg")).executeTakeFirst();
994
+ return Number(result?.avg ?? 0);
995
+ },
996
+ async min(column) {
997
+ applyScopes();
998
+ const result = await qb.select((eb) => eb.fn.min(validateColumn(column)).as("min")).executeTakeFirst();
999
+ return Number(result?.min ?? 0);
1000
+ },
1001
+ async max(column) {
1002
+ applyScopes();
1003
+ const result = await qb.select((eb) => eb.fn.max(validateColumn(column)).as("max")).executeTakeFirst();
1004
+ return Number(result?.max ?? 0);
1005
+ },
1006
+ withCount(relation) {
1007
+ const alias = `${relation}_count`;
1008
+ const rel = def.relations[relation];
1009
+ if (!rel) throw new RelationNotFoundError(def.name, relation);
1010
+ const relatedTable = rel.relatedModelClass.table;
1011
+ const fk = rel.foreignKey;
1012
+ const lk = rel.localKey;
1013
+ aggregateColumns.push(`(SELECT COUNT(*) FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk}) as ${alias}`);
1014
+ aggregateAliases.push(alias);
1015
+ return self;
1016
+ },
1017
+ withSum(relation, column) {
1018
+ const alias = `${relation}_sum_${column}`;
1019
+ const rel = def.relations[relation];
1020
+ if (!rel) throw new RelationNotFoundError(def.name, relation);
1021
+ const relatedTable = rel.relatedModelClass.table;
1022
+ const fk = rel.foreignKey;
1023
+ const lk = rel.localKey;
1024
+ aggregateColumns.push(`(SELECT COALESCE(SUM(${relatedTable}.${validateColumn(column)}), 0) FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk}) as ${alias}`);
1025
+ aggregateAliases.push(alias);
1026
+ return self;
1027
+ },
1028
+ withAvg(relation, column) {
1029
+ const alias = `${relation}_avg_${column}`;
1030
+ const rel = def.relations[relation];
1031
+ if (!rel) throw new RelationNotFoundError(def.name, relation);
1032
+ const relatedTable = rel.relatedModelClass.table;
1033
+ const fk = rel.foreignKey;
1034
+ const lk = rel.localKey;
1035
+ aggregateColumns.push(`(SELECT AVG(${relatedTable}.${validateColumn(column)}) FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk}) as ${alias}`);
1036
+ aggregateAliases.push(alias);
1037
+ return self;
1038
+ },
1039
+ withMin(relation, column) {
1040
+ const alias = `${relation}_min_${column}`;
1041
+ const rel = def.relations[relation];
1042
+ if (!rel) throw new RelationNotFoundError(def.name, relation);
1043
+ const relatedTable = rel.relatedModelClass.table;
1044
+ const fk = rel.foreignKey;
1045
+ const lk = rel.localKey;
1046
+ aggregateColumns.push(`(SELECT MIN(${relatedTable}.${validateColumn(column)}) FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk}) as ${alias}`);
1047
+ aggregateAliases.push(alias);
1048
+ return self;
1049
+ },
1050
+ withMax(relation, column) {
1051
+ const alias = `${relation}_max_${column}`;
1052
+ const rel = def.relations[relation];
1053
+ if (!rel) throw new RelationNotFoundError(def.name, relation);
1054
+ const relatedTable = rel.relatedModelClass.table;
1055
+ const fk = rel.foreignKey;
1056
+ const lk = rel.localKey;
1057
+ aggregateColumns.push(`(SELECT MAX(${relatedTable}.${validateColumn(column)}) FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk}) as ${alias}`);
1058
+ aggregateAliases.push(alias);
1059
+ return self;
1060
+ },
1061
+ withExists(relation) {
1062
+ const alias = `${relation}_exists`;
1063
+ const rel = def.relations[relation];
1064
+ if (!rel) throw new RelationNotFoundError(def.name, relation);
1065
+ const relatedTable = rel.relatedModelClass.table;
1066
+ const fk = rel.foreignKey;
1067
+ const lk = rel.localKey;
1068
+ aggregateColumns.push(`(SELECT EXISTS(SELECT 1 FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk})) as ${alias}`);
1069
+ aggregateAliases.push(alias);
1070
+ return self;
1071
+ },
1072
+ async chunk(size, callback) {
1073
+ let offset = 0;
1074
+ let hasMore = true;
1075
+ while (hasMore) {
1076
+ const items = await self.limit(size).offset(offset).execute();
1077
+ if (items.length === 0) hasMore = false;
1078
+ else {
1079
+ await callback(items);
1080
+ offset += items.length;
1081
+ hasMore = items.length >= size;
1082
+ }
1083
+ }
1084
+ },
1085
+ async paginate(page, perPage = 20) {
1086
+ const safePage = Math.max(1, page);
1087
+ const safePerPage = Math.min(Math.max(1, perPage), 1e3);
1088
+ applyScopes();
1089
+ const countResult = await qb.clearOrderBy().select((eb) => eb.fn.countAll().as("total")).executeTakeFirst();
1090
+ const total = Number(countResult?.total ?? 0);
1091
+ const items = await self.limit(safePerPage).offset((safePage - 1) * safePerPage).execute();
1092
+ const { createPaginator } = await Promise.resolve().then(() => pagination_exports);
1093
+ return createPaginator(items, total, safePerPage, safePage);
1094
+ },
1095
+ allowGraph(...expressions) {
1096
+ const paths = /* @__PURE__ */ new Set();
1097
+ for (const expr of expressions) {
1098
+ const parts = expr.replace(/[[\]']/g, "").split(/[\s,]+/).filter(Boolean);
1099
+ for (const part of parts) paths.add(part);
1100
+ }
1101
+ allowedGraphSet = paths;
1102
+ return self;
1103
+ },
1104
+ with(...relations) {
1105
+ for (const rel of relations) if (typeof rel === "string") {
1106
+ if (allowedGraphSet && !isRelationAllowed(rel, allowedGraphSet)) throw new RelationNotAllowedError(def.name, rel);
1107
+ eagerLoads.push({ name: rel });
1108
+ } else for (const [name, constraints] of Object.entries(rel)) {
1109
+ if (allowedGraphSet && !isRelationAllowed(name, allowedGraphSet)) throw new RelationNotAllowedError(def.name, name);
1110
+ eagerLoads.push({
1111
+ name,
1112
+ constraints
1113
+ });
1114
+ }
1115
+ return self;
1116
+ },
1117
+ async insertGraph(data, options) {
1118
+ const { insertGraph: doInsertGraph } = await Promise.resolve().then(() => graph_exports);
1119
+ return doInsertGraph(def, data, {
1120
+ ...options,
1121
+ allowGraph: allowedGraphSet ? [...allowedGraphSet] : options?.allowGraph
1122
+ });
1123
+ },
1124
+ async upsertGraph(data, options) {
1125
+ const { upsertGraph: doUpsertGraph } = await Promise.resolve().then(() => graph_exports);
1126
+ return doUpsertGraph(def, data, {
1127
+ ...options,
1128
+ allowGraph: allowedGraphSet ? [...allowedGraphSet] : options?.allowGraph
1129
+ });
1130
+ },
1131
+ async updateMany(data) {
1132
+ applyScopes();
1133
+ assertWhereForMutation();
1134
+ const { hasStaticHooks, getStaticHooks } = await Promise.resolve().then(() => static_exports);
1135
+ if (hasStaticHooks(def, "beforeUpdate")) {
1136
+ const hooks = getStaticHooks(def, "beforeUpdate");
1137
+ let cancelled = false;
1138
+ let cancelResult;
1139
+ const asFindQuery = () => {
1140
+ const selectQb = createQueryBuilder(def);
1141
+ for (const op of whereOps) op(selectQb);
1142
+ return selectQb;
1143
+ };
1144
+ const cancelQuery = (result) => {
1145
+ cancelled = true;
1146
+ cancelResult = result;
1147
+ };
1148
+ for (const hook of hooks) await hook({
1149
+ asFindQuery,
1150
+ cancelQuery,
1151
+ inputItems: [data]
1152
+ });
1153
+ if (cancelled) return cancelResult;
1154
+ }
1155
+ let updateQb = db.updateTable(def.table).set(data);
1156
+ for (const op of whereOps) updateQb = op(updateQb);
1157
+ try {
1158
+ const result = await updateQb.execute();
1159
+ return Number(result.numUpdatedRows ?? 0);
1160
+ } catch (e) {
1161
+ const { normalizeError } = await import("./errors-sfFJolfu.mjs").then((n) => n.t);
1162
+ throw normalizeError(e, def.table);
1163
+ }
1164
+ },
1165
+ async deleteMany() {
1166
+ applyScopes();
1167
+ assertWhereForMutation();
1168
+ const { hasStaticHooks, getStaticHooks } = await Promise.resolve().then(() => static_exports);
1169
+ const hasBefore = hasStaticHooks(def, "beforeDelete");
1170
+ const hasAfter = hasStaticHooks(def, "afterDelete");
1171
+ if (hasBefore) {
1172
+ const hooks = getStaticHooks(def, "beforeDelete");
1173
+ let cancelled = false;
1174
+ let cancelResult;
1175
+ const asFindQuery = () => {
1176
+ const selectQb = createQueryBuilder(def);
1177
+ for (const op of whereOps) op(selectQb);
1178
+ return selectQb;
1179
+ };
1180
+ const cancelQuery = (result) => {
1181
+ cancelled = true;
1182
+ cancelResult = result;
1183
+ };
1184
+ for (const hook of hooks) await hook({
1185
+ asFindQuery,
1186
+ cancelQuery,
1187
+ inputItems: void 0
1188
+ });
1189
+ if (cancelled) return cancelResult;
1190
+ }
1191
+ let deletedRows = [];
1192
+ if (hasAfter) {
1193
+ const previewQb = createQueryBuilder(def);
1194
+ for (const op of whereOps) op(previewQb);
1195
+ deletedRows = await previewQb.execute();
1196
+ }
1197
+ let deleteQb = db.deleteFrom(def.table);
1198
+ for (const op of whereOps) deleteQb = op(deleteQb);
1199
+ let numDeleted = 0;
1200
+ try {
1201
+ const result = await deleteQb.execute();
1202
+ numDeleted = Number(result.numDeletedRows ?? 0);
1203
+ } catch (e) {
1204
+ const { normalizeError } = await import("./errors-sfFJolfu.mjs").then((n) => n.t);
1205
+ throw normalizeError(e, def.table);
1206
+ }
1207
+ if (hasAfter && deletedRows.length > 0) {
1208
+ const hooks = getStaticHooks(def, "afterDelete");
1209
+ const afterAsFindQuery = () => {
1210
+ const selectQb = createQueryBuilder(def);
1211
+ for (const op of whereOps) op(selectQb);
1212
+ return selectQb;
1213
+ };
1214
+ for (const hook of hooks) await hook({
1215
+ asFindQuery: afterAsFindQuery,
1216
+ cancelQuery: () => {},
1217
+ inputItems: void 0
1218
+ });
1219
+ }
1220
+ return numDeleted;
1221
+ },
1222
+ withTrashed() {
1223
+ withTrashed = true;
1224
+ return self;
1225
+ },
1226
+ onlyTrashed() {
1227
+ onlyTrashedMode = true;
1228
+ withTrashed = false;
1229
+ return self;
1230
+ },
1231
+ whereIn(column, values) {
1232
+ qb = qb.where(validateColumn(column), "in", values);
1233
+ whereOps.push((q) => q.where(validateColumn(column), "in", values));
1234
+ hasEffectiveWhere = values.length > 0;
1235
+ return self;
1236
+ },
1237
+ whereInPivot(column, values) {
1238
+ qb = qb.where(validateColumn(column), "in", values);
1239
+ whereOps.push((q) => q.where(validateColumn(column), "in", values));
1240
+ hasEffectiveWhere = values.length > 0;
1241
+ return self;
1242
+ },
1243
+ has(relationName) {
1244
+ const rel = def.relations[relationName];
1245
+ if (!rel) throw new RelationNotFoundError(def.name, relationName);
1246
+ const relatedTable = rel.relatedModelClass.table;
1247
+ const fk = rel.foreignKey;
1248
+ const lk = rel.localKey;
1249
+ const existsExpr = rawSql(`EXISTS (SELECT 1 FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk})`);
1250
+ qb = qb.where(existsExpr);
1251
+ hasEffectiveWhere = true;
1252
+ return self;
1253
+ },
1254
+ whereHas(relationName, _callback) {
1255
+ return self.has(relationName);
1256
+ },
1257
+ whereDoesntHave(relationName, _callback) {
1258
+ const rel = def.relations[relationName];
1259
+ if (!rel) throw new RelationNotFoundError(def.name, relationName);
1260
+ const relatedTable = rel.relatedModelClass.table;
1261
+ const fk = rel.foreignKey;
1262
+ const lk = rel.localKey;
1263
+ const notExistsExpr = rawSql(`NOT EXISTS (SELECT 1 FROM ${relatedTable} WHERE ${relatedTable}.${fk} = ${def.table}.${lk})`);
1264
+ qb = qb.where(notExistsExpr);
1265
+ hasEffectiveWhere = true;
1266
+ return self;
1267
+ },
1268
+ where(column, operator, value) {
1269
+ if (value === void 0) {
1270
+ qb = qb.where(validateColumn(column), "=", operator);
1271
+ whereOps.push((q) => q.where(validateColumn(column), "=", operator));
1272
+ hasEffectiveWhere = true;
1273
+ } else {
1274
+ qb = qb.where(validateColumn(column), operator, value);
1275
+ whereOps.push((q) => q.where(validateColumn(column), operator, value));
1276
+ hasEffectiveWhere = true;
1277
+ }
1278
+ return self;
1279
+ },
1280
+ whereRef(col1, operator, col2) {
1281
+ qb = qb.whereRef(validateColumn(col1), operator, validateColumn(col2));
1282
+ whereOps.push((q) => q.whereRef(validateColumn(col1), operator, validateColumn(col2)));
1283
+ hasEffectiveWhere = true;
1284
+ return self;
1285
+ },
1286
+ orWhere(column, operator, value) {
1287
+ if (value === void 0) {
1288
+ qb = qb.orWhere(validateColumn(column), "=", operator);
1289
+ whereOps.push((q) => q.orWhere(validateColumn(column), "=", operator));
1290
+ } else {
1291
+ qb = qb.orWhere(validateColumn(column), operator, value);
1292
+ whereOps.push((q) => q.orWhere(validateColumn(column), operator, value));
1293
+ }
1294
+ hasEffectiveWhere = true;
1295
+ return self;
1296
+ },
1297
+ orderBy(column, direction = "asc") {
1298
+ qb = qb.orderBy(validateColumn(column), direction);
1299
+ return self;
1300
+ },
1301
+ limit(n) {
1302
+ qb = qb.limit(n);
1303
+ return self;
1304
+ },
1305
+ offset(n) {
1306
+ qb = qb.offset(n);
1307
+ return self;
1308
+ },
1309
+ select(...columns) {
1310
+ selectedColumns = columns;
1311
+ return self;
1312
+ },
1313
+ selectAll(_table) {
1314
+ selectedColumns = null;
1315
+ return self;
1316
+ },
1317
+ innerJoin(table, lhs, rhs) {
1318
+ qb = qb.innerJoin(table, (join) => join.onRef(lhs, "=", rhs));
1319
+ return self;
1320
+ },
1321
+ leftJoin(table, lhs, rhs) {
1322
+ qb = qb.leftJoin(table, (join) => join.onRef(lhs, "=", rhs));
1323
+ return self;
1324
+ },
1325
+ groupBy(...columns) {
1326
+ qb = qb.groupBy(columns.map(validateColumn));
1327
+ return self;
1328
+ },
1329
+ having(column, operator, value) {
1330
+ qb = qb.having(validateColumn(column), operator, value);
1331
+ hasEffectiveWhere = true;
1332
+ return self;
1333
+ },
1334
+ withoutGlobalScope(name) {
1335
+ omitScopes.add(name);
1336
+ return self;
1337
+ },
1338
+ all() {
1339
+ hasAll = true;
1340
+ return self;
1341
+ },
1342
+ when(condition, callback) {
1343
+ if (condition) return callback(self);
1344
+ return self;
1345
+ },
1346
+ unless(condition, callback) {
1347
+ if (!condition) return callback(self);
1348
+ return self;
1349
+ },
1350
+ _getKyselyQb() {
1351
+ return qb;
1352
+ },
1353
+ _replaceKyselyQb(newQb) {
1354
+ qb = newQb;
1355
+ }
1356
+ };
1357
+ return self;
1358
+ }
1359
+ //#endregion
1360
+ //#region src/model/scopes.ts
1361
+ const globalScopes = /* @__PURE__ */ new WeakMap();
1362
+ function addScope(def, name, callback) {
1363
+ let scopes = globalScopes.get(def);
1364
+ if (!scopes) {
1365
+ scopes = /* @__PURE__ */ new Map();
1366
+ globalScopes.set(def, scopes);
1367
+ }
1368
+ scopes.set(name, callback);
1369
+ }
1370
+ function removeScope(def, name) {
1371
+ globalScopes.get(def)?.delete(name);
1372
+ }
1373
+ function getScopes(def) {
1374
+ return globalScopes.get(def);
1375
+ }
1376
+ //#endregion
1377
+ //#region src/model/define.ts
1378
+ function defineModel(table, config) {
1379
+ const def = {
1380
+ table,
1381
+ columns: config.columns,
1382
+ relations: config.relations ?? {},
1383
+ name: table,
1384
+ _orm: null,
1385
+ query() {
1386
+ if (!this._orm) throw new ModelNotRegisteredError(this.name);
1387
+ return createQueryBuilder(this);
1388
+ },
1389
+ async find(id) {
1390
+ return this.query().find(id);
1391
+ },
1392
+ async findOrFail(id) {
1393
+ return this.query().findOrFail(id);
1394
+ },
1395
+ async first() {
1396
+ return this.query().first();
1397
+ },
1398
+ async create(data) {
1399
+ return (await import("./save-B8rudcT5.mjs").then((n) => n.i)).insertModel(def, data);
1400
+ },
1401
+ async insert(data) {
1402
+ return (await import("./save-B8rudcT5.mjs").then((n) => n.i)).insertModel(def, data);
1403
+ },
1404
+ async insertMany(dataArray) {
1405
+ return (await import("./save-B8rudcT5.mjs").then((n) => n.i)).insertManyModel(def, dataArray);
1406
+ },
1407
+ async update(id, data) {
1408
+ return (await import("./save-B8rudcT5.mjs").then((n) => n.i)).updateModel(def, id, data);
1409
+ },
1410
+ async insertGraph(data, options) {
1411
+ return (await Promise.resolve().then(() => graph_exports)).insertGraph(def, data, options);
1412
+ },
1413
+ async upsertGraph(data, options) {
1414
+ return (await Promise.resolve().then(() => graph_exports)).upsertGraph(def, data, options);
1415
+ },
1416
+ async delete(id) {
1417
+ const model = await this.findOrFail(id);
1418
+ await (await Promise.resolve().then(() => delete_exports)).deleteModel(def, model);
1419
+ },
1420
+ hydrate(row) {
1421
+ return createInstance(def, config, row, true);
1422
+ },
1423
+ on(event, callback) {
1424
+ return getHooksFor(def).on(event, callback);
1425
+ },
1426
+ use(plugin) {
1427
+ plugin(def);
1428
+ return def;
1429
+ },
1430
+ makeHelper(fn) {
1431
+ return (...args) => {
1432
+ return fn(def.query(), ...args);
1433
+ };
1434
+ },
1435
+ getHooks() {
1436
+ return getHooksFor(def);
1437
+ },
1438
+ addGlobalScope(name, callback) {
1439
+ addScope(def, name, callback);
1440
+ },
1441
+ removeGlobalScope(name) {
1442
+ removeScope(def, name);
1443
+ },
1444
+ getGlobalScopes() {
1445
+ return getScopes(def);
1446
+ },
1447
+ beforeDelete(callback) {
1448
+ return addStaticHook(def, "beforeDelete", callback);
1449
+ },
1450
+ afterDelete(callback) {
1451
+ return addStaticHook(def, "afterDelete", callback);
1452
+ },
1453
+ beforeUpdate(callback) {
1454
+ return addStaticHook(def, "beforeUpdate", callback);
1455
+ },
1456
+ afterUpdate(callback) {
1457
+ return addStaticHook(def, "afterUpdate", callback);
1458
+ },
1459
+ beforeCreate(callback) {
1460
+ return addStaticHook(def, "beforeCreate", callback);
1461
+ },
1462
+ afterCreate(callback) {
1463
+ return addStaticHook(def, "afterCreate", callback);
1464
+ },
1465
+ beforeFind(callback) {
1466
+ return addStaticHook(def, "beforeFind", callback);
1467
+ },
1468
+ afterFind(callback) {
1469
+ return addStaticHook(def, "afterFind", callback);
1470
+ },
1471
+ _init(orm) {
1472
+ def._orm = orm;
1473
+ setConfig$1(def, config);
1474
+ Promise.resolve().then(() => serialize_exports).then((mod) => mod.setConfig?.(def, config));
1475
+ }
1476
+ };
1477
+ setConfig$1(def, config);
1478
+ Promise.resolve().then(() => serialize_exports).then((mod) => mod.setConfig?.(def, config));
1479
+ if (config.computed) Promise.resolve().then(() => computed_exports).then((mod) => mod.setComputedConfig?.(def, config.computed));
1480
+ def.registerTimestamps = (createdAtCol, updatedAtCol) => {
1481
+ registerTimestampsFor(def, createdAtCol, updatedAtCol);
1482
+ };
1483
+ def.registerSoftDeletes = (deletedAtCol) => {
1484
+ registerSoftDeletesFor(def, deletedAtCol);
1485
+ };
1486
+ def.discover = async () => {
1487
+ throw new Error("discover() not yet implemented in v2");
1488
+ };
1489
+ return def;
1490
+ }
1491
+ //#endregion
1492
+ //#region src/model/attribute.ts
1493
+ /**
1494
+ * Defines an accessor (`get`) and/or mutator (`set`) for a model attribute.
1495
+ *
1496
+ * ### Accessor (get)
1497
+ * Transforms the attribute value when read via `model.get()` or `model.$toJSON()`.
1498
+ * Receives the casted value and the model instance.
1499
+ *
1500
+ * ### Mutator (set)
1501
+ * Transforms the attribute value when written via `model.set()`, `model.fill()`,
1502
+ * or during model creation (`Model.insert()` / `Model.create()`).
1503
+ * Receives the raw input value and the model instance, returns the value to store.
1504
+ * Applied **before** type casting.
1505
+ *
1506
+ * ### Usage
1507
+ * ```ts
1508
+ * defineModel('users', {
1509
+ * columns: { id, name, password, ... },
1510
+ * attributes: {
1511
+ * password: Attribute.make({
1512
+ * set: (value) => Bun.password.hashSync(value, { algorithm: 'bcrypt' }),
1513
+ * get: () => '***',
1514
+ * }),
1515
+ * fullName: Attribute.make({
1516
+ * get: (_, instance) => `${instance.get('firstName')} ${instance.get('lastName')}`,
1517
+ * }),
1518
+ * },
1519
+ * })
1520
+ * ```
1521
+ */
1522
+ var Attribute = class Attribute {
1523
+ get;
1524
+ set;
1525
+ constructor(get, set) {
1526
+ this.get = get;
1527
+ this.set = set;
1528
+ }
1529
+ static make(config) {
1530
+ if (!config.get && !config.set) throw new Error("Attribute.make() requires at least one of `get` or `set`");
1531
+ return new Attribute(config.get, config.set);
1532
+ }
1533
+ };
1534
+ //#endregion
1535
+ //#region src/model/computed.ts
1536
+ var computed_exports = /* @__PURE__ */ __exportAll({
1537
+ applyComputedColumnsAsync: () => applyComputedColumnsAsync,
1538
+ getComputedConfig: () => getComputedConfig,
1539
+ setComputedConfig: () => setComputedConfig
1540
+ });
1541
+ const computedConfigs = /* @__PURE__ */ new WeakMap();
1542
+ function setComputedConfig(def, config) {
1543
+ computedConfigs.set(def, config);
1544
+ }
1545
+ function getComputedConfig(def) {
1546
+ return computedConfigs.get(def);
1547
+ }
1548
+ /**
1549
+ * Apply computed columns to a set of loaded records.
1550
+ * Handles SQL, runtime, and batch computed columns.
1551
+ */
1552
+ /** Resolve a ComputedConfig entry (lazy function or plain object). */
1553
+ function resolveComputedColumn(entry) {
1554
+ return typeof entry === "function" ? entry() : entry;
1555
+ }
1556
+ /**
1557
+ * Apply computed columns and return a promise (for async batch computes).
1558
+ */
1559
+ async function applyComputedColumnsAsync(records, computedConfig, selectedColumns) {
1560
+ if (records.length === 0) return;
1561
+ const relevant = Object.entries(computedConfig).filter(([name]) => !selectedColumns || selectedColumns.includes(name));
1562
+ const batchDefs = relevant.filter(([, c]) => resolveComputedColumn(c).type === "batch");
1563
+ for (const [name, col] of batchDefs) if (col.batchCompute) {
1564
+ const values = await col.batchCompute(records);
1565
+ for (let i = 0; i < records.length && i < values.length; i++) records[i].set(name, values[i]);
1566
+ }
1567
+ for (const record of records) for (const [name, c] of relevant) {
1568
+ const col = resolveComputedColumn(c);
1569
+ if (col.type === "runtime" && col.compute) record.set(name, col.compute(record));
1570
+ }
1571
+ }
1572
+ //#endregion
1573
+ //#region src/model/delete.ts
1574
+ var delete_exports = /* @__PURE__ */ __exportAll({
1575
+ deleteModel: () => deleteModel,
1576
+ forceDeleteModel: () => forceDeleteModel,
1577
+ restoreModel: () => restoreModel,
1578
+ trashedModel: () => trashedModel
1579
+ });
1580
+ function getTable(def) {
1581
+ return def.table;
1582
+ }
1583
+ function getDb(def) {
1584
+ if (!def._orm) throw new ModelNotRegisteredError(def.name);
1585
+ return def._orm.kysely;
1586
+ }
1587
+ function getPrimaryKeyColumn$1(def) {
1588
+ const cols = def.columns;
1589
+ for (const [name, col] of Object.entries(cols)) if (col.isPrimaryKey) return name;
1590
+ return "id";
1591
+ }
1592
+ async function deleteModel(def, model) {
1593
+ const pk = getPrimaryKeyColumn$1(def);
1594
+ const pkValue = model.get(pk);
1595
+ if (pkValue == null) throw new DatabaseError("Cannot delete model without primary key", "MISSING_ID");
1596
+ const hm = getHooksFor(def);
1597
+ if (hasSoftDelete(def)) {
1598
+ await hm.trigger("beforeDelete", model);
1599
+ const config = getSoftDeleteConfig(def);
1600
+ const db = getDb(def);
1601
+ try {
1602
+ await db.updateTable(getTable(def)).set({ [config.column]: (/* @__PURE__ */ new Date()).toISOString() }).where(pk, "=", pkValue).execute();
1603
+ } catch (e) {
1604
+ throw normalizeError(e, getTable(def));
1605
+ }
1606
+ model.set(config.column, (/* @__PURE__ */ new Date()).toISOString());
1607
+ await hm.trigger("afterDelete", model);
1608
+ } else {
1609
+ await hm.trigger("beforeDelete", model);
1610
+ const db = getDb(def);
1611
+ try {
1612
+ await db.deleteFrom(getTable(def)).where(pk, "=", pkValue).execute();
1613
+ } catch (e) {
1614
+ throw normalizeError(e, getTable(def));
1615
+ }
1616
+ setExists(model, false);
1617
+ await hm.trigger("afterDelete", model);
1618
+ }
1619
+ }
1620
+ async function forceDeleteModel(def, model) {
1621
+ const pk = getPrimaryKeyColumn$1(def);
1622
+ const pkValue = model.get(pk);
1623
+ if (pkValue == null) throw new DatabaseError("Cannot delete model without primary key", "MISSING_ID");
1624
+ const hm = getHooksFor(def);
1625
+ await hm.trigger("beforeForceDelete", model);
1626
+ const db = getDb(def);
1627
+ try {
1628
+ await db.deleteFrom(getTable(def)).where(pk, "=", pkValue).execute();
1629
+ } catch (e) {
1630
+ throw normalizeError(e, getTable(def));
1631
+ }
1632
+ setExists(model, false);
1633
+ await hm.trigger("afterForceDelete", model);
1634
+ }
1635
+ async function restoreModel(def, model) {
1636
+ const pk = getPrimaryKeyColumn$1(def);
1637
+ const pkValue = model.get(pk);
1638
+ if (pkValue == null) return;
1639
+ if (!hasSoftDelete(def)) return;
1640
+ const hm = getHooksFor(def);
1641
+ await hm.trigger("beforeRestore", model);
1642
+ const config = getSoftDeleteConfig(def);
1643
+ const db = getDb(def);
1644
+ try {
1645
+ await db.updateTable(getTable(def)).set({ [config.column]: null }).where(pk, "=", pkValue).execute();
1646
+ } catch (e) {
1647
+ throw normalizeError(e, getTable(def));
1648
+ }
1649
+ model.set(config.column, null);
1650
+ setExists(model, true);
1651
+ await hm.trigger("afterRestore", model);
1652
+ }
1653
+ function trashedModel(def, model) {
1654
+ if (!hasSoftDelete(def)) return false;
1655
+ const config = getSoftDeleteConfig(def);
1656
+ return model.get(config.column) != null;
1657
+ }
1658
+ //#endregion
1659
+ //#region src/model/relation.ts
1660
+ var relation_exports = /* @__PURE__ */ __exportAll({
1661
+ getModelDef: () => getModelDef,
1662
+ loadModelRelations: () => loadModelRelations
1663
+ });
1664
+ const modelDefs = /* @__PURE__ */ new WeakMap();
1665
+ function getModelDef(instance) {
1666
+ return modelDefs.get(instance);
1667
+ }
1668
+ async function loadModelRelations(model, def, ...relations) {
1669
+ const { EagerLoader } = await Promise.resolve().then(() => eager_exports);
1670
+ const loader = new EagerLoader();
1671
+ for (const rel of relations) await loader.loadRelatedForModel(model, rel, def);
1672
+ }
1673
+ //#endregion
1674
+ //#region src/model/serialize.ts
1675
+ var serialize_exports = /* @__PURE__ */ __exportAll({
1676
+ getConfig: () => getConfig,
1677
+ modelToJSON: () => modelToJSON,
1678
+ setConfig: () => setConfig
1679
+ });
1680
+ const VISITED = /* @__PURE__ */ new WeakSet();
1681
+ /** Type guard: checks if a value looks like a SerializableModel. */
1682
+ function isSerializableModel(value) {
1683
+ return value !== null && typeof value === "object" && typeof value.$toJSON === "function";
1684
+ }
1685
+ function modelToJSON(def, model) {
1686
+ const config = getConfig$1(def) ?? getConfig(def);
1687
+ const state = getState(model);
1688
+ const result = {};
1689
+ const attributes = state.attributes;
1690
+ const hidden = config?.hidden ?? [];
1691
+ const visible = config?.visible;
1692
+ const appends = config?.appends ?? [];
1693
+ const casts = config?.casts ?? {};
1694
+ const keys = visible && visible.length > 0 ? visible : Object.keys(attributes);
1695
+ for (const key of keys) {
1696
+ if (hidden.includes(key)) continue;
1697
+ if (key in attributes) {
1698
+ let value = attributes[key];
1699
+ if (casts[key]) value = castValue(value, casts[key]);
1700
+ const attrDef = config?.attributes?.[key];
1701
+ if (attrDef?.get) value = attrDef.get(value, model);
1702
+ result[key] = value;
1703
+ }
1704
+ }
1705
+ const relations = getRawRelations(model);
1706
+ for (const [relName, relValue] of Object.entries(relations)) {
1707
+ if (hidden.includes(relName)) continue;
1708
+ if (visible && visible.length > 0 && !visible.includes(relName)) continue;
1709
+ if (Array.isArray(relValue)) result[relName] = relValue.map((item) => {
1710
+ if (isSerializableModel(item)) {
1711
+ if (VISITED.has(item)) return { id: item.get("id") };
1712
+ VISITED.add(item);
1713
+ const json = item.$toJSON();
1714
+ VISITED.delete(item);
1715
+ return json;
1716
+ }
1717
+ return item;
1718
+ });
1719
+ else if (isSerializableModel(relValue)) if (VISITED.has(relValue)) result[relName] = { id: relValue.get("id") };
1720
+ else {
1721
+ VISITED.add(relValue);
1722
+ result[relName] = relValue.$toJSON();
1723
+ VISITED.delete(relValue);
1724
+ }
1725
+ else if (relValue != null) result[relName] = relValue;
1726
+ }
1727
+ for (const append of appends) if (!(append in result)) {
1728
+ const fn = model[`get${append.charAt(0).toUpperCase()}${append.slice(1)}Attribute`];
1729
+ if (typeof fn === "function") result[append] = fn.call(model);
1730
+ }
1731
+ return result;
1732
+ }
1733
+ const configMap = /* @__PURE__ */ new WeakMap();
1734
+ function setConfig(def, config) {
1735
+ configMap.set(def, config);
1736
+ }
1737
+ function getConfig(def) {
1738
+ return configMap.get(def);
1739
+ }
1740
+ //#endregion
1741
+ //#region src/relations/related-query.ts
1742
+ /**
1743
+ * Create a RelationQuery — a QueryBuilder scoped to a relation, with
1744
+ * additional methods for managing many-to-many pivot tables.
1745
+ */
1746
+ function createRelationQuery(instance, def, relationName) {
1747
+ const relation = def.relations[relationName];
1748
+ if (!relation) throw new RelationNotFoundError(def.name, relationName);
1749
+ const relatedDef = relation.relatedModelClass;
1750
+ const qb = createQueryBuilder(relatedDef);
1751
+ if (relation.type === "belongsTo") {
1752
+ const fkValue = instance.get(relation.foreignKey);
1753
+ if (fkValue != null) qb.where(relation.localKey, "=", fkValue);
1754
+ else qb.where(relation.localKey, "=", -1);
1755
+ } else if (relation.type === "manyToMany") {
1756
+ const pkValue = instance.get(relation.localKey);
1757
+ if (pkValue != null && relation.throughTable && relation.foreignPivotKey && relation.relatedPivotKey) {
1758
+ const relatedPk = Object.keys(relatedDef.columns).find((k) => relatedDef.columns[k]?.isPrimaryKey) ?? "id";
1759
+ const t = relation.throughTable;
1760
+ const rpk = relation.relatedPivotKey;
1761
+ const fpk = relation.foreignPivotKey;
1762
+ const newQb = qb._getKyselyQb().where(sql`${sql.id(relatedPk)} IN (SELECT ${sql.id(rpk)} FROM ${sql.id(t)} WHERE ${sql.id(fpk)} = ${pkValue})`);
1763
+ qb._replaceKyselyQb(newQb);
1764
+ } else qb.where(relation.localKey, "=", -1);
1765
+ } else {
1766
+ const fkValue = instance.get(relation.localKey);
1767
+ if (fkValue != null) qb.where(relation.foreignKey, "=", fkValue);
1768
+ else qb.where(relation.foreignKey, "=", -1);
1769
+ }
1770
+ const rqb = Object.create(qb);
1771
+ for (const key of Object.keys(qb)) if (typeof qb[key] === "function") {
1772
+ const fn = qb[key];
1773
+ rqb[key] = (...args) => {
1774
+ const result = fn.apply(qb, args);
1775
+ return result === qb ? rqb : result;
1776
+ };
1777
+ }
1778
+ const pivotRelation = relation;
1779
+ function getPivotInfo() {
1780
+ if (pivotRelation.type !== "manyToMany" || !pivotRelation.throughTable) throw new Error(`attach/detach/sync are only available on manyToMany relations, got "${pivotRelation.type}"`);
1781
+ return {
1782
+ throughTable: pivotRelation.throughTable,
1783
+ foreignPivotKey: pivotRelation.foreignPivotKey ?? "",
1784
+ relatedPivotKey: pivotRelation.relatedPivotKey ?? ""
1785
+ };
1786
+ }
1787
+ rqb.attach = async (ids, pivotData) => {
1788
+ const { throughTable, foreignPivotKey, relatedPivotKey } = getPivotInfo();
1789
+ const pkValue = instance.get(relation.localKey);
1790
+ if (pkValue == null) return;
1791
+ const idsArr = Array.isArray(ids) ? ids : [ids];
1792
+ const _db = relatedDef._orm?.kysely;
1793
+ if (!_db) throw new Error("Model not registered");
1794
+ const qdb = _db;
1795
+ for (const id of idsArr) {
1796
+ const row = {
1797
+ [foreignPivotKey]: pkValue,
1798
+ [relatedPivotKey]: id,
1799
+ ...pivotData
1800
+ };
1801
+ try {
1802
+ await qdb.insertInto(throughTable).values(row).execute();
1803
+ } catch (e) {
1804
+ const err = e;
1805
+ if (!(err.code === "SQLITE_CONSTRAINT_UNIQUE" || err.code === "SQLITE_CONSTRAINT" || err.code === "23505" || err.code === "ER_DUP_ENTRY" || err.errno === 1062)) throw e;
1806
+ }
1807
+ }
1808
+ };
1809
+ rqb.detach = async (ids) => {
1810
+ const { throughTable, foreignPivotKey, relatedPivotKey } = getPivotInfo();
1811
+ const pkValue = instance.get(relation.localKey);
1812
+ if (pkValue == null) return;
1813
+ const _db = relatedDef._orm?.kysely;
1814
+ if (!_db) throw new Error("Model not registered");
1815
+ let query = _db.deleteFrom(throughTable).where(foreignPivotKey, "=", pkValue);
1816
+ if (ids !== void 0) {
1817
+ const idsArr = Array.isArray(ids) ? ids : [ids];
1818
+ query = query.where(relatedPivotKey, "in", idsArr);
1819
+ }
1820
+ await query.execute();
1821
+ };
1822
+ rqb.sync = async (ids) => {
1823
+ const { throughTable, foreignPivotKey, relatedPivotKey } = getPivotInfo();
1824
+ const pkValue = instance.get(relation.localKey);
1825
+ if (pkValue == null) return;
1826
+ const _db = relatedDef._orm?.kysely;
1827
+ if (!_db) throw new Error("Model not registered");
1828
+ const qdb = _db;
1829
+ const desiredIds = Array.isArray(ids) ? ids : Object.keys(ids).map(Number);
1830
+ const currentRows = await qdb.selectFrom(throughTable).select(relatedPivotKey).where(foreignPivotKey, "=", pkValue).execute();
1831
+ const currentIds = new Set(currentRows.map((r) => r[relatedPivotKey]));
1832
+ const toAttach = desiredIds.filter((id) => !currentIds.has(id));
1833
+ const toDetach = [...currentIds].filter((id) => (typeof id === "string" || typeof id === "number") && !desiredIds.includes(id));
1834
+ const ops = [];
1835
+ if (toDetach.length > 0) ops.push(qdb.deleteFrom(throughTable).where(foreignPivotKey, "=", pkValue).where(relatedPivotKey, "in", toDetach).execute());
1836
+ for (const id of toAttach) {
1837
+ const pivotRow = {
1838
+ [foreignPivotKey]: pkValue,
1839
+ [relatedPivotKey]: id
1840
+ };
1841
+ if (!Array.isArray(ids) && typeof ids === "object") {
1842
+ const entry = ids[String(id)];
1843
+ if (entry) Object.assign(pivotRow, entry);
1844
+ }
1845
+ ops.push(qdb.insertInto(throughTable).values(pivotRow).execute());
1846
+ }
1847
+ await Promise.all(ops);
1848
+ };
1849
+ rqb.syncWithoutDetaching = async (ids) => {
1850
+ const { throughTable, foreignPivotKey, relatedPivotKey } = getPivotInfo();
1851
+ const pkValue = instance.get(relation.localKey);
1852
+ if (pkValue == null) return;
1853
+ const _db = relatedDef._orm?.kysely;
1854
+ if (!_db) throw new Error("Model not registered");
1855
+ const qdb = _db;
1856
+ const idsArr = Array.isArray(ids) ? ids : [ids];
1857
+ for (const id of idsArr) {
1858
+ const row = {
1859
+ [foreignPivotKey]: pkValue,
1860
+ [relatedPivotKey]: id
1861
+ };
1862
+ try {
1863
+ await qdb.insertInto(throughTable).values(row).execute();
1864
+ } catch (e) {
1865
+ const err = e;
1866
+ if (!(err.code === "SQLITE_CONSTRAINT_UNIQUE" || err.code === "SQLITE_CONSTRAINT" || err.code === "23505" || err.code === "ER_DUP_ENTRY" || err.errno === 1062)) throw e;
1867
+ }
1868
+ }
1869
+ };
1870
+ rqb.updateExistingPivot = async (id, data) => {
1871
+ const { throughTable, foreignPivotKey, relatedPivotKey } = getPivotInfo();
1872
+ const pkValue = instance.get(relation.localKey);
1873
+ if (pkValue == null) return;
1874
+ const _db = relatedDef._orm?.kysely;
1875
+ if (!_db) throw new Error("Model not registered");
1876
+ await _db.updateTable(throughTable).set(data).where(foreignPivotKey, "=", pkValue).where(relatedPivotKey, "=", id).execute();
1877
+ };
1878
+ return rqb;
1879
+ }
1880
+ //#endregion
1881
+ //#region src/model/index.ts
1882
+ initRuntime({
1883
+ saveModel,
1884
+ deleteModel,
1885
+ forceDeleteModel,
1886
+ restoreModel,
1887
+ trashedModel,
1888
+ reloadModel,
1889
+ modelToJSON,
1890
+ loadModelRelations,
1891
+ createRelationQuery
1892
+ });
1893
+ //#endregion
1894
+ //#region src/orm/index.ts
1895
+ /**
1896
+ * Create an ORM instance — the central registry that wires Kysely to model definitions.
1897
+ * Replaces createPeta() from v0.x.
1898
+ */
1899
+ function createORM(config) {
1900
+ const kysely = new Kysely({ dialect: config.dialect });
1901
+ const modelMap = /* @__PURE__ */ new Map();
1902
+ const orm = {
1903
+ kysely,
1904
+ register(model) {
1905
+ model._init(orm);
1906
+ modelMap.set(model.name, model);
1907
+ },
1908
+ registerAll(...models) {
1909
+ const flat = models.flat();
1910
+ for (const model of flat) {
1911
+ if (!model.table) continue;
1912
+ this.register(model);
1913
+ }
1914
+ },
1915
+ async destroy() {
1916
+ await kysely.destroy();
1917
+ },
1918
+ async transaction(fn) {
1919
+ return kysely.transaction().execute((trx) => fn(trx));
1920
+ },
1921
+ get models() {
1922
+ return modelMap;
1923
+ },
1924
+ getModel(name) {
1925
+ return modelMap.get(name);
1926
+ }
1927
+ };
1928
+ if (config.models) for (const [_name, model] of Object.entries(config.models)) orm.register(model);
1929
+ return orm;
1930
+ }
1931
+ //#endregion
1932
+ //#region src/pagination/index.ts
1933
+ var pagination_exports = /* @__PURE__ */ __exportAll({ createPaginator: () => createPaginator });
1934
+ function createPaginator(items, total, perPage, currentPage) {
1935
+ const collection = createCollection(items);
1936
+ const lastPage = Math.max(1, Math.ceil(total / perPage));
1937
+ return {
1938
+ get data() {
1939
+ return collection;
1940
+ },
1941
+ get total() {
1942
+ return total;
1943
+ },
1944
+ get perPage() {
1945
+ return perPage;
1946
+ },
1947
+ get currentPage() {
1948
+ return currentPage;
1949
+ },
1950
+ get lastPage() {
1951
+ return lastPage;
1952
+ },
1953
+ get hasMorePages() {
1954
+ return currentPage < lastPage;
1955
+ },
1956
+ get hasPages() {
1957
+ return lastPage > 1;
1958
+ },
1959
+ get firstItem() {
1960
+ return items.length > 0 ? (currentPage - 1) * perPage + 1 : 0;
1961
+ },
1962
+ get lastItem() {
1963
+ return items.length > 0 ? (currentPage - 1) * perPage + items.length : 0;
1964
+ },
1965
+ get onFirstPage() {
1966
+ return currentPage === 1;
1967
+ },
1968
+ get onLastPage() {
1969
+ return currentPage >= lastPage;
1970
+ },
1971
+ get count() {
1972
+ return items.length;
1973
+ },
1974
+ map(fn) {
1975
+ return items.map(fn);
1976
+ },
1977
+ toJSON() {
1978
+ return {
1979
+ data: collection.toJSON(),
1980
+ total,
1981
+ perPage,
1982
+ currentPage,
1983
+ lastPage,
1984
+ hasMorePages: currentPage < lastPage,
1985
+ hasPages: lastPage > 1,
1986
+ firstItem: items.length > 0 ? (currentPage - 1) * perPage + 1 : null,
1987
+ lastItem: items.length > 0 ? (currentPage - 1) * perPage + items.length : null,
1988
+ onFirstPage: currentPage === 1,
1989
+ onLastPage: currentPage >= lastPage
1990
+ };
1991
+ }
1992
+ };
1993
+ }
1994
+ //#endregion
1995
+ //#region src/plugins/soft-deletes.ts
1996
+ let _hooksMod = null;
1997
+ async function getHooksMod() {
1998
+ if (!_hooksMod) _hooksMod = await import("./hooks-BD0xy7uw.mjs").then((n) => n.i);
1999
+ return _hooksMod;
2000
+ }
2001
+ /**
2002
+ * Plugin that enables soft-delete behavior on a model.
2003
+ * Sets `deletedAt` on delete, automatically filters out deleted records.
2004
+ *
2005
+ * ```ts
2006
+ * const User = defineModel('users', {
2007
+ * columns: { deletedAt: t.timestamp().nullable() }
2008
+ * }).use(softDeletes())
2009
+ * ```
2010
+ */
2011
+ function softDeletes(opts) {
2012
+ const column = opts?.column ?? "deletedAt";
2013
+ return (def) => {
2014
+ getHooksMod().then((mod) => mod.registerSoftDeletesFor(def, column));
2015
+ def.on("beforeDelete", async (model) => {
2016
+ const pk = getPrimaryKeyColumn(def);
2017
+ const pkValue = model.get(pk);
2018
+ if (pkValue == null) return;
2019
+ const db = def._orm?.kysely;
2020
+ if (!db) return;
2021
+ try {
2022
+ await db.updateTable(def.table).set({ [column]: (/* @__PURE__ */ new Date()).toISOString() }).where(pk, "=", pkValue).execute();
2023
+ } catch {}
2024
+ });
2025
+ };
2026
+ }
2027
+ function getPrimaryKeyColumn(def) {
2028
+ const cols = def.columns;
2029
+ for (const [name, col] of Object.entries(cols)) if (col.isPrimaryKey) return name;
2030
+ return "id";
2031
+ }
2032
+ //#endregion
2033
+ //#region src/plugins/timestamps.ts
2034
+ /**
2035
+ * Plugin that automatically sets `createdAt` and `updatedAt` timestamps.
2036
+ *
2037
+ * ```ts
2038
+ * const User = defineModel('users', { columns: { ...t.timestamps() } })
2039
+ * .use(timestamps())
2040
+ * ```
2041
+ */
2042
+ function timestamps(opts) {
2043
+ const createdAtCol = opts?.createdAt ?? "createdAt";
2044
+ const updatedAtCol = opts?.updatedAt ?? "updatedAt";
2045
+ return (def) => {
2046
+ def.on("beforeCreate", (model) => {
2047
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2048
+ if (!model.get(createdAtCol)) model.set(createdAtCol, now);
2049
+ model.set(updatedAtCol, now);
2050
+ });
2051
+ def.on("beforeUpdate", (model) => {
2052
+ model.set(updatedAtCol, (/* @__PURE__ */ new Date()).toISOString());
2053
+ });
2054
+ };
2055
+ }
2056
+ //#endregion
2057
+ //#region src/plugins/ulid.ts
2058
+ /**
2059
+ * Plugin that auto-generates ULID primary keys on `beforeCreate`.
2060
+ *
2061
+ * Requires the model's `id` column to be `t.string(26).primaryKey()`.
2062
+ *
2063
+ * @example
2064
+ * ```ts
2065
+ * const User = defineModel("users", {
2066
+ * columns: { id: t.string(26).primaryKey() }
2067
+ * }).use(ulid())
2068
+ * ```
2069
+ */
2070
+ function ulid() {
2071
+ return (def) => {
2072
+ def.on("beforeCreate", (model) => {
2073
+ if (!model.get("id")) model.set("id", ulid$1());
2074
+ });
2075
+ };
2076
+ }
2077
+ //#endregion
2078
+ //#region src/relations/has-many.ts
2079
+ const THUNK_CACHE$2 = /* @__PURE__ */ new WeakMap();
2080
+ function resolveThunk$2(thunk) {
2081
+ let cls = THUNK_CACHE$2.get(thunk);
2082
+ if (!cls) {
2083
+ cls = thunk();
2084
+ THUNK_CACHE$2.set(thunk, cls);
2085
+ }
2086
+ return cls;
2087
+ }
2088
+ function guessForeignKey(modelDef) {
2089
+ const table = modelDef.table;
2090
+ return `${table.endsWith("s") ? table.slice(0, -1) : table}Id`;
2091
+ }
2092
+ function groupByArray$1(items, key) {
2093
+ const result = {};
2094
+ for (const item of items) {
2095
+ const v = item.get(key);
2096
+ if (v == null) continue;
2097
+ const k = String(v);
2098
+ if (!result[k]) result[k] = [];
2099
+ result[k].push(item);
2100
+ }
2101
+ return result;
2102
+ }
2103
+ function hasMany(relatedThunk, options = {}) {
2104
+ let _related;
2105
+ function getRelated() {
2106
+ if (!_related) _related = resolveThunk$2(relatedThunk) ?? void 0;
2107
+ if (!_related) throw new Error(`Cannot resolve hasMany relation — related model not found`);
2108
+ return _related;
2109
+ }
2110
+ const foreignKey = options.foreignKey ?? "";
2111
+ const localKey = options.localKey ?? "id";
2112
+ return {
2113
+ type: "hasMany",
2114
+ get relatedModelClass() {
2115
+ return getRelated();
2116
+ },
2117
+ foreignKey,
2118
+ localKey,
2119
+ get throughTable() {},
2120
+ get foreignPivotKey() {},
2121
+ get relatedPivotKey() {},
2122
+ get throughForeignKey() {},
2123
+ get throughLocalKey() {},
2124
+ query(parent) {
2125
+ const qb = createQueryBuilder(getRelated());
2126
+ const fkValue = parent.get(localKey);
2127
+ if (fkValue != null) qb.where(foreignKey, "=", fkValue);
2128
+ else qb.where(foreignKey, "=", -1);
2129
+ return qb;
2130
+ },
2131
+ addEagerConstraints(qb, models) {
2132
+ const ids = models.map((m) => m.get(localKey)).filter((id) => id != null);
2133
+ if (ids.length > 0) qb.whereIn(foreignKey, ids);
2134
+ else qb.where(foreignKey, "=", -1);
2135
+ },
2136
+ match(models, results, relationName) {
2137
+ const grouped = groupByArray$1(results, foreignKey);
2138
+ for (const model of models) {
2139
+ const key = String(model.get(localKey));
2140
+ model.$setRelation(relationName, grouped[key] ?? []);
2141
+ }
2142
+ },
2143
+ async getResults(parent) {
2144
+ return this.query(parent).execute();
2145
+ },
2146
+ async loadEager(models, relationName, constraints) {
2147
+ const rel = getRelated();
2148
+ if (models.length === 0) return;
2149
+ const qb = createQueryBuilder(rel);
2150
+ this.addEagerConstraints(qb, models);
2151
+ if (constraints) constraints(qb);
2152
+ const results = await qb.execute();
2153
+ this.match(models, results, relationName);
2154
+ }
2155
+ };
2156
+ }
2157
+ function hasOne(relatedThunk, options = {}) {
2158
+ const base = hasMany(relatedThunk, options);
2159
+ const result = {};
2160
+ for (const key of Object.keys(base)) Object.defineProperty(result, key, Object.getOwnPropertyDescriptor(base, key));
2161
+ result.match = function match(models, results, relationName) {
2162
+ const grouped = groupByArray$1(results, base.foreignKey);
2163
+ for (const model of models) {
2164
+ const key = String(model.get(base.localKey));
2165
+ model.$setRelation(relationName, (grouped[key] ?? [])[0] ?? null);
2166
+ }
2167
+ };
2168
+ result.getResults = async function getResults(parent) {
2169
+ return (await base.getResults(parent))[0] ?? null;
2170
+ };
2171
+ return result;
2172
+ }
2173
+ function belongsTo(relatedThunk, options = {}) {
2174
+ const related = resolveThunk$2(relatedThunk);
2175
+ const foreignKey = options.foreignKey ?? guessForeignKey(related);
2176
+ const localKey = options.localKey ?? "id";
2177
+ return {
2178
+ type: "belongsTo",
2179
+ relatedModelClass: related,
2180
+ foreignKey,
2181
+ localKey,
2182
+ get throughTable() {},
2183
+ get foreignPivotKey() {},
2184
+ get relatedPivotKey() {},
2185
+ get throughForeignKey() {},
2186
+ get throughLocalKey() {},
2187
+ query(parent) {
2188
+ const qb = createQueryBuilder(related);
2189
+ const fkValue = parent.get(foreignKey);
2190
+ if (fkValue != null) qb.where(localKey, "=", fkValue);
2191
+ else qb.where(localKey, "=", -1);
2192
+ return qb;
2193
+ },
2194
+ addEagerConstraints(qb, models) {
2195
+ const ids = models.map((m) => m.get(foreignKey)).filter((id) => id != null);
2196
+ if (ids.length > 0) qb.whereIn(localKey, ids);
2197
+ else qb.where(localKey, "=", -1);
2198
+ },
2199
+ match(models, results, relationName) {
2200
+ const keyed = Object.fromEntries(results.map((r) => [String(r.get(localKey)), r]));
2201
+ for (const model of models) {
2202
+ const fkValue = model.get(foreignKey);
2203
+ model.$setRelation(relationName, fkValue != null ? keyed[String(fkValue)] ?? null : null);
2204
+ }
2205
+ },
2206
+ async getResults(parent) {
2207
+ return (await this.query(parent).execute())[0] ?? null;
2208
+ },
2209
+ async loadEager(models, relationName, constraints) {
2210
+ if (models.length === 0) return;
2211
+ const qb = createQueryBuilder(related);
2212
+ this.addEagerConstraints(qb, models);
2213
+ if (constraints) constraints(qb);
2214
+ const results = await qb.execute();
2215
+ this.match(models, results, relationName);
2216
+ }
2217
+ };
2218
+ }
2219
+ //#endregion
2220
+ //#region src/relations/many-to-many.ts
2221
+ const THUNK_CACHE$1 = /* @__PURE__ */ new WeakMap();
2222
+ /** Stores pivot data for many-to-many relation results (instead of attaching to the model). */
2223
+ const pivotData = /* @__PURE__ */ new WeakMap();
2224
+ function resolveThunk$1(thunk) {
2225
+ let cls = THUNK_CACHE$1.get(thunk);
2226
+ if (!cls) {
2227
+ cls = thunk();
2228
+ THUNK_CACHE$1.set(thunk, cls);
2229
+ }
2230
+ return cls;
2231
+ }
2232
+ function snakeCase(str) {
2233
+ return str.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`).replace(/^_/, "");
2234
+ }
2235
+ function manyToMany(relatedThunk, options) {
2236
+ let _related;
2237
+ function getRelated() {
2238
+ if (!_related) _related = resolveThunk$1(relatedThunk) ?? void 0;
2239
+ if (!_related) throw new Error(`Cannot resolve manyToMany relation — related model not found`);
2240
+ return _related;
2241
+ }
2242
+ const localKey = options.localKey ?? "id";
2243
+ const throughTable = options.through ?? "";
2244
+ let _table;
2245
+ try {
2246
+ _table = getRelated().table;
2247
+ } catch {}
2248
+ const foreignKey = options.foreignKey ?? (_table ? `${snakeCase(_table)}Id` : "");
2249
+ const foreignPivotKey = options.foreignPivotKey ?? (_table ? `${snakeCase(_table)}Id` : "");
2250
+ const relatedPivotKey = options.relatedPivotKey ?? (_table ? `${snakeCase(_table)}Id` : "");
2251
+ const pivotExtras = options.pivotExtras ?? [];
2252
+ return {
2253
+ type: "manyToMany",
2254
+ get relatedModelClass() {
2255
+ return getRelated();
2256
+ },
2257
+ foreignKey,
2258
+ localKey,
2259
+ throughTable,
2260
+ foreignPivotKey,
2261
+ relatedPivotKey,
2262
+ get throughForeignKey() {},
2263
+ get throughLocalKey() {},
2264
+ query(parent) {
2265
+ const rel = getRelated();
2266
+ const pkValue = parent.get(localKey);
2267
+ const qb = createQueryBuilder(rel);
2268
+ if (pkValue == null) {
2269
+ qb.where(localKey, "=", -1);
2270
+ return qb;
2271
+ }
2272
+ qb.innerJoin(throughTable, `${rel.table}.${localKey}`, `${throughTable}.${relatedPivotKey}`);
2273
+ qb.where(`${throughTable}.${foreignPivotKey}`, "=", pkValue);
2274
+ return qb;
2275
+ },
2276
+ addEagerConstraints(_query, _models) {},
2277
+ match(models, results, relationName) {
2278
+ const grouped = {};
2279
+ for (const model of models) {
2280
+ const key = String(model.get(localKey));
2281
+ grouped[key] = [];
2282
+ }
2283
+ for (const result of results) {
2284
+ const pivot = pivotData.get(result);
2285
+ if (pivot) {
2286
+ const key = String(pivot[foreignPivotKey]);
2287
+ if (grouped[key]) grouped[key].push(result);
2288
+ }
2289
+ }
2290
+ for (const model of models) {
2291
+ const key = String(model.get(localKey));
2292
+ model.$setRelation(relationName, grouped[key] ?? []);
2293
+ }
2294
+ },
2295
+ async getResults(parent) {
2296
+ return this.query(parent).execute();
2297
+ },
2298
+ async loadEager(models, relationName, constraints) {
2299
+ const rel = getRelated();
2300
+ if (models.length === 0) return;
2301
+ const ids = models.map((m) => m.get(localKey)).filter((id) => id != null);
2302
+ if (ids.length === 0) return;
2303
+ const qb = createQueryBuilder(rel);
2304
+ qb.innerJoin(throughTable, `${rel.table}.${localKey}`, `${throughTable}.${relatedPivotKey}`);
2305
+ qb.where(`${throughTable}.${foreignPivotKey}`, "in", ids);
2306
+ const selectCols = [`${rel.table}.*`];
2307
+ if (pivotExtras.length > 0) for (const extra of pivotExtras) selectCols.push(`${throughTable}.${extra}`);
2308
+ selectCols.push(`${throughTable}.${foreignPivotKey}`);
2309
+ qb.select(...selectCols);
2310
+ if (constraints) constraints(qb);
2311
+ const results = await qb.execute();
2312
+ for (const result of results) {
2313
+ const pivot = {};
2314
+ const col = `${foreignPivotKey}`;
2315
+ pivot[foreignPivotKey] = result.get(col);
2316
+ for (const extra of pivotExtras) pivot[extra] = result.get(extra);
2317
+ pivotData.set(result, pivot);
2318
+ }
2319
+ this.match(models, results, relationName);
2320
+ }
2321
+ };
2322
+ }
2323
+ function hasManyThrough(relatedThunk, throughThunk, options = {}) {
2324
+ const related = resolveThunk$1(relatedThunk);
2325
+ const through = resolveThunk$1(throughThunk);
2326
+ const foreignKey = options.foreignKey ?? `${snakeCase(through.table)}Id`;
2327
+ const localKey = options.localKey ?? "id";
2328
+ const throughForeignKey = options.throughForeignKey ?? `${snakeCase(resolveThunk$1(relatedThunk).table)}Id`;
2329
+ const throughLocalKey = options.throughLocalKey ?? "id";
2330
+ return {
2331
+ type: "hasManyThrough",
2332
+ relatedModelClass: related,
2333
+ foreignKey,
2334
+ localKey,
2335
+ throughTable: through.table,
2336
+ throughForeignKey,
2337
+ throughLocalKey,
2338
+ get foreignPivotKey() {},
2339
+ get relatedPivotKey() {},
2340
+ query(parent) {
2341
+ const pkValue = parent.get(localKey);
2342
+ const qb = createQueryBuilder(related);
2343
+ if (pkValue == null) {
2344
+ qb.where(localKey, "=", -1);
2345
+ return qb;
2346
+ }
2347
+ qb.innerJoin(through.table, `${through.table}.${throughLocalKey}`, `${related.table}.${throughForeignKey}`);
2348
+ qb.where(`${through.table}.${foreignKey}`, "=", pkValue);
2349
+ return qb;
2350
+ },
2351
+ addEagerConstraints(query, models) {
2352
+ const ids = models.map((m) => m.get(localKey)).filter((id) => id != null);
2353
+ if (ids.length > 0) {
2354
+ query.innerJoin(through.table, `${through.table}.${throughLocalKey}`, `${related.table}.${throughForeignKey}`);
2355
+ query.where(`${through.table}.${foreignKey}`, "in", ids);
2356
+ }
2357
+ },
2358
+ match(models, results, relationName) {
2359
+ const grouped = {};
2360
+ for (const result of results) {
2361
+ const fkValue = result.get(throughForeignKey);
2362
+ if (fkValue == null) continue;
2363
+ const key = String(fkValue);
2364
+ if (!grouped[key]) grouped[key] = [];
2365
+ grouped[key].push(result);
2366
+ }
2367
+ for (const model of models) {
2368
+ const key = String(model.get(localKey));
2369
+ model.$setRelation(relationName, grouped[key] ?? []);
2370
+ }
2371
+ },
2372
+ async getResults(parent) {
2373
+ return this.query(parent).execute();
2374
+ },
2375
+ async loadEager(models, relationName, constraints) {
2376
+ if (models.length === 0) return;
2377
+ const qb = createQueryBuilder(related);
2378
+ this.addEagerConstraints(qb, models);
2379
+ if (constraints) constraints(qb);
2380
+ const results = await qb.execute();
2381
+ this.match(models, results, relationName);
2382
+ }
2383
+ };
2384
+ }
2385
+ //#endregion
2386
+ //#region src/relations/morph.ts
2387
+ function groupByArray(items, key) {
2388
+ const result = {};
2389
+ for (const item of items) {
2390
+ const v = item.get(key);
2391
+ if (v == null) continue;
2392
+ const k = String(v);
2393
+ if (!result[k]) result[k] = [];
2394
+ result[k].push(item);
2395
+ }
2396
+ return result;
2397
+ }
2398
+ const THUNK_CACHE = /* @__PURE__ */ new WeakMap();
2399
+ function resolveThunk(thunk) {
2400
+ let cls = THUNK_CACHE.get(thunk);
2401
+ if (!cls) {
2402
+ cls = thunk();
2403
+ THUNK_CACHE.set(thunk, cls);
2404
+ }
2405
+ return cls;
2406
+ }
2407
+ /**
2408
+ * Resolve the related model for a MorphTo relation given a parent instance.
2409
+ * Looks up the parent's `{name}Type` column value in the relation's morphMap
2410
+ * and returns the corresponding ModelDefinition.
2411
+ *
2412
+ * Returns `undefined` if the type column is null, the morph map entry is
2413
+ * missing, or the relation is not a morphTo.
2414
+ */
2415
+ function resolveMorphRelation(relation, parent) {
2416
+ const morphMap = relation._morphMap;
2417
+ const morphType = relation._morphType;
2418
+ if (!morphMap || !morphType) return void 0;
2419
+ const typeValue = parent.get(morphType);
2420
+ if (!typeValue) return void 0;
2421
+ const thunk = morphMap[typeValue];
2422
+ return thunk ? resolveThunk(thunk) : void 0;
2423
+ }
2424
+ /**
2425
+ * Define a polymorphic belongsTo relationship.
2426
+ *
2427
+ * Requires a `morphMap` to resolve the related model class at runtime
2428
+ * based on the value of the type column.
2429
+ *
2430
+ * ### Usage
2431
+ * ```ts
2432
+ * Comment.relations.commentable = defineMorphTo({
2433
+ * name: "commentable",
2434
+ * morphMap: {
2435
+ * posts: () => Post,
2436
+ * videos: () => Video,
2437
+ * },
2438
+ * })
2439
+ * ```
2440
+ *
2441
+ * Eager loading groups parents by type and issues one query per type:
2442
+ * ```ts
2443
+ * const comments = await Comment.query().with("commentable")
2444
+ * // → SELECT * FROM comments
2445
+ * // → SELECT * FROM posts WHERE id IN (...)
2446
+ * // → SELECT * FROM videos WHERE id IN (...)
2447
+ * ```
2448
+ */
2449
+ function defineMorphTo(options) {
2450
+ const morphType = options.type ?? `${options.name}Type`;
2451
+ const morphId = options.id ?? `${options.name}Id`;
2452
+ const morphMap = options.morphMap ?? {};
2453
+ const firstEntry = Object.entries(morphMap)[0];
2454
+ return {
2455
+ type: "belongsTo",
2456
+ relatedModelClass: (firstEntry ? resolveThunk(firstEntry[1]) : null) ?? null,
2457
+ foreignKey: morphId,
2458
+ localKey: "id",
2459
+ get throughTable() {},
2460
+ get foreignPivotKey() {},
2461
+ get relatedPivotKey() {},
2462
+ get throughForeignKey() {},
2463
+ get throughLocalKey() {},
2464
+ _morphMap: morphMap,
2465
+ _morphType: morphType,
2466
+ _morphId: morphId,
2467
+ /**
2468
+ * Build a query for the related model.
2469
+ * Throws if the type column is null/undefined or if no model is registered
2470
+ * for the type value.
2471
+ */
2472
+ query(parent) {
2473
+ const typeValue = parent.get(morphType);
2474
+ if (!typeValue) throw new Error(`Cannot resolve morphTo "${options.name}": "${morphType}" is null on ${defName(parent)}`);
2475
+ const thunk = morphMap[typeValue];
2476
+ if (!thunk) throw new Error(`No model registered for morph type "${typeValue}" in morphTo "${options.name}". Available types: ${Object.keys(morphMap).join(", ") || "(none)"}`);
2477
+ const relatedDef = resolveThunk(thunk);
2478
+ const id = parent.get(morphId);
2479
+ if (id == null) throw new Error(`Cannot resolve morphTo "${options.name}": "${morphId}" is null on ${defName(parent)}`);
2480
+ return relatedDef.query().where("id", "=", id);
2481
+ },
2482
+ addEagerConstraints(_query, _models) {},
2483
+ match(_models, _results, _relationName) {},
2484
+ async getResults(parent) {
2485
+ return await this.query(parent).executeTakeFirst() ?? null;
2486
+ },
2487
+ async loadEager(models, relationName, constraints) {
2488
+ if (models.length === 0) return;
2489
+ const grouped = {};
2490
+ const nullType = [];
2491
+ for (const model of models) {
2492
+ const typeValue = model.get(morphType);
2493
+ if (typeValue) {
2494
+ if (!grouped[typeValue]) grouped[typeValue] = [];
2495
+ grouped[typeValue].push(model);
2496
+ } else nullType.push(model);
2497
+ }
2498
+ for (const model of nullType) model.$setRelation(relationName, null);
2499
+ for (const [typeValue, typeModels] of Object.entries(grouped)) {
2500
+ const thunk = morphMap[typeValue];
2501
+ if (!thunk) {
2502
+ for (const model of typeModels) model.$setRelation(relationName, null);
2503
+ continue;
2504
+ }
2505
+ const relatedDef = resolveThunk(thunk);
2506
+ const ids = typeModels.map((m) => m.get(morphId)).filter((id) => id != null);
2507
+ if (ids.length === 0) {
2508
+ for (const model of typeModels) model.$setRelation(relationName, null);
2509
+ continue;
2510
+ }
2511
+ const qb = relatedDef.query();
2512
+ qb.whereIn("id", ids);
2513
+ if (constraints) constraints(qb);
2514
+ const results = await qb.execute();
2515
+ const resultMap = /* @__PURE__ */ new Map();
2516
+ for (const r of results) resultMap.set(r.get("id"), r);
2517
+ for (const model of typeModels) model.$setRelation(relationName, resultMap.get(model.get(morphId)) ?? null);
2518
+ }
2519
+ }
2520
+ };
2521
+ }
2522
+ /**
2523
+ * Define a polymorphic hasMany relationship.
2524
+ * The related table stores the parent's type and id.
2525
+ */
2526
+ function defineMorphMany(options) {
2527
+ const related = resolveThunk(options.related);
2528
+ const morphType = options.type ?? `${options.name}Type`;
2529
+ const morphId = options.id ?? `${options.name}Id`;
2530
+ const typeValue = options.typeValue ?? related.table;
2531
+ return {
2532
+ type: "hasMany",
2533
+ relatedModelClass: related,
2534
+ foreignKey: morphId,
2535
+ localKey: "id",
2536
+ get throughTable() {},
2537
+ get foreignPivotKey() {},
2538
+ get relatedPivotKey() {},
2539
+ get throughForeignKey() {},
2540
+ get throughLocalKey() {},
2541
+ _morphType: morphType,
2542
+ _morphId: morphId,
2543
+ _morphTypeValue: typeValue,
2544
+ query(parent) {
2545
+ const qb = createQueryBuilder(related);
2546
+ qb.where(morphId, "=", parent.get("id"));
2547
+ qb.where(morphType, "=", typeValue);
2548
+ return qb;
2549
+ },
2550
+ addEagerConstraints(query, models) {
2551
+ const ids = models.map((m) => m.get("id")).filter((id) => id != null);
2552
+ if (ids.length > 0) {
2553
+ query.whereIn(morphId, ids);
2554
+ query.where(morphType, "=", typeValue);
2555
+ }
2556
+ },
2557
+ match(models, results, relationName) {
2558
+ const grouped = groupByArray(results, morphId);
2559
+ for (const model of models) {
2560
+ const key = String(model.get("id"));
2561
+ model.$setRelation(relationName, grouped[key] ?? []);
2562
+ }
2563
+ },
2564
+ async getResults(parent) {
2565
+ return this.query(parent).execute();
2566
+ },
2567
+ async loadEager(models, relationName, constraints) {
2568
+ if (models.length === 0) return;
2569
+ const qb = createQueryBuilder(related);
2570
+ this.addEagerConstraints(qb, models);
2571
+ if (constraints) constraints(qb);
2572
+ const results = await qb.execute();
2573
+ this.match(models, results, relationName);
2574
+ }
2575
+ };
2576
+ }
2577
+ /**
2578
+ * Define a polymorphic hasOne relationship.
2579
+ */
2580
+ function defineMorphOne(options) {
2581
+ const base = defineMorphMany(options);
2582
+ return {
2583
+ ...base,
2584
+ type: "hasOne",
2585
+ async getResults(parent) {
2586
+ return (await base.getResults(parent))[0] ?? null;
2587
+ },
2588
+ match(models, results, relationName) {
2589
+ const grouped = groupByArray(results, base.foreignKey);
2590
+ for (const model of models) {
2591
+ const related = grouped[String(model.get("id"))] ?? [];
2592
+ model.$setRelation(relationName, related[0] ?? null);
2593
+ }
2594
+ }
2595
+ };
2596
+ }
2597
+ function defName(instance) {
2598
+ return instance.constructor?.name ?? "model";
2599
+ }
2600
+ //#endregion
2601
+ export { Attribute, DatabaseError, ModelNotFoundError, ModelNotRegisteredError, RelationNotAllowedError, RelationNotFoundError, ValidationError, belongsTo, createArkTypeSchemaConfig, createCollection, createColumn, createHookManager, createORM, createORM as createPeta, createPaginator, createQueryBuilder, defineModel, defineMorphMany, defineMorphOne, defineMorphTo, hasMany, hasManyThrough, hasOne, eager_exports as i, manyToMany, relation_exports as n, normalizeError, delete_exports as r, resolveMorphRelation, softDeletes, t, timestamps, ulid };