@prisma-next/sql-relational-core 0.3.0-pr.99.5 → 0.3.0
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/LICENSE +201 -0
- package/README.md +20 -6
- package/dist/codec-types-DcEITed4.d.mts +144 -0
- package/dist/codec-types-DcEITed4.d.mts.map +1 -0
- package/dist/errors-Cs52upp3.d.mts +8 -0
- package/dist/errors-Cs52upp3.d.mts.map +1 -0
- package/dist/errors-D3xmG4h-.mjs +35 -0
- package/dist/errors-D3xmG4h-.mjs.map +1 -0
- package/dist/exports/ast.d.mts +158 -0
- package/dist/exports/ast.d.mts.map +1 -0
- package/dist/exports/ast.mjs +1358 -0
- package/dist/exports/ast.mjs.map +1 -0
- package/dist/exports/errors.d.mts +5 -0
- package/dist/exports/errors.mjs +3 -0
- package/dist/exports/plan.d.mts +2 -0
- package/dist/exports/plan.mjs +17 -0
- package/dist/exports/plan.mjs.map +1 -0
- package/dist/exports/query-lane-context.d.mts +3 -0
- package/dist/exports/query-lane-context.mjs +1 -0
- package/dist/exports/types.d.mts +4 -0
- package/dist/exports/types.mjs +1 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.mjs +7 -0
- package/dist/plan-5qUWdlJM.d.mts +28 -0
- package/dist/plan-5qUWdlJM.d.mts.map +1 -0
- package/dist/query-lane-context-UlR8vOkd.d.mts +89 -0
- package/dist/query-lane-context-UlR8vOkd.d.mts.map +1 -0
- package/dist/types-CLCtwVWx.d.mts +485 -0
- package/dist/types-CLCtwVWx.d.mts.map +1 -0
- package/dist/types-V1qiC5DO.d.mts +200 -0
- package/dist/types-V1qiC5DO.d.mts.map +1 -0
- package/package.json +29 -51
- package/src/ast/adapter-types.ts +11 -0
- package/src/ast/codec-types.ts +101 -53
- package/src/ast/driver-types.ts +20 -3
- package/src/ast/sql-codecs.ts +142 -0
- package/src/ast/types.ts +1678 -88
- package/src/errors.ts +47 -1
- package/src/exports/ast.ts +1 -8
- package/src/index.ts +0 -3
- package/src/plan.ts +4 -4
- package/src/query-lane-context.ts +74 -11
- package/src/types.ts +102 -404
- package/dist/ast/adapter-types.d.ts +0 -28
- package/dist/ast/adapter-types.d.ts.map +0 -1
- package/dist/ast/codec-types.d.ts +0 -141
- package/dist/ast/codec-types.d.ts.map +0 -1
- package/dist/ast/common.d.ts +0 -7
- package/dist/ast/common.d.ts.map +0 -1
- package/dist/ast/delete.d.ts +0 -8
- package/dist/ast/delete.d.ts.map +0 -1
- package/dist/ast/driver-types.d.ts +0 -20
- package/dist/ast/driver-types.d.ts.map +0 -1
- package/dist/ast/insert.d.ts +0 -8
- package/dist/ast/insert.d.ts.map +0 -1
- package/dist/ast/join.d.ts +0 -6
- package/dist/ast/join.d.ts.map +0 -1
- package/dist/ast/order.d.ts +0 -6
- package/dist/ast/order.d.ts.map +0 -1
- package/dist/ast/predicate.d.ts +0 -4
- package/dist/ast/predicate.d.ts.map +0 -1
- package/dist/ast/select.d.ts +0 -18
- package/dist/ast/select.d.ts.map +0 -1
- package/dist/ast/types.d.ts +0 -130
- package/dist/ast/types.d.ts.map +0 -1
- package/dist/ast/update.d.ts +0 -9
- package/dist/ast/update.d.ts.map +0 -1
- package/dist/ast/util.d.ts +0 -2
- package/dist/ast/util.d.ts.map +0 -1
- package/dist/chunk-2BWK6XEY.js +0 -13
- package/dist/chunk-2BWK6XEY.js.map +0 -1
- package/dist/chunk-2F7DSEOU.js +0 -8
- package/dist/chunk-2F7DSEOU.js.map +0 -1
- package/dist/chunk-2MAKNVCP.js +0 -86
- package/dist/chunk-2MAKNVCP.js.map +0 -1
- package/dist/chunk-36WJWNHT.js +0 -1
- package/dist/chunk-36WJWNHT.js.map +0 -1
- package/dist/chunk-3F4RFQIB.js +0 -169
- package/dist/chunk-3F4RFQIB.js.map +0 -1
- package/dist/chunk-7I3EMQID.js +0 -16
- package/dist/chunk-7I3EMQID.js.map +0 -1
- package/dist/chunk-G52ENULI.js +0 -1
- package/dist/chunk-G52ENULI.js.map +0 -1
- package/dist/chunk-HV334QHG.js +0 -320
- package/dist/chunk-HV334QHG.js.map +0 -1
- package/dist/chunk-KYSP7L5C.js +0 -16
- package/dist/chunk-KYSP7L5C.js.map +0 -1
- package/dist/chunk-U7AXAUJA.js +0 -1
- package/dist/chunk-U7AXAUJA.js.map +0 -1
- package/dist/chunk-YXD25S5I.js +0 -171
- package/dist/chunk-YXD25S5I.js.map +0 -1
- package/dist/errors.d.ts +0 -2
- package/dist/errors.d.ts.map +0 -1
- package/dist/exports/ast.d.ts +0 -14
- package/dist/exports/ast.d.ts.map +0 -1
- package/dist/exports/ast.js +0 -46
- package/dist/exports/ast.js.map +0 -1
- package/dist/exports/errors.d.ts +0 -2
- package/dist/exports/errors.d.ts.map +0 -1
- package/dist/exports/errors.js +0 -9
- package/dist/exports/errors.js.map +0 -1
- package/dist/exports/guards.d.ts +0 -2
- package/dist/exports/guards.d.ts.map +0 -1
- package/dist/exports/guards.js +0 -31
- package/dist/exports/guards.js.map +0 -1
- package/dist/exports/operations-registry.d.ts +0 -2
- package/dist/exports/operations-registry.d.ts.map +0 -1
- package/dist/exports/operations-registry.js +0 -9
- package/dist/exports/operations-registry.js.map +0 -1
- package/dist/exports/param.d.ts +0 -3
- package/dist/exports/param.d.ts.map +0 -1
- package/dist/exports/param.js +0 -7
- package/dist/exports/param.js.map +0 -1
- package/dist/exports/plan.d.ts +0 -2
- package/dist/exports/plan.d.ts.map +0 -1
- package/dist/exports/plan.js +0 -7
- package/dist/exports/plan.js.map +0 -1
- package/dist/exports/query-lane-context.d.ts +0 -2
- package/dist/exports/query-lane-context.d.ts.map +0 -1
- package/dist/exports/query-lane-context.js +0 -2
- package/dist/exports/query-lane-context.js.map +0 -1
- package/dist/exports/schema.d.ts +0 -3
- package/dist/exports/schema.d.ts.map +0 -1
- package/dist/exports/schema.js +0 -13
- package/dist/exports/schema.js.map +0 -1
- package/dist/exports/types.d.ts +0 -2
- package/dist/exports/types.d.ts.map +0 -1
- package/dist/exports/types.js +0 -10
- package/dist/exports/types.js.map +0 -1
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -81
- package/dist/index.js.map +0 -1
- package/dist/operations-registry.d.ts +0 -5
- package/dist/operations-registry.d.ts.map +0 -1
- package/dist/param.d.ts +0 -4
- package/dist/param.d.ts.map +0 -1
- package/dist/plan.d.ts +0 -23
- package/dist/plan.d.ts.map +0 -1
- package/dist/query-lane-context.d.ts +0 -27
- package/dist/query-lane-context.d.ts.map +0 -1
- package/dist/schema.d.ts +0 -83
- package/dist/schema.d.ts.map +0 -1
- package/dist/types.d.ts +0 -371
- package/dist/types.d.ts.map +0 -1
- package/dist/utils/guards.d.ts +0 -82
- package/dist/utils/guards.d.ts.map +0 -1
- package/src/ast/common.ts +0 -36
- package/src/ast/delete.ts +0 -17
- package/src/ast/insert.ts +0 -17
- package/src/ast/join.ts +0 -54
- package/src/ast/order.ts +0 -11
- package/src/ast/predicate.ts +0 -22
- package/src/ast/select.ts +0 -39
- package/src/ast/update.ts +0 -19
- package/src/exports/guards.ts +0 -15
- package/src/exports/operations-registry.ts +0 -1
- package/src/exports/param.ts +0 -2
- package/src/exports/schema.ts +0 -6
- package/src/operations-registry.ts +0 -276
- package/src/param.ts +0 -15
- package/src/schema.ts +0 -406
- package/src/utils/guards.ts +0 -193
package/src/ast/types.ts
CHANGED
|
@@ -1,144 +1,1734 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PlanRefs } from '@prisma-next/contract/types';
|
|
2
|
+
import type { ParamSpec } from '@prisma-next/operations';
|
|
2
3
|
import type { SqlLoweringSpec } from '@prisma-next/sql-operations';
|
|
3
4
|
|
|
4
|
-
// SQL-specific AST types and supporting types
|
|
5
|
-
// These types are needed by adapters and runtime for SQL query execution
|
|
6
|
-
|
|
7
5
|
export type Direction = 'asc' | 'desc';
|
|
8
6
|
|
|
7
|
+
export type BinaryOp =
|
|
8
|
+
| 'eq'
|
|
9
|
+
| 'neq'
|
|
10
|
+
| 'gt'
|
|
11
|
+
| 'lt'
|
|
12
|
+
| 'gte'
|
|
13
|
+
| 'lte'
|
|
14
|
+
| 'like'
|
|
15
|
+
| 'ilike'
|
|
16
|
+
| 'in'
|
|
17
|
+
| 'notIn';
|
|
18
|
+
|
|
19
|
+
export type AggregateCountFn = 'count';
|
|
20
|
+
export type AggregateOpFn = 'sum' | 'avg' | 'min' | 'max';
|
|
21
|
+
export type AggregateFn = AggregateCountFn | AggregateOpFn;
|
|
22
|
+
|
|
23
|
+
export interface ExpressionSource {
|
|
24
|
+
toExpr(): AnyExpression;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ExpressionRewriter {
|
|
28
|
+
columnRef?(expr: ColumnRef): AnyExpression;
|
|
29
|
+
identifierRef?(expr: IdentifierRef): AnyExpression;
|
|
30
|
+
paramRef?(expr: ParamRef): ParamRef | LiteralExpr;
|
|
31
|
+
literal?(expr: LiteralExpr): LiteralExpr;
|
|
32
|
+
list?(expr: ListExpression): ListExpression | LiteralExpr;
|
|
33
|
+
select?(ast: SelectAst): SelectAst;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface AstRewriter extends ExpressionRewriter {
|
|
37
|
+
tableSource?(source: TableSource): TableSource;
|
|
38
|
+
eqColJoinOn?(on: EqColJoinOn): EqColJoinOn | AnyExpression;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ExprVisitor<R> {
|
|
42
|
+
columnRef(expr: ColumnRef): R;
|
|
43
|
+
identifierRef(expr: IdentifierRef): R;
|
|
44
|
+
subquery(expr: SubqueryExpr): R;
|
|
45
|
+
operation(expr: OperationExpr): R;
|
|
46
|
+
aggregate(expr: AggregateExpr): R;
|
|
47
|
+
jsonObject(expr: JsonObjectExpr): R;
|
|
48
|
+
jsonArrayAgg(expr: JsonArrayAggExpr): R;
|
|
49
|
+
binary(expr: BinaryExpr): R;
|
|
50
|
+
and(expr: AndExpr): R;
|
|
51
|
+
or(expr: OrExpr): R;
|
|
52
|
+
exists(expr: ExistsExpr): R;
|
|
53
|
+
nullCheck(expr: NullCheckExpr): R;
|
|
54
|
+
not(expr: NotExpr): R;
|
|
55
|
+
literal(expr: LiteralExpr): R;
|
|
56
|
+
param(expr: ParamRef): R;
|
|
57
|
+
list(expr: ListExpression): R;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ExpressionFolder<T> {
|
|
61
|
+
empty: T;
|
|
62
|
+
combine(a: T, b: T): T;
|
|
63
|
+
isAbsorbing?(value: T): boolean;
|
|
64
|
+
columnRef?(expr: ColumnRef): T;
|
|
65
|
+
identifierRef?(expr: IdentifierRef): T;
|
|
66
|
+
paramRef?(expr: ParamRef): T;
|
|
67
|
+
literal?(expr: LiteralExpr): T;
|
|
68
|
+
list?(expr: ListExpression): T;
|
|
69
|
+
select?(ast: SelectAst): T;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type ProjectionExpr = AnyExpression;
|
|
73
|
+
export type InsertValue = ColumnRef | ParamRef | DefaultValueExpr;
|
|
74
|
+
export type JoinOnExpr = EqColJoinOn | AnyExpression;
|
|
75
|
+
export type WhereArg = AnyExpression | ToWhereExpr;
|
|
76
|
+
export type JsonObjectEntry = {
|
|
77
|
+
readonly key: string;
|
|
78
|
+
readonly value: ProjectionExpr;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
function frozenArrayCopy<T>(values: readonly T[]): ReadonlyArray<T> {
|
|
82
|
+
return Object.freeze([...values]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function frozenOptionalRecordCopy<T extends Record<string, unknown>>(
|
|
86
|
+
value: T | undefined,
|
|
87
|
+
): Readonly<T> | undefined {
|
|
88
|
+
return value === undefined ? undefined : Object.freeze({ ...value });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function frozenRecordCopy<T>(record: Readonly<Record<string, T>>): Readonly<Record<string, T>> {
|
|
92
|
+
return Object.freeze({ ...record });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function freezeRows(
|
|
96
|
+
rows: ReadonlyArray<Record<string, InsertValue>>,
|
|
97
|
+
): ReadonlyArray<Readonly<Record<string, InsertValue>>> {
|
|
98
|
+
return Object.freeze(rows.map((row) => Object.freeze({ ...row })));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function combineAll<T>(folder: ExpressionFolder<T>, thunks: Array<() => T>): T {
|
|
102
|
+
let result = folder.empty;
|
|
103
|
+
for (const thunk of thunks) {
|
|
104
|
+
if (folder.isAbsorbing?.(result)) {
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
result = folder.combine(result, thunk());
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function rewriteComparable(value: AnyExpression, rewriter: ExpressionRewriter): AnyExpression {
|
|
113
|
+
switch (value.kind) {
|
|
114
|
+
case 'param-ref':
|
|
115
|
+
return rewriter.paramRef ? rewriter.paramRef(value) : value;
|
|
116
|
+
case 'literal':
|
|
117
|
+
return rewriter.literal ? rewriter.literal(value) : value;
|
|
118
|
+
case 'list':
|
|
119
|
+
if (rewriter.list) {
|
|
120
|
+
return rewriter.list(value);
|
|
121
|
+
}
|
|
122
|
+
return value.rewrite(rewriter);
|
|
123
|
+
default:
|
|
124
|
+
return value.rewrite(rewriter);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function foldComparable<T>(value: AnyExpression, folder: ExpressionFolder<T>): T {
|
|
129
|
+
switch (value.kind) {
|
|
130
|
+
case 'param-ref':
|
|
131
|
+
return folder.paramRef ? folder.paramRef(value) : folder.empty;
|
|
132
|
+
case 'literal':
|
|
133
|
+
return folder.literal ? folder.literal(value) : folder.empty;
|
|
134
|
+
case 'list':
|
|
135
|
+
return value.fold(folder);
|
|
136
|
+
default:
|
|
137
|
+
return value.fold(folder);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function collectColumnRefsWith<TNode extends Expression>(node: TNode): ColumnRef[] {
|
|
142
|
+
return node.fold<ColumnRef[]>({
|
|
143
|
+
empty: [],
|
|
144
|
+
combine: (a, b) => [...a, ...b],
|
|
145
|
+
columnRef: (columnRef) => [columnRef],
|
|
146
|
+
select: (ast) => ast.collectColumnRefs(),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function collectParamRefsWith<TNode extends Expression>(node: TNode): ParamRef[] {
|
|
151
|
+
return node.fold<ParamRef[]>({
|
|
152
|
+
empty: [],
|
|
153
|
+
combine: (a, b) => [...a, ...b],
|
|
154
|
+
paramRef: (paramRef) => [paramRef],
|
|
155
|
+
select: (ast) => ast.collectParamRefs(),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function sortRefs(
|
|
160
|
+
tables: ReadonlySet<string>,
|
|
161
|
+
columns: ReadonlyMap<string, { table: string; column: string }>,
|
|
162
|
+
): PlanRefs {
|
|
163
|
+
const sortedTables = [...tables].sort((a, b) => a.localeCompare(b));
|
|
164
|
+
const sortedColumns = [...columns.values()].sort((a, b) => {
|
|
165
|
+
const tableCompare = a.table.localeCompare(b.table);
|
|
166
|
+
if (tableCompare !== 0) {
|
|
167
|
+
return tableCompare;
|
|
168
|
+
}
|
|
169
|
+
return a.column.localeCompare(b.column);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
tables: sortedTables,
|
|
174
|
+
columns: sortedColumns,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function addColumnRefToRefSets(
|
|
179
|
+
columnRef: ColumnRef,
|
|
180
|
+
tables: Set<string>,
|
|
181
|
+
columns: Map<string, { table: string; column: string }>,
|
|
182
|
+
): void {
|
|
183
|
+
if (columnRef.table === 'excluded') {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
tables.add(columnRef.table);
|
|
187
|
+
const key = `${columnRef.table}.${columnRef.column}`;
|
|
188
|
+
if (!columns.has(key)) {
|
|
189
|
+
columns.set(key, {
|
|
190
|
+
table: columnRef.table,
|
|
191
|
+
column: columnRef.column,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function mergeRefsInto(
|
|
197
|
+
refs: PlanRefs,
|
|
198
|
+
tables: Set<string>,
|
|
199
|
+
columns: Map<string, { table: string; column: string }>,
|
|
200
|
+
): void {
|
|
201
|
+
for (const table of refs.tables ?? []) {
|
|
202
|
+
tables.add(table);
|
|
203
|
+
}
|
|
204
|
+
for (const column of refs.columns ?? []) {
|
|
205
|
+
addColumnRefToRefSets(new ColumnRef(column.table, column.column), tables, columns);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
abstract class AstNode {
|
|
210
|
+
abstract readonly kind: string;
|
|
211
|
+
|
|
212
|
+
protected freeze(): void {
|
|
213
|
+
Object.freeze(this);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
abstract class QueryAst extends AstNode {
|
|
218
|
+
abstract collectRefs(): PlanRefs;
|
|
219
|
+
abstract collectParamRefs(): ParamRef[];
|
|
220
|
+
abstract toQueryAst(): AnyQueryAst;
|
|
221
|
+
|
|
222
|
+
collectColumnRefs(): ColumnRef[] {
|
|
223
|
+
const refs = this.collectRefs().columns ?? [];
|
|
224
|
+
return refs.map((ref) => new ColumnRef(ref.table, ref.column));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
abstract class FromSource extends AstNode {
|
|
229
|
+
abstract collectRefs(): PlanRefs;
|
|
230
|
+
abstract rewrite(rewriter: AstRewriter): AnyFromSource;
|
|
231
|
+
abstract toFromSource(): AnyFromSource;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
abstract class Expression extends AstNode implements ExpressionSource {
|
|
235
|
+
abstract accept<R>(visitor: ExprVisitor<R>): R;
|
|
236
|
+
abstract rewrite(rewriter: ExpressionRewriter): AnyExpression;
|
|
237
|
+
abstract fold<T>(folder: ExpressionFolder<T>): T;
|
|
238
|
+
|
|
239
|
+
collectColumnRefs(): ColumnRef[] {
|
|
240
|
+
return collectColumnRefsWith(this);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
collectParamRefs(): ParamRef[] {
|
|
244
|
+
return collectParamRefsWith(this);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
baseColumnRef(): ColumnRef {
|
|
248
|
+
throw new Error(`${this.constructor.name} does not expose a base column reference`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
toExpr(): AnyExpression {
|
|
252
|
+
return this as unknown as AnyExpression;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
not(): NotExpr {
|
|
256
|
+
return new NotExpr(this as unknown as AnyExpression);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export class TableSource extends FromSource {
|
|
261
|
+
readonly kind = 'table-source' as const;
|
|
262
|
+
readonly name: string;
|
|
263
|
+
readonly alias: string | undefined;
|
|
264
|
+
|
|
265
|
+
constructor(name: string, alias?: string) {
|
|
266
|
+
super();
|
|
267
|
+
this.name = name;
|
|
268
|
+
this.alias = alias;
|
|
269
|
+
this.freeze();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
static named(name: string, alias?: string): TableSource {
|
|
273
|
+
return new TableSource(name, alias);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
override rewrite(rewriter: AstRewriter): AnyFromSource {
|
|
277
|
+
return rewriter.tableSource ? rewriter.tableSource(this) : this;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
override toFromSource(): AnyFromSource {
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
override collectRefs(): PlanRefs {
|
|
285
|
+
return {
|
|
286
|
+
tables: [this.name],
|
|
287
|
+
columns: [],
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
9
292
|
export interface TableRef {
|
|
10
|
-
readonly kind: 'table';
|
|
11
293
|
readonly name: string;
|
|
294
|
+
readonly alias?: string;
|
|
12
295
|
}
|
|
13
296
|
|
|
14
|
-
export
|
|
15
|
-
readonly kind
|
|
297
|
+
export class DerivedTableSource extends FromSource {
|
|
298
|
+
readonly kind = 'derived-table-source' as const;
|
|
299
|
+
readonly alias: string;
|
|
300
|
+
readonly query: SelectAst;
|
|
301
|
+
|
|
302
|
+
constructor(alias: string, query: SelectAst) {
|
|
303
|
+
super();
|
|
304
|
+
this.alias = alias;
|
|
305
|
+
this.query = query;
|
|
306
|
+
this.freeze();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
static as(alias: string, query: SelectAst): DerivedTableSource {
|
|
310
|
+
return new DerivedTableSource(alias, query);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Intentionally does not call rewriter.tableSource — derived tables are rewritten
|
|
314
|
+
// via their inner query, not intercepted at the FromSource level. A future
|
|
315
|
+
// fromSource?(source: AnyFromSource) callback would be needed for that.
|
|
316
|
+
override rewrite(rewriter: AstRewriter): AnyFromSource {
|
|
317
|
+
return new DerivedTableSource(this.alias, this.query.rewrite(rewriter));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
override toFromSource(): AnyFromSource {
|
|
321
|
+
return this;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
override collectRefs(): PlanRefs {
|
|
325
|
+
return this.query.collectRefs();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export class ColumnRef extends Expression {
|
|
330
|
+
readonly kind = 'column-ref' as const;
|
|
16
331
|
readonly table: string;
|
|
17
332
|
readonly column: string;
|
|
333
|
+
|
|
334
|
+
constructor(table: string, column: string) {
|
|
335
|
+
super();
|
|
336
|
+
this.table = table;
|
|
337
|
+
this.column = column;
|
|
338
|
+
this.freeze();
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
static of(table: string, column: string): ColumnRef {
|
|
342
|
+
return new ColumnRef(table, column);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
346
|
+
return visitor.columnRef(this);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
350
|
+
return rewriter.columnRef ? rewriter.columnRef(this) : this;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
354
|
+
return folder.columnRef ? folder.columnRef(this) : folder.empty;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
override baseColumnRef(): ColumnRef {
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
18
360
|
}
|
|
19
361
|
|
|
20
|
-
export
|
|
21
|
-
readonly kind
|
|
22
|
-
readonly
|
|
23
|
-
|
|
362
|
+
export class IdentifierRef extends Expression {
|
|
363
|
+
readonly kind = 'identifier-ref' as const;
|
|
364
|
+
readonly name: string;
|
|
365
|
+
|
|
366
|
+
constructor(name: string) {
|
|
367
|
+
super();
|
|
368
|
+
this.name = name;
|
|
369
|
+
this.freeze();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
static of(name: string): IdentifierRef {
|
|
373
|
+
return new IdentifierRef(name);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
377
|
+
return visitor.identifierRef(this);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
381
|
+
return rewriter.identifierRef ? rewriter.identifierRef(this) : this;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
385
|
+
return folder.identifierRef ? folder.identifierRef(this) : folder.empty;
|
|
386
|
+
}
|
|
24
387
|
}
|
|
25
388
|
|
|
26
|
-
export
|
|
27
|
-
readonly kind
|
|
389
|
+
export class ParamRef extends Expression {
|
|
390
|
+
readonly kind = 'param-ref' as const;
|
|
28
391
|
readonly value: unknown;
|
|
392
|
+
readonly name: string | undefined;
|
|
393
|
+
readonly codecId: string | undefined;
|
|
394
|
+
|
|
395
|
+
constructor(
|
|
396
|
+
value: unknown,
|
|
397
|
+
options?: {
|
|
398
|
+
name?: string;
|
|
399
|
+
codecId?: string;
|
|
400
|
+
},
|
|
401
|
+
) {
|
|
402
|
+
super();
|
|
403
|
+
this.value = value;
|
|
404
|
+
this.name = options?.name;
|
|
405
|
+
this.codecId = options?.codecId;
|
|
406
|
+
this.freeze();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
static of(
|
|
410
|
+
value: unknown,
|
|
411
|
+
options?: {
|
|
412
|
+
name?: string;
|
|
413
|
+
codecId?: string;
|
|
414
|
+
},
|
|
415
|
+
): ParamRef {
|
|
416
|
+
return new ParamRef(value, options);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
420
|
+
return visitor.param(this);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
424
|
+
return rewriter.paramRef ? rewriter.paramRef(this) : this;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
428
|
+
return folder.paramRef ? folder.paramRef(this) : folder.empty;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export class DefaultValueExpr extends AstNode {
|
|
433
|
+
readonly kind = 'default-value' as const;
|
|
434
|
+
|
|
435
|
+
constructor() {
|
|
436
|
+
super();
|
|
437
|
+
this.freeze();
|
|
438
|
+
}
|
|
29
439
|
}
|
|
30
440
|
|
|
31
|
-
export
|
|
32
|
-
readonly kind
|
|
441
|
+
export class LiteralExpr extends Expression {
|
|
442
|
+
readonly kind = 'literal' as const;
|
|
443
|
+
readonly value: unknown;
|
|
444
|
+
|
|
445
|
+
constructor(value: unknown) {
|
|
446
|
+
super();
|
|
447
|
+
this.value = value;
|
|
448
|
+
this.freeze();
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
static of(value: unknown): LiteralExpr {
|
|
452
|
+
return new LiteralExpr(value);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
456
|
+
return visitor.literal(this);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
460
|
+
return rewriter.literal ? rewriter.literal(this) : this;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
464
|
+
return folder.literal ? folder.literal(this) : folder.empty;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export class SubqueryExpr extends Expression {
|
|
469
|
+
readonly kind = 'subquery' as const;
|
|
470
|
+
readonly query: SelectAst;
|
|
471
|
+
|
|
472
|
+
constructor(query: SelectAst) {
|
|
473
|
+
super();
|
|
474
|
+
this.query = query;
|
|
475
|
+
this.freeze();
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
static of(query: SelectAst): SubqueryExpr {
|
|
479
|
+
return new SubqueryExpr(query);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
483
|
+
return visitor.subquery(this);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
487
|
+
const query = this.query.rewrite(rewriter);
|
|
488
|
+
return new SubqueryExpr(query);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
492
|
+
return folder.select ? folder.select(this.query) : folder.empty;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export class OperationExpr extends Expression {
|
|
497
|
+
readonly kind = 'operation' as const;
|
|
33
498
|
readonly method: string;
|
|
34
|
-
readonly
|
|
35
|
-
readonly
|
|
36
|
-
readonly
|
|
37
|
-
readonly returns: ReturnSpec;
|
|
499
|
+
readonly self: AnyExpression;
|
|
500
|
+
readonly args: ReadonlyArray<AnyExpression | ParamRef | LiteralExpr>;
|
|
501
|
+
readonly returns: ParamSpec;
|
|
38
502
|
readonly lowering: SqlLoweringSpec;
|
|
503
|
+
|
|
504
|
+
constructor(options: {
|
|
505
|
+
readonly method: string;
|
|
506
|
+
readonly self: AnyExpression;
|
|
507
|
+
readonly args: ReadonlyArray<AnyExpression | ParamRef | LiteralExpr> | undefined;
|
|
508
|
+
readonly returns: ParamSpec;
|
|
509
|
+
readonly lowering: SqlLoweringSpec;
|
|
510
|
+
}) {
|
|
511
|
+
super();
|
|
512
|
+
this.method = options.method;
|
|
513
|
+
this.self = options.self;
|
|
514
|
+
this.args = frozenArrayCopy(options.args ?? []);
|
|
515
|
+
this.returns = options.returns;
|
|
516
|
+
this.lowering = options.lowering;
|
|
517
|
+
this.freeze();
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
521
|
+
return visitor.operation(this);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
525
|
+
return new OperationExpr({
|
|
526
|
+
method: this.method,
|
|
527
|
+
self: this.self.rewrite(rewriter),
|
|
528
|
+
args: this.args.map((arg) => rewriteComparable(arg, rewriter)) as ReadonlyArray<
|
|
529
|
+
AnyExpression | ParamRef | LiteralExpr
|
|
530
|
+
>,
|
|
531
|
+
returns: this.returns,
|
|
532
|
+
lowering: this.lowering,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
537
|
+
return combineAll(folder, [
|
|
538
|
+
() => this.self.fold(folder),
|
|
539
|
+
...this.args.map((arg) => () => foldComparable(arg, folder)),
|
|
540
|
+
]);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
override baseColumnRef(): ColumnRef {
|
|
544
|
+
return this.self.baseColumnRef();
|
|
545
|
+
}
|
|
39
546
|
}
|
|
40
547
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export type Expression = ColumnRef | OperationExpr;
|
|
548
|
+
export class AggregateExpr extends Expression {
|
|
549
|
+
readonly kind = 'aggregate' as const;
|
|
550
|
+
readonly fn: AggregateFn;
|
|
551
|
+
readonly expr: AnyExpression | undefined;
|
|
46
552
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
553
|
+
constructor(fn: AggregateFn, expr?: AnyExpression) {
|
|
554
|
+
super();
|
|
555
|
+
if (fn !== 'count' && expr === undefined) {
|
|
556
|
+
throw new Error(`Aggregate function "${fn}" requires an expression`);
|
|
557
|
+
}
|
|
558
|
+
this.fn = fn;
|
|
559
|
+
this.expr = expr;
|
|
560
|
+
this.freeze();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
static count(expr?: AnyExpression): AggregateExpr {
|
|
564
|
+
return new AggregateExpr('count', expr);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
static sum(expr: AnyExpression): AggregateExpr {
|
|
568
|
+
return new AggregateExpr('sum', expr);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
static avg(expr: AnyExpression): AggregateExpr {
|
|
572
|
+
return new AggregateExpr('avg', expr);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
static min(expr: AnyExpression): AggregateExpr {
|
|
576
|
+
return new AggregateExpr('min', expr);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
static max(expr: AnyExpression): AggregateExpr {
|
|
580
|
+
return new AggregateExpr('max', expr);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
584
|
+
return visitor.aggregate(this);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
588
|
+
return this.expr === undefined ? this : new AggregateExpr(this.fn, this.expr.rewrite(rewriter));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
592
|
+
return this.expr ? this.expr.fold(folder) : folder.empty;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
export class JsonObjectExpr extends Expression {
|
|
597
|
+
readonly kind = 'json-object' as const;
|
|
598
|
+
readonly entries: ReadonlyArray<JsonObjectEntry>;
|
|
599
|
+
|
|
600
|
+
constructor(entries: ReadonlyArray<JsonObjectEntry>) {
|
|
601
|
+
super();
|
|
602
|
+
this.entries = frozenArrayCopy(entries.map((entry) => Object.freeze({ ...entry })));
|
|
603
|
+
this.freeze();
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
static entry(key: string, value: ProjectionExpr): JsonObjectEntry {
|
|
607
|
+
return {
|
|
608
|
+
key,
|
|
609
|
+
value,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
static fromEntries(entries: ReadonlyArray<JsonObjectEntry>): JsonObjectExpr {
|
|
614
|
+
return new JsonObjectExpr(entries);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
618
|
+
return visitor.jsonObject(this);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
622
|
+
return new JsonObjectExpr(
|
|
623
|
+
this.entries.map((entry) => ({
|
|
624
|
+
key: entry.key,
|
|
625
|
+
value:
|
|
626
|
+
entry.value.kind === 'literal'
|
|
627
|
+
? rewriter.literal
|
|
628
|
+
? rewriter.literal(entry.value)
|
|
629
|
+
: entry.value
|
|
630
|
+
: entry.value.rewrite(rewriter),
|
|
631
|
+
})),
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
636
|
+
return combineAll(
|
|
637
|
+
folder,
|
|
638
|
+
this.entries.map(
|
|
639
|
+
(entry) => () =>
|
|
640
|
+
entry.value.kind === 'literal'
|
|
641
|
+
? folder.literal
|
|
642
|
+
? folder.literal(entry.value)
|
|
643
|
+
: folder.empty
|
|
644
|
+
: entry.value.fold(folder),
|
|
645
|
+
),
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
export class OrderByItem extends AstNode {
|
|
651
|
+
readonly kind = 'order-by-item' as const;
|
|
652
|
+
readonly expr: AnyExpression;
|
|
653
|
+
readonly dir: Direction;
|
|
654
|
+
|
|
655
|
+
constructor(expr: AnyExpression, dir: Direction) {
|
|
656
|
+
super();
|
|
657
|
+
this.expr = expr;
|
|
658
|
+
this.dir = dir;
|
|
659
|
+
this.freeze();
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
static asc(expr: AnyExpression): OrderByItem {
|
|
663
|
+
return new OrderByItem(expr, 'asc');
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
static desc(expr: AnyExpression): OrderByItem {
|
|
667
|
+
return new OrderByItem(expr, 'desc');
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
rewrite(rewriter: ExpressionRewriter): OrderByItem {
|
|
671
|
+
return new OrderByItem(this.expr.rewrite(rewriter), this.dir);
|
|
672
|
+
}
|
|
53
673
|
}
|
|
54
674
|
|
|
55
|
-
export
|
|
56
|
-
|
|
675
|
+
export class JsonArrayAggExpr extends Expression {
|
|
676
|
+
readonly kind = 'json-array-agg' as const;
|
|
677
|
+
readonly expr: AnyExpression;
|
|
678
|
+
readonly onEmpty: 'null' | 'emptyArray';
|
|
679
|
+
readonly orderBy: ReadonlyArray<OrderByItem> | undefined;
|
|
680
|
+
|
|
681
|
+
constructor(
|
|
682
|
+
expr: AnyExpression,
|
|
683
|
+
onEmpty: 'null' | 'emptyArray' = 'null',
|
|
684
|
+
orderBy?: ReadonlyArray<OrderByItem>,
|
|
685
|
+
) {
|
|
686
|
+
super();
|
|
687
|
+
this.expr = expr;
|
|
688
|
+
this.onEmpty = onEmpty;
|
|
689
|
+
this.orderBy = orderBy && orderBy.length > 0 ? frozenArrayCopy(orderBy) : undefined;
|
|
690
|
+
this.freeze();
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
static of(
|
|
694
|
+
expr: AnyExpression,
|
|
695
|
+
onEmpty: 'null' | 'emptyArray' = 'null',
|
|
696
|
+
orderBy?: ReadonlyArray<OrderByItem>,
|
|
697
|
+
): JsonArrayAggExpr {
|
|
698
|
+
return new JsonArrayAggExpr(expr, onEmpty, orderBy);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
702
|
+
return visitor.jsonArrayAgg(this);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
706
|
+
return new JsonArrayAggExpr(
|
|
707
|
+
this.expr.rewrite(rewriter),
|
|
708
|
+
this.onEmpty,
|
|
709
|
+
this.orderBy?.map((orderItem) => orderItem.rewrite(rewriter)),
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
714
|
+
return combineAll(folder, [
|
|
715
|
+
() => this.expr.fold(folder),
|
|
716
|
+
...(this.orderBy ?? []).map((orderItem) => () => orderItem.expr.fold(folder)),
|
|
717
|
+
]);
|
|
718
|
+
}
|
|
57
719
|
}
|
|
58
720
|
|
|
59
|
-
export
|
|
721
|
+
export class ListExpression extends Expression {
|
|
722
|
+
readonly kind = 'list' as const;
|
|
723
|
+
readonly values: ReadonlyArray<AnyExpression>;
|
|
724
|
+
|
|
725
|
+
constructor(values: ReadonlyArray<AnyExpression>) {
|
|
726
|
+
super();
|
|
727
|
+
this.values = frozenArrayCopy(values);
|
|
728
|
+
this.freeze();
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
static of(values: ReadonlyArray<AnyExpression>): ListExpression {
|
|
732
|
+
return new ListExpression(values);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
static fromValues(values: ReadonlyArray<unknown>): ListExpression {
|
|
736
|
+
return new ListExpression(values.map((value) => new LiteralExpr(value)));
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
740
|
+
return visitor.list(this);
|
|
741
|
+
}
|
|
60
742
|
|
|
61
|
-
|
|
62
|
-
|
|
743
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
744
|
+
if (rewriter.list) {
|
|
745
|
+
return rewriter.list(this);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
return new ListExpression(this.values.map((value) => value.rewrite(rewriter)));
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
fold<T>(folder: ExpressionFolder<T>): T {
|
|
752
|
+
if (folder.list) {
|
|
753
|
+
return folder.list(this);
|
|
754
|
+
}
|
|
755
|
+
return combineAll(
|
|
756
|
+
folder,
|
|
757
|
+
this.values.map((value) => () => value.fold(folder)),
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
export class BinaryExpr extends Expression {
|
|
763
|
+
readonly kind = 'binary' as const;
|
|
63
764
|
readonly op: BinaryOp;
|
|
64
|
-
readonly left:
|
|
65
|
-
readonly right:
|
|
765
|
+
readonly left: AnyExpression;
|
|
766
|
+
readonly right: AnyExpression;
|
|
767
|
+
|
|
768
|
+
constructor(op: BinaryOp, left: AnyExpression, right: AnyExpression) {
|
|
769
|
+
super();
|
|
770
|
+
this.op = op;
|
|
771
|
+
this.left = left;
|
|
772
|
+
this.right = right;
|
|
773
|
+
this.freeze();
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
static eq(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
777
|
+
return new BinaryExpr('eq', left, right);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
static neq(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
781
|
+
return new BinaryExpr('neq', left, right);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
static gt(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
785
|
+
return new BinaryExpr('gt', left, right);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
static lt(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
789
|
+
return new BinaryExpr('lt', left, right);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
static gte(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
793
|
+
return new BinaryExpr('gte', left, right);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
static lte(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
797
|
+
return new BinaryExpr('lte', left, right);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
static like(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
801
|
+
return new BinaryExpr('like', left, right);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
static ilike(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
805
|
+
return new BinaryExpr('ilike', left, right);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
static in(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
809
|
+
return new BinaryExpr('in', left, right);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
static notIn(left: AnyExpression, right: AnyExpression): BinaryExpr {
|
|
813
|
+
return new BinaryExpr('notIn', left, right);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
817
|
+
return visitor.binary(this);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
821
|
+
return new BinaryExpr(
|
|
822
|
+
this.op,
|
|
823
|
+
rewriteComparable(this.left, rewriter),
|
|
824
|
+
rewriteComparable(this.right, rewriter),
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
829
|
+
return combineAll(folder, [
|
|
830
|
+
() => foldComparable(this.left, folder),
|
|
831
|
+
() => foldComparable(this.right, folder),
|
|
832
|
+
]);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
export class AndExpr extends Expression {
|
|
837
|
+
readonly kind = 'and' as const;
|
|
838
|
+
readonly exprs: ReadonlyArray<AnyExpression>;
|
|
839
|
+
|
|
840
|
+
constructor(exprs: ReadonlyArray<AnyExpression>) {
|
|
841
|
+
super();
|
|
842
|
+
this.exprs = frozenArrayCopy(exprs);
|
|
843
|
+
this.freeze();
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
static of(exprs: ReadonlyArray<AnyExpression>): AndExpr {
|
|
847
|
+
return new AndExpr(exprs);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
static true(): AndExpr {
|
|
851
|
+
return new AndExpr([]);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
855
|
+
return visitor.and(this);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
859
|
+
return new AndExpr(this.exprs.map((expr) => expr.rewrite(rewriter)));
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
863
|
+
return combineAll(
|
|
864
|
+
folder,
|
|
865
|
+
this.exprs.map((expr) => () => expr.fold(folder)),
|
|
866
|
+
);
|
|
867
|
+
}
|
|
66
868
|
}
|
|
67
869
|
|
|
68
|
-
export
|
|
69
|
-
readonly kind
|
|
70
|
-
readonly
|
|
870
|
+
export class OrExpr extends Expression {
|
|
871
|
+
readonly kind = 'or' as const;
|
|
872
|
+
readonly exprs: ReadonlyArray<AnyExpression>;
|
|
873
|
+
|
|
874
|
+
constructor(exprs: ReadonlyArray<AnyExpression>) {
|
|
875
|
+
super();
|
|
876
|
+
this.exprs = frozenArrayCopy(exprs);
|
|
877
|
+
this.freeze();
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
static of(exprs: ReadonlyArray<AnyExpression>): OrExpr {
|
|
881
|
+
return new OrExpr(exprs);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
static false(): OrExpr {
|
|
885
|
+
return new OrExpr([]);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
889
|
+
return visitor.or(this);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
893
|
+
return new OrExpr(this.exprs.map((expr) => expr.rewrite(rewriter)));
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
897
|
+
return combineAll(
|
|
898
|
+
folder,
|
|
899
|
+
this.exprs.map((expr) => () => expr.fold(folder)),
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
export class ExistsExpr extends Expression {
|
|
905
|
+
readonly kind = 'exists' as const;
|
|
906
|
+
readonly notExists: boolean;
|
|
71
907
|
readonly subquery: SelectAst;
|
|
908
|
+
|
|
909
|
+
constructor(subquery: SelectAst, notExists = false) {
|
|
910
|
+
super();
|
|
911
|
+
this.notExists = notExists;
|
|
912
|
+
this.subquery = subquery;
|
|
913
|
+
this.freeze();
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
static exists(subquery: SelectAst): ExistsExpr {
|
|
917
|
+
return new ExistsExpr(subquery, false);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
static notExists(subquery: SelectAst): ExistsExpr {
|
|
921
|
+
return new ExistsExpr(subquery, true);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
925
|
+
return visitor.exists(this);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
929
|
+
return new ExistsExpr(this.subquery.rewrite(rewriter), this.notExists);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
933
|
+
return folder.select ? folder.select(this.subquery) : folder.empty;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
export class NullCheckExpr extends Expression {
|
|
938
|
+
readonly kind = 'null-check' as const;
|
|
939
|
+
readonly expr: AnyExpression;
|
|
940
|
+
readonly isNull: boolean;
|
|
941
|
+
|
|
942
|
+
constructor(expr: AnyExpression, isNull: boolean) {
|
|
943
|
+
super();
|
|
944
|
+
this.expr = expr;
|
|
945
|
+
this.isNull = isNull;
|
|
946
|
+
this.freeze();
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
static isNull(expr: AnyExpression): NullCheckExpr {
|
|
950
|
+
return new NullCheckExpr(expr, true);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
static isNotNull(expr: AnyExpression): NullCheckExpr {
|
|
954
|
+
return new NullCheckExpr(expr, false);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
958
|
+
return visitor.nullCheck(this);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
962
|
+
return new NullCheckExpr(this.expr.rewrite(rewriter), this.isNull);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
966
|
+
return this.expr.fold(folder);
|
|
967
|
+
}
|
|
72
968
|
}
|
|
73
969
|
|
|
74
|
-
export
|
|
75
|
-
readonly kind
|
|
970
|
+
export class NotExpr extends Expression {
|
|
971
|
+
readonly kind = 'not' as const;
|
|
972
|
+
readonly expr: AnyExpression;
|
|
973
|
+
|
|
974
|
+
constructor(expr: AnyExpression) {
|
|
975
|
+
super();
|
|
976
|
+
this.expr = expr;
|
|
977
|
+
this.freeze();
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
toWhereExpr(): AnyExpression {
|
|
981
|
+
return this;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
override accept<R>(visitor: ExprVisitor<R>): R {
|
|
985
|
+
return visitor.not(this);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
override rewrite(rewriter: ExpressionRewriter): AnyExpression {
|
|
989
|
+
return new NotExpr(this.expr.rewrite(rewriter));
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
override fold<T>(folder: ExpressionFolder<T>): T {
|
|
993
|
+
return this.expr.fold(folder);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
export class EqColJoinOn extends AstNode {
|
|
998
|
+
readonly kind = 'eq-col-join-on' as const;
|
|
76
999
|
readonly left: ColumnRef;
|
|
77
1000
|
readonly right: ColumnRef;
|
|
78
|
-
};
|
|
79
1001
|
|
|
80
|
-
|
|
81
|
-
|
|
1002
|
+
constructor(left: ColumnRef, right: ColumnRef) {
|
|
1003
|
+
super();
|
|
1004
|
+
this.left = left;
|
|
1005
|
+
this.right = right;
|
|
1006
|
+
this.freeze();
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
static of(left: ColumnRef, right: ColumnRef): EqColJoinOn {
|
|
1010
|
+
return new EqColJoinOn(left, right);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
rewrite(rewriter: AstRewriter): EqColJoinOn | AnyExpression {
|
|
1014
|
+
return rewriter.eqColJoinOn ? rewriter.eqColJoinOn(this) : this;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
export class JoinAst extends AstNode {
|
|
1019
|
+
readonly kind = 'join' as const;
|
|
82
1020
|
readonly joinType: 'inner' | 'left' | 'right' | 'full';
|
|
83
|
-
readonly
|
|
1021
|
+
readonly source: AnyFromSource;
|
|
1022
|
+
readonly lateral: boolean;
|
|
84
1023
|
readonly on: JoinOnExpr;
|
|
1024
|
+
|
|
1025
|
+
constructor(
|
|
1026
|
+
joinType: 'inner' | 'left' | 'right' | 'full',
|
|
1027
|
+
source: AnyFromSource,
|
|
1028
|
+
on: JoinOnExpr,
|
|
1029
|
+
lateral = false,
|
|
1030
|
+
) {
|
|
1031
|
+
super();
|
|
1032
|
+
this.joinType = joinType;
|
|
1033
|
+
this.source = source;
|
|
1034
|
+
this.lateral = lateral;
|
|
1035
|
+
this.on = on;
|
|
1036
|
+
this.freeze();
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
static inner(source: AnyFromSource, on: JoinOnExpr, lateral = false): JoinAst {
|
|
1040
|
+
return new JoinAst('inner', source, on, lateral);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
static left(source: AnyFromSource, on: JoinOnExpr, lateral = false): JoinAst {
|
|
1044
|
+
return new JoinAst('left', source, on, lateral);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
static right(source: AnyFromSource, on: JoinOnExpr, lateral = false): JoinAst {
|
|
1048
|
+
return new JoinAst('right', source, on, lateral);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
static full(source: AnyFromSource, on: JoinOnExpr, lateral = false): JoinAst {
|
|
1052
|
+
return new JoinAst('full', source, on, lateral);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
rewrite(rewriter: AstRewriter): JoinAst {
|
|
1056
|
+
return new JoinAst(
|
|
1057
|
+
this.joinType,
|
|
1058
|
+
this.source.rewrite(rewriter),
|
|
1059
|
+
this.on.kind === 'eq-col-join-on' ? this.on.rewrite(rewriter) : this.on.rewrite(rewriter),
|
|
1060
|
+
this.lateral,
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
85
1063
|
}
|
|
86
1064
|
|
|
87
|
-
export
|
|
88
|
-
readonly kind
|
|
1065
|
+
export class ProjectionItem extends AstNode {
|
|
1066
|
+
readonly kind = 'projection-item' as const;
|
|
89
1067
|
readonly alias: string;
|
|
1068
|
+
readonly expr: ProjectionExpr;
|
|
1069
|
+
|
|
1070
|
+
constructor(alias: string, expr: ProjectionExpr) {
|
|
1071
|
+
super();
|
|
1072
|
+
this.alias = alias;
|
|
1073
|
+
this.expr = expr;
|
|
1074
|
+
this.freeze();
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
static of(alias: string, expr: ProjectionExpr): ProjectionItem {
|
|
1078
|
+
return new ProjectionItem(alias, expr);
|
|
1079
|
+
}
|
|
90
1080
|
}
|
|
91
1081
|
|
|
92
|
-
export interface
|
|
93
|
-
readonly
|
|
94
|
-
readonly
|
|
95
|
-
readonly
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
1082
|
+
export interface SelectAstOptions {
|
|
1083
|
+
readonly from: AnyFromSource;
|
|
1084
|
+
readonly joins: ReadonlyArray<JoinAst> | undefined;
|
|
1085
|
+
readonly projection: ReadonlyArray<ProjectionItem>;
|
|
1086
|
+
readonly where: AnyExpression | undefined;
|
|
1087
|
+
readonly orderBy: ReadonlyArray<OrderByItem> | undefined;
|
|
1088
|
+
readonly distinct: true | undefined;
|
|
1089
|
+
readonly distinctOn: ReadonlyArray<AnyExpression> | undefined;
|
|
1090
|
+
readonly groupBy: ReadonlyArray<AnyExpression> | undefined;
|
|
1091
|
+
readonly having: AnyExpression | undefined;
|
|
1092
|
+
readonly limit: number | undefined;
|
|
1093
|
+
readonly offset: number | undefined;
|
|
1094
|
+
readonly selectAllIntent: { readonly table?: string } | undefined;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
export class SelectAst extends QueryAst {
|
|
1098
|
+
readonly kind = 'select' as const;
|
|
1099
|
+
readonly from: AnyFromSource;
|
|
1100
|
+
readonly joins: ReadonlyArray<JoinAst> | undefined;
|
|
1101
|
+
readonly projection: ReadonlyArray<ProjectionItem>;
|
|
1102
|
+
readonly where: AnyExpression | undefined;
|
|
1103
|
+
readonly orderBy: ReadonlyArray<OrderByItem> | undefined;
|
|
1104
|
+
readonly distinct: true | undefined;
|
|
1105
|
+
readonly distinctOn: ReadonlyArray<AnyExpression> | undefined;
|
|
1106
|
+
readonly groupBy: ReadonlyArray<AnyExpression> | undefined;
|
|
1107
|
+
readonly having: AnyExpression | undefined;
|
|
1108
|
+
readonly limit: number | undefined;
|
|
1109
|
+
readonly offset: number | undefined;
|
|
1110
|
+
readonly selectAllIntent: { readonly table?: string } | undefined;
|
|
1111
|
+
|
|
1112
|
+
constructor(options: SelectAstOptions) {
|
|
1113
|
+
super();
|
|
1114
|
+
this.from = options.from;
|
|
1115
|
+
this.joins =
|
|
1116
|
+
options.joins && options.joins.length > 0 ? frozenArrayCopy(options.joins) : undefined;
|
|
1117
|
+
this.projection = frozenArrayCopy(options.projection);
|
|
1118
|
+
this.where = options.where;
|
|
1119
|
+
this.orderBy =
|
|
1120
|
+
options.orderBy && options.orderBy.length > 0 ? frozenArrayCopy(options.orderBy) : undefined;
|
|
1121
|
+
this.distinct = options.distinct;
|
|
1122
|
+
this.distinctOn =
|
|
1123
|
+
options.distinctOn && options.distinctOn.length > 0
|
|
1124
|
+
? frozenArrayCopy(options.distinctOn)
|
|
1125
|
+
: undefined;
|
|
1126
|
+
this.groupBy =
|
|
1127
|
+
options.groupBy && options.groupBy.length > 0 ? frozenArrayCopy(options.groupBy) : undefined;
|
|
1128
|
+
this.having = options.having;
|
|
1129
|
+
this.limit = options.limit;
|
|
1130
|
+
this.offset = options.offset;
|
|
1131
|
+
this.selectAllIntent = frozenOptionalRecordCopy(options.selectAllIntent);
|
|
1132
|
+
this.freeze();
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
static from(from: AnyFromSource): SelectAst {
|
|
1136
|
+
return new SelectAst({
|
|
1137
|
+
from,
|
|
1138
|
+
joins: undefined,
|
|
1139
|
+
projection: [],
|
|
1140
|
+
where: undefined,
|
|
1141
|
+
orderBy: undefined,
|
|
1142
|
+
distinct: undefined,
|
|
1143
|
+
distinctOn: undefined,
|
|
1144
|
+
groupBy: undefined,
|
|
1145
|
+
having: undefined,
|
|
1146
|
+
limit: undefined,
|
|
1147
|
+
offset: undefined,
|
|
1148
|
+
selectAllIntent: undefined,
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
withFrom(from: AnyFromSource): SelectAst {
|
|
1153
|
+
return new SelectAst({ ...this, from });
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
withJoins(joins: ReadonlyArray<JoinAst>): SelectAst {
|
|
1157
|
+
return new SelectAst({
|
|
1158
|
+
...this,
|
|
1159
|
+
joins: joins.length > 0 ? joins : undefined,
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
withProjection(projection: ReadonlyArray<ProjectionItem>): SelectAst {
|
|
1164
|
+
return new SelectAst({ ...this, projection });
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
addProjection(alias: string, expr: ProjectionExpr): SelectAst {
|
|
1168
|
+
return new SelectAst({
|
|
1169
|
+
...this,
|
|
1170
|
+
projection: [...this.projection, new ProjectionItem(alias, expr)],
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
withWhere(where: AnyExpression | undefined): SelectAst {
|
|
1175
|
+
return new SelectAst({ ...this, where });
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
withOrderBy(orderBy: ReadonlyArray<OrderByItem>): SelectAst {
|
|
1179
|
+
return new SelectAst({
|
|
1180
|
+
...this,
|
|
1181
|
+
orderBy: orderBy.length > 0 ? orderBy : undefined,
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
withDistinct(enabled = true): SelectAst {
|
|
1186
|
+
return new SelectAst({
|
|
1187
|
+
...this,
|
|
1188
|
+
distinct: enabled ? true : undefined,
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
withDistinctOn(distinctOn: ReadonlyArray<AnyExpression>): SelectAst {
|
|
1193
|
+
return new SelectAst({
|
|
1194
|
+
...this,
|
|
1195
|
+
distinctOn: distinctOn.length > 0 ? distinctOn : undefined,
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
withGroupBy(groupBy: ReadonlyArray<AnyExpression>): SelectAst {
|
|
1200
|
+
return new SelectAst({
|
|
1201
|
+
...this,
|
|
1202
|
+
groupBy: groupBy.length > 0 ? groupBy : undefined,
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
withHaving(having: AnyExpression | undefined): SelectAst {
|
|
1207
|
+
return new SelectAst({ ...this, having });
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
withLimit(limit: number | undefined): SelectAst {
|
|
1211
|
+
return new SelectAst({ ...this, limit });
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
withOffset(offset: number | undefined): SelectAst {
|
|
1215
|
+
return new SelectAst({ ...this, offset });
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
withSelectAllIntent(selectAllIntent: { readonly table?: string } | undefined): SelectAst {
|
|
1219
|
+
return new SelectAst({ ...this, selectAllIntent });
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
rewrite(rewriter: AstRewriter): SelectAst {
|
|
1223
|
+
const rewritten = new SelectAst({
|
|
1224
|
+
from: this.from.rewrite(rewriter),
|
|
1225
|
+
joins: this.joins?.map((join) => join.rewrite(rewriter)),
|
|
1226
|
+
projection: this.projection.map(
|
|
1227
|
+
(projection) =>
|
|
1228
|
+
new ProjectionItem(
|
|
1229
|
+
projection.alias,
|
|
1230
|
+
projection.expr.kind === 'literal'
|
|
1231
|
+
? rewriter.literal
|
|
1232
|
+
? rewriter.literal(projection.expr)
|
|
1233
|
+
: projection.expr
|
|
1234
|
+
: projection.expr.rewrite(rewriter),
|
|
1235
|
+
),
|
|
1236
|
+
),
|
|
1237
|
+
where: this.where?.rewrite(rewriter),
|
|
1238
|
+
orderBy: this.orderBy?.map((orderItem) => orderItem.rewrite(rewriter)),
|
|
1239
|
+
distinct: this.distinct,
|
|
1240
|
+
distinctOn: this.distinctOn?.map((expr) => expr.rewrite(rewriter)),
|
|
1241
|
+
groupBy: this.groupBy?.map((expr) => expr.rewrite(rewriter)),
|
|
1242
|
+
having: this.having?.rewrite(rewriter),
|
|
1243
|
+
limit: this.limit,
|
|
1244
|
+
offset: this.offset,
|
|
1245
|
+
selectAllIntent: this.selectAllIntent,
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
return rewriter.select ? rewriter.select(rewritten) : rewritten;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
override collectColumnRefs(): ColumnRef[] {
|
|
1252
|
+
const refs: ColumnRef[] = [];
|
|
1253
|
+
const pushRefs = (columns: ReadonlyArray<ColumnRef>) => {
|
|
1254
|
+
refs.push(...columns);
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
if (this.from.kind === 'derived-table-source') {
|
|
1258
|
+
pushRefs(this.from.query.collectColumnRefs());
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
for (const projection of this.projection) {
|
|
1262
|
+
if (!(projection.expr.kind === 'literal')) {
|
|
1263
|
+
pushRefs(projection.expr.collectColumnRefs());
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
if (this.where) {
|
|
1268
|
+
pushRefs(this.where.collectColumnRefs());
|
|
1269
|
+
}
|
|
1270
|
+
if (this.having) {
|
|
1271
|
+
pushRefs(this.having.collectColumnRefs());
|
|
1272
|
+
}
|
|
1273
|
+
for (const orderItem of this.orderBy ?? []) {
|
|
1274
|
+
pushRefs(orderItem.expr.collectColumnRefs());
|
|
1275
|
+
}
|
|
1276
|
+
for (const expr of this.distinctOn ?? []) {
|
|
1277
|
+
pushRefs(expr.collectColumnRefs());
|
|
1278
|
+
}
|
|
1279
|
+
for (const expr of this.groupBy ?? []) {
|
|
1280
|
+
pushRefs(expr.collectColumnRefs());
|
|
1281
|
+
}
|
|
1282
|
+
for (const join of this.joins ?? []) {
|
|
1283
|
+
if (join.source.kind === 'derived-table-source') {
|
|
1284
|
+
pushRefs(join.source.query.collectColumnRefs());
|
|
1285
|
+
}
|
|
1286
|
+
if (join.on.kind === 'eq-col-join-on') {
|
|
1287
|
+
refs.push(join.on.left, join.on.right);
|
|
1288
|
+
} else {
|
|
1289
|
+
pushRefs(join.on.collectColumnRefs());
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
return refs;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
collectParamRefs(): ParamRef[] {
|
|
1297
|
+
const refs: ParamRef[] = [];
|
|
1298
|
+
const pushRefs = (params: ReadonlyArray<ParamRef>) => {
|
|
1299
|
+
refs.push(...params);
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
if (this.from.kind === 'derived-table-source') {
|
|
1303
|
+
pushRefs(this.from.query.collectParamRefs());
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
for (const projection of this.projection) {
|
|
1307
|
+
if (!(projection.expr.kind === 'literal')) {
|
|
1308
|
+
pushRefs(projection.expr.collectParamRefs());
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
if (this.where) {
|
|
1313
|
+
pushRefs(this.where.collectParamRefs());
|
|
1314
|
+
}
|
|
1315
|
+
if (this.having) {
|
|
1316
|
+
pushRefs(this.having.collectParamRefs());
|
|
1317
|
+
}
|
|
1318
|
+
for (const orderItem of this.orderBy ?? []) {
|
|
1319
|
+
pushRefs(orderItem.expr.collectParamRefs());
|
|
1320
|
+
}
|
|
1321
|
+
for (const expr of this.distinctOn ?? []) {
|
|
1322
|
+
pushRefs(expr.collectParamRefs());
|
|
1323
|
+
}
|
|
1324
|
+
for (const expr of this.groupBy ?? []) {
|
|
1325
|
+
pushRefs(expr.collectParamRefs());
|
|
1326
|
+
}
|
|
1327
|
+
for (const join of this.joins ?? []) {
|
|
1328
|
+
if (join.source.kind === 'derived-table-source') {
|
|
1329
|
+
pushRefs(join.source.query.collectParamRefs());
|
|
1330
|
+
}
|
|
1331
|
+
if (!(join.on.kind === 'eq-col-join-on')) {
|
|
1332
|
+
pushRefs(join.on.collectParamRefs());
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
return refs;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
override collectRefs(): PlanRefs {
|
|
1340
|
+
const tables = new Set<string>();
|
|
1341
|
+
const columns = new Map<string, { table: string; column: string }>();
|
|
1342
|
+
|
|
1343
|
+
const addSource = (source: AnyFromSource) => {
|
|
1344
|
+
mergeRefsInto(source.collectRefs(), tables, columns);
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
addSource(this.from);
|
|
1348
|
+
|
|
1349
|
+
for (const join of this.joins ?? []) {
|
|
1350
|
+
addSource(join.source);
|
|
1351
|
+
if (join.on.kind === 'eq-col-join-on') {
|
|
1352
|
+
addColumnRefToRefSets(join.on.left, tables, columns);
|
|
1353
|
+
addColumnRefToRefSets(join.on.right, tables, columns);
|
|
1354
|
+
} else {
|
|
1355
|
+
for (const columnRef of join.on.collectColumnRefs()) {
|
|
1356
|
+
addColumnRefToRefSets(columnRef, tables, columns);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
for (const columnRef of this.collectColumnRefs()) {
|
|
1362
|
+
addColumnRefToRefSets(columnRef, tables, columns);
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
return sortRefs(tables, columns);
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
override toQueryAst(): AnyQueryAst {
|
|
1369
|
+
return this;
|
|
1370
|
+
}
|
|
103
1371
|
}
|
|
104
1372
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
readonly from: TableRef;
|
|
108
|
-
readonly joins?: ReadonlyArray<JoinAst>;
|
|
109
|
-
readonly includes?: ReadonlyArray<IncludeAst>;
|
|
110
|
-
readonly project: ReadonlyArray<{
|
|
111
|
-
alias: string;
|
|
112
|
-
expr: Expression | IncludeRef | LiteralExpr;
|
|
113
|
-
}>;
|
|
114
|
-
readonly where?: BinaryExpr | ExistsExpr;
|
|
115
|
-
readonly orderBy?: ReadonlyArray<{ expr: Expression; dir: Direction }>;
|
|
116
|
-
readonly limit?: number;
|
|
1373
|
+
abstract class InsertOnConflictAction extends AstNode {
|
|
1374
|
+
abstract toInsertOnConflictAction(): AnyInsertOnConflictAction;
|
|
117
1375
|
}
|
|
118
1376
|
|
|
119
|
-
export
|
|
120
|
-
readonly kind
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
1377
|
+
export class DoNothingConflictAction extends InsertOnConflictAction {
|
|
1378
|
+
readonly kind = 'do-nothing' as const;
|
|
1379
|
+
|
|
1380
|
+
constructor() {
|
|
1381
|
+
super();
|
|
1382
|
+
this.freeze();
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
override toInsertOnConflictAction(): AnyInsertOnConflictAction {
|
|
1386
|
+
return this;
|
|
1387
|
+
}
|
|
124
1388
|
}
|
|
125
1389
|
|
|
126
|
-
export
|
|
127
|
-
readonly kind
|
|
128
|
-
readonly
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
1390
|
+
export class DoUpdateSetConflictAction extends InsertOnConflictAction {
|
|
1391
|
+
readonly kind = 'do-update-set' as const;
|
|
1392
|
+
readonly set: Readonly<Record<string, ColumnRef | ParamRef>>;
|
|
1393
|
+
|
|
1394
|
+
constructor(set: Readonly<Record<string, ColumnRef | ParamRef>>) {
|
|
1395
|
+
super();
|
|
1396
|
+
this.set = frozenRecordCopy(set);
|
|
1397
|
+
this.freeze();
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
override toInsertOnConflictAction(): AnyInsertOnConflictAction {
|
|
1401
|
+
return this;
|
|
1402
|
+
}
|
|
132
1403
|
}
|
|
133
1404
|
|
|
134
|
-
export
|
|
135
|
-
readonly kind
|
|
136
|
-
readonly
|
|
137
|
-
readonly
|
|
138
|
-
|
|
1405
|
+
export class InsertOnConflict extends AstNode {
|
|
1406
|
+
readonly kind = 'insert-on-conflict' as const;
|
|
1407
|
+
readonly columns: ReadonlyArray<ColumnRef>;
|
|
1408
|
+
readonly action: AnyInsertOnConflictAction;
|
|
1409
|
+
|
|
1410
|
+
constructor(columns: ReadonlyArray<ColumnRef>, action: AnyInsertOnConflictAction) {
|
|
1411
|
+
super();
|
|
1412
|
+
this.columns = frozenArrayCopy(columns);
|
|
1413
|
+
this.action = action;
|
|
1414
|
+
this.freeze();
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
static on(columns: ReadonlyArray<ColumnRef>): InsertOnConflict {
|
|
1418
|
+
return new InsertOnConflict(columns, new DoNothingConflictAction());
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
doNothing(): InsertOnConflict {
|
|
1422
|
+
return new InsertOnConflict(this.columns, new DoNothingConflictAction());
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
doUpdateSet(set: Readonly<Record<string, ColumnRef | ParamRef>>): InsertOnConflict {
|
|
1426
|
+
return new InsertOnConflict(this.columns, new DoUpdateSetConflictAction(set));
|
|
1427
|
+
}
|
|
139
1428
|
}
|
|
140
1429
|
|
|
141
|
-
export
|
|
1430
|
+
export class InsertAst extends QueryAst {
|
|
1431
|
+
readonly kind = 'insert' as const;
|
|
1432
|
+
readonly table: TableSource;
|
|
1433
|
+
readonly rows: ReadonlyArray<Readonly<Record<string, InsertValue>>>;
|
|
1434
|
+
readonly onConflict: InsertOnConflict | undefined;
|
|
1435
|
+
readonly returning: ReadonlyArray<ColumnRef> | undefined;
|
|
1436
|
+
|
|
1437
|
+
constructor(
|
|
1438
|
+
table: TableSource,
|
|
1439
|
+
rows: ReadonlyArray<Record<string, InsertValue>> = [{}],
|
|
1440
|
+
onConflict?: InsertOnConflict,
|
|
1441
|
+
returning?: ReadonlyArray<ColumnRef>,
|
|
1442
|
+
) {
|
|
1443
|
+
super();
|
|
1444
|
+
this.table = table;
|
|
1445
|
+
this.rows = freezeRows(rows);
|
|
1446
|
+
this.onConflict = onConflict;
|
|
1447
|
+
this.returning = returning && returning.length > 0 ? frozenArrayCopy(returning) : undefined;
|
|
1448
|
+
this.freeze();
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
static into(table: TableSource): InsertAst {
|
|
1452
|
+
return new InsertAst(table);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
withValues(values: Record<string, InsertValue>): InsertAst {
|
|
1456
|
+
return new InsertAst(this.table, [{ ...values }], this.onConflict, this.returning);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
withRows(rows: ReadonlyArray<Record<string, InsertValue>>): InsertAst {
|
|
1460
|
+
return new InsertAst(
|
|
1461
|
+
this.table,
|
|
1462
|
+
rows.map((row) => ({ ...row })),
|
|
1463
|
+
this.onConflict,
|
|
1464
|
+
this.returning,
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
withReturning(returning: ReadonlyArray<ColumnRef> | undefined): InsertAst {
|
|
1469
|
+
return new InsertAst(
|
|
1470
|
+
this.table,
|
|
1471
|
+
this.rows.map((row) => ({ ...row })),
|
|
1472
|
+
this.onConflict,
|
|
1473
|
+
returning,
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
withOnConflict(onConflict: InsertOnConflict | undefined): InsertAst {
|
|
1478
|
+
return new InsertAst(
|
|
1479
|
+
this.table,
|
|
1480
|
+
this.rows.map((row) => ({ ...row })),
|
|
1481
|
+
onConflict,
|
|
1482
|
+
this.returning,
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
override collectParamRefs(): ParamRef[] {
|
|
1487
|
+
const refs: ParamRef[] = [];
|
|
1488
|
+
for (const row of this.rows) {
|
|
1489
|
+
for (const value of Object.values(row)) {
|
|
1490
|
+
if (value.kind === 'param-ref') {
|
|
1491
|
+
refs.push(value);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (this.onConflict?.action.kind === 'do-update-set') {
|
|
1496
|
+
for (const value of Object.values(this.onConflict.action.set)) {
|
|
1497
|
+
if (value.kind === 'param-ref') {
|
|
1498
|
+
refs.push(value);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
return refs;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
override collectRefs(): PlanRefs {
|
|
1506
|
+
const tables = new Set<string>([this.table.name]);
|
|
1507
|
+
const columns = new Map<string, { table: string; column: string }>();
|
|
1508
|
+
|
|
1509
|
+
const addColumn = (columnRef: ColumnRef) => addColumnRefToRefSets(columnRef, tables, columns);
|
|
1510
|
+
const addValue = (value: InsertValue) => {
|
|
1511
|
+
if (value.kind === 'column-ref') {
|
|
1512
|
+
addColumn(value);
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1516
|
+
for (const row of this.rows) {
|
|
1517
|
+
for (const value of Object.values(row)) {
|
|
1518
|
+
addValue(value);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
for (const columnRef of this.returning ?? []) {
|
|
1523
|
+
addColumn(columnRef);
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
if (this.onConflict) {
|
|
1527
|
+
for (const columnRef of this.onConflict.columns) {
|
|
1528
|
+
addColumn(columnRef);
|
|
1529
|
+
}
|
|
1530
|
+
if (this.onConflict.action.kind === 'do-update-set') {
|
|
1531
|
+
for (const value of Object.values(this.onConflict.action.set)) {
|
|
1532
|
+
if (value.kind === 'column-ref') {
|
|
1533
|
+
addColumn(value);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
return sortRefs(tables, columns);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
override toQueryAst(): AnyQueryAst {
|
|
1543
|
+
return this;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
export class UpdateAst extends QueryAst {
|
|
1548
|
+
readonly kind = 'update' as const;
|
|
1549
|
+
readonly table: TableSource;
|
|
1550
|
+
readonly set: Readonly<Record<string, ColumnRef | ParamRef>>;
|
|
1551
|
+
readonly where: AnyExpression | undefined;
|
|
1552
|
+
readonly returning: ReadonlyArray<ColumnRef> | undefined;
|
|
1553
|
+
|
|
1554
|
+
constructor(
|
|
1555
|
+
table: TableSource,
|
|
1556
|
+
set: Readonly<Record<string, ColumnRef | ParamRef>> = {},
|
|
1557
|
+
where?: AnyExpression,
|
|
1558
|
+
returning?: ReadonlyArray<ColumnRef>,
|
|
1559
|
+
) {
|
|
1560
|
+
super();
|
|
1561
|
+
this.table = table;
|
|
1562
|
+
this.set = frozenRecordCopy(set);
|
|
1563
|
+
this.where = where;
|
|
1564
|
+
this.returning = returning && returning.length > 0 ? frozenArrayCopy(returning) : undefined;
|
|
1565
|
+
this.freeze();
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
static table(table: TableSource): UpdateAst {
|
|
1569
|
+
return new UpdateAst(table);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
withSet(set: Readonly<Record<string, ColumnRef | ParamRef>>): UpdateAst {
|
|
1573
|
+
return new UpdateAst(this.table, set, this.where, this.returning);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
withWhere(where: AnyExpression | undefined): UpdateAst {
|
|
1577
|
+
return new UpdateAst(this.table, this.set, where, this.returning);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
withReturning(returning: ReadonlyArray<ColumnRef> | undefined): UpdateAst {
|
|
1581
|
+
return new UpdateAst(this.table, this.set, this.where, returning);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
override collectParamRefs(): ParamRef[] {
|
|
1585
|
+
const refs: ParamRef[] = [];
|
|
1586
|
+
for (const value of Object.values(this.set)) {
|
|
1587
|
+
if (value.kind === 'param-ref') {
|
|
1588
|
+
refs.push(value);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
if (this.where) {
|
|
1592
|
+
refs.push(...this.where.collectParamRefs());
|
|
1593
|
+
}
|
|
1594
|
+
return refs;
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
override collectRefs(): PlanRefs {
|
|
1598
|
+
const tables = new Set<string>([this.table.name]);
|
|
1599
|
+
const columns = new Map<string, { table: string; column: string }>();
|
|
1600
|
+
|
|
1601
|
+
for (const value of Object.values(this.set)) {
|
|
1602
|
+
if (value.kind === 'column-ref') {
|
|
1603
|
+
addColumnRefToRefSets(value, tables, columns);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
for (const columnRef of this.where?.collectColumnRefs() ?? []) {
|
|
1608
|
+
addColumnRefToRefSets(columnRef, tables, columns);
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
for (const columnRef of this.returning ?? []) {
|
|
1612
|
+
addColumnRefToRefSets(columnRef, tables, columns);
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
return sortRefs(tables, columns);
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
override toQueryAst(): AnyQueryAst {
|
|
1619
|
+
return this;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
export class DeleteAst extends QueryAst {
|
|
1624
|
+
readonly kind = 'delete' as const;
|
|
1625
|
+
readonly table: TableSource;
|
|
1626
|
+
readonly where: AnyExpression | undefined;
|
|
1627
|
+
readonly returning: ReadonlyArray<ColumnRef> | undefined;
|
|
1628
|
+
|
|
1629
|
+
constructor(table: TableSource, where?: AnyExpression, returning?: ReadonlyArray<ColumnRef>) {
|
|
1630
|
+
super();
|
|
1631
|
+
this.table = table;
|
|
1632
|
+
this.where = where;
|
|
1633
|
+
this.returning = returning && returning.length > 0 ? frozenArrayCopy(returning) : undefined;
|
|
1634
|
+
this.freeze();
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
static from(table: TableSource): DeleteAst {
|
|
1638
|
+
return new DeleteAst(table);
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
withWhere(where: AnyExpression | undefined): DeleteAst {
|
|
1642
|
+
return new DeleteAst(this.table, where, this.returning);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
withReturning(returning: ReadonlyArray<ColumnRef> | undefined): DeleteAst {
|
|
1646
|
+
return new DeleteAst(this.table, this.where, returning);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
override collectParamRefs(): ParamRef[] {
|
|
1650
|
+
return this.where?.collectParamRefs() ?? [];
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
override collectRefs(): PlanRefs {
|
|
1654
|
+
const tables = new Set<string>([this.table.name]);
|
|
1655
|
+
const columns = new Map<string, { table: string; column: string }>();
|
|
1656
|
+
|
|
1657
|
+
for (const columnRef of this.where?.collectColumnRefs() ?? []) {
|
|
1658
|
+
addColumnRefToRefSets(columnRef, tables, columns);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
for (const columnRef of this.returning ?? []) {
|
|
1662
|
+
addColumnRefToRefSets(columnRef, tables, columns);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
return sortRefs(tables, columns);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
override toQueryAst(): AnyQueryAst {
|
|
1669
|
+
return this;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
export type AnyQueryAst = SelectAst | InsertAst | UpdateAst | DeleteAst;
|
|
1674
|
+
export type AnyFromSource = TableSource | DerivedTableSource;
|
|
1675
|
+
export type AnyExpression =
|
|
1676
|
+
| ColumnRef
|
|
1677
|
+
| IdentifierRef
|
|
1678
|
+
| ParamRef
|
|
1679
|
+
| LiteralExpr
|
|
1680
|
+
| SubqueryExpr
|
|
1681
|
+
| OperationExpr
|
|
1682
|
+
| AggregateExpr
|
|
1683
|
+
| JsonObjectExpr
|
|
1684
|
+
| JsonArrayAggExpr
|
|
1685
|
+
| ListExpression
|
|
1686
|
+
| BinaryExpr
|
|
1687
|
+
| AndExpr
|
|
1688
|
+
| OrExpr
|
|
1689
|
+
| ExistsExpr
|
|
1690
|
+
| NullCheckExpr
|
|
1691
|
+
| NotExpr;
|
|
1692
|
+
export type AnyInsertOnConflictAction = DoNothingConflictAction | DoUpdateSetConflictAction;
|
|
1693
|
+
export type AnyInsertValue = ColumnRef | ParamRef | DefaultValueExpr;
|
|
1694
|
+
export type AnyOperationArg = AnyExpression | ParamRef | LiteralExpr;
|
|
1695
|
+
|
|
1696
|
+
export const queryAstKinds: ReadonlySet<string> = new Set<AnyQueryAst['kind']>([
|
|
1697
|
+
'select',
|
|
1698
|
+
'insert',
|
|
1699
|
+
'update',
|
|
1700
|
+
'delete',
|
|
1701
|
+
]);
|
|
1702
|
+
export const whereExprKinds: ReadonlySet<string> = new Set<AnyExpression['kind']>([
|
|
1703
|
+
'binary',
|
|
1704
|
+
'and',
|
|
1705
|
+
'or',
|
|
1706
|
+
'exists',
|
|
1707
|
+
'null-check',
|
|
1708
|
+
'not',
|
|
1709
|
+
]);
|
|
1710
|
+
|
|
1711
|
+
export function isQueryAst(value: unknown): value is AnyQueryAst {
|
|
1712
|
+
return (
|
|
1713
|
+
typeof value === 'object' &&
|
|
1714
|
+
value !== null &&
|
|
1715
|
+
'kind' in value &&
|
|
1716
|
+
queryAstKinds.has((value as { kind: string }).kind)
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
export function isWhereExpr(value: unknown): value is AnyExpression {
|
|
1721
|
+
return (
|
|
1722
|
+
typeof value === 'object' &&
|
|
1723
|
+
value !== null &&
|
|
1724
|
+
'kind' in value &&
|
|
1725
|
+
whereExprKinds.has((value as { kind: string }).kind)
|
|
1726
|
+
);
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
export interface ToWhereExpr {
|
|
1730
|
+
toWhereExpr(): AnyExpression;
|
|
1731
|
+
}
|
|
142
1732
|
|
|
143
1733
|
export interface LoweredStatement {
|
|
144
1734
|
readonly sql: string;
|