@prisma-next/sql-lane 0.3.0-pr.93.4 → 0.3.0-pr.94.1
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/dist/builder-C87NiJaP.mjs +1175 -0
- package/dist/builder-C87NiJaP.mjs.map +1 -0
- package/dist/builder-C8ExdG4j.d.mts +121 -0
- package/dist/builder-C8ExdG4j.d.mts.map +1 -0
- package/dist/exports/sql.d.mts +3 -0
- package/dist/exports/sql.mjs +3 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +3 -0
- package/package.json +20 -18
- package/src/sql/include-builder.ts +1 -1
- package/src/sql/plan.ts +102 -101
- package/src/sql/predicate-builder.ts +41 -44
- package/src/sql/projection.ts +15 -10
- package/src/sql/select-builder.ts +16 -35
- package/src/types/internal.ts +2 -2
- package/src/utils/errors.ts +1 -1
- package/src/utils/state.ts +2 -4
- package/dist/chunk-AWSKRSFP.js +0 -1569
- package/dist/chunk-AWSKRSFP.js.map +0 -1
- package/dist/exports/sql.d.ts +0 -5
- package/dist/exports/sql.d.ts.map +0 -1
- package/dist/exports/sql.js +0 -11
- package/dist/exports/sql.js.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -11
- package/dist/index.js.map +0 -1
- package/dist/raw.d.ts +0 -11
- package/dist/raw.d.ts.map +0 -1
- package/dist/sql/builder.d.ts +0 -11
- package/dist/sql/builder.d.ts.map +0 -1
- package/dist/sql/context.d.ts +0 -5
- package/dist/sql/context.d.ts.map +0 -1
- package/dist/sql/include-builder.d.ts +0 -35
- package/dist/sql/include-builder.d.ts.map +0 -1
- package/dist/sql/join-builder.d.ts +0 -4
- package/dist/sql/join-builder.d.ts.map +0 -1
- package/dist/sql/mutation-builder.d.ts +0 -64
- package/dist/sql/mutation-builder.d.ts.map +0 -1
- package/dist/sql/plan.d.ts +0 -4
- package/dist/sql/plan.d.ts.map +0 -1
- package/dist/sql/predicate-builder.d.ts +0 -11
- package/dist/sql/predicate-builder.d.ts.map +0 -1
- package/dist/sql/projection.d.ts +0 -18
- package/dist/sql/projection.d.ts.map +0 -1
- package/dist/sql/select-builder.d.ts +0 -35
- package/dist/sql/select-builder.d.ts.map +0 -1
- package/dist/types/internal.d.ts +0 -35
- package/dist/types/internal.d.ts.map +0 -1
- package/dist/types/public.d.ts +0 -18
- package/dist/types/public.d.ts.map +0 -1
- package/dist/utils/assertions.d.ts +0 -28
- package/dist/utils/assertions.d.ts.map +0 -1
- package/dist/utils/capabilities.d.ts +0 -4
- package/dist/utils/capabilities.d.ts.map +0 -1
- package/dist/utils/errors.d.ts +0 -30
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/state.d.ts +0 -30
- package/dist/utils/state.d.ts.map +0 -1
|
@@ -0,0 +1,1175 @@
|
|
|
1
|
+
import { planInvalid } from "@prisma-next/plan";
|
|
2
|
+
import { compact, createBinaryExpr, createColumnRef, createDeleteAst, createInsertAst, createJoin, createJoinOnBuilder, createJoinOnBuilder as createJoinOnBuilder$1, createJoinOnExpr, createOrderByItem, createParamRef, createSelectAst, createTableRef, createUpdateAst } from "@prisma-next/sql-relational-core/ast";
|
|
3
|
+
import { collectColumnRefs, extractBaseColumnRef, isColumnBuilder, isExpressionBuilder, isExpressionSource, isOperationExpr, isParamPlaceholder } from "@prisma-next/sql-relational-core/utils/guards";
|
|
4
|
+
|
|
5
|
+
//#region src/raw.ts
|
|
6
|
+
const RAW_OPTIONS_SENTINEL = Symbol("rawOptions");
|
|
7
|
+
function createRawFactory(contract) {
|
|
8
|
+
const factory = ((first, ...rest) => {
|
|
9
|
+
if (isTemplateInvocation(first)) {
|
|
10
|
+
const { values, options: options$1 } = splitTemplateValues(rest);
|
|
11
|
+
const compiled = compileTemplateToPositional(first, values);
|
|
12
|
+
return buildRawPlan({
|
|
13
|
+
contract,
|
|
14
|
+
sql: compiled.sql,
|
|
15
|
+
params: compiled.params,
|
|
16
|
+
paramDescriptors: compiled.paramDescriptors,
|
|
17
|
+
...options$1 ? { options: options$1 } : {}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const text = first;
|
|
21
|
+
const [options] = rest;
|
|
22
|
+
if (!options) throw planInvalid("Function form requires params option");
|
|
23
|
+
if (!Array.isArray(options.params)) throw planInvalid("Function form params must be an array");
|
|
24
|
+
const paramDescriptors = buildSequentialDescriptors(options.params.length);
|
|
25
|
+
return buildRawPlan({
|
|
26
|
+
contract,
|
|
27
|
+
sql: text,
|
|
28
|
+
params: options.params,
|
|
29
|
+
paramDescriptors,
|
|
30
|
+
options
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
factory.with = (options) => {
|
|
34
|
+
return ((strings, ...values) => {
|
|
35
|
+
const compiled = compileTemplateToPositional(strings, values);
|
|
36
|
+
return buildRawPlan({
|
|
37
|
+
contract,
|
|
38
|
+
sql: compiled.sql,
|
|
39
|
+
params: compiled.params,
|
|
40
|
+
paramDescriptors: compiled.paramDescriptors,
|
|
41
|
+
options
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
return factory;
|
|
46
|
+
}
|
|
47
|
+
function compileTemplateToPositional(strings, values) {
|
|
48
|
+
let sql$1 = "";
|
|
49
|
+
const params = [];
|
|
50
|
+
const paramDescriptors = [];
|
|
51
|
+
strings.forEach((part, index) => {
|
|
52
|
+
sql$1 += part;
|
|
53
|
+
if (index < values.length) {
|
|
54
|
+
const value = values[index];
|
|
55
|
+
const placeholderIndex = params.push(value);
|
|
56
|
+
sql$1 += `$${placeholderIndex}`;
|
|
57
|
+
paramDescriptors.push({
|
|
58
|
+
index: placeholderIndex,
|
|
59
|
+
name: `p${placeholderIndex}`,
|
|
60
|
+
source: "raw"
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
sql: sql$1,
|
|
66
|
+
params,
|
|
67
|
+
paramDescriptors
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function buildRawPlan(args) {
|
|
71
|
+
const params = Array.from(args.params);
|
|
72
|
+
const descriptors = args.paramDescriptors.map((descriptor) => Object.freeze({
|
|
73
|
+
...descriptor,
|
|
74
|
+
source: "raw"
|
|
75
|
+
}));
|
|
76
|
+
const meta = buildRawMeta({
|
|
77
|
+
contract: args.contract,
|
|
78
|
+
paramDescriptors: descriptors,
|
|
79
|
+
...args.options ? { options: args.options } : {}
|
|
80
|
+
});
|
|
81
|
+
return Object.freeze({
|
|
82
|
+
sql: args.sql,
|
|
83
|
+
params: Object.freeze(params),
|
|
84
|
+
meta
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function buildRawMeta(args) {
|
|
88
|
+
const { contract, paramDescriptors, options } = args;
|
|
89
|
+
const meta = {
|
|
90
|
+
target: contract.target,
|
|
91
|
+
targetFamily: contract.targetFamily,
|
|
92
|
+
coreHash: contract.coreHash,
|
|
93
|
+
...contract.profileHash !== void 0 ? { profileHash: contract.profileHash } : {},
|
|
94
|
+
lane: "raw",
|
|
95
|
+
paramDescriptors: Object.freeze([...paramDescriptors]),
|
|
96
|
+
...options?.annotations ? { annotations: Object.freeze({ ...options.annotations }) } : {},
|
|
97
|
+
...options?.refs ? { refs: freezeRefs(options.refs) } : {},
|
|
98
|
+
...options?.projection ? { projection: Object.freeze([...options.projection]) } : {}
|
|
99
|
+
};
|
|
100
|
+
return Object.freeze(meta);
|
|
101
|
+
}
|
|
102
|
+
function freezeRefs(refs) {
|
|
103
|
+
return Object.freeze({
|
|
104
|
+
...refs.tables ? { tables: Object.freeze([...refs.tables]) } : {},
|
|
105
|
+
...refs.columns ? { columns: Object.freeze(refs.columns.map((col) => Object.freeze({ ...col }))) } : {},
|
|
106
|
+
...refs.indexes ? { indexes: Object.freeze(refs.indexes.map((index) => Object.freeze({
|
|
107
|
+
...index,
|
|
108
|
+
columns: Object.freeze([...index.columns])
|
|
109
|
+
}))) } : {}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function buildSequentialDescriptors(count) {
|
|
113
|
+
return Array.from({ length: count }, (_, idx) => Object.freeze({
|
|
114
|
+
index: idx + 1,
|
|
115
|
+
name: `p${idx + 1}`,
|
|
116
|
+
source: "raw"
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
function isTemplateInvocation(value) {
|
|
120
|
+
return Array.isArray(value) && Object.hasOwn(value, "raw");
|
|
121
|
+
}
|
|
122
|
+
function rawOptions(options) {
|
|
123
|
+
return Object.freeze({
|
|
124
|
+
[RAW_OPTIONS_SENTINEL]: true,
|
|
125
|
+
value: options
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function splitTemplateValues(values) {
|
|
129
|
+
if (values.length === 0) return { values };
|
|
130
|
+
const last = values[values.length - 1];
|
|
131
|
+
if (!isOptionsSentinel(last)) return { values };
|
|
132
|
+
return {
|
|
133
|
+
values: values.slice(0, values.length - 1),
|
|
134
|
+
options: last.value
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function isOptionsSentinel(value) {
|
|
138
|
+
return typeof value === "object" && value !== null && RAW_OPTIONS_SENTINEL in value;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/utils/errors.ts
|
|
143
|
+
function errorAliasPathEmpty() {
|
|
144
|
+
throw planInvalid("Alias path cannot be empty");
|
|
145
|
+
}
|
|
146
|
+
function errorAliasCollision(path, alias, existingPath) {
|
|
147
|
+
throw planInvalid(`Alias collision: path ${path.join(".")} would generate alias "${alias}" which conflicts with path ${existingPath?.join(".") ?? "unknown"}`);
|
|
148
|
+
}
|
|
149
|
+
function errorLimitMustBeNonNegativeInteger() {
|
|
150
|
+
throw planInvalid("Limit must be a non-negative integer");
|
|
151
|
+
}
|
|
152
|
+
function errorChildProjectionMustBeSpecified() {
|
|
153
|
+
throw planInvalid("Child projection must be specified");
|
|
154
|
+
}
|
|
155
|
+
function errorIncludeRequiresCapabilities(target) {
|
|
156
|
+
throw planInvalid("includeMany requires lateral and jsonAgg capabilities", target ? { target } : void 0, [
|
|
157
|
+
"Enable capabilities for your target in contract.capabilities[target]",
|
|
158
|
+
"For SQL includes, set both 'lateral' and 'jsonAgg' to true",
|
|
159
|
+
"If your database lacks lateral/json_agg, use explicit joins + group aggregates"
|
|
160
|
+
], [
|
|
161
|
+
"docs/Architecture Overview.md",
|
|
162
|
+
"docs/reference/extensions-glossary.md",
|
|
163
|
+
"packages/3-targets/6-adapters/postgres/README.md"
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
166
|
+
function errorIncludeCapabilitiesNotTrue(target, values) {
|
|
167
|
+
throw planInvalid("includeMany requires lateral and jsonAgg capabilities to be true", target ? {
|
|
168
|
+
target,
|
|
169
|
+
values
|
|
170
|
+
} : void 0, ["Set contract.capabilities[target].lateral = true and .jsonAgg = true", "If the target does not support these, avoid includeMany and compose a two-step plan"], [
|
|
171
|
+
"docs/Architecture Overview.md",
|
|
172
|
+
"docs/reference/extensions-glossary.md",
|
|
173
|
+
"packages/3-targets/6-adapters/postgres/README.md"
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
176
|
+
function errorUnknownTable(tableName) {
|
|
177
|
+
throw planInvalid(`Unknown table ${tableName}`);
|
|
178
|
+
}
|
|
179
|
+
function errorSelfJoinNotSupported() {
|
|
180
|
+
throw planInvalid("Self-joins are not supported in MVP");
|
|
181
|
+
}
|
|
182
|
+
function errorChildProjectionEmpty() {
|
|
183
|
+
throw planInvalid("Child projection must not be empty");
|
|
184
|
+
}
|
|
185
|
+
function errorIncludeAliasCollision(alias, type) {
|
|
186
|
+
throw planInvalid(`Alias collision: include alias "${alias}" conflicts with existing ${type} alias`);
|
|
187
|
+
}
|
|
188
|
+
function errorMissingColumnForAlias(alias, index) {
|
|
189
|
+
throw planInvalid(`Missing column for alias ${alias ?? "unknown"} at index ${index}`);
|
|
190
|
+
}
|
|
191
|
+
function errorMissingAlias(index) {
|
|
192
|
+
throw planInvalid(`Missing alias at index ${index}`);
|
|
193
|
+
}
|
|
194
|
+
function errorFromMustBeCalled() {
|
|
195
|
+
throw planInvalid("from() must be called before building a query");
|
|
196
|
+
}
|
|
197
|
+
function errorSelectMustBeCalled() {
|
|
198
|
+
throw planInvalid("select() must be called before build()");
|
|
199
|
+
}
|
|
200
|
+
function errorMissingParameter(paramName) {
|
|
201
|
+
throw planInvalid(`Missing value for parameter ${paramName}`);
|
|
202
|
+
}
|
|
203
|
+
function errorInvalidProjectionValue(path) {
|
|
204
|
+
throw planInvalid(`Invalid projection value at path ${path.join(".")}: expected ExpressionSource (ColumnBuilder or ExpressionBuilder) or nested object`);
|
|
205
|
+
}
|
|
206
|
+
function errorIncludeAliasNotFound(alias) {
|
|
207
|
+
throw planInvalid(`Include alias "${alias}" not found. Did you call includeMany() with alias "${alias}"?`);
|
|
208
|
+
}
|
|
209
|
+
function errorInvalidProjectionKey(key) {
|
|
210
|
+
throw planInvalid(`Invalid projection value at key "${key}": expected ColumnBuilder, boolean true (for includes), or nested object`);
|
|
211
|
+
}
|
|
212
|
+
function errorProjectionEmpty() {
|
|
213
|
+
throw planInvalid("select() requires at least one column or include");
|
|
214
|
+
}
|
|
215
|
+
function errorReturningRequiresCapability(target) {
|
|
216
|
+
throw planInvalid("returning() requires returning capability", target ? { target } : void 0, [
|
|
217
|
+
"Enable 'returning' for your target in contract.capabilities[target]",
|
|
218
|
+
"PostgreSQL supports RETURNING; MySQL does not",
|
|
219
|
+
"If unsupported, remove returning() and fetch with a follow-up select()"
|
|
220
|
+
], [
|
|
221
|
+
"docs/Architecture Overview.md",
|
|
222
|
+
"docs/reference/extensions-glossary.md",
|
|
223
|
+
"packages/3-targets/6-adapters/postgres/README.md"
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
function errorReturningCapabilityNotTrue(target, value) {
|
|
227
|
+
throw planInvalid("returning() requires returning capability to be true", target ? {
|
|
228
|
+
target,
|
|
229
|
+
value
|
|
230
|
+
} : void 0, ["Set contract.capabilities[target].returning = true", "If your database/adapter cannot support RETURNING, remove returning() and select after"], [
|
|
231
|
+
"docs/Architecture Overview.md",
|
|
232
|
+
"docs/reference/extensions-glossary.md",
|
|
233
|
+
"packages/3-targets/6-adapters/postgres/README.md"
|
|
234
|
+
]);
|
|
235
|
+
}
|
|
236
|
+
function errorUnknownColumn(columnName, tableName) {
|
|
237
|
+
throw planInvalid(`Unknown column ${columnName} in table ${tableName}`);
|
|
238
|
+
}
|
|
239
|
+
function errorWhereMustBeCalledForUpdate() {
|
|
240
|
+
throw planInvalid("where() must be called before building an UPDATE query");
|
|
241
|
+
}
|
|
242
|
+
function errorFailedToBuildWhereClause() {
|
|
243
|
+
throw planInvalid("Failed to build WHERE clause");
|
|
244
|
+
}
|
|
245
|
+
function errorWhereMustBeCalledForDelete() {
|
|
246
|
+
throw planInvalid("where() must be called before building a DELETE query");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
//#endregion
|
|
250
|
+
//#region src/utils/capabilities.ts
|
|
251
|
+
function checkIncludeCapabilities(contract) {
|
|
252
|
+
const target = contract.target;
|
|
253
|
+
const contractCapabilities = contract.capabilities;
|
|
254
|
+
const declaredTargetCapabilities = contractCapabilities?.[target];
|
|
255
|
+
if (!contractCapabilities || !declaredTargetCapabilities) errorIncludeRequiresCapabilities(target);
|
|
256
|
+
if (declaredTargetCapabilities["lateral"] !== true || declaredTargetCapabilities["jsonAgg"] !== true) errorIncludeCapabilitiesNotTrue(target, {
|
|
257
|
+
lateral: declaredTargetCapabilities["lateral"],
|
|
258
|
+
jsonAgg: declaredTargetCapabilities["jsonAgg"]
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function checkReturningCapability(contract) {
|
|
262
|
+
const target = contract.target;
|
|
263
|
+
const capabilities = contract.capabilities;
|
|
264
|
+
if (!capabilities || !capabilities[target]) errorReturningRequiresCapability(target);
|
|
265
|
+
const targetCapabilities = capabilities[target];
|
|
266
|
+
if (targetCapabilities["returning"] !== true) errorReturningCapabilityNotTrue(target, targetCapabilities["returning"]);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region src/utils/assertions.ts
|
|
271
|
+
/**
|
|
272
|
+
* Asserts that a ColumnBuilder has table and column properties.
|
|
273
|
+
*/
|
|
274
|
+
function assertColumnBuilder(col, context) {
|
|
275
|
+
if (typeof col === "object" && col !== null && "table" in col && "column" in col && typeof col.table === "string" && typeof col.column === "string") return col;
|
|
276
|
+
throw planInvalid(`ColumnBuilder missing table/column in ${context}`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/sql/plan.ts
|
|
281
|
+
/**
|
|
282
|
+
* Extracts column references from an ExpressionSource (ColumnBuilder or ExpressionBuilder).
|
|
283
|
+
*/
|
|
284
|
+
function collectRefsFromExpressionSource(source, refsColumns) {
|
|
285
|
+
if (isExpressionBuilder(source)) {
|
|
286
|
+
const allRefs = collectColumnRefs(source.expr);
|
|
287
|
+
for (const ref of allRefs) refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
288
|
+
table: ref.table,
|
|
289
|
+
column: ref.column
|
|
290
|
+
});
|
|
291
|
+
} else if (isColumnBuilder(source)) {
|
|
292
|
+
const col = source;
|
|
293
|
+
refsColumns.set(`${col.table}.${col.column}`, {
|
|
294
|
+
table: col.table,
|
|
295
|
+
column: col.column
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Extracts column references from an Expression (AST node).
|
|
301
|
+
*/
|
|
302
|
+
function collectRefsFromExpression(expr, refsColumns) {
|
|
303
|
+
if (isOperationExpr(expr)) {
|
|
304
|
+
const allRefs = collectColumnRefs(expr);
|
|
305
|
+
for (const ref of allRefs) refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
306
|
+
table: ref.table,
|
|
307
|
+
column: ref.column
|
|
308
|
+
});
|
|
309
|
+
} else if (expr.kind === "col") refsColumns.set(`${expr.table}.${expr.column}`, {
|
|
310
|
+
table: expr.table,
|
|
311
|
+
column: expr.column
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
function buildMeta(args) {
|
|
315
|
+
const refsColumns = /* @__PURE__ */ new Map();
|
|
316
|
+
const refsTables = new Set([args.table.name]);
|
|
317
|
+
for (const column of args.projection.columns) collectRefsFromExpressionSource(column, refsColumns);
|
|
318
|
+
if (args.joins) for (const join of args.joins) {
|
|
319
|
+
refsTables.add(join.table.name);
|
|
320
|
+
const onLeft = assertColumnBuilder(join.on.left, "join ON left");
|
|
321
|
+
const onRight = assertColumnBuilder(join.on.right, "join ON right");
|
|
322
|
+
refsColumns.set(`${onLeft.table}.${onLeft.column}`, {
|
|
323
|
+
table: onLeft.table,
|
|
324
|
+
column: onLeft.column
|
|
325
|
+
});
|
|
326
|
+
refsColumns.set(`${onRight.table}.${onRight.column}`, {
|
|
327
|
+
table: onRight.table,
|
|
328
|
+
column: onRight.column
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
if (args.includes) for (const include of args.includes) {
|
|
332
|
+
refsTables.add(include.table.name);
|
|
333
|
+
const leftCol = assertColumnBuilder(include.on.left, "include ON left");
|
|
334
|
+
const rightCol = assertColumnBuilder(include.on.right, "include ON right");
|
|
335
|
+
refsColumns.set(`${leftCol.table}.${leftCol.column}`, {
|
|
336
|
+
table: leftCol.table,
|
|
337
|
+
column: leftCol.column
|
|
338
|
+
});
|
|
339
|
+
refsColumns.set(`${rightCol.table}.${rightCol.column}`, {
|
|
340
|
+
table: rightCol.table,
|
|
341
|
+
column: rightCol.column
|
|
342
|
+
});
|
|
343
|
+
for (const column of include.childProjection.columns) {
|
|
344
|
+
const col = assertColumnBuilder(column, "include child projection column");
|
|
345
|
+
refsColumns.set(`${col.table}.${col.column}`, {
|
|
346
|
+
table: col.table,
|
|
347
|
+
column: col.column
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
if (include.childWhere) {
|
|
351
|
+
collectRefsFromExpression(include.childWhere.left, refsColumns);
|
|
352
|
+
const childWhereRight = include.childWhere.right;
|
|
353
|
+
if (isColumnBuilder(childWhereRight) || isExpressionBuilder(childWhereRight)) collectRefsFromExpressionSource(childWhereRight, refsColumns);
|
|
354
|
+
}
|
|
355
|
+
if (include.childOrderBy) collectRefsFromExpression(include.childOrderBy.expr, refsColumns);
|
|
356
|
+
}
|
|
357
|
+
if (args.where) {
|
|
358
|
+
const leftExpr = args.where.left;
|
|
359
|
+
if (isOperationExpr(leftExpr)) {
|
|
360
|
+
const allRefs = collectColumnRefs(leftExpr);
|
|
361
|
+
for (const ref of allRefs) refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
362
|
+
table: ref.table,
|
|
363
|
+
column: ref.column
|
|
364
|
+
});
|
|
365
|
+
} else refsColumns.set(`${leftExpr.table}.${leftExpr.column}`, {
|
|
366
|
+
table: leftExpr.table,
|
|
367
|
+
column: leftExpr.column
|
|
368
|
+
});
|
|
369
|
+
const whereRight = args.where.right;
|
|
370
|
+
if (isColumnBuilder(whereRight) || isExpressionBuilder(whereRight)) collectRefsFromExpressionSource(whereRight, refsColumns);
|
|
371
|
+
}
|
|
372
|
+
if (args.orderBy) {
|
|
373
|
+
const orderByExpr = args.orderBy.expr;
|
|
374
|
+
if (isOperationExpr(orderByExpr)) {
|
|
375
|
+
const allRefs = collectColumnRefs(orderByExpr);
|
|
376
|
+
for (const ref of allRefs) refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
377
|
+
table: ref.table,
|
|
378
|
+
column: ref.column
|
|
379
|
+
});
|
|
380
|
+
} else refsColumns.set(`${orderByExpr.table}.${orderByExpr.column}`, {
|
|
381
|
+
table: orderByExpr.table,
|
|
382
|
+
column: orderByExpr.column
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
const includeAliases = new Set(args.includes?.map((inc) => inc.alias) ?? []);
|
|
386
|
+
const projectionMap = Object.fromEntries(args.projection.aliases.map((alias, index) => {
|
|
387
|
+
if (includeAliases.has(alias)) return [alias, `include:${alias}`];
|
|
388
|
+
const column = args.projection.columns[index];
|
|
389
|
+
if (!column) errorMissingColumnForAlias(alias, index);
|
|
390
|
+
if (isExpressionBuilder(column)) return [alias, `operation:${column.expr.method}`];
|
|
391
|
+
const col = column;
|
|
392
|
+
if (!col.table || !col.column) return [alias, `include:${alias}`];
|
|
393
|
+
return [alias, `${col.table}.${col.column}`];
|
|
394
|
+
}));
|
|
395
|
+
const projectionTypes = {};
|
|
396
|
+
for (let i = 0; i < args.projection.aliases.length; i++) {
|
|
397
|
+
const alias = args.projection.aliases[i];
|
|
398
|
+
if (!alias || includeAliases.has(alias)) continue;
|
|
399
|
+
const column = args.projection.columns[i];
|
|
400
|
+
if (!column) continue;
|
|
401
|
+
if (isExpressionBuilder(column)) {
|
|
402
|
+
const operationExpr = column.expr;
|
|
403
|
+
if (operationExpr.returns.kind === "typeId") projectionTypes[alias] = operationExpr.returns.type;
|
|
404
|
+
else if (operationExpr.returns.kind === "builtin") projectionTypes[alias] = operationExpr.returns.type;
|
|
405
|
+
} else {
|
|
406
|
+
const codecId = column.columnMeta?.codecId;
|
|
407
|
+
if (codecId) projectionTypes[alias] = codecId;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const projectionCodecs = {};
|
|
411
|
+
for (let i = 0; i < args.projection.aliases.length; i++) {
|
|
412
|
+
const alias = args.projection.aliases[i];
|
|
413
|
+
if (!alias || includeAliases.has(alias)) continue;
|
|
414
|
+
const column = args.projection.columns[i];
|
|
415
|
+
if (!column) continue;
|
|
416
|
+
if (isExpressionBuilder(column)) {
|
|
417
|
+
const operationExpr = column.expr;
|
|
418
|
+
if (operationExpr.returns.kind === "typeId") projectionCodecs[alias] = operationExpr.returns.type;
|
|
419
|
+
} else {
|
|
420
|
+
const codecId = column.columnMeta?.codecId;
|
|
421
|
+
if (codecId) projectionCodecs[alias] = codecId;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const allCodecs = {
|
|
425
|
+
...projectionCodecs,
|
|
426
|
+
...args.paramCodecs ? args.paramCodecs : {}
|
|
427
|
+
};
|
|
428
|
+
return Object.freeze(compact({
|
|
429
|
+
target: args.contract.target,
|
|
430
|
+
targetFamily: args.contract.targetFamily,
|
|
431
|
+
coreHash: args.contract.coreHash,
|
|
432
|
+
lane: "dsl",
|
|
433
|
+
refs: {
|
|
434
|
+
tables: Array.from(refsTables),
|
|
435
|
+
columns: Array.from(refsColumns.values())
|
|
436
|
+
},
|
|
437
|
+
projection: projectionMap,
|
|
438
|
+
projectionTypes: Object.keys(projectionTypes).length > 0 ? projectionTypes : void 0,
|
|
439
|
+
annotations: Object.keys(allCodecs).length > 0 ? Object.freeze({ codecs: Object.freeze(allCodecs) }) : void 0,
|
|
440
|
+
paramDescriptors: args.paramDescriptors,
|
|
441
|
+
profileHash: args.contract.profileHash
|
|
442
|
+
}));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
//#endregion
|
|
446
|
+
//#region src/sql/predicate-builder.ts
|
|
447
|
+
function buildWhereExpr(contract, where, paramsMap, descriptors, values) {
|
|
448
|
+
let leftExpr;
|
|
449
|
+
let codecId;
|
|
450
|
+
let rightExpr;
|
|
451
|
+
let paramName;
|
|
452
|
+
if (!where.left || typeof where.left !== "object" || !["col", "operation"].includes(where.left.kind ?? "")) errorFailedToBuildWhereClause();
|
|
453
|
+
leftExpr = where.left;
|
|
454
|
+
if (leftExpr.kind === "col") {
|
|
455
|
+
const { table, column } = leftExpr;
|
|
456
|
+
const contractTable = contract.storage.tables[table];
|
|
457
|
+
if (!contractTable) errorUnknownTable(table);
|
|
458
|
+
const columnMeta = contractTable.columns[column];
|
|
459
|
+
if (!columnMeta) errorUnknownColumn(column, table);
|
|
460
|
+
codecId = columnMeta.codecId;
|
|
461
|
+
}
|
|
462
|
+
if (isParamPlaceholder(where.right)) {
|
|
463
|
+
paramName = where.right.name;
|
|
464
|
+
if (!Object.hasOwn(paramsMap, paramName)) errorMissingParameter(paramName);
|
|
465
|
+
const value = paramsMap[paramName];
|
|
466
|
+
const index = values.push(value);
|
|
467
|
+
if (leftExpr.kind === "col") {
|
|
468
|
+
const { table, column } = leftExpr;
|
|
469
|
+
const columnMeta = contract.storage.tables[table]?.columns[column];
|
|
470
|
+
if (columnMeta) descriptors.push({
|
|
471
|
+
name: paramName,
|
|
472
|
+
source: "dsl",
|
|
473
|
+
refs: {
|
|
474
|
+
table,
|
|
475
|
+
column
|
|
476
|
+
},
|
|
477
|
+
nullable: columnMeta.nullable,
|
|
478
|
+
codecId: columnMeta.codecId,
|
|
479
|
+
nativeType: columnMeta.nativeType
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
rightExpr = createParamRef(index, paramName);
|
|
483
|
+
} else if (isColumnBuilder(where.right) || isExpressionBuilder(where.right)) {
|
|
484
|
+
rightExpr = where.right.toExpr();
|
|
485
|
+
if (rightExpr.kind === "col") {
|
|
486
|
+
const { table, column } = rightExpr;
|
|
487
|
+
const contractTable = contract.storage.tables[table];
|
|
488
|
+
if (!contractTable) errorUnknownTable(table);
|
|
489
|
+
if (!contractTable.columns[column]) errorUnknownColumn(column, table);
|
|
490
|
+
}
|
|
491
|
+
paramName = "";
|
|
492
|
+
} else errorFailedToBuildWhereClause();
|
|
493
|
+
return {
|
|
494
|
+
expr: createBinaryExpr(where.op, leftExpr, rightExpr),
|
|
495
|
+
codecId,
|
|
496
|
+
paramName
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
//#endregion
|
|
501
|
+
//#region src/sql/mutation-builder.ts
|
|
502
|
+
var InsertBuilderImpl = class InsertBuilderImpl {
|
|
503
|
+
contract;
|
|
504
|
+
context;
|
|
505
|
+
table;
|
|
506
|
+
values;
|
|
507
|
+
returningColumns = [];
|
|
508
|
+
constructor(options, table, values) {
|
|
509
|
+
this.context = options.context;
|
|
510
|
+
this.contract = options.context.contract;
|
|
511
|
+
this.table = table;
|
|
512
|
+
this.values = values;
|
|
513
|
+
}
|
|
514
|
+
returning(...columns) {
|
|
515
|
+
checkReturningCapability(this.contract);
|
|
516
|
+
const builder = new InsertBuilderImpl({ context: this.context }, this.table, this.values);
|
|
517
|
+
builder.returningColumns = [...this.returningColumns, ...columns];
|
|
518
|
+
return builder;
|
|
519
|
+
}
|
|
520
|
+
build(options) {
|
|
521
|
+
const paramsMap = options?.params ?? {};
|
|
522
|
+
const paramDescriptors = [];
|
|
523
|
+
const paramValues = [];
|
|
524
|
+
const paramCodecs = {};
|
|
525
|
+
const contractTable = this.contract.storage.tables[this.table.name];
|
|
526
|
+
if (!contractTable) errorUnknownTable(this.table.name);
|
|
527
|
+
const values = {};
|
|
528
|
+
for (const [columnName, placeholder] of Object.entries(this.values)) {
|
|
529
|
+
if (!contractTable.columns[columnName]) errorUnknownColumn(columnName, this.table.name);
|
|
530
|
+
const paramName = placeholder.name;
|
|
531
|
+
if (!Object.hasOwn(paramsMap, paramName)) errorMissingParameter(paramName);
|
|
532
|
+
const value = paramsMap[paramName];
|
|
533
|
+
const index = paramValues.push(value);
|
|
534
|
+
const columnMeta = contractTable.columns[columnName];
|
|
535
|
+
const codecId = columnMeta?.codecId;
|
|
536
|
+
if (paramName && codecId) paramCodecs[paramName] = codecId;
|
|
537
|
+
paramDescriptors.push({
|
|
538
|
+
name: paramName,
|
|
539
|
+
source: "dsl",
|
|
540
|
+
refs: {
|
|
541
|
+
table: this.table.name,
|
|
542
|
+
column: columnName
|
|
543
|
+
},
|
|
544
|
+
...codecId ? { codecId } : {},
|
|
545
|
+
...columnMeta?.nativeType ? { nativeType: columnMeta.nativeType } : {},
|
|
546
|
+
...columnMeta?.nullable !== void 0 ? { nullable: columnMeta.nullable } : {}
|
|
547
|
+
});
|
|
548
|
+
values[columnName] = createParamRef(index, paramName);
|
|
549
|
+
}
|
|
550
|
+
const returning = this.returningColumns.map((col) => {
|
|
551
|
+
const c = col;
|
|
552
|
+
return createColumnRef(c.table, c.column);
|
|
553
|
+
});
|
|
554
|
+
const ast = createInsertAst({
|
|
555
|
+
table: createTableRef(this.table.name),
|
|
556
|
+
values,
|
|
557
|
+
returning
|
|
558
|
+
});
|
|
559
|
+
const returningProjection = {
|
|
560
|
+
aliases: this.returningColumns.map((col) => {
|
|
561
|
+
return col.column;
|
|
562
|
+
}),
|
|
563
|
+
columns: this.returningColumns
|
|
564
|
+
};
|
|
565
|
+
const planMeta = buildMeta({
|
|
566
|
+
contract: this.contract,
|
|
567
|
+
table: this.table,
|
|
568
|
+
projection: returning.length > 0 ? returningProjection : {
|
|
569
|
+
aliases: [],
|
|
570
|
+
columns: []
|
|
571
|
+
},
|
|
572
|
+
paramDescriptors,
|
|
573
|
+
...Object.keys(paramCodecs).length > 0 ? { paramCodecs } : {}
|
|
574
|
+
});
|
|
575
|
+
return Object.freeze({
|
|
576
|
+
ast,
|
|
577
|
+
params: paramValues,
|
|
578
|
+
meta: {
|
|
579
|
+
...planMeta,
|
|
580
|
+
lane: "dsl",
|
|
581
|
+
annotations: {
|
|
582
|
+
...planMeta.annotations,
|
|
583
|
+
intent: "write",
|
|
584
|
+
isMutation: true
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
var UpdateBuilderImpl = class UpdateBuilderImpl {
|
|
591
|
+
contract;
|
|
592
|
+
context;
|
|
593
|
+
table;
|
|
594
|
+
set;
|
|
595
|
+
wherePredicate;
|
|
596
|
+
returningColumns = [];
|
|
597
|
+
constructor(options, table, set) {
|
|
598
|
+
this.context = options.context;
|
|
599
|
+
this.contract = options.context.contract;
|
|
600
|
+
this.table = table;
|
|
601
|
+
this.set = set;
|
|
602
|
+
}
|
|
603
|
+
where(predicate) {
|
|
604
|
+
const builder = new UpdateBuilderImpl({ context: this.context }, this.table, this.set);
|
|
605
|
+
builder.wherePredicate = predicate;
|
|
606
|
+
builder.returningColumns = [...this.returningColumns];
|
|
607
|
+
return builder;
|
|
608
|
+
}
|
|
609
|
+
returning(...columns) {
|
|
610
|
+
checkReturningCapability(this.contract);
|
|
611
|
+
const builder = new UpdateBuilderImpl({ context: this.context }, this.table, this.set);
|
|
612
|
+
if (this.wherePredicate) builder.wherePredicate = this.wherePredicate;
|
|
613
|
+
builder.returningColumns = [...this.returningColumns, ...columns];
|
|
614
|
+
return builder;
|
|
615
|
+
}
|
|
616
|
+
build(options) {
|
|
617
|
+
if (!this.wherePredicate) errorWhereMustBeCalledForUpdate();
|
|
618
|
+
const paramsMap = options?.params ?? {};
|
|
619
|
+
const paramDescriptors = [];
|
|
620
|
+
const paramValues = [];
|
|
621
|
+
const paramCodecs = {};
|
|
622
|
+
const contractTable = this.contract.storage.tables[this.table.name];
|
|
623
|
+
if (!contractTable) errorUnknownTable(this.table.name);
|
|
624
|
+
const set = {};
|
|
625
|
+
for (const [columnName, placeholder] of Object.entries(this.set)) {
|
|
626
|
+
if (!contractTable.columns[columnName]) errorUnknownColumn(columnName, this.table.name);
|
|
627
|
+
const paramName = placeholder.name;
|
|
628
|
+
if (!Object.hasOwn(paramsMap, paramName)) errorMissingParameter(paramName);
|
|
629
|
+
const value = paramsMap[paramName];
|
|
630
|
+
const index = paramValues.push(value);
|
|
631
|
+
const columnMeta = contractTable.columns[columnName];
|
|
632
|
+
const codecId = columnMeta?.codecId;
|
|
633
|
+
if (paramName && codecId) paramCodecs[paramName] = codecId;
|
|
634
|
+
paramDescriptors.push({
|
|
635
|
+
name: paramName,
|
|
636
|
+
source: "dsl",
|
|
637
|
+
refs: {
|
|
638
|
+
table: this.table.name,
|
|
639
|
+
column: columnName
|
|
640
|
+
},
|
|
641
|
+
...codecId ? { codecId } : {},
|
|
642
|
+
...columnMeta?.nativeType ? { nativeType: columnMeta.nativeType } : {},
|
|
643
|
+
...columnMeta?.nullable !== void 0 ? { nullable: columnMeta.nullable } : {}
|
|
644
|
+
});
|
|
645
|
+
set[columnName] = createParamRef(index, paramName);
|
|
646
|
+
}
|
|
647
|
+
const whereResult = buildWhereExpr(this.contract, this.wherePredicate, paramsMap, paramDescriptors, paramValues);
|
|
648
|
+
const whereExpr = whereResult.expr;
|
|
649
|
+
if (!whereExpr) errorFailedToBuildWhereClause();
|
|
650
|
+
if (whereResult.codecId && whereResult.paramName) paramCodecs[whereResult.paramName] = whereResult.codecId;
|
|
651
|
+
const returning = this.returningColumns.map((col) => {
|
|
652
|
+
const c = col;
|
|
653
|
+
return createColumnRef(c.table, c.column);
|
|
654
|
+
});
|
|
655
|
+
const ast = createUpdateAst({
|
|
656
|
+
table: createTableRef(this.table.name),
|
|
657
|
+
set,
|
|
658
|
+
where: whereExpr,
|
|
659
|
+
returning
|
|
660
|
+
});
|
|
661
|
+
const returningProjection = {
|
|
662
|
+
aliases: this.returningColumns.map((col) => {
|
|
663
|
+
return col.column;
|
|
664
|
+
}),
|
|
665
|
+
columns: this.returningColumns
|
|
666
|
+
};
|
|
667
|
+
const planMeta = buildMeta({
|
|
668
|
+
contract: this.contract,
|
|
669
|
+
table: this.table,
|
|
670
|
+
projection: returning.length > 0 ? returningProjection : {
|
|
671
|
+
aliases: [],
|
|
672
|
+
columns: []
|
|
673
|
+
},
|
|
674
|
+
paramDescriptors,
|
|
675
|
+
...Object.keys(paramCodecs).length > 0 ? { paramCodecs } : {},
|
|
676
|
+
where: this.wherePredicate
|
|
677
|
+
});
|
|
678
|
+
return Object.freeze({
|
|
679
|
+
ast,
|
|
680
|
+
params: paramValues,
|
|
681
|
+
meta: {
|
|
682
|
+
...planMeta,
|
|
683
|
+
lane: "dsl",
|
|
684
|
+
annotations: {
|
|
685
|
+
...planMeta.annotations,
|
|
686
|
+
intent: "write",
|
|
687
|
+
isMutation: true,
|
|
688
|
+
hasWhere: true
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
var DeleteBuilderImpl = class DeleteBuilderImpl {
|
|
695
|
+
contract;
|
|
696
|
+
context;
|
|
697
|
+
table;
|
|
698
|
+
wherePredicate;
|
|
699
|
+
returningColumns = [];
|
|
700
|
+
constructor(options, table) {
|
|
701
|
+
this.context = options.context;
|
|
702
|
+
this.contract = options.context.contract;
|
|
703
|
+
this.table = table;
|
|
704
|
+
}
|
|
705
|
+
where(predicate) {
|
|
706
|
+
const builder = new DeleteBuilderImpl({ context: this.context }, this.table);
|
|
707
|
+
builder.wherePredicate = predicate;
|
|
708
|
+
builder.returningColumns = [...this.returningColumns];
|
|
709
|
+
return builder;
|
|
710
|
+
}
|
|
711
|
+
returning(...columns) {
|
|
712
|
+
checkReturningCapability(this.contract);
|
|
713
|
+
const builder = new DeleteBuilderImpl({ context: this.context }, this.table);
|
|
714
|
+
if (this.wherePredicate) builder.wherePredicate = this.wherePredicate;
|
|
715
|
+
builder.returningColumns = [...this.returningColumns, ...columns];
|
|
716
|
+
return builder;
|
|
717
|
+
}
|
|
718
|
+
build(options) {
|
|
719
|
+
if (!this.wherePredicate) errorWhereMustBeCalledForDelete();
|
|
720
|
+
const paramsMap = options?.params ?? {};
|
|
721
|
+
const paramDescriptors = [];
|
|
722
|
+
const paramValues = [];
|
|
723
|
+
const paramCodecs = {};
|
|
724
|
+
if (!this.contract.storage.tables[this.table.name]) errorUnknownTable(this.table.name);
|
|
725
|
+
const whereResult = buildWhereExpr(this.contract, this.wherePredicate, paramsMap, paramDescriptors, paramValues);
|
|
726
|
+
const whereExpr = whereResult.expr;
|
|
727
|
+
if (!whereExpr) errorFailedToBuildWhereClause();
|
|
728
|
+
if (whereResult.codecId && whereResult.paramName) paramCodecs[whereResult.paramName] = whereResult.codecId;
|
|
729
|
+
const returning = this.returningColumns.map((col) => {
|
|
730
|
+
const c = col;
|
|
731
|
+
return createColumnRef(c.table, c.column);
|
|
732
|
+
});
|
|
733
|
+
const ast = createDeleteAst({
|
|
734
|
+
table: createTableRef(this.table.name),
|
|
735
|
+
where: whereExpr,
|
|
736
|
+
returning
|
|
737
|
+
});
|
|
738
|
+
const returningProjection = {
|
|
739
|
+
aliases: this.returningColumns.map((col) => {
|
|
740
|
+
return col.column;
|
|
741
|
+
}),
|
|
742
|
+
columns: this.returningColumns
|
|
743
|
+
};
|
|
744
|
+
const planMeta = buildMeta({
|
|
745
|
+
contract: this.contract,
|
|
746
|
+
table: this.table,
|
|
747
|
+
projection: returning.length > 0 ? returningProjection : {
|
|
748
|
+
aliases: [],
|
|
749
|
+
columns: []
|
|
750
|
+
},
|
|
751
|
+
paramDescriptors,
|
|
752
|
+
...Object.keys(paramCodecs).length > 0 ? { paramCodecs } : {},
|
|
753
|
+
where: this.wherePredicate
|
|
754
|
+
});
|
|
755
|
+
return Object.freeze({
|
|
756
|
+
ast,
|
|
757
|
+
params: paramValues,
|
|
758
|
+
meta: {
|
|
759
|
+
...planMeta,
|
|
760
|
+
lane: "dsl",
|
|
761
|
+
annotations: {
|
|
762
|
+
...planMeta.annotations,
|
|
763
|
+
intent: "write",
|
|
764
|
+
isMutation: true,
|
|
765
|
+
hasWhere: true
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
//#endregion
|
|
773
|
+
//#region src/sql/projection.ts
|
|
774
|
+
function generateAlias(path) {
|
|
775
|
+
if (path.length === 0) errorAliasPathEmpty();
|
|
776
|
+
return path.join("_");
|
|
777
|
+
}
|
|
778
|
+
var AliasTracker = class {
|
|
779
|
+
aliases = /* @__PURE__ */ new Set();
|
|
780
|
+
aliasToPath = /* @__PURE__ */ new Map();
|
|
781
|
+
register(path) {
|
|
782
|
+
const alias = generateAlias(path);
|
|
783
|
+
if (this.aliases.has(alias)) errorAliasCollision(path, alias, this.aliasToPath.get(alias));
|
|
784
|
+
this.aliases.add(alias);
|
|
785
|
+
this.aliasToPath.set(alias, path);
|
|
786
|
+
return alias;
|
|
787
|
+
}
|
|
788
|
+
getPath(alias) {
|
|
789
|
+
return this.aliasToPath.get(alias);
|
|
790
|
+
}
|
|
791
|
+
has(alias) {
|
|
792
|
+
return this.aliases.has(alias);
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
function flattenProjection(projection, tracker, currentPath = []) {
|
|
796
|
+
const aliases = [];
|
|
797
|
+
const columns = [];
|
|
798
|
+
for (const [key, value] of Object.entries(projection)) {
|
|
799
|
+
const path = [...currentPath, key];
|
|
800
|
+
if (isExpressionSource(value)) {
|
|
801
|
+
const alias = tracker.register(path);
|
|
802
|
+
aliases.push(alias);
|
|
803
|
+
columns.push(value);
|
|
804
|
+
} else if (typeof value === "object" && value !== null) {
|
|
805
|
+
const nested = flattenProjection(value, tracker, path);
|
|
806
|
+
aliases.push(...nested.aliases);
|
|
807
|
+
columns.push(...nested.columns);
|
|
808
|
+
} else errorInvalidProjectionValue(path);
|
|
809
|
+
}
|
|
810
|
+
return {
|
|
811
|
+
aliases,
|
|
812
|
+
columns
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
function buildProjectionState(_table, projection, includes) {
|
|
816
|
+
const tracker = new AliasTracker();
|
|
817
|
+
const aliases = [];
|
|
818
|
+
const columns = [];
|
|
819
|
+
for (const [key, value] of Object.entries(projection)) if (value === true) {
|
|
820
|
+
const matchingInclude = includes?.find((inc) => inc.alias === key);
|
|
821
|
+
if (!matchingInclude) errorIncludeAliasNotFound(key);
|
|
822
|
+
aliases.push(key);
|
|
823
|
+
columns.push({
|
|
824
|
+
kind: "column",
|
|
825
|
+
table: matchingInclude.table.name,
|
|
826
|
+
column: "",
|
|
827
|
+
columnMeta: {
|
|
828
|
+
nativeType: "jsonb",
|
|
829
|
+
codecId: "core/json@1",
|
|
830
|
+
nullable: true
|
|
831
|
+
},
|
|
832
|
+
toExpr: () => ({
|
|
833
|
+
kind: "col",
|
|
834
|
+
table: matchingInclude.table.name,
|
|
835
|
+
column: ""
|
|
836
|
+
})
|
|
837
|
+
});
|
|
838
|
+
} else if (isExpressionSource(value)) {
|
|
839
|
+
const alias = tracker.register([key]);
|
|
840
|
+
aliases.push(alias);
|
|
841
|
+
columns.push(value);
|
|
842
|
+
} else if (typeof value === "object" && value !== null) {
|
|
843
|
+
const nested = flattenProjection(value, tracker, [key]);
|
|
844
|
+
aliases.push(...nested.aliases);
|
|
845
|
+
columns.push(...nested.columns);
|
|
846
|
+
} else errorInvalidProjectionKey(key);
|
|
847
|
+
if (aliases.length === 0) errorProjectionEmpty();
|
|
848
|
+
return {
|
|
849
|
+
aliases,
|
|
850
|
+
columns
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
//#endregion
|
|
855
|
+
//#region src/sql/include-builder.ts
|
|
856
|
+
var IncludeChildBuilderImpl = class IncludeChildBuilderImpl {
|
|
857
|
+
contract;
|
|
858
|
+
codecTypes;
|
|
859
|
+
table;
|
|
860
|
+
childProjection;
|
|
861
|
+
childWhere;
|
|
862
|
+
childOrderBy;
|
|
863
|
+
childLimit;
|
|
864
|
+
constructor(contract, codecTypes, table) {
|
|
865
|
+
this.contract = contract;
|
|
866
|
+
this.codecTypes = codecTypes;
|
|
867
|
+
this.table = table;
|
|
868
|
+
}
|
|
869
|
+
select(projection) {
|
|
870
|
+
const projectionState = buildProjectionState(this.table, projection);
|
|
871
|
+
const builder = new IncludeChildBuilderImpl(this.contract, this.codecTypes, this.table);
|
|
872
|
+
builder.childProjection = projectionState;
|
|
873
|
+
if (this.childWhere !== void 0) builder.childWhere = this.childWhere;
|
|
874
|
+
if (this.childOrderBy !== void 0) builder.childOrderBy = this.childOrderBy;
|
|
875
|
+
if (this.childLimit !== void 0) builder.childLimit = this.childLimit;
|
|
876
|
+
return builder;
|
|
877
|
+
}
|
|
878
|
+
where(expr) {
|
|
879
|
+
const builder = new IncludeChildBuilderImpl(this.contract, this.codecTypes, this.table);
|
|
880
|
+
if (this.childProjection !== void 0) builder.childProjection = this.childProjection;
|
|
881
|
+
builder.childWhere = expr;
|
|
882
|
+
if (this.childOrderBy !== void 0) builder.childOrderBy = this.childOrderBy;
|
|
883
|
+
if (this.childLimit !== void 0) builder.childLimit = this.childLimit;
|
|
884
|
+
return builder;
|
|
885
|
+
}
|
|
886
|
+
orderBy(order) {
|
|
887
|
+
const builder = new IncludeChildBuilderImpl(this.contract, this.codecTypes, this.table);
|
|
888
|
+
if (this.childProjection !== void 0) builder.childProjection = this.childProjection;
|
|
889
|
+
if (this.childWhere !== void 0) builder.childWhere = this.childWhere;
|
|
890
|
+
builder.childOrderBy = order;
|
|
891
|
+
if (this.childLimit !== void 0) builder.childLimit = this.childLimit;
|
|
892
|
+
return builder;
|
|
893
|
+
}
|
|
894
|
+
limit(count) {
|
|
895
|
+
if (!Number.isInteger(count) || count < 0) errorLimitMustBeNonNegativeInteger();
|
|
896
|
+
const builder = new IncludeChildBuilderImpl(this.contract, this.codecTypes, this.table);
|
|
897
|
+
if (this.childProjection !== void 0) builder.childProjection = this.childProjection;
|
|
898
|
+
if (this.childWhere !== void 0) builder.childWhere = this.childWhere;
|
|
899
|
+
if (this.childOrderBy !== void 0) builder.childOrderBy = this.childOrderBy;
|
|
900
|
+
builder.childLimit = count;
|
|
901
|
+
return builder;
|
|
902
|
+
}
|
|
903
|
+
getState() {
|
|
904
|
+
if (!this.childProjection) errorChildProjectionMustBeSpecified();
|
|
905
|
+
const state = { childProjection: this.childProjection };
|
|
906
|
+
if (this.childWhere !== void 0) state.childWhere = this.childWhere;
|
|
907
|
+
if (this.childOrderBy !== void 0) state.childOrderBy = this.childOrderBy;
|
|
908
|
+
if (this.childLimit !== void 0) state.childLimit = this.childLimit;
|
|
909
|
+
return state;
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
function buildIncludeAst(include, contract, paramsMap, paramDescriptors, paramValues) {
|
|
913
|
+
const childOrderBy = include.childOrderBy ? (() => {
|
|
914
|
+
const orderBy = include.childOrderBy;
|
|
915
|
+
const orderExpr = orderBy.expr;
|
|
916
|
+
return [createOrderByItem((() => {
|
|
917
|
+
if (isOperationExpr(orderExpr)) {
|
|
918
|
+
const baseCol = extractBaseColumnRef(orderExpr);
|
|
919
|
+
return createColumnRef(baseCol.table, baseCol.column);
|
|
920
|
+
}
|
|
921
|
+
const colBuilder = orderExpr;
|
|
922
|
+
return createColumnRef(colBuilder.table, colBuilder.column);
|
|
923
|
+
})(), orderBy.dir)];
|
|
924
|
+
})() : void 0;
|
|
925
|
+
let childWhere;
|
|
926
|
+
if (include.childWhere) childWhere = buildWhereExpr(contract, include.childWhere, paramsMap, paramDescriptors, paramValues).expr;
|
|
927
|
+
const onLeft = include.on.left;
|
|
928
|
+
const onRight = include.on.right;
|
|
929
|
+
const onExpr = createJoinOnExpr(createColumnRef(onLeft.table, onLeft.column), createColumnRef(onRight.table, onRight.column));
|
|
930
|
+
return {
|
|
931
|
+
kind: "includeMany",
|
|
932
|
+
alias: include.alias,
|
|
933
|
+
child: {
|
|
934
|
+
table: createTableRef(include.table.name),
|
|
935
|
+
on: onExpr,
|
|
936
|
+
...childWhere ? { where: childWhere } : {},
|
|
937
|
+
...childOrderBy ? { orderBy: childOrderBy } : {},
|
|
938
|
+
...typeof include.childLimit === "number" ? { limit: include.childLimit } : {},
|
|
939
|
+
project: include.childProjection.aliases.map((alias, idx) => {
|
|
940
|
+
const column = include.childProjection.columns[idx];
|
|
941
|
+
if (!column || !alias) errorMissingColumnForAlias(alias ?? "unknown", idx);
|
|
942
|
+
return {
|
|
943
|
+
alias,
|
|
944
|
+
expr: column.toExpr()
|
|
945
|
+
};
|
|
946
|
+
})
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
//#endregion
|
|
952
|
+
//#region src/sql/join-builder.ts
|
|
953
|
+
function buildJoinAst(join) {
|
|
954
|
+
const onLeft = join.on.left;
|
|
955
|
+
const onRight = join.on.right;
|
|
956
|
+
const onExpr = createJoinOnExpr(createColumnRef(onLeft.table, onLeft.column), createColumnRef(onRight.table, onRight.column));
|
|
957
|
+
return createJoin(join.joinType, createTableRef(join.table.name), onExpr);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
//#endregion
|
|
961
|
+
//#region src/sql/select-builder.ts
|
|
962
|
+
var SelectBuilderImpl = class SelectBuilderImpl {
|
|
963
|
+
contract;
|
|
964
|
+
codecTypes;
|
|
965
|
+
context;
|
|
966
|
+
state = {};
|
|
967
|
+
constructor(options, state) {
|
|
968
|
+
this.context = options.context;
|
|
969
|
+
this.contract = options.context.contract;
|
|
970
|
+
this.codecTypes = options.context.contract.mappings.codecTypes;
|
|
971
|
+
if (state) this.state = state;
|
|
972
|
+
}
|
|
973
|
+
from(table) {
|
|
974
|
+
return new SelectBuilderImpl({ context: this.context }, {
|
|
975
|
+
...this.state,
|
|
976
|
+
from: table
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
innerJoin(table, on) {
|
|
980
|
+
return this._addJoin("inner", table, on);
|
|
981
|
+
}
|
|
982
|
+
leftJoin(table, on) {
|
|
983
|
+
return this._addJoin("left", table, on);
|
|
984
|
+
}
|
|
985
|
+
rightJoin(table, on) {
|
|
986
|
+
return this._addJoin("right", table, on);
|
|
987
|
+
}
|
|
988
|
+
fullJoin(table, on) {
|
|
989
|
+
return this._addJoin("full", table, on);
|
|
990
|
+
}
|
|
991
|
+
includeMany(childTable, on, childBuilder, options) {
|
|
992
|
+
checkIncludeCapabilities(this.contract);
|
|
993
|
+
if (!this.contract.storage.tables[childTable.name]) errorUnknownTable(childTable.name);
|
|
994
|
+
const onPredicate = on(createJoinOnBuilder());
|
|
995
|
+
const onLeft = onPredicate.left;
|
|
996
|
+
const onRight = onPredicate.right;
|
|
997
|
+
if (onLeft.table === onRight.table) errorSelfJoinNotSupported();
|
|
998
|
+
const childState = childBuilder(new IncludeChildBuilderImpl(this.contract, this.codecTypes, childTable)).getState();
|
|
999
|
+
if (childState.childProjection.aliases.length === 0) errorChildProjectionEmpty();
|
|
1000
|
+
const alias = options?.alias ?? childTable.name;
|
|
1001
|
+
if (this.state.projection) {
|
|
1002
|
+
if (this.state.projection.aliases.includes(alias)) errorIncludeAliasCollision(alias, "projection");
|
|
1003
|
+
}
|
|
1004
|
+
const existingIncludes = this.state.includes ?? [];
|
|
1005
|
+
if (existingIncludes.some((inc) => inc.alias === alias)) errorIncludeAliasCollision(alias, "include");
|
|
1006
|
+
const includeState = {
|
|
1007
|
+
alias,
|
|
1008
|
+
table: childTable,
|
|
1009
|
+
on: onPredicate,
|
|
1010
|
+
childProjection: childState.childProjection,
|
|
1011
|
+
...childState.childWhere !== void 0 ? { childWhere: childState.childWhere } : {},
|
|
1012
|
+
...childState.childOrderBy !== void 0 ? { childOrderBy: childState.childOrderBy } : {},
|
|
1013
|
+
...childState.childLimit !== void 0 ? { childLimit: childState.childLimit } : {}
|
|
1014
|
+
};
|
|
1015
|
+
const newIncludes = [...existingIncludes, includeState];
|
|
1016
|
+
return new SelectBuilderImpl({ context: this.context }, {
|
|
1017
|
+
...this.state,
|
|
1018
|
+
includes: newIncludes
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
_addJoin(joinType, table, on) {
|
|
1022
|
+
const fromTable = this.ensureFrom();
|
|
1023
|
+
if (!this.contract.storage.tables[table.name]) errorUnknownTable(table.name);
|
|
1024
|
+
if (table.name === fromTable.name) errorSelfJoinNotSupported();
|
|
1025
|
+
const joinState = {
|
|
1026
|
+
joinType,
|
|
1027
|
+
table,
|
|
1028
|
+
on: on(createJoinOnBuilder())
|
|
1029
|
+
};
|
|
1030
|
+
const newJoins = [...this.state.joins ?? [], joinState];
|
|
1031
|
+
return new SelectBuilderImpl({ context: this.context }, {
|
|
1032
|
+
...this.state,
|
|
1033
|
+
joins: newJoins
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
where(expr) {
|
|
1037
|
+
return new SelectBuilderImpl({ context: this.context }, {
|
|
1038
|
+
...this.state,
|
|
1039
|
+
where: expr
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
select(projection) {
|
|
1043
|
+
const projectionState = buildProjectionState(this.ensureFrom(), projection, this.state.includes);
|
|
1044
|
+
return new SelectBuilderImpl({ context: this.context }, {
|
|
1045
|
+
...this.state,
|
|
1046
|
+
projection: projectionState
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
orderBy(order) {
|
|
1050
|
+
return new SelectBuilderImpl({ context: this.context }, {
|
|
1051
|
+
...this.state,
|
|
1052
|
+
orderBy: order
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
limit(count) {
|
|
1056
|
+
if (!Number.isInteger(count) || count < 0) errorLimitMustBeNonNegativeInteger();
|
|
1057
|
+
return new SelectBuilderImpl({ context: this.context }, {
|
|
1058
|
+
...this.state,
|
|
1059
|
+
limit: count
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
build(options) {
|
|
1063
|
+
const table = this.ensureFrom();
|
|
1064
|
+
const projection = this.ensureProjection();
|
|
1065
|
+
const paramsMap = options?.params ?? {};
|
|
1066
|
+
if (!this.contract.storage.tables[table.name]) errorUnknownTable(table.name);
|
|
1067
|
+
const paramDescriptors = [];
|
|
1068
|
+
const paramValues = [];
|
|
1069
|
+
const paramCodecs = {};
|
|
1070
|
+
const whereResult = this.state.where ? buildWhereExpr(this.contract, this.state.where, paramsMap, paramDescriptors, paramValues) : void 0;
|
|
1071
|
+
const whereExpr = whereResult?.expr;
|
|
1072
|
+
if (whereResult?.codecId && whereResult.paramName) paramCodecs[whereResult.paramName] = whereResult.codecId;
|
|
1073
|
+
const orderByClause = this.state.orderBy ? (() => {
|
|
1074
|
+
const orderBy = this.state.orderBy;
|
|
1075
|
+
return [createOrderByItem(orderBy.expr, orderBy.dir)];
|
|
1076
|
+
})() : void 0;
|
|
1077
|
+
const joins = this.state.joins?.map((join) => buildJoinAst(join));
|
|
1078
|
+
const includes = this.state.includes?.map((include) => buildIncludeAst(include, this.contract, paramsMap, paramDescriptors, paramValues));
|
|
1079
|
+
const projectEntries = [];
|
|
1080
|
+
for (let i = 0; i < projection.aliases.length; i++) {
|
|
1081
|
+
const alias = projection.aliases[i];
|
|
1082
|
+
if (!alias) errorMissingAlias(i);
|
|
1083
|
+
const column = projection.columns[i];
|
|
1084
|
+
if (this.state.includes?.find((inc) => inc.alias === alias)) projectEntries.push({
|
|
1085
|
+
alias,
|
|
1086
|
+
expr: {
|
|
1087
|
+
kind: "includeRef",
|
|
1088
|
+
alias
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
else if (column && isExpressionBuilder(column)) projectEntries.push({
|
|
1092
|
+
alias,
|
|
1093
|
+
expr: column.expr
|
|
1094
|
+
});
|
|
1095
|
+
else if (column) {
|
|
1096
|
+
const columnRef = column.toExpr();
|
|
1097
|
+
projectEntries.push({
|
|
1098
|
+
alias,
|
|
1099
|
+
expr: columnRef
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
const ast = createSelectAst({
|
|
1104
|
+
from: createTableRef(table.name),
|
|
1105
|
+
joins,
|
|
1106
|
+
includes,
|
|
1107
|
+
project: projectEntries,
|
|
1108
|
+
where: whereExpr,
|
|
1109
|
+
orderBy: orderByClause,
|
|
1110
|
+
limit: this.state.limit
|
|
1111
|
+
});
|
|
1112
|
+
const planMeta = buildMeta({
|
|
1113
|
+
contract: this.contract,
|
|
1114
|
+
table,
|
|
1115
|
+
projection,
|
|
1116
|
+
joins: this.state.joins,
|
|
1117
|
+
includes: this.state.includes,
|
|
1118
|
+
paramDescriptors,
|
|
1119
|
+
paramCodecs,
|
|
1120
|
+
where: this.state.where,
|
|
1121
|
+
orderBy: this.state.orderBy
|
|
1122
|
+
});
|
|
1123
|
+
return Object.freeze({
|
|
1124
|
+
ast,
|
|
1125
|
+
params: paramValues,
|
|
1126
|
+
meta: planMeta
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
ensureFrom() {
|
|
1130
|
+
if (!this.state.from) errorFromMustBeCalled();
|
|
1131
|
+
return this.state.from;
|
|
1132
|
+
}
|
|
1133
|
+
ensureProjection() {
|
|
1134
|
+
if (!this.state.projection) errorSelectMustBeCalled();
|
|
1135
|
+
return this.state.projection;
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
|
|
1139
|
+
//#endregion
|
|
1140
|
+
//#region src/sql/builder.ts
|
|
1141
|
+
function sql(options) {
|
|
1142
|
+
const builder = new SelectBuilderImpl(options);
|
|
1143
|
+
const rawFactory = createRawFactory(options.context.contract);
|
|
1144
|
+
Object.defineProperty(builder, "raw", {
|
|
1145
|
+
value: rawFactory,
|
|
1146
|
+
enumerable: true,
|
|
1147
|
+
configurable: false
|
|
1148
|
+
});
|
|
1149
|
+
Object.defineProperty(builder, "insert", {
|
|
1150
|
+
value: (table, values) => {
|
|
1151
|
+
return new InsertBuilderImpl(options, table, values);
|
|
1152
|
+
},
|
|
1153
|
+
enumerable: true,
|
|
1154
|
+
configurable: false
|
|
1155
|
+
});
|
|
1156
|
+
Object.defineProperty(builder, "update", {
|
|
1157
|
+
value: (table, set) => {
|
|
1158
|
+
return new UpdateBuilderImpl(options, table, set);
|
|
1159
|
+
},
|
|
1160
|
+
enumerable: true,
|
|
1161
|
+
configurable: false
|
|
1162
|
+
});
|
|
1163
|
+
Object.defineProperty(builder, "delete", {
|
|
1164
|
+
value: (table) => {
|
|
1165
|
+
return new DeleteBuilderImpl(options, table);
|
|
1166
|
+
},
|
|
1167
|
+
enumerable: true,
|
|
1168
|
+
configurable: false
|
|
1169
|
+
});
|
|
1170
|
+
return builder;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
//#endregion
|
|
1174
|
+
export { sql as n, rawOptions as r, createJoinOnBuilder$1 as t };
|
|
1175
|
+
//# sourceMappingURL=builder-C87NiJaP.mjs.map
|