@simplysm/orm-common 13.0.96 → 13.0.98

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.
@@ -0,0 +1,415 @@
1
+ # Schema Builders
2
+
3
+ Fluent API builders for defining tables, views, procedures, columns, indexes, and relations.
4
+
5
+ Source: `src/schema/table-builder.ts`, `src/schema/view-builder.ts`, `src/schema/procedure-builder.ts`, `src/schema/factory/column-builder.ts`, `src/schema/factory/index-builder.ts`, `src/schema/factory/relation-builder.ts`, `src/models/system-migration.ts`
6
+
7
+ ## Table / TableBuilder
8
+
9
+ ### Table (factory function)
10
+
11
+ ```typescript
12
+ function Table(name: string): TableBuilder<{}, {}>;
13
+ ```
14
+
15
+ ### TableBuilder
16
+
17
+ Immutable fluent builder. Each method returns a new instance.
18
+
19
+ ```typescript
20
+ class TableBuilder<
21
+ TColumns extends ColumnBuilderRecord,
22
+ TRelations extends RelationBuilderRecord,
23
+ > {
24
+ readonly meta: {
25
+ name: string;
26
+ description?: string;
27
+ database?: string;
28
+ schema?: string;
29
+ columns?: TColumns;
30
+ primaryKey?: (keyof TColumns & string)[];
31
+ relations?: TRelations;
32
+ indexes?: IndexBuilder<(keyof TColumns & string)[]>[];
33
+ };
34
+
35
+ // Type inference helpers
36
+ readonly $inferSelect: InferColumns<TColumns> & InferDeepRelations<TRelations>;
37
+ readonly $inferColumns: InferColumns<TColumns>;
38
+ readonly $inferInsert: InferInsertColumns<TColumns>;
39
+ readonly $inferUpdate: InferUpdateColumns<TColumns>;
40
+
41
+ description(desc: string): TableBuilder<TColumns, TRelations>;
42
+ database(db: string): TableBuilder<TColumns, TRelations>;
43
+ schema(schema: string): TableBuilder<TColumns, TRelations>;
44
+ columns<T extends ColumnBuilderRecord>(
45
+ fn: (c: ReturnType<typeof createColumnFactory>) => T,
46
+ ): TableBuilder<T, TRelations>;
47
+ primaryKey(...columns: (keyof TColumns & string)[]): TableBuilder<TColumns, TRelations>;
48
+ indexes(
49
+ fn: (i: ReturnType<typeof createIndexFactory<keyof TColumns & string>>) => IndexBuilder<string[]>[],
50
+ ): TableBuilder<TColumns, TRelations>;
51
+ relations<T extends RelationBuilderRecord>(
52
+ fn: (r: RelationFactory) => T,
53
+ ): TableBuilder<TColumns, T>;
54
+ }
55
+ ```
56
+
57
+ **Example:**
58
+
59
+ ```typescript
60
+ const User = Table("User")
61
+ .database("mydb")
62
+ .columns((c) => ({
63
+ id: c.bigint().autoIncrement(),
64
+ name: c.varchar(100),
65
+ email: c.varchar(200).nullable(),
66
+ status: c.varchar(20).default("active"),
67
+ createdAt: c.datetime(),
68
+ }))
69
+ .primaryKey("id")
70
+ .indexes((i) => [i.index("email").unique()])
71
+ .relations((r) => ({
72
+ posts: r.foreignKeyTarget(() => Post, "author"),
73
+ }));
74
+ ```
75
+
76
+ ---
77
+
78
+ ## View / ViewBuilder
79
+
80
+ ### View (factory function)
81
+
82
+ ```typescript
83
+ function View(name: string): ViewBuilder<any, any, {}>;
84
+ ```
85
+
86
+ ### ViewBuilder
87
+
88
+ ```typescript
89
+ class ViewBuilder<
90
+ TDbContext extends DbContextBase,
91
+ TData extends DataRecord,
92
+ TRelations extends RelationBuilderRecord,
93
+ > {
94
+ readonly meta: {
95
+ name: string;
96
+ description?: string;
97
+ database?: string;
98
+ schema?: string;
99
+ viewFn?: (db: TDbContext) => Queryable<TData, any>;
100
+ relations?: TRelations;
101
+ };
102
+
103
+ readonly $inferSelect: TData;
104
+
105
+ description(desc: string): ViewBuilder<TDbContext, TData, TRelations>;
106
+ database(db: string): ViewBuilder<TDbContext, TData, TRelations>;
107
+ schema(schema: string): ViewBuilder<TDbContext, TData, TRelations>;
108
+ query<TViewData extends DataRecord, TDb extends DbContextBase>(
109
+ viewFn: (db: TDb) => Queryable<TViewData, any>,
110
+ ): ViewBuilder<TDb, TViewData, TRelations>;
111
+ relations<T extends RelationBuilderRecord>(
112
+ fn: (r: RelationFactory) => T,
113
+ ): ViewBuilder<TDbContext, TData & InferDeepRelations<T>, TRelations>;
114
+ }
115
+ ```
116
+
117
+ **Example:**
118
+
119
+ ```typescript
120
+ const ActiveUsers = View("ActiveUsers")
121
+ .database("mydb")
122
+ .query((db: MyDb) =>
123
+ db.user()
124
+ .where((u) => [expr.eq(u.status, "active")])
125
+ .select((u) => ({ id: u.id, name: u.name, email: u.email }))
126
+ );
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Procedure / ProcedureBuilder
132
+
133
+ ### Procedure (factory function)
134
+
135
+ ```typescript
136
+ function Procedure(name: string): ProcedureBuilder<never, never>;
137
+ ```
138
+
139
+ ### ProcedureBuilder
140
+
141
+ ```typescript
142
+ class ProcedureBuilder<
143
+ TParams extends ColumnBuilderRecord,
144
+ TReturns extends ColumnBuilderRecord,
145
+ > {
146
+ readonly meta: {
147
+ name: string;
148
+ description?: string;
149
+ database?: string;
150
+ schema?: string;
151
+ params?: TParams;
152
+ returns?: TReturns;
153
+ query?: string;
154
+ };
155
+
156
+ description(desc: string): ProcedureBuilder<TParams, TReturns>;
157
+ database(db: string): ProcedureBuilder<TParams, TReturns>;
158
+ schema(schema: string): ProcedureBuilder<TParams, TReturns>;
159
+ params<T extends ColumnBuilderRecord>(
160
+ fn: (c: ReturnType<typeof createColumnFactory>) => T,
161
+ ): ProcedureBuilder<T, TReturns>;
162
+ returns<T extends ColumnBuilderRecord>(
163
+ fn: (c: ReturnType<typeof createColumnFactory>) => T,
164
+ ): ProcedureBuilder<TParams, T>;
165
+ body(sql: string): ProcedureBuilder<TParams, TReturns>;
166
+ }
167
+ ```
168
+
169
+ **Example:**
170
+
171
+ ```typescript
172
+ const GetUserById = Procedure("GetUserById")
173
+ .database("mydb")
174
+ .params((c) => ({ userId: c.bigint() }))
175
+ .returns((c) => ({ id: c.bigint(), name: c.varchar(100) }))
176
+ .body("SELECT id, name FROM User WHERE id = userId");
177
+ ```
178
+
179
+ ---
180
+
181
+ ## ColumnBuilder
182
+
183
+ Column definition builder used within `TableBuilder.columns()`.
184
+
185
+ ```typescript
186
+ class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnMeta> {
187
+ readonly meta: TMeta;
188
+
189
+ autoIncrement(): ColumnBuilder<TValue, TMeta & { autoIncrement: true }>;
190
+ nullable(): ColumnBuilder<TValue | undefined, TMeta & { nullable: true }>;
191
+ default(value: TValue): ColumnBuilder<TValue, TMeta & { default: typeof value }>;
192
+ description(desc: string): ColumnBuilder<TValue, TMeta & { description: string }>;
193
+ }
194
+ ```
195
+
196
+ ## createColumnFactory
197
+
198
+ Returns an object with methods for all column types.
199
+
200
+ ```typescript
201
+ function createColumnFactory(): {
202
+ int(): ColumnBuilder<number, ...>;
203
+ bigint(): ColumnBuilder<number, ...>;
204
+ float(): ColumnBuilder<number, ...>;
205
+ double(): ColumnBuilder<number, ...>;
206
+ decimal(precision: number, scale?: number): ColumnBuilder<number, ...>;
207
+ varchar(length: number): ColumnBuilder<string, ...>;
208
+ char(length: number): ColumnBuilder<string, ...>;
209
+ text(): ColumnBuilder<string, ...>;
210
+ binary(): ColumnBuilder<Bytes, ...>;
211
+ boolean(): ColumnBuilder<boolean, ...>;
212
+ datetime(): ColumnBuilder<DateTime, ...>;
213
+ date(): ColumnBuilder<DateOnly, ...>;
214
+ time(): ColumnBuilder<Time, ...>;
215
+ uuid(): ColumnBuilder<Uuid, ...>;
216
+ };
217
+ ```
218
+
219
+ **Example:**
220
+
221
+ ```typescript
222
+ Table("Product").columns((c) => ({
223
+ id: c.bigint().autoIncrement(),
224
+ name: c.varchar(100),
225
+ price: c.decimal(10, 2),
226
+ description: c.text().nullable(),
227
+ isActive: c.boolean().default(true),
228
+ createdAt: c.datetime(),
229
+ }))
230
+ ```
231
+
232
+ ---
233
+
234
+ ## IndexBuilder
235
+
236
+ Index definition builder used within `TableBuilder.indexes()`.
237
+
238
+ ```typescript
239
+ class IndexBuilder<TKeys extends string[]> {
240
+ readonly meta: {
241
+ columns: TKeys;
242
+ name?: string;
243
+ unique?: boolean;
244
+ orderBy?: { [K in keyof TKeys]: "ASC" | "DESC" };
245
+ description?: string;
246
+ };
247
+
248
+ name(name: string): IndexBuilder<TKeys>;
249
+ unique(): IndexBuilder<TKeys>;
250
+ orderBy(...orderBy: { [K in keyof TKeys]: "ASC" | "DESC" }): IndexBuilder<TKeys>;
251
+ description(description: string): IndexBuilder<TKeys>;
252
+ }
253
+ ```
254
+
255
+ ## createIndexFactory
256
+
257
+ ```typescript
258
+ function createIndexFactory<TColumnKey extends string>(): {
259
+ index<TKeys extends TColumnKey[]>(...columns: [...TKeys]): IndexBuilder<TKeys>;
260
+ };
261
+ ```
262
+
263
+ **Example:**
264
+
265
+ ```typescript
266
+ Table("User")
267
+ .columns((c) => ({ id: c.bigint(), email: c.varchar(200), name: c.varchar(100) }))
268
+ .indexes((i) => [
269
+ i.index("email").unique(),
270
+ i.index("name", "email").orderBy("ASC", "DESC"),
271
+ i.index("email").name("IX_User_Email"),
272
+ ]);
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Relation Builders
278
+
279
+ ### ForeignKeyBuilder
280
+
281
+ N:1 FK relation that creates a DB constraint.
282
+
283
+ ```typescript
284
+ class ForeignKeyBuilder<TOwner extends TableBuilder<any, any>, TTargetFn extends () => TableBuilder<any, any>> {
285
+ readonly meta: {
286
+ ownerFn: () => TOwner;
287
+ columns: string[];
288
+ targetFn: TTargetFn;
289
+ description?: string;
290
+ };
291
+
292
+ description(desc: string): ForeignKeyBuilder<TOwner, TTargetFn>;
293
+ }
294
+ ```
295
+
296
+ ### ForeignKeyTargetBuilder
297
+
298
+ 1:N FK reverse-reference. Loaded as array by default; call `.single()` for 1:1.
299
+
300
+ ```typescript
301
+ class ForeignKeyTargetBuilder<TTargetTableFn extends () => TableBuilder<any, any>, TIsSingle extends boolean> {
302
+ readonly meta: {
303
+ targetTableFn: TTargetTableFn;
304
+ relationName: string;
305
+ description?: string;
306
+ isSingle?: TIsSingle;
307
+ };
308
+
309
+ description(desc: string): ForeignKeyTargetBuilder<TTargetTableFn, TIsSingle>;
310
+ single(): ForeignKeyTargetBuilder<TTargetTableFn, true>;
311
+ }
312
+ ```
313
+
314
+ ### RelationKeyBuilder
315
+
316
+ N:1 logical relation (no DB FK constraint). Can be used in Views.
317
+
318
+ ```typescript
319
+ class RelationKeyBuilder<
320
+ TOwner extends TableBuilder<any, any> | ViewBuilder<any, any, any>,
321
+ TTargetFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
322
+ > {
323
+ readonly meta: {
324
+ ownerFn: () => TOwner;
325
+ columns: string[];
326
+ targetFn: TTargetFn;
327
+ description?: string;
328
+ };
329
+
330
+ description(desc: string): RelationKeyBuilder<TOwner, TTargetFn>;
331
+ }
332
+ ```
333
+
334
+ ### RelationKeyTargetBuilder
335
+
336
+ 1:N logical reverse-reference (no DB FK constraint). Can be used in Views.
337
+
338
+ ```typescript
339
+ class RelationKeyTargetBuilder<
340
+ TTargetTableFn extends () => TableBuilder<any, any> | ViewBuilder<any, any, any>,
341
+ TIsSingle extends boolean,
342
+ > {
343
+ readonly meta: {
344
+ targetTableFn: TTargetTableFn;
345
+ relationName: string;
346
+ description?: string;
347
+ isSingle?: TIsSingle;
348
+ };
349
+
350
+ description(desc: string): RelationKeyTargetBuilder<TTargetTableFn, TIsSingle>;
351
+ single(): RelationKeyTargetBuilder<TTargetTableFn, true>;
352
+ }
353
+ ```
354
+
355
+ ### createRelationFactory
356
+
357
+ ```typescript
358
+ function createRelationFactory<TOwner, TColumnKey extends string>(
359
+ ownerFn: () => TOwner,
360
+ ): TOwner extends TableBuilder<any, any>
361
+ ? RelationFkFactory & RelationRkFactory // Tables get both FK and RK
362
+ : RelationRkFactory; // Views get only RK
363
+ ```
364
+
365
+ Factory methods:
366
+ - `foreignKey(columns, targetFn)` -- N:1 FK (table only)
367
+ - `foreignKeyTarget(targetTableFn, relationName)` -- 1:N FK reverse-reference (table only)
368
+ - `relationKey(columns, targetFn)` -- N:1 logical relation
369
+ - `relationKeyTarget(targetTableFn, relationName)` -- 1:N logical reverse-reference
370
+
371
+ **Example:**
372
+
373
+ ```typescript
374
+ const Post = Table("Post")
375
+ .columns((c) => ({ id: c.bigint().autoIncrement(), authorId: c.bigint() }))
376
+ .primaryKey("id")
377
+ .relations((r) => ({
378
+ author: r.foreignKey(["authorId"], () => User),
379
+ }));
380
+
381
+ const User = Table("User")
382
+ .columns((c) => ({ id: c.bigint().autoIncrement(), name: c.varchar(100) }))
383
+ .primaryKey("id")
384
+ .relations((r) => ({
385
+ posts: r.foreignKeyTarget(() => Post, "author"),
386
+ profile: r.foreignKeyTarget(() => Profile, "user").single(),
387
+ }));
388
+ ```
389
+
390
+ ---
391
+
392
+ ## _Migration
393
+
394
+ Built-in system migration table. Automatically included by `defineDbContext`.
395
+
396
+ ```typescript
397
+ const _Migration = Table("_migration")
398
+ .columns((c) => ({ code: c.varchar(255) }))
399
+ .description("System Migration Table")
400
+ .primaryKey("code");
401
+ ```
402
+
403
+ ---
404
+
405
+ ## Type Inference Utilities
406
+
407
+ | Type | Description |
408
+ |------|-------------|
409
+ | `ColumnBuilderRecord` | `Record<string, ColumnBuilder<ColumnPrimitive, ColumnMeta>>` |
410
+ | `InferColumns<T>` | Map column builders to value types (`{ id: number; name: string; ... }`) |
411
+ | `InferInsertColumns<T>` | Required columns + Partial optional columns (autoIncrement/nullable/default are optional) |
412
+ | `InferUpdateColumns<T>` | All columns Partial |
413
+ | `InferColumnExprs<T>` | Map column builders to `ExprInput` types |
414
+ | `RelationBuilderRecord` | Record of FK/FKT/RK/RKT builders |
415
+ | `InferDeepRelations<T>` | Deep relation type inference (all relations optional) |