@simplysm/orm-common 14.0.1 → 14.0.5

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 (59) hide show
  1. package/README.md +163 -0
  2. package/dist/exec/queryable.js +18 -18
  3. package/dist/exec/queryable.js.map +1 -1
  4. package/dist/expr/expr.d.ts +102 -102
  5. package/dist/expr/expr.js +105 -105
  6. package/dist/expr/expr.js.map +1 -1
  7. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +1 -1
  8. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  9. package/dist/query-builder/mssql/mssql-expr-renderer.js +17 -17
  10. package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
  11. package/dist/query-builder/mssql/mssql-query-builder.d.ts +2 -2
  12. package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
  13. package/dist/query-builder/mssql/mssql-query-builder.js +26 -26
  14. package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
  15. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +1 -1
  16. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  17. package/dist/query-builder/mysql/mysql-expr-renderer.js +14 -14
  18. package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
  19. package/dist/query-builder/mysql/mysql-query-builder.d.ts +10 -10
  20. package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
  21. package/dist/query-builder/mysql/mysql-query-builder.js +67 -67
  22. package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
  23. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +1 -1
  24. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  25. package/dist/query-builder/postgresql/postgresql-expr-renderer.js +13 -13
  26. package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
  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 +47 -47
  30. package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
  31. package/dist/schema/factory/relation-builder.d.ts +8 -8
  32. package/dist/schema/factory/relation-builder.js +9 -9
  33. package/dist/schema/factory/relation-builder.js.map +1 -1
  34. package/dist/schema/view-builder.js +2 -2
  35. package/dist/schema/view-builder.js.map +1 -1
  36. package/dist/types/column.d.ts +21 -21
  37. package/dist/types/column.js +5 -5
  38. package/dist/utils/result-parser.d.ts +11 -11
  39. package/dist/utils/result-parser.js +48 -48
  40. package/dist/utils/result-parser.js.map +1 -1
  41. package/docs/core.md +157 -0
  42. package/docs/expression.md +220 -0
  43. package/docs/query-builder.md +150 -0
  44. package/docs/queryable.md +261 -0
  45. package/docs/schema-builders.md +294 -0
  46. package/docs/types.md +520 -0
  47. package/package.json +7 -3
  48. package/src/exec/queryable.ts +18 -18
  49. package/src/expr/expr.ts +105 -105
  50. package/src/query-builder/mssql/mssql-expr-renderer.ts +17 -17
  51. package/src/query-builder/mssql/mssql-query-builder.ts +26 -26
  52. package/src/query-builder/mysql/mysql-expr-renderer.ts +14 -14
  53. package/src/query-builder/mysql/mysql-query-builder.ts +67 -67
  54. package/src/query-builder/postgresql/postgresql-expr-renderer.ts +13 -13
  55. package/src/query-builder/postgresql/postgresql-query-builder.ts +47 -47
  56. package/src/schema/factory/relation-builder.ts +9 -9
  57. package/src/schema/view-builder.ts +2 -2
  58. package/src/types/column.ts +23 -23
  59. package/src/utils/result-parser.ts +49 -49
package/docs/core.md ADDED
@@ -0,0 +1,157 @@
1
+ # Core
2
+
3
+ DbContext definition, creation, and lifecycle management.
4
+
5
+ ## defineDbContext
6
+
7
+ ```typescript
8
+ function defineDbContext<
9
+ TTables extends Record<string, TableBuilder<any, any>> = {},
10
+ TViews extends Record<string, ViewBuilder<any, any, any>> = {},
11
+ TProcedures extends Record<string, ProcedureBuilder<any, any>> = {},
12
+ >(config: {
13
+ tables?: TTables;
14
+ views?: TViews;
15
+ procedures?: TProcedures;
16
+ migrations?: Migration[];
17
+ }): DbContextDef<TTables & { _migration: typeof _Migration }, TViews, TProcedures>
18
+ ```
19
+
20
+ Creates a DbContext definition (blueprint) containing schema metadata. Automatically adds the `_migration` system table. The definition itself has no runtime state.
21
+
22
+ | Parameter | Type | Description |
23
+ |-----------|------|-------------|
24
+ | `config.tables` | `Record<string, TableBuilder>` | Table definitions |
25
+ | `config.views` | `Record<string, ViewBuilder>` | View definitions |
26
+ | `config.procedures` | `Record<string, ProcedureBuilder>` | Procedure definitions |
27
+ | `config.migrations` | `Migration[]` | Migration definitions |
28
+
29
+ ```typescript
30
+ const MyDb = defineDbContext({
31
+ tables: { user: User, post: Post },
32
+ views: { activeUsers: ActiveUsersView },
33
+ procedures: { getUserById: GetUserById },
34
+ migrations: [
35
+ { name: "20260101_001_init", up: async (db) => { await db.createTable(User); } },
36
+ ],
37
+ });
38
+ ```
39
+
40
+ ## createDbContext
41
+
42
+ ```typescript
43
+ function createDbContext<TDef extends DbContextDef<any, any, any>>(
44
+ def: TDef,
45
+ executor: DbContextExecutor,
46
+ opt: { database: string; schema?: string },
47
+ ): DbContextInstance<TDef>
48
+ ```
49
+
50
+ Creates a full DbContext instance from a definition and executor. The returned object provides:
51
+
52
+ - **Queryable accessors** for each table/view (e.g., `db.user()` returns a `Queryable`)
53
+ - **Executable accessors** for each procedure (e.g., `db.getUserById()` returns an `Executable`)
54
+ - **Connection management**: `connect()`, `connectWithoutTransaction()`, `transaction()`
55
+ - **DDL methods**: `createTable()`, `dropTable()`, `addColumn()`, etc. (see `DbContextDdlMethods`)
56
+ - **DDL QueryDef generators**: `getCreateTableQueryDef()`, etc.
57
+ - **Initialize**: `initialize()` runs migrations
58
+
59
+ | Parameter | Type | Description |
60
+ |-----------|------|-------------|
61
+ | `def` | `DbContextDef` | Definition from `defineDbContext()` |
62
+ | `executor` | `DbContextExecutor` | Query execution engine (e.g., `NodeDbContextExecutor`) |
63
+ | `opt.database` | `string` | Database name |
64
+ | `opt.schema` | `string?` | Schema name (MSSQL: dbo, PostgreSQL: public) |
65
+
66
+ ### Connection Methods
67
+
68
+ | Method | Signature | Description |
69
+ |--------|-----------|-------------|
70
+ | `connect` | `<R>(fn: () => Promise<R>, isolationLevel?: IsolationLevel) => Promise<R>` | Connect, begin transaction, execute callback, commit (auto-rollback on error) |
71
+ | `connectWithoutTransaction` | `<R>(fn: () => Promise<R>) => Promise<R>` | Connect without transaction, execute callback, close |
72
+ | `transaction` | `<R>(fn: () => Promise<R>, isolationLevel?: IsolationLevel) => Promise<R>` | Begin transaction within existing connection (for use inside `connectWithoutTransaction`) |
73
+
74
+ ### DDL Execution Methods
75
+
76
+ | Method | Signature |
77
+ |--------|-----------|
78
+ | `createTable` | `(table: TableBuilder) => Promise<void>` |
79
+ | `dropTable` | `(table: QueryDefObjectName) => Promise<void>` |
80
+ | `renameTable` | `(table: QueryDefObjectName, newName: string) => Promise<void>` |
81
+ | `createView` | `(view: ViewBuilder) => Promise<void>` |
82
+ | `dropView` | `(view: QueryDefObjectName) => Promise<void>` |
83
+ | `createProc` | `(procedure: ProcedureBuilder) => Promise<void>` |
84
+ | `dropProc` | `(procedure: QueryDefObjectName) => Promise<void>` |
85
+ | `addColumn` | `(table: QueryDefObjectName, columnName: string, column: ColumnBuilder) => Promise<void>` |
86
+ | `dropColumn` | `(table: QueryDefObjectName, column: string) => Promise<void>` |
87
+ | `modifyColumn` | `(table: QueryDefObjectName, columnName: string, column: ColumnBuilder) => Promise<void>` |
88
+ | `renameColumn` | `(table: QueryDefObjectName, column: string, newName: string) => Promise<void>` |
89
+ | `addPrimaryKey` | `(table: QueryDefObjectName, columns: string[]) => Promise<void>` |
90
+ | `dropPrimaryKey` | `(table: QueryDefObjectName) => Promise<void>` |
91
+ | `addForeignKey` | `(table: QueryDefObjectName, relationName: string, relationDef: ForeignKeyBuilder) => Promise<void>` |
92
+ | `addIndex` | `(table: QueryDefObjectName, indexBuilder: IndexBuilder) => Promise<void>` |
93
+ | `dropForeignKey` | `(table: QueryDefObjectName, relationName: string) => Promise<void>` |
94
+ | `dropIndex` | `(table: QueryDefObjectName, columns: string[]) => Promise<void>` |
95
+ | `clearSchema` | `(params: { database: string; schema?: string }) => Promise<void>` |
96
+ | `schemaExists` | `(database: string, schema?: string) => Promise<boolean>` |
97
+ | `truncate` | `(table: QueryDefObjectName) => Promise<void>` |
98
+ | `switchFk` | `(table: QueryDefObjectName, enabled: boolean) => Promise<void>` |
99
+
100
+ ### DDL QueryDef Generators
101
+
102
+ Each DDL method has a corresponding `get*QueryDef` method that returns a `QueryDef` without executing it. For example: `getCreateTableQueryDef(table)`, `getDropTableQueryDef(table)`, etc.
103
+
104
+ ### Initialize
105
+
106
+ ```typescript
107
+ async initialize(options?: { dbs?: string[]; force?: boolean }): Promise<void>
108
+ ```
109
+
110
+ Runs pending migrations. If `force` is true, drops and recreates the schema.
111
+
112
+ ## DbTransactionError
113
+
114
+ ```typescript
115
+ class DbTransactionError extends Error {
116
+ readonly name = "DbTransactionError";
117
+ constructor(
118
+ public readonly code: DbErrorCode,
119
+ message: string,
120
+ public readonly originalError?: unknown,
121
+ )
122
+ }
123
+ ```
124
+
125
+ Wraps DBMS-native transaction errors into standardized error codes.
126
+
127
+ | Field | Type | Description |
128
+ |-------|------|-------------|
129
+ | `code` | `DbErrorCode` | Standardized error code |
130
+ | `message` | `string` | Error message |
131
+ | `originalError` | `unknown?` | Original DBMS error (for debugging) |
132
+
133
+ ## DbErrorCode
134
+
135
+ ```typescript
136
+ enum DbErrorCode {
137
+ NO_ACTIVE_TRANSACTION = "NO_ACTIVE_TRANSACTION",
138
+ TRANSACTION_ALREADY_STARTED = "TRANSACTION_ALREADY_STARTED",
139
+ DEADLOCK = "DEADLOCK",
140
+ LOCK_TIMEOUT = "LOCK_TIMEOUT",
141
+ }
142
+ ```
143
+
144
+ | Value | Description |
145
+ |-------|-------------|
146
+ | `NO_ACTIVE_TRANSACTION` | No active transaction (e.g., rollback when no transaction) |
147
+ | `TRANSACTION_ALREADY_STARTED` | Transaction already started |
148
+ | `DEADLOCK` | Deadlock detected |
149
+ | `LOCK_TIMEOUT` | Lock timeout exceeded |
150
+
151
+ ## _Migration
152
+
153
+ ```typescript
154
+ const _Migration: TableBuilder<{ code: ColumnBuilder<string, ...> }, {}>
155
+ ```
156
+
157
+ System migration tracking table. Automatically added to every DbContext via `defineDbContext()`. Has a single `code` column (VARCHAR(255)) as primary key, storing executed migration names.
@@ -0,0 +1,220 @@
1
+ # Expression DSL
2
+
3
+ Dialect-independent SQL expression builder. Generates JSON AST (`Expr`) instead of SQL strings. The QueryBuilder transforms the AST to target DBMS syntax.
4
+
5
+ ## ExprUnit
6
+
7
+ ```typescript
8
+ class ExprUnit<TPrimitive extends ColumnPrimitive> {
9
+ readonly $infer!: TPrimitive;
10
+ readonly dataType: ColumnPrimitiveStr;
11
+ readonly expr: Expr;
12
+ get n(): ExprUnit<NonNullable<TPrimitive>>;
13
+ constructor(dataType: ColumnPrimitiveStr, expr: Expr);
14
+ }
15
+ ```
16
+
17
+ Type-safe expression wrapper. Tracks the return type via the `TPrimitive` generic parameter.
18
+
19
+ | Member | Type | Description |
20
+ |--------|------|-------------|
21
+ | `$infer` | `TPrimitive` | Type inference helper (phantom type) |
22
+ | `dataType` | `ColumnPrimitiveStr` | Runtime type name (`"string"`, `"number"`, etc.) |
23
+ | `expr` | `Expr` | Underlying JSON AST expression |
24
+ | `n` | `ExprUnit<NonNullable<TPrimitive>>` | Getter that narrows nullable to non-nullable |
25
+
26
+ ## WhereExprUnit
27
+
28
+ ```typescript
29
+ class WhereExprUnit {
30
+ readonly expr: WhereExpr;
31
+ constructor(expr: WhereExpr);
32
+ }
33
+ ```
34
+
35
+ WHERE clause expression wrapper. Returned by comparison and logical methods on `expr`.
36
+
37
+ ## ExprInput
38
+
39
+ ```typescript
40
+ type ExprInput<TPrimitive extends ColumnPrimitive> = ExprUnit<TPrimitive> | TPrimitive;
41
+ ```
42
+
43
+ Accepts either an `ExprUnit` or a literal value. Literal values are automatically wrapped.
44
+
45
+ ## SwitchExprBuilder
46
+
47
+ ```typescript
48
+ interface SwitchExprBuilder<TPrimitive extends ColumnPrimitive> {
49
+ case(condition: WhereExprUnit, then: ExprInput<TPrimitive>): SwitchExprBuilder<TPrimitive>;
50
+ default(value: ExprInput<TPrimitive>): ExprUnit<TPrimitive>;
51
+ }
52
+ ```
53
+
54
+ Fluent CASE WHEN builder. Chain `.case()` calls and terminate with `.default()`.
55
+
56
+ ## expr Object
57
+
58
+ The `expr` object provides all expression-building methods. Methods are grouped by category below.
59
+
60
+ ### Value Creation
61
+
62
+ | Method | Signature | Description |
63
+ |--------|-----------|-------------|
64
+ | `val` | `<TStr extends ColumnPrimitiveStr>(dataType: TStr, value: T) => ExprUnit` | Wrap a literal value into an ExprUnit |
65
+ | `col` | `<TStr extends ColumnPrimitiveStr>(dataType: ColumnPrimitiveStr, ...path: string[]) => ExprUnit` | Create a column reference |
66
+ | `raw` | `<T extends ColumnPrimitiveStr>(dataType: T) => (strings: TemplateStringsArray, ...values: ExprInput[]) => ExprUnit` | Raw SQL via tagged template literal; interpolated values become parameters |
67
+
68
+ ### Comparison (WHERE)
69
+
70
+ | Method | Signature | SQL | Description |
71
+ |--------|-----------|-----|-------------|
72
+ | `eq` | `(source: ExprUnit<T>, target: ExprInput<T>) => WhereExprUnit` | `<=>` / `IS NULL OR =` | NULL-safe equality |
73
+ | `gt` | `(source: ExprUnit<T>, target: ExprInput<T>) => WhereExprUnit` | `>` | Greater than |
74
+ | `lt` | `(source: ExprUnit<T>, target: ExprInput<T>) => WhereExprUnit` | `<` | Less than |
75
+ | `gte` | `(source: ExprUnit<T>, target: ExprInput<T>) => WhereExprUnit` | `>=` | Greater than or equal |
76
+ | `lte` | `(source: ExprUnit<T>, target: ExprInput<T>) => WhereExprUnit` | `<=` | Less than or equal |
77
+ | `between` | `(source: ExprUnit<T>, from?: ExprInput<T>, to?: ExprInput<T>) => WhereExprUnit` | `BETWEEN` | Range comparison (undefined bounds omitted) |
78
+
79
+ ### NULL Check (WHERE)
80
+
81
+ | Method | Signature | SQL | Description |
82
+ |--------|-----------|-----|-------------|
83
+ | `null` | `(source: ExprUnit<T>) => WhereExprUnit` | `IS NULL` | NULL check |
84
+
85
+ ### String Search (WHERE)
86
+
87
+ | Method | Signature | SQL | Description |
88
+ |--------|-----------|-----|-------------|
89
+ | `like` | `(source: ExprUnit<string\|undefined>, pattern: ExprInput<string\|undefined>) => WhereExprUnit` | `LIKE ... ESCAPE '\'` | Pattern matching |
90
+ | `regexp` | `(source: ExprUnit<string\|undefined>, pattern: ExprInput<string\|undefined>) => WhereExprUnit` | `REGEXP` | Regex matching |
91
+
92
+ ### IN / EXISTS (WHERE)
93
+
94
+ | Method | Signature | SQL | Description |
95
+ |--------|-----------|-----|-------------|
96
+ | `in` | `(source: ExprUnit<T>, values: ExprInput<T>[]) => WhereExprUnit` | `IN (...)` | List membership |
97
+ | `inQuery` | `(source: ExprUnit<T>, query: Queryable<...>) => WhereExprUnit` | `IN (SELECT ...)` | Subquery membership (single column) |
98
+ | `exists` | `(query: Queryable<any, any>) => WhereExprUnit` | `EXISTS (SELECT ...)` | Subquery existence check |
99
+
100
+ ### Logical (WHERE)
101
+
102
+ | Method | Signature | SQL | Description |
103
+ |--------|-----------|-----|-------------|
104
+ | `not` | `(arg: WhereExprUnit) => WhereExprUnit` | `NOT (...)` | Negate condition |
105
+ | `and` | `(conditions: WhereExprUnit[]) => WhereExprUnit` | `... AND ...` | All conditions must match |
106
+ | `or` | `(conditions: WhereExprUnit[]) => WhereExprUnit` | `... OR ...` | At least one condition must match |
107
+
108
+ ### String Functions (SELECT)
109
+
110
+ | Method | Signature | SQL | Description |
111
+ |--------|-----------|-----|-------------|
112
+ | `concat` | `(...args: ExprInput<string\|undefined>[]) => ExprUnit<string>` | `CONCAT(...)` | String concatenation (NULL becomes empty) |
113
+ | `left` | `(source, length) => ExprUnit<T>` | `LEFT(source, n)` | Left substring |
114
+ | `right` | `(source, length) => ExprUnit<T>` | `RIGHT(source, n)` | Right substring |
115
+ | `trim` | `(source) => ExprUnit<T>` | `TRIM(source)` | Remove leading/trailing whitespace |
116
+ | `padStart` | `(source, length, fillString) => ExprUnit<T>` | `LPAD(...)` | Left-pad to target length |
117
+ | `replace` | `(source, from, to) => ExprUnit<T>` | `REPLACE(...)` | String replacement |
118
+ | `upper` | `(source) => ExprUnit<T>` | `UPPER(source)` | Uppercase |
119
+ | `lower` | `(source) => ExprUnit<T>` | `LOWER(source)` | Lowercase |
120
+ | `length` | `(source) => ExprUnit<number>` | `CHAR_LENGTH(source)` | Character count |
121
+ | `byteLength` | `(source) => ExprUnit<number>` | `OCTET_LENGTH(source)` | Byte count |
122
+ | `substring` | `(source, start, length?) => ExprUnit<T>` | `SUBSTRING(source, start, length)` | Extract substring (1-based index) |
123
+ | `indexOf` | `(source, search) => ExprUnit<number>` | `LOCATE(search, source)` | Find position (1-based, 0 if not found) |
124
+
125
+ ### Math Functions (SELECT)
126
+
127
+ | Method | Signature | SQL | Description |
128
+ |--------|-----------|-----|-------------|
129
+ | `abs` | `(source) => ExprUnit<T>` | `ABS(source)` | Absolute value |
130
+ | `round` | `(source, digits) => ExprUnit<T>` | `ROUND(source, digits)` | Round to N decimal places |
131
+ | `ceil` | `(source) => ExprUnit<T>` | `CEILING(source)` | Round up |
132
+ | `floor` | `(source) => ExprUnit<T>` | `FLOOR(source)` | Round down |
133
+
134
+ ### Date Functions (SELECT)
135
+
136
+ | Method | Signature | SQL | Description |
137
+ |--------|-----------|-----|-------------|
138
+ | `year` | `(source) => ExprUnit<number>` | `YEAR(source)` | Extract year (4-digit) |
139
+ | `month` | `(source) => ExprUnit<number>` | `MONTH(source)` | Extract month (1-12) |
140
+ | `day` | `(source) => ExprUnit<number>` | `DAY(source)` | Extract day (1-31) |
141
+ | `hour` | `(source) => ExprUnit<number>` | `HOUR(source)` | Extract hour (0-23) |
142
+ | `minute` | `(source) => ExprUnit<number>` | `MINUTE(source)` | Extract minute (0-59) |
143
+ | `second` | `(source) => ExprUnit<number>` | `SECOND(source)` | Extract second (0-59) |
144
+ | `isoWeek` | `(source) => ExprUnit<number>` | `WEEK(source, 3)` | ISO week number (1-53) |
145
+ | `isoWeekStartDate` | `(source) => ExprUnit<T>` | Computed | Monday of the source date's week |
146
+ | `isoYearMonth` | `(source) => ExprUnit<T>` | Computed | First day of the source date's month |
147
+ | `dateDiff` | `(unit: DateUnit, from, to) => ExprUnit<number>` | `DATEDIFF(unit, from, to)` | Date difference (to - from) |
148
+ | `dateAdd` | `(unit: DateUnit, source, value) => ExprUnit<T>` | `DATEADD(unit, value, source)` | Add time to date |
149
+ | `formatDate` | `(source, format: string) => ExprUnit<string>` | `DATE_FORMAT(...)` | Format date as string |
150
+
151
+ ### Conditional (SELECT)
152
+
153
+ | Method | Signature | SQL | Description |
154
+ |--------|-----------|-----|-------------|
155
+ | `coalesce` | `(...args) => ExprUnit<T>` | `COALESCE(...)` | First non-null value |
156
+ | `nullIf` | `(source, value) => ExprUnit<T\|undefined>` | `NULLIF(source, value)` | Return NULL if source equals value |
157
+ | `is` | `(condition: WhereExprUnit) => ExprUnit<boolean>` | Condition as boolean | Convert WHERE expression to boolean column |
158
+ | `switch` | `<T>() => SwitchExprBuilder<T>` | `CASE WHEN ... END` | Fluent CASE WHEN builder |
159
+ | `if` | `(condition, then, else_) => ExprUnit<T>` | `IF(...)` / `IIF(...)` | Ternary conditional |
160
+
161
+ ### Aggregate (SELECT)
162
+
163
+ | Method | Signature | SQL | Description |
164
+ |--------|-----------|-----|-------------|
165
+ | `count` | `(arg?, distinct?) => ExprUnit<number>` | `COUNT(...)` | Row count (all rows if arg omitted) |
166
+ | `sum` | `(arg) => ExprUnit<number\|undefined>` | `SUM(arg)` | Sum (NULL if all values NULL) |
167
+ | `avg` | `(arg) => ExprUnit<number\|undefined>` | `AVG(arg)` | Average (NULL if all values NULL) |
168
+ | `max` | `(arg) => ExprUnit<T\|undefined>` | `MAX(arg)` | Maximum value |
169
+ | `min` | `(arg) => ExprUnit<T\|undefined>` | `MIN(arg)` | Minimum value |
170
+
171
+ ### Other (SELECT)
172
+
173
+ | Method | Signature | SQL | Description |
174
+ |--------|-----------|-----|-------------|
175
+ | `greatest` | `(...args) => ExprUnit<T>` | `GREATEST(...)` | Greatest of multiple values |
176
+ | `least` | `(...args) => ExprUnit<T>` | `LEAST(...)` | Least of multiple values |
177
+ | `rowNum` | `() => ExprUnit<number>` | `ROW_NUMBER` variant | Simple row numbering |
178
+ | `random` | `() => ExprUnit<number>` | `RAND()` / `RANDOM()` | Random number (0 to 1) |
179
+ | `cast` | `(source, targetType: DataType) => ExprUnit` | `CAST(source AS type)` | Type conversion |
180
+ | `subquery` | `(dataType, queryable) => ExprUnit` | `(SELECT ...)` | Scalar subquery in SELECT |
181
+
182
+ ### Window Functions (SELECT)
183
+
184
+ | Method | Signature | SQL | Description |
185
+ |--------|-----------|-----|-------------|
186
+ | `rowNumber` | `(spec: WinSpecInput) => ExprUnit<number>` | `ROW_NUMBER() OVER (...)` | Row number within partition |
187
+ | `rank` | `(spec: WinSpecInput) => ExprUnit<number>` | `RANK() OVER (...)` | Rank (gaps after ties: 1,1,3) |
188
+ | `denseRank` | `(spec: WinSpecInput) => ExprUnit<number>` | `DENSE_RANK() OVER (...)` | Dense rank (no gaps: 1,1,2) |
189
+ | `ntile` | `(n: number, spec: WinSpecInput) => ExprUnit<number>` | `NTILE(n) OVER (...)` | Split into n groups |
190
+ | `lag` | `(column, spec, options?) => ExprUnit<T\|undefined>` | `LAG(...) OVER (...)` | Previous row value |
191
+ | `lead` | `(column, spec, options?) => ExprUnit<T\|undefined>` | `LEAD(...) OVER (...)` | Next row value |
192
+ | `firstValue` | `(column, spec) => ExprUnit<T\|undefined>` | `FIRST_VALUE(...) OVER (...)` | First value in partition |
193
+ | `lastValue` | `(column, spec) => ExprUnit<T\|undefined>` | `LAST_VALUE(...) OVER (...)` | Last value in partition |
194
+ | `sumOver` | `(column, spec) => ExprUnit<number\|undefined>` | `SUM(...) OVER (...)` | Window sum |
195
+ | `avgOver` | `(column, spec) => ExprUnit<number\|undefined>` | `AVG(...) OVER (...)` | Window average |
196
+ | `countOver` | `(spec, column?) => ExprUnit<number>` | `COUNT(...) OVER (...)` | Window count |
197
+ | `minOver` | `(column, spec) => ExprUnit<T\|undefined>` | `MIN(...) OVER (...)` | Window minimum |
198
+ | `maxOver` | `(column, spec) => ExprUnit<T\|undefined>` | `MAX(...) OVER (...)` | Window maximum |
199
+
200
+ **WinSpecInput** (window specification input):
201
+
202
+ ```typescript
203
+ interface WinSpecInput {
204
+ partitionBy?: ExprInput<ColumnPrimitive>[];
205
+ orderBy?: [ExprInput<ColumnPrimitive>, ("ASC" | "DESC")?][];
206
+ }
207
+ ```
208
+
209
+ **lag/lead options**:
210
+
211
+ | Option | Type | Default | Description |
212
+ |--------|------|---------|-------------|
213
+ | `offset` | `number` | `1` | Number of rows to look back/forward |
214
+ | `default` | `ExprInput<T>` | `undefined` (NULL) | Default value when no row exists |
215
+
216
+ ### Helper
217
+
218
+ | Method | Signature | Description |
219
+ |--------|-----------|-------------|
220
+ | `toExpr` | `(value: ExprInput<ColumnPrimitive>) => Expr` | Convert ExprInput to Expr JSON AST (internal use) |
@@ -0,0 +1,150 @@
1
+ # Query Builder
2
+
3
+ Transforms `QueryDef` AST into dialect-specific SQL strings.
4
+
5
+ ## createQueryBuilder
6
+
7
+ ```typescript
8
+ function createQueryBuilder(dialect: Dialect): QueryBuilderBase
9
+ ```
10
+
11
+ Factory function that creates a dialect-specific QueryBuilder instance.
12
+
13
+ | Parameter | Type | Description |
14
+ |-----------|------|-------------|
15
+ | `dialect` | `"mysql" \| "mssql" \| "postgresql"` | Target DBMS dialect |
16
+
17
+ Returns `MysqlQueryBuilder`, `MssqlQueryBuilder`, or `PostgresqlQueryBuilder`.
18
+
19
+ ## QueryBuilderBase
20
+
21
+ ```typescript
22
+ abstract class QueryBuilderBase {
23
+ build(def: QueryDef): QueryBuildResult;
24
+ }
25
+ ```
26
+
27
+ Abstract base class for rendering `QueryDef` AST to SQL. Implements common dispatch logic; dialect-specific differences are handled by abstract methods in subclasses.
28
+
29
+ | Method | Signature | Description |
30
+ |--------|-----------|-------------|
31
+ | `build` | `(def: QueryDef) => QueryBuildResult` | Convert any QueryDef to SQL |
32
+
33
+ `QueryBuildResult` contains:
34
+
35
+ | Field | Type | Description |
36
+ |-------|------|-------------|
37
+ | `sql` | `string` | Generated SQL string |
38
+ | `resultSetIndex` | `number?` | Result set index for multi-statement queries |
39
+ | `resultSetStride` | `number?` | Stride for extracting results from multi-statement queries |
40
+
41
+ ## Dialect-Specific Query Builders
42
+
43
+ ### MysqlQueryBuilder
44
+
45
+ ```typescript
46
+ class MysqlQueryBuilder extends QueryBuilderBase
47
+ ```
48
+
49
+ MySQL 8.0.14+ query builder. Handles MySQL-specific syntax such as backtick quoting, `<=>` for NULL-safe equality, `LIMIT ... OFFSET`, `LOAD DATA LOCAL INFILE`, etc.
50
+
51
+ ### MssqlQueryBuilder
52
+
53
+ ```typescript
54
+ class MssqlQueryBuilder extends QueryBuilderBase
55
+ ```
56
+
57
+ MSSQL 2012+ query builder. Handles bracket quoting, `TOP`, `OFFSET ... FETCH NEXT`, `MERGE` for upsert, `SET IDENTITY_INSERT`, etc.
58
+
59
+ ### PostgresqlQueryBuilder
60
+
61
+ ```typescript
62
+ class PostgresqlQueryBuilder extends QueryBuilderBase
63
+ ```
64
+
65
+ PostgreSQL 9.0+ query builder. Handles double-quote quoting, `LIMIT ... OFFSET`, `ON CONFLICT` for upsert, `COPY FROM STDIN`, etc.
66
+
67
+ ## ExprRendererBase
68
+
69
+ ```typescript
70
+ abstract class ExprRendererBase {
71
+ renderExpr(expr: Expr): string;
72
+ renderWhereExpr(expr: WhereExpr): string;
73
+ }
74
+ ```
75
+
76
+ Abstract base class for rendering `Expr` and `WhereExpr` AST nodes to SQL fragments. Each QueryBuilder uses a corresponding ExprRenderer.
77
+
78
+ | Method | Signature | Description |
79
+ |--------|-----------|-------------|
80
+ | `renderExpr` | `(expr: Expr) => string` | Render a value/function expression to SQL |
81
+ | `renderWhereExpr` | `(expr: WhereExpr) => string` | Render a WHERE condition expression to SQL |
82
+
83
+ ## Dialect-Specific Expression Renderers
84
+
85
+ ### MysqlExprRenderer
86
+
87
+ ```typescript
88
+ class MysqlExprRenderer extends ExprRendererBase
89
+ ```
90
+
91
+ MySQL expression renderer. Uses `<=>` for NULL-safe equality, `IFNULL`, `LOCATE`, MySQL `DATE_FORMAT` patterns, etc.
92
+
93
+ ### MssqlExprRenderer
94
+
95
+ ```typescript
96
+ class MssqlExprRenderer extends ExprRendererBase
97
+ ```
98
+
99
+ MSSQL expression renderer. Uses `IIF`, `CHARINDEX`, `FORMAT` for date formatting, `DATALENGTH` for byte length, etc.
100
+
101
+ ### PostgresqlExprRenderer
102
+
103
+ ```typescript
104
+ class PostgresqlExprRenderer extends ExprRendererBase
105
+ ```
106
+
107
+ PostgreSQL expression renderer. Uses `IS NOT DISTINCT FROM` for NULL-safe equality, `POSITION`, `TO_CHAR` for date formatting, `OCTET_LENGTH`, etc.
108
+
109
+ ## parseQueryResult
110
+
111
+ ```typescript
112
+ async function parseQueryResult<TRecord>(
113
+ rawResults: Record<string, unknown>[],
114
+ meta: ResultMeta,
115
+ ): Promise<TRecord[] | undefined>
116
+ ```
117
+
118
+ Parses raw database query results into typed TypeScript objects. Handles:
119
+
120
+ - **Type conversion**: Converts raw values (strings, numbers) to proper TypeScript types (`DateTime`, `DateOnly`, `Uuid`, etc.) based on `ResultMeta.columns`
121
+ - **JOIN nesting**: Flattens `"posts.id"` keys into nested `{ posts: { id: ... } }` objects
122
+ - **Grouping**: Groups rows by non-JOIN columns, collecting JOIN data into arrays (1:N) or single objects (1:1)
123
+ - **Event loop yielding**: Yields to the event loop every 100 records for large result sets
124
+
125
+ | Parameter | Type | Description |
126
+ |-----------|------|-------------|
127
+ | `rawResults` | `Record<string, unknown>[]` | Raw DB result rows |
128
+ | `meta` | `ResultMeta` | Column types and JOIN structure info |
129
+
130
+ Returns `undefined` if the input is empty or all records parse to empty objects.
131
+
132
+ ```typescript
133
+ // Simple type parsing
134
+ const raw = [{ id: "1", createdAt: "2026-01-07T10:00:00.000Z" }];
135
+ const meta = { columns: { id: "number", createdAt: "DateTime" }, joins: {} };
136
+ const result = await parseQueryResult(raw, meta);
137
+ // [{ id: 1, createdAt: DateTime(...) }]
138
+
139
+ // JOIN nesting
140
+ const raw = [
141
+ { id: 1, name: "User1", "posts.id": 10, "posts.title": "Post1" },
142
+ { id: 1, name: "User1", "posts.id": 11, "posts.title": "Post2" },
143
+ ];
144
+ const meta = {
145
+ columns: { id: "number", name: "string", "posts.id": "number", "posts.title": "string" },
146
+ joins: { posts: { isSingle: false } },
147
+ };
148
+ const result = await parseQueryResult(raw, meta);
149
+ // [{ id: 1, name: "User1", posts: [{ id: 10, title: "Post1" }, { id: 11, title: "Post2" }] }]
150
+ ```