@simplysm/orm-common 13.0.98 → 13.0.100

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.
@@ -1,48 +1,45 @@
1
1
  # Expression
2
2
 
3
- Dialect-independent SQL expression builder. Generates JSON AST (`Expr`) instead of SQL strings, which `QueryBuilder` converts to each DBMS dialect.
4
-
5
- Source: `src/expr/expr-unit.ts`, `src/expr/expr.ts`
6
-
7
- ## ExprUnit
3
+ ## `ExprUnit`
8
4
 
9
5
  Type-safe expression wrapper. Tracks expression return type using TypeScript generics.
10
6
 
11
7
  ```typescript
12
8
  class ExprUnit<TPrimitive extends ColumnPrimitive> {
13
9
  readonly $infer!: TPrimitive;
14
- readonly dataType: ColumnPrimitiveStr;
15
- readonly expr: Expr;
16
-
17
- /** Strip undefined from the type (non-null assertion) */
18
10
  get n(): ExprUnit<NonNullable<TPrimitive>>;
19
-
20
- constructor(dataType: ColumnPrimitiveStr, expr: Expr);
11
+ constructor(readonly dataType: ColumnPrimitiveStr, readonly expr: Expr);
21
12
  }
22
13
  ```
23
14
 
24
- ## WhereExprUnit
15
+ | Property | Type | Description |
16
+ |----------|------|-------------|
17
+ | `$infer` | `TPrimitive` | Type inference marker (not used at runtime) |
18
+ | `n` | `ExprUnit<NonNullable<TPrimitive>>` | Non-nullable version of this expression |
19
+ | `dataType` | `ColumnPrimitiveStr` | Column data type name |
20
+ | `expr` | `Expr` | Internal expression AST |
21
+
22
+ ## `WhereExprUnit`
25
23
 
26
24
  Expression wrapper for WHERE clause conditions.
27
25
 
28
26
  ```typescript
29
27
  class WhereExprUnit {
30
- readonly expr: WhereExpr;
31
- constructor(expr: WhereExpr);
28
+ constructor(readonly expr: WhereExpr);
32
29
  }
33
30
  ```
34
31
 
35
- ## ExprInput
32
+ ## `ExprInput`
36
33
 
37
- Input type that accepts either an `ExprUnit` or a literal value.
34
+ Input type that accepts `ExprUnit` or literal values.
38
35
 
39
36
  ```typescript
40
37
  type ExprInput<TPrimitive extends ColumnPrimitive> = ExprUnit<TPrimitive> | TPrimitive;
41
38
  ```
42
39
 
43
- ## SwitchExprBuilder
40
+ ## `SwitchExprBuilder`
44
41
 
45
- Builder interface returned by `expr.switch()` for CASE WHEN expressions.
42
+ CASE/WHEN expression builder interface.
46
43
 
47
44
  ```typescript
48
45
  interface SwitchExprBuilder<TPrimitive extends ColumnPrimitive> {
@@ -51,246 +48,187 @@ interface SwitchExprBuilder<TPrimitive extends ColumnPrimitive> {
51
48
  }
52
49
  ```
53
50
 
54
- ---
55
-
56
- ## expr
57
-
58
- The main expression builder object. All methods return `ExprUnit` or `WhereExprUnit`.
59
-
60
- ### Value Creation
61
-
62
- | Method | Signature | Description |
63
- |--------|-----------|-------------|
64
- | `val` | `val<TStr>(dataType: TStr, value: T): ExprUnit` | Wrap literal value as expression |
65
- | `col` | `col<TStr>(dataType: ColumnPrimitiveStr, ...path: string[]): ExprUnit` | Column reference (internal use) |
66
- | `raw` | `raw<T>(dataType: T): (strings, ...values) => ExprUnit` | Raw SQL tagged template (escape hatch) |
67
-
68
- ```typescript
69
- expr.val("string", "active")
70
- expr.val("number", 100)
71
- expr.val("DateTime", DateTime.now())
72
-
73
- // Raw SQL
74
- expr.raw("string")`JSON_EXTRACT(${u.metadata}, '$.email')`
75
- ```
76
-
77
- ### Comparison Operators (WHERE)
78
-
79
- | Method | SQL | Description |
80
- |--------|-----|-------------|
81
- | `eq(source, target)` | `<=>` / `IS NULL OR =` | Equality (NULL-safe) |
82
- | `gt(source, target)` | `>` | Greater than |
83
- | `lt(source, target)` | `<` | Less than |
84
- | `gte(source, target)` | `>=` | Greater than or equal |
85
- | `lte(source, target)` | `<=` | Less than or equal |
86
- | `between(source, from?, to?)` | `BETWEEN` | Range (undefined = unbounded) |
87
-
88
- ```typescript
89
- db.user().where((u) => [
90
- expr.eq(u.status, "active"),
91
- expr.gte(u.age, 18),
92
- expr.between(u.score, 60, 100),
93
- ])
94
- ```
95
-
96
- ### NULL Check
97
-
98
- | Method | SQL | Description |
99
- |--------|-----|-------------|
100
- | `null(source)` | `IS NULL` | Check if value is NULL |
101
-
102
- ### String Search (WHERE)
103
-
104
- | Method | SQL | Description |
105
- |--------|-----|-------------|
106
- | `like(source, pattern)` | `LIKE ... ESCAPE '\'` | Pattern matching (`%`, `_` wildcards) |
107
- | `regexp(source, pattern)` | `REGEXP` | Regular expression matching |
108
-
109
- ### IN / EXISTS (WHERE)
51
+ ## `expr`
110
52
 
111
- | Method | SQL | Description |
112
- |--------|-----|-------------|
113
- | `in(source, values)` | `IN (...)` | Value list inclusion |
114
- | `inQuery(source, query)` | `IN (SELECT ...)` | Subquery inclusion (single column) |
115
- | `exists(query)` | `EXISTS (SELECT ...)` | Subquery existence check |
53
+ Dialect-independent SQL expression builder. Generates JSON AST (`Expr`) instead of SQL strings, which `QueryBuilder` converts to each DBMS (MySQL, MSSQL, PostgreSQL).
116
54
 
117
55
  ```typescript
118
- db.user().where((u) => [
119
- expr.in(u.status, ["active", "pending"]),
120
- expr.exists(
121
- db.order().where((o) => [expr.eq(o.userId, u.id)])
122
- ),
123
- ])
56
+ const expr: {
57
+ // Value creation
58
+ val<TStr extends ColumnPrimitiveStr>(dataType: TStr, value): ExprUnit<...>;
59
+ col<TStr extends ColumnPrimitiveStr>(dataType: ColumnPrimitiveStr, ...path: string[]): ExprUnit<...>;
60
+ raw<T extends ColumnPrimitiveStr>(dataType: T): (strings: TemplateStringsArray, ...values: ExprInput<ColumnPrimitive>[]) => ExprUnit<...>;
61
+
62
+ // Comparison (WHERE)
63
+ eq<T extends ColumnPrimitive>(source: ExprUnit<T>, target: ExprInput<T>): WhereExprUnit;
64
+ gt<T extends ColumnPrimitive>(source: ExprUnit<T>, target: ExprInput<T>): WhereExprUnit;
65
+ lt<T extends ColumnPrimitive>(source: ExprUnit<T>, target: ExprInput<T>): WhereExprUnit;
66
+ gte<T extends ColumnPrimitive>(source: ExprUnit<T>, target: ExprInput<T>): WhereExprUnit;
67
+ lte<T extends ColumnPrimitive>(source: ExprUnit<T>, target: ExprInput<T>): WhereExprUnit;
68
+ between<T extends ColumnPrimitive>(source: ExprUnit<T>, from?: ExprInput<T>, to?: ExprInput<T>): WhereExprUnit;
69
+ isNull(arg: ExprUnit<ColumnPrimitive>): WhereExprUnit;
70
+ like(source: ExprUnit<string | undefined>, pattern: ExprInput<string>): WhereExprUnit;
71
+ regexp(source: ExprUnit<string | undefined>, pattern: ExprInput<string>): WhereExprUnit;
72
+ in<T extends ColumnPrimitive>(source: ExprUnit<T>, values: ExprInput<T>[]): WhereExprUnit;
73
+ inQuery<T extends ColumnPrimitive>(source: ExprUnit<T>, query: Queryable<any, any>): WhereExprUnit;
74
+ exists(query: Queryable<any, any>): WhereExprUnit;
75
+
76
+ // Logical
77
+ not(condition: WhereExprUnit): WhereExprUnit;
78
+ and(...conditions: WhereExprUnit[]): WhereExprUnit;
79
+ or(...conditions: WhereExprUnit[]): WhereExprUnit;
80
+
81
+ // String
82
+ concat(...args: ExprInput<string | undefined>[]): ExprUnit<string>;
83
+ left(source: ExprInput<string | undefined>, length: ExprInput<number>): ExprUnit<string>;
84
+ right(source: ExprInput<string | undefined>, length: ExprInput<number>): ExprUnit<string>;
85
+ trim(arg: ExprInput<string | undefined>): ExprUnit<string>;
86
+ padStart(source: ExprInput<string | undefined>, length: ExprInput<number>, fillString: ExprInput<string>): ExprUnit<string>;
87
+ replace(source: ExprInput<string | undefined>, from: ExprInput<string>, to: ExprInput<string>): ExprUnit<string>;
88
+ upper(arg: ExprInput<string | undefined>): ExprUnit<string>;
89
+ lower(arg: ExprInput<string | undefined>): ExprUnit<string>;
90
+ length(arg: ExprInput<string | undefined>): ExprUnit<number>;
91
+ byteLength(arg: ExprInput<string | undefined>): ExprUnit<number>;
92
+ substring(source: ExprInput<string | undefined>, start: ExprInput<number>, length?: ExprInput<number>): ExprUnit<string>;
93
+ indexOf(source: ExprInput<string | undefined>, search: ExprInput<string>): ExprUnit<number>;
94
+
95
+ // Numeric
96
+ abs(arg: ExprInput<number | undefined>): ExprUnit<number>;
97
+ round(arg: ExprInput<number | undefined>, digits: number): ExprUnit<number>;
98
+ ceil(arg: ExprInput<number | undefined>): ExprUnit<number>;
99
+ floor(arg: ExprInput<number | undefined>): ExprUnit<number>;
100
+
101
+ // Date
102
+ year(arg: ExprInput<DateTime | DateOnly | undefined>): ExprUnit<number>;
103
+ month(arg: ExprInput<DateTime | DateOnly | undefined>): ExprUnit<number>;
104
+ day(arg: ExprInput<DateTime | DateOnly | undefined>): ExprUnit<number>;
105
+ hour(arg: ExprInput<DateTime | undefined>): ExprUnit<number>;
106
+ minute(arg: ExprInput<DateTime | undefined>): ExprUnit<number>;
107
+ second(arg: ExprInput<DateTime | undefined>): ExprUnit<number>;
108
+ isoWeek(arg: ExprInput<DateTime | DateOnly | undefined>): ExprUnit<number>;
109
+ isoWeekStartDate(arg: ExprInput<DateTime | DateOnly | undefined>): ExprUnit<DateOnly>;
110
+ isoYearMonth(arg: ExprInput<DateTime | DateOnly | undefined>): ExprUnit<string>;
111
+ dateDiff(unit: DateUnit, from: ExprInput<ColumnPrimitive>, to: ExprInput<ColumnPrimitive>): ExprUnit<number>;
112
+ dateAdd(unit: DateUnit, source: ExprInput<ColumnPrimitive>, value: ExprInput<number>): ExprUnit<DateTime>;
113
+ formatDate(source: ExprInput<ColumnPrimitive>, format: string): ExprUnit<string>;
114
+
115
+ // Conditional
116
+ coalesce<T extends ColumnPrimitive>(...args: ExprInput<T | undefined>[]): ExprUnit<T>;
117
+ nullIf<T extends ColumnPrimitive>(source: ExprInput<T>, value: ExprInput<T>): ExprUnit<T | undefined>;
118
+ is(condition: WhereExprUnit): ExprUnit<number>;
119
+ switch<T extends ColumnPrimitive>(dataType: ColumnPrimitiveStr): SwitchExprBuilder<T>;
120
+ if<T extends ColumnPrimitive>(condition: WhereExprUnit, then: ExprInput<T>, elseVal?: ExprInput<T>): ExprUnit<T>;
121
+
122
+ // Aggregate
123
+ count(arg?: ExprUnit<ColumnPrimitive>, distinct?: boolean): ExprUnit<number>;
124
+ sum(arg: ExprUnit<number | undefined>): ExprUnit<number>;
125
+ avg(arg: ExprUnit<number | undefined>): ExprUnit<number>;
126
+ max<T extends ColumnPrimitive>(arg: ExprUnit<T>): ExprUnit<T>;
127
+ min<T extends ColumnPrimitive>(arg: ExprUnit<T>): ExprUnit<T>;
128
+
129
+ // Other
130
+ greatest<T extends ColumnPrimitive>(...args: ExprInput<T>[]): ExprUnit<T>;
131
+ least<T extends ColumnPrimitive>(...args: ExprInput<T>[]): ExprUnit<T>;
132
+ rowNum(): ExprUnit<number>;
133
+ random(): ExprUnit<number>;
134
+ cast<TDataType extends DataType>(source: ExprInput<ColumnPrimitive>, targetType: TDataType): ExprUnit<InferColumnPrimitiveFromDataType<TDataType>>;
135
+
136
+ // Window
137
+ window(fn: WinFn, spec?: WinSpecInput): ExprUnit<number>;
138
+
139
+ // Subquery
140
+ subquery<T extends ColumnPrimitive>(query: Queryable<any, any>, selectFn: (q: ...) => ExprUnit<T>): ExprUnit<T>;
141
+ };
124
142
  ```
125
143
 
126
- ### Logical Operators (WHERE)
144
+ ### Value Creation
127
145
 
128
- | Method | SQL | Description |
129
- |--------|-----|-------------|
130
- | `not(arg)` | `NOT (...)` | Negate a condition |
131
- | `and(conditions)` | `... AND ...` | All conditions must be true |
132
- | `or(conditions)` | `... OR ...` | At least one must be true |
146
+ | Method | Description |
147
+ |--------|-------------|
148
+ | `val()` | Wrap literal value as ExprUnit |
149
+ | `col()` | Generate column reference |
150
+ | `raw()` | Raw SQL expression (escape hatch, tagged template literal) |
133
151
 
134
- ### String Functions (SELECT)
152
+ ### Comparison (WHERE)
135
153
 
136
154
  | Method | SQL | Description |
137
155
  |--------|-----|-------------|
138
- | `concat(...args)` | `CONCAT(...)` | String concatenation (NULL-safe) |
139
- | `left(source, length)` | `LEFT(...)` | Extract from left |
140
- | `right(source, length)` | `RIGHT(...)` | Extract from right |
141
- | `trim(source)` | `TRIM(...)` | Remove whitespace |
142
- | `padStart(source, length, fill)` | `LPAD(...)` | Left padding |
143
- | `replace(source, from, to)` | `REPLACE(...)` | String replacement |
144
- | `upper(source)` | `UPPER(...)` | Uppercase |
145
- | `lower(source)` | `LOWER(...)` | Lowercase |
146
- | `length(source)` | `CHAR_LENGTH(...)` | Character count |
147
- | `byteLength(source)` | `OCTET_LENGTH(...)` | Byte count |
148
- | `substring(source, start, length?)` | `SUBSTRING(...)` | Extract substring (1-based) |
149
- | `indexOf(source, search)` | `LOCATE(...)`/`CHARINDEX(...)` | Find position (1-based, 0 if not found) |
150
-
151
- ```typescript
152
- db.user().select((u) => ({
153
- fullName: expr.concat(u.firstName, " ", u.lastName),
154
- initial: expr.left(u.name, 1),
155
- email: expr.lower(u.email),
156
- }))
157
- ```
158
-
159
- ### Numeric Functions (SELECT)
156
+ | `eq()` | `=` | Equality comparison (NULL-safe) |
157
+ | `gt()` | `>` | Greater than |
158
+ | `lt()` | `<` | Less than |
159
+ | `gte()` | `>=` | Greater than or equal |
160
+ | `lte()` | `<=` | Less than or equal |
161
+ | `between()` | `BETWEEN` | Range comparison |
162
+ | `isNull()` | `IS NULL` | NULL check |
163
+ | `like()` | `LIKE` | Pattern matching |
164
+ | `regexp()` | `REGEXP` | Regular expression matching |
165
+ | `in()` | `IN` | Value list inclusion |
166
+ | `inQuery()` | `IN (SELECT)` | Subquery inclusion |
167
+ | `exists()` | `EXISTS` | Subquery existence |
168
+
169
+ ### Logical
160
170
 
161
171
  | Method | SQL | Description |
162
172
  |--------|-----|-------------|
163
- | `abs(source)` | `ABS(...)` | Absolute value |
164
- | `round(source, digits)` | `ROUND(...)` | Round to N digits |
165
- | `ceil(source)` | `CEILING(...)` | Ceiling |
166
- | `floor(source)` | `FLOOR(...)` | Floor |
173
+ | `not()` | `NOT` | Logical negation |
174
+ | `and()` | `AND` | Logical conjunction |
175
+ | `or()` | `OR` | Logical disjunction |
167
176
 
168
- ### Date Functions (SELECT)
177
+ ### String Functions
169
178
 
170
179
  | Method | SQL | Description |
171
180
  |--------|-----|-------------|
172
- | `year(source)` | `YEAR(...)` | Extract year |
173
- | `month(source)` | `MONTH(...)` | Extract month (1-12) |
174
- | `day(source)` | `DAY(...)` | Extract day (1-31) |
175
- | `hour(source)` | `HOUR(...)` | Extract hour (0-23) |
176
- | `minute(source)` | `MINUTE(...)` | Extract minute (0-59) |
177
- | `second(source)` | `SECOND(...)` | Extract second (0-59) |
178
- | `isoWeek(source)` | `WEEK(..., 3)` | ISO week number (1-53) |
179
- | `isoWeekStartDate(source)` | (computed) | Monday of the week |
180
- | `isoYearMonth(source)` | (computed) | First day of the month |
181
- | `dateDiff(unit, from, to)` | `DATEDIFF(...)` | Date difference |
182
- | `dateAdd(unit, source, value)` | `DATEADD(...)` | Add to date |
183
- | `formatDate(source, format)` | `DATE_FORMAT(...)` | Format date as string |
184
-
185
- `DateUnit` values: `"year"`, `"month"`, `"day"`, `"hour"`, `"minute"`, `"second"`
186
-
187
- ```typescript
188
- db.user().select((u) => ({
189
- age: expr.dateDiff("year", u.birthDate, expr.val("DateOnly", DateOnly.today())),
190
- expiresAt: expr.dateAdd("month", u.startDate, 12),
191
- }))
192
- ```
193
-
194
- ### Conditional Functions (SELECT)
181
+ | `concat()` | `CONCAT` | String concatenation |
182
+ | `left()` | `LEFT` | Extract left N characters |
183
+ | `right()` | `RIGHT` | Extract right N characters |
184
+ | `trim()` | `TRIM` | Remove leading/trailing whitespace |
185
+ | `padStart()` | `LPAD` | Left padding |
186
+ | `replace()` | `REPLACE` | String replacement |
187
+ | `upper()` | `UPPER` | Uppercase |
188
+ | `lower()` | `LOWER` | Lowercase |
189
+ | `length()` | `CHAR_LENGTH` | Character length |
190
+ | `byteLength()` | `LENGTH/DATALENGTH` | Byte length |
191
+ | `substring()` | `SUBSTRING` | Substring extraction |
192
+ | `indexOf()` | `LOCATE/CHARINDEX` | Find string position |
193
+
194
+ ### Numeric Functions
195
195
 
196
196
  | Method | SQL | Description |
197
197
  |--------|-----|-------------|
198
- | `coalesce(...args)` | `COALESCE(...)` | First non-null value |
199
- | `nullIf(source, value)` | `NULLIF(...)` | Return NULL if equal |
200
- | `is(condition)` | (computed) | Transform WHERE to boolean column |
201
- | `switch<T>()` | `CASE WHEN ... END` | CASE WHEN builder |
202
- | `if(condition, then, else_)` | `IF(...)`/`IIF(...)` | Ternary conditional |
203
-
204
- ```typescript
205
- db.user().select((u) => ({
206
- displayName: expr.coalesce(u.nickname, u.name, "Guest"),
207
- isActive: expr.is(expr.eq(u.status, "active")),
208
- grade: expr.switch<string>()
209
- .case(expr.gte(u.score, 90), "A")
210
- .case(expr.gte(u.score, 80), "B")
211
- .default("C"),
212
- }))
213
- ```
198
+ | `abs()` | `ABS` | Absolute value |
199
+ | `round()` | `ROUND` | Rounding |
200
+ | `ceil()` | `CEIL` | Ceiling |
201
+ | `floor()` | `FLOOR` | Floor |
214
202
 
215
- ### Aggregate Functions (SELECT)
203
+ ### Date Functions
216
204
 
217
205
  | Method | SQL | Description |
218
206
  |--------|-----|-------------|
219
- | `count(arg?, distinct?)` | `COUNT(...)` | Row count |
220
- | `sum(arg)` | `SUM(...)` | Sum (NULL ignored) |
221
- | `avg(arg)` | `AVG(...)` | Average (NULL ignored) |
222
- | `max(arg)` | `MAX(...)` | Maximum value |
223
- | `min(arg)` | `MIN(...)` | Minimum value |
224
-
225
- ### Other Functions (SELECT)
207
+ | `year()` | `YEAR` | Extract year |
208
+ | `month()` | `MONTH` | Extract month |
209
+ | `day()` | `DAY` | Extract day |
210
+ | `hour()` | `HOUR` | Extract hour |
211
+ | `minute()` | `MINUTE` | Extract minute |
212
+ | `second()` | `SECOND` | Extract second |
213
+ | `isoWeek()` | `WEEK` | ISO week number |
214
+ | `isoWeekStartDate()` | - | ISO week start date |
215
+ | `isoYearMonth()` | - | ISO year-month (YYYYMM) |
216
+ | `dateDiff()` | `DATEDIFF` | Date difference |
217
+ | `dateAdd()` | `DATEADD` | Date arithmetic |
218
+ | `formatDate()` | `FORMAT/DATE_FORMAT` | Date formatting |
219
+
220
+ ### Aggregate Functions
226
221
 
227
222
  | Method | SQL | Description |
228
223
  |--------|-----|-------------|
229
- | `greatest(...args)` | `GREATEST(...)` | Greatest among values |
230
- | `least(...args)` | `LEAST(...)` | Least among values |
231
- | `rowNum()` | (computed) | Row number (no OVER) |
232
- | `random()` | `RAND()`/`RANDOM()` | Random number (0-1) |
233
- | `cast(source, targetType)` | `CAST(... AS ...)` | Type conversion |
234
- | `subquery(dataType, queryable)` | `(SELECT ...)` | Scalar subquery |
235
-
236
- ```typescript
237
- db.user().select((u) => ({
238
- id: u.id,
239
- postCount: expr.subquery("number",
240
- db.post()
241
- .where((p) => [expr.eq(p.userId, u.id)])
242
- .select(() => ({ cnt: expr.count() }))
243
- ),
244
- }))
245
- ```
224
+ | `count()` | `COUNT` | Record count |
225
+ | `sum()` | `SUM` | Sum |
226
+ | `avg()` | `AVG` | Average |
227
+ | `max()` | `MAX` | Maximum |
228
+ | `min()` | `MIN` | Minimum |
246
229
 
247
- ### Window Functions (SELECT)
248
-
249
- All window functions accept a `WinSpecInput`:
250
-
251
- ```typescript
252
- interface WinSpecInput {
253
- partitionBy?: ExprInput<ColumnPrimitive>[];
254
- orderBy?: [ExprInput<ColumnPrimitive>, ("ASC" | "DESC")?][];
255
- }
256
- ```
230
+ ### Window Functions
257
231
 
258
232
  | Method | SQL | Description |
259
233
  |--------|-----|-------------|
260
- | `rowNumber(spec)` | `ROW_NUMBER() OVER(...)` | Row number within partition |
261
- | `rank(spec)` | `RANK() OVER(...)` | Rank (ties skip: 1,1,3) |
262
- | `denseRank(spec)` | `DENSE_RANK() OVER(...)` | Dense rank (ties consecutive: 1,1,2) |
263
- | `ntile(n, spec)` | `NTILE(n) OVER(...)` | Split into n groups |
264
- | `lag(column, spec, options?)` | `LAG() OVER(...)` | Previous row value |
265
- | `lead(column, spec, options?)` | `LEAD() OVER(...)` | Next row value |
266
- | `firstValue(column, spec)` | `FIRST_VALUE() OVER(...)` | First value in frame |
267
- | `lastValue(column, spec)` | `LAST_VALUE() OVER(...)` | Last value in frame |
268
- | `sumOver(column, spec)` | `SUM() OVER(...)` | Window sum |
269
- | `avgOver(column, spec)` | `AVG() OVER(...)` | Window average |
270
- | `countOver(spec, column?)` | `COUNT() OVER(...)` | Window count |
271
- | `minOver(column, spec)` | `MIN() OVER(...)` | Window minimum |
272
- | `maxOver(column, spec)` | `MAX() OVER(...)` | Window maximum |
273
-
274
- `lag` and `lead` options:
275
- - `offset?: number` -- default 1
276
- - `default?: ExprInput<T>` -- default value when no row exists
277
-
278
- ```typescript
279
- db.order().select((o) => ({
280
- ...o,
281
- rowNum: expr.rowNumber({
282
- partitionBy: [o.userId],
283
- orderBy: [[o.createdAt, "DESC"]],
284
- }),
285
- runningTotal: expr.sumOver(o.amount, {
286
- partitionBy: [o.userId],
287
- orderBy: [[o.createdAt, "ASC"]],
288
- }),
289
- }))
290
- ```
291
-
292
- ### Helper
293
-
294
- | Method | Description |
295
- |--------|-------------|
296
- | `toExpr(value: ExprInput<ColumnPrimitive>): Expr` | Convert ExprInput to Expr JSON AST (internal use) |
234
+ | `window()` | `OVER(...)` | Window function (rowNumber, rank, denseRank, ntile, lag, lead, firstValue, lastValue, sum, avg, count, min, max) |