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.js CHANGED
@@ -371,16 +371,27 @@ var operandTypes = /* @__PURE__ */ new Set([
371
371
  "BitwiseExpression",
372
372
  "Collate"
373
373
  ]);
374
- var hasTypeProperty = (value) => typeof value === "object" && value !== null && "type" in value;
374
+ var getNodeType = (value) => {
375
+ if (typeof value !== "object" || value === null) return void 0;
376
+ const descriptor = Object.getOwnPropertyDescriptor(value, "type");
377
+ if (descriptor && typeof descriptor.value === "string") {
378
+ return descriptor.value;
379
+ }
380
+ if ("type" in value) {
381
+ const type = value.type;
382
+ return typeof type === "string" ? type : void 0;
383
+ }
384
+ return void 0;
385
+ };
375
386
  var isOperandNode = (node) => {
376
- if (!hasTypeProperty(node)) return false;
377
- return operandTypes.has(node.type);
378
- };
379
- var isFunctionNode = (node) => isOperandNode(node) && node.type === "Function";
380
- var isCaseExpressionNode = (node) => isOperandNode(node) && node.type === "CaseExpression";
381
- var isCastExpressionNode = (node) => isOperandNode(node) && node.type === "Cast";
382
- var isCollateExpressionNode = (node) => isOperandNode(node) && node.type === "Collate";
383
- var isWindowFunctionNode = (node) => isOperandNode(node) && node.type === "WindowFunction";
387
+ const type = getNodeType(node);
388
+ return type !== void 0 && operandTypes.has(type);
389
+ };
390
+ var isFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "Function";
391
+ var isCaseExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "CaseExpression";
392
+ var isCastExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Cast";
393
+ var isCollateExpressionNode = (node) => isOperandNode(node) && getNodeType(node) === "Collate";
394
+ var isWindowFunctionNode = (node) => isOperandNode(node) && getNodeType(node) === "WindowFunction";
384
395
  var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressionNode(node) || isCastExpressionNode(node) || isWindowFunctionNode(node);
385
396
 
386
397
  // src/core/ast/expression-builders.ts
@@ -759,23 +770,34 @@ var registerExpressionDispatcher = (type, dispatcher) => {
759
770
  var registerOperandDispatcher = (type, dispatcher) => {
760
771
  operandRegistry = operandRegistry.register(type, dispatcher);
761
772
  };
773
+ var hasExpressionDispatcher = (type) => expressionRegistry.get(type) !== void 0;
774
+ var hasOperandDispatcher = (type) => operandRegistry.get(type) !== void 0;
762
775
  var clearExpressionDispatchers = () => {
763
776
  expressionRegistry = expressionRegistry.clear();
764
777
  };
765
778
  var clearOperandDispatchers = () => {
766
779
  operandRegistry = operandRegistry.clear();
767
780
  };
768
- var getNodeType = (node) => typeof node === "object" && node !== null && typeof node.type === "string" ? node.type : void 0;
781
+ var getNodeType2 = (node) => {
782
+ if (typeof node !== "object" || node === null) return void 0;
783
+ const descriptor = Object.getOwnPropertyDescriptor(node, "type");
784
+ if (descriptor && typeof descriptor.value === "string") {
785
+ return descriptor.value;
786
+ }
787
+ const type = node.type;
788
+ return typeof type === "string" ? type : void 0;
789
+ };
769
790
  var unsupportedExpression = (node) => {
770
- throw new Error(`Unsupported expression type "${getNodeType(node) ?? "unknown"}"`);
791
+ throw new Error(`Unsupported expression type "${getNodeType2(node) ?? "unknown"}"`);
771
792
  };
772
793
  var unsupportedOperand = (node) => {
773
- throw new Error(`Unsupported operand type "${getNodeType(node) ?? "unknown"}"`);
794
+ throw new Error(`Unsupported operand type "${getNodeType2(node) ?? "unknown"}"`);
774
795
  };
775
796
  var visitExpression = (node, visitor) => {
776
- const dynamic = expressionRegistry.get(node.type);
797
+ const type = getNodeType2(node);
798
+ const dynamic = type ? expressionRegistry.get(type) : void 0;
777
799
  if (dynamic) return dynamic(node, visitor);
778
- switch (node.type) {
800
+ switch (type) {
779
801
  case "BinaryExpression":
780
802
  if (visitor.visitBinaryExpression) return visitor.visitBinaryExpression(node);
781
803
  break;
@@ -807,9 +829,10 @@ var visitExpression = (node, visitor) => {
807
829
  return unsupportedExpression(node);
808
830
  };
809
831
  var visitOperand = (node, visitor) => {
810
- const dynamic = operandRegistry.get(node.type);
832
+ const type = getNodeType2(node);
833
+ const dynamic = type ? operandRegistry.get(type) : void 0;
811
834
  if (dynamic) return dynamic(node, visitor);
812
- switch (node.type) {
835
+ switch (type) {
813
836
  case "Column":
814
837
  if (visitor.visitColumn) return visitor.visitColumn(node);
815
838
  break;
@@ -843,6 +866,12 @@ var visitOperand = (node, visitor) => {
843
866
  case "Collate":
844
867
  if (visitor.visitCollate) return visitor.visitCollate(node);
845
868
  break;
869
+ case "ArithmeticExpression":
870
+ if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
871
+ break;
872
+ case "BitwiseExpression":
873
+ if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node);
874
+ break;
846
875
  default:
847
876
  break;
848
877
  }
@@ -1538,9 +1567,11 @@ var Dialect = class _Dialect {
1538
1567
  * @returns Compiled SQL operand
1539
1568
  */
1540
1569
  compileOperand(node, ctx) {
1541
- const compiler = this.operandCompilers.get(node.type);
1570
+ const descriptor = Object.getOwnPropertyDescriptor(node, "type");
1571
+ const nodeType = typeof descriptor?.value === "string" ? descriptor.value : typeof node.type === "string" ? node.type : void 0;
1572
+ const compiler = nodeType ? this.operandCompilers.get(nodeType) : void 0;
1542
1573
  if (!compiler) {
1543
- throw new Error(`Unsupported operand node type "${node.type}" for ${this.constructor.name}`);
1574
+ throw new Error(`Unsupported operand node type "${nodeType ?? "unknown"}" for ${this.constructor.name}`);
1544
1575
  }
1545
1576
  return compiler(node, ctx);
1546
1577
  }
@@ -3861,6 +3892,10 @@ var QueryAstService = class {
3861
3892
  * @returns Normalized ordering term
3862
3893
  */
3863
3894
  normalizeOrderingTerm(term) {
3895
+ const paramNode = this.toParamNode(term);
3896
+ if (paramNode) {
3897
+ return paramNode;
3898
+ }
3864
3899
  const from = this.state.ast.from;
3865
3900
  const tableRef2 = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
3866
3901
  const termType = term.type;
@@ -3878,6 +3913,14 @@ var QueryAstService = class {
3878
3913
  }
3879
3914
  return buildColumnNode(tableRef2, term);
3880
3915
  }
3916
+ toParamNode(value) {
3917
+ if (typeof value !== "object" || value === null) return void 0;
3918
+ const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
3919
+ if (type !== "Param") return void 0;
3920
+ const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
3921
+ if (typeof name !== "string") return void 0;
3922
+ return { type: "Param", name };
3923
+ }
3881
3924
  };
3882
3925
 
3883
3926
  // src/query-builder/relation-projection-helper.ts
@@ -6117,9 +6160,9 @@ var flattenResults = (results) => {
6117
6160
  }
6118
6161
  return rows;
6119
6162
  };
6120
- var executeWithContexts = async (execCtx, entityCtx, qb) => {
6163
+ var executeWithContexts = async (execCtx, entityCtx, qb, options) => {
6121
6164
  const ast = qb.getAST();
6122
- const compiled = execCtx.dialect.compileSelect(ast);
6165
+ const compiled = options?.allowParamOperands ? execCtx.dialect.compileSelectWithOptions(ast, { allowParams: true }) : execCtx.dialect.compileSelect(ast);
6123
6166
  const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
6124
6167
  const rows = flattenResults(executed);
6125
6168
  const lazyRelations = qb.getLazyRelations();
@@ -6137,9 +6180,9 @@ var executeWithContexts = async (execCtx, entityCtx, qb) => {
6137
6180
  await preloadRelationIncludes(entities, includeTree);
6138
6181
  return entities;
6139
6182
  };
6140
- var executePlainWithContexts = async (execCtx, qb) => {
6183
+ var executePlainWithContexts = async (execCtx, qb, options) => {
6141
6184
  const ast = qb.getAST();
6142
- const compiled = execCtx.dialect.compileSelect(ast);
6185
+ const compiled = options?.allowParamOperands ? execCtx.dialect.compileSelectWithOptions(ast, { allowParams: true }) : execCtx.dialect.compileSelect(ast);
6143
6186
  const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
6144
6187
  const rows = flattenResults(executed);
6145
6188
  if (ast.setOps && ast.setOps.length > 0) {
@@ -6147,21 +6190,21 @@ var executePlainWithContexts = async (execCtx, qb) => {
6147
6190
  }
6148
6191
  return hydrateRows(rows, qb.getHydrationPlan());
6149
6192
  };
6150
- async function executeHydrated(session, qb) {
6151
- return executeWithContexts(session.getExecutionContext(), session, qb);
6193
+ async function executeHydrated(session, qb, options) {
6194
+ return executeWithContexts(session.getExecutionContext(), session, qb, options);
6152
6195
  }
6153
- async function executeHydratedPlain(session, qb) {
6154
- return executePlainWithContexts(session.getExecutionContext(), qb);
6196
+ async function executeHydratedPlain(session, qb, options) {
6197
+ return executePlainWithContexts(session.getExecutionContext(), qb, options);
6155
6198
  }
6156
- async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
6199
+ async function executeHydratedWithContexts(execCtx, hydCtx, qb, options) {
6157
6200
  const entityCtx = hydCtx.entityContext;
6158
6201
  if (!entityCtx) {
6159
6202
  throw new Error("Hydration context is missing an EntityContext");
6160
6203
  }
6161
- return executeWithContexts(execCtx, entityCtx, qb);
6204
+ return executeWithContexts(execCtx, entityCtx, qb, options);
6162
6205
  }
6163
- async function executeHydratedPlainWithContexts(execCtx, qb) {
6164
- return executePlainWithContexts(execCtx, qb);
6206
+ async function executeHydratedPlainWithContexts(execCtx, qb, options) {
6207
+ return executePlainWithContexts(execCtx, qb, options);
6165
6208
  }
6166
6209
  var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOptions) => {
6167
6210
  if (!lazyRelations.length) return;
@@ -6362,7 +6405,7 @@ function applyOrderBy(context, predicateFacet, term, directionOrOptions) {
6362
6405
  const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
6363
6406
  return predicateFacet.orderBy(context, term, dir, options.nulls, options.collation);
6364
6407
  }
6365
- async function executeCount(context, env, session) {
6408
+ async function executeCount(context, env, session, options) {
6366
6409
  const unpagedAst = {
6367
6410
  ...context.state.ast,
6368
6411
  orderBy: void 0,
@@ -6382,7 +6425,7 @@ async function executeCount(context, env, session) {
6382
6425
  joins: []
6383
6426
  };
6384
6427
  const execCtx = session.getExecutionContext();
6385
- const compiled = execCtx.dialect.compileSelect(countQuery);
6428
+ const compiled = options?.allowParamOperands ? execCtx.dialect.compileSelectWithOptions(countQuery, { allowParams: true }) : execCtx.dialect.compileSelect(countQuery);
6386
6429
  const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
6387
6430
  const value = results[0]?.values?.[0]?.[0];
6388
6431
  if (typeof value === "number") return value;
@@ -6390,7 +6433,7 @@ async function executeCount(context, env, session) {
6390
6433
  if (typeof value === "string") return Number(value);
6391
6434
  return value === null || value === void 0 ? 0 : Number(value);
6392
6435
  }
6393
- async function executePagedQuery(builder, session, options, countCallback) {
6436
+ async function executePagedQuery(builder, session, options, countCallback, paramOptions) {
6394
6437
  const { page, pageSize } = options;
6395
6438
  if (!Number.isInteger(page) || page < 1) {
6396
6439
  throw new Error("executePaged: page must be an integer >= 1");
@@ -6400,7 +6443,7 @@ async function executePagedQuery(builder, session, options, countCallback) {
6400
6443
  }
6401
6444
  const offset = (page - 1) * pageSize;
6402
6445
  const totalItems = await countCallback(session);
6403
- const items = await builder.limit(pageSize).offset(offset).execute(session);
6446
+ const items = await builder.limit(pageSize).offset(offset).execute(session, paramOptions);
6404
6447
  return { items, totalItems, page, pageSize };
6405
6448
  }
6406
6449
  function buildWhereHasPredicate(env, context, relationFacet, createChildBuilder, relationName, callbackOrOptions, maybeOptions, negate = false) {
@@ -7483,225 +7526,235 @@ var buildFilterParameters = (table, where, from, options = {}) => {
7483
7526
  }];
7484
7527
  };
7485
7528
 
7486
- // src/core/ast/ast-validation.ts
7487
- var hasParamOperandsInExpression = (expr) => {
7488
- let hasParams = false;
7489
- visitExpression(expr, {
7529
+ // src/core/ast/query-visitor.ts
7530
+ var getNodeType3 = (value) => {
7531
+ if (typeof value !== "object" || value === null) return void 0;
7532
+ const descriptor = Object.getOwnPropertyDescriptor(value, "type");
7533
+ if (descriptor && typeof descriptor.value === "string") {
7534
+ return descriptor.value;
7535
+ }
7536
+ if ("type" in value) {
7537
+ const type = value.type;
7538
+ return typeof type === "string" ? type : void 0;
7539
+ }
7540
+ return void 0;
7541
+ };
7542
+ var visitSelectQuery = (ast, visitor) => {
7543
+ const visitExpressionNode = (node) => {
7544
+ visitExpression(node, expressionVisitor);
7545
+ };
7546
+ const visitOperandNode = (node) => {
7547
+ visitOperand(node, operandVisitor);
7548
+ };
7549
+ const visitOrderingTerm = (term) => {
7550
+ if (!term || typeof term !== "object") return;
7551
+ if (isOperandNode(term)) {
7552
+ visitOperandNode(term);
7553
+ return;
7554
+ }
7555
+ const type = getNodeType3(term);
7556
+ if (type && hasOperandDispatcher(type)) {
7557
+ visitOperandNode(term);
7558
+ return;
7559
+ }
7560
+ if (type) {
7561
+ visitExpressionNode(term);
7562
+ }
7563
+ };
7564
+ const visitOrderByNode = (node) => {
7565
+ visitor.visitOrderBy?.(node);
7566
+ visitOrderingTerm(node.term);
7567
+ };
7568
+ const visitTableSource = (source) => {
7569
+ visitor.visitTableSource?.(source);
7570
+ if (source.type === "DerivedTable") {
7571
+ visitor.visitDerivedTable?.(source);
7572
+ visitSelectQuery(source.query, visitor);
7573
+ return;
7574
+ }
7575
+ if (source.type === "FunctionTable") {
7576
+ visitor.visitFunctionTable?.(source);
7577
+ source.args?.forEach((arg) => visitOperandNode(arg));
7578
+ }
7579
+ };
7580
+ const expressionVisitor = {
7490
7581
  visitBinaryExpression: (node) => {
7491
- visitOperand(node.left, {
7492
- visitParam: () => {
7493
- hasParams = true;
7494
- },
7495
- otherwise: () => {
7496
- }
7497
- });
7498
- visitOperand(node.right, {
7499
- visitParam: () => {
7500
- hasParams = true;
7501
- },
7502
- otherwise: () => {
7503
- }
7504
- });
7582
+ visitor.visitExpression?.(node);
7583
+ visitOperandNode(node.left);
7584
+ visitOperandNode(node.right);
7505
7585
  if (node.escape) {
7506
- visitOperand(node.escape, {
7507
- visitParam: () => {
7508
- hasParams = true;
7509
- },
7510
- otherwise: () => {
7511
- }
7512
- });
7586
+ visitOperandNode(node.escape);
7513
7587
  }
7514
7588
  },
7515
7589
  visitLogicalExpression: (node) => {
7516
- node.operands.forEach((operand) => {
7517
- if (hasParamOperandsInExpression(operand)) {
7518
- hasParams = true;
7519
- }
7520
- });
7590
+ visitor.visitExpression?.(node);
7591
+ node.operands.forEach((operand) => visitExpressionNode(operand));
7521
7592
  },
7522
- visitNullExpression: () => {
7593
+ visitNullExpression: (node) => {
7594
+ visitor.visitExpression?.(node);
7595
+ visitOperandNode(node.left);
7523
7596
  },
7524
7597
  visitInExpression: (node) => {
7525
- visitOperand(node.left, {
7526
- visitParam: () => {
7527
- hasParams = true;
7528
- },
7529
- otherwise: () => {
7530
- }
7531
- });
7598
+ visitor.visitExpression?.(node);
7599
+ visitOperandNode(node.left);
7532
7600
  if (Array.isArray(node.right)) {
7533
- node.right.forEach((operand) => visitOperand(operand, {
7534
- visitParam: () => {
7535
- hasParams = true;
7536
- },
7537
- otherwise: () => {
7538
- }
7539
- }));
7601
+ node.right.forEach((operand) => visitOperandNode(operand));
7602
+ } else {
7603
+ visitOperandNode(node.right);
7540
7604
  }
7541
7605
  },
7542
- visitExistsExpression: () => {
7606
+ visitExistsExpression: (node) => {
7607
+ visitor.visitExpression?.(node);
7608
+ visitSelectQuery(node.subquery, visitor);
7543
7609
  },
7544
7610
  visitBetweenExpression: (node) => {
7545
- visitOperand(node.left, {
7546
- visitParam: () => {
7547
- hasParams = true;
7548
- },
7549
- otherwise: () => {
7550
- }
7551
- });
7552
- visitOperand(node.lower, {
7553
- visitParam: () => {
7554
- hasParams = true;
7555
- },
7556
- otherwise: () => {
7557
- }
7558
- });
7559
- visitOperand(node.upper, {
7560
- visitParam: () => {
7561
- hasParams = true;
7562
- },
7563
- otherwise: () => {
7564
- }
7565
- });
7611
+ visitor.visitExpression?.(node);
7612
+ visitOperandNode(node.left);
7613
+ visitOperandNode(node.lower);
7614
+ visitOperandNode(node.upper);
7566
7615
  },
7567
7616
  visitArithmeticExpression: (node) => {
7568
- visitOperand(node.left, {
7569
- visitParam: () => {
7570
- hasParams = true;
7571
- },
7572
- otherwise: () => {
7573
- }
7574
- });
7575
- visitOperand(node.right, {
7576
- visitParam: () => {
7577
- hasParams = true;
7578
- },
7579
- otherwise: () => {
7580
- }
7581
- });
7617
+ visitor.visitExpression?.(node);
7618
+ visitOperandNode(node.left);
7619
+ visitOperandNode(node.right);
7582
7620
  },
7583
7621
  visitBitwiseExpression: (node) => {
7584
- visitOperand(node.left, {
7585
- visitParam: () => {
7586
- hasParams = true;
7587
- },
7588
- otherwise: () => {
7589
- }
7590
- });
7591
- visitOperand(node.right, {
7592
- visitParam: () => {
7593
- hasParams = true;
7594
- },
7595
- otherwise: () => {
7596
- }
7597
- });
7622
+ visitor.visitExpression?.(node);
7623
+ visitOperandNode(node.left);
7624
+ visitOperandNode(node.right);
7598
7625
  },
7599
- otherwise: () => {
7626
+ visitOperand: (node) => {
7627
+ visitOperandNode(node);
7628
+ },
7629
+ visitSelectQuery: (node) => {
7630
+ visitSelectQuery(node, visitor);
7631
+ },
7632
+ otherwise: (node) => {
7633
+ visitor.visitExpression?.(node);
7600
7634
  }
7601
- });
7602
- return hasParams;
7603
- };
7604
- var hasParamOperandsInOperand = (operand) => {
7605
- let hasParams = false;
7606
- visitOperand(operand, {
7607
- visitColumn: () => {
7635
+ };
7636
+ const operandVisitor = {
7637
+ visitColumn: (node) => {
7638
+ visitor.visitOperand?.(node);
7608
7639
  },
7609
- visitLiteral: () => {
7640
+ visitLiteral: (node) => {
7641
+ visitor.visitOperand?.(node);
7610
7642
  },
7611
- visitParam: () => {
7612
- hasParams = true;
7643
+ visitParam: (node) => {
7644
+ visitor.visitOperand?.(node);
7645
+ visitor.visitParam?.(node);
7613
7646
  },
7614
7647
  visitFunction: (node) => {
7615
- node.args?.forEach((arg) => {
7616
- if (hasParamOperandsInOperand(arg)) {
7617
- hasParams = true;
7618
- }
7619
- });
7648
+ visitor.visitOperand?.(node);
7649
+ node.args?.forEach((arg) => visitOperandNode(arg));
7650
+ node.orderBy?.forEach((order) => visitOrderByNode(order));
7651
+ if (node.separator) {
7652
+ visitOperandNode(node.separator);
7653
+ }
7620
7654
  },
7621
- visitJsonPath: () => {
7655
+ visitJsonPath: (node) => {
7656
+ visitor.visitOperand?.(node);
7657
+ visitOperandNode(node.column);
7622
7658
  },
7623
- visitScalarSubquery: () => {
7659
+ visitScalarSubquery: (node) => {
7660
+ visitor.visitOperand?.(node);
7661
+ visitSelectQuery(node.query, visitor);
7624
7662
  },
7625
7663
  visitCaseExpression: (node) => {
7664
+ visitor.visitOperand?.(node);
7626
7665
  node.conditions.forEach((cond) => {
7627
- if (hasParamOperandsInExpression(cond.when)) {
7628
- hasParams = true;
7629
- }
7630
- if (hasParamOperandsInOperand(cond.then)) {
7631
- hasParams = true;
7632
- }
7666
+ visitExpressionNode(cond.when);
7667
+ visitOperandNode(cond.then);
7633
7668
  });
7634
- if (node.else && hasParamOperandsInOperand(node.else)) {
7635
- hasParams = true;
7669
+ if (node.else) {
7670
+ visitOperandNode(node.else);
7636
7671
  }
7637
7672
  },
7638
7673
  visitCast: (node) => {
7639
- if (hasParamOperandsInOperand(node.expression)) {
7640
- hasParams = true;
7641
- }
7674
+ visitor.visitOperand?.(node);
7675
+ visitOperandNode(node.expression);
7642
7676
  },
7643
7677
  visitWindowFunction: (node) => {
7644
- node.args?.forEach((arg) => {
7645
- if (hasParamOperandsInOperand(arg)) {
7646
- hasParams = true;
7647
- }
7648
- });
7649
- node.orderBy?.forEach((ord) => {
7650
- if (ord.term) {
7651
- if (hasParamOperandsInOperand(ord.term)) {
7652
- hasParams = true;
7653
- }
7654
- }
7655
- });
7678
+ visitor.visitOperand?.(node);
7679
+ node.args?.forEach((arg) => visitOperandNode(arg));
7680
+ node.partitionBy?.forEach((term) => visitOperandNode(term));
7681
+ node.orderBy?.forEach((order) => visitOrderByNode(order));
7682
+ },
7683
+ visitArithmeticExpression: (node) => {
7684
+ visitor.visitOperand?.(node);
7685
+ visitOperandNode(node.left);
7686
+ visitOperandNode(node.right);
7687
+ },
7688
+ visitBitwiseExpression: (node) => {
7689
+ visitor.visitOperand?.(node);
7690
+ visitOperandNode(node.left);
7691
+ visitOperandNode(node.right);
7692
+ },
7693
+ visitExpression: (node) => {
7694
+ visitExpressionNode(node);
7695
+ },
7696
+ visitSelectQuery: (node) => {
7697
+ visitSelectQuery(node, visitor);
7656
7698
  },
7657
7699
  visitCollate: (node) => {
7658
- if (hasParamOperandsInOperand(node.expression)) {
7659
- hasParams = true;
7660
- }
7700
+ visitor.visitOperand?.(node);
7701
+ visitOperandNode(node.expression);
7661
7702
  },
7662
- visitAliasRef: () => {
7703
+ visitAliasRef: (node) => {
7704
+ visitor.visitOperand?.(node);
7663
7705
  },
7664
- otherwise: () => {
7706
+ otherwise: (node) => {
7707
+ visitor.visitOperand?.(node);
7708
+ }
7709
+ };
7710
+ visitor.visitSelectQuery?.(ast);
7711
+ if (ast.ctes) {
7712
+ for (const cte of ast.ctes) {
7713
+ visitor.visitCte?.(cte);
7714
+ visitSelectQuery(cte.query, visitor);
7665
7715
  }
7666
- });
7667
- return hasParams;
7668
- };
7669
- var hasParamOperandsInQuery = (ast) => {
7670
- if (ast.where && hasParamOperandsInExpression(ast.where)) {
7671
- return true;
7672
- }
7673
- if (ast.having && hasParamOperandsInExpression(ast.having)) {
7674
- return true;
7675
7716
  }
7717
+ visitTableSource(ast.from);
7676
7718
  ast.columns?.forEach((col2) => {
7677
- if (typeof col2 === "object" && col2 !== null && "type" in col2) {
7678
- if (hasParamOperandsInOperand(col2)) {
7679
- return true;
7680
- }
7681
- }
7719
+ visitOperandNode(col2);
7682
7720
  });
7683
- ast.orderBy?.forEach((ord) => {
7684
- if (ord.term) {
7685
- if (hasParamOperandsInOperand(ord.term)) {
7686
- return true;
7687
- }
7688
- }
7721
+ ast.joins?.forEach((join) => {
7722
+ visitor.visitJoin?.(join);
7723
+ visitTableSource(join.table);
7724
+ visitExpressionNode(join.condition);
7689
7725
  });
7690
- if (ast.ctes) {
7691
- for (const cte of ast.ctes) {
7692
- if (cte.query.where && hasParamOperandsInExpression(cte.query.where)) {
7693
- return true;
7694
- }
7695
- }
7726
+ if (ast.where) {
7727
+ visitExpressionNode(ast.where);
7696
7728
  }
7697
- if (ast.setOps) {
7698
- for (const op of ast.setOps) {
7699
- if (hasParamOperandsInQuery(op.query)) {
7700
- return true;
7729
+ ast.groupBy?.forEach((term) => {
7730
+ visitOrderingTerm(term);
7731
+ });
7732
+ if (ast.having) {
7733
+ visitExpressionNode(ast.having);
7734
+ }
7735
+ ast.orderBy?.forEach((order) => {
7736
+ visitOrderByNode(order);
7737
+ });
7738
+ ast.distinct?.forEach((col2) => {
7739
+ visitOperandNode(col2);
7740
+ });
7741
+ ast.setOps?.forEach((op) => {
7742
+ visitor.visitSetOperation?.(op);
7743
+ visitSelectQuery(op.query, visitor);
7744
+ });
7745
+ };
7746
+
7747
+ // src/core/ast/ast-validation.ts
7748
+ var findFirstParamOperandName = (ast) => {
7749
+ let name;
7750
+ visitSelectQuery(ast, {
7751
+ visitParam: (node) => {
7752
+ if (!name) {
7753
+ name = node.name;
7701
7754
  }
7702
7755
  }
7703
- }
7704
- return false;
7756
+ });
7757
+ return name;
7705
7758
  };
7706
7759
 
7707
7760
  // src/query-builder/select.ts
@@ -8181,11 +8234,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8181
8234
  * Validates that the query does not contain Param operands.
8182
8235
  * Param proxies are only for schema generation, not execution.
8183
8236
  */
8184
- validateNoParamOperands() {
8237
+ validateNoParamOperands(options) {
8238
+ if (options?.allowParamOperands) return;
8185
8239
  const ast = this.context.hydration.applyToAst(this.context.state.ast);
8186
- const hasParams = hasParamOperandsInQuery(ast);
8187
- if (hasParams) {
8188
- 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.");
8240
+ const paramName = findFirstParamOperandName(ast);
8241
+ if (paramName) {
8242
+ 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.`);
8189
8243
  }
8190
8244
  }
8191
8245
  /**
@@ -8200,13 +8254,13 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8200
8254
  * // users is User[]
8201
8255
  * users[0] instanceof User; // true
8202
8256
  */
8203
- async execute(ctx) {
8204
- this.validateNoParamOperands();
8257
+ async execute(ctx, options) {
8258
+ this.validateNoParamOperands(options);
8205
8259
  if (this.entityConstructor) {
8206
- return this.executeAs(this.entityConstructor, ctx);
8260
+ return this.executeAs(this.entityConstructor, ctx, options);
8207
8261
  }
8208
8262
  const builder = this.ensureDefaultSelection();
8209
- return executeHydrated(ctx, builder);
8263
+ return executeHydrated(ctx, builder, options);
8210
8264
  }
8211
8265
  /**
8212
8266
  * Executes the query and returns plain row objects (POJOs), ignoring any entity materialization.
@@ -8219,10 +8273,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8219
8273
  * // rows is EntityInstance<UserTable>[] (plain objects)
8220
8274
  * rows[0] instanceof User; // false
8221
8275
  */
8222
- async executePlain(ctx) {
8223
- this.validateNoParamOperands();
8276
+ async executePlain(ctx, options) {
8277
+ this.validateNoParamOperands(options);
8224
8278
  const builder = this.ensureDefaultSelection();
8225
- const rows = await executeHydratedPlain(ctx, builder);
8279
+ const rows = await executeHydratedPlain(ctx, builder, options);
8226
8280
  return rows;
8227
8281
  }
8228
8282
  /**
@@ -8239,10 +8293,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8239
8293
  * users[0] instanceof User; // true!
8240
8294
  * users[0].getFullName(); // works!
8241
8295
  */
8242
- async executeAs(entityClass, ctx) {
8243
- this.validateNoParamOperands();
8296
+ async executeAs(entityClass, ctx, options) {
8297
+ this.validateNoParamOperands(options);
8244
8298
  const builder = this.ensureDefaultSelection();
8245
- const results = await executeHydrated(ctx, builder);
8299
+ const results = await executeHydrated(ctx, builder, options);
8246
8300
  return materializeAs(entityClass, results);
8247
8301
  }
8248
8302
  /**
@@ -8251,9 +8305,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8251
8305
  * @example
8252
8306
  * const total = await qb.count(session);
8253
8307
  */
8254
- async count(session) {
8255
- this.validateNoParamOperands();
8256
- return executeCount(this.context, this.env, session);
8308
+ async count(session, options) {
8309
+ this.validateNoParamOperands(options);
8310
+ return executeCount(this.context, this.env, session, options);
8257
8311
  }
8258
8312
  /**
8259
8313
  * Executes the query and returns both the paged items and the total.
@@ -8262,9 +8316,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8262
8316
  * const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
8263
8317
  */
8264
8318
  async executePaged(session, options) {
8265
- this.validateNoParamOperands();
8319
+ this.validateNoParamOperands(options);
8266
8320
  const builder = this.ensureDefaultSelection();
8267
- return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
8321
+ return executePagedQuery(builder, session, options, (sess) => builder.count(sess, options), options);
8268
8322
  }
8269
8323
  /**
8270
8324
  * Executes the query with provided execution and hydration contexts
@@ -8276,10 +8330,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8276
8330
  * const hydCtx = new HydrationContext();
8277
8331
  * const users = await qb.executeWithContexts(execCtx, hydCtx);
8278
8332
  */
8279
- async executeWithContexts(execCtx, hydCtx) {
8280
- this.validateNoParamOperands();
8333
+ async executeWithContexts(execCtx, hydCtx, options) {
8334
+ this.validateNoParamOperands(options);
8281
8335
  const builder = this.ensureDefaultSelection();
8282
- const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
8336
+ const results = await executeHydratedWithContexts(execCtx, hydCtx, builder, options);
8283
8337
  if (this.entityConstructor) {
8284
8338
  return materializeAs(this.entityConstructor, results);
8285
8339
  }
@@ -8512,9 +8566,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8512
8566
  * .compile('postgres');
8513
8567
  * console.log(compiled.sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
8514
8568
  */
8515
- compile(dialect) {
8569
+ compile(dialect, options) {
8516
8570
  const resolved = resolveDialectInput(dialect);
8517
- return resolved.compileSelect(this.getAST());
8571
+ const ast = this.getAST();
8572
+ if (!options?.allowParamOperands) {
8573
+ const paramName = findFirstParamOperandName(ast);
8574
+ if (paramName) {
8575
+ 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.`);
8576
+ }
8577
+ return resolved.compileSelect(ast);
8578
+ }
8579
+ return resolved.compileSelectWithOptions(ast, { allowParams: true });
8518
8580
  }
8519
8581
  /**
8520
8582
  * Converts the query to SQL string for a specific dialect
@@ -8526,8 +8588,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8526
8588
  * .toSql('postgres');
8527
8589
  * console.log(sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
8528
8590
  */
8529
- toSql(dialect) {
8530
- return this.compile(dialect).sql;
8591
+ toSql(dialect, options) {
8592
+ return this.compile(dialect, options).sql;
8531
8593
  }
8532
8594
  /**
8533
8595
  * Gets hydration plan for query
@@ -14215,8 +14277,10 @@ export {
14215
14277
  groupConcat,
14216
14278
  gt,
14217
14279
  gte,
14280
+ hasExpressionDispatcher,
14218
14281
  hasMany,
14219
14282
  hasOne,
14283
+ hasOperandDispatcher,
14220
14284
  hour,
14221
14285
  hydrateRows,
14222
14286
  ifNull,