@simplysm/orm-common 13.0.82 → 13.0.84

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 (80) hide show
  1. package/README.md +106 -0
  2. package/dist/ddl/initialize.d.ts +2 -2
  3. package/dist/ddl/initialize.js +1 -1
  4. package/dist/ddl/initialize.js.map +1 -1
  5. package/dist/ddl/table-ddl.d.ts +1 -1
  6. package/dist/exec/queryable.d.ts +115 -115
  7. package/dist/exec/queryable.js +68 -68
  8. package/dist/exec/queryable.js.map +1 -1
  9. package/dist/expr/expr.d.ts +248 -248
  10. package/dist/expr/expr.js +250 -250
  11. package/dist/query-builder/base/expr-renderer-base.d.ts +7 -7
  12. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +3 -3
  13. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  14. package/dist/query-builder/mssql/mssql-expr-renderer.js +5 -5
  15. package/dist/query-builder/mssql/mssql-query-builder.d.ts +2 -2
  16. package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
  17. package/dist/query-builder/mssql/mssql-query-builder.js +7 -7
  18. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +2 -2
  19. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  20. package/dist/query-builder/mysql/mysql-expr-renderer.js +4 -4
  21. package/dist/query-builder/mysql/mysql-query-builder.d.ts +10 -10
  22. package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
  23. package/dist/query-builder/mysql/mysql-query-builder.js +4 -4
  24. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +2 -2
  25. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  26. package/dist/query-builder/postgresql/postgresql-expr-renderer.js +4 -4
  27. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts +8 -8
  28. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
  29. package/dist/query-builder/postgresql/postgresql-query-builder.js +7 -7
  30. package/dist/query-builder/query-builder.d.ts +1 -1
  31. package/dist/schema/factory/column-builder.d.ts +46 -46
  32. package/dist/schema/factory/column-builder.js +25 -25
  33. package/dist/schema/factory/index-builder.d.ts +22 -22
  34. package/dist/schema/factory/index-builder.js +14 -14
  35. package/dist/schema/factory/relation-builder.d.ts +93 -93
  36. package/dist/schema/factory/relation-builder.d.ts.map +1 -1
  37. package/dist/schema/factory/relation-builder.js +37 -37
  38. package/dist/schema/procedure-builder.d.ts +38 -38
  39. package/dist/schema/procedure-builder.d.ts.map +1 -1
  40. package/dist/schema/procedure-builder.js +26 -26
  41. package/dist/schema/table-builder.d.ts +38 -38
  42. package/dist/schema/table-builder.d.ts.map +1 -1
  43. package/dist/schema/table-builder.js +29 -29
  44. package/dist/schema/view-builder.d.ts +26 -26
  45. package/dist/schema/view-builder.d.ts.map +1 -1
  46. package/dist/schema/view-builder.js +18 -18
  47. package/dist/types/db.d.ts +40 -40
  48. package/dist/types/expr.d.ts +75 -75
  49. package/dist/types/expr.d.ts.map +1 -1
  50. package/dist/types/query-def.d.ts +32 -32
  51. package/dist/types/query-def.d.ts.map +1 -1
  52. package/docs/db-context.md +238 -0
  53. package/docs/expressions.md +413 -0
  54. package/docs/query-builder.md +198 -0
  55. package/docs/queryable.md +420 -0
  56. package/docs/schema-builders.md +216 -0
  57. package/docs/types-and-utilities.md +353 -0
  58. package/package.json +4 -3
  59. package/src/ddl/initialize.ts +16 -16
  60. package/src/ddl/table-ddl.ts +1 -1
  61. package/src/exec/queryable.ts +163 -163
  62. package/src/expr/expr.ts +257 -257
  63. package/src/query-builder/base/expr-renderer-base.ts +8 -8
  64. package/src/query-builder/mssql/mssql-expr-renderer.ts +20 -20
  65. package/src/query-builder/mssql/mssql-query-builder.ts +28 -28
  66. package/src/query-builder/mysql/mysql-expr-renderer.ts +22 -22
  67. package/src/query-builder/mysql/mysql-query-builder.ts +65 -65
  68. package/src/query-builder/postgresql/postgresql-expr-renderer.ts +15 -15
  69. package/src/query-builder/postgresql/postgresql-query-builder.ts +43 -43
  70. package/src/query-builder/query-builder.ts +1 -1
  71. package/src/schema/factory/column-builder.ts +48 -48
  72. package/src/schema/factory/index-builder.ts +22 -22
  73. package/src/schema/factory/relation-builder.ts +95 -95
  74. package/src/schema/procedure-builder.ts +38 -38
  75. package/src/schema/table-builder.ts +38 -38
  76. package/src/schema/view-builder.ts +28 -28
  77. package/src/types/db.ts +41 -41
  78. package/src/types/expr.ts +79 -79
  79. package/src/types/query-def.ts +37 -37
  80. package/tests/ddl/basic.expected.ts +8 -8
@@ -0,0 +1,216 @@
1
+ # Schema Builders
2
+
3
+ Define database tables, views, and stored procedures with a fluent, type-safe API.
4
+
5
+ ## API Reference
6
+
7
+ ### `Table(name)`
8
+
9
+ Factory function that creates a `TableBuilder` for defining table schemas.
10
+
11
+ ```typescript
12
+ function Table(name: string): TableBuilder<{}, {}>
13
+ ```
14
+
15
+ #### TableBuilder Methods
16
+
17
+ | Method | Signature | Description |
18
+ |--------|-----------|-------------|
19
+ | `description(desc)` | `.description(desc: string)` | Set table description (DDL comment) |
20
+ | `database(db)` | `.database(db: string)` | Set database name |
21
+ | `schema(schema)` | `.schema(schema: string)` | Set schema name (MSSQL: `dbo`, PostgreSQL: `public`) |
22
+ | `columns(fn)` | `.columns((c) => ({...}))` | Define columns using column factory |
23
+ | `primaryKey(...cols)` | `.primaryKey("col1", "col2")` | Set primary key (single or composite) |
24
+ | `indexes(fn)` | `.indexes((i) => [...])` | Define indexes |
25
+ | `relations(fn)` | `.relations((r) => ({...}))` | Define relationships (FK, reverse FK, logical relations) |
26
+
27
+ #### Type Inference Properties
28
+
29
+ | Property | Description |
30
+ |----------|-------------|
31
+ | `$inferSelect` | Full type (columns + deep relations) |
32
+ | `$inferColumns` | Columns only |
33
+ | `$inferInsert` | Insert type (autoIncrement/nullable/default fields are optional) |
34
+ | `$inferUpdate` | Update type (all fields optional) |
35
+
36
+ ---
37
+
38
+ ### `View(name)`
39
+
40
+ Factory function that creates a `ViewBuilder` for defining database views.
41
+
42
+ ```typescript
43
+ function View(name: string): ViewBuilder<any, {}, {}>
44
+ ```
45
+
46
+ #### ViewBuilder Methods
47
+
48
+ | Method | Signature | Description |
49
+ |--------|-----------|-------------|
50
+ | `description(desc)` | `.description(desc: string)` | Set view description |
51
+ | `database(db)` | `.database(db: string)` | Set database name |
52
+ | `schema(schema)` | `.schema(schema: string)` | Set schema name |
53
+ | `query(viewFn)` | `.query((db) => db.table().select(...))` | Define view SELECT query |
54
+ | `relations(fn)` | `.relations((r) => ({...}))` | Define relationships (logical only, no FK) |
55
+
56
+ ---
57
+
58
+ ### `Procedure(name)`
59
+
60
+ Factory function that creates a `ProcedureBuilder` for defining stored procedures.
61
+
62
+ ```typescript
63
+ function Procedure(name: string): ProcedureBuilder<never, never>
64
+ ```
65
+
66
+ #### ProcedureBuilder Methods
67
+
68
+ | Method | Signature | Description |
69
+ |--------|-----------|-------------|
70
+ | `description(desc)` | `.description(desc: string)` | Set procedure description |
71
+ | `database(db)` | `.database(db: string)` | Set database name |
72
+ | `schema(schema)` | `.schema(schema: string)` | Set schema name |
73
+ | `params(fn)` | `.params((c) => ({...}))` | Define input parameters |
74
+ | `returns(fn)` | `.returns((c) => ({...}))` | Define return columns |
75
+ | `body(sql)` | `.body("SELECT ...")` | Set procedure body SQL |
76
+
77
+ ---
78
+
79
+ ### Column Factory
80
+
81
+ The column factory (`c`) is provided inside `.columns()` and `.params()`/`.returns()` callbacks.
82
+
83
+ #### Column Types
84
+
85
+ | Method | SQL Type | TypeScript Type | Notes |
86
+ |--------|----------|-----------------|-------|
87
+ | `c.int()` | INT | `number` | 4 bytes |
88
+ | `c.bigint()` | BIGINT | `number` | 8 bytes |
89
+ | `c.float()` | FLOAT | `number` | Single precision |
90
+ | `c.double()` | DOUBLE | `number` | Double precision |
91
+ | `c.decimal(p, s)` | DECIMAL(p,s) | `number` | Fixed-point |
92
+ | `c.varchar(len)` | VARCHAR(len) | `string` | Variable-length string |
93
+ | `c.char(len)` | CHAR(len) | `string` | Fixed-length string |
94
+ | `c.text()` | TEXT | `string` | Large text |
95
+ | `c.binary()` | BLOB/VARBINARY/BYTEA | `Bytes` | Binary data |
96
+ | `c.boolean()` | TINYINT(1)/BIT/BOOLEAN | `boolean` | |
97
+ | `c.datetime()` | DATETIME | `DateTime` | Date + time |
98
+ | `c.date()` | DATE | `DateOnly` | Date only |
99
+ | `c.time()` | TIME | `Time` | Time only |
100
+ | `c.uuid()` | BINARY(16)/UNIQUEIDENTIFIER/UUID | `Uuid` | |
101
+
102
+ #### Column Modifiers
103
+
104
+ | Method | Description |
105
+ |--------|-------------|
106
+ | `.autoIncrement()` | Auto-increment (optional in INSERT inference) |
107
+ | `.nullable()` | Allow NULL (adds `undefined` to type) |
108
+ | `.default(value)` | Set default value (optional in INSERT inference) |
109
+ | `.description(desc)` | Set column comment |
110
+
111
+ ---
112
+
113
+ ### Index Factory
114
+
115
+ The index factory (`i`) is provided inside `.indexes()` callbacks.
116
+
117
+ ```typescript
118
+ i.index("col1", "col2") // Create index on columns
119
+ .unique() // Make unique
120
+ .orderBy("ASC", "DESC") // Set sort order per column
121
+ .name("IX_Custom_Name") // Custom index name
122
+ .description("desc") // Description
123
+ ```
124
+
125
+ ---
126
+
127
+ ### Relation Factory
128
+
129
+ The relation factory (`r`) is provided inside `.relations()` callbacks.
130
+
131
+ | Method | Type | Description |
132
+ |--------|------|-------------|
133
+ | `r.foreignKey(cols, targetFn)` | N:1 | FK constraint created in DB |
134
+ | `r.foreignKeyTarget(targetFn, relName)` | 1:N | Reverse FK reference (array by default) |
135
+ | `r.relationKey(cols, targetFn)` | N:1 | Logical relation (no DB FK) |
136
+ | `r.relationKeyTarget(targetFn, relName)` | 1:N | Logical reverse reference |
137
+
138
+ Both `foreignKeyTarget` and `relationKeyTarget` support `.single()` to indicate a 1:1 relationship (returns single object instead of array).
139
+
140
+ ---
141
+
142
+ ## Usage Examples
143
+
144
+ ### Complete Table Definition
145
+
146
+ ```typescript
147
+ const User = Table("User")
148
+ .database("mydb")
149
+ .description("Application users")
150
+ .columns((c) => ({
151
+ id: c.bigint().autoIncrement(),
152
+ name: c.varchar(100),
153
+ email: c.varchar(200).nullable(),
154
+ status: c.varchar(20).default("active"),
155
+ createdAt: c.datetime().default("CURRENT_TIMESTAMP"),
156
+ }))
157
+ .primaryKey("id")
158
+ .indexes((i) => [
159
+ i.index("email").unique(),
160
+ i.index("status", "createdAt").orderBy("ASC", "DESC"),
161
+ ]);
162
+ ```
163
+
164
+ ### Table with Relations
165
+
166
+ ```typescript
167
+ const Post = Table("Post")
168
+ .columns((c) => ({
169
+ id: c.bigint().autoIncrement(),
170
+ authorId: c.bigint(),
171
+ title: c.varchar(200),
172
+ }))
173
+ .primaryKey("id")
174
+ .relations((r) => ({
175
+ author: r.foreignKey(["authorId"], () => User),
176
+ }));
177
+
178
+ const User = Table("User")
179
+ .columns((c) => ({
180
+ id: c.bigint().autoIncrement(),
181
+ name: c.varchar(100),
182
+ }))
183
+ .primaryKey("id")
184
+ .relations((r) => ({
185
+ posts: r.foreignKeyTarget(() => Post, "author"),
186
+ profile: r.foreignKeyTarget(() => Profile, "user").single(),
187
+ }));
188
+ ```
189
+
190
+ ### View Definition
191
+
192
+ ```typescript
193
+ const ActiveUsers = View("ActiveUsers")
194
+ .database("mydb")
195
+ .query((db: MyDb) =>
196
+ db.user()
197
+ .where((u) => [expr.eq(u.status, "active")])
198
+ .select((u) => ({ id: u.id, name: u.name, email: u.email }))
199
+ );
200
+ ```
201
+
202
+ ### Procedure Definition
203
+
204
+ ```typescript
205
+ const GetUserById = Procedure("GetUserById")
206
+ .database("mydb")
207
+ .params((c) => ({
208
+ userId: c.bigint(),
209
+ }))
210
+ .returns((c) => ({
211
+ id: c.bigint(),
212
+ name: c.varchar(100),
213
+ email: c.varchar(200),
214
+ }))
215
+ .body("SELECT id, name, email FROM User WHERE id = userId");
216
+ ```
@@ -0,0 +1,353 @@
1
+ # Types and Utilities
2
+
3
+ Core type definitions, error handling, search parsing, and result parsing utilities.
4
+
5
+ ## API Reference
6
+
7
+ ### Column Types
8
+
9
+ #### `DataType`
10
+
11
+ SQL data type definition used in column metadata.
12
+
13
+ ```typescript
14
+ type DataType =
15
+ | { type: "int" }
16
+ | { type: "bigint" }
17
+ | { type: "float" }
18
+ | { type: "double" }
19
+ | { type: "decimal"; precision: number; scale?: number }
20
+ | { type: "varchar"; length: number }
21
+ | { type: "char"; length: number }
22
+ | { type: "text" }
23
+ | { type: "binary" }
24
+ | { type: "boolean" }
25
+ | { type: "datetime" }
26
+ | { type: "date" }
27
+ | { type: "time" }
28
+ | { type: "uuid" };
29
+ ```
30
+
31
+ #### `ColumnPrimitive`
32
+
33
+ All primitive TypeScript types that can be stored in columns. `undefined` represents NULL.
34
+
35
+ ```typescript
36
+ type ColumnPrimitive = string | number | boolean | DateTime | DateOnly | Time | Uuid | Bytes | undefined;
37
+ ```
38
+
39
+ #### `ColumnPrimitiveStr`
40
+
41
+ String keys for column primitive type mapping.
42
+
43
+ ```typescript
44
+ type ColumnPrimitiveStr = "string" | "number" | "boolean" | "DateTime" | "DateOnly" | "Time" | "Uuid" | "Bytes";
45
+ ```
46
+
47
+ #### `ColumnMeta`
48
+
49
+ Column metadata generated by `ColumnBuilder`.
50
+
51
+ ```typescript
52
+ interface ColumnMeta {
53
+ type: ColumnPrimitiveStr;
54
+ dataType: DataType;
55
+ autoIncrement?: boolean;
56
+ nullable?: boolean;
57
+ default?: ColumnPrimitive;
58
+ description?: string;
59
+ }
60
+ ```
61
+
62
+ #### `inferColumnPrimitiveStr(value)`
63
+
64
+ Infer `ColumnPrimitiveStr` from a runtime value.
65
+
66
+ ```typescript
67
+ function inferColumnPrimitiveStr(value: ColumnPrimitive): ColumnPrimitiveStr
68
+ ```
69
+
70
+ ```typescript
71
+ inferColumnPrimitiveStr("hello") // "string"
72
+ inferColumnPrimitiveStr(123) // "number"
73
+ inferColumnPrimitiveStr(new DateTime()) // "DateTime"
74
+ ```
75
+
76
+ #### `dataTypeStrToColumnPrimitiveStr`
77
+
78
+ Mapping from SQL type strings to TypeScript type names.
79
+
80
+ ```typescript
81
+ dataTypeStrToColumnPrimitiveStr["int"] // "number"
82
+ dataTypeStrToColumnPrimitiveStr["varchar"] // "string"
83
+ dataTypeStrToColumnPrimitiveStr["datetime"] // "DateTime"
84
+ ```
85
+
86
+ ---
87
+
88
+ ### Database Types
89
+
90
+ #### `Dialect`
91
+
92
+ Supported database dialects.
93
+
94
+ ```typescript
95
+ type Dialect = "mysql" | "mssql" | "postgresql";
96
+ ```
97
+
98
+ #### `dialects`
99
+
100
+ Array of all supported dialects (useful for testing).
101
+
102
+ ```typescript
103
+ const dialects: Dialect[] = ["mysql", "mssql", "postgresql"];
104
+ ```
105
+
106
+ #### `IsolationLevel`
107
+
108
+ Transaction isolation levels.
109
+
110
+ ```typescript
111
+ type IsolationLevel =
112
+ | "READ_UNCOMMITTED"
113
+ | "READ_COMMITTED"
114
+ | "REPEATABLE_READ"
115
+ | "SERIALIZABLE";
116
+ ```
117
+
118
+ #### `DataRecord`
119
+
120
+ Recursive type for query result records (supports nested relations).
121
+
122
+ ```typescript
123
+ type DataRecord = {
124
+ [key: string]: ColumnPrimitive | DataRecord | DataRecord[];
125
+ };
126
+ ```
127
+
128
+ #### `ResultMeta`
129
+
130
+ Metadata for transforming raw query results into typed TypeScript objects.
131
+
132
+ ```typescript
133
+ interface ResultMeta {
134
+ columns: Record<string, ColumnPrimitiveStr>;
135
+ joins: Record<string, { isSingle: boolean }>;
136
+ }
137
+ ```
138
+
139
+ #### `QueryBuildResult`
140
+
141
+ Result of building a QueryDef into SQL.
142
+
143
+ ```typescript
144
+ interface QueryBuildResult {
145
+ sql: string;
146
+ resultSetIndex?: number;
147
+ resultSetStride?: number;
148
+ }
149
+ ```
150
+
151
+ #### `Migration`
152
+
153
+ Database migration definition.
154
+
155
+ ```typescript
156
+ interface Migration {
157
+ name: string;
158
+ up: (db: DbContextBase & DbContextDdlMethods) => Promise<void>;
159
+ }
160
+ ```
161
+
162
+ ---
163
+
164
+ ### Error Handling
165
+
166
+ #### `DbTransactionError`
167
+
168
+ Standardized database transaction error with DBMS-independent error codes.
169
+
170
+ ```typescript
171
+ class DbTransactionError extends Error {
172
+ readonly name = "DbTransactionError";
173
+ readonly code: DbErrorCode;
174
+ readonly originalError?: unknown;
175
+
176
+ constructor(code: DbErrorCode, message: string, originalError?: unknown);
177
+ }
178
+ ```
179
+
180
+ #### `DbErrorCode`
181
+
182
+ Transaction-related error codes.
183
+
184
+ ```typescript
185
+ enum DbErrorCode {
186
+ NO_ACTIVE_TRANSACTION = "NO_ACTIVE_TRANSACTION",
187
+ TRANSACTION_ALREADY_STARTED = "TRANSACTION_ALREADY_STARTED",
188
+ DEADLOCK = "DEADLOCK",
189
+ LOCK_TIMEOUT = "LOCK_TIMEOUT",
190
+ }
191
+ ```
192
+
193
+ ```typescript
194
+ try {
195
+ await executor.rollbackTransaction();
196
+ } catch (err) {
197
+ if (err instanceof DbTransactionError) {
198
+ if (err.code === DbErrorCode.NO_ACTIVE_TRANSACTION) {
199
+ return; // Already rolled back, safe to ignore
200
+ }
201
+ }
202
+ throw err;
203
+ }
204
+ ```
205
+
206
+ ---
207
+
208
+ ### Search Parser
209
+
210
+ #### `parseSearchQuery(searchText)`
211
+
212
+ Parse a user search string into structured SQL LIKE patterns.
213
+
214
+ ```typescript
215
+ function parseSearchQuery(searchText: string): ParsedSearchQuery
216
+ ```
217
+
218
+ ```typescript
219
+ interface ParsedSearchQuery {
220
+ or: string[]; // General terms (OR condition)
221
+ must: string[]; // Required terms (AND condition, + prefix or quotes)
222
+ not: string[]; // Excluded terms (NOT condition, - prefix)
223
+ }
224
+ ```
225
+
226
+ **Search Syntax:**
227
+
228
+ | Syntax | Meaning | Example |
229
+ |--------|---------|---------|
230
+ | `term1 term2` | OR (match any) | `apple banana` |
231
+ | `+term` | Required (AND) | `+apple +banana` |
232
+ | `-term` | Excluded (NOT) | `apple -banana` |
233
+ | `"exact phrase"` | Exact match (required) | `"delicious fruit"` |
234
+ | `*` | Wildcard | `app*` -> `app%` |
235
+
236
+ **Escape sequences:** `\\` (literal `\`), `\*` (literal `*`), `\%` (literal `%`), `\"` (literal `"`), `\+` (literal `+`), `\-` (literal `-`)
237
+
238
+ ```typescript
239
+ parseSearchQuery('apple "delicious fruit" -banana +strawberry')
240
+ // {
241
+ // or: ["%apple%"],
242
+ // must: ["%delicious fruit%", "%strawberry%"],
243
+ // not: ["%banana%"]
244
+ // }
245
+
246
+ parseSearchQuery('app* test')
247
+ // {
248
+ // or: ["app%", "%test%"],
249
+ // must: [],
250
+ // not: []
251
+ // }
252
+ ```
253
+
254
+ ---
255
+
256
+ ### Result Parser
257
+
258
+ #### `parseQueryResult(rawResults, meta)`
259
+
260
+ Transform raw database query results into typed TypeScript objects. Handles type conversion, nested JOIN result grouping, and deduplication.
261
+
262
+ ```typescript
263
+ async function parseQueryResult<TRecord>(
264
+ rawResults: Record<string, unknown>[],
265
+ meta: ResultMeta,
266
+ ): Promise<TRecord[] | undefined>
267
+ ```
268
+
269
+ **Features:**
270
+ - Type conversion (string to number, string to DateTime, etc.)
271
+ - Flat-to-nested object transformation (`"posts.id"` -> `{ posts: { id } }`)
272
+ - JOIN result grouping with deduplication
273
+ - Single vs array relationship handling (`isSingle`)
274
+ - Event loop yielding for large datasets (every 100 records)
275
+ - Returns `undefined` for empty results
276
+
277
+ ```typescript
278
+ // Simple type parsing
279
+ const raw = [{ id: "1", createdAt: "2026-01-07T10:00:00.000Z" }];
280
+ const meta = { columns: { id: "number", createdAt: "DateTime" }, joins: {} };
281
+ const result = await parseQueryResult(raw, meta);
282
+ // [{ id: 1, createdAt: DateTime(...) }]
283
+
284
+ // JOIN result nesting
285
+ const raw = [
286
+ { id: 1, name: "Alice", "posts.id": 10, "posts.title": "Post1" },
287
+ { id: 1, name: "Alice", "posts.id": 11, "posts.title": "Post2" },
288
+ ];
289
+ const meta = {
290
+ columns: { id: "number", name: "string", "posts.id": "number", "posts.title": "string" },
291
+ joins: { posts: { isSingle: false } },
292
+ };
293
+ const result = await parseQueryResult(raw, meta);
294
+ // [{ id: 1, name: "Alice", posts: [{ id: 10, title: "Post1" }, { id: 11, title: "Post2" }] }]
295
+ ```
296
+
297
+ ---
298
+
299
+ ### QueryDef Types
300
+
301
+ #### `QueryDefObjectName`
302
+
303
+ Database object name with optional namespace.
304
+
305
+ ```typescript
306
+ interface QueryDefObjectName {
307
+ database?: string;
308
+ schema?: string;
309
+ name: string;
310
+ }
311
+ ```
312
+
313
+ #### `QueryDef`
314
+
315
+ Union type of all query definitions (DML + DDL + utility).
316
+
317
+ Key DML types:
318
+
319
+ | Type | Interface | Description |
320
+ |------|-----------|-------------|
321
+ | `"select"` | `SelectQueryDef` | SELECT with FROM, WHERE, JOIN, ORDER BY, GROUP BY, HAVING, LIMIT, WITH |
322
+ | `"insert"` | `InsertQueryDef` | INSERT with records, output, overrideIdentity |
323
+ | `"insertIfNotExists"` | `InsertIfNotExistsQueryDef` | Conditional INSERT |
324
+ | `"insertInto"` | `InsertIntoQueryDef` | INSERT INTO ... SELECT |
325
+ | `"update"` | `UpdateQueryDef` | UPDATE with JOIN support |
326
+ | `"delete"` | `DeleteQueryDef` | DELETE with JOIN support |
327
+ | `"upsert"` | `UpsertQueryDef` | INSERT or UPDATE (MERGE) |
328
+
329
+ #### `DDL_TYPES`
330
+
331
+ Constant array of all DDL query type strings. Used to prevent DDL execution inside transactions.
332
+
333
+ ```typescript
334
+ const DDL_TYPES: readonly string[]
335
+ // ["clearSchema", "createTable", "dropTable", "renameTable", "truncate",
336
+ // "addColumn", "dropColumn", "modifyColumn", "renameColumn",
337
+ // "dropPrimaryKey", "addPrimaryKey", "addForeignKey", "dropForeignKey",
338
+ // "addIndex", "dropIndex", "createView", "dropView", "createProc", "dropProc"]
339
+ ```
340
+
341
+ ---
342
+
343
+ ### Type Inference Utilities
344
+
345
+ | Type | Description |
346
+ |------|-------------|
347
+ | `InferColumns<T>` | Infer value types from ColumnBuilderRecord |
348
+ | `InferInsertColumns<T>` | Infer INSERT type (required + optional fields) |
349
+ | `InferUpdateColumns<T>` | Infer UPDATE type (all fields optional) |
350
+ | `InferColumnExprs<T>` | Infer expression input types |
351
+ | `InferDeepRelations<T>` | Infer nested relation types (all optional) |
352
+ | `ExtractRelationTarget<T>` | Extract N:1 relation target type |
353
+ | `ExtractRelationTargetResult<T>` | Extract 1:N relation target type (array or single) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/orm-common",
3
- "version": "13.0.82",
3
+ "version": "13.0.84",
4
4
  "description": "Simplysm Package - ORM Module (common)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -15,10 +15,11 @@
15
15
  "files": [
16
16
  "dist",
17
17
  "src",
18
- "tests"
18
+ "tests",
19
+ "docs"
19
20
  ],
20
21
  "sideEffects": false,
21
22
  "dependencies": {
22
- "@simplysm/core-common": "13.0.82"
23
+ "@simplysm/core-common": "13.0.84"
23
24
  }
24
25
  }
@@ -46,7 +46,7 @@ export async function initialize(
46
46
 
47
47
  const force = options?.force ?? false;
48
48
 
49
- // 1. DB 존재 확인
49
+ // 1. Check DB existence
50
50
  for (const dbName of dbNames) {
51
51
  const schemaExistsDef = getSchemaExistsQueryDef(dbName, db.schema);
52
52
  const result = await db.executeDefs([schemaExistsDef]);
@@ -57,7 +57,7 @@ export async function initialize(
57
57
  }
58
58
 
59
59
  if (force) {
60
- // 2. force: dbs 전체 Initialize
60
+ // 2. force: initialize all dbs
61
61
  for (const dbName of dbNames) {
62
62
  const clearDef = getClearSchemaQueryDef({ database: dbName, schema: db.schema });
63
63
  await db.executeDefs([clearDef]);
@@ -69,7 +69,7 @@ export async function initialize(
69
69
  await db._migration().insert(def.meta.migrations.map((m) => ({ code: m.name })));
70
70
  }
71
71
  } else {
72
- // 3. Migration 기반 Initialize
72
+ // 3. Migration-based initialize
73
73
  let appliedMigrations: { code: string }[] | undefined;
74
74
  try {
75
75
  appliedMigrations = await db._migration().execute();
@@ -102,13 +102,13 @@ export async function initialize(
102
102
  }
103
103
 
104
104
  /**
105
- * 전체 object Generate (table/View/Procedure/FK/Index)
105
+ * Generate all objects (table/view/procedure/FK/index)
106
106
  */
107
107
  async function createAllObjects(
108
108
  db: DbContextBase,
109
109
  def: DbContextDef<any, any, any>,
110
110
  ): Promise<void> {
111
- // 1. Table/View/Procedure Generate
111
+ // 1. Generate Table/View/Procedure
112
112
  const builders = getBuilders(def);
113
113
  const createDefs: QueryDef[] = [];
114
114
  for (const builder of builders) {
@@ -118,7 +118,7 @@ async function createAllObjects(
118
118
  await db.executeDefs(createDefs);
119
119
  }
120
120
 
121
- // 2. FK Generate (TableBuilder)
121
+ // 2. Generate FK (TableBuilder only)
122
122
  const tables = builders.filter((b) => b instanceof TableBuilder);
123
123
  const addFkDefs: QueryDef[] = [];
124
124
  for (const table of tables) {
@@ -136,7 +136,7 @@ async function createAllObjects(
136
136
  await db.executeDefs(addFkDefs);
137
137
  }
138
138
 
139
- // 3. Index Generate (TableBuilder)
139
+ // 3. Generate Index (TableBuilder only)
140
140
  const createIndexDefs: QueryDef[] = [];
141
141
  for (const table of tables) {
142
142
  const indexes = table.meta.indexes;
@@ -153,7 +153,7 @@ async function createAllObjects(
153
153
  }
154
154
 
155
155
  /**
156
- * DbContext의 모든 Builder 수집 (Table/View/Procedure)
156
+ * Collect all builders from DbContext (Table/View/Procedure)
157
157
  */
158
158
  function getBuilders(
159
159
  def: DbContextDef<any, any, any>,
@@ -186,8 +186,8 @@ function getBuilders(
186
186
  }
187
187
 
188
188
  /**
189
- * ForeignKeyTarget/RelationKeyTarget 관계의 유효성 Validation
190
- * - targetTableFn() 반환하는 Table에 relationName에 해당하는 FK/RelationKey 있는지 확인
189
+ * Validate ForeignKeyTarget/RelationKeyTarget relations
190
+ * - Checks if the table returned by targetTableFn() has a FK/RelationKey matching the relationName
191
191
  */
192
192
  export function validateRelations(def: DbContextDef<any, any, any>): void {
193
193
  const builders = getBuilders(def);
@@ -211,8 +211,8 @@ export function validateRelations(def: DbContextDef<any, any, any>): void {
211
211
 
212
212
  if (!(fkRel instanceof ForeignKeyBuilder) && !(fkRel instanceof RelationKeyBuilder)) {
213
213
  throw new Error(
214
- `Invalid relation target: ${table.meta.name}.${relName} 참조하는 ` +
215
- `'${fkRelName}'이(가) ${targetTable.meta.name}의 유효한 ForeignKey/RelationKey가 아닙니다.`,
214
+ `Invalid relation target: '${fkRelName}' referenced by ${table.meta.name}.${relName} ` +
215
+ `is not a valid ForeignKey/RelationKey in ${targetTable.meta.name}.`,
216
216
  );
217
217
  }
218
218
  }
@@ -220,9 +220,9 @@ export function validateRelations(def: DbContextDef<any, any, any>): void {
220
220
  }
221
221
 
222
222
  /**
223
- * Table N/A 에러인지 확인
223
+ * Check if the error indicates a table does not exist
224
224
  *
225
- * DBMS error code/메시지 pattern:
225
+ * DBMS-specific error code/message patterns:
226
226
  * - MySQL: errno 1146 (ER_NO_SUCH_TABLE), "Table 'xxx' doesn't exist"
227
227
  * - MSSQL: number 208, "Invalid object name 'xxx'"
228
228
  * - PostgreSQL: code "42P01", "relation \"xxx\" does not exist"
@@ -230,13 +230,13 @@ export function validateRelations(def: DbContextDef<any, any, any>): void {
230
230
  function isTableNotExistsError(err: unknown): boolean {
231
231
  if (err == null) return false;
232
232
 
233
- // error code 우선 확인 (multilingual 환경에서도 안정적)
233
+ // Check error code first (reliable even in multilingual environments)
234
234
  const errObj = err as Record<string, unknown>;
235
235
  if (errObj["errno"] === 1146) return true; // MySQL ER_NO_SUCH_TABLE
236
236
  if (errObj["number"] === 208) return true; // MSSQL
237
237
  if (errObj["code"] === "42P01") return true; // PostgreSQL
238
238
 
239
- // 폴백: 메시지 매칭 (multilingual 환경에서 불안정할 있음)
239
+ // Fallback: message matching (may be unreliable in multilingual environments)
240
240
  const message = err instanceof Error ? err.message : String(err);
241
241
  const lowerMessage = message.toLowerCase();
242
242