@simplysm/orm-common 13.0.96 → 13.0.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/types.md ADDED
@@ -0,0 +1,445 @@
1
+ # Types
2
+
3
+ TypeScript types for dialects, queries, expressions, columns, and results.
4
+
5
+ Source: `src/types/db.ts`, `src/types/column.ts`, `src/types/expr.ts`, `src/types/query-def.ts`
6
+
7
+ ## Database Types
8
+
9
+ Source: `src/types/db.ts`
10
+
11
+ ### Dialect
12
+
13
+ ```typescript
14
+ type Dialect = "mysql" | "mssql" | "postgresql";
15
+ ```
16
+
17
+ - `mysql`: MySQL 8.0.14+
18
+ - `mssql`: Microsoft SQL Server 2012+
19
+ - `postgresql`: PostgreSQL 9.0+
20
+
21
+ ### dialects
22
+
23
+ ```typescript
24
+ const dialects: Dialect[] = ["mysql", "mssql", "postgresql"];
25
+ ```
26
+
27
+ ### QueryBuildResult
28
+
29
+ Return type of `QueryBuilderBase.build()`.
30
+
31
+ ```typescript
32
+ interface QueryBuildResult {
33
+ /** Built SQL string */
34
+ sql: string;
35
+ /** Result set index to fetch results from (default: 0) */
36
+ resultSetIndex?: number;
37
+ /** Extract every Nth result set from multiple results */
38
+ resultSetStride?: number;
39
+ }
40
+ ```
41
+
42
+ ### IsolationLevel
43
+
44
+ ```typescript
45
+ type IsolationLevel =
46
+ | "READ_UNCOMMITTED"
47
+ | "READ_COMMITTED"
48
+ | "REPEATABLE_READ"
49
+ | "SERIALIZABLE";
50
+ ```
51
+
52
+ ### DataRecord
53
+
54
+ Recursive record type for query results, supporting nested relations.
55
+
56
+ ```typescript
57
+ type DataRecord = {
58
+ [key: string]: ColumnPrimitive | DataRecord | DataRecord[];
59
+ };
60
+ ```
61
+
62
+ ### DbContextExecutor
63
+
64
+ Interface for actual DB connection and query execution. Implemented by `NodeDbContextExecutor` (server) or service client executors.
65
+
66
+ ```typescript
67
+ interface DbContextExecutor {
68
+ connect(): Promise<void>;
69
+ close(): Promise<void>;
70
+ beginTransaction(isolationLevel?: IsolationLevel): Promise<void>;
71
+ commitTransaction(): Promise<void>;
72
+ rollbackTransaction(): Promise<void>;
73
+ executeDefs<T = DataRecord>(
74
+ defs: QueryDef[],
75
+ resultMetas?: (ResultMeta | undefined)[],
76
+ ): Promise<T[][]>;
77
+ }
78
+ ```
79
+
80
+ ### ResultMeta
81
+
82
+ Metadata for query result transformation (type parsing and JOIN nesting).
83
+
84
+ ```typescript
85
+ interface ResultMeta {
86
+ /** Column name -> ColumnPrimitiveStr mapping */
87
+ columns: Record<string, ColumnPrimitiveStr>;
88
+ /** JOIN alias -> single/array indicator */
89
+ joins: Record<string, { isSingle: boolean }>;
90
+ }
91
+ ```
92
+
93
+ ### Migration
94
+
95
+ Database migration definition.
96
+
97
+ ```typescript
98
+ interface Migration {
99
+ name: string;
100
+ up: (db: DbContextBase & DbContextDdlMethods) => Promise<void>;
101
+ }
102
+ ```
103
+
104
+ **Example:**
105
+
106
+ ```typescript
107
+ const migrations: Migration[] = [
108
+ {
109
+ name: "20260105_001_create_user_table",
110
+ up: async (db) => {
111
+ await db.createTable(User);
112
+ },
113
+ },
114
+ ];
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Column Types
120
+
121
+ Source: `src/types/column.ts`
122
+
123
+ ### DataType
124
+
125
+ SQL data type definition (discriminated union).
126
+
127
+ ```typescript
128
+ type DataType =
129
+ | { type: "int" }
130
+ | { type: "bigint" }
131
+ | { type: "float" }
132
+ | { type: "double" }
133
+ | { type: "decimal"; precision: number; scale?: number }
134
+ | { type: "varchar"; length: number }
135
+ | { type: "char"; length: number }
136
+ | { type: "text" }
137
+ | { type: "binary" }
138
+ | { type: "boolean" }
139
+ | { type: "datetime" }
140
+ | { type: "date" }
141
+ | { type: "time" }
142
+ | { type: "uuid" };
143
+ ```
144
+
145
+ ### ColumnPrimitiveMap
146
+
147
+ TypeScript type name to actual type mapping.
148
+
149
+ ```typescript
150
+ type ColumnPrimitiveMap = {
151
+ string: string;
152
+ number: number;
153
+ boolean: boolean;
154
+ DateTime: DateTime;
155
+ DateOnly: DateOnly;
156
+ Time: Time;
157
+ Uuid: Uuid;
158
+ Bytes: Bytes;
159
+ };
160
+ ```
161
+
162
+ ### ColumnPrimitiveStr
163
+
164
+ ```typescript
165
+ type ColumnPrimitiveStr = keyof ColumnPrimitiveMap;
166
+ // "string" | "number" | "boolean" | "DateTime" | "DateOnly" | "Time" | "Uuid" | "Bytes"
167
+ ```
168
+
169
+ ### ColumnPrimitive
170
+
171
+ All primitive types that can be stored in columns. `undefined` represents NULL.
172
+
173
+ ```typescript
174
+ type ColumnPrimitive = ColumnPrimitiveMap[ColumnPrimitiveStr] | undefined;
175
+ ```
176
+
177
+ ### ColumnMeta
178
+
179
+ Column metadata generated by `ColumnBuilder`.
180
+
181
+ ```typescript
182
+ interface ColumnMeta {
183
+ type: ColumnPrimitiveStr;
184
+ dataType: DataType;
185
+ autoIncrement?: boolean;
186
+ nullable?: boolean;
187
+ default?: ColumnPrimitive;
188
+ description?: string;
189
+ }
190
+ ```
191
+
192
+ ### dataTypeStrToColumnPrimitiveStr
193
+
194
+ SQL DataType type string to TypeScript type name mapping.
195
+
196
+ ```typescript
197
+ const dataTypeStrToColumnPrimitiveStr: {
198
+ int: "number";
199
+ bigint: "number";
200
+ float: "number";
201
+ double: "number";
202
+ decimal: "number";
203
+ varchar: "string";
204
+ char: "string";
205
+ text: "string";
206
+ binary: "Bytes";
207
+ boolean: "boolean";
208
+ datetime: "DateTime";
209
+ date: "DateOnly";
210
+ time: "Time";
211
+ uuid: "Uuid";
212
+ };
213
+ ```
214
+
215
+ ### InferColumnPrimitiveFromDataType
216
+
217
+ Infer TypeScript type from `DataType`.
218
+
219
+ ```typescript
220
+ type InferColumnPrimitiveFromDataType<TDataType extends DataType> =
221
+ ColumnPrimitiveMap[(typeof dataTypeStrToColumnPrimitiveStr)[TDataType["type"]]];
222
+ ```
223
+
224
+ ### inferColumnPrimitiveStr (function)
225
+
226
+ Infer `ColumnPrimitiveStr` from a runtime value.
227
+
228
+ ```typescript
229
+ function inferColumnPrimitiveStr(value: ColumnPrimitive): ColumnPrimitiveStr;
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Expression Types
235
+
236
+ Source: `src/types/expr.ts`
237
+
238
+ ### DateUnit
239
+
240
+ ```typescript
241
+ type DateUnit = "year" | "month" | "day" | "hour" | "minute" | "second";
242
+ ```
243
+
244
+ ### Expr (union type)
245
+
246
+ Discriminated union of all expression AST node types. Used in `select()`, `orderBy()`, etc.
247
+
248
+ | Category | Types |
249
+ |----------|-------|
250
+ | Value | `ExprColumn`, `ExprValue`, `ExprRaw` |
251
+ | String | `ExprConcat`, `ExprLeft`, `ExprRight`, `ExprTrim`, `ExprPadStart`, `ExprReplace`, `ExprUpper`, `ExprLower`, `ExprLength`, `ExprByteLength`, `ExprSubstring`, `ExprIndexOf` |
252
+ | Numeric | `ExprAbs`, `ExprRound`, `ExprCeil`, `ExprFloor` |
253
+ | Date | `ExprYear`, `ExprMonth`, `ExprDay`, `ExprHour`, `ExprMinute`, `ExprSecond`, `ExprIsoWeek`, `ExprIsoWeekStartDate`, `ExprIsoYearMonth`, `ExprDateDiff`, `ExprDateAdd`, `ExprFormatDate` |
254
+ | Condition | `ExprCoalesce`, `ExprNullIf`, `ExprIs`, `ExprSwitch`, `ExprIf` |
255
+ | Aggregate | `ExprCount`, `ExprSum`, `ExprAvg`, `ExprMax`, `ExprMin` |
256
+ | Other | `ExprGreatest`, `ExprLeast`, `ExprRowNum`, `ExprRandom`, `ExprCast` |
257
+ | Window | `ExprWindow` |
258
+ | System | `ExprSubquery` |
259
+
260
+ ### WhereExpr (union type)
261
+
262
+ Subset of `Expr` for WHERE clauses (comparison + logical operators).
263
+
264
+ | Category | Types |
265
+ |----------|-------|
266
+ | Comparison | `ExprEq`, `ExprGt`, `ExprLt`, `ExprGte`, `ExprLte`, `ExprBetween`, `ExprIsNull`, `ExprLike`, `ExprRegexp`, `ExprIn`, `ExprInQuery`, `ExprExists` |
267
+ | Logical | `ExprNot`, `ExprAnd`, `ExprOr` |
268
+
269
+ ### Individual Expr Interfaces
270
+
271
+ Each expression type is a simple interface with a `type` discriminant:
272
+
273
+ ```typescript
274
+ interface ExprColumn { type: "column"; path: string[]; }
275
+ interface ExprValue { type: "value"; value: ColumnPrimitive; }
276
+ interface ExprRaw { type: "raw"; sql: string; params: Expr[]; }
277
+ interface ExprEq { type: "eq"; source: Expr; target: Expr; }
278
+ interface ExprGt { type: "gt"; source: Expr; target: Expr; }
279
+ // ... etc.
280
+ ```
281
+
282
+ ### Window Function Types
283
+
284
+ ```typescript
285
+ type WinFn =
286
+ | WinFnRowNumber | WinFnRank | WinFnDenseRank | WinFnNtile
287
+ | WinFnLag | WinFnLead | WinFnFirstValue | WinFnLastValue
288
+ | WinFnSum | WinFnAvg | WinFnCount | WinFnMin | WinFnMax;
289
+
290
+ interface WinSpec {
291
+ partitionBy?: Expr[];
292
+ orderBy?: [Expr, ("ASC" | "DESC")?][];
293
+ }
294
+
295
+ interface ExprWindow {
296
+ type: "window";
297
+ fn: WinFn;
298
+ spec: WinSpec;
299
+ }
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Query Definition Types
305
+
306
+ Source: `src/types/query-def.ts`
307
+
308
+ ### QueryDefObjectName
309
+
310
+ ```typescript
311
+ interface QueryDefObjectName {
312
+ database?: string;
313
+ schema?: string;
314
+ name: string;
315
+ }
316
+ ```
317
+
318
+ DBMS-specific namespaces:
319
+ - MySQL: `database.name` (schema ignored)
320
+ - MSSQL: `database.schema.name` (schema defaults to dbo)
321
+ - PostgreSQL: `schema.name` (database is for connection only)
322
+
323
+ ### QueryDef (union type)
324
+
325
+ Union of all query definition types:
326
+
327
+ **DML:** `SelectQueryDef`, `InsertQueryDef`, `InsertIfNotExistsQueryDef`, `InsertIntoQueryDef`, `UpdateQueryDef`, `DeleteQueryDef`, `UpsertQueryDef`
328
+
329
+ **DDL - Schema:** `ClearSchemaQueryDef`
330
+
331
+ **DDL - Table:** `CreateTableQueryDef`, `DropTableQueryDef`, `RenameTableQueryDef`, `TruncateQueryDef`
332
+
333
+ **DDL - Column:** `AddColumnQueryDef`, `DropColumnQueryDef`, `ModifyColumnQueryDef`, `RenameColumnQueryDef`
334
+
335
+ **DDL - Constraint:** `DropPrimaryKeyQueryDef`, `AddPrimaryKeyQueryDef`, `AddForeignKeyQueryDef`, `DropForeignKeyQueryDef`, `AddIndexQueryDef`, `DropIndexQueryDef`
336
+
337
+ **DDL - View/Procedure:** `CreateViewQueryDef`, `DropViewQueryDef`, `CreateProcQueryDef`, `DropProcQueryDef`, `ExecProcQueryDef`
338
+
339
+ **Utils:** `SwitchFkQueryDef`
340
+
341
+ **Meta:** `SchemaExistsQueryDef`
342
+
343
+ ### SelectQueryDef
344
+
345
+ ```typescript
346
+ interface SelectQueryDef {
347
+ type: "select";
348
+ from?: QueryDefObjectName | SelectQueryDef | SelectQueryDef[] | string;
349
+ as: string;
350
+ select?: Record<string, Expr>;
351
+ distinct?: boolean;
352
+ top?: number;
353
+ lock?: boolean;
354
+ where?: WhereExpr[];
355
+ joins?: SelectQueryDefJoin[];
356
+ orderBy?: [Expr, ("ASC" | "DESC")?][];
357
+ limit?: [number, number];
358
+ groupBy?: Expr[];
359
+ having?: WhereExpr[];
360
+ with?: { name: string; base: SelectQueryDef; recursive: SelectQueryDef };
361
+ }
362
+ ```
363
+
364
+ ### SelectQueryDefJoin
365
+
366
+ ```typescript
367
+ interface SelectQueryDefJoin extends SelectQueryDef {
368
+ isSingle?: boolean;
369
+ }
370
+ ```
371
+
372
+ ### InsertQueryDef
373
+
374
+ ```typescript
375
+ interface InsertQueryDef {
376
+ type: "insert";
377
+ table: QueryDefObjectName;
378
+ records: Record<string, ColumnPrimitive>[];
379
+ overrideIdentity?: boolean;
380
+ output?: CudOutputDef;
381
+ }
382
+ ```
383
+
384
+ ### UpdateQueryDef
385
+
386
+ ```typescript
387
+ interface UpdateQueryDef {
388
+ type: "update";
389
+ table: QueryDefObjectName;
390
+ as: string;
391
+ record: Record<string, Expr>;
392
+ top?: number;
393
+ where?: WhereExpr[];
394
+ joins?: SelectQueryDefJoin[];
395
+ limit?: [number, number];
396
+ output?: CudOutputDef;
397
+ }
398
+ ```
399
+
400
+ ### DeleteQueryDef
401
+
402
+ ```typescript
403
+ interface DeleteQueryDef {
404
+ type: "delete";
405
+ table: QueryDefObjectName;
406
+ as: string;
407
+ top?: number;
408
+ where?: WhereExpr[];
409
+ joins?: SelectQueryDefJoin[];
410
+ limit?: [number, number];
411
+ output?: CudOutputDef;
412
+ }
413
+ ```
414
+
415
+ ### UpsertQueryDef
416
+
417
+ ```typescript
418
+ interface UpsertQueryDef {
419
+ type: "upsert";
420
+ table: QueryDefObjectName;
421
+ existsSelectQuery: SelectQueryDef;
422
+ insertRecord: Record<string, Expr>;
423
+ updateRecord: Record<string, Expr>;
424
+ overrideIdentity?: boolean;
425
+ output?: CudOutputDef;
426
+ }
427
+ ```
428
+
429
+ ### CudOutputDef
430
+
431
+ ```typescript
432
+ interface CudOutputDef {
433
+ columns: string[];
434
+ pkColNames: string[];
435
+ aiColName?: string;
436
+ }
437
+ ```
438
+
439
+ ### DDL_TYPES
440
+
441
+ Constant array of all DDL type strings (for blocking DDL within transactions).
442
+
443
+ ```typescript
444
+ const DDL_TYPES: readonly DdlType[];
445
+ ```
@@ -0,0 +1,122 @@
1
+ # Utilities
2
+
3
+ Result parsing helpers for transforming raw database output to typed TypeScript objects.
4
+
5
+ Source: `src/utils/result-parser.ts`
6
+
7
+ ## parseQueryResult
8
+
9
+ Transform raw DB query results to TypeScript objects via `ResultMeta`. Handles type parsing, flat-to-nested transformation, and JOIN grouping.
10
+
11
+ ```typescript
12
+ async function parseQueryResult<TRecord>(
13
+ rawResults: Record<string, unknown>[],
14
+ meta: ResultMeta,
15
+ ): Promise<TRecord[] | undefined>;
16
+ ```
17
+
18
+ **Parameters:**
19
+
20
+ - `rawResults` -- Raw result array from the database driver (flat key-value records)
21
+ - `meta` -- Type transformation and JOIN structure information (`ResultMeta`)
22
+
23
+ **Returns:**
24
+
25
+ - Type-transformed and nested result array, or `undefined` if input is empty or all records are empty after parsing
26
+
27
+ **Behavior:**
28
+
29
+ - **Type parsing** -- Converts raw values (strings from DB) to proper TypeScript types based on `meta.columns` mapping (e.g., `"1"` to `1` for number, `"2026-01-15T10:00:00Z"` to `DateTime`)
30
+ - **Flat-to-nested** -- Transforms dot-notation keys to nested objects (e.g., `"posts.id"` becomes `{ posts: { id: ... } }`)
31
+ - **JOIN grouping** -- Groups rows by non-JOIN columns, collecting JOIN data into arrays (1:N) or single objects (1:1)
32
+ - **Async** -- Yields to the event loop every 100 records to prevent blocking
33
+ - **Empty handling** -- Returns `undefined` for empty input or when all parsed records are empty objects
34
+
35
+ ### Example: Simple Type Parsing
36
+
37
+ ```typescript
38
+ const raw = [
39
+ { id: "1", name: "Alice", createdAt: "2026-01-07T10:00:00.000Z" },
40
+ ];
41
+
42
+ const meta: ResultMeta = {
43
+ columns: { id: "number", name: "string", createdAt: "DateTime" },
44
+ joins: {},
45
+ };
46
+
47
+ const result = await parseQueryResult(raw, meta);
48
+ // [{ id: 1, name: "Alice", createdAt: DateTime("2026-01-07T10:00:00.000Z") }]
49
+ ```
50
+
51
+ ### Example: JOIN Result Nesting
52
+
53
+ ```typescript
54
+ const raw = [
55
+ { id: 1, name: "User1", "posts.id": 10, "posts.title": "Post1" },
56
+ { id: 1, name: "User1", "posts.id": 11, "posts.title": "Post2" },
57
+ { id: 2, name: "User2", "posts.id": 20, "posts.title": "Post3" },
58
+ ];
59
+
60
+ const meta: ResultMeta = {
61
+ columns: {
62
+ id: "number",
63
+ name: "string",
64
+ "posts.id": "number",
65
+ "posts.title": "string",
66
+ },
67
+ joins: {
68
+ posts: { isSingle: false },
69
+ },
70
+ };
71
+
72
+ const result = await parseQueryResult(raw, meta);
73
+ // [
74
+ // { id: 1, name: "User1", posts: [{ id: 10, title: "Post1" }, { id: 11, title: "Post2" }] },
75
+ // { id: 2, name: "User2", posts: [{ id: 20, title: "Post3" }] },
76
+ // ]
77
+ ```
78
+
79
+ ### Example: Single JOIN (1:1)
80
+
81
+ ```typescript
82
+ const raw = [
83
+ { id: 1, title: "Post1", "author.id": 10, "author.name": "Alice" },
84
+ { id: 2, title: "Post2", "author.id": 10, "author.name": "Alice" },
85
+ ];
86
+
87
+ const meta: ResultMeta = {
88
+ columns: {
89
+ id: "number",
90
+ title: "string",
91
+ "author.id": "number",
92
+ "author.name": "string",
93
+ },
94
+ joins: {
95
+ author: { isSingle: true },
96
+ },
97
+ };
98
+
99
+ const result = await parseQueryResult(raw, meta);
100
+ // [
101
+ // { id: 1, title: "Post1", author: { id: 10, name: "Alice" } },
102
+ // { id: 2, title: "Post2", author: { id: 10, name: "Alice" } },
103
+ // ]
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Type Parsing Rules
109
+
110
+ | ColumnPrimitiveStr | Input | Output |
111
+ |--------------------|-------|--------|
112
+ | `"number"` | `"123"` / `123` | `123` (throws if NaN) |
113
+ | `"string"` | any | `String(value)` |
114
+ | `"boolean"` | `0` / `"0"` / `false` | `false` |
115
+ | `"boolean"` | `1` / `"1"` / `true` | `true` |
116
+ | `"DateTime"` | ISO string | `DateTime.parse(value)` |
117
+ | `"DateOnly"` | date string | `DateOnly.parse(value)` |
118
+ | `"Time"` | time string | `Time.parse(value)` |
119
+ | `"Uuid"` | `Uint8Array` / string | `Uuid.fromBytes(value)` / `new Uuid(value)` |
120
+ | `"Bytes"` | `Uint8Array` / hex string | as-is / `bytes.fromHex(value)` |
121
+
122
+ `null` and `undefined` values are returned as `undefined` (keys are omitted from the result).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/orm-common",
3
- "version": "13.0.96",
3
+ "version": "13.0.98",
4
4
  "description": "Simplysm Package - ORM Module (common)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -20,6 +20,6 @@
20
20
  ],
21
21
  "sideEffects": false,
22
22
  "dependencies": {
23
- "@simplysm/core-common": "13.0.96"
23
+ "@simplysm/core-common": "13.0.98"
24
24
  }
25
25
  }