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 CHANGED
@@ -655,16 +655,27 @@ var operandTypes = /* @__PURE__ */ new Set([
655
655
  "BitwiseExpression",
656
656
  "Collate"
657
657
  ]);
658
- var hasTypeProperty = (value) => typeof value === "object" && value !== null && "type" in value;
658
+ var getNodeType = (value) => {
659
+ if (typeof value !== "object" || value === null) return void 0;
660
+ const descriptor = Object.getOwnPropertyDescriptor(value, "type");
661
+ if (descriptor && typeof descriptor.value === "string") {
662
+ return descriptor.value;
663
+ }
664
+ if ("type" in value) {
665
+ const type = value.type;
666
+ return typeof type === "string" ? type : void 0;
667
+ }
668
+ return void 0;
669
+ };
659
670
  var isOperandNode = (node) => {
660
- if (!hasTypeProperty(node)) return false;
661
- return operandTypes.has(node.type);
662
- };
663
- var isFunctionNode = (node) => isOperandNode(node) && node.type === "Function";
664
- var isCaseExpressionNode = (node) => isOperandNode(node) && node.type === "CaseExpression";
665
- var isCastExpressionNode = (node) => isOperandNode(node) && node.type === "Cast";
666
- var isCollateExpressionNode = (node) => isOperandNode(node) && node.type === "Collate";
667
- var isWindowFunctionNode = (node) => isOperandNode(node) && node.type === "WindowFunction";
671
+ const type = getNodeType(node);
672
+ return type !== void 0 && operandTypes.has(type);
673
+ };
674
+ var isFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "Function";
675
+ var isCaseExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "CaseExpression";
676
+ var isCastExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Cast";
677
+ var isCollateExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Collate";
678
+ var isWindowFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "WindowFunction";
668
679
  var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressionNode(node) || isCastExpressionNode(node) || isWindowFunctionNode(node);
669
680
 
670
681
  // src/core/ast/expression-builders.ts
@@ -673,6 +684,14 @@ var toLiteralNode = (value) => ({
673
684
  type: "Literal",
674
685
  value: value instanceof Date ? value.toISOString() : value
675
686
  });
687
+ var toParamNode = (value) => {
688
+ if (typeof value !== "object" || value === null) return void 0;
689
+ const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
690
+ if (type !== "Param") return void 0;
691
+ const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
692
+ if (typeof name !== "string") return void 0;
693
+ return { type: "Param", name };
694
+ };
676
695
  var columnRefToNode = (col2) => {
677
696
  if (!col2.table) {
678
697
  throw new Error(
@@ -682,6 +701,10 @@ var columnRefToNode = (col2) => {
682
701
  return { type: "Column", table: col2.table, name: col2.name };
683
702
  };
684
703
  var toOperandNode = (value) => {
704
+ const paramNode = toParamNode(value);
705
+ if (paramNode) {
706
+ return paramNode;
707
+ }
685
708
  if (isOperandNode(value)) {
686
709
  return value;
687
710
  }
@@ -691,6 +714,10 @@ var toOperandNode = (value) => {
691
714
  return columnRefToNode(value);
692
715
  };
693
716
  var valueToOperand = (value) => {
717
+ const paramNode = toParamNode(value);
718
+ if (paramNode) {
719
+ return paramNode;
720
+ }
694
721
  if (isOperandNode(value)) {
695
722
  return value;
696
723
  }
@@ -1033,17 +1060,26 @@ var clearExpressionDispatchers = () => {
1033
1060
  var clearOperandDispatchers = () => {
1034
1061
  operandRegistry = operandRegistry.clear();
1035
1062
  };
1036
- var getNodeType = (node) => typeof node === "object" && node !== null && typeof node.type === "string" ? node.type : void 0;
1063
+ var getNodeType2 = (node) => {
1064
+ if (typeof node !== "object" || node === null) return void 0;
1065
+ const descriptor = Object.getOwnPropertyDescriptor(node, "type");
1066
+ if (descriptor && typeof descriptor.value === "string") {
1067
+ return descriptor.value;
1068
+ }
1069
+ const type = node.type;
1070
+ return typeof type === "string" ? type : void 0;
1071
+ };
1037
1072
  var unsupportedExpression = (node) => {
1038
- throw new Error(`Unsupported expression type "${getNodeType(node) ?? "unknown"}"`);
1073
+ throw new Error(`Unsupported expression type "${getNodeType2(node) ?? "unknown"}"`);
1039
1074
  };
1040
1075
  var unsupportedOperand = (node) => {
1041
- throw new Error(`Unsupported operand type "${getNodeType(node) ?? "unknown"}"`);
1076
+ throw new Error(`Unsupported operand type "${getNodeType2(node) ?? "unknown"}"`);
1042
1077
  };
1043
1078
  var visitExpression = (node, visitor) => {
1044
- const dynamic = expressionRegistry.get(node.type);
1079
+ const type = getNodeType2(node);
1080
+ const dynamic = type ? expressionRegistry.get(type) : void 0;
1045
1081
  if (dynamic) return dynamic(node, visitor);
1046
- switch (node.type) {
1082
+ switch (type) {
1047
1083
  case "BinaryExpression":
1048
1084
  if (visitor.visitBinaryExpression) return visitor.visitBinaryExpression(node);
1049
1085
  break;
@@ -1075,9 +1111,10 @@ var visitExpression = (node, visitor) => {
1075
1111
  return unsupportedExpression(node);
1076
1112
  };
1077
1113
  var visitOperand = (node, visitor) => {
1078
- const dynamic = operandRegistry.get(node.type);
1114
+ const type = getNodeType2(node);
1115
+ const dynamic = type ? operandRegistry.get(type) : void 0;
1079
1116
  if (dynamic) return dynamic(node, visitor);
1080
- switch (node.type) {
1117
+ switch (type) {
1081
1118
  case "Column":
1082
1119
  if (visitor.visitColumn) return visitor.visitColumn(node);
1083
1120
  break;
@@ -1132,7 +1169,7 @@ var buildParamProxy = (name) => {
1132
1169
  const nextName2 = name ? `${name}.${trimmed}` : trimmed;
1133
1170
  return buildParamProxy(nextName2);
1134
1171
  }
1135
- if (prop in t) {
1172
+ if (prop in t && name === "") {
1136
1173
  return t[prop];
1137
1174
  }
1138
1175
  const nextName = name ? `${name}.${prop}` : prop;
@@ -1151,9 +1188,6 @@ var createParamProxy = () => {
1151
1188
  if (typeof prop === "string" && prop.startsWith("$")) {
1152
1189
  return buildParamProxy(prop.slice(1));
1153
1190
  }
1154
- if (prop in t) {
1155
- return t[prop];
1156
- }
1157
1191
  return buildParamProxy(String(prop));
1158
1192
  }
1159
1193
  });
@@ -1570,6 +1604,16 @@ var Dialect = class _Dialect {
1570
1604
  params: [...ctx.params]
1571
1605
  };
1572
1606
  }
1607
+ compileSelectWithOptions(ast, options = {}) {
1608
+ const ctx = this.createCompilerContext(options);
1609
+ const normalized = this.normalizeSelectAst(ast);
1610
+ const rawSql = this.compileSelectAst(normalized, ctx).trim();
1611
+ const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1612
+ return {
1613
+ sql,
1614
+ params: [...ctx.params]
1615
+ };
1616
+ }
1573
1617
  compileInsert(ast) {
1574
1618
  const ctx = this.createCompilerContext();
1575
1619
  const rawSql = this.compileInsertAst(ast, ctx).trim();
@@ -1640,13 +1684,15 @@ var Dialect = class _Dialect {
1640
1684
  }
1641
1685
  /**
1642
1686
  * Creates a new compiler context
1687
+ * @param options - Optional compiler context options
1643
1688
  * @returns Compiler context with parameter management
1644
1689
  */
1645
- createCompilerContext() {
1690
+ createCompilerContext(options = {}) {
1646
1691
  const params = [];
1647
1692
  let counter = 0;
1648
1693
  return {
1649
1694
  params,
1695
+ allowParams: options.allowParams ?? false,
1650
1696
  addParameter: (value) => {
1651
1697
  counter += 1;
1652
1698
  params.push(value);
@@ -1797,9 +1843,11 @@ var Dialect = class _Dialect {
1797
1843
  * @returns Compiled SQL operand
1798
1844
  */
1799
1845
  compileOperand(node, ctx) {
1800
- const compiler = this.operandCompilers.get(node.type);
1846
+ const descriptor = Object.getOwnPropertyDescriptor(node, "type");
1847
+ const nodeType = typeof descriptor?.value === "string" ? descriptor.value : typeof node.type === "string" ? node.type : void 0;
1848
+ const compiler = nodeType ? this.operandCompilers.get(nodeType) : void 0;
1801
1849
  if (!compiler) {
1802
- throw new Error(`Unsupported operand node type "${node.type}" for ${this.constructor.name}`);
1850
+ throw new Error(`Unsupported operand node type "${nodeType ?? "unknown"}" for ${this.constructor.name}`);
1803
1851
  }
1804
1852
  return compiler(node, ctx);
1805
1853
  }
@@ -1868,7 +1916,12 @@ var Dialect = class _Dialect {
1868
1916
  }
1869
1917
  registerDefaultOperandCompilers() {
1870
1918
  this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1871
- this.registerOperandCompiler("Param", (_param, ctx) => ctx.addParameter(null));
1919
+ this.registerOperandCompiler("Param", (_param, ctx) => {
1920
+ if (!ctx.allowParams) {
1921
+ 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.");
1922
+ }
1923
+ return ctx.addParameter(null);
1924
+ });
1872
1925
  this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1873
1926
  void _ctx;
1874
1927
  return this.quoteIdentifier(alias.name);
@@ -4115,6 +4168,10 @@ var QueryAstService = class {
4115
4168
  * @returns Normalized ordering term
4116
4169
  */
4117
4170
  normalizeOrderingTerm(term) {
4171
+ const paramNode = this.toParamNode(term);
4172
+ if (paramNode) {
4173
+ return paramNode;
4174
+ }
4118
4175
  const from = this.state.ast.from;
4119
4176
  const tableRef2 = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
4120
4177
  const termType = term.type;
@@ -4132,6 +4189,14 @@ var QueryAstService = class {
4132
4189
  }
4133
4190
  return buildColumnNode(tableRef2, term);
4134
4191
  }
4192
+ toParamNode(value) {
4193
+ if (typeof value !== "object" || value === null) return void 0;
4194
+ const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
4195
+ if (type !== "Param") return void 0;
4196
+ const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
4197
+ if (typeof name !== "string") return void 0;
4198
+ return { type: "Param", name };
4199
+ }
4135
4200
  };
4136
4201
 
4137
4202
  // src/query-builder/relation-projection-helper.ts
@@ -7586,7 +7651,7 @@ var collectFilterColumns = (expr, table, rootTables) => {
7586
7651
  columns.add(node.name);
7587
7652
  }
7588
7653
  };
7589
- const visitOrderingTerm = (term) => {
7654
+ const visitOrderingTerm2 = (term) => {
7590
7655
  if (!term || typeof term !== "object") return;
7591
7656
  if (isOperandNode(term)) {
7592
7657
  visitOperand2(term);
@@ -7598,7 +7663,7 @@ var collectFilterColumns = (expr, table, rootTables) => {
7598
7663
  };
7599
7664
  const visitOrderBy = (orderBy) => {
7600
7665
  if (!orderBy) return;
7601
- orderBy.forEach((node) => visitOrderingTerm(node.term));
7666
+ orderBy.forEach((node) => visitOrderingTerm2(node.term));
7602
7667
  };
7603
7668
  const visitOperand2 = (node) => {
7604
7669
  switch (node.type) {
@@ -7737,6 +7802,198 @@ var buildFilterParameters = (table, where, from, options = {}) => {
7737
7802
  }];
7738
7803
  };
7739
7804
 
7805
+ // src/core/ast/query-visitor.ts
7806
+ var getNodeType3 = (value) => {
7807
+ if (typeof value !== "object" || value === null) return void 0;
7808
+ const descriptor = Object.getOwnPropertyDescriptor(value, "type");
7809
+ if (descriptor && typeof descriptor.value === "string") {
7810
+ return descriptor.value;
7811
+ }
7812
+ if ("type" in value) {
7813
+ const type = value.type;
7814
+ return typeof type === "string" ? type : void 0;
7815
+ }
7816
+ return void 0;
7817
+ };
7818
+ var visitOrderingTerm = (term, visitor) => {
7819
+ if (isOperandNode(term)) {
7820
+ visitOperandNode(term, visitor);
7821
+ return;
7822
+ }
7823
+ visitExpressionNode(term, visitor);
7824
+ };
7825
+ var visitOrderByNode = (node, visitor) => {
7826
+ visitor.visitOrderBy?.(node);
7827
+ visitOrderingTerm(node.term, visitor);
7828
+ };
7829
+ var visitTableSource = (source, visitor) => {
7830
+ visitor.visitTableSource?.(source);
7831
+ if (source.type === "DerivedTable") {
7832
+ visitor.visitDerivedTable?.(source);
7833
+ visitSelectQuery(source.query, visitor);
7834
+ return;
7835
+ }
7836
+ if (source.type === "FunctionTable") {
7837
+ visitor.visitFunctionTable?.(source);
7838
+ source.args?.forEach((arg) => visitOperandNode(arg, visitor));
7839
+ }
7840
+ };
7841
+ var visitExpressionNode = (node, visitor) => {
7842
+ visitor.visitExpression?.(node);
7843
+ const type = getNodeType3(node);
7844
+ if (!type) return;
7845
+ switch (type) {
7846
+ case "BinaryExpression":
7847
+ visitOperandNode(node.left, visitor);
7848
+ visitOperandNode(node.right, visitor);
7849
+ if (node.escape) {
7850
+ visitOperandNode(node.escape, visitor);
7851
+ }
7852
+ return;
7853
+ case "LogicalExpression":
7854
+ node.operands.forEach((operand) => visitExpressionNode(operand, visitor));
7855
+ return;
7856
+ case "NullExpression":
7857
+ visitOperandNode(node.left, visitor);
7858
+ return;
7859
+ case "InExpression":
7860
+ visitOperandNode(node.left, visitor);
7861
+ if (Array.isArray(node.right)) {
7862
+ node.right.forEach((operand) => visitOperandNode(operand, visitor));
7863
+ } else {
7864
+ visitOperandNode(node.right, visitor);
7865
+ }
7866
+ return;
7867
+ case "ExistsExpression":
7868
+ visitSelectQuery(node.subquery, visitor);
7869
+ return;
7870
+ case "BetweenExpression":
7871
+ visitOperandNode(node.left, visitor);
7872
+ visitOperandNode(node.lower, visitor);
7873
+ visitOperandNode(node.upper, visitor);
7874
+ return;
7875
+ case "ArithmeticExpression":
7876
+ visitOperandNode(node.left, visitor);
7877
+ visitOperandNode(node.right, visitor);
7878
+ return;
7879
+ case "BitwiseExpression":
7880
+ visitOperandNode(node.left, visitor);
7881
+ visitOperandNode(node.right, visitor);
7882
+ return;
7883
+ default: {
7884
+ return;
7885
+ }
7886
+ }
7887
+ };
7888
+ var visitOperandNode = (node, visitor) => {
7889
+ visitor.visitOperand?.(node);
7890
+ const type = getNodeType3(node);
7891
+ if (type === "Param") {
7892
+ visitor.visitParam?.(node);
7893
+ }
7894
+ if (!type) return;
7895
+ switch (type) {
7896
+ case "Column":
7897
+ case "Literal":
7898
+ case "Param":
7899
+ case "AliasRef":
7900
+ return;
7901
+ case "Function":
7902
+ node.args?.forEach((arg) => visitOperandNode(arg, visitor));
7903
+ node.orderBy?.forEach((order) => visitOrderByNode(order, visitor));
7904
+ if (node.separator) {
7905
+ visitOperandNode(node.separator, visitor);
7906
+ }
7907
+ return;
7908
+ case "JsonPath":
7909
+ visitOperandNode(node.column, visitor);
7910
+ return;
7911
+ case "ScalarSubquery":
7912
+ visitSelectQuery(node.query, visitor);
7913
+ return;
7914
+ case "CaseExpression":
7915
+ node.conditions.forEach((cond) => {
7916
+ visitExpressionNode(cond.when, visitor);
7917
+ visitOperandNode(cond.then, visitor);
7918
+ });
7919
+ if (node.else) {
7920
+ visitOperandNode(node.else, visitor);
7921
+ }
7922
+ return;
7923
+ case "Cast":
7924
+ visitOperandNode(node.expression, visitor);
7925
+ return;
7926
+ case "WindowFunction":
7927
+ node.args?.forEach((arg) => visitOperandNode(arg, visitor));
7928
+ node.partitionBy?.forEach((term) => visitOperandNode(term, visitor));
7929
+ node.orderBy?.forEach((order) => visitOrderByNode(order, visitor));
7930
+ return;
7931
+ case "ArithmeticExpression":
7932
+ visitOperandNode(node.left, visitor);
7933
+ visitOperandNode(node.right, visitor);
7934
+ return;
7935
+ case "BitwiseExpression":
7936
+ visitOperandNode(node.left, visitor);
7937
+ visitOperandNode(node.right, visitor);
7938
+ return;
7939
+ case "Collate":
7940
+ visitOperandNode(node.expression, visitor);
7941
+ return;
7942
+ default: {
7943
+ const _exhaustive = node;
7944
+ return _exhaustive;
7945
+ }
7946
+ }
7947
+ };
7948
+ var visitSelectQuery = (ast, visitor) => {
7949
+ visitor.visitSelectQuery?.(ast);
7950
+ if (ast.ctes) {
7951
+ for (const cte of ast.ctes) {
7952
+ visitor.visitCte?.(cte);
7953
+ visitSelectQuery(cte.query, visitor);
7954
+ }
7955
+ }
7956
+ visitTableSource(ast.from, visitor);
7957
+ ast.columns?.forEach((col2) => {
7958
+ visitOperandNode(col2, visitor);
7959
+ });
7960
+ ast.joins?.forEach((join) => {
7961
+ visitor.visitJoin?.(join);
7962
+ visitTableSource(join.table, visitor);
7963
+ visitExpressionNode(join.condition, visitor);
7964
+ });
7965
+ if (ast.where) {
7966
+ visitExpressionNode(ast.where, visitor);
7967
+ }
7968
+ ast.groupBy?.forEach((term) => {
7969
+ visitOrderingTerm(term, visitor);
7970
+ });
7971
+ if (ast.having) {
7972
+ visitExpressionNode(ast.having, visitor);
7973
+ }
7974
+ ast.orderBy?.forEach((order) => {
7975
+ visitOrderByNode(order, visitor);
7976
+ });
7977
+ ast.distinct?.forEach((col2) => {
7978
+ visitOperandNode(col2, visitor);
7979
+ });
7980
+ ast.setOps?.forEach((op) => {
7981
+ visitor.visitSetOperation?.(op);
7982
+ visitSelectQuery(op.query, visitor);
7983
+ });
7984
+ };
7985
+
7986
+ // src/core/ast/ast-validation.ts
7987
+ var hasParamOperandsInQuery = (ast) => {
7988
+ let hasParams = false;
7989
+ visitSelectQuery(ast, {
7990
+ visitParam: () => {
7991
+ hasParams = true;
7992
+ }
7993
+ });
7994
+ return hasParams;
7995
+ };
7996
+
7740
7997
  // src/query-builder/select.ts
7741
7998
  var SelectQueryBuilder = class _SelectQueryBuilder {
7742
7999
  env;
@@ -8210,6 +8467,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8210
8467
  }
8211
8468
  return this;
8212
8469
  }
8470
+ /**
8471
+ * Validates that the query does not contain Param operands.
8472
+ * Param proxies are only for schema generation, not execution.
8473
+ */
8474
+ validateNoParamOperands() {
8475
+ const ast = this.context.hydration.applyToAst(this.context.state.ast);
8476
+ const hasParams = hasParamOperandsInQuery(ast);
8477
+ if (hasParams) {
8478
+ 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.");
8479
+ }
8480
+ }
8213
8481
  /**
8214
8482
  * Executes the query and returns hydrated results.
8215
8483
  * If the builder was created with an entity constructor (e.g. via selectFromEntity),
@@ -8223,6 +8491,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8223
8491
  * users[0] instanceof User; // true
8224
8492
  */
8225
8493
  async execute(ctx) {
8494
+ this.validateNoParamOperands();
8226
8495
  if (this.entityConstructor) {
8227
8496
  return this.executeAs(this.entityConstructor, ctx);
8228
8497
  }
@@ -8241,6 +8510,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8241
8510
  * rows[0] instanceof User; // false
8242
8511
  */
8243
8512
  async executePlain(ctx) {
8513
+ this.validateNoParamOperands();
8244
8514
  const builder = this.ensureDefaultSelection();
8245
8515
  const rows = await executeHydratedPlain(ctx, builder);
8246
8516
  return rows;
@@ -8260,6 +8530,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8260
8530
  * users[0].getFullName(); // works!
8261
8531
  */
8262
8532
  async executeAs(entityClass, ctx) {
8533
+ this.validateNoParamOperands();
8263
8534
  const builder = this.ensureDefaultSelection();
8264
8535
  const results = await executeHydrated(ctx, builder);
8265
8536
  return materializeAs(entityClass, results);
@@ -8271,6 +8542,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8271
8542
  * const total = await qb.count(session);
8272
8543
  */
8273
8544
  async count(session) {
8545
+ this.validateNoParamOperands();
8274
8546
  return executeCount(this.context, this.env, session);
8275
8547
  }
8276
8548
  /**
@@ -8280,6 +8552,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8280
8552
  * const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
8281
8553
  */
8282
8554
  async executePaged(session, options) {
8555
+ this.validateNoParamOperands();
8283
8556
  const builder = this.ensureDefaultSelection();
8284
8557
  return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
8285
8558
  }
@@ -8294,6 +8567,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8294
8567
  * const users = await qb.executeWithContexts(execCtx, hydCtx);
8295
8568
  */
8296
8569
  async executeWithContexts(execCtx, hydCtx) {
8570
+ this.validateNoParamOperands();
8297
8571
  const builder = this.ensureDefaultSelection();
8298
8572
  const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
8299
8573
  if (this.entityConstructor) {