@zerotal/orm 1.0.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 (87) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +21 -0
  3. package/README.md +170 -0
  4. package/package.json +58 -0
  5. package/src/casts/Cast.ts +200 -0
  6. package/src/commands/DbSeedCommand.ts +71 -0
  7. package/src/commands/MakeFactoryCommand.ts +59 -0
  8. package/src/commands/MakeMigrationCommand.ts +109 -0
  9. package/src/commands/MakeModelCommand.ts +83 -0
  10. package/src/commands/MakeSeederCommand.ts +50 -0
  11. package/src/commands/MigrateCommand.ts +60 -0
  12. package/src/commands/MigrateFreshCommand.ts +41 -0
  13. package/src/commands/MigrateGenerateCommand.ts +110 -0
  14. package/src/commands/MigrateRollbackCommand.ts +43 -0
  15. package/src/commands/MigrateStatusCommand.ts +49 -0
  16. package/src/commands/_loadMigrations.ts +34 -0
  17. package/src/commands/index.ts +30 -0
  18. package/src/config.ts +182 -0
  19. package/src/conventions.ts +67 -0
  20. package/src/db/DB.ts +486 -0
  21. package/src/db/NPlusOneDetector.ts +176 -0
  22. package/src/db/QueryBuilder.ts +2458 -0
  23. package/src/db/ReadWriteRouter.ts +96 -0
  24. package/src/db/TransactionContext.ts +13 -0
  25. package/src/db/dialects/MysqlDialect.ts +57 -0
  26. package/src/db/dialects/PostgresDialect.ts +55 -0
  27. package/src/db/dialects/SqliteDialect.ts +54 -0
  28. package/src/db/dialects/index.ts +25 -0
  29. package/src/db/dialects/types.ts +67 -0
  30. package/src/db/resolver.ts +30 -0
  31. package/src/db/sql-types.ts +12 -0
  32. package/src/db/types.ts +296 -0
  33. package/src/errors/MassAssignmentError.ts +25 -0
  34. package/src/errors/MigrationError.ts +18 -0
  35. package/src/errors/ModelNotFoundError.ts +21 -0
  36. package/src/errors/NPlusOneError.ts +6 -0
  37. package/src/errors/RelationNotLoadedError.ts +19 -0
  38. package/src/errors/StateError.ts +18 -0
  39. package/src/errors/TransactionError.ts +13 -0
  40. package/src/errors/UnsupportedDialectError.ts +18 -0
  41. package/src/errors/index.ts +7 -0
  42. package/src/events.ts +112 -0
  43. package/src/global.d.ts +17 -0
  44. package/src/implicitBinding.ts +73 -0
  45. package/src/index.ts +255 -0
  46. package/src/model/BaseModel.ts +2499 -0
  47. package/src/model/ModelQueryBuilder.ts +1808 -0
  48. package/src/model/Observer.ts +73 -0
  49. package/src/model/OrmContext.ts +71 -0
  50. package/src/model/ReactiveProxy.ts +53 -0
  51. package/src/model/SoftDeletes.ts +108 -0
  52. package/src/model/State.ts +290 -0
  53. package/src/model/decorators/_metadata.ts +211 -0
  54. package/src/model/decorators/_registerRelation.ts +20 -0
  55. package/src/model/decorators/belongsTo.ts +38 -0
  56. package/src/model/decorators/column.ts +278 -0
  57. package/src/model/decorators/hasMany.ts +34 -0
  58. package/src/model/decorators/hasManyThrough.ts +50 -0
  59. package/src/model/decorators/hasOne.ts +34 -0
  60. package/src/model/decorators/hasOneThrough.ts +40 -0
  61. package/src/model/decorators/manyToMany.ts +55 -0
  62. package/src/model/decorators/morphMany.ts +38 -0
  63. package/src/model/decorators/morphOne.ts +38 -0
  64. package/src/model/decorators/morphTo.ts +51 -0
  65. package/src/model/decorators/morphToMany.ts +49 -0
  66. package/src/model/decorators/morphedByMany.ts +46 -0
  67. package/src/model/decorators/table.ts +124 -0
  68. package/src/model/hooks/HookRegistry.ts +110 -0
  69. package/src/model/mixins.ts +536 -0
  70. package/src/model/payload.ts +114 -0
  71. package/src/model/relations/RelationRegistry.ts +184 -0
  72. package/src/observability.ts +210 -0
  73. package/src/provider/DatabaseProvider.ts +266 -0
  74. package/src/schema/Blueprint.ts +900 -0
  75. package/src/schema/ColumnDefinition.ts +517 -0
  76. package/src/schema/Migration.ts +34 -0
  77. package/src/schema/MigrationCodegen.ts +108 -0
  78. package/src/schema/MigrationRunner.ts +351 -0
  79. package/src/schema/ModelInspector.ts +133 -0
  80. package/src/schema/Schema.ts +140 -0
  81. package/src/schema/SchemaDiffer.ts +137 -0
  82. package/src/schema/SchemaInspector.ts +164 -0
  83. package/src/schema/__test_migrations__/001_create_test_table.ts +15 -0
  84. package/src/schema/autoMigrate.ts +154 -0
  85. package/src/schema/index.ts +28 -0
  86. package/src/seeding/Seeder.ts +46 -0
  87. package/src/support/identifiers.ts +62 -0
@@ -0,0 +1,536 @@
1
+ // ── Model mixins ──────────────────────────────────────────────────────────────
2
+ //
3
+ // `BaseModelWith(...)` composes any number of model mixins on top of `BaseModel`,
4
+ // so packages can ship reusable model behaviour (auth contract, roles, permissions,
5
+ // soft deletes, …) that apps stack without "wrapper hell":
6
+ //
7
+ // // before — nested, base repeated, order reads inside-out
8
+ // class User extends Roles(Permissions(AuthUser)) {}
9
+ //
10
+ // // after — flat, left-to-right, base baked in
11
+ // class User extends BaseModelWith(Authenticatable, Permissions, Roles) {}
12
+ //
13
+ // A mixin is the canonical generic form `(<T>(Base: T) => class extends Base { … })`.
14
+ // Because each one returns `class extends Base`, BaseModel's full static surface
15
+ // (`User.query()`, `find()`, `create()`, scopes, …) and every mixin's instance
16
+ // members flow through to the final class — fully type-checked.
17
+
18
+ import { BaseModel } from "./BaseModel.ts";
19
+
20
+ /** A concrete class constructor. */
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- generic mixin base bound
22
+ export type Constructor<T = object> = new (...args: any[]) => T;
23
+
24
+ /**
25
+ * A model mixin: receives a base constructor and returns an extended one. Authors
26
+ * write the generic form so the mixin composes onto whatever base it is given:
27
+ *
28
+ * export const SoftDeletes = <T extends Constructor>(Base: T) =>
29
+ * class extends Base { … };
30
+ */
31
+ export type Mixin<TIn extends Constructor = Constructor, TOut extends Constructor = Constructor> = (
32
+ Base: TIn,
33
+ ) => TOut;
34
+
35
+ type Base = typeof BaseModel;
36
+
37
+ // Typed overloads (1–8 mixins) thread the accumulated type through each step so the
38
+ // result is `BaseModel`'s statics + every mixin's members. Need more? Nest a
39
+ // `BaseModelWith(...)` call or add another overload.
40
+
41
+ /**
42
+ * Compose any number of model {@link Mixin | mixins} on top of {@link BaseModel},
43
+ * folding them left-to-right so the resulting class carries `BaseModel`'s full
44
+ * static surface (`query()`, `find()`, `create()`, scopes, …) plus every mixin's
45
+ * instance and static members — all fully type-checked.
46
+ *
47
+ * Prefer this over hand-nesting mixins (`Roles(Permissions(AuthUser))`), which
48
+ * reads inside-out and repeats the base. Each overload (1–20 mixins) threads the
49
+ * accumulated type through every step; for more, nest a second `BaseModelWith(...)`.
50
+ *
51
+ * @param mixins - Mixin factories applied in order; each receives the class the
52
+ * previous one produced.
53
+ * @returns A model class extending `BaseModel` with every mixin applied.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * class User extends BaseModelWith(Authenticatable, Permissions, Roles) {}
58
+ * ```
59
+ */
60
+ export function BaseModelWith<A extends Constructor>(a: (base: Base) => A): A;
61
+ export function BaseModelWith<A extends Constructor, B extends Constructor>(
62
+ a: (base: Base) => A,
63
+ b: (base: A) => B,
64
+ ): B;
65
+ export function BaseModelWith<A extends Constructor, B extends Constructor, C extends Constructor>(
66
+ a: (base: Base) => A,
67
+ b: (base: A) => B,
68
+ c: (base: B) => C,
69
+ ): C;
70
+ export function BaseModelWith<
71
+ A extends Constructor,
72
+ B extends Constructor,
73
+ C extends Constructor,
74
+ D extends Constructor,
75
+ >(a: (base: Base) => A, b: (base: A) => B, c: (base: B) => C, d: (base: C) => D): D;
76
+ export function BaseModelWith<
77
+ A extends Constructor,
78
+ B extends Constructor,
79
+ C extends Constructor,
80
+ D extends Constructor,
81
+ E extends Constructor,
82
+ >(
83
+ a: (base: Base) => A,
84
+ b: (base: A) => B,
85
+ c: (base: B) => C,
86
+ d: (base: C) => D,
87
+ e: (base: D) => E,
88
+ ): E;
89
+ export function BaseModelWith<
90
+ A extends Constructor,
91
+ B extends Constructor,
92
+ C extends Constructor,
93
+ D extends Constructor,
94
+ E extends Constructor,
95
+ F extends Constructor,
96
+ >(
97
+ a: (base: Base) => A,
98
+ b: (base: A) => B,
99
+ c: (base: B) => C,
100
+ d: (base: C) => D,
101
+ e: (base: D) => E,
102
+ f: (base: E) => F,
103
+ ): F;
104
+ export function BaseModelWith<
105
+ A extends Constructor,
106
+ B extends Constructor,
107
+ C extends Constructor,
108
+ D extends Constructor,
109
+ E extends Constructor,
110
+ F extends Constructor,
111
+ G extends Constructor,
112
+ >(
113
+ a: (base: Base) => A,
114
+ b: (base: A) => B,
115
+ c: (base: B) => C,
116
+ d: (base: C) => D,
117
+ e: (base: D) => E,
118
+ f: (base: E) => F,
119
+ g: (base: F) => G,
120
+ ): G;
121
+ export function BaseModelWith<
122
+ A extends Constructor,
123
+ B extends Constructor,
124
+ C extends Constructor,
125
+ D extends Constructor,
126
+ E extends Constructor,
127
+ F extends Constructor,
128
+ G extends Constructor,
129
+ H extends Constructor,
130
+ >(
131
+ a: (base: Base) => A,
132
+ b: (base: A) => B,
133
+ c: (base: B) => C,
134
+ d: (base: C) => D,
135
+ e: (base: D) => E,
136
+ f: (base: E) => F,
137
+ g: (base: F) => G,
138
+ h: (base: G) => H,
139
+ ): H;
140
+ export function BaseModelWith<
141
+ A extends Constructor,
142
+ B extends Constructor,
143
+ C extends Constructor,
144
+ D extends Constructor,
145
+ E extends Constructor,
146
+ F extends Constructor,
147
+ G extends Constructor,
148
+ H extends Constructor,
149
+ I extends Constructor,
150
+ >(
151
+ a: (base: Base) => A,
152
+ b: (base: A) => B,
153
+ c: (base: B) => C,
154
+ d: (base: C) => D,
155
+ e: (base: D) => E,
156
+ f: (base: E) => F,
157
+ g: (base: F) => G,
158
+ h: (base: G) => H,
159
+ i: (base: H) => I,
160
+ ): I;
161
+ export function BaseModelWith<
162
+ A extends Constructor,
163
+ B extends Constructor,
164
+ C extends Constructor,
165
+ D extends Constructor,
166
+ E extends Constructor,
167
+ F extends Constructor,
168
+ G extends Constructor,
169
+ H extends Constructor,
170
+ I extends Constructor,
171
+ J extends Constructor,
172
+ >(
173
+ a: (base: Base) => A,
174
+ b: (base: A) => B,
175
+ c: (base: B) => C,
176
+ d: (base: C) => D,
177
+ e: (base: D) => E,
178
+ f: (base: E) => F,
179
+ g: (base: F) => G,
180
+ h: (base: G) => H,
181
+ i: (base: H) => I,
182
+ j: (base: I) => J,
183
+ ): J;
184
+ export function BaseModelWith<
185
+ A extends Constructor,
186
+ B extends Constructor,
187
+ C extends Constructor,
188
+ D extends Constructor,
189
+ E extends Constructor,
190
+ F extends Constructor,
191
+ G extends Constructor,
192
+ H extends Constructor,
193
+ I extends Constructor,
194
+ J extends Constructor,
195
+ K extends Constructor,
196
+ >(
197
+ a: (base: Base) => A,
198
+ b: (base: A) => B,
199
+ c: (base: B) => C,
200
+ d: (base: C) => D,
201
+ e: (base: D) => E,
202
+ f: (base: E) => F,
203
+ g: (base: F) => G,
204
+ h: (base: G) => H,
205
+ i: (base: H) => I,
206
+ j: (base: I) => J,
207
+ k: (base: J) => K,
208
+ ): K;
209
+ export function BaseModelWith<
210
+ A extends Constructor,
211
+ B extends Constructor,
212
+ C extends Constructor,
213
+ D extends Constructor,
214
+ E extends Constructor,
215
+ F extends Constructor,
216
+ G extends Constructor,
217
+ H extends Constructor,
218
+ I extends Constructor,
219
+ J extends Constructor,
220
+ K extends Constructor,
221
+ L extends Constructor,
222
+ >(
223
+ a: (base: Base) => A,
224
+ b: (base: A) => B,
225
+ c: (base: B) => C,
226
+ d: (base: C) => D,
227
+ e: (base: D) => E,
228
+ f: (base: E) => F,
229
+ g: (base: F) => G,
230
+ h: (base: G) => H,
231
+ i: (base: H) => I,
232
+ j: (base: I) => J,
233
+ k: (base: J) => K,
234
+ l: (base: K) => L,
235
+ ): L;
236
+ export function BaseModelWith<
237
+ A extends Constructor,
238
+ B extends Constructor,
239
+ C extends Constructor,
240
+ D extends Constructor,
241
+ E extends Constructor,
242
+ F extends Constructor,
243
+ G extends Constructor,
244
+ H extends Constructor,
245
+ I extends Constructor,
246
+ J extends Constructor,
247
+ K extends Constructor,
248
+ L extends Constructor,
249
+ M extends Constructor,
250
+ >(
251
+ a: (base: Base) => A,
252
+ b: (base: A) => B,
253
+ c: (base: B) => C,
254
+ d: (base: C) => D,
255
+ e: (base: D) => E,
256
+ f: (base: E) => F,
257
+ g: (base: F) => G,
258
+ h: (base: G) => H,
259
+ i: (base: H) => I,
260
+ j: (base: I) => J,
261
+ k: (base: J) => K,
262
+ l: (base: K) => L,
263
+ m: (base: L) => M,
264
+ ): M;
265
+ export function BaseModelWith<
266
+ A extends Constructor,
267
+ B extends Constructor,
268
+ C extends Constructor,
269
+ D extends Constructor,
270
+ E extends Constructor,
271
+ F extends Constructor,
272
+ G extends Constructor,
273
+ H extends Constructor,
274
+ I extends Constructor,
275
+ J extends Constructor,
276
+ K extends Constructor,
277
+ L extends Constructor,
278
+ M extends Constructor,
279
+ N extends Constructor,
280
+ >(
281
+ a: (base: Base) => A,
282
+ b: (base: A) => B,
283
+ c: (base: B) => C,
284
+ d: (base: C) => D,
285
+ e: (base: D) => E,
286
+ f: (base: E) => F,
287
+ g: (base: F) => G,
288
+ h: (base: G) => H,
289
+ i: (base: H) => I,
290
+ j: (base: I) => J,
291
+ k: (base: J) => K,
292
+ l: (base: K) => L,
293
+ m: (base: L) => M,
294
+ n: (base: M) => N,
295
+ ): N;
296
+ export function BaseModelWith<
297
+ A extends Constructor,
298
+ B extends Constructor,
299
+ C extends Constructor,
300
+ D extends Constructor,
301
+ E extends Constructor,
302
+ F extends Constructor,
303
+ G extends Constructor,
304
+ H extends Constructor,
305
+ I extends Constructor,
306
+ J extends Constructor,
307
+ K extends Constructor,
308
+ L extends Constructor,
309
+ M extends Constructor,
310
+ N extends Constructor,
311
+ O extends Constructor,
312
+ >(
313
+ a: (base: Base) => A,
314
+ b: (base: A) => B,
315
+ c: (base: B) => C,
316
+ d: (base: C) => D,
317
+ e: (base: D) => E,
318
+ f: (base: E) => F,
319
+ g: (base: F) => G,
320
+ h: (base: G) => H,
321
+ i: (base: H) => I,
322
+ j: (base: I) => J,
323
+ k: (base: J) => K,
324
+ l: (base: K) => L,
325
+ m: (base: L) => M,
326
+ n: (base: M) => N,
327
+ o: (base: N) => O,
328
+ ): O;
329
+ export function BaseModelWith<
330
+ A extends Constructor,
331
+ B extends Constructor,
332
+ C extends Constructor,
333
+ D extends Constructor,
334
+ E extends Constructor,
335
+ F extends Constructor,
336
+ G extends Constructor,
337
+ H extends Constructor,
338
+ I extends Constructor,
339
+ J extends Constructor,
340
+ K extends Constructor,
341
+ L extends Constructor,
342
+ M extends Constructor,
343
+ N extends Constructor,
344
+ O extends Constructor,
345
+ P extends Constructor,
346
+ >(
347
+ a: (base: Base) => A,
348
+ b: (base: A) => B,
349
+ c: (base: B) => C,
350
+ d: (base: C) => D,
351
+ e: (base: D) => E,
352
+ f: (base: E) => F,
353
+ g: (base: F) => G,
354
+ h: (base: G) => H,
355
+ i: (base: H) => I,
356
+ j: (base: I) => J,
357
+ k: (base: J) => K,
358
+ l: (base: K) => L,
359
+ m: (base: L) => M,
360
+ n: (base: M) => N,
361
+ o: (base: N) => O,
362
+ p: (base: O) => P,
363
+ ): P;
364
+ export function BaseModelWith<
365
+ A extends Constructor,
366
+ B extends Constructor,
367
+ C extends Constructor,
368
+ D extends Constructor,
369
+ E extends Constructor,
370
+ F extends Constructor,
371
+ G extends Constructor,
372
+ H extends Constructor,
373
+ I extends Constructor,
374
+ J extends Constructor,
375
+ K extends Constructor,
376
+ L extends Constructor,
377
+ M extends Constructor,
378
+ N extends Constructor,
379
+ O extends Constructor,
380
+ P extends Constructor,
381
+ Q extends Constructor,
382
+ >(
383
+ a: (base: Base) => A,
384
+ b: (base: A) => B,
385
+ c: (base: B) => C,
386
+ d: (base: C) => D,
387
+ e: (base: D) => E,
388
+ f: (base: E) => F,
389
+ g: (base: F) => G,
390
+ h: (base: G) => H,
391
+ i: (base: H) => I,
392
+ j: (base: I) => J,
393
+ k: (base: J) => K,
394
+ l: (base: K) => L,
395
+ m: (base: L) => M,
396
+ n: (base: M) => N,
397
+ o: (base: N) => O,
398
+ p: (base: O) => P,
399
+ q: (base: P) => Q,
400
+ ): Q;
401
+ export function BaseModelWith<
402
+ A extends Constructor,
403
+ B extends Constructor,
404
+ C extends Constructor,
405
+ D extends Constructor,
406
+ E extends Constructor,
407
+ F extends Constructor,
408
+ G extends Constructor,
409
+ H extends Constructor,
410
+ I extends Constructor,
411
+ J extends Constructor,
412
+ K extends Constructor,
413
+ L extends Constructor,
414
+ M extends Constructor,
415
+ N extends Constructor,
416
+ O extends Constructor,
417
+ P extends Constructor,
418
+ Q extends Constructor,
419
+ R extends Constructor,
420
+ >(
421
+ a: (base: Base) => A,
422
+ b: (base: A) => B,
423
+ c: (base: B) => C,
424
+ d: (base: C) => D,
425
+ e: (base: D) => E,
426
+ f: (base: E) => F,
427
+ g: (base: F) => G,
428
+ h: (base: G) => H,
429
+ i: (base: H) => I,
430
+ j: (base: I) => J,
431
+ k: (base: J) => K,
432
+ l: (base: K) => L,
433
+ m: (base: L) => M,
434
+ n: (base: M) => N,
435
+ o: (base: N) => O,
436
+ p: (base: O) => P,
437
+ q: (base: P) => Q,
438
+ r: (base: Q) => R,
439
+ ): R;
440
+ export function BaseModelWith<
441
+ A extends Constructor,
442
+ B extends Constructor,
443
+ C extends Constructor,
444
+ D extends Constructor,
445
+ E extends Constructor,
446
+ F extends Constructor,
447
+ G extends Constructor,
448
+ H extends Constructor,
449
+ I extends Constructor,
450
+ J extends Constructor,
451
+ K extends Constructor,
452
+ L extends Constructor,
453
+ M extends Constructor,
454
+ N extends Constructor,
455
+ O extends Constructor,
456
+ P extends Constructor,
457
+ Q extends Constructor,
458
+ R extends Constructor,
459
+ S extends Constructor,
460
+ >(
461
+ a: (base: Base) => A,
462
+ b: (base: A) => B,
463
+ c: (base: B) => C,
464
+ d: (base: C) => D,
465
+ e: (base: D) => E,
466
+ f: (base: E) => F,
467
+ g: (base: F) => G,
468
+ h: (base: G) => H,
469
+ i: (base: H) => I,
470
+ j: (base: I) => J,
471
+ k: (base: J) => K,
472
+ l: (base: K) => L,
473
+ m: (base: L) => M,
474
+ n: (base: M) => N,
475
+ o: (base: N) => O,
476
+ p: (base: O) => P,
477
+ q: (base: P) => Q,
478
+ r: (base: Q) => R,
479
+ s: (base: R) => S,
480
+ ): S;
481
+ export function BaseModelWith<
482
+ A extends Constructor,
483
+ B extends Constructor,
484
+ C extends Constructor,
485
+ D extends Constructor,
486
+ E extends Constructor,
487
+ F extends Constructor,
488
+ G extends Constructor,
489
+ H extends Constructor,
490
+ I extends Constructor,
491
+ J extends Constructor,
492
+ K extends Constructor,
493
+ L extends Constructor,
494
+ M extends Constructor,
495
+ N extends Constructor,
496
+ O extends Constructor,
497
+ P extends Constructor,
498
+ Q extends Constructor,
499
+ R extends Constructor,
500
+ S extends Constructor,
501
+ T extends Constructor,
502
+ >(
503
+ a: (base: Base) => A,
504
+ b: (base: A) => B,
505
+ c: (base: B) => C,
506
+ d: (base: C) => D,
507
+ e: (base: D) => E,
508
+ f: (base: E) => F,
509
+ g: (base: F) => G,
510
+ h: (base: G) => H,
511
+ i: (base: H) => I,
512
+ j: (base: I) => J,
513
+ k: (base: J) => K,
514
+ l: (base: K) => L,
515
+ m: (base: L) => M,
516
+ n: (base: M) => N,
517
+ o: (base: N) => O,
518
+ p: (base: O) => P,
519
+ q: (base: P) => Q,
520
+ r: (base: Q) => R,
521
+ s: (base: R) => S,
522
+ t: (base: S) => T,
523
+ ): T;
524
+
525
+ // Implementation: fold the mixins over BaseModel, left to right. The base param is
526
+ // `any` so each typed overload above (whose base is the narrower `typeof BaseModel`
527
+ // or a prior mixin's result) stays assignable to this implementation signature.
528
+ export function BaseModelWith(
529
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- variadic mixin folder
530
+ ...mixins: Array<(base: any) => Constructor>
531
+ ): Constructor {
532
+ return mixins.reduce<Constructor>(
533
+ (acc, mixin) => mixin(acc),
534
+ BaseModel as unknown as Constructor,
535
+ );
536
+ }
@@ -0,0 +1,114 @@
1
+ // ── RelationBrand — nominal marker for "this property is a related model" ────
2
+
3
+ /**
4
+ * Structural shape carried by every `BaseModel` (via its phantom `__isZerotalModel`
5
+ * brand). We detect relation properties by this single marker instead of
6
+ * `extends BaseModel`, because matching against the full `BaseModel` structure
7
+ * drags in its `fill(data: UpdatePayload<this>)` method — whose type loops back
8
+ * through `ColumnKeys`. For mutually-referential models (A.b: B, B.a: A) that
9
+ * feedback loop never bottoms out and TS reports TS2615. Resolving one branded
10
+ * property does not, so the cycle is broken. See `BaseModel.__isZerotalModel`.
11
+ */
12
+ type RelationBrand = { readonly __isZerotalModel: true };
13
+
14
+ // ── WritableKeys — exclude getter-only computed properties ───────────────────
15
+
16
+ /**
17
+ * Detect whether property K of T is writable (plain field or has a setter).
18
+ * Readonly getter-only properties resolve to `never` so they are excluded.
19
+ *
20
+ * Technique: compare { [P in K]: T[P] } against { -readonly [P in K]: T[P] }
21
+ * using TypeScript's structural equality check. They match only when K is
22
+ * not readonly.
23
+ */
24
+ type IfEquals<X, Y, A = X, B = never> =
25
+ (<G>() => G extends X ? 1 : 2) extends <G>() => G extends Y ? 1 : 2 ? A : B;
26
+
27
+ type WritableKeys<T> = {
28
+ [K in keyof T]-?: IfEquals<{ [P in K]: T[P] }, { -readonly [P in K]: T[P] }, K, never>;
29
+ }[keyof T];
30
+
31
+ // ── ColumnKeys — the set of properties that map to actual DB columns ─────────
32
+
33
+ /**
34
+ * Columns automatically managed by the ORM or the database engine.
35
+ * Excluded from both InsertPayload and UpdatePayload.
36
+ */
37
+ type AutoManagedKeys = "id" | "createdAt" | "updatedAt" | "deletedAt";
38
+
39
+ /**
40
+ * Extract the property keys of T that represent actual database columns.
41
+ *
42
+ * A key is a column key when ALL of the following hold:
43
+ * - It is writable (not a getter-only computed property)
44
+ * - It does not start with `_` (internal ORM bookkeeping)
45
+ * - Its non-null value does NOT extend BaseModel or BaseModel[]
46
+ * (i.e. it is not a relation — BelongsTo, HasMany, ManyToMany, etc.)
47
+ * - Its value is not a function / method
48
+ *
49
+ * This correctly INCLUDES:
50
+ * - Primitive columns: string, number, boolean
51
+ * - Date columns: Date, Carbon (Carbon is a standalone class, not Date)
52
+ * - JSON columns: Record<string, unknown>, any[] of non-model values
53
+ * - Nullable variants: string | null, Carbon | null, etc.
54
+ *
55
+ * And correctly EXCLUDES:
56
+ * - Relation properties typed as Post[], User, ManyToMany<Tag>, …
57
+ * - Methods (save, delete, toJSON, …)
58
+ * - Internal fields (_exists, _original, _zerotal_*)
59
+ * - Getter-only computed properties (isVerified, isPublished, …)
60
+ */
61
+
62
+ type ColumnKeys<T> = WritableKeys<T> &
63
+ {
64
+ [K in keyof T & string]-?: K extends `_${string}`
65
+ ? never
66
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ T[K] extends (...args: any[]) => any
68
+ ? never
69
+ : NonNullable<T[K]> extends RelationBrand | RelationBrand[]
70
+ ? never
71
+ : K;
72
+ }[keyof T & string];
73
+
74
+ // ── Public payload types ──────────────────────────────────────────────────────
75
+
76
+ /**
77
+ * Data shape required to create a new model record.
78
+ *
79
+ * - Retains all writable column properties, including Carbon dates and JSON
80
+ * columns, while stripping relations, methods, computed getters, and the
81
+ * ORM-managed fields (id, createdAt, updatedAt, deletedAt).
82
+ * - Preserves required (`name!: string`) vs optional (`role?: string`)
83
+ * exactly as declared on the model — no manual DTO needed.
84
+ *
85
+ * @example
86
+ * // In a controller:
87
+ * const user = await User.create(await ctx.body<InsertPayload<User>>());
88
+ *
89
+ * // Alias pattern (recommended — keeps controllers clean):
90
+ * export type NewUser = InsertPayload<User>;
91
+ * const user = await User.create({ name: "Alice", email: "alice@example.com", password: "…" });
92
+ */
93
+ export type InsertPayload<T> = Omit<Pick<T, ColumnKeys<T>>, AutoManagedKeys>;
94
+
95
+ /**
96
+ * Data shape accepted when updating an existing record.
97
+ * Every field is optional — pass only what should change.
98
+ *
99
+ * @example
100
+ * const user = await User.findOrFail(ctx.integer("id"));
101
+ * await user.update(await ctx.body<UpdatePayload<User>>());
102
+ *
103
+ * // Alias pattern:
104
+ * export type UserPatch = UpdatePayload<User>;
105
+ */
106
+ export type UpdatePayload<T> = Partial<InsertPayload<T>>;
107
+
108
+ /**
109
+ * Union of all data-column property names on a model class.
110
+ *
111
+ * Re-exported here as a convenience alongside InsertPayload / UpdatePayload.
112
+ * Primary definition lives in BaseModel.ts.
113
+ */
114
+ export type { Columns } from "./BaseModel.ts";