metal-orm 1.0.82 → 1.0.83
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 +274 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +274 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ast/ast-validation.ts +188 -0
- package/src/core/ast/expression-builders.ts +43 -24
- package/src/core/ast/param-proxy.ts +1 -4
- package/src/core/dialect/abstract.ts +59 -39
- package/src/query-builder/select.ts +128 -109
package/dist/index.cjs
CHANGED
|
@@ -673,6 +673,14 @@ var toLiteralNode = (value) => ({
|
|
|
673
673
|
type: "Literal",
|
|
674
674
|
value: value instanceof Date ? value.toISOString() : value
|
|
675
675
|
});
|
|
676
|
+
var toParamNode = (value) => {
|
|
677
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
678
|
+
const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
|
|
679
|
+
if (type !== "Param") return void 0;
|
|
680
|
+
const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
|
|
681
|
+
if (typeof name !== "string") return void 0;
|
|
682
|
+
return { type: "Param", name };
|
|
683
|
+
};
|
|
676
684
|
var columnRefToNode = (col2) => {
|
|
677
685
|
if (!col2.table) {
|
|
678
686
|
throw new Error(
|
|
@@ -682,6 +690,10 @@ var columnRefToNode = (col2) => {
|
|
|
682
690
|
return { type: "Column", table: col2.table, name: col2.name };
|
|
683
691
|
};
|
|
684
692
|
var toOperandNode = (value) => {
|
|
693
|
+
const paramNode = toParamNode(value);
|
|
694
|
+
if (paramNode) {
|
|
695
|
+
return paramNode;
|
|
696
|
+
}
|
|
685
697
|
if (isOperandNode(value)) {
|
|
686
698
|
return value;
|
|
687
699
|
}
|
|
@@ -691,6 +703,10 @@ var toOperandNode = (value) => {
|
|
|
691
703
|
return columnRefToNode(value);
|
|
692
704
|
};
|
|
693
705
|
var valueToOperand = (value) => {
|
|
706
|
+
const paramNode = toParamNode(value);
|
|
707
|
+
if (paramNode) {
|
|
708
|
+
return paramNode;
|
|
709
|
+
}
|
|
694
710
|
if (isOperandNode(value)) {
|
|
695
711
|
return value;
|
|
696
712
|
}
|
|
@@ -1132,7 +1148,7 @@ var buildParamProxy = (name) => {
|
|
|
1132
1148
|
const nextName2 = name ? `${name}.${trimmed}` : trimmed;
|
|
1133
1149
|
return buildParamProxy(nextName2);
|
|
1134
1150
|
}
|
|
1135
|
-
if (prop in t) {
|
|
1151
|
+
if (prop in t && name === "") {
|
|
1136
1152
|
return t[prop];
|
|
1137
1153
|
}
|
|
1138
1154
|
const nextName = name ? `${name}.${prop}` : prop;
|
|
@@ -1151,9 +1167,6 @@ var createParamProxy = () => {
|
|
|
1151
1167
|
if (typeof prop === "string" && prop.startsWith("$")) {
|
|
1152
1168
|
return buildParamProxy(prop.slice(1));
|
|
1153
1169
|
}
|
|
1154
|
-
if (prop in t) {
|
|
1155
|
-
return t[prop];
|
|
1156
|
-
}
|
|
1157
1170
|
return buildParamProxy(String(prop));
|
|
1158
1171
|
}
|
|
1159
1172
|
});
|
|
@@ -1570,6 +1583,16 @@ var Dialect = class _Dialect {
|
|
|
1570
1583
|
params: [...ctx.params]
|
|
1571
1584
|
};
|
|
1572
1585
|
}
|
|
1586
|
+
compileSelectWithOptions(ast, options = {}) {
|
|
1587
|
+
const ctx = this.createCompilerContext(options);
|
|
1588
|
+
const normalized = this.normalizeSelectAst(ast);
|
|
1589
|
+
const rawSql = this.compileSelectAst(normalized, ctx).trim();
|
|
1590
|
+
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1591
|
+
return {
|
|
1592
|
+
sql,
|
|
1593
|
+
params: [...ctx.params]
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1573
1596
|
compileInsert(ast) {
|
|
1574
1597
|
const ctx = this.createCompilerContext();
|
|
1575
1598
|
const rawSql = this.compileInsertAst(ast, ctx).trim();
|
|
@@ -1640,13 +1663,15 @@ var Dialect = class _Dialect {
|
|
|
1640
1663
|
}
|
|
1641
1664
|
/**
|
|
1642
1665
|
* Creates a new compiler context
|
|
1666
|
+
* @param options - Optional compiler context options
|
|
1643
1667
|
* @returns Compiler context with parameter management
|
|
1644
1668
|
*/
|
|
1645
|
-
createCompilerContext() {
|
|
1669
|
+
createCompilerContext(options = {}) {
|
|
1646
1670
|
const params = [];
|
|
1647
1671
|
let counter = 0;
|
|
1648
1672
|
return {
|
|
1649
1673
|
params,
|
|
1674
|
+
allowParams: options.allowParams ?? false,
|
|
1650
1675
|
addParameter: (value) => {
|
|
1651
1676
|
counter += 1;
|
|
1652
1677
|
params.push(value);
|
|
@@ -1868,7 +1893,12 @@ var Dialect = class _Dialect {
|
|
|
1868
1893
|
}
|
|
1869
1894
|
registerDefaultOperandCompilers() {
|
|
1870
1895
|
this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
|
|
1871
|
-
this.registerOperandCompiler("Param", (_param, ctx) =>
|
|
1896
|
+
this.registerOperandCompiler("Param", (_param, ctx) => {
|
|
1897
|
+
if (!ctx.allowParams) {
|
|
1898
|
+
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.");
|
|
1899
|
+
}
|
|
1900
|
+
return ctx.addParameter(null);
|
|
1901
|
+
});
|
|
1872
1902
|
this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
|
|
1873
1903
|
void _ctx;
|
|
1874
1904
|
return this.quoteIdentifier(alias.name);
|
|
@@ -7737,6 +7767,227 @@ var buildFilterParameters = (table, where, from, options = {}) => {
|
|
|
7737
7767
|
}];
|
|
7738
7768
|
};
|
|
7739
7769
|
|
|
7770
|
+
// src/core/ast/ast-validation.ts
|
|
7771
|
+
var hasParamOperandsInExpression = (expr) => {
|
|
7772
|
+
let hasParams = false;
|
|
7773
|
+
visitExpression(expr, {
|
|
7774
|
+
visitBinaryExpression: (node) => {
|
|
7775
|
+
visitOperand(node.left, {
|
|
7776
|
+
visitParam: () => {
|
|
7777
|
+
hasParams = true;
|
|
7778
|
+
},
|
|
7779
|
+
otherwise: () => {
|
|
7780
|
+
}
|
|
7781
|
+
});
|
|
7782
|
+
visitOperand(node.right, {
|
|
7783
|
+
visitParam: () => {
|
|
7784
|
+
hasParams = true;
|
|
7785
|
+
},
|
|
7786
|
+
otherwise: () => {
|
|
7787
|
+
}
|
|
7788
|
+
});
|
|
7789
|
+
if (node.escape) {
|
|
7790
|
+
visitOperand(node.escape, {
|
|
7791
|
+
visitParam: () => {
|
|
7792
|
+
hasParams = true;
|
|
7793
|
+
},
|
|
7794
|
+
otherwise: () => {
|
|
7795
|
+
}
|
|
7796
|
+
});
|
|
7797
|
+
}
|
|
7798
|
+
},
|
|
7799
|
+
visitLogicalExpression: (node) => {
|
|
7800
|
+
node.operands.forEach((operand) => {
|
|
7801
|
+
if (hasParamOperandsInExpression(operand)) {
|
|
7802
|
+
hasParams = true;
|
|
7803
|
+
}
|
|
7804
|
+
});
|
|
7805
|
+
},
|
|
7806
|
+
visitNullExpression: () => {
|
|
7807
|
+
},
|
|
7808
|
+
visitInExpression: (node) => {
|
|
7809
|
+
visitOperand(node.left, {
|
|
7810
|
+
visitParam: () => {
|
|
7811
|
+
hasParams = true;
|
|
7812
|
+
},
|
|
7813
|
+
otherwise: () => {
|
|
7814
|
+
}
|
|
7815
|
+
});
|
|
7816
|
+
if (Array.isArray(node.right)) {
|
|
7817
|
+
node.right.forEach((operand) => visitOperand(operand, {
|
|
7818
|
+
visitParam: () => {
|
|
7819
|
+
hasParams = true;
|
|
7820
|
+
},
|
|
7821
|
+
otherwise: () => {
|
|
7822
|
+
}
|
|
7823
|
+
}));
|
|
7824
|
+
}
|
|
7825
|
+
},
|
|
7826
|
+
visitExistsExpression: () => {
|
|
7827
|
+
},
|
|
7828
|
+
visitBetweenExpression: (node) => {
|
|
7829
|
+
visitOperand(node.left, {
|
|
7830
|
+
visitParam: () => {
|
|
7831
|
+
hasParams = true;
|
|
7832
|
+
},
|
|
7833
|
+
otherwise: () => {
|
|
7834
|
+
}
|
|
7835
|
+
});
|
|
7836
|
+
visitOperand(node.lower, {
|
|
7837
|
+
visitParam: () => {
|
|
7838
|
+
hasParams = true;
|
|
7839
|
+
},
|
|
7840
|
+
otherwise: () => {
|
|
7841
|
+
}
|
|
7842
|
+
});
|
|
7843
|
+
visitOperand(node.upper, {
|
|
7844
|
+
visitParam: () => {
|
|
7845
|
+
hasParams = true;
|
|
7846
|
+
},
|
|
7847
|
+
otherwise: () => {
|
|
7848
|
+
}
|
|
7849
|
+
});
|
|
7850
|
+
},
|
|
7851
|
+
visitArithmeticExpression: (node) => {
|
|
7852
|
+
visitOperand(node.left, {
|
|
7853
|
+
visitParam: () => {
|
|
7854
|
+
hasParams = true;
|
|
7855
|
+
},
|
|
7856
|
+
otherwise: () => {
|
|
7857
|
+
}
|
|
7858
|
+
});
|
|
7859
|
+
visitOperand(node.right, {
|
|
7860
|
+
visitParam: () => {
|
|
7861
|
+
hasParams = true;
|
|
7862
|
+
},
|
|
7863
|
+
otherwise: () => {
|
|
7864
|
+
}
|
|
7865
|
+
});
|
|
7866
|
+
},
|
|
7867
|
+
visitBitwiseExpression: (node) => {
|
|
7868
|
+
visitOperand(node.left, {
|
|
7869
|
+
visitParam: () => {
|
|
7870
|
+
hasParams = true;
|
|
7871
|
+
},
|
|
7872
|
+
otherwise: () => {
|
|
7873
|
+
}
|
|
7874
|
+
});
|
|
7875
|
+
visitOperand(node.right, {
|
|
7876
|
+
visitParam: () => {
|
|
7877
|
+
hasParams = true;
|
|
7878
|
+
},
|
|
7879
|
+
otherwise: () => {
|
|
7880
|
+
}
|
|
7881
|
+
});
|
|
7882
|
+
},
|
|
7883
|
+
otherwise: () => {
|
|
7884
|
+
}
|
|
7885
|
+
});
|
|
7886
|
+
return hasParams;
|
|
7887
|
+
};
|
|
7888
|
+
var hasParamOperandsInOperand = (operand) => {
|
|
7889
|
+
let hasParams = false;
|
|
7890
|
+
visitOperand(operand, {
|
|
7891
|
+
visitColumn: () => {
|
|
7892
|
+
},
|
|
7893
|
+
visitLiteral: () => {
|
|
7894
|
+
},
|
|
7895
|
+
visitParam: () => {
|
|
7896
|
+
hasParams = true;
|
|
7897
|
+
},
|
|
7898
|
+
visitFunction: (node) => {
|
|
7899
|
+
node.args?.forEach((arg) => {
|
|
7900
|
+
if (hasParamOperandsInOperand(arg)) {
|
|
7901
|
+
hasParams = true;
|
|
7902
|
+
}
|
|
7903
|
+
});
|
|
7904
|
+
},
|
|
7905
|
+
visitJsonPath: () => {
|
|
7906
|
+
},
|
|
7907
|
+
visitScalarSubquery: () => {
|
|
7908
|
+
},
|
|
7909
|
+
visitCaseExpression: (node) => {
|
|
7910
|
+
node.conditions.forEach((cond) => {
|
|
7911
|
+
if (hasParamOperandsInExpression(cond.when)) {
|
|
7912
|
+
hasParams = true;
|
|
7913
|
+
}
|
|
7914
|
+
if (hasParamOperandsInOperand(cond.then)) {
|
|
7915
|
+
hasParams = true;
|
|
7916
|
+
}
|
|
7917
|
+
});
|
|
7918
|
+
if (node.else && hasParamOperandsInOperand(node.else)) {
|
|
7919
|
+
hasParams = true;
|
|
7920
|
+
}
|
|
7921
|
+
},
|
|
7922
|
+
visitCast: (node) => {
|
|
7923
|
+
if (hasParamOperandsInOperand(node.expression)) {
|
|
7924
|
+
hasParams = true;
|
|
7925
|
+
}
|
|
7926
|
+
},
|
|
7927
|
+
visitWindowFunction: (node) => {
|
|
7928
|
+
node.args?.forEach((arg) => {
|
|
7929
|
+
if (hasParamOperandsInOperand(arg)) {
|
|
7930
|
+
hasParams = true;
|
|
7931
|
+
}
|
|
7932
|
+
});
|
|
7933
|
+
node.orderBy?.forEach((ord) => {
|
|
7934
|
+
if (ord.term) {
|
|
7935
|
+
if (hasParamOperandsInOperand(ord.term)) {
|
|
7936
|
+
hasParams = true;
|
|
7937
|
+
}
|
|
7938
|
+
}
|
|
7939
|
+
});
|
|
7940
|
+
},
|
|
7941
|
+
visitCollate: (node) => {
|
|
7942
|
+
if (hasParamOperandsInOperand(node.expression)) {
|
|
7943
|
+
hasParams = true;
|
|
7944
|
+
}
|
|
7945
|
+
},
|
|
7946
|
+
visitAliasRef: () => {
|
|
7947
|
+
},
|
|
7948
|
+
otherwise: () => {
|
|
7949
|
+
}
|
|
7950
|
+
});
|
|
7951
|
+
return hasParams;
|
|
7952
|
+
};
|
|
7953
|
+
var hasParamOperandsInQuery = (ast) => {
|
|
7954
|
+
if (ast.where && hasParamOperandsInExpression(ast.where)) {
|
|
7955
|
+
return true;
|
|
7956
|
+
}
|
|
7957
|
+
if (ast.having && hasParamOperandsInExpression(ast.having)) {
|
|
7958
|
+
return true;
|
|
7959
|
+
}
|
|
7960
|
+
ast.columns?.forEach((col2) => {
|
|
7961
|
+
if (typeof col2 === "object" && col2 !== null && "type" in col2) {
|
|
7962
|
+
if (hasParamOperandsInOperand(col2)) {
|
|
7963
|
+
return true;
|
|
7964
|
+
}
|
|
7965
|
+
}
|
|
7966
|
+
});
|
|
7967
|
+
ast.orderBy?.forEach((ord) => {
|
|
7968
|
+
if (ord.term) {
|
|
7969
|
+
if (hasParamOperandsInOperand(ord.term)) {
|
|
7970
|
+
return true;
|
|
7971
|
+
}
|
|
7972
|
+
}
|
|
7973
|
+
});
|
|
7974
|
+
if (ast.ctes) {
|
|
7975
|
+
for (const cte of ast.ctes) {
|
|
7976
|
+
if (cte.query.where && hasParamOperandsInExpression(cte.query.where)) {
|
|
7977
|
+
return true;
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
}
|
|
7981
|
+
if (ast.setOps) {
|
|
7982
|
+
for (const op of ast.setOps) {
|
|
7983
|
+
if (hasParamOperandsInQuery(op.query)) {
|
|
7984
|
+
return true;
|
|
7985
|
+
}
|
|
7986
|
+
}
|
|
7987
|
+
}
|
|
7988
|
+
return false;
|
|
7989
|
+
};
|
|
7990
|
+
|
|
7740
7991
|
// src/query-builder/select.ts
|
|
7741
7992
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
7742
7993
|
env;
|
|
@@ -8210,6 +8461,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8210
8461
|
}
|
|
8211
8462
|
return this;
|
|
8212
8463
|
}
|
|
8464
|
+
/**
|
|
8465
|
+
* Validates that the query does not contain Param operands.
|
|
8466
|
+
* Param proxies are only for schema generation, not execution.
|
|
8467
|
+
*/
|
|
8468
|
+
validateNoParamOperands() {
|
|
8469
|
+
const ast = this.context.hydration.applyToAst(this.context.state.ast);
|
|
8470
|
+
const hasParams = hasParamOperandsInQuery(ast);
|
|
8471
|
+
if (hasParams) {
|
|
8472
|
+
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.");
|
|
8473
|
+
}
|
|
8474
|
+
}
|
|
8213
8475
|
/**
|
|
8214
8476
|
* Executes the query and returns hydrated results.
|
|
8215
8477
|
* If the builder was created with an entity constructor (e.g. via selectFromEntity),
|
|
@@ -8223,6 +8485,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8223
8485
|
* users[0] instanceof User; // true
|
|
8224
8486
|
*/
|
|
8225
8487
|
async execute(ctx) {
|
|
8488
|
+
this.validateNoParamOperands();
|
|
8226
8489
|
if (this.entityConstructor) {
|
|
8227
8490
|
return this.executeAs(this.entityConstructor, ctx);
|
|
8228
8491
|
}
|
|
@@ -8241,6 +8504,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8241
8504
|
* rows[0] instanceof User; // false
|
|
8242
8505
|
*/
|
|
8243
8506
|
async executePlain(ctx) {
|
|
8507
|
+
this.validateNoParamOperands();
|
|
8244
8508
|
const builder = this.ensureDefaultSelection();
|
|
8245
8509
|
const rows = await executeHydratedPlain(ctx, builder);
|
|
8246
8510
|
return rows;
|
|
@@ -8260,6 +8524,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8260
8524
|
* users[0].getFullName(); // works!
|
|
8261
8525
|
*/
|
|
8262
8526
|
async executeAs(entityClass, ctx) {
|
|
8527
|
+
this.validateNoParamOperands();
|
|
8263
8528
|
const builder = this.ensureDefaultSelection();
|
|
8264
8529
|
const results = await executeHydrated(ctx, builder);
|
|
8265
8530
|
return materializeAs(entityClass, results);
|
|
@@ -8271,6 +8536,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8271
8536
|
* const total = await qb.count(session);
|
|
8272
8537
|
*/
|
|
8273
8538
|
async count(session) {
|
|
8539
|
+
this.validateNoParamOperands();
|
|
8274
8540
|
return executeCount(this.context, this.env, session);
|
|
8275
8541
|
}
|
|
8276
8542
|
/**
|
|
@@ -8280,6 +8546,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8280
8546
|
* const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
8281
8547
|
*/
|
|
8282
8548
|
async executePaged(session, options) {
|
|
8549
|
+
this.validateNoParamOperands();
|
|
8283
8550
|
const builder = this.ensureDefaultSelection();
|
|
8284
8551
|
return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
|
|
8285
8552
|
}
|
|
@@ -8294,6 +8561,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8294
8561
|
* const users = await qb.executeWithContexts(execCtx, hydCtx);
|
|
8295
8562
|
*/
|
|
8296
8563
|
async executeWithContexts(execCtx, hydCtx) {
|
|
8564
|
+
this.validateNoParamOperands();
|
|
8297
8565
|
const builder = this.ensureDefaultSelection();
|
|
8298
8566
|
const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
|
|
8299
8567
|
if (this.entityConstructor) {
|