@prisma-next/sql-builder 0.0.1 → 0.3.0-dev.128

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