sumak 0.0.5 → 0.0.6

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.
@@ -35,6 +35,18 @@ export class Col {
35
35
  return wrap(binOp("LIKE", this._node, rawLit(pattern)));
36
36
  }
37
37
 
38
+ notLike(pattern) {
39
+ return wrap(binOp("NOT LIKE", this._node, rawLit(pattern)));
40
+ }
41
+
42
+ ilike(pattern) {
43
+ return wrap(binOp("ILIKE", this._node, rawLit(pattern)));
44
+ }
45
+
46
+ notIlike(pattern) {
47
+ return wrap(binOp("NOT ILIKE", this._node, rawLit(pattern)));
48
+ }
49
+
38
50
  in(values) {
39
51
  return wrap({
40
52
  type: "in",
@@ -79,10 +91,101 @@ export class Col {
79
91
  });
80
92
  }
81
93
 
94
+ notBetween(low, high) {
95
+ return wrap({
96
+ type: "between",
97
+ expr: this._node,
98
+ low: autoParam(low),
99
+ high: autoParam(high),
100
+ negated: true
101
+ });
102
+ }
103
+
104
+ betweenSymmetric(low, high) {
105
+ return wrap({
106
+ type: "between",
107
+ expr: this._node,
108
+ low: autoParam(low),
109
+ high: autoParam(high),
110
+ negated: false,
111
+ symmetric: true
112
+ });
113
+ }
114
+
115
+ inSubquery(query) {
116
+ return wrap({
117
+ type: "in",
118
+ expr: this._node,
119
+ values: query,
120
+ negated: false
121
+ });
122
+ }
123
+
124
+ notInSubquery(query) {
125
+ return wrap({
126
+ type: "in",
127
+ expr: this._node,
128
+ values: query,
129
+ negated: true
130
+ });
131
+ }
132
+
133
+ eqExpr(value) {
134
+ return wrap(binOp("=", this._node, value.node));
135
+ }
136
+
137
+ neqExpr(value) {
138
+ return wrap(binOp("!=", this._node, value.node));
139
+ }
140
+
141
+ gtExpr(value) {
142
+ return wrap(binOp(">", this._node, value.node));
143
+ }
144
+
145
+ gteExpr(value) {
146
+ return wrap(binOp(">=", this._node, value.node));
147
+ }
148
+
149
+ ltExpr(value) {
150
+ return wrap(binOp("<", this._node, value.node));
151
+ }
152
+
153
+ lteExpr(value) {
154
+ return wrap(binOp("<=", this._node, value.node));
155
+ }
156
+
157
+ isDistinctFrom(value) {
158
+ return wrap(binOp("IS DISTINCT FROM", this._node, autoParam(value)));
159
+ }
160
+
161
+ isNotDistinctFrom(value) {
162
+ return wrap(binOp("IS NOT DISTINCT FROM", this._node, autoParam(value)));
163
+ }
164
+
82
165
  eqCol(other) {
83
166
  return wrap(binOp("=", this._node, other._node));
84
167
  }
85
168
 
169
+ neqCol(other) {
170
+ return wrap(binOp("!=", this._node, other._node));
171
+ }
172
+
173
+ gtCol(other) {
174
+ return wrap(binOp(">", this._node, other._node));
175
+ }
176
+
177
+ ltCol(other) {
178
+ return wrap(binOp("<", this._node, other._node));
179
+ }
180
+
181
+ gteCol(other) {
182
+ return wrap(binOp(">=", this._node, other._node));
183
+ }
184
+
185
+ lteCol(other) {
186
+ return wrap(binOp("<=", this._node, other._node));
187
+ }
188
+
86
189
  toExpr() {
87
190
  return wrap(this._node);
88
191
  }
@@ -114,18 +217,30 @@ export function createColumnProxies(_table) {
114
217
  }
115
218
 
116
219
 
117
- export function and(left, right) {
118
- return wrap(rawAnd(left.node, right.node));
220
+ export function and(...exprs) {
221
+ if (exprs.length === 0) return wrap(rawLit(true));
222
+ if (exprs.length === 1) return exprs[0];
223
+ return exprs.reduce((acc, expr) => wrap(rawAnd(acc.node, expr.node)));
119
224
  }
120
225
 
121
- export function or(left, right) {
122
- return wrap(rawOr(left.node, right.node));
226
+ export function or(...exprs) {
227
+ if (exprs.length === 0) return wrap(rawLit(false));
228
+ if (exprs.length === 1) return exprs[0];
229
+ return exprs.reduce((acc, expr) => wrap(rawOr(acc.node, expr.node)));
123
230
  }
124
231
 
125
232
  export function val(value) {
126
233
  return wrap(rawLit(value));
127
234
  }
128
235
 
236
+ export function rawExpr(sql, params = []) {
237
+ return wrap({
238
+ type: "raw",
239
+ sql,
240
+ params
241
+ });
242
+ }
243
+
129
244
  export function sqlFn(name, ...args) {
130
245
  return wrap(rawFn(name, args.map((a) => a.node)));
131
246
  }
@@ -148,10 +263,30 @@ export function sum(expr) {
148
263
  return wrap(rawFn("SUM", [expr.node]));
149
264
  }
150
265
 
266
+ export function sumDistinct(expr) {
267
+ const node = {
268
+ type: "function_call",
269
+ name: "SUM",
270
+ args: [expr.node],
271
+ distinct: true
272
+ };
273
+ return wrap(node);
274
+ }
275
+
151
276
  export function avg(expr) {
152
277
  return wrap(rawFn("AVG", [expr.node]));
153
278
  }
154
279
 
280
+ export function avgDistinct(expr) {
281
+ const node = {
282
+ type: "function_call",
283
+ name: "AVG",
284
+ args: [expr.node],
285
+ distinct: true
286
+ };
287
+ return wrap(node);
288
+ }
289
+
155
290
  export function min(expr) {
156
291
  return wrap(rawFn("MIN", [expr.node]));
157
292
  }
@@ -160,14 +295,43 @@ export function max(expr) {
160
295
  return wrap(rawFn("MAX", [expr.node]));
161
296
  }
162
297
 
163
- export function coalesce(expr, fallback) {
164
- return wrap(rawFn("COALESCE", [expr.node, fallback.node]));
298
+ export function coalesce(...args) {
299
+ return wrap(rawFn("COALESCE", args.map((a) => a.node)));
165
300
  }
166
301
 
167
302
  export function not(expr) {
168
303
  return wrap(rawNot(expr.node));
169
304
  }
170
305
 
306
+ export function add(a, b) {
307
+ return wrap(binOp("+", a.node, b.node));
308
+ }
309
+
310
+ export function sub(a, b) {
311
+ return wrap(binOp("-", a.node, b.node));
312
+ }
313
+
314
+ export function mul(a, b) {
315
+ return wrap(binOp("*", a.node, b.node));
316
+ }
317
+
318
+ export function div(a, b) {
319
+ return wrap(binOp("/", a.node, b.node));
320
+ }
321
+
322
+ export function mod(a, b) {
323
+ return wrap(binOp("%", a.node, b.node));
324
+ }
325
+
326
+ export function neg(expr) {
327
+ return wrap({
328
+ type: "unary_op",
329
+ op: "-",
330
+ operand: expr.node,
331
+ position: "prefix"
332
+ });
333
+ }
334
+
171
335
  export function exists(query) {
172
336
  return wrap(rawExists(query));
173
337
  }
@@ -280,6 +444,9 @@ export class WindowBuilder {
280
444
  range(start, end) {
281
445
  return this._withFrame("RANGE", start, end);
282
446
  }
447
+ groups(start, end) {
448
+ return this._withFrame("GROUPS", start, end);
449
+ }
283
450
 
284
451
  _withFrame(kind, start, end) {
285
452
  const b = new WindowBuilder();
@@ -386,10 +553,85 @@ export function ceil(expr) {
386
553
  return wrap(rawFn("CEIL", [expr.node]));
387
554
  }
388
555
 
556
+ export function jsonAgg(expr) {
557
+ return wrap(rawFn("JSON_AGG", [expr.node]));
558
+ }
559
+
560
+ export function toJson(expr) {
561
+ return wrap(rawFn("TO_JSON", [expr.node]));
562
+ }
563
+
564
+ export function jsonBuildObject(...pairs) {
565
+ const args = [];
566
+ for (const [key, val] of pairs) {
567
+ args.push(rawLit(key));
568
+ args.push(val.node);
569
+ }
570
+ return wrap(rawFn("JSON_BUILD_OBJECT", args));
571
+ }
572
+
573
+
574
+ export function arrayContains(arr, values) {
575
+ return wrap(binOp("@>", arr.node, values.node));
576
+ }
577
+
578
+ export function arrayContainedBy(arr, values) {
579
+ return wrap(binOp("<@", arr.node, values.node));
580
+ }
581
+
582
+ export function arrayOverlaps(arr, values) {
583
+ return wrap(binOp("&&", arr.node, values.node));
584
+ }
585
+
389
586
  export function floor(expr) {
390
587
  return wrap(rawFn("FLOOR", [expr.node]));
391
588
  }
392
589
 
590
+ export function stringAgg(expr, delimiter, orderBy) {
591
+ const node = {
592
+ type: "function_call",
593
+ name: "STRING_AGG",
594
+ args: [expr.node, rawLit(delimiter)],
595
+ orderBy: orderBy?.map((o) => ({
596
+ expr: o.expr.node,
597
+ direction: o.direction ?? "ASC"
598
+ }))
599
+ };
600
+ return wrap(node);
601
+ }
602
+
603
+ export function arrayAgg(expr, orderBy) {
604
+ const node = {
605
+ type: "function_call",
606
+ name: "ARRAY_AGG",
607
+ args: [expr.node],
608
+ orderBy: orderBy?.map((o) => ({
609
+ expr: o.expr.node,
610
+ direction: o.direction ?? "ASC"
611
+ }))
612
+ };
613
+ return wrap(node);
614
+ }
615
+
616
+ export function aggOrderBy(agg, orderBy) {
617
+ const fnNode = agg.node;
618
+ return wrap({
619
+ ...fnNode,
620
+ orderBy: orderBy.map((o) => ({
621
+ expr: o.expr.node,
622
+ direction: o.direction ?? "ASC"
623
+ }))
624
+ });
625
+ }
626
+
627
+ export function tuple(...exprs) {
628
+ const node = {
629
+ type: "tuple",
630
+ elements: exprs.map((e) => e.node)
631
+ };
632
+ return wrap(node);
633
+ }
634
+
393
635
  export function filter(agg, condition) {
394
636
  const fnNode = agg.node;
395
637
  return wrap({
@@ -13,6 +13,9 @@ export declare class SelectBuilder {
13
13
  innerJoin(table: string | TableRefNode, on: ExpressionNode, alias?: string): SelectBuilder;
14
14
  leftJoin(table: string | TableRefNode, on: ExpressionNode, alias?: string): SelectBuilder;
15
15
  rightJoin(table: string | TableRefNode, on: ExpressionNode, alias?: string): SelectBuilder;
16
+ innerJoinLateral(subquery: SubqueryNode, on: ExpressionNode): SelectBuilder;
17
+ leftJoinLateral(subquery: SubqueryNode, on: ExpressionNode): SelectBuilder;
18
+ crossJoinLateral(subquery: SubqueryNode): SelectBuilder;
16
19
  groupBy(...exprs: (string | ExpressionNode)[]): SelectBuilder;
17
20
  having(expr: ExpressionNode): SelectBuilder;
18
21
  orderBy(expr: string | ExpressionNode, direction?: OrderDirection, nulls?: "FIRST" | "LAST"): SelectBuilder;
@@ -101,6 +101,44 @@ export class SelectBuilder {
101
101
  rightJoin(table, on, alias) {
102
102
  return this.join("RIGHT", table, on, alias);
103
103
  }
104
+ innerJoinLateral(subquery, on) {
105
+ const join = {
106
+ type: "join",
107
+ joinType: "INNER",
108
+ table: subquery,
109
+ on,
110
+ lateral: true
111
+ };
112
+ return new SelectBuilder({
113
+ ...this.node,
114
+ joins: [...this.node.joins, join]
115
+ });
116
+ }
117
+ leftJoinLateral(subquery, on) {
118
+ const join = {
119
+ type: "join",
120
+ joinType: "LEFT",
121
+ table: subquery,
122
+ on,
123
+ lateral: true
124
+ };
125
+ return new SelectBuilder({
126
+ ...this.node,
127
+ joins: [...this.node.joins, join]
128
+ });
129
+ }
130
+ crossJoinLateral(subquery) {
131
+ const join = {
132
+ type: "join",
133
+ joinType: "CROSS",
134
+ table: subquery,
135
+ lateral: true
136
+ };
137
+ return new SelectBuilder({
138
+ ...this.node,
139
+ joins: [...this.node.joins, join]
140
+ });
141
+ }
104
142
  groupBy(...exprs) {
105
143
  const nodes = exprs.map((e) => typeof e === "string" ? col(e) : e);
106
144
  return new SelectBuilder({
@@ -17,6 +17,12 @@ export declare class TypedDeleteBuilder<
17
17
  * WHERE — callback or raw Expression.
18
18
  */
19
19
  where(exprOrCallback: Expression<boolean> | WhereCallback<DB, TB>): TypedDeleteBuilder<DB, TB>;
20
+ /** USING clause (PG: DELETE FROM t USING other WHERE ...) */
21
+ using<T extends keyof DB & string>(table: T): TypedDeleteBuilder<DB, TB>;
22
+ /** INNER JOIN for DELETE (MySQL pattern) */
23
+ innerJoin(table: string, on: Expression<boolean>): TypedDeleteBuilder<DB, TB>;
24
+ /** LEFT JOIN for DELETE */
25
+ leftJoin(table: string, on: Expression<boolean>): TypedDeleteBuilder<DB, TB>;
20
26
  /**
21
27
  * RETURNING specific columns.
22
28
  */
@@ -27,6 +27,18 @@ export class TypedDeleteBuilder {
27
27
  return this._with(this._builder.where(unwrap(exprOrCallback)));
28
28
  }
29
29
 
30
+ using(table) {
31
+ return this._with(this._builder.using(table));
32
+ }
33
+
34
+ innerJoin(table, on) {
35
+ return this._with(this._builder.innerJoin(table, unwrap(on)));
36
+ }
37
+
38
+ leftJoin(table, on) {
39
+ return this._with(this._builder.leftJoin(table, unwrap(on)));
40
+ }
41
+
30
42
  returning(...cols) {
31
43
  const exprs = cols.map((c) => ({
32
44
  type: "column_ref",
@@ -18,6 +18,10 @@ export declare class TypedInsertBuilder<
18
18
  */
19
19
  values(row: Insertable<DB[TB]>): TypedInsertBuilder<DB, TB>;
20
20
  /**
21
+ * Insert multiple rows at once.
22
+ */
23
+ valuesMany(rows: Insertable<DB[TB]>[]): TypedInsertBuilder<DB, TB>;
24
+ /**
21
25
  * RETURNING specific columns.
22
26
  */
23
27
  returning<K extends keyof DB[TB] & string>(...cols: K[]): TypedInsertReturningBuilder<DB, TB, Pick<SelectRow<DB, TB>, K>>;
@@ -30,12 +34,20 @@ export declare class TypedInsertBuilder<
30
34
  */
31
35
  onConflictDoNothing(...columns: (keyof DB[TB] & string)[]): TypedInsertBuilder<DB, TB>;
32
36
  /**
33
- * ON CONFLICT DO UPDATE.
37
+ * ON CONFLICT DO UPDATE — with Expression values.
34
38
  */
35
39
  onConflictDoUpdate(columns: (keyof DB[TB] & string)[], set: {
36
40
  column: keyof DB[TB] & string;
37
41
  value: Expression<any>;
38
42
  }[]): TypedInsertBuilder<DB, TB>;
43
+ /**
44
+ * ON CONFLICT DO UPDATE — with plain object (auto-parameterized).
45
+ *
46
+ * ```ts
47
+ * .onConflictDoUpdateSet(["email"], { name: "Alice Updated" })
48
+ * ```
49
+ */
50
+ onConflictDoUpdateSet(columns: (keyof DB[TB] & string)[], values: Partial<Insertable<DB[TB]>>): TypedInsertBuilder<DB, TB>;
39
51
  /** ON CONFLICT ON CONSTRAINT name DO NOTHING */
40
52
  onConflictConstraintDoNothing(constraint: string): TypedInsertBuilder<DB, TB>;
41
53
  /** ON CONFLICT ON CONSTRAINT name DO UPDATE SET ... */
@@ -39,6 +39,14 @@ export class TypedInsertBuilder {
39
39
  return this._withBuilder(builder, this._paramIdx);
40
40
  }
41
41
 
42
+ valuesMany(rows) {
43
+ let current = this;
44
+ for (const row of rows) {
45
+ current = current.values(row);
46
+ }
47
+ return current;
48
+ }
49
+
42
50
  returning(...cols) {
43
51
  const exprs = cols.map((c) => ({
44
52
  type: "column_ref",
@@ -70,6 +78,21 @@ export class TypedInsertBuilder {
70
78
  }))), this._paramIdx);
71
79
  }
72
80
 
81
+ onConflictDoUpdateSet(columns, values) {
82
+ const set = [];
83
+ let idx = this._paramIdx;
84
+ for (const [col, val] of Object.entries(values)) {
85
+ if (val !== undefined) {
86
+ set.push({
87
+ column: col,
88
+ value: param(idx, val)
89
+ });
90
+ idx++;
91
+ }
92
+ }
93
+ return this._withBuilder(this._builder.onConflictDoUpdate(columns, set), idx);
94
+ }
95
+
73
96
  onConflictConstraintDoNothing(constraint) {
74
97
  return this._withBuilder(this._builder.onConflictConstraintDoNothing(constraint), this._paramIdx);
75
98
  }
@@ -28,6 +28,8 @@ export declare class TypedSelectBuilder<
28
28
  Alias extends string,
29
29
  T
30
30
  >(expr: Expression<T>, alias: Alias): TypedSelectBuilder<DB, TB, O & Record<Alias, T>>;
31
+ /** Select multiple aliased expressions at once. */
32
+ selectExprs<Aliases extends Record<string, Expression<any>>>(exprs: Aliases): TypedSelectBuilder<DB, TB, O & { [K in keyof Aliases] : any }>;
31
33
  /** DISTINCT */
32
34
  distinct(): TypedSelectBuilder<DB, TB, O>;
33
35
  /** DISTINCT ON (PG-specific) */
@@ -59,12 +61,12 @@ export declare class TypedSelectBuilder<
59
61
  leftJoin<T extends keyof DB & string>(table: T, onOrCallback: Expression<boolean> | ((cols: JoinProxies<DB, TB, T>) => Expression<boolean>)): TypedSelectBuilder<DB, TB | T, O & Nullable<SelectRow<DB, T>>>;
60
62
  /** RIGHT JOIN */
61
63
  rightJoin<T extends keyof DB & string>(table: T, onOrCallback: Expression<boolean> | ((cols: JoinProxies<DB, TB, T>) => Expression<boolean>)): TypedSelectBuilder<DB, TB | T, Nullable<O> & SelectRow<DB, T>>;
62
- /** GROUP BY */
63
- groupBy(...cols: (keyof O & string)[]): TypedSelectBuilder<DB, TB, O>;
64
+ /** GROUP BY — accepts column names or expressions */
65
+ groupBy(...cols: ((keyof O & string) | Expression<any>)[]): TypedSelectBuilder<DB, TB, O>;
64
66
  /** HAVING */
65
67
  having(exprOrCallback: Expression<boolean> | WhereCallback<DB, TB>): TypedSelectBuilder<DB, TB, O>;
66
- /** ORDER BY */
67
- orderBy(col: keyof O & string, direction?: OrderDirection, nulls?: "FIRST" | "LAST"): TypedSelectBuilder<DB, TB, O>;
68
+ /** ORDER BY — accepts column name or expression */
69
+ orderBy(col: (keyof O & string) | Expression<any>, direction?: OrderDirection, nulls?: "FIRST" | "LAST"): TypedSelectBuilder<DB, TB, O>;
68
70
  /** LIMIT */
69
71
  limit(n: number): TypedSelectBuilder<DB, TB, O>;
70
72
  /** OFFSET */
@@ -99,8 +101,45 @@ export declare class TypedSelectBuilder<
99
101
  exceptAll(query: TypedSelectBuilder<DB, any, O>): TypedSelectBuilder<DB, TB, O>;
100
102
  /** FULL JOIN — both sides become nullable. */
101
103
  fullJoin<T extends keyof DB & string>(table: T, onOrCallback: Expression<boolean> | ((cols: JoinProxies<DB, TB, T>) => Expression<boolean>)): TypedSelectBuilder<DB, TB | T, Nullable<O> & Nullable<SelectRow<DB, T>>>;
104
+ /** INNER JOIN LATERAL (subquery) */
105
+ innerJoinLateral<
106
+ Alias extends string,
107
+ R
108
+ >(subquery: {
109
+ build(): SelectNode;
110
+ }, alias: Alias, on: Expression<boolean>): TypedSelectBuilder<DB, TB, O & Record<Alias, R>>;
111
+ /** LEFT JOIN LATERAL (subquery) */
112
+ leftJoinLateral<
113
+ Alias extends string,
114
+ R
115
+ >(subquery: {
116
+ build(): SelectNode;
117
+ }, alias: Alias, on: Expression<boolean>): TypedSelectBuilder<DB, TB, O & Partial<Record<Alias, R>>>;
102
118
  /** CROSS JOIN — cartesian product. */
103
119
  crossJoin<T extends keyof DB & string>(table: T): TypedSelectBuilder<DB, TB | T, O & SelectRow<DB, T>>;
120
+ /** CROSS JOIN LATERAL (subquery) */
121
+ crossJoinLateral<
122
+ Alias extends string,
123
+ R
124
+ >(subquery: {
125
+ build(): SelectNode;
126
+ }, alias: Alias): TypedSelectBuilder<DB, TB, O & Record<Alias, R>>;
127
+ /** Clear WHERE clause. */
128
+ clearWhere(): TypedSelectBuilder<DB, TB, O>;
129
+ /** Clear ORDER BY clause. */
130
+ clearOrderBy(): TypedSelectBuilder<DB, TB, O>;
131
+ /** Clear LIMIT. */
132
+ clearLimit(): TypedSelectBuilder<DB, TB, O>;
133
+ /** Clear OFFSET. */
134
+ clearOffset(): TypedSelectBuilder<DB, TB, O>;
135
+ /** Clear GROUP BY clause. */
136
+ clearGroupBy(): TypedSelectBuilder<DB, TB, O>;
137
+ /** Clear HAVING clause. */
138
+ clearHaving(): TypedSelectBuilder<DB, TB, O>;
139
+ /** Clear SELECT columns (resets to empty). */
140
+ clearSelect(): TypedSelectBuilder<DB, TB, O>;
141
+ /** Pipe builder through a function for reusable query fragments. */
142
+ $call<R>(fn: (qb: TypedSelectBuilder<DB, TB, O>) => R): R;
104
143
  /** Conditionally apply a transformation. */
105
144
  $if<O2>(condition: boolean, fn: (qb: TypedSelectBuilder<DB, TB, O>) => TypedSelectBuilder<DB, TB, O2>): TypedSelectBuilder<DB, TB, O | O2>;
106
145
  /** Build the AST node. */
@@ -25,6 +25,16 @@ export class TypedSelectBuilder {
25
25
  return new TypedSelectBuilder(this._builder.columns(aliased), this._table);
26
26
  }
27
27
 
28
+ selectExprs(exprs) {
29
+ let builder = this._builder;
30
+ for (const [alias, expr] of Object.entries(exprs)) {
31
+ const node = unwrap(expr);
32
+ const aliased = aliasExpr(node, alias);
33
+ builder = builder.columns(aliased);
34
+ }
35
+ return new TypedSelectBuilder(builder, this._table);
36
+ }
37
+
28
38
  distinct() {
29
39
  return new TypedSelectBuilder(this._builder.distinct(), this._table);
30
40
  }
@@ -59,7 +69,8 @@ export class TypedSelectBuilder {
59
69
  }
60
70
 
61
71
  groupBy(...cols) {
62
- return new TypedSelectBuilder(this._builder.groupBy(...cols), this._table);
72
+ const resolved = cols.map((c) => typeof c === "string" ? c : unwrap(c));
73
+ return new TypedSelectBuilder(this._builder.groupBy(...resolved), this._table);
63
74
  }
64
75
 
65
76
  having(exprOrCallback) {
@@ -73,7 +84,8 @@ export class TypedSelectBuilder {
73
84
  }
74
85
 
75
86
  orderBy(col, direction = "ASC", nulls) {
76
- return new TypedSelectBuilder(this._builder.orderBy(col, direction, nulls), this._table);
87
+ const expr = typeof col === "string" ? col : unwrap(col);
88
+ return new TypedSelectBuilder(this._builder.orderBy(expr, direction, nulls), this._table);
77
89
  }
78
90
 
79
91
  limit(n) {
@@ -151,10 +163,90 @@ export class TypedSelectBuilder {
151
163
  return new TypedSelectBuilder(this._builder.join("FULL", table, unwrap(on)), this._table);
152
164
  }
153
165
 
166
+ innerJoinLateral(subquery, alias, on) {
167
+ const sub = {
168
+ type: "subquery",
169
+ query: subquery.build(),
170
+ alias
171
+ };
172
+ return new TypedSelectBuilder(this._builder.innerJoinLateral(sub, unwrap(on)), this._table);
173
+ }
174
+
175
+ leftJoinLateral(subquery, alias, on) {
176
+ const sub = {
177
+ type: "subquery",
178
+ query: subquery.build(),
179
+ alias
180
+ };
181
+ return new TypedSelectBuilder(this._builder.leftJoinLateral(sub, unwrap(on)), this._table);
182
+ }
183
+
154
184
  crossJoin(table) {
155
185
  return new TypedSelectBuilder(this._builder.join("CROSS", table), this._table);
156
186
  }
157
187
 
188
+ crossJoinLateral(subquery, alias) {
189
+ const sub = {
190
+ type: "subquery",
191
+ query: subquery.build(),
192
+ alias
193
+ };
194
+ return new TypedSelectBuilder(this._builder.crossJoinLateral(sub), this._table);
195
+ }
196
+
197
+ clearWhere() {
198
+ return new TypedSelectBuilder(new SelectBuilder({
199
+ ...this._builder.build(),
200
+ where: undefined
201
+ }), this._table);
202
+ }
203
+
204
+ clearOrderBy() {
205
+ return new TypedSelectBuilder(new SelectBuilder({
206
+ ...this._builder.build(),
207
+ orderBy: []
208
+ }), this._table);
209
+ }
210
+
211
+ clearLimit() {
212
+ return new TypedSelectBuilder(new SelectBuilder({
213
+ ...this._builder.build(),
214
+ limit: undefined
215
+ }), this._table);
216
+ }
217
+
218
+ clearOffset() {
219
+ return new TypedSelectBuilder(new SelectBuilder({
220
+ ...this._builder.build(),
221
+ offset: undefined
222
+ }), this._table);
223
+ }
224
+
225
+ clearGroupBy() {
226
+ return new TypedSelectBuilder(new SelectBuilder({
227
+ ...this._builder.build(),
228
+ groupBy: []
229
+ }), this._table);
230
+ }
231
+
232
+ clearHaving() {
233
+ return new TypedSelectBuilder(new SelectBuilder({
234
+ ...this._builder.build(),
235
+ having: undefined
236
+ }), this._table);
237
+ }
238
+
239
+ clearSelect() {
240
+ return new TypedSelectBuilder(new SelectBuilder({
241
+ ...this._builder.build(),
242
+ columns: []
243
+ }), this._table);
244
+ }
245
+
246
+ $call(fn) {
247
+ return fn(this);
248
+ }
249
+
158
250
  $if(condition, fn) {
159
251
  if (condition) {
160
252
  return fn(this);
@@ -35,6 +35,10 @@ export declare class TypedUpdateBuilder<
35
35
  * RETURNING all columns.
36
36
  */
37
37
  returningAll(): TypedUpdateReturningBuilder<DB, TB, SelectRow<DB, TB>>;
38
+ /** INNER JOIN for UPDATE (MySQL pattern) */
39
+ innerJoin(table: string, on: Expression<boolean>): TypedUpdateBuilder<DB, TB>;
40
+ /** LEFT JOIN for UPDATE */
41
+ leftJoin(table: string, on: Expression<boolean>): TypedUpdateBuilder<DB, TB>;
38
42
  /** FROM clause (for UPDATE ... FROM ... WHERE joins). */
39
43
  from<T extends keyof DB & string>(table: T): TypedUpdateBuilder<DB, TB>;
40
44
  /** WITH (CTE) */