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 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) => ctx.addParameter(null));
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) {