metal-orm 1.0.81 → 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
@@ -123,6 +123,7 @@ __export(index_exports, {
123
123
  createExecutorFromQueryRunner: () => createExecutorFromQueryRunner,
124
124
  createMssqlExecutor: () => createMssqlExecutor,
125
125
  createMysqlExecutor: () => createMysqlExecutor,
126
+ createParamProxy: () => createParamProxy,
126
127
  createPooledExecutorFactory: () => createPooledExecutorFactory,
127
128
  createPostgresExecutor: () => createPostgresExecutor,
128
129
  createQueryLoggingExecutor: () => createQueryLoggingExecutor,
@@ -643,6 +644,7 @@ var operandTypes = /* @__PURE__ */ new Set([
643
644
  "AliasRef",
644
645
  "Column",
645
646
  "Literal",
647
+ "Param",
646
648
  "Function",
647
649
  "JsonPath",
648
650
  "ScalarSubquery",
@@ -671,6 +673,14 @@ var toLiteralNode = (value) => ({
671
673
  type: "Literal",
672
674
  value: value instanceof Date ? value.toISOString() : value
673
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
+ };
674
684
  var columnRefToNode = (col2) => {
675
685
  if (!col2.table) {
676
686
  throw new Error(
@@ -680,6 +690,10 @@ var columnRefToNode = (col2) => {
680
690
  return { type: "Column", table: col2.table, name: col2.name };
681
691
  };
682
692
  var toOperandNode = (value) => {
693
+ const paramNode = toParamNode(value);
694
+ if (paramNode) {
695
+ return paramNode;
696
+ }
683
697
  if (isOperandNode(value)) {
684
698
  return value;
685
699
  }
@@ -689,6 +703,10 @@ var toOperandNode = (value) => {
689
703
  return columnRefToNode(value);
690
704
  };
691
705
  var valueToOperand = (value) => {
706
+ const paramNode = toParamNode(value);
707
+ if (paramNode) {
708
+ return paramNode;
709
+ }
692
710
  if (isOperandNode(value)) {
693
711
  return value;
694
712
  }
@@ -1082,6 +1100,9 @@ var visitOperand = (node, visitor) => {
1082
1100
  case "Literal":
1083
1101
  if (visitor.visitLiteral) return visitor.visitLiteral(node);
1084
1102
  break;
1103
+ case "Param":
1104
+ if (visitor.visitParam) return visitor.visitParam(node);
1105
+ break;
1085
1106
  case "Function":
1086
1107
  if (visitor.visitFunction) return visitor.visitFunction(node);
1087
1108
  break;
@@ -1113,6 +1134,44 @@ var visitOperand = (node, visitor) => {
1113
1134
  return unsupportedOperand(node);
1114
1135
  };
1115
1136
 
1137
+ // src/core/ast/param-proxy.ts
1138
+ var buildParamProxy = (name) => {
1139
+ const target = { type: "Param", name };
1140
+ return new Proxy(target, {
1141
+ get(t, prop, receiver) {
1142
+ if (prop === "then") return void 0;
1143
+ if (typeof prop === "symbol") {
1144
+ return Reflect.get(t, prop, receiver);
1145
+ }
1146
+ if (typeof prop === "string" && prop.startsWith("$")) {
1147
+ const trimmed = prop.slice(1);
1148
+ const nextName2 = name ? `${name}.${trimmed}` : trimmed;
1149
+ return buildParamProxy(nextName2);
1150
+ }
1151
+ if (prop in t && name === "") {
1152
+ return t[prop];
1153
+ }
1154
+ const nextName = name ? `${name}.${prop}` : prop;
1155
+ return buildParamProxy(nextName);
1156
+ }
1157
+ });
1158
+ };
1159
+ var createParamProxy = () => {
1160
+ const target = {};
1161
+ return new Proxy(target, {
1162
+ get(t, prop, receiver) {
1163
+ if (prop === "then") return void 0;
1164
+ if (typeof prop === "symbol") {
1165
+ return Reflect.get(t, prop, receiver);
1166
+ }
1167
+ if (typeof prop === "string" && prop.startsWith("$")) {
1168
+ return buildParamProxy(prop.slice(1));
1169
+ }
1170
+ return buildParamProxy(String(prop));
1171
+ }
1172
+ });
1173
+ };
1174
+
1116
1175
  // src/core/ast/adapters.ts
1117
1176
  var hasAlias = (obj) => typeof obj === "object" && obj !== null && "alias" in obj;
1118
1177
  var toColumnRef = (col2) => ({
@@ -1524,6 +1583,16 @@ var Dialect = class _Dialect {
1524
1583
  params: [...ctx.params]
1525
1584
  };
1526
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
+ }
1527
1596
  compileInsert(ast) {
1528
1597
  const ctx = this.createCompilerContext();
1529
1598
  const rawSql = this.compileInsertAst(ast, ctx).trim();
@@ -1594,13 +1663,15 @@ var Dialect = class _Dialect {
1594
1663
  }
1595
1664
  /**
1596
1665
  * Creates a new compiler context
1666
+ * @param options - Optional compiler context options
1597
1667
  * @returns Compiler context with parameter management
1598
1668
  */
1599
- createCompilerContext() {
1669
+ createCompilerContext(options = {}) {
1600
1670
  const params = [];
1601
1671
  let counter = 0;
1602
1672
  return {
1603
1673
  params,
1674
+ allowParams: options.allowParams ?? false,
1604
1675
  addParameter: (value) => {
1605
1676
  counter += 1;
1606
1677
  params.push(value);
@@ -1822,6 +1893,12 @@ var Dialect = class _Dialect {
1822
1893
  }
1823
1894
  registerDefaultOperandCompilers() {
1824
1895
  this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
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
+ });
1825
1902
  this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1826
1903
  void _ctx;
1827
1904
  return this.quoteIdentifier(alias.name);
@@ -4345,6 +4422,7 @@ var collectFromOperand = (node, collector) => {
4345
4422
  break;
4346
4423
  case "Literal":
4347
4424
  case "AliasRef":
4425
+ case "Param":
4348
4426
  break;
4349
4427
  default:
4350
4428
  break;
@@ -7611,6 +7689,7 @@ var collectFilterColumns = (expr, table, rootTables) => {
7611
7689
  }
7612
7690
  case "AliasRef":
7613
7691
  case "Literal":
7692
+ case "Param":
7614
7693
  return;
7615
7694
  default:
7616
7695
  return;
@@ -7688,6 +7767,227 @@ var buildFilterParameters = (table, where, from, options = {}) => {
7688
7767
  }];
7689
7768
  };
7690
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
+
7691
7991
  // src/query-builder/select.ts
7692
7992
  var SelectQueryBuilder = class _SelectQueryBuilder {
7693
7993
  env;
@@ -8161,6 +8461,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8161
8461
  }
8162
8462
  return this;
8163
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
+ }
8164
8475
  /**
8165
8476
  * Executes the query and returns hydrated results.
8166
8477
  * If the builder was created with an entity constructor (e.g. via selectFromEntity),
@@ -8174,6 +8485,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8174
8485
  * users[0] instanceof User; // true
8175
8486
  */
8176
8487
  async execute(ctx) {
8488
+ this.validateNoParamOperands();
8177
8489
  if (this.entityConstructor) {
8178
8490
  return this.executeAs(this.entityConstructor, ctx);
8179
8491
  }
@@ -8192,6 +8504,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8192
8504
  * rows[0] instanceof User; // false
8193
8505
  */
8194
8506
  async executePlain(ctx) {
8507
+ this.validateNoParamOperands();
8195
8508
  const builder = this.ensureDefaultSelection();
8196
8509
  const rows = await executeHydratedPlain(ctx, builder);
8197
8510
  return rows;
@@ -8211,6 +8524,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8211
8524
  * users[0].getFullName(); // works!
8212
8525
  */
8213
8526
  async executeAs(entityClass, ctx) {
8527
+ this.validateNoParamOperands();
8214
8528
  const builder = this.ensureDefaultSelection();
8215
8529
  const results = await executeHydrated(ctx, builder);
8216
8530
  return materializeAs(entityClass, results);
@@ -8222,6 +8536,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8222
8536
  * const total = await qb.count(session);
8223
8537
  */
8224
8538
  async count(session) {
8539
+ this.validateNoParamOperands();
8225
8540
  return executeCount(this.context, this.env, session);
8226
8541
  }
8227
8542
  /**
@@ -8231,6 +8546,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8231
8546
  * const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
8232
8547
  */
8233
8548
  async executePaged(session, options) {
8549
+ this.validateNoParamOperands();
8234
8550
  const builder = this.ensureDefaultSelection();
8235
8551
  return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
8236
8552
  }
@@ -8245,6 +8561,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8245
8561
  * const users = await qb.executeWithContexts(execCtx, hydCtx);
8246
8562
  */
8247
8563
  async executeWithContexts(execCtx, hydCtx) {
8564
+ this.validateNoParamOperands();
8248
8565
  const builder = this.ensureDefaultSelection();
8249
8566
  const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
8250
8567
  if (this.entityConstructor) {
@@ -11650,6 +11967,7 @@ var TypeScriptGenerator = class {
11650
11967
  case "WindowFunction":
11651
11968
  case "Cast":
11652
11969
  case "Collate":
11970
+ case "Param":
11653
11971
  return this.printOperand(term);
11654
11972
  default:
11655
11973
  return this.printExpression(term);
@@ -11694,6 +12012,9 @@ var TypeScriptGenerator = class {
11694
12012
  visitLiteral(node) {
11695
12013
  return this.printLiteralOperand(node);
11696
12014
  }
12015
+ visitParam(node) {
12016
+ return this.printParamOperand(node);
12017
+ }
11697
12018
  visitFunction(node) {
11698
12019
  return this.printFunctionOperand(node);
11699
12020
  }
@@ -11815,6 +12136,10 @@ var TypeScriptGenerator = class {
11815
12136
  if (literal.value === null) return "null";
11816
12137
  return typeof literal.value === "string" ? `'${literal.value}'` : String(literal.value);
11817
12138
  }
12139
+ printParamOperand(param) {
12140
+ const name = param.name.replace(/'/g, "\\'");
12141
+ return `{ type: 'Param', name: '${name}' }`;
12142
+ }
11818
12143
  /**
11819
12144
  * Prints a function operand to TypeScript code
11820
12145
  * @param fn - Function node
@@ -14123,6 +14448,7 @@ function createPooledExecutorFactory(opts) {
14123
14448
  createExecutorFromQueryRunner,
14124
14449
  createMssqlExecutor,
14125
14450
  createMysqlExecutor,
14451
+ createParamProxy,
14126
14452
  createPooledExecutorFactory,
14127
14453
  createPostgresExecutor,
14128
14454
  createQueryLoggingExecutor,