metal-orm 1.0.82 → 1.0.85
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/index.cjs +300 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +300 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ast/ast-validation.ts +14 -0
- package/src/core/ast/expression-builders.ts +43 -24
- package/src/core/ast/expression-nodes.ts +35 -25
- package/src/core/ast/expression-visitor.ts +34 -25
- package/src/core/ast/param-proxy.ts +1 -4
- package/src/core/ast/query-visitor.ts +227 -0
- package/src/core/dialect/abstract.ts +70 -46
- package/src/query-builder/query-ast-service.ts +13 -0
- package/src/query-builder/select.ts +128 -109
package/dist/index.d.cts
CHANGED
|
@@ -1820,6 +1820,8 @@ interface CompilerContext {
|
|
|
1820
1820
|
params: unknown[];
|
|
1821
1821
|
/** Function to add a parameter and get its placeholder */
|
|
1822
1822
|
addParameter(value: unknown): string;
|
|
1823
|
+
/** Whether Param operands are allowed (for schema generation) */
|
|
1824
|
+
allowParams?: boolean;
|
|
1823
1825
|
}
|
|
1824
1826
|
/**
|
|
1825
1827
|
* Result of SQL compilation
|
|
@@ -1854,6 +1856,9 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
|
|
|
1854
1856
|
* @returns Compiled query with SQL and parameters
|
|
1855
1857
|
*/
|
|
1856
1858
|
compileSelect(ast: SelectQueryNode): CompiledQuery;
|
|
1859
|
+
compileSelectWithOptions(ast: SelectQueryNode, options?: {
|
|
1860
|
+
allowParams?: boolean;
|
|
1861
|
+
}): CompiledQuery;
|
|
1857
1862
|
compileInsert(ast: InsertQueryNode): CompiledQuery;
|
|
1858
1863
|
compileUpdate(ast: UpdateQueryNode): CompiledQuery;
|
|
1859
1864
|
compileDelete(ast: DeleteQueryNode): CompiledQuery;
|
|
@@ -1894,9 +1899,12 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
|
|
|
1894
1899
|
protected compileSelectForExists(ast: SelectQueryNode, ctx: CompilerContext): string;
|
|
1895
1900
|
/**
|
|
1896
1901
|
* Creates a new compiler context
|
|
1902
|
+
* @param options - Optional compiler context options
|
|
1897
1903
|
* @returns Compiler context with parameter management
|
|
1898
1904
|
*/
|
|
1899
|
-
protected createCompilerContext(
|
|
1905
|
+
protected createCompilerContext(options?: {
|
|
1906
|
+
allowParams?: boolean;
|
|
1907
|
+
}): CompilerContext;
|
|
1900
1908
|
/**
|
|
1901
1909
|
* Formats a parameter placeholder
|
|
1902
1910
|
* @param index - Parameter index
|
|
@@ -2384,6 +2392,7 @@ declare class QueryAstService {
|
|
|
2384
2392
|
* @returns Normalized ordering term
|
|
2385
2393
|
*/
|
|
2386
2394
|
private normalizeOrderingTerm;
|
|
2395
|
+
private toParamNode;
|
|
2387
2396
|
}
|
|
2388
2397
|
|
|
2389
2398
|
/**
|
|
@@ -4312,6 +4321,11 @@ declare class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Ta
|
|
|
4312
4321
|
* Ensures that if no columns are selected, all columns from the table are selected by default.
|
|
4313
4322
|
*/
|
|
4314
4323
|
private ensureDefaultSelection;
|
|
4324
|
+
/**
|
|
4325
|
+
* Validates that the query does not contain Param operands.
|
|
4326
|
+
* Param proxies are only for schema generation, not execution.
|
|
4327
|
+
*/
|
|
4328
|
+
private validateNoParamOperands;
|
|
4315
4329
|
/**
|
|
4316
4330
|
* Executes the query and returns hydrated results.
|
|
4317
4331
|
* If the builder was created with an entity constructor (e.g. via selectFromEntity),
|
package/dist/index.d.ts
CHANGED
|
@@ -1820,6 +1820,8 @@ interface CompilerContext {
|
|
|
1820
1820
|
params: unknown[];
|
|
1821
1821
|
/** Function to add a parameter and get its placeholder */
|
|
1822
1822
|
addParameter(value: unknown): string;
|
|
1823
|
+
/** Whether Param operands are allowed (for schema generation) */
|
|
1824
|
+
allowParams?: boolean;
|
|
1823
1825
|
}
|
|
1824
1826
|
/**
|
|
1825
1827
|
* Result of SQL compilation
|
|
@@ -1854,6 +1856,9 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
|
|
|
1854
1856
|
* @returns Compiled query with SQL and parameters
|
|
1855
1857
|
*/
|
|
1856
1858
|
compileSelect(ast: SelectQueryNode): CompiledQuery;
|
|
1859
|
+
compileSelectWithOptions(ast: SelectQueryNode, options?: {
|
|
1860
|
+
allowParams?: boolean;
|
|
1861
|
+
}): CompiledQuery;
|
|
1857
1862
|
compileInsert(ast: InsertQueryNode): CompiledQuery;
|
|
1858
1863
|
compileUpdate(ast: UpdateQueryNode): CompiledQuery;
|
|
1859
1864
|
compileDelete(ast: DeleteQueryNode): CompiledQuery;
|
|
@@ -1894,9 +1899,12 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
|
|
|
1894
1899
|
protected compileSelectForExists(ast: SelectQueryNode, ctx: CompilerContext): string;
|
|
1895
1900
|
/**
|
|
1896
1901
|
* Creates a new compiler context
|
|
1902
|
+
* @param options - Optional compiler context options
|
|
1897
1903
|
* @returns Compiler context with parameter management
|
|
1898
1904
|
*/
|
|
1899
|
-
protected createCompilerContext(
|
|
1905
|
+
protected createCompilerContext(options?: {
|
|
1906
|
+
allowParams?: boolean;
|
|
1907
|
+
}): CompilerContext;
|
|
1900
1908
|
/**
|
|
1901
1909
|
* Formats a parameter placeholder
|
|
1902
1910
|
* @param index - Parameter index
|
|
@@ -2384,6 +2392,7 @@ declare class QueryAstService {
|
|
|
2384
2392
|
* @returns Normalized ordering term
|
|
2385
2393
|
*/
|
|
2386
2394
|
private normalizeOrderingTerm;
|
|
2395
|
+
private toParamNode;
|
|
2387
2396
|
}
|
|
2388
2397
|
|
|
2389
2398
|
/**
|
|
@@ -4312,6 +4321,11 @@ declare class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Ta
|
|
|
4312
4321
|
* Ensures that if no columns are selected, all columns from the table are selected by default.
|
|
4313
4322
|
*/
|
|
4314
4323
|
private ensureDefaultSelection;
|
|
4324
|
+
/**
|
|
4325
|
+
* Validates that the query does not contain Param operands.
|
|
4326
|
+
* Param proxies are only for schema generation, not execution.
|
|
4327
|
+
*/
|
|
4328
|
+
private validateNoParamOperands;
|
|
4315
4329
|
/**
|
|
4316
4330
|
* Executes the query and returns hydrated results.
|
|
4317
4331
|
* If the builder was created with an entity constructor (e.g. via selectFromEntity),
|
package/dist/index.js
CHANGED
|
@@ -371,16 +371,27 @@ var operandTypes = /* @__PURE__ */ new Set([
|
|
|
371
371
|
"BitwiseExpression",
|
|
372
372
|
"Collate"
|
|
373
373
|
]);
|
|
374
|
-
var
|
|
374
|
+
var getNodeType = (value) => {
|
|
375
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
376
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, "type");
|
|
377
|
+
if (descriptor && typeof descriptor.value === "string") {
|
|
378
|
+
return descriptor.value;
|
|
379
|
+
}
|
|
380
|
+
if ("type" in value) {
|
|
381
|
+
const type = value.type;
|
|
382
|
+
return typeof type === "string" ? type : void 0;
|
|
383
|
+
}
|
|
384
|
+
return void 0;
|
|
385
|
+
};
|
|
375
386
|
var isOperandNode = (node) => {
|
|
376
|
-
|
|
377
|
-
return operandTypes.has(
|
|
378
|
-
};
|
|
379
|
-
var isFunctionNode = (node) => isOperandNode(node) && node
|
|
380
|
-
var isCaseExpressionNode = (node) => isOperandNode(node) && node
|
|
381
|
-
var isCastExpressionNode = (node) => isOperandNode(node) && node
|
|
382
|
-
var isCollateExpressionNode = (node) => isOperandNode(node) && node
|
|
383
|
-
var isWindowFunctionNode = (node) => isOperandNode(node) && node
|
|
387
|
+
const type = getNodeType(node);
|
|
388
|
+
return type !== void 0 && operandTypes.has(type);
|
|
389
|
+
};
|
|
390
|
+
var isFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "Function";
|
|
391
|
+
var isCaseExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "CaseExpression";
|
|
392
|
+
var isCastExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Cast";
|
|
393
|
+
var isCollateExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Collate";
|
|
394
|
+
var isWindowFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "WindowFunction";
|
|
384
395
|
var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressionNode(node) || isCastExpressionNode(node) || isWindowFunctionNode(node);
|
|
385
396
|
|
|
386
397
|
// src/core/ast/expression-builders.ts
|
|
@@ -389,6 +400,14 @@ var toLiteralNode = (value) => ({
|
|
|
389
400
|
type: "Literal",
|
|
390
401
|
value: value instanceof Date ? value.toISOString() : value
|
|
391
402
|
});
|
|
403
|
+
var toParamNode = (value) => {
|
|
404
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
405
|
+
const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
|
|
406
|
+
if (type !== "Param") return void 0;
|
|
407
|
+
const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
|
|
408
|
+
if (typeof name !== "string") return void 0;
|
|
409
|
+
return { type: "Param", name };
|
|
410
|
+
};
|
|
392
411
|
var columnRefToNode = (col2) => {
|
|
393
412
|
if (!col2.table) {
|
|
394
413
|
throw new Error(
|
|
@@ -398,6 +417,10 @@ var columnRefToNode = (col2) => {
|
|
|
398
417
|
return { type: "Column", table: col2.table, name: col2.name };
|
|
399
418
|
};
|
|
400
419
|
var toOperandNode = (value) => {
|
|
420
|
+
const paramNode = toParamNode(value);
|
|
421
|
+
if (paramNode) {
|
|
422
|
+
return paramNode;
|
|
423
|
+
}
|
|
401
424
|
if (isOperandNode(value)) {
|
|
402
425
|
return value;
|
|
403
426
|
}
|
|
@@ -407,6 +430,10 @@ var toOperandNode = (value) => {
|
|
|
407
430
|
return columnRefToNode(value);
|
|
408
431
|
};
|
|
409
432
|
var valueToOperand = (value) => {
|
|
433
|
+
const paramNode = toParamNode(value);
|
|
434
|
+
if (paramNode) {
|
|
435
|
+
return paramNode;
|
|
436
|
+
}
|
|
410
437
|
if (isOperandNode(value)) {
|
|
411
438
|
return value;
|
|
412
439
|
}
|
|
@@ -749,17 +776,26 @@ var clearExpressionDispatchers = () => {
|
|
|
749
776
|
var clearOperandDispatchers = () => {
|
|
750
777
|
operandRegistry = operandRegistry.clear();
|
|
751
778
|
};
|
|
752
|
-
var
|
|
779
|
+
var getNodeType2 = (node) => {
|
|
780
|
+
if (typeof node !== "object" || node === null) return void 0;
|
|
781
|
+
const descriptor = Object.getOwnPropertyDescriptor(node, "type");
|
|
782
|
+
if (descriptor && typeof descriptor.value === "string") {
|
|
783
|
+
return descriptor.value;
|
|
784
|
+
}
|
|
785
|
+
const type = node.type;
|
|
786
|
+
return typeof type === "string" ? type : void 0;
|
|
787
|
+
};
|
|
753
788
|
var unsupportedExpression = (node) => {
|
|
754
|
-
throw new Error(`Unsupported expression type "${
|
|
789
|
+
throw new Error(`Unsupported expression type "${getNodeType2(node) ?? "unknown"}"`);
|
|
755
790
|
};
|
|
756
791
|
var unsupportedOperand = (node) => {
|
|
757
|
-
throw new Error(`Unsupported operand type "${
|
|
792
|
+
throw new Error(`Unsupported operand type "${getNodeType2(node) ?? "unknown"}"`);
|
|
758
793
|
};
|
|
759
794
|
var visitExpression = (node, visitor) => {
|
|
760
|
-
const
|
|
795
|
+
const type = getNodeType2(node);
|
|
796
|
+
const dynamic = type ? expressionRegistry.get(type) : void 0;
|
|
761
797
|
if (dynamic) return dynamic(node, visitor);
|
|
762
|
-
switch (
|
|
798
|
+
switch (type) {
|
|
763
799
|
case "BinaryExpression":
|
|
764
800
|
if (visitor.visitBinaryExpression) return visitor.visitBinaryExpression(node);
|
|
765
801
|
break;
|
|
@@ -791,9 +827,10 @@ var visitExpression = (node, visitor) => {
|
|
|
791
827
|
return unsupportedExpression(node);
|
|
792
828
|
};
|
|
793
829
|
var visitOperand = (node, visitor) => {
|
|
794
|
-
const
|
|
830
|
+
const type = getNodeType2(node);
|
|
831
|
+
const dynamic = type ? operandRegistry.get(type) : void 0;
|
|
795
832
|
if (dynamic) return dynamic(node, visitor);
|
|
796
|
-
switch (
|
|
833
|
+
switch (type) {
|
|
797
834
|
case "Column":
|
|
798
835
|
if (visitor.visitColumn) return visitor.visitColumn(node);
|
|
799
836
|
break;
|
|
@@ -848,7 +885,7 @@ var buildParamProxy = (name) => {
|
|
|
848
885
|
const nextName2 = name ? `${name}.${trimmed}` : trimmed;
|
|
849
886
|
return buildParamProxy(nextName2);
|
|
850
887
|
}
|
|
851
|
-
if (prop in t) {
|
|
888
|
+
if (prop in t && name === "") {
|
|
852
889
|
return t[prop];
|
|
853
890
|
}
|
|
854
891
|
const nextName = name ? `${name}.${prop}` : prop;
|
|
@@ -867,9 +904,6 @@ var createParamProxy = () => {
|
|
|
867
904
|
if (typeof prop === "string" && prop.startsWith("$")) {
|
|
868
905
|
return buildParamProxy(prop.slice(1));
|
|
869
906
|
}
|
|
870
|
-
if (prop in t) {
|
|
871
|
-
return t[prop];
|
|
872
|
-
}
|
|
873
907
|
return buildParamProxy(String(prop));
|
|
874
908
|
}
|
|
875
909
|
});
|
|
@@ -1286,6 +1320,16 @@ var Dialect = class _Dialect {
|
|
|
1286
1320
|
params: [...ctx.params]
|
|
1287
1321
|
};
|
|
1288
1322
|
}
|
|
1323
|
+
compileSelectWithOptions(ast, options = {}) {
|
|
1324
|
+
const ctx = this.createCompilerContext(options);
|
|
1325
|
+
const normalized = this.normalizeSelectAst(ast);
|
|
1326
|
+
const rawSql = this.compileSelectAst(normalized, ctx).trim();
|
|
1327
|
+
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1328
|
+
return {
|
|
1329
|
+
sql,
|
|
1330
|
+
params: [...ctx.params]
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1289
1333
|
compileInsert(ast) {
|
|
1290
1334
|
const ctx = this.createCompilerContext();
|
|
1291
1335
|
const rawSql = this.compileInsertAst(ast, ctx).trim();
|
|
@@ -1356,13 +1400,15 @@ var Dialect = class _Dialect {
|
|
|
1356
1400
|
}
|
|
1357
1401
|
/**
|
|
1358
1402
|
* Creates a new compiler context
|
|
1403
|
+
* @param options - Optional compiler context options
|
|
1359
1404
|
* @returns Compiler context with parameter management
|
|
1360
1405
|
*/
|
|
1361
|
-
createCompilerContext() {
|
|
1406
|
+
createCompilerContext(options = {}) {
|
|
1362
1407
|
const params = [];
|
|
1363
1408
|
let counter = 0;
|
|
1364
1409
|
return {
|
|
1365
1410
|
params,
|
|
1411
|
+
allowParams: options.allowParams ?? false,
|
|
1366
1412
|
addParameter: (value) => {
|
|
1367
1413
|
counter += 1;
|
|
1368
1414
|
params.push(value);
|
|
@@ -1513,9 +1559,11 @@ var Dialect = class _Dialect {
|
|
|
1513
1559
|
* @returns Compiled SQL operand
|
|
1514
1560
|
*/
|
|
1515
1561
|
compileOperand(node, ctx) {
|
|
1516
|
-
const
|
|
1562
|
+
const descriptor = Object.getOwnPropertyDescriptor(node, "type");
|
|
1563
|
+
const nodeType = typeof descriptor?.value === "string" ? descriptor.value : typeof node.type === "string" ? node.type : void 0;
|
|
1564
|
+
const compiler = nodeType ? this.operandCompilers.get(nodeType) : void 0;
|
|
1517
1565
|
if (!compiler) {
|
|
1518
|
-
throw new Error(`Unsupported operand node type "${
|
|
1566
|
+
throw new Error(`Unsupported operand node type "${nodeType ?? "unknown"}" for ${this.constructor.name}`);
|
|
1519
1567
|
}
|
|
1520
1568
|
return compiler(node, ctx);
|
|
1521
1569
|
}
|
|
@@ -1584,7 +1632,12 @@ var Dialect = class _Dialect {
|
|
|
1584
1632
|
}
|
|
1585
1633
|
registerDefaultOperandCompilers() {
|
|
1586
1634
|
this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
|
|
1587
|
-
this.registerOperandCompiler("Param", (_param, ctx) =>
|
|
1635
|
+
this.registerOperandCompiler("Param", (_param, ctx) => {
|
|
1636
|
+
if (!ctx.allowParams) {
|
|
1637
|
+
throw new Error("Cannot compile query with Param operands. Param proxies are only for schema generation (getSchema()). If you need real parameters, use literal values.");
|
|
1638
|
+
}
|
|
1639
|
+
return ctx.addParameter(null);
|
|
1640
|
+
});
|
|
1588
1641
|
this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
|
|
1589
1642
|
void _ctx;
|
|
1590
1643
|
return this.quoteIdentifier(alias.name);
|
|
@@ -3831,6 +3884,10 @@ var QueryAstService = class {
|
|
|
3831
3884
|
* @returns Normalized ordering term
|
|
3832
3885
|
*/
|
|
3833
3886
|
normalizeOrderingTerm(term) {
|
|
3887
|
+
const paramNode = this.toParamNode(term);
|
|
3888
|
+
if (paramNode) {
|
|
3889
|
+
return paramNode;
|
|
3890
|
+
}
|
|
3834
3891
|
const from = this.state.ast.from;
|
|
3835
3892
|
const tableRef2 = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
3836
3893
|
const termType = term.type;
|
|
@@ -3848,6 +3905,14 @@ var QueryAstService = class {
|
|
|
3848
3905
|
}
|
|
3849
3906
|
return buildColumnNode(tableRef2, term);
|
|
3850
3907
|
}
|
|
3908
|
+
toParamNode(value) {
|
|
3909
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
3910
|
+
const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
|
|
3911
|
+
if (type !== "Param") return void 0;
|
|
3912
|
+
const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
|
|
3913
|
+
if (typeof name !== "string") return void 0;
|
|
3914
|
+
return { type: "Param", name };
|
|
3915
|
+
}
|
|
3851
3916
|
};
|
|
3852
3917
|
|
|
3853
3918
|
// src/query-builder/relation-projection-helper.ts
|
|
@@ -7302,7 +7367,7 @@ var collectFilterColumns = (expr, table, rootTables) => {
|
|
|
7302
7367
|
columns.add(node.name);
|
|
7303
7368
|
}
|
|
7304
7369
|
};
|
|
7305
|
-
const
|
|
7370
|
+
const visitOrderingTerm2 = (term) => {
|
|
7306
7371
|
if (!term || typeof term !== "object") return;
|
|
7307
7372
|
if (isOperandNode(term)) {
|
|
7308
7373
|
visitOperand2(term);
|
|
@@ -7314,7 +7379,7 @@ var collectFilterColumns = (expr, table, rootTables) => {
|
|
|
7314
7379
|
};
|
|
7315
7380
|
const visitOrderBy = (orderBy) => {
|
|
7316
7381
|
if (!orderBy) return;
|
|
7317
|
-
orderBy.forEach((node) =>
|
|
7382
|
+
orderBy.forEach((node) => visitOrderingTerm2(node.term));
|
|
7318
7383
|
};
|
|
7319
7384
|
const visitOperand2 = (node) => {
|
|
7320
7385
|
switch (node.type) {
|
|
@@ -7453,6 +7518,198 @@ var buildFilterParameters = (table, where, from, options = {}) => {
|
|
|
7453
7518
|
}];
|
|
7454
7519
|
};
|
|
7455
7520
|
|
|
7521
|
+
// src/core/ast/query-visitor.ts
|
|
7522
|
+
var getNodeType3 = (value) => {
|
|
7523
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
7524
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, "type");
|
|
7525
|
+
if (descriptor && typeof descriptor.value === "string") {
|
|
7526
|
+
return descriptor.value;
|
|
7527
|
+
}
|
|
7528
|
+
if ("type" in value) {
|
|
7529
|
+
const type = value.type;
|
|
7530
|
+
return typeof type === "string" ? type : void 0;
|
|
7531
|
+
}
|
|
7532
|
+
return void 0;
|
|
7533
|
+
};
|
|
7534
|
+
var visitOrderingTerm = (term, visitor) => {
|
|
7535
|
+
if (isOperandNode(term)) {
|
|
7536
|
+
visitOperandNode(term, visitor);
|
|
7537
|
+
return;
|
|
7538
|
+
}
|
|
7539
|
+
visitExpressionNode(term, visitor);
|
|
7540
|
+
};
|
|
7541
|
+
var visitOrderByNode = (node, visitor) => {
|
|
7542
|
+
visitor.visitOrderBy?.(node);
|
|
7543
|
+
visitOrderingTerm(node.term, visitor);
|
|
7544
|
+
};
|
|
7545
|
+
var visitTableSource = (source, visitor) => {
|
|
7546
|
+
visitor.visitTableSource?.(source);
|
|
7547
|
+
if (source.type === "DerivedTable") {
|
|
7548
|
+
visitor.visitDerivedTable?.(source);
|
|
7549
|
+
visitSelectQuery(source.query, visitor);
|
|
7550
|
+
return;
|
|
7551
|
+
}
|
|
7552
|
+
if (source.type === "FunctionTable") {
|
|
7553
|
+
visitor.visitFunctionTable?.(source);
|
|
7554
|
+
source.args?.forEach((arg) => visitOperandNode(arg, visitor));
|
|
7555
|
+
}
|
|
7556
|
+
};
|
|
7557
|
+
var visitExpressionNode = (node, visitor) => {
|
|
7558
|
+
visitor.visitExpression?.(node);
|
|
7559
|
+
const type = getNodeType3(node);
|
|
7560
|
+
if (!type) return;
|
|
7561
|
+
switch (type) {
|
|
7562
|
+
case "BinaryExpression":
|
|
7563
|
+
visitOperandNode(node.left, visitor);
|
|
7564
|
+
visitOperandNode(node.right, visitor);
|
|
7565
|
+
if (node.escape) {
|
|
7566
|
+
visitOperandNode(node.escape, visitor);
|
|
7567
|
+
}
|
|
7568
|
+
return;
|
|
7569
|
+
case "LogicalExpression":
|
|
7570
|
+
node.operands.forEach((operand) => visitExpressionNode(operand, visitor));
|
|
7571
|
+
return;
|
|
7572
|
+
case "NullExpression":
|
|
7573
|
+
visitOperandNode(node.left, visitor);
|
|
7574
|
+
return;
|
|
7575
|
+
case "InExpression":
|
|
7576
|
+
visitOperandNode(node.left, visitor);
|
|
7577
|
+
if (Array.isArray(node.right)) {
|
|
7578
|
+
node.right.forEach((operand) => visitOperandNode(operand, visitor));
|
|
7579
|
+
} else {
|
|
7580
|
+
visitOperandNode(node.right, visitor);
|
|
7581
|
+
}
|
|
7582
|
+
return;
|
|
7583
|
+
case "ExistsExpression":
|
|
7584
|
+
visitSelectQuery(node.subquery, visitor);
|
|
7585
|
+
return;
|
|
7586
|
+
case "BetweenExpression":
|
|
7587
|
+
visitOperandNode(node.left, visitor);
|
|
7588
|
+
visitOperandNode(node.lower, visitor);
|
|
7589
|
+
visitOperandNode(node.upper, visitor);
|
|
7590
|
+
return;
|
|
7591
|
+
case "ArithmeticExpression":
|
|
7592
|
+
visitOperandNode(node.left, visitor);
|
|
7593
|
+
visitOperandNode(node.right, visitor);
|
|
7594
|
+
return;
|
|
7595
|
+
case "BitwiseExpression":
|
|
7596
|
+
visitOperandNode(node.left, visitor);
|
|
7597
|
+
visitOperandNode(node.right, visitor);
|
|
7598
|
+
return;
|
|
7599
|
+
default: {
|
|
7600
|
+
return;
|
|
7601
|
+
}
|
|
7602
|
+
}
|
|
7603
|
+
};
|
|
7604
|
+
var visitOperandNode = (node, visitor) => {
|
|
7605
|
+
visitor.visitOperand?.(node);
|
|
7606
|
+
const type = getNodeType3(node);
|
|
7607
|
+
if (type === "Param") {
|
|
7608
|
+
visitor.visitParam?.(node);
|
|
7609
|
+
}
|
|
7610
|
+
if (!type) return;
|
|
7611
|
+
switch (type) {
|
|
7612
|
+
case "Column":
|
|
7613
|
+
case "Literal":
|
|
7614
|
+
case "Param":
|
|
7615
|
+
case "AliasRef":
|
|
7616
|
+
return;
|
|
7617
|
+
case "Function":
|
|
7618
|
+
node.args?.forEach((arg) => visitOperandNode(arg, visitor));
|
|
7619
|
+
node.orderBy?.forEach((order) => visitOrderByNode(order, visitor));
|
|
7620
|
+
if (node.separator) {
|
|
7621
|
+
visitOperandNode(node.separator, visitor);
|
|
7622
|
+
}
|
|
7623
|
+
return;
|
|
7624
|
+
case "JsonPath":
|
|
7625
|
+
visitOperandNode(node.column, visitor);
|
|
7626
|
+
return;
|
|
7627
|
+
case "ScalarSubquery":
|
|
7628
|
+
visitSelectQuery(node.query, visitor);
|
|
7629
|
+
return;
|
|
7630
|
+
case "CaseExpression":
|
|
7631
|
+
node.conditions.forEach((cond) => {
|
|
7632
|
+
visitExpressionNode(cond.when, visitor);
|
|
7633
|
+
visitOperandNode(cond.then, visitor);
|
|
7634
|
+
});
|
|
7635
|
+
if (node.else) {
|
|
7636
|
+
visitOperandNode(node.else, visitor);
|
|
7637
|
+
}
|
|
7638
|
+
return;
|
|
7639
|
+
case "Cast":
|
|
7640
|
+
visitOperandNode(node.expression, visitor);
|
|
7641
|
+
return;
|
|
7642
|
+
case "WindowFunction":
|
|
7643
|
+
node.args?.forEach((arg) => visitOperandNode(arg, visitor));
|
|
7644
|
+
node.partitionBy?.forEach((term) => visitOperandNode(term, visitor));
|
|
7645
|
+
node.orderBy?.forEach((order) => visitOrderByNode(order, visitor));
|
|
7646
|
+
return;
|
|
7647
|
+
case "ArithmeticExpression":
|
|
7648
|
+
visitOperandNode(node.left, visitor);
|
|
7649
|
+
visitOperandNode(node.right, visitor);
|
|
7650
|
+
return;
|
|
7651
|
+
case "BitwiseExpression":
|
|
7652
|
+
visitOperandNode(node.left, visitor);
|
|
7653
|
+
visitOperandNode(node.right, visitor);
|
|
7654
|
+
return;
|
|
7655
|
+
case "Collate":
|
|
7656
|
+
visitOperandNode(node.expression, visitor);
|
|
7657
|
+
return;
|
|
7658
|
+
default: {
|
|
7659
|
+
const _exhaustive = node;
|
|
7660
|
+
return _exhaustive;
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
};
|
|
7664
|
+
var visitSelectQuery = (ast, visitor) => {
|
|
7665
|
+
visitor.visitSelectQuery?.(ast);
|
|
7666
|
+
if (ast.ctes) {
|
|
7667
|
+
for (const cte of ast.ctes) {
|
|
7668
|
+
visitor.visitCte?.(cte);
|
|
7669
|
+
visitSelectQuery(cte.query, visitor);
|
|
7670
|
+
}
|
|
7671
|
+
}
|
|
7672
|
+
visitTableSource(ast.from, visitor);
|
|
7673
|
+
ast.columns?.forEach((col2) => {
|
|
7674
|
+
visitOperandNode(col2, visitor);
|
|
7675
|
+
});
|
|
7676
|
+
ast.joins?.forEach((join) => {
|
|
7677
|
+
visitor.visitJoin?.(join);
|
|
7678
|
+
visitTableSource(join.table, visitor);
|
|
7679
|
+
visitExpressionNode(join.condition, visitor);
|
|
7680
|
+
});
|
|
7681
|
+
if (ast.where) {
|
|
7682
|
+
visitExpressionNode(ast.where, visitor);
|
|
7683
|
+
}
|
|
7684
|
+
ast.groupBy?.forEach((term) => {
|
|
7685
|
+
visitOrderingTerm(term, visitor);
|
|
7686
|
+
});
|
|
7687
|
+
if (ast.having) {
|
|
7688
|
+
visitExpressionNode(ast.having, visitor);
|
|
7689
|
+
}
|
|
7690
|
+
ast.orderBy?.forEach((order) => {
|
|
7691
|
+
visitOrderByNode(order, visitor);
|
|
7692
|
+
});
|
|
7693
|
+
ast.distinct?.forEach((col2) => {
|
|
7694
|
+
visitOperandNode(col2, visitor);
|
|
7695
|
+
});
|
|
7696
|
+
ast.setOps?.forEach((op) => {
|
|
7697
|
+
visitor.visitSetOperation?.(op);
|
|
7698
|
+
visitSelectQuery(op.query, visitor);
|
|
7699
|
+
});
|
|
7700
|
+
};
|
|
7701
|
+
|
|
7702
|
+
// src/core/ast/ast-validation.ts
|
|
7703
|
+
var hasParamOperandsInQuery = (ast) => {
|
|
7704
|
+
let hasParams = false;
|
|
7705
|
+
visitSelectQuery(ast, {
|
|
7706
|
+
visitParam: () => {
|
|
7707
|
+
hasParams = true;
|
|
7708
|
+
}
|
|
7709
|
+
});
|
|
7710
|
+
return hasParams;
|
|
7711
|
+
};
|
|
7712
|
+
|
|
7456
7713
|
// src/query-builder/select.ts
|
|
7457
7714
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
7458
7715
|
env;
|
|
@@ -7926,6 +8183,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
7926
8183
|
}
|
|
7927
8184
|
return this;
|
|
7928
8185
|
}
|
|
8186
|
+
/**
|
|
8187
|
+
* Validates that the query does not contain Param operands.
|
|
8188
|
+
* Param proxies are only for schema generation, not execution.
|
|
8189
|
+
*/
|
|
8190
|
+
validateNoParamOperands() {
|
|
8191
|
+
const ast = this.context.hydration.applyToAst(this.context.state.ast);
|
|
8192
|
+
const hasParams = hasParamOperandsInQuery(ast);
|
|
8193
|
+
if (hasParams) {
|
|
8194
|
+
throw new Error("Cannot execute query containing Param operands. Param proxies are only for schema generation (getSchema()). If you need real parameters, use literal values.");
|
|
8195
|
+
}
|
|
8196
|
+
}
|
|
7929
8197
|
/**
|
|
7930
8198
|
* Executes the query and returns hydrated results.
|
|
7931
8199
|
* If the builder was created with an entity constructor (e.g. via selectFromEntity),
|
|
@@ -7939,6 +8207,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
7939
8207
|
* users[0] instanceof User; // true
|
|
7940
8208
|
*/
|
|
7941
8209
|
async execute(ctx) {
|
|
8210
|
+
this.validateNoParamOperands();
|
|
7942
8211
|
if (this.entityConstructor) {
|
|
7943
8212
|
return this.executeAs(this.entityConstructor, ctx);
|
|
7944
8213
|
}
|
|
@@ -7957,6 +8226,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
7957
8226
|
* rows[0] instanceof User; // false
|
|
7958
8227
|
*/
|
|
7959
8228
|
async executePlain(ctx) {
|
|
8229
|
+
this.validateNoParamOperands();
|
|
7960
8230
|
const builder = this.ensureDefaultSelection();
|
|
7961
8231
|
const rows = await executeHydratedPlain(ctx, builder);
|
|
7962
8232
|
return rows;
|
|
@@ -7976,6 +8246,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
7976
8246
|
* users[0].getFullName(); // works!
|
|
7977
8247
|
*/
|
|
7978
8248
|
async executeAs(entityClass, ctx) {
|
|
8249
|
+
this.validateNoParamOperands();
|
|
7979
8250
|
const builder = this.ensureDefaultSelection();
|
|
7980
8251
|
const results = await executeHydrated(ctx, builder);
|
|
7981
8252
|
return materializeAs(entityClass, results);
|
|
@@ -7987,6 +8258,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
7987
8258
|
* const total = await qb.count(session);
|
|
7988
8259
|
*/
|
|
7989
8260
|
async count(session) {
|
|
8261
|
+
this.validateNoParamOperands();
|
|
7990
8262
|
return executeCount(this.context, this.env, session);
|
|
7991
8263
|
}
|
|
7992
8264
|
/**
|
|
@@ -7996,6 +8268,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
7996
8268
|
* const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
7997
8269
|
*/
|
|
7998
8270
|
async executePaged(session, options) {
|
|
8271
|
+
this.validateNoParamOperands();
|
|
7999
8272
|
const builder = this.ensureDefaultSelection();
|
|
8000
8273
|
return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
|
|
8001
8274
|
}
|
|
@@ -8010,6 +8283,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8010
8283
|
* const users = await qb.executeWithContexts(execCtx, hydCtx);
|
|
8011
8284
|
*/
|
|
8012
8285
|
async executeWithContexts(execCtx, hydCtx) {
|
|
8286
|
+
this.validateNoParamOperands();
|
|
8013
8287
|
const builder = this.ensureDefaultSelection();
|
|
8014
8288
|
const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
|
|
8015
8289
|
if (this.entityConstructor) {
|