@simplysm/orm-common 13.0.78 → 13.0.80

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 (2) hide show
  1. package/package.json +2 -2
  2. package/README.md +0 -647
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/orm-common",
3
- "version": "13.0.78",
3
+ "version": "13.0.80",
4
4
  "description": "Simplysm Package - ORM Module (common)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -19,6 +19,6 @@
19
19
  ],
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
- "@simplysm/core-common": "13.0.78"
22
+ "@simplysm/core-common": "13.0.80"
23
23
  }
24
24
  }
package/README.md DELETED
@@ -1,647 +0,0 @@
1
- # @simplysm/orm-common
2
-
3
- Shared ORM infrastructure for the Simplysm framework. Provides schema builders, a type-safe query builder (`Queryable`), a dialect-independent expression DSL (`expr`), a multi-dialect SQL generator, and supporting utilities. Used by both server-side (`orm-node`) and client-side ORM packages.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pnpm add @simplysm/orm-common
9
- ```
10
-
11
- ---
12
-
13
- ## Table of Contents
14
-
15
- - [Core](#core)
16
- - [Queryable / Executable](#queryable--executable)
17
- - [Expressions](#expressions)
18
- - [Schema Builders](#schema-builders)
19
- - [Models](#models)
20
- - [Query Builder](#query-builder)
21
- - [Types](#types)
22
-
23
- ---
24
-
25
- ## Core
26
-
27
- Define and instantiate database contexts.
28
-
29
- | Symbol | Description |
30
- |---|---|
31
- | `defineDbContext(config)` | Create a `DbContextDef` blueprint from tables, views, procedures, and migrations |
32
- | `createDbContext(def, executor, opt)` | Instantiate a fully operational `DbContextInstance` |
33
-
34
- ### `defineDbContext(config)`
35
-
36
- ```typescript
37
- import { defineDbContext } from "@simplysm/orm-common";
38
-
39
- const MyDb = defineDbContext({
40
- tables: { user: User, post: Post },
41
- views: { userSummary: UserSummary },
42
- procedures: { getUserById: GetUserById },
43
- migrations: [...],
44
- });
45
- ```
46
-
47
- - `config.tables` — `Record<string, TableBuilder>` (optional)
48
- - `config.views` — `Record<string, ViewBuilder>` (optional)
49
- - `config.procedures` — `Record<string, ProcedureBuilder>` (optional)
50
- - `config.migrations` — `Migration[]` (optional)
51
- - Returns `DbContextDef` — always includes the built-in `_migration` table
52
-
53
- ### `createDbContext(def, executor, opt)`
54
-
55
- ```typescript
56
- import { createDbContext } from "@simplysm/orm-common";
57
-
58
- const db = createDbContext(MyDb, executor, { database: "mydb", schema: "dbo" });
59
-
60
- await db.connect(async () => {
61
- const users = await db.user().execute();
62
- });
63
- ```
64
-
65
- - `def` — `DbContextDef` created by `defineDbContext()`
66
- - `executor` — `DbContextExecutor` (e.g. `NodeDbContextExecutor`, `ServiceDbContextExecutor`)
67
- - `opt.database` — database name (required)
68
- - `opt.schema` — schema name for MSSQL/PostgreSQL (optional)
69
- - Returns `DbContextInstance<TDef>` — includes typed queryable/executable accessors, DDL methods, and connection management
70
-
71
- **Connection / Transaction methods on the returned instance:**
72
-
73
- | Method | Description |
74
- |---|---|
75
- | `connect(fn, isolationLevel?)` | Open connection, start transaction, run `fn`, commit; rollback on error |
76
- | `connectWithoutTransaction(fn)` | Open connection without a transaction, run `fn`, close |
77
- | `transaction(fn, isolationLevel?)` | Start a transaction within an already-connected context |
78
- | `initialize(options?)` | Run pending migrations (`options.dbs`, `options.force`) |
79
-
80
- **DDL execution methods** (requires `connectWithoutTransaction`):
81
-
82
- `createTable`, `dropTable`, `renameTable`, `createView`, `dropView`, `createProc`, `dropProc`, `addColumn`, `dropColumn`, `modifyColumn`, `renameColumn`, `addPrimaryKey`, `dropPrimaryKey`, `addForeignKey`, `addIndex`, `dropForeignKey`, `dropIndex`, `clearSchema`, `schemaExists`, `truncate`, `switchFk`
83
-
84
- **DDL `QueryDef` generator methods** (return `QueryDef` without executing):
85
-
86
- `getCreateTableQueryDef`, `getCreateViewQueryDef`, `getCreateProcQueryDef`, `getCreateObjectQueryDef`, `getDropTableQueryDef`, `getRenameTableQueryDef`, `getDropViewQueryDef`, `getDropProcQueryDef`, `getAddColumnQueryDef`, `getDropColumnQueryDef`, `getModifyColumnQueryDef`, `getRenameColumnQueryDef`, `getAddPrimaryKeyQueryDef`, `getDropPrimaryKeyQueryDef`, `getAddForeignKeyQueryDef`, `getAddIndexQueryDef`, `getDropForeignKeyQueryDef`, `getDropIndexQueryDef`, `getClearSchemaQueryDef`, `getSchemaExistsQueryDef`, `getTruncateQueryDef`, `getSwitchFkQueryDef`
87
-
88
- ---
89
-
90
- ## Queryable / Executable
91
-
92
- Type-safe query and procedure execution.
93
-
94
- | Symbol | Description |
95
- |---|---|
96
- | `Queryable<TData, TFrom>` | Fluent SELECT / INSERT / UPDATE / DELETE / UPSERT builder |
97
- | `queryable(db, tableOrView, alias?)` | Factory returning a `() => Queryable` accessor |
98
- | `Executable<TParams, TReturns>` | Stored procedure execution wrapper |
99
- | `executable(db, builder)` | Factory returning a `() => Executable` accessor |
100
- | `parseSearchQuery(searchText)` | Parse a user search string into SQL LIKE pattern groups |
101
- | `parseQueryResult(rawResults, meta)` | Transform flat DB rows into nested TypeScript objects |
102
- | `QueryableRecord<TData>` | Maps `DataRecord` fields to `ExprUnit` counterparts (used in callbacks) |
103
- | `QueryableWriteRecord<TData>` | Maps `DataRecord` fields to `ExprInput` counterparts (used in write callbacks) |
104
- | `NullableQueryableRecord<TData>` | Like `QueryableRecord` but all primitives include `\| undefined` (LEFT JOIN propagation) |
105
- | `UnwrapQueryableRecord<R>` | Reverses `QueryableRecord` — `ExprUnit<T>` → `T` |
106
- | `PathProxy<TObject>` | Type-safe relation-path proxy used by `include()` |
107
- | `ParsedSearchQuery` | Return type of `parseSearchQuery` |
108
- | `getMatchedPrimaryKeys(fkCols, targetTable)` | Match FK column array to target table PK columns |
109
-
110
- ### `Queryable<TData, TFrom>`
111
-
112
- The central query builder. Constructed via `queryable()` and the table/view accessors on a `DbContextInstance`.
113
-
114
- **Query shaping methods** (all return a new `Queryable`):
115
-
116
- | Method | Description |
117
- |---|---|
118
- | `.select(fn)` | Map columns to a new shape |
119
- | `.distinct()` | Apply DISTINCT |
120
- | `.lock()` | Apply FOR UPDATE row lock |
121
- | `.top(count)` | Limit to first N rows (no ORDER BY required) |
122
- | `.limit(skip, take)` | Paginate (requires `.orderBy()` first) |
123
- | `.orderBy(fn, dir?)` | Add ORDER BY column (stackable, default ASC) |
124
- | `.where(predicate)` | Add WHERE condition (stackable, AND-combined) |
125
- | `.search(fn, searchText)` | Full-text LIKE search against multiple columns |
126
- | `.groupBy(fn)` | Add GROUP BY |
127
- | `.having(predicate)` | Add HAVING condition (stackable, AND-combined) |
128
- | `.join(as, fn)` | LEFT OUTER JOIN — result added as array (`1:N`) |
129
- | `.joinSingle(as, fn)` | LEFT OUTER JOIN — result added as single object (`N:1` / `1:1`) |
130
- | `.include(fn)` | Auto-JOIN a defined relation by path (uses `PathProxy`) |
131
- | `.wrap()` | Wrap current query as subquery |
132
- | `Queryable.union(...queries)` | Static UNION ALL of multiple queryables |
133
- | `.recursive(fn)` | Build a recursive CTE (WITH RECURSIVE) |
134
-
135
- **Execution methods:**
136
-
137
- | Method | Returns | Description |
138
- |---|---|---|
139
- | `.execute()` | `Promise<TData[]>` | Run SELECT, return all rows |
140
- | `.single()` | `Promise<TData \| undefined>` | Return single row (throws if > 1) |
141
- | `.first()` | `Promise<TData \| undefined>` | Return first row |
142
- | `.count(fn?)` | `Promise<number>` | Return row count |
143
- | `.exists()` | `Promise<boolean>` | Return whether any rows match |
144
- | `.insert(records, outputColumns?)` | `Promise<void \| Pick[]>` | INSERT (chunked at 1000) |
145
- | `.insertIfNotExists(record, outputColumns?)` | `Promise<void \| Pick>` | INSERT if WHERE finds no match |
146
- | `.insertInto(targetTable, outputColumns?)` | `Promise<void \| Pick[]>` | INSERT INTO … SELECT |
147
- | `.update(recordFwd, outputColumns?)` | `Promise<void \| Pick[]>` | UPDATE matched rows |
148
- | `.delete(outputColumns?)` | `Promise<void \| Pick[]>` | DELETE matched rows |
149
- | `.upsert(updateFn, insertFn?, outputColumns?)` | `Promise<void \| Pick[]>` | INSERT or UPDATE (MERGE pattern) |
150
- | `.switchFk(enabled)` | `Promise<void>` | Enable/disable FK constraints on this table |
151
-
152
- **`QueryDef` generator methods** (without executing):
153
-
154
- `getSelectQueryDef()`, `getResultMeta(outputColumns?)`, `getInsertQueryDef(records, outputColumns?)`, `getInsertIfNotExistsQueryDef(record, outputColumns?)`, `getInsertIntoQueryDef(targetTable, outputColumns?)`, `getUpdateQueryDef(recordFwd, outputColumns?)`, `getDeleteQueryDef(outputColumns?)`, `getUpsertQueryDef(updateFn, insertFn, outputColumns?)`
155
-
156
- ```typescript
157
- import { queryable, expr } from "@simplysm/orm-common";
158
-
159
- // In a DbContext definition (createDbContext handles this automatically)
160
- const userAccessor = queryable(db, User);
161
-
162
- // Using the accessor
163
- const activeUsers = await userAccessor()
164
- .where((u) => [expr.eq(u.isActive, true)])
165
- .orderBy((u) => u.name)
166
- .execute();
167
- ```
168
-
169
- ### `Executable<TParams, TReturns>`
170
-
171
- ```typescript
172
- import { executable } from "@simplysm/orm-common";
173
-
174
- // Factory used internally by createDbContext
175
- const proc = executable(db, GetUserById);
176
- const result = await proc().execute({ userId: 1n });
177
- ```
178
-
179
- Methods on `Executable`:
180
- - `.execute(params)` — run the stored procedure, returns `Promise<InferColumnExprs<TReturns>[][]>`
181
- - `.getExecProcQueryDef(params?)` — return `ExecProcQueryDef` without executing
182
-
183
- ### `parseSearchQuery(searchText)`
184
-
185
- Parse a user-entered search string into SQL LIKE patterns.
186
-
187
- ```typescript
188
- import { parseSearchQuery } from "@simplysm/orm-common";
189
-
190
- parseSearchQuery('apple "delicious fruit" -banana +strawberry');
191
- // { or: ["%apple%"], must: ["%delicious fruit%", "%strawberry%"], not: ["%banana%"] }
192
- ```
193
-
194
- Returns `ParsedSearchQuery`:
195
-
196
- ```typescript
197
- interface ParsedSearchQuery {
198
- or: string[]; // OR conditions — LIKE patterns
199
- must: string[]; // AND conditions (+ prefix or quoted)
200
- not: string[]; // NOT conditions (- prefix)
201
- }
202
- ```
203
-
204
- Search syntax:
205
-
206
- | Syntax | Meaning |
207
- |---|---|
208
- | `term1 term2` | OR — one of them matches |
209
- | `+term` | Required (AND) |
210
- | `-term` | Excluded (NOT) |
211
- | `"exact phrase"` | Exact match (required) |
212
- | `*` | Wildcard → `%` |
213
-
214
- ### `parseQueryResult(rawResults, meta)`
215
-
216
- Transform flat DB rows (with dot-notation keys) into nested TypeScript objects.
217
-
218
- ```typescript
219
- import { parseQueryResult } from "@simplysm/orm-common";
220
-
221
- const raw = [
222
- { id: 1, name: "User1", "posts.id": 10, "posts.title": "Post1" },
223
- { id: 1, name: "User1", "posts.id": 11, "posts.title": "Post2" },
224
- ];
225
- const meta = {
226
- columns: { id: "number", name: "string", "posts.id": "number", "posts.title": "string" },
227
- joins: { posts: { isSingle: false } }
228
- };
229
- const result = await parseQueryResult(raw, meta);
230
- // [{ id: 1, name: "User1", posts: [{ id: 10, title: "Post1" }, { id: 11, title: "Post2" }] }]
231
- ```
232
-
233
- - Returns `Promise<TRecord[] | undefined>` — `undefined` if input is empty or all parsed records are empty
234
-
235
- ---
236
-
237
- ## Expressions
238
-
239
- Dialect-independent SQL expression DSL.
240
-
241
- | Symbol | Description |
242
- |---|---|
243
- | `expr` | Expression builder object — comparisons, string/number/date functions, aggregates, window functions |
244
- | `ExprUnit<TPrimitive>` | Type-safe AST wrapper for a SQL expression |
245
- | `WhereExprUnit` | AST wrapper for WHERE/HAVING boolean expressions |
246
- | `ExprInput<TPrimitive>` | `ExprUnit<T> \| T` — accepts raw values alongside expression nodes |
247
- | `SwitchExprBuilder<TPrimitive>` | Builder returned by `expr.switch()` for constructing CASE WHEN chains |
248
-
249
- ### `expr`
250
-
251
- The `expr` object provides methods to build SQL expressions as JSON AST nodes. `QueryBuilderBase` then converts these to dialect-specific SQL.
252
-
253
- **Value creation:**
254
-
255
- | Method | SQL equivalent |
256
- |---|---|
257
- | `expr.val(dataType, value)` | Literal value |
258
- | `expr.col(dataType, ...path)` | Column reference |
259
- | `expr.raw(sql, ...params)` | Raw SQL fragment |
260
-
261
- **Comparison (return `WhereExprUnit`):**
262
-
263
- `expr.eq(a, b)`, `expr.gt(a, b)`, `expr.lt(a, b)`, `expr.gte(a, b)`, `expr.lte(a, b)`, `expr.between(src, from, to)`, `expr.null(arg)`, `expr.like(src, pattern)`, `expr.regexp(src, pattern)`, `expr.in(src, values)`, `expr.inQuery(src, query)`, `expr.exists(query)`
264
-
265
- **Logic (return `WhereExprUnit`):**
266
-
267
- `expr.not(cond)`, `expr.and(conditions)`, `expr.or(conditions)`
268
-
269
- **String functions:**
270
-
271
- `expr.concat(...args)`, `expr.left(src, len)`, `expr.right(src, len)`, `expr.trim(arg)`, `expr.padStart(src, len, fill)`, `expr.replace(src, from, to)`, `expr.upper(arg)`, `expr.lower(arg)`, `expr.length(arg)`, `expr.byteLength(arg)`, `expr.substring(src, start, len?)`, `expr.indexOf(src, search)`
272
-
273
- **Number functions:**
274
-
275
- `expr.abs(arg)`, `expr.round(arg, digits)`, `expr.ceil(arg)`, `expr.floor(arg)`
276
-
277
- **Date functions:**
278
-
279
- `expr.year(arg)`, `expr.month(arg)`, `expr.day(arg)`, `expr.hour(arg)`, `expr.minute(arg)`, `expr.second(arg)`, `expr.isoWeek(arg)`, `expr.isoWeekStartDate(arg)`, `expr.isoYearMonth(arg)`, `expr.dateDiff(unit, from, to)`, `expr.dateAdd(unit, src, value)`, `expr.formatDate(src, format)`
280
-
281
- **Condition functions:**
282
-
283
- `expr.coalesce(...args)`, `expr.nullIf(src, value)`, `expr.is(condition)`, `expr.switch(dataType)` → `SwitchExprBuilder`, `expr.if(condition, then, else?)`
284
-
285
- **Aggregate functions:**
286
-
287
- `expr.count(arg?, distinct?)`, `expr.sum(arg)`, `expr.avg(arg)`, `expr.max(arg)`, `expr.min(arg)`, `expr.greatest(...args)`, `expr.least(...args)`
288
-
289
- **Other:**
290
-
291
- `expr.rowNum()`, `expr.random()`, `expr.cast(src, targetType)`, `expr.toExpr(value)`, `expr.subquery(queryable, fn)`
292
-
293
- **Window functions:**
294
-
295
- `expr.window(fn, spec)` — takes a `WinFn` and `WinSpec`
296
-
297
- ```typescript
298
- import { expr } from "@simplysm/orm-common";
299
-
300
- // WHERE condition
301
- db.user().where((u) => [
302
- expr.eq(u.status, "active"),
303
- expr.gt(u.age, 18),
304
- ])
305
-
306
- // SELECT expression
307
- db.user().select((u) => ({
308
- fullName: expr.concat(u.firstName, " ", u.lastName),
309
- age: expr.dateDiff("year", u.birthDate, expr.val("DateOnly", DateOnly.today())),
310
- }))
311
-
312
- // Aggregate
313
- db.order().groupBy((o) => [o.userId]).select((o) => ({
314
- userId: o.userId,
315
- total: expr.sum(o.amount),
316
- }))
317
- ```
318
-
319
- ### `ExprUnit<TPrimitive>`
320
-
321
- Type-safe wrapper around an `Expr` AST node.
322
-
323
- ```typescript
324
- class ExprUnit<TPrimitive extends ColumnPrimitive> {
325
- readonly $infer: TPrimitive;
326
- readonly dataType: ColumnPrimitiveStr;
327
- readonly expr: Expr;
328
- get n(): ExprUnit<NonNullable<TPrimitive>>; // strip undefined from type
329
- }
330
- ```
331
-
332
- ### `WhereExprUnit`
333
-
334
- Wrapper around a `WhereExpr` AST node. Used in `.where()` and `.having()` callbacks.
335
-
336
- ```typescript
337
- class WhereExprUnit {
338
- readonly expr: WhereExpr;
339
- }
340
- ```
341
-
342
- ### `SwitchExprBuilder<TPrimitive>`
343
-
344
- Builder for CASE WHEN expressions, returned by `expr.switch(dataType)`.
345
-
346
- ```typescript
347
- interface SwitchExprBuilder<TPrimitive extends ColumnPrimitive> {
348
- case(condition: WhereExprUnit, then: ExprInput<TPrimitive>): SwitchExprBuilder<TPrimitive>;
349
- default(value: ExprInput<TPrimitive>): ExprUnit<TPrimitive>;
350
- }
351
- ```
352
-
353
- ---
354
-
355
- ## Schema Builders
356
-
357
- Fluent builders for tables, views, procedures, columns, indexes, and relationships.
358
-
359
- | Symbol | Description |
360
- |---|---|
361
- | `Table(name)` | Create a `TableBuilder` |
362
- | `TableBuilder<TColumns, TRelations>` | Immutable table schema definition with type-inference properties |
363
- | `View(name)` | Create a `ViewBuilder` |
364
- | `ViewBuilder<TDbContext, TData, TRelations>` | Immutable view schema definition |
365
- | `Procedure(name)` | Create a `ProcedureBuilder` |
366
- | `ProcedureBuilder<TParams, TReturns>` | Immutable stored procedure schema definition |
367
- | `ColumnBuilder<TValue, TMeta>` | Column definition with `nullable()`, `default()`, `autoIncrement()`, `description()` |
368
- | `createColumnFactory()` | Returns column factory (`c.int()`, `c.varchar()`, `c.datetime()`, …) |
369
- | `IndexBuilder<TKeys>` | Index definition with `unique()`, `orderBy()`, `name()`, `description()` |
370
- | `createIndexFactory<TColumnKey>()` | Returns index factory used in `indexes()` callbacks |
371
- | `ForeignKeyBuilder<TOwner, TTargetFn>` | N:1 FK relationship (creates DB constraint) |
372
- | `ForeignKeyTargetBuilder<TTargetTableFn, TIsSingle>` | 1:N FK back-reference |
373
- | `RelationKeyBuilder<TOwner, TTargetFn>` | N:1 logical relationship (no DB constraint) |
374
- | `RelationKeyTargetBuilder<TTargetTableFn, TIsSingle>` | 1:N logical back-reference |
375
- | `createRelationFactory<TOwner, TColumnKey>(ownerFn)` | Returns relation factory used in `relations()` callbacks |
376
-
377
- ### `Table(name)` / `TableBuilder`
378
-
379
- ```typescript
380
- import { Table } from "@simplysm/orm-common";
381
-
382
- const User = Table("User")
383
- .database("mydb")
384
- .columns((c) => ({
385
- id: c.bigint().autoIncrement(),
386
- name: c.varchar(100),
387
- email: c.varchar(200).nullable(),
388
- status: c.varchar(20).default("active"),
389
- createdAt: c.datetime().description("Record creation timestamp"),
390
- }))
391
- .primaryKey("id")
392
- .indexes((i) => [i.index("email").unique()])
393
- .relations((r) => ({
394
- posts: r.foreignKeyTarget(() => Post, "author"),
395
- }));
396
- ```
397
-
398
- `TableBuilder` methods: `.database(db)`, `.schema(schema)`, `.description(desc)`, `.columns(fn)`, `.primaryKey(...cols)`, `.indexes(fn)`, `.relations(fn)`
399
-
400
- Type inference properties: `$inferSelect`, `$inferColumns`, `$inferInsert`, `$inferUpdate`, `$columns`, `$relations`
401
-
402
- ### `View(name)` / `ViewBuilder`
403
-
404
- ```typescript
405
- import { View } from "@simplysm/orm-common";
406
-
407
- const ActiveUsers = View("ActiveUsers")
408
- .database("mydb")
409
- .query((db: MyDb) =>
410
- db.user()
411
- .where((u) => [expr.eq(u.status, "active")])
412
- .select((u) => ({ id: u.id, name: u.name }))
413
- );
414
- ```
415
-
416
- `ViewBuilder` methods: `.database(db)`, `.schema(schema)`, `.description(desc)`, `.query(viewFn)`, `.relations(fn)`
417
-
418
- ### `Procedure(name)` / `ProcedureBuilder`
419
-
420
- ```typescript
421
- import { Procedure } from "@simplysm/orm-common";
422
-
423
- const GetUserById = Procedure("GetUserById")
424
- .database("mydb")
425
- .params((c) => ({ userId: c.bigint() }))
426
- .returns((c) => ({ id: c.bigint(), name: c.varchar(100) }))
427
- .body("SELECT id, name FROM User WHERE id = userId");
428
- ```
429
-
430
- `ProcedureBuilder` methods: `.database(db)`, `.schema(schema)`, `.description(desc)`, `.params(fn)`, `.returns(fn)`, `.body(sql)`
431
-
432
- ### `createColumnFactory()`
433
-
434
- Returns an object with typed column factory methods:
435
-
436
- | Factory method | SQL type | TypeScript type |
437
- |---|---|---|
438
- | `c.int()` | INT | `number` |
439
- | `c.bigint()` | BIGINT | `number` |
440
- | `c.float()` | FLOAT | `number` |
441
- | `c.double()` | DOUBLE | `number` |
442
- | `c.decimal(precision, scale?)` | DECIMAL | `number` |
443
- | `c.varchar(length)` | VARCHAR | `string` |
444
- | `c.char(length)` | CHAR | `string` |
445
- | `c.text()` | TEXT | `string` |
446
- | `c.binary()` | BLOB/VARBINARY/BYTEA | `Bytes` |
447
- | `c.boolean()` | TINYINT/BIT/BOOLEAN | `boolean` |
448
- | `c.datetime()` | DATETIME | `DateTime` |
449
- | `c.date()` | DATE | `DateOnly` |
450
- | `c.time()` | TIME | `Time` |
451
- | `c.uuid()` | BINARY/UNIQUEIDENTIFIER/UUID | `Uuid` |
452
-
453
- `ColumnBuilder` modifier methods: `.autoIncrement()`, `.nullable()`, `.default(value)`, `.description(desc)`
454
-
455
- ### `createIndexFactory<TColumnKey>()`
456
-
457
- Returns `{ index(...columns) }`. The resulting `IndexBuilder` has: `.name(name)`, `.unique()`, `.orderBy(...dirs)`, `.description(desc)`
458
-
459
- ### `createRelationFactory<TOwner, TColumnKey>(ownerFn)`
460
-
461
- Returns a factory with methods:
462
- - `r.foreignKey(columns, targetFn)` → `ForeignKeyBuilder` (Tables only — creates DB FK constraint)
463
- - `r.foreignKeyTarget(targetTableFn, relationName)` → `ForeignKeyTargetBuilder` (Tables only)
464
- - `r.relationKey(columns, targetFn)` → `RelationKeyBuilder` (Tables and Views — no DB FK)
465
- - `r.relationKeyTarget(targetTableFn, relationName)` → `RelationKeyTargetBuilder` (Tables and Views)
466
-
467
- `ForeignKeyTargetBuilder` and `RelationKeyTargetBuilder` both have a `.single()` method to mark the relationship as 1:1 (returns a single object instead of an array).
468
-
469
- ---
470
-
471
- ## Models
472
-
473
- | Symbol | Description |
474
- |---|---|
475
- | `_Migration` | Built-in system table for tracking applied migrations |
476
-
477
- The `_Migration` table is always automatically included in every context created by `defineDbContext()`. It has a single `code: varchar(255)` primary-key column.
478
-
479
- ---
480
-
481
- ## Query Builder
482
-
483
- Multi-dialect SQL generator from `QueryDef` AST nodes.
484
-
485
- | Symbol | Description |
486
- |---|---|
487
- | `createQueryBuilder(dialect)` | Create a dialect-specific `QueryBuilderBase` |
488
- | `QueryBuilderBase` | Abstract base — `build(def): QueryBuildResult` |
489
- | `ExprRendererBase` | Abstract base for expression-to-SQL rendering |
490
- | `MysqlQueryBuilder` | MySQL implementation |
491
- | `MysqlExprRenderer` | MySQL expression renderer |
492
- | `MssqlQueryBuilder` | MSSQL implementation |
493
- | `MssqlExprRenderer` | MSSQL expression renderer |
494
- | `PostgresqlQueryBuilder` | PostgreSQL implementation |
495
- | `PostgresqlExprRenderer` | PostgreSQL expression renderer |
496
-
497
- ### `createQueryBuilder(dialect)`
498
-
499
- ```typescript
500
- import { createQueryBuilder } from "@simplysm/orm-common";
501
-
502
- const builder = createQueryBuilder("mysql");
503
- const { sql } = builder.build(selectQueryDef);
504
- ```
505
-
506
- - `dialect` — `"mysql" | "mssql" | "postgresql"`
507
- - Returns a `QueryBuilderBase` instance
508
-
509
- ### `QueryBuilderBase`
510
-
511
- Abstract class. Key public member:
512
-
513
- ```typescript
514
- abstract class QueryBuilderBase {
515
- build(def: QueryDef): QueryBuildResult;
516
- }
517
- ```
518
-
519
- ### `ExprRendererBase`
520
-
521
- Abstract class for rendering `Expr` AST nodes to SQL strings. Key public members:
522
-
523
- ```typescript
524
- abstract class ExprRendererBase {
525
- abstract wrap(name: string): string; // identifier quoting
526
- abstract escapeString(value: string): string; // string literal escaping
527
- abstract escapeValue(value: unknown): string; // value to SQL literal
528
- render(expr: Expr | WhereExpr): string;
529
- renderWhere(exprs: WhereExpr[]): string;
530
- }
531
- ```
532
-
533
- ---
534
-
535
- ## Types
536
-
537
- All type definitions and utility types.
538
-
539
- ### Database types
540
-
541
- | Symbol | Description |
542
- |---|---|
543
- | `Dialect` | `"mysql" \| "mssql" \| "postgresql"` |
544
- | `dialects` | `Dialect[]` — array of all supported dialects |
545
- | `QueryBuildResult` | `{ sql: string; resultSetIndex?: number; resultSetStride?: number }` |
546
- | `IsolationLevel` | `"READ_UNCOMMITTED" \| "READ_COMMITTED" \| "REPEATABLE_READ" \| "SERIALIZABLE"` |
547
- | `DataRecord` | `{ [key: string]: ColumnPrimitive \| DataRecord \| DataRecord[] }` — recursive result record |
548
- | `DbContextExecutor` | Interface for DB connection/execution: `connect`, `close`, `beginTransaction`, `commitTransaction`, `rollbackTransaction`, `executeDefs` |
549
- | `ResultMeta` | `{ columns: Record<string, ColumnPrimitiveStr>; joins: Record<string, { isSingle: boolean }> }` |
550
- | `Migration` | `{ name: string; up: (db) => Promise<void> }` — migration definition |
551
-
552
- ### Column types
553
-
554
- | Symbol | Description |
555
- |---|---|
556
- | `DataType` | SQL data type union: `{ type: "int" }`, `{ type: "varchar"; length }`, `{ type: "decimal"; precision; scale? }`, … |
557
- | `ColumnPrimitive` | `string \| number \| boolean \| DateTime \| DateOnly \| Time \| Uuid \| Bytes \| undefined` |
558
- | `ColumnPrimitiveStr` | `"string" \| "number" \| "boolean" \| "DateTime" \| "DateOnly" \| "Time" \| "Uuid" \| "Bytes"` |
559
- | `ColumnPrimitiveMap` | Map from `ColumnPrimitiveStr` to the actual TypeScript type |
560
- | `ColumnMeta` | `{ type, dataType, autoIncrement?, nullable?, default?, description? }` — column metadata |
561
- | `ColumnBuilderRecord` | `Record<string, ColumnBuilder<ColumnPrimitive, ColumnMeta>>` |
562
- | `InferColumns<T>` | Infer value types from a `ColumnBuilderRecord` |
563
- | `InferInsertColumns<T>` | Infer INSERT-time type (required/optional based on autoIncrement/nullable/default) |
564
- | `InferUpdateColumns<T>` | Infer UPDATE-time type (all fields optional) |
565
- | `InferColumnExprs<T>` | Map `ColumnBuilderRecord` fields to `ExprInput<V>` |
566
- | `RequiredInsertKeys<T>` | Keys without autoIncrement, nullable, or default |
567
- | `OptionalInsertKeys<T>` | Keys with autoIncrement, nullable, or default |
568
- | `DataToColumnBuilderRecord<TData>` | Convert a `DataRecord` type to a `ColumnBuilderRecord` |
569
- | `dataTypeStrToColumnPrimitiveStr` | Constant map from SQL type name to `ColumnPrimitiveStr` |
570
- | `inferColumnPrimitiveStr(value)` | Runtime function — infer `ColumnPrimitiveStr` from a value |
571
- | `InferColumnPrimitiveFromDataType<T>` | Compile-time infer TypeScript type from a `DataType` |
572
-
573
- ### Expression types
574
-
575
- **Union types:**
576
-
577
- | Symbol | Description |
578
- |---|---|
579
- | `Expr` | All value/string/number/date/condition/aggregate/window expression nodes |
580
- | `WhereExpr` | Comparison and logical expression nodes (for WHERE/HAVING) |
581
- | `WinFn` | Window function nodes union |
582
- | `WinSpec` | `{ partitionBy?: Expr[]; orderBy?: [Expr, ("ASC" \| "DESC")?][] }` |
583
- | `DateUnit` | `"year" \| "month" \| "day" \| "hour" \| "minute" \| "second"` |
584
-
585
- **Individual `Expr*` node types** (all exported):
586
-
587
- `ExprColumn`, `ExprValue`, `ExprRaw`, `ExprEq`, `ExprGt`, `ExprLt`, `ExprGte`, `ExprLte`, `ExprBetween`, `ExprIsNull`, `ExprLike`, `ExprRegexp`, `ExprIn`, `ExprInQuery`, `ExprExists`, `ExprNot`, `ExprAnd`, `ExprOr`, `ExprConcat`, `ExprLeft`, `ExprRight`, `ExprTrim`, `ExprPadStart`, `ExprReplace`, `ExprUpper`, `ExprLower`, `ExprLength`, `ExprByteLength`, `ExprSubstring`, `ExprIndexOf`, `ExprAbs`, `ExprRound`, `ExprCeil`, `ExprFloor`, `ExprYear`, `ExprMonth`, `ExprDay`, `ExprHour`, `ExprMinute`, `ExprSecond`, `ExprIsoWeek`, `ExprIsoWeekStartDate`, `ExprIsoYearMonth`, `ExprDateDiff`, `ExprDateAdd`, `ExprFormatDate`, `ExprCoalesce`, `ExprNullIf`, `ExprIs`, `ExprSwitch`, `ExprIf`, `ExprCount`, `ExprSum`, `ExprAvg`, `ExprMax`, `ExprMin`, `ExprGreatest`, `ExprLeast`, `ExprRowNum`, `ExprRandom`, `ExprCast`, `ExprWindow`, `ExprSubquery`
588
-
589
- **Individual `WinFn*` node types** (all exported):
590
-
591
- `WinFnRowNumber`, `WinFnRank`, `WinFnDenseRank`, `WinFnNtile`, `WinFnLag`, `WinFnLead`, `WinFnFirstValue`, `WinFnLastValue`, `WinFnSum`, `WinFnAvg`, `WinFnCount`, `WinFnMin`, `WinFnMax`
592
-
593
- ### QueryDef types
594
-
595
- **Union type:**
596
-
597
- | Symbol | Description |
598
- |---|---|
599
- | `QueryDef` | Union of all DML + DDL + Util + Meta query definition types |
600
- | `DDL_TYPES` | Readonly array of DDL type string literals (used to block DDL inside transactions) |
601
- | `DdlType` | Union of all DDL type string literals |
602
-
603
- **Individual `QueryDef` types** (all exported):
604
-
605
- `QueryDefObjectName`, `CudOutputDef`, `SelectQueryDef`, `SelectQueryDefJoin`, `InsertQueryDef`, `InsertIfNotExistsQueryDef`, `InsertIntoQueryDef`, `UpdateQueryDef`, `DeleteQueryDef`, `UpsertQueryDef`, `SwitchFkQueryDef`, `ClearSchemaQueryDef`, `CreateTableQueryDef`, `DropTableQueryDef`, `RenameTableQueryDef`, `TruncateQueryDef`, `AddColumnQueryDef`, `DropColumnQueryDef`, `ModifyColumnQueryDef`, `RenameColumnQueryDef`, `DropPrimaryKeyQueryDef`, `AddPrimaryKeyQueryDef`, `AddForeignKeyQueryDef`, `DropForeignKeyQueryDef`, `AddIndexQueryDef`, `DropIndexQueryDef`, `CreateViewQueryDef`, `DropViewQueryDef`, `CreateProcQueryDef`, `DropProcQueryDef`, `ExecProcQueryDef`, `SchemaExistsQueryDef`
606
-
607
- ### Relation types
608
-
609
- | Symbol | Description |
610
- |---|---|
611
- | `RelationBuilderRecord` | `Record<string, ForeignKeyBuilder \| ForeignKeyTargetBuilder \| RelationKeyBuilder \| RelationKeyTargetBuilder>` |
612
- | `ExtractRelationTarget<TRelation>` | Extract the referenced record type from a FK/RelationKey builder (N:1 — single object) |
613
- | `ExtractRelationTargetResult<TRelation>` | Extract the referenced record type from a FKTarget/RelationKeyTarget builder (1:N — array or single) |
614
- | `InferDeepRelations<TRelations>` | Map all relations to optional properties for `include()`-based loading |
615
-
616
- ### DbContext types
617
-
618
- | Symbol | Description |
619
- |---|---|
620
- | `DbContextBase` | Internal interface used by `Queryable`, `Executable`, and `ViewBuilder` |
621
- | `DbContextStatus` | `"ready" \| "connect" \| "transact"` |
622
- | `DbContextDef<TTables, TViews, TProcedures>` | Blueprint created by `defineDbContext()` |
623
- | `DbContextInstance<TDef>` | Full instance type returned by `createDbContext()` |
624
- | `DbContextConnectionMethods` | `connect`, `connectWithoutTransaction`, `transaction` |
625
- | `DbContextDdlMethods` | All DDL execution + `QueryDef` generator methods |
626
-
627
- ### Error types
628
-
629
- | Symbol | Description |
630
- |---|---|
631
- | `DbTransactionError` | Error class wrapping DBMS-specific transaction errors with a standardized `code` |
632
- | `DbErrorCode` | Enum: `NO_ACTIVE_TRANSACTION`, `TRANSACTION_ALREADY_STARTED`, `DEADLOCK`, `LOCK_TIMEOUT` |
633
-
634
- ```typescript
635
- import { DbTransactionError, DbErrorCode } from "@simplysm/orm-common";
636
-
637
- try {
638
- await executor.rollbackTransaction();
639
- } catch (err) {
640
- if (err instanceof DbTransactionError) {
641
- if (err.code === DbErrorCode.NO_ACTIVE_TRANSACTION) {
642
- return; // already rolled back — ignore
643
- }
644
- }
645
- throw err;
646
- }
647
- ```