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.js CHANGED
@@ -360,6 +360,7 @@ var operandTypes = /* @__PURE__ */ new Set([
360
360
  "AliasRef",
361
361
  "Column",
362
362
  "Literal",
363
+ "Param",
363
364
  "Function",
364
365
  "JsonPath",
365
366
  "ScalarSubquery",
@@ -388,6 +389,14 @@ var toLiteralNode = (value) => ({
388
389
  type: "Literal",
389
390
  value: value instanceof Date ? value.toISOString() : value
390
391
  });
392
+ var toParamNode = (value) => {
393
+ if (typeof value !== "object" || value === null) return void 0;
394
+ const type = Object.getOwnPropertyDescriptor(value, "type")?.value;
395
+ if (type !== "Param") return void 0;
396
+ const name = Object.getOwnPropertyDescriptor(value, "name")?.value;
397
+ if (typeof name !== "string") return void 0;
398
+ return { type: "Param", name };
399
+ };
391
400
  var columnRefToNode = (col2) => {
392
401
  if (!col2.table) {
393
402
  throw new Error(
@@ -397,6 +406,10 @@ var columnRefToNode = (col2) => {
397
406
  return { type: "Column", table: col2.table, name: col2.name };
398
407
  };
399
408
  var toOperandNode = (value) => {
409
+ const paramNode = toParamNode(value);
410
+ if (paramNode) {
411
+ return paramNode;
412
+ }
400
413
  if (isOperandNode(value)) {
401
414
  return value;
402
415
  }
@@ -406,6 +419,10 @@ var toOperandNode = (value) => {
406
419
  return columnRefToNode(value);
407
420
  };
408
421
  var valueToOperand = (value) => {
422
+ const paramNode = toParamNode(value);
423
+ if (paramNode) {
424
+ return paramNode;
425
+ }
409
426
  if (isOperandNode(value)) {
410
427
  return value;
411
428
  }
@@ -799,6 +816,9 @@ var visitOperand = (node, visitor) => {
799
816
  case "Literal":
800
817
  if (visitor.visitLiteral) return visitor.visitLiteral(node);
801
818
  break;
819
+ case "Param":
820
+ if (visitor.visitParam) return visitor.visitParam(node);
821
+ break;
802
822
  case "Function":
803
823
  if (visitor.visitFunction) return visitor.visitFunction(node);
804
824
  break;
@@ -830,6 +850,44 @@ var visitOperand = (node, visitor) => {
830
850
  return unsupportedOperand(node);
831
851
  };
832
852
 
853
+ // src/core/ast/param-proxy.ts
854
+ var buildParamProxy = (name) => {
855
+ const target = { type: "Param", name };
856
+ return new Proxy(target, {
857
+ get(t, prop, receiver) {
858
+ if (prop === "then") return void 0;
859
+ if (typeof prop === "symbol") {
860
+ return Reflect.get(t, prop, receiver);
861
+ }
862
+ if (typeof prop === "string" && prop.startsWith("$")) {
863
+ const trimmed = prop.slice(1);
864
+ const nextName2 = name ? `${name}.${trimmed}` : trimmed;
865
+ return buildParamProxy(nextName2);
866
+ }
867
+ if (prop in t && name === "") {
868
+ return t[prop];
869
+ }
870
+ const nextName = name ? `${name}.${prop}` : prop;
871
+ return buildParamProxy(nextName);
872
+ }
873
+ });
874
+ };
875
+ var createParamProxy = () => {
876
+ const target = {};
877
+ return new Proxy(target, {
878
+ get(t, prop, receiver) {
879
+ if (prop === "then") return void 0;
880
+ if (typeof prop === "symbol") {
881
+ return Reflect.get(t, prop, receiver);
882
+ }
883
+ if (typeof prop === "string" && prop.startsWith("$")) {
884
+ return buildParamProxy(prop.slice(1));
885
+ }
886
+ return buildParamProxy(String(prop));
887
+ }
888
+ });
889
+ };
890
+
833
891
  // src/core/ast/adapters.ts
834
892
  var hasAlias = (obj) => typeof obj === "object" && obj !== null && "alias" in obj;
835
893
  var toColumnRef = (col2) => ({
@@ -1241,6 +1299,16 @@ var Dialect = class _Dialect {
1241
1299
  params: [...ctx.params]
1242
1300
  };
1243
1301
  }
1302
+ compileSelectWithOptions(ast, options = {}) {
1303
+ const ctx = this.createCompilerContext(options);
1304
+ const normalized = this.normalizeSelectAst(ast);
1305
+ const rawSql = this.compileSelectAst(normalized, ctx).trim();
1306
+ const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1307
+ return {
1308
+ sql,
1309
+ params: [...ctx.params]
1310
+ };
1311
+ }
1244
1312
  compileInsert(ast) {
1245
1313
  const ctx = this.createCompilerContext();
1246
1314
  const rawSql = this.compileInsertAst(ast, ctx).trim();
@@ -1311,13 +1379,15 @@ var Dialect = class _Dialect {
1311
1379
  }
1312
1380
  /**
1313
1381
  * Creates a new compiler context
1382
+ * @param options - Optional compiler context options
1314
1383
  * @returns Compiler context with parameter management
1315
1384
  */
1316
- createCompilerContext() {
1385
+ createCompilerContext(options = {}) {
1317
1386
  const params = [];
1318
1387
  let counter = 0;
1319
1388
  return {
1320
1389
  params,
1390
+ allowParams: options.allowParams ?? false,
1321
1391
  addParameter: (value) => {
1322
1392
  counter += 1;
1323
1393
  params.push(value);
@@ -1539,6 +1609,12 @@ var Dialect = class _Dialect {
1539
1609
  }
1540
1610
  registerDefaultOperandCompilers() {
1541
1611
  this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1612
+ this.registerOperandCompiler("Param", (_param, ctx) => {
1613
+ if (!ctx.allowParams) {
1614
+ 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.");
1615
+ }
1616
+ return ctx.addParameter(null);
1617
+ });
1542
1618
  this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1543
1619
  void _ctx;
1544
1620
  return this.quoteIdentifier(alias.name);
@@ -4062,6 +4138,7 @@ var collectFromOperand = (node, collector) => {
4062
4138
  break;
4063
4139
  case "Literal":
4064
4140
  case "AliasRef":
4141
+ case "Param":
4065
4142
  break;
4066
4143
  default:
4067
4144
  break;
@@ -7328,6 +7405,7 @@ var collectFilterColumns = (expr, table, rootTables) => {
7328
7405
  }
7329
7406
  case "AliasRef":
7330
7407
  case "Literal":
7408
+ case "Param":
7331
7409
  return;
7332
7410
  default:
7333
7411
  return;
@@ -7405,6 +7483,227 @@ var buildFilterParameters = (table, where, from, options = {}) => {
7405
7483
  }];
7406
7484
  };
7407
7485
 
7486
+ // src/core/ast/ast-validation.ts
7487
+ var hasParamOperandsInExpression = (expr) => {
7488
+ let hasParams = false;
7489
+ visitExpression(expr, {
7490
+ 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
+ });
7505
+ if (node.escape) {
7506
+ visitOperand(node.escape, {
7507
+ visitParam: () => {
7508
+ hasParams = true;
7509
+ },
7510
+ otherwise: () => {
7511
+ }
7512
+ });
7513
+ }
7514
+ },
7515
+ visitLogicalExpression: (node) => {
7516
+ node.operands.forEach((operand) => {
7517
+ if (hasParamOperandsInExpression(operand)) {
7518
+ hasParams = true;
7519
+ }
7520
+ });
7521
+ },
7522
+ visitNullExpression: () => {
7523
+ },
7524
+ visitInExpression: (node) => {
7525
+ visitOperand(node.left, {
7526
+ visitParam: () => {
7527
+ hasParams = true;
7528
+ },
7529
+ otherwise: () => {
7530
+ }
7531
+ });
7532
+ if (Array.isArray(node.right)) {
7533
+ node.right.forEach((operand) => visitOperand(operand, {
7534
+ visitParam: () => {
7535
+ hasParams = true;
7536
+ },
7537
+ otherwise: () => {
7538
+ }
7539
+ }));
7540
+ }
7541
+ },
7542
+ visitExistsExpression: () => {
7543
+ },
7544
+ 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
+ });
7566
+ },
7567
+ 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
+ });
7582
+ },
7583
+ 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
+ });
7598
+ },
7599
+ otherwise: () => {
7600
+ }
7601
+ });
7602
+ return hasParams;
7603
+ };
7604
+ var hasParamOperandsInOperand = (operand) => {
7605
+ let hasParams = false;
7606
+ visitOperand(operand, {
7607
+ visitColumn: () => {
7608
+ },
7609
+ visitLiteral: () => {
7610
+ },
7611
+ visitParam: () => {
7612
+ hasParams = true;
7613
+ },
7614
+ visitFunction: (node) => {
7615
+ node.args?.forEach((arg) => {
7616
+ if (hasParamOperandsInOperand(arg)) {
7617
+ hasParams = true;
7618
+ }
7619
+ });
7620
+ },
7621
+ visitJsonPath: () => {
7622
+ },
7623
+ visitScalarSubquery: () => {
7624
+ },
7625
+ visitCaseExpression: (node) => {
7626
+ node.conditions.forEach((cond) => {
7627
+ if (hasParamOperandsInExpression(cond.when)) {
7628
+ hasParams = true;
7629
+ }
7630
+ if (hasParamOperandsInOperand(cond.then)) {
7631
+ hasParams = true;
7632
+ }
7633
+ });
7634
+ if (node.else && hasParamOperandsInOperand(node.else)) {
7635
+ hasParams = true;
7636
+ }
7637
+ },
7638
+ visitCast: (node) => {
7639
+ if (hasParamOperandsInOperand(node.expression)) {
7640
+ hasParams = true;
7641
+ }
7642
+ },
7643
+ 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
+ });
7656
+ },
7657
+ visitCollate: (node) => {
7658
+ if (hasParamOperandsInOperand(node.expression)) {
7659
+ hasParams = true;
7660
+ }
7661
+ },
7662
+ visitAliasRef: () => {
7663
+ },
7664
+ otherwise: () => {
7665
+ }
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
+ }
7676
+ ast.columns?.forEach((col2) => {
7677
+ if (typeof col2 === "object" && col2 !== null && "type" in col2) {
7678
+ if (hasParamOperandsInOperand(col2)) {
7679
+ return true;
7680
+ }
7681
+ }
7682
+ });
7683
+ ast.orderBy?.forEach((ord) => {
7684
+ if (ord.term) {
7685
+ if (hasParamOperandsInOperand(ord.term)) {
7686
+ return true;
7687
+ }
7688
+ }
7689
+ });
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
+ }
7696
+ }
7697
+ if (ast.setOps) {
7698
+ for (const op of ast.setOps) {
7699
+ if (hasParamOperandsInQuery(op.query)) {
7700
+ return true;
7701
+ }
7702
+ }
7703
+ }
7704
+ return false;
7705
+ };
7706
+
7408
7707
  // src/query-builder/select.ts
7409
7708
  var SelectQueryBuilder = class _SelectQueryBuilder {
7410
7709
  env;
@@ -7878,6 +8177,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7878
8177
  }
7879
8178
  return this;
7880
8179
  }
8180
+ /**
8181
+ * Validates that the query does not contain Param operands.
8182
+ * Param proxies are only for schema generation, not execution.
8183
+ */
8184
+ validateNoParamOperands() {
8185
+ 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.");
8189
+ }
8190
+ }
7881
8191
  /**
7882
8192
  * Executes the query and returns hydrated results.
7883
8193
  * If the builder was created with an entity constructor (e.g. via selectFromEntity),
@@ -7891,6 +8201,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7891
8201
  * users[0] instanceof User; // true
7892
8202
  */
7893
8203
  async execute(ctx) {
8204
+ this.validateNoParamOperands();
7894
8205
  if (this.entityConstructor) {
7895
8206
  return this.executeAs(this.entityConstructor, ctx);
7896
8207
  }
@@ -7909,6 +8220,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7909
8220
  * rows[0] instanceof User; // false
7910
8221
  */
7911
8222
  async executePlain(ctx) {
8223
+ this.validateNoParamOperands();
7912
8224
  const builder = this.ensureDefaultSelection();
7913
8225
  const rows = await executeHydratedPlain(ctx, builder);
7914
8226
  return rows;
@@ -7928,6 +8240,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7928
8240
  * users[0].getFullName(); // works!
7929
8241
  */
7930
8242
  async executeAs(entityClass, ctx) {
8243
+ this.validateNoParamOperands();
7931
8244
  const builder = this.ensureDefaultSelection();
7932
8245
  const results = await executeHydrated(ctx, builder);
7933
8246
  return materializeAs(entityClass, results);
@@ -7939,6 +8252,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7939
8252
  * const total = await qb.count(session);
7940
8253
  */
7941
8254
  async count(session) {
8255
+ this.validateNoParamOperands();
7942
8256
  return executeCount(this.context, this.env, session);
7943
8257
  }
7944
8258
  /**
@@ -7948,6 +8262,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7948
8262
  * const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
7949
8263
  */
7950
8264
  async executePaged(session, options) {
8265
+ this.validateNoParamOperands();
7951
8266
  const builder = this.ensureDefaultSelection();
7952
8267
  return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
7953
8268
  }
@@ -7962,6 +8277,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7962
8277
  * const users = await qb.executeWithContexts(execCtx, hydCtx);
7963
8278
  */
7964
8279
  async executeWithContexts(execCtx, hydCtx) {
8280
+ this.validateNoParamOperands();
7965
8281
  const builder = this.ensureDefaultSelection();
7966
8282
  const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
7967
8283
  if (this.entityConstructor) {
@@ -11367,6 +11683,7 @@ var TypeScriptGenerator = class {
11367
11683
  case "WindowFunction":
11368
11684
  case "Cast":
11369
11685
  case "Collate":
11686
+ case "Param":
11370
11687
  return this.printOperand(term);
11371
11688
  default:
11372
11689
  return this.printExpression(term);
@@ -11411,6 +11728,9 @@ var TypeScriptGenerator = class {
11411
11728
  visitLiteral(node) {
11412
11729
  return this.printLiteralOperand(node);
11413
11730
  }
11731
+ visitParam(node) {
11732
+ return this.printParamOperand(node);
11733
+ }
11414
11734
  visitFunction(node) {
11415
11735
  return this.printFunctionOperand(node);
11416
11736
  }
@@ -11532,6 +11852,10 @@ var TypeScriptGenerator = class {
11532
11852
  if (literal.value === null) return "null";
11533
11853
  return typeof literal.value === "string" ? `'${literal.value}'` : String(literal.value);
11534
11854
  }
11855
+ printParamOperand(param) {
11856
+ const name = param.name.replace(/'/g, "\\'");
11857
+ return `{ type: 'Param', name: '${name}' }`;
11858
+ }
11535
11859
  /**
11536
11860
  * Prints a function operand to TypeScript code
11537
11861
  * @param fn - Function node
@@ -13839,6 +14163,7 @@ export {
13839
14163
  createExecutorFromQueryRunner,
13840
14164
  createMssqlExecutor,
13841
14165
  createMysqlExecutor,
14166
+ createParamProxy,
13842
14167
  createPooledExecutorFactory,
13843
14168
  createPostgresExecutor,
13844
14169
  createQueryLoggingExecutor,