metal-orm 1.0.83 → 1.0.86

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
@@ -175,8 +175,10 @@ __export(index_exports, {
175
175
  groupConcat: () => groupConcat,
176
176
  gt: () => gt,
177
177
  gte: () => gte,
178
+ hasExpressionDispatcher: () => hasExpressionDispatcher,
178
179
  hasMany: () => hasMany,
179
180
  hasOne: () => hasOne,
181
+ hasOperandDispatcher: () => hasOperandDispatcher,
180
182
  hour: () => hour,
181
183
  hydrateRows: () => hydrateRows,
182
184
  ifNull: () => ifNull,
@@ -655,16 +657,27 @@ var operandTypes = /* @__PURE__ */ new Set([
655
657
  "BitwiseExpression",
656
658
  "Collate"
657
659
  ]);
658
- var hasTypeProperty = (value) => typeof value === "object" && value !== null && "type" in value;
660
+ var getNodeType = (value) => {
661
+ if (typeof value !== "object" || value === null) return void 0;
662
+ const descriptor = Object.getOwnPropertyDescriptor(value, "type");
663
+ if (descriptor && typeof descriptor.value === "string") {
664
+ return descriptor.value;
665
+ }
666
+ if ("type" in value) {
667
+ const type = value.type;
668
+ return typeof type === "string" ? type : void 0;
669
+ }
670
+ return void 0;
671
+ };
659
672
  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";
673
+ const type = getNodeType(node);
674
+ return type !== void 0 && operandTypes.has(type);
675
+ };
676
+ var isFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "Function";
677
+ var isCaseExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "CaseExpression";
678
+ var isCastExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Cast";
679
+ var isCollateExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Collate";
680
+ var isWindowFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "WindowFunction";
668
681
  var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressionNode(node) || isCastExpressionNode(node) || isWindowFunctionNode(node);
669
682
 
670
683
  // src/core/ast/expression-builders.ts
@@ -1043,23 +1056,34 @@ var registerExpressionDispatcher = (type, dispatcher) => {
1043
1056
  var registerOperandDispatcher = (type, dispatcher) => {
1044
1057
  operandRegistry = operandRegistry.register(type, dispatcher);
1045
1058
  };
1059
+ var hasExpressionDispatcher = (type) => expressionRegistry.get(type) !== void 0;
1060
+ var hasOperandDispatcher = (type) => operandRegistry.get(type) !== void 0;
1046
1061
  var clearExpressionDispatchers = () => {
1047
1062
  expressionRegistry = expressionRegistry.clear();
1048
1063
  };
1049
1064
  var clearOperandDispatchers = () => {
1050
1065
  operandRegistry = operandRegistry.clear();
1051
1066
  };
1052
- var getNodeType = (node) => typeof node === "object" && node !== null && typeof node.type === "string" ? node.type : void 0;
1067
+ var getNodeType2 = (node) => {
1068
+ if (typeof node !== "object" || node === null) return void 0;
1069
+ const descriptor = Object.getOwnPropertyDescriptor(node, "type");
1070
+ if (descriptor && typeof descriptor.value === "string") {
1071
+ return descriptor.value;
1072
+ }
1073
+ const type = node.type;
1074
+ return typeof type === "string" ? type : void 0;
1075
+ };
1053
1076
  var unsupportedExpression = (node) => {
1054
- throw new Error(`Unsupported expression type "${getNodeType(node) ?? "unknown"}"`);
1077
+ throw new Error(`Unsupported expression type "${getNodeType2(node) ?? "unknown"}"`);
1055
1078
  };
1056
1079
  var unsupportedOperand = (node) => {
1057
- throw new Error(`Unsupported operand type "${getNodeType(node) ?? "unknown"}"`);
1080
+ throw new Error(`Unsupported operand type "${getNodeType2(node) ?? "unknown"}"`);
1058
1081
  };
1059
1082
  var visitExpression = (node, visitor) => {
1060
- const dynamic = expressionRegistry.get(node.type);
1083
+ const type = getNodeType2(node);
1084
+ const dynamic = type ? expressionRegistry.get(type) : void 0;
1061
1085
  if (dynamic) return dynamic(node, visitor);
1062
- switch (node.type) {
1086
+ switch (type) {
1063
1087
  case "BinaryExpression":
1064
1088
  if (visitor.visitBinaryExpression) return visitor.visitBinaryExpression(node);
1065
1089
  break;
@@ -1091,9 +1115,10 @@ var visitExpression = (node, visitor) => {
1091
1115
  return unsupportedExpression(node);
1092
1116
  };
1093
1117
  var visitOperand = (node, visitor) => {
1094
- const dynamic = operandRegistry.get(node.type);
1118
+ const type = getNodeType2(node);
1119
+ const dynamic = type ? operandRegistry.get(type) : void 0;
1095
1120
  if (dynamic) return dynamic(node, visitor);
1096
- switch (node.type) {
1121
+ switch (type) {
1097
1122
  case "Column":
1098
1123
  if (visitor.visitColumn) return visitor.visitColumn(node);
1099
1124
  break;
@@ -1127,6 +1152,12 @@ var visitOperand = (node, visitor) => {
1127
1152
  case "Collate":
1128
1153
  if (visitor.visitCollate) return visitor.visitCollate(node);
1129
1154
  break;
1155
+ case "ArithmeticExpression":
1156
+ if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
1157
+ break;
1158
+ case "BitwiseExpression":
1159
+ if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node);
1160
+ break;
1130
1161
  default:
1131
1162
  break;
1132
1163
  }
@@ -1822,9 +1853,11 @@ var Dialect = class _Dialect {
1822
1853
  * @returns Compiled SQL operand
1823
1854
  */
1824
1855
  compileOperand(node, ctx) {
1825
- const compiler = this.operandCompilers.get(node.type);
1856
+ const descriptor = Object.getOwnPropertyDescriptor(node, "type");
1857
+ const nodeType = typeof descriptor?.value === "string" ? descriptor.value : typeof node.type === "string" ? node.type : void 0;
1858
+ const compiler = nodeType ? this.operandCompilers.get(nodeType) : void 0;
1826
1859
  if (!compiler) {
1827
- throw new Error(`Unsupported operand node type "${node.type}" for ${this.constructor.name}`);
1860
+ throw new Error(`Unsupported operand node type "${nodeType ?? "unknown"}" for ${this.constructor.name}`);
1828
1861
  }
1829
1862
  return compiler(node, ctx);
1830
1863
  }
@@ -4145,6 +4178,10 @@ var QueryAstService = class {
4145
4178
  * @returns Normalized ordering term
4146
4179
  */
4147
4180
  normalizeOrderingTerm(term) {
4181
+ const paramNode = this.toParamNode(term);
4182
+ if (paramNode) {
4183
+ return paramNode;
4184
+ }
4148
4185
  const from = this.state.ast.from;
4149
4186
  const tableRef2 = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
4150
4187
  const termType = term.type;
@@ -4162,6 +4199,14 @@ var QueryAstService = class {
4162
4199
  }
4163
4200
  return buildColumnNode(tableRef2, term);
4164
4201
  }
4202
+ toParamNode(value) {
4203
+ if (typeof value !== "object" || value === null) return void 0;
4204
+ const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
4205
+ if (type !== "Param") return void 0;
4206
+ const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
4207
+ if (typeof name !== "string") return void 0;
4208
+ return { type: "Param", name };
4209
+ }
4165
4210
  };
4166
4211
 
4167
4212
  // src/query-builder/relation-projection-helper.ts
@@ -6401,9 +6446,9 @@ var flattenResults = (results) => {
6401
6446
  }
6402
6447
  return rows;
6403
6448
  };
6404
- var executeWithContexts = async (execCtx, entityCtx, qb) => {
6449
+ var executeWithContexts = async (execCtx, entityCtx, qb, options) => {
6405
6450
  const ast = qb.getAST();
6406
- const compiled = execCtx.dialect.compileSelect(ast);
6451
+ const compiled = options?.allowParamOperands ? execCtx.dialect.compileSelectWithOptions(ast, { allowParams: true }) : execCtx.dialect.compileSelect(ast);
6407
6452
  const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
6408
6453
  const rows = flattenResults(executed);
6409
6454
  const lazyRelations = qb.getLazyRelations();
@@ -6421,9 +6466,9 @@ var executeWithContexts = async (execCtx, entityCtx, qb) => {
6421
6466
  await preloadRelationIncludes(entities, includeTree);
6422
6467
  return entities;
6423
6468
  };
6424
- var executePlainWithContexts = async (execCtx, qb) => {
6469
+ var executePlainWithContexts = async (execCtx, qb, options) => {
6425
6470
  const ast = qb.getAST();
6426
- const compiled = execCtx.dialect.compileSelect(ast);
6471
+ const compiled = options?.allowParamOperands ? execCtx.dialect.compileSelectWithOptions(ast, { allowParams: true }) : execCtx.dialect.compileSelect(ast);
6427
6472
  const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
6428
6473
  const rows = flattenResults(executed);
6429
6474
  if (ast.setOps && ast.setOps.length > 0) {
@@ -6431,21 +6476,21 @@ var executePlainWithContexts = async (execCtx, qb) => {
6431
6476
  }
6432
6477
  return hydrateRows(rows, qb.getHydrationPlan());
6433
6478
  };
6434
- async function executeHydrated(session, qb) {
6435
- return executeWithContexts(session.getExecutionContext(), session, qb);
6479
+ async function executeHydrated(session, qb, options) {
6480
+ return executeWithContexts(session.getExecutionContext(), session, qb, options);
6436
6481
  }
6437
- async function executeHydratedPlain(session, qb) {
6438
- return executePlainWithContexts(session.getExecutionContext(), qb);
6482
+ async function executeHydratedPlain(session, qb, options) {
6483
+ return executePlainWithContexts(session.getExecutionContext(), qb, options);
6439
6484
  }
6440
- async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
6485
+ async function executeHydratedWithContexts(execCtx, hydCtx, qb, options) {
6441
6486
  const entityCtx = hydCtx.entityContext;
6442
6487
  if (!entityCtx) {
6443
6488
  throw new Error("Hydration context is missing an EntityContext");
6444
6489
  }
6445
- return executeWithContexts(execCtx, entityCtx, qb);
6490
+ return executeWithContexts(execCtx, entityCtx, qb, options);
6446
6491
  }
6447
- async function executeHydratedPlainWithContexts(execCtx, qb) {
6448
- return executePlainWithContexts(execCtx, qb);
6492
+ async function executeHydratedPlainWithContexts(execCtx, qb, options) {
6493
+ return executePlainWithContexts(execCtx, qb, options);
6449
6494
  }
6450
6495
  var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOptions) => {
6451
6496
  if (!lazyRelations.length) return;
@@ -6646,7 +6691,7 @@ function applyOrderBy(context, predicateFacet, term, directionOrOptions) {
6646
6691
  const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
6647
6692
  return predicateFacet.orderBy(context, term, dir, options.nulls, options.collation);
6648
6693
  }
6649
- async function executeCount(context, env, session) {
6694
+ async function executeCount(context, env, session, options) {
6650
6695
  const unpagedAst = {
6651
6696
  ...context.state.ast,
6652
6697
  orderBy: void 0,
@@ -6666,7 +6711,7 @@ async function executeCount(context, env, session) {
6666
6711
  joins: []
6667
6712
  };
6668
6713
  const execCtx = session.getExecutionContext();
6669
- const compiled = execCtx.dialect.compileSelect(countQuery);
6714
+ const compiled = options?.allowParamOperands ? execCtx.dialect.compileSelectWithOptions(countQuery, { allowParams: true }) : execCtx.dialect.compileSelect(countQuery);
6670
6715
  const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
6671
6716
  const value = results[0]?.values?.[0]?.[0];
6672
6717
  if (typeof value === "number") return value;
@@ -6674,7 +6719,7 @@ async function executeCount(context, env, session) {
6674
6719
  if (typeof value === "string") return Number(value);
6675
6720
  return value === null || value === void 0 ? 0 : Number(value);
6676
6721
  }
6677
- async function executePagedQuery(builder, session, options, countCallback) {
6722
+ async function executePagedQuery(builder, session, options, countCallback, paramOptions) {
6678
6723
  const { page, pageSize } = options;
6679
6724
  if (!Number.isInteger(page) || page < 1) {
6680
6725
  throw new Error("executePaged: page must be an integer >= 1");
@@ -6684,7 +6729,7 @@ async function executePagedQuery(builder, session, options, countCallback) {
6684
6729
  }
6685
6730
  const offset = (page - 1) * pageSize;
6686
6731
  const totalItems = await countCallback(session);
6687
- const items = await builder.limit(pageSize).offset(offset).execute(session);
6732
+ const items = await builder.limit(pageSize).offset(offset).execute(session, paramOptions);
6688
6733
  return { items, totalItems, page, pageSize };
6689
6734
  }
6690
6735
  function buildWhereHasPredicate(env, context, relationFacet, createChildBuilder, relationName, callbackOrOptions, maybeOptions, negate = false) {
@@ -7767,225 +7812,235 @@ var buildFilterParameters = (table, where, from, options = {}) => {
7767
7812
  }];
7768
7813
  };
7769
7814
 
7770
- // src/core/ast/ast-validation.ts
7771
- var hasParamOperandsInExpression = (expr) => {
7772
- let hasParams = false;
7773
- visitExpression(expr, {
7815
+ // src/core/ast/query-visitor.ts
7816
+ var getNodeType3 = (value) => {
7817
+ if (typeof value !== "object" || value === null) return void 0;
7818
+ const descriptor = Object.getOwnPropertyDescriptor(value, "type");
7819
+ if (descriptor && typeof descriptor.value === "string") {
7820
+ return descriptor.value;
7821
+ }
7822
+ if ("type" in value) {
7823
+ const type = value.type;
7824
+ return typeof type === "string" ? type : void 0;
7825
+ }
7826
+ return void 0;
7827
+ };
7828
+ var visitSelectQuery = (ast, visitor) => {
7829
+ const visitExpressionNode = (node) => {
7830
+ visitExpression(node, expressionVisitor);
7831
+ };
7832
+ const visitOperandNode = (node) => {
7833
+ visitOperand(node, operandVisitor);
7834
+ };
7835
+ const visitOrderingTerm = (term) => {
7836
+ if (!term || typeof term !== "object") return;
7837
+ if (isOperandNode(term)) {
7838
+ visitOperandNode(term);
7839
+ return;
7840
+ }
7841
+ const type = getNodeType3(term);
7842
+ if (type && hasOperandDispatcher(type)) {
7843
+ visitOperandNode(term);
7844
+ return;
7845
+ }
7846
+ if (type) {
7847
+ visitExpressionNode(term);
7848
+ }
7849
+ };
7850
+ const visitOrderByNode = (node) => {
7851
+ visitor.visitOrderBy?.(node);
7852
+ visitOrderingTerm(node.term);
7853
+ };
7854
+ const visitTableSource = (source) => {
7855
+ visitor.visitTableSource?.(source);
7856
+ if (source.type === "DerivedTable") {
7857
+ visitor.visitDerivedTable?.(source);
7858
+ visitSelectQuery(source.query, visitor);
7859
+ return;
7860
+ }
7861
+ if (source.type === "FunctionTable") {
7862
+ visitor.visitFunctionTable?.(source);
7863
+ source.args?.forEach((arg) => visitOperandNode(arg));
7864
+ }
7865
+ };
7866
+ const expressionVisitor = {
7774
7867
  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
- });
7868
+ visitor.visitExpression?.(node);
7869
+ visitOperandNode(node.left);
7870
+ visitOperandNode(node.right);
7789
7871
  if (node.escape) {
7790
- visitOperand(node.escape, {
7791
- visitParam: () => {
7792
- hasParams = true;
7793
- },
7794
- otherwise: () => {
7795
- }
7796
- });
7872
+ visitOperandNode(node.escape);
7797
7873
  }
7798
7874
  },
7799
7875
  visitLogicalExpression: (node) => {
7800
- node.operands.forEach((operand) => {
7801
- if (hasParamOperandsInExpression(operand)) {
7802
- hasParams = true;
7803
- }
7804
- });
7876
+ visitor.visitExpression?.(node);
7877
+ node.operands.forEach((operand) => visitExpressionNode(operand));
7805
7878
  },
7806
- visitNullExpression: () => {
7879
+ visitNullExpression: (node) => {
7880
+ visitor.visitExpression?.(node);
7881
+ visitOperandNode(node.left);
7807
7882
  },
7808
7883
  visitInExpression: (node) => {
7809
- visitOperand(node.left, {
7810
- visitParam: () => {
7811
- hasParams = true;
7812
- },
7813
- otherwise: () => {
7814
- }
7815
- });
7884
+ visitor.visitExpression?.(node);
7885
+ visitOperandNode(node.left);
7816
7886
  if (Array.isArray(node.right)) {
7817
- node.right.forEach((operand) => visitOperand(operand, {
7818
- visitParam: () => {
7819
- hasParams = true;
7820
- },
7821
- otherwise: () => {
7822
- }
7823
- }));
7887
+ node.right.forEach((operand) => visitOperandNode(operand));
7888
+ } else {
7889
+ visitOperandNode(node.right);
7824
7890
  }
7825
7891
  },
7826
- visitExistsExpression: () => {
7892
+ visitExistsExpression: (node) => {
7893
+ visitor.visitExpression?.(node);
7894
+ visitSelectQuery(node.subquery, visitor);
7827
7895
  },
7828
7896
  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
- });
7897
+ visitor.visitExpression?.(node);
7898
+ visitOperandNode(node.left);
7899
+ visitOperandNode(node.lower);
7900
+ visitOperandNode(node.upper);
7850
7901
  },
7851
7902
  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
- });
7903
+ visitor.visitExpression?.(node);
7904
+ visitOperandNode(node.left);
7905
+ visitOperandNode(node.right);
7866
7906
  },
7867
7907
  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
- });
7908
+ visitor.visitExpression?.(node);
7909
+ visitOperandNode(node.left);
7910
+ visitOperandNode(node.right);
7882
7911
  },
7883
- otherwise: () => {
7912
+ visitOperand: (node) => {
7913
+ visitOperandNode(node);
7914
+ },
7915
+ visitSelectQuery: (node) => {
7916
+ visitSelectQuery(node, visitor);
7917
+ },
7918
+ otherwise: (node) => {
7919
+ visitor.visitExpression?.(node);
7884
7920
  }
7885
- });
7886
- return hasParams;
7887
- };
7888
- var hasParamOperandsInOperand = (operand) => {
7889
- let hasParams = false;
7890
- visitOperand(operand, {
7891
- visitColumn: () => {
7921
+ };
7922
+ const operandVisitor = {
7923
+ visitColumn: (node) => {
7924
+ visitor.visitOperand?.(node);
7892
7925
  },
7893
- visitLiteral: () => {
7926
+ visitLiteral: (node) => {
7927
+ visitor.visitOperand?.(node);
7894
7928
  },
7895
- visitParam: () => {
7896
- hasParams = true;
7929
+ visitParam: (node) => {
7930
+ visitor.visitOperand?.(node);
7931
+ visitor.visitParam?.(node);
7897
7932
  },
7898
7933
  visitFunction: (node) => {
7899
- node.args?.forEach((arg) => {
7900
- if (hasParamOperandsInOperand(arg)) {
7901
- hasParams = true;
7902
- }
7903
- });
7934
+ visitor.visitOperand?.(node);
7935
+ node.args?.forEach((arg) => visitOperandNode(arg));
7936
+ node.orderBy?.forEach((order) => visitOrderByNode(order));
7937
+ if (node.separator) {
7938
+ visitOperandNode(node.separator);
7939
+ }
7904
7940
  },
7905
- visitJsonPath: () => {
7941
+ visitJsonPath: (node) => {
7942
+ visitor.visitOperand?.(node);
7943
+ visitOperandNode(node.column);
7906
7944
  },
7907
- visitScalarSubquery: () => {
7945
+ visitScalarSubquery: (node) => {
7946
+ visitor.visitOperand?.(node);
7947
+ visitSelectQuery(node.query, visitor);
7908
7948
  },
7909
7949
  visitCaseExpression: (node) => {
7950
+ visitor.visitOperand?.(node);
7910
7951
  node.conditions.forEach((cond) => {
7911
- if (hasParamOperandsInExpression(cond.when)) {
7912
- hasParams = true;
7913
- }
7914
- if (hasParamOperandsInOperand(cond.then)) {
7915
- hasParams = true;
7916
- }
7952
+ visitExpressionNode(cond.when);
7953
+ visitOperandNode(cond.then);
7917
7954
  });
7918
- if (node.else && hasParamOperandsInOperand(node.else)) {
7919
- hasParams = true;
7955
+ if (node.else) {
7956
+ visitOperandNode(node.else);
7920
7957
  }
7921
7958
  },
7922
7959
  visitCast: (node) => {
7923
- if (hasParamOperandsInOperand(node.expression)) {
7924
- hasParams = true;
7925
- }
7960
+ visitor.visitOperand?.(node);
7961
+ visitOperandNode(node.expression);
7926
7962
  },
7927
7963
  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
- });
7964
+ visitor.visitOperand?.(node);
7965
+ node.args?.forEach((arg) => visitOperandNode(arg));
7966
+ node.partitionBy?.forEach((term) => visitOperandNode(term));
7967
+ node.orderBy?.forEach((order) => visitOrderByNode(order));
7968
+ },
7969
+ visitArithmeticExpression: (node) => {
7970
+ visitor.visitOperand?.(node);
7971
+ visitOperandNode(node.left);
7972
+ visitOperandNode(node.right);
7973
+ },
7974
+ visitBitwiseExpression: (node) => {
7975
+ visitor.visitOperand?.(node);
7976
+ visitOperandNode(node.left);
7977
+ visitOperandNode(node.right);
7978
+ },
7979
+ visitExpression: (node) => {
7980
+ visitExpressionNode(node);
7981
+ },
7982
+ visitSelectQuery: (node) => {
7983
+ visitSelectQuery(node, visitor);
7940
7984
  },
7941
7985
  visitCollate: (node) => {
7942
- if (hasParamOperandsInOperand(node.expression)) {
7943
- hasParams = true;
7944
- }
7986
+ visitor.visitOperand?.(node);
7987
+ visitOperandNode(node.expression);
7945
7988
  },
7946
- visitAliasRef: () => {
7989
+ visitAliasRef: (node) => {
7990
+ visitor.visitOperand?.(node);
7947
7991
  },
7948
- otherwise: () => {
7992
+ otherwise: (node) => {
7993
+ visitor.visitOperand?.(node);
7994
+ }
7995
+ };
7996
+ visitor.visitSelectQuery?.(ast);
7997
+ if (ast.ctes) {
7998
+ for (const cte of ast.ctes) {
7999
+ visitor.visitCte?.(cte);
8000
+ visitSelectQuery(cte.query, visitor);
7949
8001
  }
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
8002
  }
8003
+ visitTableSource(ast.from);
7960
8004
  ast.columns?.forEach((col2) => {
7961
- if (typeof col2 === "object" && col2 !== null && "type" in col2) {
7962
- if (hasParamOperandsInOperand(col2)) {
7963
- return true;
7964
- }
7965
- }
8005
+ visitOperandNode(col2);
7966
8006
  });
7967
- ast.orderBy?.forEach((ord) => {
7968
- if (ord.term) {
7969
- if (hasParamOperandsInOperand(ord.term)) {
7970
- return true;
7971
- }
7972
- }
8007
+ ast.joins?.forEach((join) => {
8008
+ visitor.visitJoin?.(join);
8009
+ visitTableSource(join.table);
8010
+ visitExpressionNode(join.condition);
7973
8011
  });
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
- }
8012
+ if (ast.where) {
8013
+ visitExpressionNode(ast.where);
7980
8014
  }
7981
- if (ast.setOps) {
7982
- for (const op of ast.setOps) {
7983
- if (hasParamOperandsInQuery(op.query)) {
7984
- return true;
8015
+ ast.groupBy?.forEach((term) => {
8016
+ visitOrderingTerm(term);
8017
+ });
8018
+ if (ast.having) {
8019
+ visitExpressionNode(ast.having);
8020
+ }
8021
+ ast.orderBy?.forEach((order) => {
8022
+ visitOrderByNode(order);
8023
+ });
8024
+ ast.distinct?.forEach((col2) => {
8025
+ visitOperandNode(col2);
8026
+ });
8027
+ ast.setOps?.forEach((op) => {
8028
+ visitor.visitSetOperation?.(op);
8029
+ visitSelectQuery(op.query, visitor);
8030
+ });
8031
+ };
8032
+
8033
+ // src/core/ast/ast-validation.ts
8034
+ var findFirstParamOperandName = (ast) => {
8035
+ let name;
8036
+ visitSelectQuery(ast, {
8037
+ visitParam: (node) => {
8038
+ if (!name) {
8039
+ name = node.name;
7985
8040
  }
7986
8041
  }
7987
- }
7988
- return false;
8042
+ });
8043
+ return name;
7989
8044
  };
7990
8045
 
7991
8046
  // src/query-builder/select.ts
@@ -8465,11 +8520,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8465
8520
  * Validates that the query does not contain Param operands.
8466
8521
  * Param proxies are only for schema generation, not execution.
8467
8522
  */
8468
- validateNoParamOperands() {
8523
+ validateNoParamOperands(options) {
8524
+ if (options?.allowParamOperands) return;
8469
8525
  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.");
8526
+ const paramName = findFirstParamOperandName(ast);
8527
+ if (paramName) {
8528
+ throw new Error(`Cannot execute query containing Param operand "${paramName}". Param proxies are only for schema generation (getSchema()). If you need real parameters, use literal values.`);
8473
8529
  }
8474
8530
  }
8475
8531
  /**
@@ -8484,13 +8540,13 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8484
8540
  * // users is User[]
8485
8541
  * users[0] instanceof User; // true
8486
8542
  */
8487
- async execute(ctx) {
8488
- this.validateNoParamOperands();
8543
+ async execute(ctx, options) {
8544
+ this.validateNoParamOperands(options);
8489
8545
  if (this.entityConstructor) {
8490
- return this.executeAs(this.entityConstructor, ctx);
8546
+ return this.executeAs(this.entityConstructor, ctx, options);
8491
8547
  }
8492
8548
  const builder = this.ensureDefaultSelection();
8493
- return executeHydrated(ctx, builder);
8549
+ return executeHydrated(ctx, builder, options);
8494
8550
  }
8495
8551
  /**
8496
8552
  * Executes the query and returns plain row objects (POJOs), ignoring any entity materialization.
@@ -8503,10 +8559,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8503
8559
  * // rows is EntityInstance<UserTable>[] (plain objects)
8504
8560
  * rows[0] instanceof User; // false
8505
8561
  */
8506
- async executePlain(ctx) {
8507
- this.validateNoParamOperands();
8562
+ async executePlain(ctx, options) {
8563
+ this.validateNoParamOperands(options);
8508
8564
  const builder = this.ensureDefaultSelection();
8509
- const rows = await executeHydratedPlain(ctx, builder);
8565
+ const rows = await executeHydratedPlain(ctx, builder, options);
8510
8566
  return rows;
8511
8567
  }
8512
8568
  /**
@@ -8523,10 +8579,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8523
8579
  * users[0] instanceof User; // true!
8524
8580
  * users[0].getFullName(); // works!
8525
8581
  */
8526
- async executeAs(entityClass, ctx) {
8527
- this.validateNoParamOperands();
8582
+ async executeAs(entityClass, ctx, options) {
8583
+ this.validateNoParamOperands(options);
8528
8584
  const builder = this.ensureDefaultSelection();
8529
- const results = await executeHydrated(ctx, builder);
8585
+ const results = await executeHydrated(ctx, builder, options);
8530
8586
  return materializeAs(entityClass, results);
8531
8587
  }
8532
8588
  /**
@@ -8535,9 +8591,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8535
8591
  * @example
8536
8592
  * const total = await qb.count(session);
8537
8593
  */
8538
- async count(session) {
8539
- this.validateNoParamOperands();
8540
- return executeCount(this.context, this.env, session);
8594
+ async count(session, options) {
8595
+ this.validateNoParamOperands(options);
8596
+ return executeCount(this.context, this.env, session, options);
8541
8597
  }
8542
8598
  /**
8543
8599
  * Executes the query and returns both the paged items and the total.
@@ -8546,9 +8602,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8546
8602
  * const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
8547
8603
  */
8548
8604
  async executePaged(session, options) {
8549
- this.validateNoParamOperands();
8605
+ this.validateNoParamOperands(options);
8550
8606
  const builder = this.ensureDefaultSelection();
8551
- return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
8607
+ return executePagedQuery(builder, session, options, (sess) => builder.count(sess, options), options);
8552
8608
  }
8553
8609
  /**
8554
8610
  * Executes the query with provided execution and hydration contexts
@@ -8560,10 +8616,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8560
8616
  * const hydCtx = new HydrationContext();
8561
8617
  * const users = await qb.executeWithContexts(execCtx, hydCtx);
8562
8618
  */
8563
- async executeWithContexts(execCtx, hydCtx) {
8564
- this.validateNoParamOperands();
8619
+ async executeWithContexts(execCtx, hydCtx, options) {
8620
+ this.validateNoParamOperands(options);
8565
8621
  const builder = this.ensureDefaultSelection();
8566
- const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
8622
+ const results = await executeHydratedWithContexts(execCtx, hydCtx, builder, options);
8567
8623
  if (this.entityConstructor) {
8568
8624
  return materializeAs(this.entityConstructor, results);
8569
8625
  }
@@ -8796,9 +8852,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8796
8852
  * .compile('postgres');
8797
8853
  * console.log(compiled.sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
8798
8854
  */
8799
- compile(dialect) {
8855
+ compile(dialect, options) {
8800
8856
  const resolved = resolveDialectInput(dialect);
8801
- return resolved.compileSelect(this.getAST());
8857
+ const ast = this.getAST();
8858
+ if (!options?.allowParamOperands) {
8859
+ const paramName = findFirstParamOperandName(ast);
8860
+ if (paramName) {
8861
+ throw new Error(`Cannot compile query containing Param operand "${paramName}". Param proxies are only for schema generation (getSchema()). If you need real parameters, use literal values.`);
8862
+ }
8863
+ return resolved.compileSelect(ast);
8864
+ }
8865
+ return resolved.compileSelectWithOptions(ast, { allowParams: true });
8802
8866
  }
8803
8867
  /**
8804
8868
  * Converts the query to SQL string for a specific dialect
@@ -8810,8 +8874,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8810
8874
  * .toSql('postgres');
8811
8875
  * console.log(sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
8812
8876
  */
8813
- toSql(dialect) {
8814
- return this.compile(dialect).sql;
8877
+ toSql(dialect, options) {
8878
+ return this.compile(dialect, options).sql;
8815
8879
  }
8816
8880
  /**
8817
8881
  * Gets hydration plan for query
@@ -14500,8 +14564,10 @@ function createPooledExecutorFactory(opts) {
14500
14564
  groupConcat,
14501
14565
  gt,
14502
14566
  gte,
14567
+ hasExpressionDispatcher,
14503
14568
  hasMany,
14504
14569
  hasOne,
14570
+ hasOperandDispatcher,
14505
14571
  hour,
14506
14572
  hydrateRows,
14507
14573
  ifNull,