metal-orm 1.0.82 → 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.d.cts CHANGED
@@ -1820,6 +1820,8 @@ interface CompilerContext {
1820
1820
  params: unknown[];
1821
1821
  /** Function to add a parameter and get its placeholder */
1822
1822
  addParameter(value: unknown): string;
1823
+ /** Whether Param operands are allowed (for schema generation) */
1824
+ allowParams?: boolean;
1823
1825
  }
1824
1826
  /**
1825
1827
  * Result of SQL compilation
@@ -1854,6 +1856,9 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
1854
1856
  * @returns Compiled query with SQL and parameters
1855
1857
  */
1856
1858
  compileSelect(ast: SelectQueryNode): CompiledQuery;
1859
+ compileSelectWithOptions(ast: SelectQueryNode, options?: {
1860
+ allowParams?: boolean;
1861
+ }): CompiledQuery;
1857
1862
  compileInsert(ast: InsertQueryNode): CompiledQuery;
1858
1863
  compileUpdate(ast: UpdateQueryNode): CompiledQuery;
1859
1864
  compileDelete(ast: DeleteQueryNode): CompiledQuery;
@@ -1894,9 +1899,12 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
1894
1899
  protected compileSelectForExists(ast: SelectQueryNode, ctx: CompilerContext): string;
1895
1900
  /**
1896
1901
  * Creates a new compiler context
1902
+ * @param options - Optional compiler context options
1897
1903
  * @returns Compiler context with parameter management
1898
1904
  */
1899
- protected createCompilerContext(): CompilerContext;
1905
+ protected createCompilerContext(options?: {
1906
+ allowParams?: boolean;
1907
+ }): CompilerContext;
1900
1908
  /**
1901
1909
  * Formats a parameter placeholder
1902
1910
  * @param index - Parameter index
@@ -4312,6 +4320,11 @@ declare class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Ta
4312
4320
  * Ensures that if no columns are selected, all columns from the table are selected by default.
4313
4321
  */
4314
4322
  private ensureDefaultSelection;
4323
+ /**
4324
+ * Validates that the query does not contain Param operands.
4325
+ * Param proxies are only for schema generation, not execution.
4326
+ */
4327
+ private validateNoParamOperands;
4315
4328
  /**
4316
4329
  * Executes the query and returns hydrated results.
4317
4330
  * If the builder was created with an entity constructor (e.g. via selectFromEntity),
package/dist/index.d.ts CHANGED
@@ -1820,6 +1820,8 @@ interface CompilerContext {
1820
1820
  params: unknown[];
1821
1821
  /** Function to add a parameter and get its placeholder */
1822
1822
  addParameter(value: unknown): string;
1823
+ /** Whether Param operands are allowed (for schema generation) */
1824
+ allowParams?: boolean;
1823
1825
  }
1824
1826
  /**
1825
1827
  * Result of SQL compilation
@@ -1854,6 +1856,9 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
1854
1856
  * @returns Compiled query with SQL and parameters
1855
1857
  */
1856
1858
  compileSelect(ast: SelectQueryNode): CompiledQuery;
1859
+ compileSelectWithOptions(ast: SelectQueryNode, options?: {
1860
+ allowParams?: boolean;
1861
+ }): CompiledQuery;
1857
1862
  compileInsert(ast: InsertQueryNode): CompiledQuery;
1858
1863
  compileUpdate(ast: UpdateQueryNode): CompiledQuery;
1859
1864
  compileDelete(ast: DeleteQueryNode): CompiledQuery;
@@ -1894,9 +1899,12 @@ declare abstract class Dialect implements SelectCompiler, InsertCompiler, Update
1894
1899
  protected compileSelectForExists(ast: SelectQueryNode, ctx: CompilerContext): string;
1895
1900
  /**
1896
1901
  * Creates a new compiler context
1902
+ * @param options - Optional compiler context options
1897
1903
  * @returns Compiler context with parameter management
1898
1904
  */
1899
- protected createCompilerContext(): CompilerContext;
1905
+ protected createCompilerContext(options?: {
1906
+ allowParams?: boolean;
1907
+ }): CompilerContext;
1900
1908
  /**
1901
1909
  * Formats a parameter placeholder
1902
1910
  * @param index - Parameter index
@@ -4312,6 +4320,11 @@ declare class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Ta
4312
4320
  * Ensures that if no columns are selected, all columns from the table are selected by default.
4313
4321
  */
4314
4322
  private ensureDefaultSelection;
4323
+ /**
4324
+ * Validates that the query does not contain Param operands.
4325
+ * Param proxies are only for schema generation, not execution.
4326
+ */
4327
+ private validateNoParamOperands;
4315
4328
  /**
4316
4329
  * Executes the query and returns hydrated results.
4317
4330
  * If the builder was created with an entity constructor (e.g. via selectFromEntity),
package/dist/index.js CHANGED
@@ -389,6 +389,14 @@ var toLiteralNode = (value) => ({
389
389
  type: "Literal",
390
390
  value: value instanceof Date ? value.toISOString() : value
391
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
+ };
392
400
  var columnRefToNode = (col2) => {
393
401
  if (!col2.table) {
394
402
  throw new Error(
@@ -398,6 +406,10 @@ var columnRefToNode = (col2) => {
398
406
  return { type: "Column", table: col2.table, name: col2.name };
399
407
  };
400
408
  var toOperandNode = (value) => {
409
+ const paramNode = toParamNode(value);
410
+ if (paramNode) {
411
+ return paramNode;
412
+ }
401
413
  if (isOperandNode(value)) {
402
414
  return value;
403
415
  }
@@ -407,6 +419,10 @@ var toOperandNode = (value) => {
407
419
  return columnRefToNode(value);
408
420
  };
409
421
  var valueToOperand = (value) => {
422
+ const paramNode = toParamNode(value);
423
+ if (paramNode) {
424
+ return paramNode;
425
+ }
410
426
  if (isOperandNode(value)) {
411
427
  return value;
412
428
  }
@@ -848,7 +864,7 @@ var buildParamProxy = (name) => {
848
864
  const nextName2 = name ? `${name}.${trimmed}` : trimmed;
849
865
  return buildParamProxy(nextName2);
850
866
  }
851
- if (prop in t) {
867
+ if (prop in t && name === "") {
852
868
  return t[prop];
853
869
  }
854
870
  const nextName = name ? `${name}.${prop}` : prop;
@@ -867,9 +883,6 @@ var createParamProxy = () => {
867
883
  if (typeof prop === "string" && prop.startsWith("$")) {
868
884
  return buildParamProxy(prop.slice(1));
869
885
  }
870
- if (prop in t) {
871
- return t[prop];
872
- }
873
886
  return buildParamProxy(String(prop));
874
887
  }
875
888
  });
@@ -1286,6 +1299,16 @@ var Dialect = class _Dialect {
1286
1299
  params: [...ctx.params]
1287
1300
  };
1288
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
+ }
1289
1312
  compileInsert(ast) {
1290
1313
  const ctx = this.createCompilerContext();
1291
1314
  const rawSql = this.compileInsertAst(ast, ctx).trim();
@@ -1356,13 +1379,15 @@ var Dialect = class _Dialect {
1356
1379
  }
1357
1380
  /**
1358
1381
  * Creates a new compiler context
1382
+ * @param options - Optional compiler context options
1359
1383
  * @returns Compiler context with parameter management
1360
1384
  */
1361
- createCompilerContext() {
1385
+ createCompilerContext(options = {}) {
1362
1386
  const params = [];
1363
1387
  let counter = 0;
1364
1388
  return {
1365
1389
  params,
1390
+ allowParams: options.allowParams ?? false,
1366
1391
  addParameter: (value) => {
1367
1392
  counter += 1;
1368
1393
  params.push(value);
@@ -1584,7 +1609,12 @@ var Dialect = class _Dialect {
1584
1609
  }
1585
1610
  registerDefaultOperandCompilers() {
1586
1611
  this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1587
- this.registerOperandCompiler("Param", (_param, ctx) => ctx.addParameter(null));
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
+ });
1588
1618
  this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1589
1619
  void _ctx;
1590
1620
  return this.quoteIdentifier(alias.name);
@@ -7453,6 +7483,227 @@ var buildFilterParameters = (table, where, from, options = {}) => {
7453
7483
  }];
7454
7484
  };
7455
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
+
7456
7707
  // src/query-builder/select.ts
7457
7708
  var SelectQueryBuilder = class _SelectQueryBuilder {
7458
7709
  env;
@@ -7926,6 +8177,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7926
8177
  }
7927
8178
  return this;
7928
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
+ }
7929
8191
  /**
7930
8192
  * Executes the query and returns hydrated results.
7931
8193
  * If the builder was created with an entity constructor (e.g. via selectFromEntity),
@@ -7939,6 +8201,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7939
8201
  * users[0] instanceof User; // true
7940
8202
  */
7941
8203
  async execute(ctx) {
8204
+ this.validateNoParamOperands();
7942
8205
  if (this.entityConstructor) {
7943
8206
  return this.executeAs(this.entityConstructor, ctx);
7944
8207
  }
@@ -7957,6 +8220,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7957
8220
  * rows[0] instanceof User; // false
7958
8221
  */
7959
8222
  async executePlain(ctx) {
8223
+ this.validateNoParamOperands();
7960
8224
  const builder = this.ensureDefaultSelection();
7961
8225
  const rows = await executeHydratedPlain(ctx, builder);
7962
8226
  return rows;
@@ -7976,6 +8240,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7976
8240
  * users[0].getFullName(); // works!
7977
8241
  */
7978
8242
  async executeAs(entityClass, ctx) {
8243
+ this.validateNoParamOperands();
7979
8244
  const builder = this.ensureDefaultSelection();
7980
8245
  const results = await executeHydrated(ctx, builder);
7981
8246
  return materializeAs(entityClass, results);
@@ -7987,6 +8252,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7987
8252
  * const total = await qb.count(session);
7988
8253
  */
7989
8254
  async count(session) {
8255
+ this.validateNoParamOperands();
7990
8256
  return executeCount(this.context, this.env, session);
7991
8257
  }
7992
8258
  /**
@@ -7996,6 +8262,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
7996
8262
  * const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
7997
8263
  */
7998
8264
  async executePaged(session, options) {
8265
+ this.validateNoParamOperands();
7999
8266
  const builder = this.ensureDefaultSelection();
8000
8267
  return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
8001
8268
  }
@@ -8010,6 +8277,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
8010
8277
  * const users = await qb.executeWithContexts(execCtx, hydCtx);
8011
8278
  */
8012
8279
  async executeWithContexts(execCtx, hydCtx) {
8280
+ this.validateNoParamOperands();
8013
8281
  const builder = this.ensureDefaultSelection();
8014
8282
  const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
8015
8283
  if (this.entityConstructor) {