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.
- package/README.md +155 -1
- package/dist/ast/nodes.d.mts +12 -1
- package/dist/builder/delete.d.mts +2 -0
- package/dist/builder/delete.mjs +19 -0
- package/dist/builder/eb.d.mts +108 -6
- package/dist/builder/eb.mjs +248 -6
- package/dist/builder/select.d.mts +3 -0
- package/dist/builder/select.mjs +38 -0
- package/dist/builder/typed-delete.d.mts +6 -0
- package/dist/builder/typed-delete.mjs +12 -0
- package/dist/builder/typed-insert.d.mts +13 -1
- package/dist/builder/typed-insert.mjs +23 -0
- package/dist/builder/typed-select.d.mts +43 -4
- package/dist/builder/typed-select.mjs +94 -2
- package/dist/builder/typed-update.d.mts +4 -0
- package/dist/builder/typed-update.mjs +8 -0
- package/dist/builder/update.d.mts +2 -0
- package/dist/builder/update.mjs +19 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +3 -1
- package/dist/printer/base.d.mts +2 -1
- package/dist/printer/base.mjs +25 -3
- package/dist/sumak.d.mts +12 -0
- package/dist/sumak.mjs +9 -0
- package/package.json +1 -1
package/dist/builder/eb.mjs
CHANGED
|
@@ -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(
|
|
118
|
-
return wrap(
|
|
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(
|
|
122
|
-
return wrap(
|
|
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(
|
|
164
|
-
return wrap(rawFn("COALESCE",
|
|
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;
|
package/dist/builder/select.mjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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) */
|