@simplysm/orm-common 13.0.76 → 13.0.77

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 (109) hide show
  1. package/README.md +575 -50
  2. package/dist/create-db-context.d.ts +1 -1
  3. package/dist/create-db-context.d.ts.map +1 -1
  4. package/dist/create-db-context.js +34 -27
  5. package/dist/create-db-context.js.map +1 -1
  6. package/dist/ddl/initialize.js +4 -4
  7. package/dist/ddl/initialize.js.map +1 -1
  8. package/dist/ddl/relation-ddl.d.ts +7 -7
  9. package/dist/ddl/relation-ddl.d.ts.map +1 -1
  10. package/dist/ddl/relation-ddl.js +18 -18
  11. package/dist/ddl/relation-ddl.js.map +1 -1
  12. package/dist/ddl/schema-ddl.d.ts +1 -1
  13. package/dist/ddl/schema-ddl.d.ts.map +1 -1
  14. package/dist/ddl/schema-ddl.js +2 -2
  15. package/dist/ddl/schema-ddl.js.map +1 -1
  16. package/dist/ddl/table-ddl.js +2 -2
  17. package/dist/ddl/table-ddl.js.map +1 -1
  18. package/dist/exec/queryable.d.ts +24 -24
  19. package/dist/exec/queryable.d.ts.map +1 -1
  20. package/dist/exec/queryable.js +37 -37
  21. package/dist/exec/queryable.js.map +1 -1
  22. package/dist/expr/expr-unit.js +1 -1
  23. package/dist/expr/expr-unit.js.map +1 -1
  24. package/dist/expr/expr.d.ts +9 -9
  25. package/dist/expr/expr.d.ts.map +1 -1
  26. package/dist/expr/expr.js +10 -10
  27. package/dist/expr/expr.js.map +1 -1
  28. package/dist/query-builder/base/expr-renderer-base.d.ts +2 -2
  29. package/dist/query-builder/base/expr-renderer-base.d.ts.map +1 -1
  30. package/dist/query-builder/base/query-builder-base.d.ts +7 -15
  31. package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
  32. package/dist/query-builder/base/query-builder-base.js +2 -2
  33. package/dist/query-builder/base/query-builder-base.js.map +1 -1
  34. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +4 -4
  35. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  36. package/dist/query-builder/mssql/mssql-expr-renderer.js +8 -8
  37. package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
  38. package/dist/query-builder/mssql/mssql-query-builder.d.ts +7 -7
  39. package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
  40. package/dist/query-builder/mssql/mssql-query-builder.js +7 -7
  41. package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
  42. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +4 -4
  43. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  44. package/dist/query-builder/mysql/mysql-expr-renderer.js +9 -9
  45. package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
  46. package/dist/query-builder/mysql/mysql-query-builder.d.ts +7 -7
  47. package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
  48. package/dist/query-builder/mysql/mysql-query-builder.js +11 -11
  49. package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
  50. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +4 -4
  51. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  52. package/dist/query-builder/postgresql/postgresql-expr-renderer.js +8 -8
  53. package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
  54. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts +7 -7
  55. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
  56. package/dist/query-builder/postgresql/postgresql-query-builder.js +7 -7
  57. package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
  58. package/dist/schema/procedure-builder.d.ts +1 -1
  59. package/dist/schema/table-builder.d.ts +1 -1
  60. package/dist/schema/table-builder.d.ts.map +1 -1
  61. package/dist/schema/table-builder.js +1 -1
  62. package/dist/schema/view-builder.d.ts +1 -1
  63. package/dist/schema/view-builder.d.ts.map +1 -1
  64. package/dist/schema/view-builder.js +1 -1
  65. package/dist/types/db-context-def.d.ts +18 -18
  66. package/dist/types/db-context-def.d.ts.map +1 -1
  67. package/dist/types/expr.d.ts +6 -6
  68. package/dist/types/expr.d.ts.map +1 -1
  69. package/dist/types/query-def.d.ts +15 -15
  70. package/dist/types/query-def.d.ts.map +1 -1
  71. package/dist/types/query-def.js +6 -6
  72. package/dist/utils/result-parser.d.ts.map +1 -1
  73. package/dist/utils/result-parser.js +44 -16
  74. package/dist/utils/result-parser.js.map +1 -1
  75. package/package.json +2 -2
  76. package/src/create-db-context.ts +36 -29
  77. package/src/ddl/initialize.ts +4 -4
  78. package/src/ddl/relation-ddl.ts +16 -16
  79. package/src/ddl/schema-ddl.ts +2 -2
  80. package/src/ddl/table-ddl.ts +2 -2
  81. package/src/exec/queryable.ts +58 -58
  82. package/src/expr/expr-unit.ts +1 -1
  83. package/src/expr/expr.ts +13 -13
  84. package/src/query-builder/base/expr-renderer-base.ts +2 -2
  85. package/src/query-builder/base/query-builder-base.ts +18 -14
  86. package/src/query-builder/mssql/mssql-expr-renderer.ts +11 -10
  87. package/src/query-builder/mssql/mssql-query-builder.ts +13 -13
  88. package/src/query-builder/mysql/mysql-expr-renderer.ts +12 -11
  89. package/src/query-builder/mysql/mysql-query-builder.ts +17 -17
  90. package/src/query-builder/postgresql/postgresql-expr-renderer.ts +11 -10
  91. package/src/query-builder/postgresql/postgresql-query-builder.ts +13 -13
  92. package/src/schema/procedure-builder.ts +1 -1
  93. package/src/schema/table-builder.ts +1 -1
  94. package/src/schema/view-builder.ts +1 -1
  95. package/src/types/db-context-def.ts +18 -18
  96. package/src/types/expr.ts +6 -6
  97. package/src/types/query-def.ts +31 -31
  98. package/src/utils/result-parser.ts +60 -16
  99. package/tests/db-context/create-db-context.spec.ts +6 -6
  100. package/tests/ddl/basic.expected.ts +8 -8
  101. package/tests/ddl/basic.spec.ts +24 -24
  102. package/tests/ddl/index-builder.spec.ts +10 -10
  103. package/tests/ddl/relation-builder.spec.ts +4 -4
  104. package/tests/dml/update.spec.ts +2 -2
  105. package/tests/expr/conditional.expected.ts +2 -2
  106. package/tests/expr/conditional.spec.ts +8 -8
  107. package/tests/expr/date.spec.ts +5 -5
  108. package/tests/select/basic.spec.ts +5 -5
  109. package/tests/utils/result-parser.spec.ts +4 -4
package/README.md CHANGED
@@ -16,6 +16,7 @@ pnpm add @simplysm/orm-common
16
16
  - [Queryable / Executable](#queryable--executable)
17
17
  - [Expressions](#expressions)
18
18
  - [Schema Builders](#schema-builders)
19
+ - [Models](#models)
19
20
  - [Query Builder](#query-builder)
20
21
  - [Types](#types)
21
22
 
@@ -23,100 +24,624 @@ pnpm add @simplysm/orm-common
23
24
 
24
25
  ## Core
25
26
 
26
- Define and instantiate database contexts. [`docs/core.md`](docs/core.md)
27
+ Define and instantiate database contexts.
27
28
 
28
29
  | Symbol | Description |
29
30
  |---|---|
30
- | [`defineDbContext(config)`](docs/core.md#definedbcontextconfig) | Create a `DbContextDef` blueprint from tables, views, procedures, and migrations |
31
- | [`createDbContext(def, executor, opt)`](docs/core.md#createdbcontextdef-executor-opt) | Instantiate a fully operational `DbContextInstance` |
32
- | [`_Migration`](docs/core.md#_migration) | Built-in system table for tracking applied migrations |
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`
33
87
 
34
88
  ---
35
89
 
36
90
  ## Queryable / Executable
37
91
 
38
- Type-safe query and procedure execution. [`docs/queryable.md`](docs/queryable.md)
92
+ Type-safe query and procedure execution.
39
93
 
40
94
  | Symbol | Description |
41
95
  |---|---|
42
- | [`Queryable<TData, TFrom>`](docs/queryable.md#queryabletdata-tfrom) | Fluent SELECT / INSERT / UPDATE / DELETE / UPSERT builder |
43
- | [`queryable(db, tableOrView, alias?)`](docs/queryable.md#queryabledb-tableorview-alias) | Factory returning a `() => Queryable` accessor |
44
- | [`Executable<TParams, TReturns>`](docs/queryable.md#executabletparams-treturns) | Stored procedure execution wrapper |
45
- | [`executable(db, builder)`](docs/queryable.md#executabledb-builder) | Factory returning a `() => Executable` accessor |
46
- | [`parseSearchQuery(searchText)`](docs/queryable.md#parsesearchquerysearchtext) | Parse a user search string into SQL LIKE pattern groups |
47
- | [`parseQueryResult(rawResults, meta)`](docs/queryable.md#parsequeryresultrawresults-meta) | Transform flat DB rows into nested TypeScript objects |
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
48
234
 
49
235
  ---
50
236
 
51
237
  ## Expressions
52
238
 
53
- Dialect-independent SQL expression DSL. [`docs/expressions.md`](docs/expressions.md)
239
+ Dialect-independent SQL expression DSL.
54
240
 
55
241
  | Symbol | Description |
56
242
  |---|---|
57
- | [`expr`](docs/expressions.md#expr) | Expression builder — comparisons, string/number/date functions, aggregates, window functions |
58
- | [`ExprUnit<TPrimitive>`](docs/expressions.md#exprunittprimitive) | Type-safe AST wrapper for a SQL expression |
59
- | [`WhereExprUnit`](docs/expressions.md#whereexprunit) | AST wrapper for WHERE/HAVING boolean expressions |
60
- | [`ExprInput<TPrimitive>`](docs/expressions.md#exprinputtprimitive) | `ExprUnit<T> | T` — accepts raw values alongside expression nodes |
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
+ ```
61
352
 
62
353
  ---
63
354
 
64
355
  ## Schema Builders
65
356
 
66
- Fluent builders for tables, views, procedures, columns, indexes, and relationships. [`docs/schema.md`](docs/schema.md)
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
67
472
 
68
473
  | Symbol | Description |
69
474
  |---|---|
70
- | [`Table(name)`](docs/schema.md#tablename) | Create a `TableBuilder` |
71
- | [`TableBuilder`](docs/schema.md#tablebuildertcolumns-trelations) | Immutable table schema definition with type-inference properties |
72
- | [`View(name)`](docs/schema.md#viewname) | Create a `ViewBuilder` |
73
- | [`ViewBuilder`](docs/schema.md#viewbuilder) | Immutable view schema definition |
74
- | [`Procedure(name)`](docs/schema.md#procedurename) | Create a `ProcedureBuilder` |
75
- | [`ProcedureBuilder`](docs/schema.md#procedurebuildertparams-treturns) | Immutable stored procedure schema definition |
76
- | [`ColumnBuilder`](docs/schema.md#columnbuildertvalue-tmeta) | Column definition with `nullable()`, `default()`, `autoIncrement()` |
77
- | [`createColumnFactory()`](docs/schema.md#createcolumnfactory) | Returns column factory (`c.int()`, `c.varchar()`, `c.datetime()`, …) |
78
- | [`IndexBuilder`](docs/schema.md#indexbuilder) | Index definition with `unique()`, `orderBy()` |
79
- | [`createIndexFactory()`](docs/schema.md#createindexfactory) | Returns index factory used in `indexes()` callbacks |
80
- | [`ForeignKeyBuilder`](docs/schema.md#foreignkeybuildertowner-ttargetfn) | N:1 FK relationship (creates DB constraint) |
81
- | [`ForeignKeyTargetBuilder`](docs/schema.md#foreignkeytargetbuilder) | 1:N FK back-reference |
82
- | [`RelationKeyBuilder`](docs/schema.md#relationkeybuildertowner-ttargetfn) | N:1 logical relationship (no DB constraint) |
83
- | [`RelationKeyTargetBuilder`](docs/schema.md#relationkeytargetbuilder) | 1:N logical back-reference |
84
- | [`createRelationFactory()`](docs/schema.md#createrelationfactorytowner-tcolumnkeyownerfn) | Returns relation factory used in `relations()` callbacks |
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.
85
478
 
86
479
  ---
87
480
 
88
481
  ## Query Builder
89
482
 
90
- Multi-dialect SQL generator from `QueryDef` AST nodes. [`docs/query-builder.md`](docs/query-builder.md)
483
+ Multi-dialect SQL generator from `QueryDef` AST nodes.
91
484
 
92
485
  | Symbol | Description |
93
486
  |---|---|
94
- | [`createQueryBuilder(dialect)`](docs/query-builder.md#createquerybuilderdialect) | Create a dialect-specific `QueryBuilderBase` |
95
- | [`QueryBuilderBase`](docs/query-builder.md#querybuilderbase) | Abstract base — `build(def): QueryBuildResult` |
96
- | [`ExprRendererBase`](docs/query-builder.md#exprrendererbase) | Abstract base for expression-to-SQL rendering |
97
- | [`MysqlQueryBuilder`](docs/query-builder.md#mysqlquerybuilder) | MySQL implementation |
98
- | [`MysqlExprRenderer`](docs/query-builder.md#mysqlexprrenderer) | MySQL expression renderer |
99
- | [`MssqlQueryBuilder`](docs/query-builder.md#mssqlquerybuilder) | MSSQL implementation |
100
- | [`MssqlExprRenderer`](docs/query-builder.md#mssqlexprrenderer) | MSSQL expression renderer |
101
- | [`PostgresqlQueryBuilder`](docs/query-builder.md#postgresqlquerybuilder) | PostgreSQL implementation |
102
- | [`PostgresqlExprRenderer`](docs/query-builder.md#postgresqlexprrenderer) | PostgreSQL expression renderer |
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
+ ```
103
532
 
104
533
  ---
105
534
 
106
535
  ## Types
107
536
 
108
- All type definitions, error types, and utility types. [`docs/types.md`](docs/types.md)
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):
109
604
 
110
- **Database types**: [`Dialect`](docs/types.md#dialect), [`dialects`](docs/types.md#dialects), [`QueryBuildResult`](docs/types.md#querybuildresult), [`IsolationLevel`](docs/types.md#isolationlevel), [`DataRecord`](docs/types.md#datarecord), [`DbContextExecutor`](docs/types.md#dbcontextexecutor), [`ResultMeta`](docs/types.md#resultmeta), [`Migration`](docs/types.md#migration)
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`
111
606
 
112
- **Column types**: [`DataType`](docs/types.md#datatype), [`ColumnPrimitive`](docs/types.md#columnprimitive), [`ColumnPrimitiveStr`](docs/types.md#columnprimitivestr), [`ColumnPrimitiveMap`](docs/types.md#columnprimitivemap), [`ColumnMeta`](docs/types.md#columnmeta), [`ColumnBuilderRecord`](docs/types.md#columnbuilderrecord), [`InferColumns`](docs/types.md#infercolumns), [`InferInsertColumns`](docs/types.md#inferinsertcolumns), [`InferUpdateColumns`](docs/types.md#inferupdatecolumns), [`dataTypeStrToColumnPrimitiveStr`](docs/types.md#datatypestrtoColumnprimitivestr), [`inferColumnPrimitiveStr`](docs/types.md#infercolumnprimitivestr), [`InferColumnPrimitiveFromDataType`](docs/types.md#infercolumnprimitivefromdatatype)
607
+ ### Relation types
113
608
 
114
- **Expression types**: [`Expr`](docs/types.md#expression-types), [`WhereExpr`](docs/types.md#expression-types), [`WinFn`](docs/types.md#expression-types), [`WinSpec`](docs/types.md#expression-types), [`DateSeparator`](docs/types.md#expression-types), and all individual `Expr*` / `WinFn*` node types
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 |
115
615
 
116
- **QueryDef types**: [`QueryDef`](docs/types.md#querydef-types), [`SelectQueryDef`](docs/types.md#querydef-types), [`InsertQueryDef`](docs/types.md#querydef-types), and all DDL/DML query definition types, [`DDL_TYPES`](docs/types.md#querydef-types), [`DdlType`](docs/types.md#querydef-types)
616
+ ### DbContext types
117
617
 
118
- **Relation types**: [`RelationBuilderRecord`](docs/types.md#relationbuilderrecord), [`ExtractRelationTarget`](docs/types.md#extractrelationtarget), [`ExtractRelationTargetResult`](docs/types.md#extractrelationtargetresult), [`InferDeepRelations`](docs/types.md#inferdeeprelations)
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 |
119
626
 
120
- **DbContext types**: [`DbContextBase`](docs/types.md#dbcontextbase), [`DbContextStatus`](docs/types.md#dbcontextstatus), [`DbContextDef`](docs/types.md#dbcontextdef), [`DbContextInstance`](docs/types.md#dbcontextinstance), [`DbContextConnectionMethods`](docs/types.md#dbcontextconnectionmethods), [`DbContextDdlMethods`](docs/types.md#dbcontextddlmethods)
627
+ ### Error types
121
628
 
122
- **Error types**: [`DbTransactionError`](docs/types.md#dbtransactionerror), [`DbErrorCode`](docs/types.md#dberrorcode)
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
+ ```