@simplysm/orm-common 14.0.4 → 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.
- package/README.md +127 -99
- package/docs/core.md +88 -137
- package/docs/expression.md +177 -174
- package/docs/query-builder.md +95 -71
- package/docs/queryable.md +160 -135
- package/docs/schema-builders.md +151 -209
- package/docs/types.md +273 -254
- package/package.json +2 -2
package/docs/expression.md
CHANGED
|
@@ -2,216 +2,219 @@
|
|
|
2
2
|
|
|
3
3
|
Dialect-independent SQL expression builder. Generates JSON AST (`Expr`) instead of SQL strings. The QueryBuilder transforms the AST to target DBMS syntax.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
Constant object with all expression builder methods. Used inside Queryable callbacks for `where()`, `select()`, `orderBy()`, etc.
|
|
8
|
-
|
|
9
|
-
### Value Generation
|
|
10
|
-
|
|
11
|
-
| Method | Signature | Description |
|
|
12
|
-
|---|---|---|
|
|
13
|
-
| `val` | `(dataType: ColumnPrimitiveStr, value) => ExprUnit` | Wrap literal value as ExprUnit |
|
|
14
|
-
| `col` | `(dataType, ...path: string[]) => ExprUnit` | Generate column reference (internal use) |
|
|
15
|
-
| `raw` | `(dataType) => tagged template => ExprUnit` | Raw SQL expression (escape hatch). Interpolated values are auto-parameterized. |
|
|
16
|
-
|
|
17
|
-
**Example:**
|
|
5
|
+
## ExprUnit
|
|
18
6
|
|
|
19
7
|
```typescript
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
expr
|
|
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
|
+
}
|
|
24
15
|
```
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
| Method | Signature | Description |
|
|
29
|
-
|---|---|---|
|
|
30
|
-
| `eq` | `(source, target) => WhereExprUnit` | Equality (NULL-safe: MySQL `<=>`) |
|
|
31
|
-
| `gt` | `(source, target) => WhereExprUnit` | Greater than (`>`) |
|
|
32
|
-
| `lt` | `(source, target) => WhereExprUnit` | Less than (`<`) |
|
|
33
|
-
| `gte` | `(source, target) => WhereExprUnit` | Greater than or equal (`>=`) |
|
|
34
|
-
| `lte` | `(source, target) => WhereExprUnit` | Less than or equal (`<=`) |
|
|
35
|
-
| `between` | `(source, from?, to?) => WhereExprUnit` | Range (BETWEEN). Undefined bounds are unbounded. |
|
|
36
|
-
|
|
37
|
-
### NULL Check
|
|
38
|
-
|
|
39
|
-
| Method | Signature | Description |
|
|
40
|
-
|---|---|---|
|
|
41
|
-
| `null` | `(source) => WhereExprUnit` | IS NULL check |
|
|
17
|
+
Type-safe expression wrapper. Tracks the return type via the `TPrimitive` generic parameter.
|
|
42
18
|
|
|
43
|
-
|
|
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 |
|
|
44
25
|
|
|
45
|
-
|
|
46
|
-
|---|---|---|
|
|
47
|
-
| `like` | `(source, pattern) => WhereExprUnit` | LIKE pattern matching (`%`, `_` wildcards) |
|
|
48
|
-
| `regexp` | `(source, pattern) => WhereExprUnit` | Regular expression matching |
|
|
26
|
+
## WhereExprUnit
|
|
49
27
|
|
|
50
|
-
|
|
28
|
+
```typescript
|
|
29
|
+
class WhereExprUnit {
|
|
30
|
+
readonly expr: WhereExpr;
|
|
31
|
+
constructor(expr: WhereExpr);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
51
34
|
|
|
52
|
-
|
|
53
|
-
|---|---|---|
|
|
54
|
-
| `in` | `(source, values[]) => WhereExprUnit` | IN value list |
|
|
55
|
-
| `inQuery` | `(source, query: Queryable) => WhereExprUnit` | IN subquery (single-column SELECT) |
|
|
56
|
-
| `exists` | `(query: Queryable) => WhereExprUnit` | EXISTS subquery |
|
|
35
|
+
WHERE clause expression wrapper. Returned by comparison and logical methods on `expr`.
|
|
57
36
|
|
|
58
|
-
|
|
37
|
+
## ExprInput
|
|
59
38
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
| `and` | `(conditions: WhereExprUnit[]) => WhereExprUnit` | AND (all must match) |
|
|
64
|
-
| `or` | `(conditions: WhereExprUnit[]) => WhereExprUnit` | OR (any must match) |
|
|
39
|
+
```typescript
|
|
40
|
+
type ExprInput<TPrimitive extends ColumnPrimitive> = ExprUnit<TPrimitive> | TPrimitive;
|
|
41
|
+
```
|
|
65
42
|
|
|
66
|
-
|
|
43
|
+
Accepts either an `ExprUnit` or a literal value. Literal values are automatically wrapped.
|
|
67
44
|
|
|
68
|
-
|
|
69
|
-
|---|---|---|
|
|
70
|
-
| `concat` | `(...args) => ExprUnit<string>` | String concatenation (CONCAT) |
|
|
71
|
-
| `left` | `(source, length) => ExprUnit` | Left N characters |
|
|
72
|
-
| `right` | `(source, length) => ExprUnit` | Right N characters |
|
|
73
|
-
| `trim` | `(source) => ExprUnit` | Trim whitespace |
|
|
74
|
-
| `padStart` | `(source, length, fillString) => ExprUnit` | Left padding (LPAD) |
|
|
75
|
-
| `replace` | `(source, from, to) => ExprUnit` | String replacement |
|
|
76
|
-
| `upper` | `(source) => ExprUnit` | Uppercase |
|
|
77
|
-
| `lower` | `(source) => ExprUnit` | Lowercase |
|
|
78
|
-
| `length` | `(source) => ExprUnit<number>` | Character length |
|
|
79
|
-
| `byteLength` | `(source) => ExprUnit<number>` | Byte length |
|
|
80
|
-
| `substring` | `(source, start, length?) => ExprUnit` | Substring (1-based index) |
|
|
81
|
-
| `indexOf` | `(source, search) => ExprUnit<number>` | Find position (1-based, 0 if not found) |
|
|
82
|
-
|
|
83
|
-
### Number Functions (SELECT)
|
|
45
|
+
## SwitchExprBuilder
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
```
|
|
91
53
|
|
|
92
|
-
|
|
54
|
+
Fluent CASE WHEN builder. Chain `.case()` calls and terminate with `.default()`.
|
|
93
55
|
|
|
94
|
-
|
|
95
|
-
|---|---|---|
|
|
96
|
-
| `year` | `(source) => ExprUnit<number>` | Extract year |
|
|
97
|
-
| `month` | `(source) => ExprUnit<number>` | Extract month |
|
|
98
|
-
| `day` | `(source) => ExprUnit<number>` | Extract day |
|
|
99
|
-
| `hour` | `(source) => ExprUnit<number>` | Extract hour |
|
|
100
|
-
| `minute` | `(source) => ExprUnit<number>` | Extract minute |
|
|
101
|
-
| `second` | `(source) => ExprUnit<number>` | Extract second |
|
|
102
|
-
| `isoWeek` | `(source) => ExprUnit<number>` | ISO week number |
|
|
103
|
-
| `isoWeekStartDate` | `(source) => ExprUnit<DateOnly>` | ISO week start date (Monday) |
|
|
104
|
-
| `isoYearMonth` | `(source) => ExprUnit<DateOnly>` | ISO year-month (YYYYMM format) |
|
|
105
|
-
| `dateDiff` | `(unit: DateUnit, from, to) => ExprUnit<number>` | Date difference |
|
|
106
|
-
| `dateAdd` | `(unit: DateUnit, source, value) => ExprUnit` | Date arithmetic |
|
|
107
|
-
| `formatDate` | `(source, format: string) => ExprUnit<string>` | Date formatting |
|
|
108
|
-
|
|
109
|
-
### Conditional
|
|
56
|
+
## expr Object
|
|
110
57
|
|
|
111
|
-
|
|
112
|
-
|---|---|---|
|
|
113
|
-
| `coalesce` | `(...args) => ExprUnit` | First non-null value (COALESCE) |
|
|
114
|
-
| `nullIf` | `(source, value) => ExprUnit` | NULL if equal (NULLIF) |
|
|
115
|
-
| `is` | `(condition: WhereExprUnit) => ExprUnit<boolean>` | Convert condition to boolean (0/1) |
|
|
116
|
-
| `switch` | `() => SwitchExprBuilder` | CASE WHEN expression (chain `.case().default()`) |
|
|
117
|
-
| `if` | `(condition, then, else?) => ExprUnit` | IIF conditional expression |
|
|
58
|
+
The `expr` object provides all expression-building methods. Methods are grouped by category below.
|
|
118
59
|
|
|
119
|
-
###
|
|
60
|
+
### Value Creation
|
|
120
61
|
|
|
121
62
|
| Method | Signature | Description |
|
|
122
|
-
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `max` | `(arg) => ExprUnit<T \| undefined>` | MAX |
|
|
127
|
-
| `min` | `(arg) => ExprUnit<T \| undefined>` | MIN |
|
|
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 |
|
|
128
67
|
|
|
129
|
-
###
|
|
68
|
+
### Comparison (WHERE)
|
|
130
69
|
|
|
131
|
-
| Method | Signature | Description |
|
|
132
|
-
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `toExpr` | `(value: ExprInput) => Expr` | Convert ExprInput to raw Expr AST |
|
|
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) |
|
|
140
78
|
|
|
141
|
-
###
|
|
79
|
+
### NULL Check (WHERE)
|
|
142
80
|
|
|
143
|
-
|
|
81
|
+
| Method | Signature | SQL | Description |
|
|
82
|
+
|--------|-----------|-----|-------------|
|
|
83
|
+
| `null` | `(source: ExprUnit<T>) => WhereExprUnit` | `IS NULL` | NULL check |
|
|
144
84
|
|
|
145
|
-
|
|
146
|
-
|---|---|---|
|
|
147
|
-
| `rowNumber` | `(spec) => ExprUnit<number>` | ROW_NUMBER() OVER(...) |
|
|
148
|
-
| `rank` | `(spec) => ExprUnit<number>` | RANK() OVER(...) |
|
|
149
|
-
| `denseRank` | `(spec) => ExprUnit<number>` | DENSE_RANK() OVER(...) |
|
|
150
|
-
| `ntile` | `(n, spec) => ExprUnit<number>` | NTILE(n) OVER(...) |
|
|
151
|
-
| `lag` | `(column, spec, offset?, defaultValue?) => ExprUnit` | Previous row value |
|
|
152
|
-
| `lead` | `(column, spec, offset?, defaultValue?) => ExprUnit` | Next row value |
|
|
153
|
-
| `firstValue` | `(column, spec) => ExprUnit` | First value in partition |
|
|
154
|
-
| `lastValue` | `(column, spec) => ExprUnit` | Last value in partition |
|
|
155
|
-
| `sumOver` | `(column, spec) => ExprUnit<number \| undefined>` | Window SUM |
|
|
156
|
-
| `avgOver` | `(column, spec) => ExprUnit<number \| undefined>` | Window AVG |
|
|
157
|
-
| `countOver` | `(spec, column?) => ExprUnit<number>` | Window COUNT |
|
|
158
|
-
| `minOver` | `(column, spec) => ExprUnit` | Window MIN |
|
|
159
|
-
| `maxOver` | `(column, spec) => ExprUnit` | Window MAX |
|
|
85
|
+
### String Search (WHERE)
|
|
160
86
|
|
|
161
|
-
|
|
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 |
|
|
162
91
|
|
|
163
|
-
|
|
92
|
+
### IN / EXISTS (WHERE)
|
|
164
93
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
```
|
|
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 |
|
|
171
99
|
|
|
172
|
-
|
|
100
|
+
### Logical (WHERE)
|
|
173
101
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
.default("bronze"),
|
|
180
|
-
}))
|
|
181
|
-
```
|
|
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 |
|
|
182
107
|
|
|
183
|
-
|
|
108
|
+
### String Functions (SELECT)
|
|
184
109
|
|
|
185
|
-
|
|
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):
|
|
186
201
|
|
|
187
202
|
```typescript
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
readonly expr: Expr;
|
|
192
|
-
|
|
193
|
-
/** Non-nullable assertion accessor */
|
|
194
|
-
get n(): ExprUnit<NonNullable<TPrimitive>>;
|
|
195
|
-
|
|
196
|
-
constructor(dataType: ColumnPrimitiveStr, expr: Expr);
|
|
203
|
+
interface WinSpecInput {
|
|
204
|
+
partitionBy?: ExprInput<ColumnPrimitive>[];
|
|
205
|
+
orderBy?: [ExprInput<ColumnPrimitive>, ("ASC" | "DESC")?][];
|
|
197
206
|
}
|
|
198
207
|
```
|
|
199
208
|
|
|
200
|
-
|
|
209
|
+
**lag/lead options**:
|
|
201
210
|
|
|
202
|
-
|
|
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 |
|
|
203
215
|
|
|
204
|
-
|
|
205
|
-
class WhereExprUnit {
|
|
206
|
-
readonly expr: WhereExpr;
|
|
207
|
-
constructor(expr: WhereExpr);
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
## ExprInput
|
|
212
|
-
|
|
213
|
-
Union type accepting either an `ExprUnit` or a literal value.
|
|
216
|
+
### Helper
|
|
214
217
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
| Method | Signature | Description |
|
|
219
|
+
|--------|-----------|-------------|
|
|
220
|
+
| `toExpr` | `(value: ExprInput<ColumnPrimitive>) => Expr` | Convert ExprInput to Expr JSON AST (internal use) |
|
package/docs/query-builder.md
CHANGED
|
@@ -4,123 +4,147 @@ Transforms `QueryDef` AST into dialect-specific SQL strings.
|
|
|
4
4
|
|
|
5
5
|
## createQueryBuilder
|
|
6
6
|
|
|
7
|
-
Factory function that creates the appropriate `QueryBuilderBase` for a given dialect.
|
|
8
|
-
|
|
9
7
|
```typescript
|
|
10
|
-
function createQueryBuilder(dialect: Dialect): QueryBuilderBase
|
|
8
|
+
function createQueryBuilder(dialect: Dialect): QueryBuilderBase
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
Factory function that creates a dialect-specific QueryBuilder instance.
|
|
14
12
|
|
|
15
13
|
| Parameter | Type | Description |
|
|
16
|
-
|
|
17
|
-
| `dialect` | `"mysql" \| "mssql" \| "postgresql"` | Target
|
|
14
|
+
|-----------|------|-------------|
|
|
15
|
+
| `dialect` | `"mysql" \| "mssql" \| "postgresql"` | Target DBMS dialect |
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
Returns `MysqlQueryBuilder`, `MssqlQueryBuilder`, or `PostgresqlQueryBuilder`.
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
## QueryBuilderBase
|
|
22
20
|
|
|
23
21
|
```typescript
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
abstract class QueryBuilderBase {
|
|
23
|
+
build(def: QueryDef): QueryBuildResult;
|
|
24
|
+
}
|
|
27
25
|
```
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
Abstract base class for rendering `QueryDef` AST to SQL. Implements common dispatch logic; dialect-specific differences are handled by abstract methods in subclasses.
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
| Method | Signature | Description |
|
|
30
|
+
|--------|-----------|-------------|
|
|
31
|
+
| `build` | `(def: QueryDef) => QueryBuildResult` | Convert any QueryDef to SQL |
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
abstract class QueryBuilderBase {
|
|
35
|
-
abstract readonly exprRenderer: ExprRendererBase;
|
|
33
|
+
`QueryBuildResult` contains:
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
39
47
|
```
|
|
40
48
|
|
|
41
|
-
|
|
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.
|
|
42
50
|
|
|
43
|
-
|
|
51
|
+
### MssqlQueryBuilder
|
|
44
52
|
|
|
45
53
|
```typescript
|
|
46
|
-
|
|
54
|
+
class MssqlQueryBuilder extends QueryBuilderBase
|
|
47
55
|
```
|
|
48
56
|
|
|
49
|
-
|
|
57
|
+
MSSQL 2012+ query builder. Handles bracket quoting, `TOP`, `OFFSET ... FETCH NEXT`, `MERGE` for upsert, `SET IDENTITY_INSERT`, etc.
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|---|---|---|
|
|
53
|
-
| `sql` | `string` | Generated SQL |
|
|
54
|
-
| `resultSetIndex?` | `number` | Which result set to read (default: 0) |
|
|
55
|
-
| `resultSetStride?` | `number` | For multi-result sets, read every Nth |
|
|
59
|
+
### PostgresqlQueryBuilder
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
```typescript
|
|
62
|
+
class PostgresqlQueryBuilder extends QueryBuilderBase
|
|
63
|
+
```
|
|
58
64
|
|
|
59
|
-
|
|
65
|
+
PostgreSQL 9.0+ query builder. Handles double-quote quoting, `LIMIT ... OFFSET`, `ON CONFLICT` for upsert, `COPY FROM STDIN`, etc.
|
|
66
|
+
|
|
67
|
+
## ExprRendererBase
|
|
60
68
|
|
|
61
69
|
```typescript
|
|
62
70
|
abstract class ExprRendererBase {
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
renderExpr(expr: Expr): string;
|
|
72
|
+
renderWhereExpr(expr: WhereExpr): string;
|
|
65
73
|
}
|
|
66
74
|
```
|
|
67
75
|
|
|
68
|
-
|
|
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
|
|
69
84
|
|
|
70
|
-
|
|
85
|
+
### MysqlExprRenderer
|
|
71
86
|
|
|
72
87
|
```typescript
|
|
73
|
-
class
|
|
74
|
-
readonly exprRenderer: MysqlExprRenderer;
|
|
75
|
-
}
|
|
88
|
+
class MysqlExprRenderer extends ExprRendererBase
|
|
76
89
|
```
|
|
77
90
|
|
|
78
|
-
MySQL-
|
|
79
|
-
- Uses `<=>` for NULL-safe equality
|
|
80
|
-
- Uses backtick quoting for identifiers
|
|
81
|
-
- INSERT OUTPUT via separate SELECT with `LAST_INSERT_ID()`
|
|
82
|
-
- UPSERT via `INSERT ... ON DUPLICATE KEY UPDATE`
|
|
83
|
-
|
|
84
|
-
## MssqlQueryBuilder
|
|
91
|
+
MySQL expression renderer. Uses `<=>` for NULL-safe equality, `IFNULL`, `LOCATE`, MySQL `DATE_FORMAT` patterns, etc.
|
|
85
92
|
|
|
86
|
-
|
|
93
|
+
### MssqlExprRenderer
|
|
87
94
|
|
|
88
95
|
```typescript
|
|
89
|
-
class
|
|
90
|
-
readonly exprRenderer: MssqlExprRenderer;
|
|
91
|
-
}
|
|
96
|
+
class MssqlExprRenderer extends ExprRendererBase
|
|
92
97
|
```
|
|
93
98
|
|
|
94
|
-
MSSQL
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- OUTPUT clause for INSERT/UPDATE/DELETE
|
|
98
|
-
- `IDENTITY_INSERT` for auto-increment override
|
|
99
|
-
- `OFFSET...FETCH` for pagination
|
|
99
|
+
MSSQL expression renderer. Uses `IIF`, `CHARINDEX`, `FORMAT` for date formatting, `DATALENGTH` for byte length, etc.
|
|
100
|
+
|
|
101
|
+
### PostgresqlExprRenderer
|
|
100
102
|
|
|
101
|
-
|
|
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.
|
|
102
108
|
|
|
103
|
-
|
|
109
|
+
## parseQueryResult
|
|
104
110
|
|
|
105
111
|
```typescript
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
async function parseQueryResult<TRecord>(
|
|
113
|
+
rawResults: Record<string, unknown>[],
|
|
114
|
+
meta: ResultMeta,
|
|
115
|
+
): Promise<TRecord[] | undefined>
|
|
109
116
|
```
|
|
110
117
|
|
|
111
|
-
|
|
112
|
-
- Uses `"` for identifier quoting
|
|
113
|
-
- `RETURNING` clause for INSERT/UPDATE/DELETE output
|
|
114
|
-
- `LIMIT...OFFSET` for pagination
|
|
115
|
-
- `LATERAL` subquery JOINs
|
|
116
|
-
- `IS NOT DISTINCT FROM` for NULL-safe equality
|
|
118
|
+
Parses raw database query results into typed TypeScript objects. Handles:
|
|
117
119
|
|
|
118
|
-
|
|
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
|
|
119
124
|
|
|
120
|
-
|
|
|
121
|
-
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
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.
|
|
125
131
|
|
|
126
|
-
|
|
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
|
+
```
|