@prisma-next/sql-builder 0.0.1 → 0.3.0-dev.162
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/dist/db-C7A7Y4tB.d.mts +348 -0
- package/dist/db-C7A7Y4tB.d.mts.map +1 -0
- package/dist/exports/types.d.mts +2 -0
- package/dist/exports/types.mjs +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -0
- package/dist/runtime/index.d.mts +35 -0
- package/dist/runtime/index.d.mts.map +1 -0
- package/dist/runtime/index.mjs +765 -0
- package/dist/runtime/index.mjs.map +1 -0
- package/package.json +30 -36
- package/src/exports/types.ts +1 -1
- package/src/resolve.ts +17 -7
- package/src/runtime/builder-base.ts +2 -2
- package/src/runtime/functions.ts +5 -6
- package/src/runtime/index.ts +1 -0
- package/src/runtime/mutation-impl.ts +18 -6
- package/src/runtime/query-impl.ts +5 -2
- package/src/runtime/sql.ts +5 -4
- package/src/scope.ts +1 -0
- package/src/types/mutation-query.ts +3 -3
- package/src/types/shared.ts +1 -1
- package/src/types/table-proxy.ts +114 -11
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
import { AggregateExpr, AndExpr, BinaryExpr, ColumnRef, DeleteAst, DerivedTableSource, ExistsExpr, IdentifierRef, InsertAst, JoinAst, ListExpression, LiteralExpr, NullCheckExpr, OperationExpr, OrExpr, OrderByItem, ParamRef, ProjectionItem, SelectAst, SubqueryExpr, TableSource, UpdateAst } from "@prisma-next/sql-relational-core/ast";
|
|
2
|
+
|
|
3
|
+
//#region src/runtime/expression-impl.ts
|
|
4
|
+
/**
|
|
5
|
+
* Runtime wrapper around a relational-core AST expression node.
|
|
6
|
+
* Carries ScopeField metadata (codecId, nullable) for plan generation.
|
|
7
|
+
*/
|
|
8
|
+
var ExpressionImpl = class {
|
|
9
|
+
ast;
|
|
10
|
+
field;
|
|
11
|
+
constructor(ast, field) {
|
|
12
|
+
this.ast = ast;
|
|
13
|
+
this.field = field;
|
|
14
|
+
}
|
|
15
|
+
buildAst() {
|
|
16
|
+
return this.ast;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/runtime/field-proxy.ts
|
|
22
|
+
function createFieldProxy(scope) {
|
|
23
|
+
return new Proxy({}, { get(_target, prop) {
|
|
24
|
+
if (Object.hasOwn(scope.topLevel, prop)) {
|
|
25
|
+
const topField = scope.topLevel[prop];
|
|
26
|
+
if (topField) return new ExpressionImpl(IdentifierRef.of(prop), topField);
|
|
27
|
+
}
|
|
28
|
+
if (Object.hasOwn(scope.namespaces, prop)) {
|
|
29
|
+
const nsFields = scope.namespaces[prop];
|
|
30
|
+
if (nsFields) return createNamespaceProxy(prop, nsFields);
|
|
31
|
+
}
|
|
32
|
+
} });
|
|
33
|
+
}
|
|
34
|
+
function createNamespaceProxy(namespaceName, fields) {
|
|
35
|
+
return new Proxy({}, { get(_target, prop) {
|
|
36
|
+
if (Object.hasOwn(fields, prop)) {
|
|
37
|
+
const field = fields[prop];
|
|
38
|
+
if (field) return new ExpressionImpl(ColumnRef.of(namespaceName, prop), field);
|
|
39
|
+
}
|
|
40
|
+
} });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/runtime/functions.ts
|
|
45
|
+
const BOOL_FIELD = {
|
|
46
|
+
codecId: "pg/bool@1",
|
|
47
|
+
nullable: false
|
|
48
|
+
};
|
|
49
|
+
function resolve(value) {
|
|
50
|
+
if (value instanceof ExpressionImpl) return value.buildAst();
|
|
51
|
+
return ParamRef.of(value);
|
|
52
|
+
}
|
|
53
|
+
function resolveToAst(value) {
|
|
54
|
+
if (value instanceof ExpressionImpl) return value.buildAst();
|
|
55
|
+
return new LiteralExpr(value);
|
|
56
|
+
}
|
|
57
|
+
function boolExpr(astNode) {
|
|
58
|
+
return new ExpressionImpl(astNode, BOOL_FIELD);
|
|
59
|
+
}
|
|
60
|
+
function eq(a, b) {
|
|
61
|
+
if (b === null) return boolExpr(NullCheckExpr.isNull(resolve(a)));
|
|
62
|
+
if (a === null) return boolExpr(NullCheckExpr.isNull(resolve(b)));
|
|
63
|
+
return boolExpr(new BinaryExpr("eq", resolve(a), resolve(b)));
|
|
64
|
+
}
|
|
65
|
+
function ne(a, b) {
|
|
66
|
+
if (b === null) return boolExpr(NullCheckExpr.isNotNull(resolve(a)));
|
|
67
|
+
if (a === null) return boolExpr(NullCheckExpr.isNotNull(resolve(b)));
|
|
68
|
+
return boolExpr(new BinaryExpr("neq", resolve(a), resolve(b)));
|
|
69
|
+
}
|
|
70
|
+
function comparison(a, b, op) {
|
|
71
|
+
return boolExpr(new BinaryExpr(op, resolve(a), resolve(b)));
|
|
72
|
+
}
|
|
73
|
+
function inOrNotIn(expr, valuesOrSubquery, op) {
|
|
74
|
+
const left = expr.buildAst();
|
|
75
|
+
const binaryFn = op === "in" ? BinaryExpr.in : BinaryExpr.notIn;
|
|
76
|
+
if (Array.isArray(valuesOrSubquery)) {
|
|
77
|
+
const refs = valuesOrSubquery.map((v) => resolve(v));
|
|
78
|
+
return boolExpr(binaryFn(left, ListExpression.of(refs)));
|
|
79
|
+
}
|
|
80
|
+
return boolExpr(binaryFn(left, SubqueryExpr.of(valuesOrSubquery.buildAst())));
|
|
81
|
+
}
|
|
82
|
+
function numericAgg(fn, expr) {
|
|
83
|
+
return new ExpressionImpl(AggregateExpr[fn](expr.buildAst()), {
|
|
84
|
+
codecId: expr.field.codecId,
|
|
85
|
+
nullable: true
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function createBuiltinFunctions() {
|
|
89
|
+
return {
|
|
90
|
+
eq: (a, b) => eq(a, b),
|
|
91
|
+
ne: (a, b) => ne(a, b),
|
|
92
|
+
gt: (a, b) => comparison(a, b, "gt"),
|
|
93
|
+
gte: (a, b) => comparison(a, b, "gte"),
|
|
94
|
+
lt: (a, b) => comparison(a, b, "lt"),
|
|
95
|
+
lte: (a, b) => comparison(a, b, "lte"),
|
|
96
|
+
and: (...exprs) => boolExpr(AndExpr.of(exprs.map(resolveToAst))),
|
|
97
|
+
or: (...exprs) => boolExpr(OrExpr.of(exprs.map(resolveToAst))),
|
|
98
|
+
exists: (subquery) => boolExpr(ExistsExpr.exists(subquery.buildAst())),
|
|
99
|
+
notExists: (subquery) => boolExpr(ExistsExpr.notExists(subquery.buildAst())),
|
|
100
|
+
in: (expr, valuesOrSubquery) => inOrNotIn(expr, valuesOrSubquery, "in"),
|
|
101
|
+
notIn: (expr, valuesOrSubquery) => inOrNotIn(expr, valuesOrSubquery, "notIn")
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function createAggregateOnlyFunctions() {
|
|
105
|
+
return {
|
|
106
|
+
count: (expr) => {
|
|
107
|
+
const astExpr = expr ? expr.buildAst() : void 0;
|
|
108
|
+
return new ExpressionImpl(AggregateExpr.count(astExpr), {
|
|
109
|
+
codecId: "pg/int8@1",
|
|
110
|
+
nullable: false
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
sum: (expr) => numericAgg("sum", expr),
|
|
114
|
+
avg: (expr) => numericAgg("avg", expr),
|
|
115
|
+
min: (expr) => numericAgg("min", expr),
|
|
116
|
+
max: (expr) => numericAgg("max", expr)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function createExtensionFunction(name, entry) {
|
|
120
|
+
return (...args) => {
|
|
121
|
+
const resolvedArgs = args.map((arg, i) => {
|
|
122
|
+
if (arg instanceof ExpressionImpl) return arg.buildAst();
|
|
123
|
+
const codecId = entry.args[i]?.codecId;
|
|
124
|
+
return ParamRef.of(arg, codecId ? { codecId } : void 0);
|
|
125
|
+
});
|
|
126
|
+
const self = resolvedArgs[0];
|
|
127
|
+
const restArgs = resolvedArgs.slice(1);
|
|
128
|
+
return new ExpressionImpl(new OperationExpr({
|
|
129
|
+
method: name,
|
|
130
|
+
self,
|
|
131
|
+
args: restArgs.length > 0 ? restArgs : void 0,
|
|
132
|
+
returns: entry.returns,
|
|
133
|
+
lowering: entry.lowering
|
|
134
|
+
}), entry.returns);
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function createFunctions(queryOperationTypes) {
|
|
138
|
+
const builtins = createBuiltinFunctions();
|
|
139
|
+
return new Proxy({}, { get(_target, prop) {
|
|
140
|
+
const builtin = builtins[prop];
|
|
141
|
+
if (builtin) return builtin;
|
|
142
|
+
const extOp = queryOperationTypes[prop];
|
|
143
|
+
if (extOp) return createExtensionFunction(prop, extOp);
|
|
144
|
+
} });
|
|
145
|
+
}
|
|
146
|
+
function createAggregateFunctions(queryOperationTypes) {
|
|
147
|
+
const baseFns = createFunctions(queryOperationTypes);
|
|
148
|
+
const aggregates = createAggregateOnlyFunctions();
|
|
149
|
+
return new Proxy({}, { get(_target, prop) {
|
|
150
|
+
const agg = aggregates[prop];
|
|
151
|
+
if (agg) return agg;
|
|
152
|
+
return baseFns[prop];
|
|
153
|
+
} });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/runtime/builder-base.ts
|
|
158
|
+
var BuilderBase = class {
|
|
159
|
+
ctx;
|
|
160
|
+
constructor(ctx) {
|
|
161
|
+
this.ctx = ctx;
|
|
162
|
+
}
|
|
163
|
+
_gate(required, methodName, method) {
|
|
164
|
+
return ((...args) => {
|
|
165
|
+
assertCapability(this.ctx, required, methodName);
|
|
166
|
+
return method(...args);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
function emptyState(from, scope) {
|
|
171
|
+
return {
|
|
172
|
+
from,
|
|
173
|
+
joins: [],
|
|
174
|
+
projections: [],
|
|
175
|
+
where: [],
|
|
176
|
+
orderBy: [],
|
|
177
|
+
groupBy: [],
|
|
178
|
+
having: void 0,
|
|
179
|
+
limit: void 0,
|
|
180
|
+
offset: void 0,
|
|
181
|
+
distinct: void 0,
|
|
182
|
+
distinctOn: void 0,
|
|
183
|
+
scope,
|
|
184
|
+
rowFields: {}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function cloneState(state, overrides) {
|
|
188
|
+
return {
|
|
189
|
+
...state,
|
|
190
|
+
...overrides
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function combineWhereExprs(exprs) {
|
|
194
|
+
if (exprs.length === 0) return void 0;
|
|
195
|
+
if (exprs.length === 1) return exprs[0];
|
|
196
|
+
return AndExpr.of(exprs);
|
|
197
|
+
}
|
|
198
|
+
function buildSelectAst(state) {
|
|
199
|
+
const where = combineWhereExprs(state.where);
|
|
200
|
+
return new SelectAst({
|
|
201
|
+
from: state.from,
|
|
202
|
+
joins: state.joins.length > 0 ? state.joins : void 0,
|
|
203
|
+
projection: state.projections,
|
|
204
|
+
where,
|
|
205
|
+
orderBy: state.orderBy.length > 0 ? state.orderBy : void 0,
|
|
206
|
+
distinct: state.distinct,
|
|
207
|
+
distinctOn: state.distinctOn && state.distinctOn.length > 0 ? state.distinctOn : void 0,
|
|
208
|
+
groupBy: state.groupBy.length > 0 ? state.groupBy : void 0,
|
|
209
|
+
having: state.having,
|
|
210
|
+
limit: state.limit,
|
|
211
|
+
offset: state.offset,
|
|
212
|
+
selectAllIntent: void 0
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
function buildQueryPlan(ast, rowFields, ctx) {
|
|
216
|
+
const projectionTypes = {};
|
|
217
|
+
const codecs = {};
|
|
218
|
+
for (const [alias, field] of Object.entries(rowFields)) {
|
|
219
|
+
projectionTypes[alias] = field.codecId;
|
|
220
|
+
codecs[alias] = field.codecId;
|
|
221
|
+
}
|
|
222
|
+
const paramRefs = ast.collectParamRefs();
|
|
223
|
+
const seen = /* @__PURE__ */ new Set();
|
|
224
|
+
const uniqueRefs = [];
|
|
225
|
+
for (const ref of paramRefs) if (!seen.has(ref)) {
|
|
226
|
+
seen.add(ref);
|
|
227
|
+
uniqueRefs.push(ref);
|
|
228
|
+
}
|
|
229
|
+
const paramValues = uniqueRefs.map((r) => r.value);
|
|
230
|
+
const paramDescriptors = uniqueRefs.map((ref, i) => ({
|
|
231
|
+
index: i + 1,
|
|
232
|
+
source: "dsl",
|
|
233
|
+
...ref.codecId ? { codecId: ref.codecId } : {}
|
|
234
|
+
}));
|
|
235
|
+
for (const [i, ref] of uniqueRefs.entries()) if (ref.codecId) codecs[`$${i + 1}`] = ref.codecId;
|
|
236
|
+
const hasProjectionTypes = Object.keys(projectionTypes).length > 0;
|
|
237
|
+
const hasCodecs = Object.keys(codecs).length > 0;
|
|
238
|
+
const meta = Object.freeze({
|
|
239
|
+
target: ctx.target,
|
|
240
|
+
storageHash: ctx.storageHash,
|
|
241
|
+
lane: "dsl",
|
|
242
|
+
paramDescriptors,
|
|
243
|
+
...hasProjectionTypes ? { projectionTypes } : {},
|
|
244
|
+
...hasCodecs ? { annotations: Object.freeze({ codecs: Object.freeze(codecs) }) } : {}
|
|
245
|
+
});
|
|
246
|
+
return Object.freeze({
|
|
247
|
+
ast,
|
|
248
|
+
params: paramValues,
|
|
249
|
+
meta
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
function buildPlan(state, ctx) {
|
|
253
|
+
return buildQueryPlan(buildSelectAst(state), state.rowFields, ctx);
|
|
254
|
+
}
|
|
255
|
+
function tableToScope(name, table) {
|
|
256
|
+
const fields = {};
|
|
257
|
+
for (const [colName, col] of Object.entries(table.columns)) fields[colName] = {
|
|
258
|
+
codecId: col.codecId,
|
|
259
|
+
nullable: col.nullable
|
|
260
|
+
};
|
|
261
|
+
return {
|
|
262
|
+
topLevel: { ...fields },
|
|
263
|
+
namespaces: { [name]: fields }
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function mergeScopes(a, b) {
|
|
267
|
+
const topLevel = {};
|
|
268
|
+
for (const [k, v] of Object.entries(a.topLevel)) if (!(k in b.topLevel)) topLevel[k] = v;
|
|
269
|
+
for (const [k, v] of Object.entries(b.topLevel)) if (!(k in a.topLevel)) topLevel[k] = v;
|
|
270
|
+
return {
|
|
271
|
+
topLevel,
|
|
272
|
+
namespaces: {
|
|
273
|
+
...a.namespaces,
|
|
274
|
+
...b.namespaces
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function nullableScope(scope) {
|
|
279
|
+
const mkNullable = (tbl) => {
|
|
280
|
+
const result = {};
|
|
281
|
+
for (const [k, v] of Object.entries(tbl)) result[k] = {
|
|
282
|
+
codecId: v.codecId,
|
|
283
|
+
nullable: true
|
|
284
|
+
};
|
|
285
|
+
return result;
|
|
286
|
+
};
|
|
287
|
+
const namespaces = {};
|
|
288
|
+
for (const [k, v] of Object.entries(scope.namespaces)) namespaces[k] = mkNullable(v);
|
|
289
|
+
return {
|
|
290
|
+
topLevel: mkNullable(scope.topLevel),
|
|
291
|
+
namespaces
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function orderByScopeOf(scope, rowFields) {
|
|
295
|
+
return {
|
|
296
|
+
topLevel: {
|
|
297
|
+
...scope.topLevel,
|
|
298
|
+
...rowFields
|
|
299
|
+
},
|
|
300
|
+
namespaces: scope.namespaces
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function assertCapability(ctx, required, methodName) {
|
|
304
|
+
for (const [ns, keys] of Object.entries(required)) for (const key of Object.keys(keys)) if (!ctx.capabilities[ns]?.[key]) throw new Error(`${methodName}() requires capability ${ns}.${key}`);
|
|
305
|
+
}
|
|
306
|
+
function resolveSelectArgs(args, scope, ctx) {
|
|
307
|
+
const projections = [];
|
|
308
|
+
const newRowFields = {};
|
|
309
|
+
if (args.length === 0) return {
|
|
310
|
+
projections,
|
|
311
|
+
newRowFields
|
|
312
|
+
};
|
|
313
|
+
if (typeof args[0] === "string" && (args.length === 1 || typeof args[1] !== "function")) {
|
|
314
|
+
for (const colName of args) {
|
|
315
|
+
const field = scope.topLevel[colName];
|
|
316
|
+
if (!field) throw new Error(`Column "${colName}" not found in scope`);
|
|
317
|
+
projections.push(ProjectionItem.of(colName, IdentifierRef.of(colName)));
|
|
318
|
+
newRowFields[colName] = field;
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
projections,
|
|
322
|
+
newRowFields
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (typeof args[0] === "string" && typeof args[1] === "function") {
|
|
326
|
+
const alias = args[0];
|
|
327
|
+
const exprFn = args[1];
|
|
328
|
+
const fns = createAggregateFunctions(ctx.queryOperationTypes);
|
|
329
|
+
const result = exprFn(createFieldProxy(scope), fns);
|
|
330
|
+
projections.push(ProjectionItem.of(alias, result.buildAst()));
|
|
331
|
+
newRowFields[alias] = result.field;
|
|
332
|
+
return {
|
|
333
|
+
projections,
|
|
334
|
+
newRowFields
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
if (typeof args[0] === "function") {
|
|
338
|
+
const callbackFn = args[0];
|
|
339
|
+
const fns = createAggregateFunctions(ctx.queryOperationTypes);
|
|
340
|
+
const record = callbackFn(createFieldProxy(scope), fns);
|
|
341
|
+
for (const [key, expr] of Object.entries(record)) {
|
|
342
|
+
projections.push(ProjectionItem.of(key, expr.buildAst()));
|
|
343
|
+
newRowFields[key] = expr.field;
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
projections,
|
|
347
|
+
newRowFields
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
throw new Error("Invalid .select() arguments");
|
|
351
|
+
}
|
|
352
|
+
function resolveOrderBy(arg, options, scope, rowFields, ctx, useAggregateFns) {
|
|
353
|
+
const dir = options?.direction ?? "asc";
|
|
354
|
+
if (typeof arg === "string") {
|
|
355
|
+
if (!(arg in orderByScopeOf(scope, rowFields).topLevel)) throw new Error(`Column "${arg}" not found in scope for orderBy`);
|
|
356
|
+
const expr = IdentifierRef.of(arg);
|
|
357
|
+
return dir === "asc" ? OrderByItem.asc(expr) : OrderByItem.desc(expr);
|
|
358
|
+
}
|
|
359
|
+
if (typeof arg === "function") {
|
|
360
|
+
const combined = orderByScopeOf(scope, rowFields);
|
|
361
|
+
const fns = useAggregateFns ? createAggregateFunctions(ctx.queryOperationTypes) : createFunctions(ctx.queryOperationTypes);
|
|
362
|
+
const result = arg(createFieldProxy(combined), fns);
|
|
363
|
+
return dir === "asc" ? OrderByItem.asc(result.buildAst()) : OrderByItem.desc(result.buildAst());
|
|
364
|
+
}
|
|
365
|
+
throw new Error("Invalid orderBy argument");
|
|
366
|
+
}
|
|
367
|
+
function resolveGroupBy(args, scope, rowFields, ctx) {
|
|
368
|
+
if (typeof args[0] === "string") {
|
|
369
|
+
const combined = orderByScopeOf(scope, rowFields);
|
|
370
|
+
return args.map((colName) => {
|
|
371
|
+
if (!(colName in combined.topLevel)) throw new Error(`Column "${colName}" not found in scope for groupBy`);
|
|
372
|
+
return IdentifierRef.of(colName);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
if (typeof args[0] === "function") {
|
|
376
|
+
const combined = orderByScopeOf(scope, rowFields);
|
|
377
|
+
const fns = createFunctions(ctx.queryOperationTypes);
|
|
378
|
+
return [args[0](createFieldProxy(combined), fns).buildAst()];
|
|
379
|
+
}
|
|
380
|
+
throw new Error("Invalid groupBy arguments");
|
|
381
|
+
}
|
|
382
|
+
function resolveDistinctOn(args, scope, rowFields, ctx) {
|
|
383
|
+
if (args.length === 1 && typeof args[0] === "function") {
|
|
384
|
+
const combined$1 = orderByScopeOf(scope, rowFields);
|
|
385
|
+
const fns = createFunctions(ctx.queryOperationTypes);
|
|
386
|
+
return [args[0](createFieldProxy(combined$1), fns).buildAst()];
|
|
387
|
+
}
|
|
388
|
+
const combined = orderByScopeOf(scope, rowFields);
|
|
389
|
+
return args.map((colName) => {
|
|
390
|
+
if (!(colName in combined.topLevel)) throw new Error(`Column "${colName}" not found in scope for distinctOn`);
|
|
391
|
+
return IdentifierRef.of(colName);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/runtime/query-impl.ts
|
|
397
|
+
var QueryBase = class extends BuilderBase {
|
|
398
|
+
state;
|
|
399
|
+
constructor(state, ctx) {
|
|
400
|
+
super(ctx);
|
|
401
|
+
this.state = state;
|
|
402
|
+
}
|
|
403
|
+
distinctOn = this._gate({ postgres: { distinctOn: true } }, "distinctOn", (...args) => {
|
|
404
|
+
const exprs = resolveDistinctOn(args, this.state.scope, this.state.rowFields, this.ctx);
|
|
405
|
+
return this.clone(cloneState(this.state, { distinctOn: [...this.state.distinctOn ?? [], ...exprs] }));
|
|
406
|
+
});
|
|
407
|
+
limit(count) {
|
|
408
|
+
return this.clone(cloneState(this.state, { limit: count }));
|
|
409
|
+
}
|
|
410
|
+
offset(count) {
|
|
411
|
+
return this.clone(cloneState(this.state, { offset: count }));
|
|
412
|
+
}
|
|
413
|
+
distinct() {
|
|
414
|
+
return this.clone(cloneState(this.state, { distinct: true }));
|
|
415
|
+
}
|
|
416
|
+
groupBy(...args) {
|
|
417
|
+
const exprs = resolveGroupBy(args, this.state.scope, this.state.rowFields, this.ctx);
|
|
418
|
+
return new GroupedQueryImpl(cloneState(this.state, { groupBy: [...this.state.groupBy, ...exprs] }), this.ctx);
|
|
419
|
+
}
|
|
420
|
+
as(alias) {
|
|
421
|
+
const ast = buildSelectAst(this.state);
|
|
422
|
+
const derivedSource = DerivedTableSource.as(alias, ast);
|
|
423
|
+
const scope = {
|
|
424
|
+
topLevel: this.state.rowFields,
|
|
425
|
+
namespaces: { [alias]: this.state.rowFields }
|
|
426
|
+
};
|
|
427
|
+
return {
|
|
428
|
+
getJoinOuterScope: () => scope,
|
|
429
|
+
buildAst: () => derivedSource
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
getRowFields() {
|
|
433
|
+
return this.state.rowFields;
|
|
434
|
+
}
|
|
435
|
+
buildAst() {
|
|
436
|
+
return buildSelectAst(this.state);
|
|
437
|
+
}
|
|
438
|
+
build() {
|
|
439
|
+
return buildPlan(this.state, this.ctx);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
var SelectQueryImpl = class SelectQueryImpl extends QueryBase {
|
|
443
|
+
clone(state) {
|
|
444
|
+
return new SelectQueryImpl(state, this.ctx);
|
|
445
|
+
}
|
|
446
|
+
select(...args) {
|
|
447
|
+
const { projections, newRowFields } = resolveSelectArgs(args, this.state.scope, this.ctx);
|
|
448
|
+
return new SelectQueryImpl(cloneState(this.state, {
|
|
449
|
+
projections: [...this.state.projections, ...projections],
|
|
450
|
+
rowFields: {
|
|
451
|
+
...this.state.rowFields,
|
|
452
|
+
...newRowFields
|
|
453
|
+
}
|
|
454
|
+
}), this.ctx);
|
|
455
|
+
}
|
|
456
|
+
where(expr) {
|
|
457
|
+
const result = expr(createFieldProxy(this.state.scope), createFunctions(this.ctx.queryOperationTypes));
|
|
458
|
+
return new SelectQueryImpl(cloneState(this.state, { where: [...this.state.where, result.buildAst()] }), this.ctx);
|
|
459
|
+
}
|
|
460
|
+
orderBy(arg, options) {
|
|
461
|
+
const item = resolveOrderBy(arg, options, this.state.scope, this.state.rowFields, this.ctx, false);
|
|
462
|
+
return this.clone(cloneState(this.state, { orderBy: [...this.state.orderBy, item] }));
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
var GroupedQueryImpl = class GroupedQueryImpl extends QueryBase {
|
|
466
|
+
clone(state) {
|
|
467
|
+
return new GroupedQueryImpl(state, this.ctx);
|
|
468
|
+
}
|
|
469
|
+
having(expr) {
|
|
470
|
+
const combined = orderByScopeOf(this.state.scope, this.state.rowFields);
|
|
471
|
+
const fns = createAggregateFunctions(this.ctx.queryOperationTypes);
|
|
472
|
+
const result = expr(createFieldProxy(combined), fns);
|
|
473
|
+
return new GroupedQueryImpl(cloneState(this.state, { having: result.buildAst() }), this.ctx);
|
|
474
|
+
}
|
|
475
|
+
orderBy(arg, options) {
|
|
476
|
+
const item = resolveOrderBy(arg, options, this.state.scope, this.state.rowFields, this.ctx, true);
|
|
477
|
+
return this.clone(cloneState(this.state, { orderBy: [...this.state.orderBy, item] }));
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region src/runtime/joined-tables-impl.ts
|
|
483
|
+
var JoinedTablesImpl = class JoinedTablesImpl extends BuilderBase {
|
|
484
|
+
#state;
|
|
485
|
+
constructor(state, ctx) {
|
|
486
|
+
super(ctx);
|
|
487
|
+
this.#state = state;
|
|
488
|
+
}
|
|
489
|
+
lateralJoin = this._gate({ sql: { lateral: true } }, "lateralJoin", (alias, builder) => {
|
|
490
|
+
const { derivedSource, lateralScope } = this.#buildLateral(alias, builder);
|
|
491
|
+
const resultScope = mergeScopes(this.#state.scope, lateralScope);
|
|
492
|
+
return this.#addLateralJoin("inner", resultScope, derivedSource);
|
|
493
|
+
});
|
|
494
|
+
outerLateralJoin = this._gate({ sql: { lateral: true } }, "outerLateralJoin", (alias, builder) => {
|
|
495
|
+
const { derivedSource, lateralScope } = this.#buildLateral(alias, builder);
|
|
496
|
+
const resultScope = mergeScopes(this.#state.scope, nullableScope(lateralScope));
|
|
497
|
+
return this.#addLateralJoin("left", resultScope, derivedSource);
|
|
498
|
+
});
|
|
499
|
+
select(...args) {
|
|
500
|
+
const { projections, newRowFields } = resolveSelectArgs(args, this.#state.scope, this.ctx);
|
|
501
|
+
return new SelectQueryImpl(cloneState(this.#state, {
|
|
502
|
+
projections: [...this.#state.projections, ...projections],
|
|
503
|
+
rowFields: {
|
|
504
|
+
...this.#state.rowFields,
|
|
505
|
+
...newRowFields
|
|
506
|
+
}
|
|
507
|
+
}), this.ctx);
|
|
508
|
+
}
|
|
509
|
+
innerJoin(other, on) {
|
|
510
|
+
const targetScope = mergeScopes(this.#state.scope, other.getJoinOuterScope());
|
|
511
|
+
return this.#addJoin(other, "inner", targetScope, on);
|
|
512
|
+
}
|
|
513
|
+
outerLeftJoin(other, on) {
|
|
514
|
+
const targetScope = mergeScopes(this.#state.scope, nullableScope(other.getJoinOuterScope()));
|
|
515
|
+
return this.#addJoin(other, "left", targetScope, on);
|
|
516
|
+
}
|
|
517
|
+
outerRightJoin(other, on) {
|
|
518
|
+
const targetScope = mergeScopes(nullableScope(this.#state.scope), other.getJoinOuterScope());
|
|
519
|
+
return this.#addJoin(other, "right", targetScope, on);
|
|
520
|
+
}
|
|
521
|
+
outerFullJoin(other, on) {
|
|
522
|
+
const targetScope = mergeScopes(nullableScope(this.#state.scope), nullableScope(other.getJoinOuterScope()));
|
|
523
|
+
return this.#addJoin(other, "full", targetScope, on);
|
|
524
|
+
}
|
|
525
|
+
#addJoin(other, joinType, resultScope, onExpr) {
|
|
526
|
+
const onResult = onExpr(createFieldProxy(mergeScopes(this.#state.scope, other.getJoinOuterScope())), createFunctions(this.ctx.queryOperationTypes));
|
|
527
|
+
const joinAst = new JoinAst(joinType, other.buildAst(), onResult.buildAst());
|
|
528
|
+
return new JoinedTablesImpl(cloneState(this.#state, {
|
|
529
|
+
joins: [...this.#state.joins, joinAst],
|
|
530
|
+
scope: resultScope
|
|
531
|
+
}), this.ctx);
|
|
532
|
+
}
|
|
533
|
+
#buildLateral(alias, builderFn) {
|
|
534
|
+
const subquery = builderFn({ from: (other) => {
|
|
535
|
+
const otherScope = other.getJoinOuterScope();
|
|
536
|
+
const parentMerged = mergeScopes(this.#state.scope, otherScope);
|
|
537
|
+
return new SelectQueryImpl(emptyState(other.buildAst(), parentMerged), this.ctx);
|
|
538
|
+
} });
|
|
539
|
+
const subqueryAst = subquery.buildAst();
|
|
540
|
+
const derivedSource = DerivedTableSource.as(alias, subqueryAst);
|
|
541
|
+
const subqueryRowFields = subquery.getRowFields();
|
|
542
|
+
return {
|
|
543
|
+
derivedSource,
|
|
544
|
+
lateralScope: {
|
|
545
|
+
topLevel: subqueryRowFields,
|
|
546
|
+
namespaces: { [alias]: subqueryRowFields }
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
#addLateralJoin(joinType, resultScope, derivedSource) {
|
|
551
|
+
const joinAst = new JoinAst(joinType, derivedSource, AndExpr.of([]), true);
|
|
552
|
+
return new JoinedTablesImpl(cloneState(this.#state, {
|
|
553
|
+
joins: [...this.#state.joins, joinAst],
|
|
554
|
+
scope: resultScope
|
|
555
|
+
}), this.ctx);
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
//#endregion
|
|
560
|
+
//#region src/runtime/mutation-impl.ts
|
|
561
|
+
function buildParamValues(values, table, tableName, op, ctx) {
|
|
562
|
+
const params = {};
|
|
563
|
+
for (const [col, value] of Object.entries(values)) {
|
|
564
|
+
const column = table.columns[col];
|
|
565
|
+
params[col] = ParamRef.of(value, column ? { codecId: column.codecId } : void 0);
|
|
566
|
+
}
|
|
567
|
+
for (const def of ctx.applyMutationDefaults({
|
|
568
|
+
op,
|
|
569
|
+
table: tableName,
|
|
570
|
+
values
|
|
571
|
+
})) {
|
|
572
|
+
const column = table.columns[def.column];
|
|
573
|
+
params[def.column] = ParamRef.of(def.value, column ? { codecId: column.codecId } : void 0);
|
|
574
|
+
}
|
|
575
|
+
return params;
|
|
576
|
+
}
|
|
577
|
+
function buildReturningColumnRefs(tableName, columns) {
|
|
578
|
+
return columns.map((col) => ColumnRef.of(tableName, col));
|
|
579
|
+
}
|
|
580
|
+
function evaluateWhere(whereCallback, scope, queryOperationTypes) {
|
|
581
|
+
return whereCallback(createFieldProxy(scope), createFunctions(queryOperationTypes)).buildAst();
|
|
582
|
+
}
|
|
583
|
+
var InsertQueryImpl = class InsertQueryImpl extends BuilderBase {
|
|
584
|
+
#tableName;
|
|
585
|
+
#table;
|
|
586
|
+
#scope;
|
|
587
|
+
#values;
|
|
588
|
+
#returningColumns;
|
|
589
|
+
#rowFields;
|
|
590
|
+
constructor(tableName, table, scope, values, ctx, returningColumns = [], rowFields = {}) {
|
|
591
|
+
super(ctx);
|
|
592
|
+
this.#tableName = tableName;
|
|
593
|
+
this.#table = table;
|
|
594
|
+
this.#scope = scope;
|
|
595
|
+
this.#values = values;
|
|
596
|
+
this.#returningColumns = returningColumns;
|
|
597
|
+
this.#rowFields = rowFields;
|
|
598
|
+
}
|
|
599
|
+
returning = this._gate({ sql: { returning: true } }, "returning", (...columns) => {
|
|
600
|
+
const newRowFields = {};
|
|
601
|
+
for (const col of columns) {
|
|
602
|
+
const field = this.#scope.topLevel[col];
|
|
603
|
+
if (!field) throw new Error(`Column "${col}" not found in scope`);
|
|
604
|
+
newRowFields[col] = field;
|
|
605
|
+
}
|
|
606
|
+
return new InsertQueryImpl(this.#tableName, this.#table, this.#scope, this.#values, this.ctx, columns, newRowFields);
|
|
607
|
+
});
|
|
608
|
+
build() {
|
|
609
|
+
const paramValues = buildParamValues(this.#values, this.#table, this.#tableName, "create", this.ctx);
|
|
610
|
+
let ast = InsertAst.into(TableSource.named(this.#tableName)).withValues(paramValues);
|
|
611
|
+
if (this.#returningColumns.length > 0) ast = ast.withReturning(buildReturningColumnRefs(this.#tableName, this.#returningColumns));
|
|
612
|
+
return buildQueryPlan(ast, this.#rowFields, this.ctx);
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
var UpdateQueryImpl = class UpdateQueryImpl extends BuilderBase {
|
|
616
|
+
#tableName;
|
|
617
|
+
#table;
|
|
618
|
+
#scope;
|
|
619
|
+
#setValues;
|
|
620
|
+
#whereCallbacks;
|
|
621
|
+
#returningColumns;
|
|
622
|
+
#rowFields;
|
|
623
|
+
constructor(tableName, table, scope, setValues, ctx, whereCallbacks = [], returningColumns = [], rowFields = {}) {
|
|
624
|
+
super(ctx);
|
|
625
|
+
this.#tableName = tableName;
|
|
626
|
+
this.#table = table;
|
|
627
|
+
this.#scope = scope;
|
|
628
|
+
this.#setValues = setValues;
|
|
629
|
+
this.#whereCallbacks = whereCallbacks;
|
|
630
|
+
this.#returningColumns = returningColumns;
|
|
631
|
+
this.#rowFields = rowFields;
|
|
632
|
+
}
|
|
633
|
+
where(expr) {
|
|
634
|
+
return new UpdateQueryImpl(this.#tableName, this.#table, this.#scope, this.#setValues, this.ctx, [...this.#whereCallbacks, expr], this.#returningColumns, this.#rowFields);
|
|
635
|
+
}
|
|
636
|
+
returning = this._gate({ sql: { returning: true } }, "returning", (...columns) => {
|
|
637
|
+
const newRowFields = {};
|
|
638
|
+
for (const col of columns) {
|
|
639
|
+
const field = this.#scope.topLevel[col];
|
|
640
|
+
if (!field) throw new Error(`Column "${col}" not found in scope`);
|
|
641
|
+
newRowFields[col] = field;
|
|
642
|
+
}
|
|
643
|
+
return new UpdateQueryImpl(this.#tableName, this.#table, this.#scope, this.#setValues, this.ctx, this.#whereCallbacks, columns, newRowFields);
|
|
644
|
+
});
|
|
645
|
+
build() {
|
|
646
|
+
const setParams = buildParamValues(this.#setValues, this.#table, this.#tableName, "update", this.ctx);
|
|
647
|
+
const whereExpr = combineWhereExprs(this.#whereCallbacks.map((cb) => evaluateWhere(cb, this.#scope, this.ctx.queryOperationTypes)));
|
|
648
|
+
let ast = UpdateAst.table(TableSource.named(this.#tableName)).withSet(setParams).withWhere(whereExpr);
|
|
649
|
+
if (this.#returningColumns.length > 0) ast = ast.withReturning(buildReturningColumnRefs(this.#tableName, this.#returningColumns));
|
|
650
|
+
return buildQueryPlan(ast, this.#rowFields, this.ctx);
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
var DeleteQueryImpl = class DeleteQueryImpl extends BuilderBase {
|
|
654
|
+
#tableName;
|
|
655
|
+
#scope;
|
|
656
|
+
#whereCallbacks;
|
|
657
|
+
#returningColumns;
|
|
658
|
+
#rowFields;
|
|
659
|
+
constructor(tableName, scope, ctx, whereCallbacks = [], returningColumns = [], rowFields = {}) {
|
|
660
|
+
super(ctx);
|
|
661
|
+
this.#tableName = tableName;
|
|
662
|
+
this.#scope = scope;
|
|
663
|
+
this.#whereCallbacks = whereCallbacks;
|
|
664
|
+
this.#returningColumns = returningColumns;
|
|
665
|
+
this.#rowFields = rowFields;
|
|
666
|
+
}
|
|
667
|
+
where(expr) {
|
|
668
|
+
return new DeleteQueryImpl(this.#tableName, this.#scope, this.ctx, [...this.#whereCallbacks, expr], this.#returningColumns, this.#rowFields);
|
|
669
|
+
}
|
|
670
|
+
returning = this._gate({ sql: { returning: true } }, "returning", (...columns) => {
|
|
671
|
+
const newRowFields = {};
|
|
672
|
+
for (const col of columns) {
|
|
673
|
+
const field = this.#scope.topLevel[col];
|
|
674
|
+
if (!field) throw new Error(`Column "${col}" not found in scope`);
|
|
675
|
+
newRowFields[col] = field;
|
|
676
|
+
}
|
|
677
|
+
return new DeleteQueryImpl(this.#tableName, this.#scope, this.ctx, this.#whereCallbacks, columns, newRowFields);
|
|
678
|
+
});
|
|
679
|
+
build() {
|
|
680
|
+
const whereExpr = combineWhereExprs(this.#whereCallbacks.map((cb) => evaluateWhere(cb, this.#scope, this.ctx.queryOperationTypes)));
|
|
681
|
+
let ast = DeleteAst.from(TableSource.named(this.#tableName)).withWhere(whereExpr);
|
|
682
|
+
if (this.#returningColumns.length > 0) ast = ast.withReturning(buildReturningColumnRefs(this.#tableName, this.#returningColumns));
|
|
683
|
+
return buildQueryPlan(ast, this.#rowFields, this.ctx);
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
//#endregion
|
|
688
|
+
//#region src/runtime/table-proxy-impl.ts
|
|
689
|
+
var TableProxyImpl = class TableProxyImpl extends BuilderBase {
|
|
690
|
+
#tableName;
|
|
691
|
+
#table;
|
|
692
|
+
#fromSource;
|
|
693
|
+
#scope;
|
|
694
|
+
constructor(tableName, table, alias, ctx) {
|
|
695
|
+
super(ctx);
|
|
696
|
+
this.#tableName = tableName;
|
|
697
|
+
this.#table = table;
|
|
698
|
+
this.#scope = tableToScope(alias, table);
|
|
699
|
+
this.#fromSource = TableSource.named(tableName, alias !== tableName ? alias : void 0);
|
|
700
|
+
}
|
|
701
|
+
lateralJoin = this._gate({ sql: { lateral: true } }, "lateralJoin", (alias, builder) => {
|
|
702
|
+
return this.#toJoined().lateralJoin(alias, builder);
|
|
703
|
+
});
|
|
704
|
+
outerLateralJoin = this._gate({ sql: { lateral: true } }, "outerLateralJoin", (alias, builder) => {
|
|
705
|
+
return this.#toJoined().outerLateralJoin(alias, builder);
|
|
706
|
+
});
|
|
707
|
+
getJoinOuterScope() {
|
|
708
|
+
return this.#scope;
|
|
709
|
+
}
|
|
710
|
+
buildAst() {
|
|
711
|
+
return this.#fromSource;
|
|
712
|
+
}
|
|
713
|
+
as(newAlias) {
|
|
714
|
+
return new TableProxyImpl(this.#tableName, this.#table, newAlias, this.ctx);
|
|
715
|
+
}
|
|
716
|
+
select(...args) {
|
|
717
|
+
return new SelectQueryImpl(emptyState(this.#fromSource, this.#scope), this.ctx).select(...args);
|
|
718
|
+
}
|
|
719
|
+
innerJoin(other, on) {
|
|
720
|
+
return this.#toJoined().innerJoin(other, on);
|
|
721
|
+
}
|
|
722
|
+
outerLeftJoin(other, on) {
|
|
723
|
+
return this.#toJoined().outerLeftJoin(other, on);
|
|
724
|
+
}
|
|
725
|
+
outerRightJoin(other, on) {
|
|
726
|
+
return this.#toJoined().outerRightJoin(other, on);
|
|
727
|
+
}
|
|
728
|
+
outerFullJoin(other, on) {
|
|
729
|
+
return this.#toJoined().outerFullJoin(other, on);
|
|
730
|
+
}
|
|
731
|
+
insert(values) {
|
|
732
|
+
return new InsertQueryImpl(this.#tableName, this.#table, this.#scope, values, this.ctx);
|
|
733
|
+
}
|
|
734
|
+
update(set) {
|
|
735
|
+
return new UpdateQueryImpl(this.#tableName, this.#table, this.#scope, set, this.ctx);
|
|
736
|
+
}
|
|
737
|
+
delete() {
|
|
738
|
+
return new DeleteQueryImpl(this.#tableName, this.#scope, this.ctx);
|
|
739
|
+
}
|
|
740
|
+
#toJoined() {
|
|
741
|
+
return new JoinedTablesImpl(emptyState(this.#fromSource, this.#scope), this.ctx);
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/runtime/sql.ts
|
|
747
|
+
function sql(options) {
|
|
748
|
+
const { context } = options;
|
|
749
|
+
const ctx = {
|
|
750
|
+
capabilities: context.contract.capabilities,
|
|
751
|
+
queryOperationTypes: context.queryOperations.entries(),
|
|
752
|
+
target: context.contract.target ?? "unknown",
|
|
753
|
+
storageHash: context.contract.storage.storageHash ?? "unknown",
|
|
754
|
+
applyMutationDefaults: (options$1) => context.applyMutationDefaults(options$1)
|
|
755
|
+
};
|
|
756
|
+
return new Proxy({}, { get(_target, prop) {
|
|
757
|
+
const tables = context.contract.storage.tables;
|
|
758
|
+
const table = Object.hasOwn(tables, prop) ? tables[prop] : void 0;
|
|
759
|
+
if (table) return new TableProxyImpl(prop, table, prop, ctx);
|
|
760
|
+
} });
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
//#endregion
|
|
764
|
+
export { ExpressionImpl, createAggregateFunctions, createFieldProxy, createFunctions, sql };
|
|
765
|
+
//# sourceMappingURL=index.mjs.map
|