metal-orm 1.1.22 → 1.1.23

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
@@ -1314,268 +1314,40 @@ var StandardTableFunctionStrategy = class {
1314
1314
  }
1315
1315
  };
1316
1316
 
1317
- // src/core/dialect/abstract.ts
1318
- var Dialect = class _Dialect {
1319
- /**
1320
- * Compiles a SELECT query AST to SQL
1321
- * @param ast - Query AST to compile
1322
- * @returns Compiled query with SQL and parameters
1323
- */
1324
- compileSelect(ast) {
1325
- const ctx = this.createCompilerContext();
1326
- const normalized = this.normalizeSelectAst(ast);
1327
- const rawSql = this.compileSelectAst(normalized, ctx).trim();
1328
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1329
- return {
1330
- sql,
1331
- params: [...ctx.params]
1332
- };
1333
- }
1334
- compileInsert(ast) {
1335
- const ctx = this.createCompilerContext();
1336
- const rawSql = this.compileInsertAst(ast, ctx).trim();
1337
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1338
- return {
1339
- sql,
1340
- params: [...ctx.params]
1341
- };
1342
- }
1343
- compileUpdate(ast) {
1344
- const ctx = this.createCompilerContext();
1345
- const rawSql = this.compileUpdateAst(ast, ctx).trim();
1346
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1347
- return {
1348
- sql,
1349
- params: [...ctx.params]
1350
- };
1351
- }
1352
- compileDelete(ast) {
1353
- const ctx = this.createCompilerContext();
1354
- const rawSql = this.compileDeleteAst(ast, ctx).trim();
1355
- const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
1356
- return {
1357
- sql,
1358
- params: [...ctx.params]
1359
- };
1360
- }
1361
- supportsDmlReturningClause() {
1362
- return false;
1363
- }
1364
- /**
1365
- * Compiles a WHERE clause
1366
- * @param where - WHERE expression
1367
- * @param ctx - Compiler context
1368
- * @returns SQL WHERE clause or empty string
1369
- */
1370
- compileWhere(where, ctx) {
1371
- if (!where) return "";
1372
- return ` WHERE ${this.compileExpression(where, ctx)}`;
1373
- }
1374
- compileReturning(returning, _ctx) {
1375
- void _ctx;
1376
- if (!returning || returning.length === 0) return "";
1377
- throw new Error("RETURNING is not supported by this dialect.");
1378
- }
1379
- /**
1380
- * Generates subquery for EXISTS expressions
1381
- * Rule: Always forces SELECT 1, ignoring column list
1382
- * Maintains FROM, JOINs, WHERE, GROUP BY, ORDER BY, LIMIT/OFFSET
1383
- * Does not add ';' at the end
1384
- * @param ast - Query AST
1385
- * @param ctx - Compiler context
1386
- * @returns SQL for EXISTS subquery
1387
- */
1388
- compileSelectForExists(ast, ctx) {
1389
- const normalized = this.normalizeSelectAst(ast);
1390
- const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
1391
- if (normalized.setOps && normalized.setOps.length > 0) {
1392
- return `SELECT 1 FROM (${full}) AS _exists`;
1393
- }
1394
- const upper2 = full.toUpperCase();
1395
- const fromIndex = upper2.indexOf(" FROM ");
1396
- if (fromIndex === -1) {
1397
- return full;
1398
- }
1399
- const tail = full.slice(fromIndex);
1400
- return `SELECT 1${tail}`;
1401
- }
1402
- /**
1403
- * Creates a new compiler context
1404
- * @returns Compiler context with parameter management
1405
- */
1406
- createCompilerContext() {
1407
- const params = [];
1408
- let counter = 0;
1409
- return {
1410
- params,
1411
- addParameter: (value) => {
1412
- counter += 1;
1413
- params.push(value);
1414
- return this.formatPlaceholder(counter);
1415
- }
1416
- };
1417
- }
1418
- /**
1419
- * Formats a parameter placeholder
1420
- * @param index - Parameter index
1421
- * @returns Formatted placeholder string
1422
- */
1423
- formatPlaceholder(_index) {
1424
- void _index;
1425
- return "?";
1426
- }
1427
- /**
1428
- * Whether the current dialect supports a given set operation.
1429
- * Override in concrete dialects to restrict support.
1430
- */
1431
- supportsSetOperation(_kind) {
1432
- void _kind;
1433
- return true;
1434
- }
1435
- /**
1436
- * Validates set-operation semantics:
1437
- * - Ensures the dialect supports requested operators.
1438
- * - Enforces that only the outermost compound query may have ORDER/LIMIT/OFFSET.
1439
- * @param ast - Query to validate
1440
- * @param isOutermost - Whether this node is the outermost compound query
1441
- */
1442
- validateSetOperations(ast, isOutermost = true) {
1443
- const hasSetOps = !!(ast.setOps && ast.setOps.length);
1444
- if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
1445
- throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
1446
- }
1447
- if (hasSetOps) {
1448
- for (const op of ast.setOps) {
1449
- if (!this.supportsSetOperation(op.operator)) {
1450
- throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
1451
- }
1452
- this.validateSetOperations(op.query, false);
1453
- }
1454
- }
1455
- }
1456
- /**
1457
- * Hoists CTEs from set-operation operands to the outermost query so WITH appears once.
1458
- * @param ast - Query AST
1459
- * @returns Normalized AST without inner CTEs and a list of hoisted CTEs
1460
- */
1461
- hoistCtes(ast) {
1462
- let hoisted = [];
1463
- const normalizedSetOps = ast.setOps?.map((op) => {
1464
- const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
1465
- const childCtes = child.ctes ?? [];
1466
- if (childCtes.length) {
1467
- hoisted = hoisted.concat(childCtes);
1468
- }
1469
- hoisted = hoisted.concat(childHoisted);
1470
- const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
1471
- return { ...op, query: queryWithoutCtes };
1472
- });
1473
- const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
1474
- return { normalized, hoistedCtes: hoisted };
1475
- }
1476
- /**
1477
- * Normalizes a SELECT AST before compilation (validation + CTE hoisting).
1478
- * @param ast - Query AST
1479
- * @returns Normalized query AST
1480
- */
1481
- normalizeSelectAst(ast) {
1482
- this.validateSetOperations(ast, true);
1483
- const { normalized, hoistedCtes } = this.hoistCtes(ast);
1484
- const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
1485
- return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
1486
- }
1487
- expressionCompilers;
1488
- operandCompilers;
1489
- functionStrategy;
1490
- tableFunctionStrategy;
1491
- constructor(functionStrategy, tableFunctionStrategy) {
1492
- this.expressionCompilers = /* @__PURE__ */ new Map();
1493
- this.operandCompilers = /* @__PURE__ */ new Map();
1494
- this.functionStrategy = functionStrategy || new StandardFunctionStrategy();
1495
- this.tableFunctionStrategy = tableFunctionStrategy || new StandardTableFunctionStrategy();
1317
+ // src/core/dialect/base/expression-compiler-registry.ts
1318
+ var ExpressionCompilerRegistry = class {
1319
+ constructor(host) {
1320
+ this.host = host;
1496
1321
  this.registerDefaultOperandCompilers();
1497
1322
  this.registerDefaultExpressionCompilers();
1498
1323
  }
1499
- /**
1500
- * Creates a new Dialect instance (for testing purposes)
1501
- * @param functionStrategy - Optional function strategy
1502
- * @returns New Dialect instance
1503
- */
1504
- static create(functionStrategy, tableFunctionStrategy) {
1505
- class TestDialect extends _Dialect {
1506
- dialect = "sqlite";
1507
- quoteIdentifier(id) {
1508
- return `"${id}"`;
1509
- }
1510
- compileSelectAst() {
1511
- throw new Error("Not implemented");
1512
- }
1513
- compileInsertAst() {
1514
- throw new Error("Not implemented");
1515
- }
1516
- compileUpdateAst() {
1517
- throw new Error("Not implemented");
1518
- }
1519
- compileDeleteAst() {
1520
- throw new Error("Not implemented");
1521
- }
1522
- compileProcedureCall() {
1523
- throw new Error("Not implemented");
1524
- }
1525
- }
1526
- return new TestDialect(functionStrategy, tableFunctionStrategy);
1527
- }
1528
- /**
1529
- * Registers an expression compiler for a specific node type
1530
- * @param type - Expression node type
1531
- * @param compiler - Compiler function
1532
- */
1324
+ expressionCompilers = /* @__PURE__ */ new Map();
1325
+ operandCompilers = /* @__PURE__ */ new Map();
1533
1326
  registerExpressionCompiler(type, compiler) {
1534
1327
  this.expressionCompilers.set(type, compiler);
1535
1328
  }
1536
- /**
1537
- * Registers an operand compiler for a specific node type
1538
- * @param type - Operand node type
1539
- * @param compiler - Compiler function
1540
- */
1541
1329
  registerOperandCompiler(type, compiler) {
1542
1330
  this.operandCompilers.set(type, compiler);
1543
1331
  }
1544
- /**
1545
- * Compiles an expression node
1546
- * @param node - Expression node to compile
1547
- * @param ctx - Compiler context
1548
- * @returns Compiled SQL expression
1549
- */
1550
1332
  compileExpression(node, ctx) {
1551
1333
  const compiler = this.expressionCompilers.get(node.type);
1552
1334
  if (!compiler) {
1553
- throw new Error(`Unsupported expression node type "${node.type}" for ${this.constructor.name}`);
1335
+ throw new Error(`Unsupported expression node type "${node.type}" for ${this.host.describe()}`);
1554
1336
  }
1555
1337
  return compiler(node, ctx);
1556
1338
  }
1557
- /**
1558
- * Compiles an operand node
1559
- * @param node - Operand node to compile
1560
- * @param ctx - Compiler context
1561
- * @returns Compiled SQL operand
1562
- */
1563
1339
  compileOperand(node, ctx) {
1564
1340
  const compiler = this.operandCompilers.get(node.type);
1565
1341
  if (!compiler) {
1566
- throw new Error(`Unsupported operand node type "${node.type}" for ${this.constructor.name}`);
1342
+ throw new Error(`Unsupported operand node type "${node.type}" for ${this.host.describe()}`);
1567
1343
  }
1568
1344
  return compiler(node, ctx);
1569
1345
  }
1570
- /**
1571
- * Compiles an ordering term (operand, expression, or alias reference).
1572
- */
1573
1346
  compileOrderingTerm(term, ctx) {
1574
1347
  if (isOperandNode(term)) {
1575
1348
  return this.compileOperand(term, ctx);
1576
1349
  }
1577
- const expr = this.compileExpression(term, ctx);
1578
- return `(${expr})`;
1350
+ return `(${this.compileExpression(term, ctx)})`;
1579
1351
  }
1580
1352
  registerDefaultExpressionCompilers() {
1581
1353
  this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
@@ -1610,11 +1382,11 @@ var Dialect = class _Dialect {
1610
1382
  const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
1611
1383
  return `${left2} ${inExpr.operator} (${values})`;
1612
1384
  }
1613
- const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
1385
+ const subquerySql = this.host.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
1614
1386
  return `${left2} ${inExpr.operator} (${subquerySql})`;
1615
1387
  });
1616
1388
  this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
1617
- const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
1389
+ const subquerySql = this.host.compileSelectForExists(existsExpr.subquery, ctx);
1618
1390
  return `${existsExpr.operator} (${subquerySql})`;
1619
1391
  });
1620
1392
  this.registerExpressionCompiler("BetweenExpression", (betweenExpr, ctx) => {
@@ -1640,25 +1412,28 @@ var Dialect = class _Dialect {
1640
1412
  });
1641
1413
  }
1642
1414
  registerDefaultOperandCompilers() {
1643
- this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1644
- this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1645
- void _ctx;
1646
- return this.quoteIdentifier(alias.name);
1647
- });
1648
- this.registerOperandCompiler("Column", (column, _ctx) => {
1649
- void _ctx;
1650
- return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
1651
- });
1415
+ this.registerOperandCompiler(
1416
+ "Literal",
1417
+ (literal, ctx) => ctx.addParameter(literal.value)
1418
+ );
1419
+ this.registerOperandCompiler(
1420
+ "AliasRef",
1421
+ (alias) => this.host.quoteIdentifier(alias.name)
1422
+ );
1423
+ this.registerOperandCompiler(
1424
+ "Column",
1425
+ (column) => `${this.host.quoteIdentifier(column.table)}.${this.host.quoteIdentifier(column.name)}`
1426
+ );
1652
1427
  this.registerOperandCompiler(
1653
1428
  "Function",
1654
- (fnNode, ctx) => this.compileFunctionOperand(fnNode, ctx)
1429
+ (fnNode, ctx) => this.host.compileFunctionOperand(fnNode, ctx)
1430
+ );
1431
+ this.registerOperandCompiler(
1432
+ "JsonPath",
1433
+ (path) => this.host.compileJsonPath(path)
1655
1434
  );
1656
- this.registerOperandCompiler("JsonPath", (path, _ctx) => {
1657
- void _ctx;
1658
- return this.compileJsonPath(path);
1659
- });
1660
1435
  this.registerOperandCompiler("ScalarSubquery", (node, ctx) => {
1661
- const sql = this.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
1436
+ const sql = this.host.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
1662
1437
  return `(${sql})`;
1663
1438
  });
1664
1439
  this.registerOperandCompiler("CaseExpression", (node, ctx) => {
@@ -1685,7 +1460,7 @@ var Dialect = class _Dialect {
1685
1460
  const parts = [];
1686
1461
  if (node.partitionBy && node.partitionBy.length > 0) {
1687
1462
  const partitionClause = "PARTITION BY " + node.partitionBy.map(
1688
- (col2) => `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`
1463
+ (col2) => `${this.host.quoteIdentifier(col2.table)}.${this.host.quoteIdentifier(col2.name)}`
1689
1464
  ).join(", ");
1690
1465
  parts.push(partitionClause);
1691
1466
  }
@@ -1717,14 +1492,164 @@ var Dialect = class _Dialect {
1717
1492
  return `${expr} COLLATE ${node.collation}`;
1718
1493
  });
1719
1494
  }
1720
- // Default fallback, should be overridden by dialects if supported
1495
+ };
1496
+
1497
+ // src/core/dialect/base/select-ast-normalizer.ts
1498
+ var SelectAstNormalizer = class {
1499
+ constructor(supportsSetOperation) {
1500
+ this.supportsSetOperation = supportsSetOperation;
1501
+ }
1502
+ normalize(ast) {
1503
+ this.validateSetOperations(ast, true);
1504
+ const { normalized, hoistedCtes } = this.hoistCtes(ast);
1505
+ const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
1506
+ return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
1507
+ }
1508
+ validateSetOperations(ast, isOutermost) {
1509
+ const hasSetOps = !!(ast.setOps && ast.setOps.length);
1510
+ if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
1511
+ throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
1512
+ }
1513
+ if (!hasSetOps) return;
1514
+ for (const op of ast.setOps) {
1515
+ if (!this.supportsSetOperation(op.operator)) {
1516
+ throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
1517
+ }
1518
+ this.validateSetOperations(op.query, false);
1519
+ }
1520
+ }
1521
+ hoistCtes(ast) {
1522
+ let hoisted = [];
1523
+ const normalizedSetOps = ast.setOps?.map((op) => {
1524
+ const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
1525
+ const childCtes = child.ctes ?? [];
1526
+ if (childCtes.length) hoisted = hoisted.concat(childCtes);
1527
+ hoisted = hoisted.concat(childHoisted);
1528
+ const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
1529
+ return { ...op, query: queryWithoutCtes };
1530
+ });
1531
+ const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
1532
+ return { normalized, hoistedCtes: hoisted };
1533
+ }
1534
+ };
1535
+
1536
+ // src/core/dialect/abstract.ts
1537
+ var DialectBase = class _DialectBase {
1538
+ expressionCompilerRegistry;
1539
+ selectAstNormalizer;
1540
+ functionStrategy;
1541
+ tableFunctionStrategy;
1542
+ constructor(functionStrategy, tableFunctionStrategy) {
1543
+ this.functionStrategy = functionStrategy ?? new StandardFunctionStrategy();
1544
+ this.tableFunctionStrategy = tableFunctionStrategy ?? new StandardTableFunctionStrategy();
1545
+ this.selectAstNormalizer = new SelectAstNormalizer((kind) => this.supportsSetOperation(kind));
1546
+ this.expressionCompilerRegistry = new ExpressionCompilerRegistry({
1547
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
1548
+ compileSelectAst: (ast, ctx) => this.compileSelectAst(ast, ctx),
1549
+ compileSelectForExists: (ast, ctx) => this.compileSelectForExists(ast, ctx),
1550
+ compileJsonPath: (node) => this.compileJsonPath(node),
1551
+ compileFunctionOperand: (node, ctx) => this.compileFunctionOperand(node, ctx),
1552
+ describe: () => this.constructor.name
1553
+ });
1554
+ }
1555
+ compileSelect(ast) {
1556
+ const ctx = this.createCompilerContext();
1557
+ const normalized = this.normalizeSelectAst(ast);
1558
+ const rawSql = this.compileSelectAst(normalized, ctx).trim();
1559
+ return {
1560
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1561
+ params: [...ctx.params]
1562
+ };
1563
+ }
1564
+ compileInsert(ast) {
1565
+ const ctx = this.createCompilerContext();
1566
+ const rawSql = this.compileInsertAst(ast, ctx).trim();
1567
+ return {
1568
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1569
+ params: [...ctx.params]
1570
+ };
1571
+ }
1572
+ compileUpdate(ast) {
1573
+ const ctx = this.createCompilerContext();
1574
+ const rawSql = this.compileUpdateAst(ast, ctx).trim();
1575
+ return {
1576
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1577
+ params: [...ctx.params]
1578
+ };
1579
+ }
1580
+ compileDelete(ast) {
1581
+ const ctx = this.createCompilerContext();
1582
+ const rawSql = this.compileDeleteAst(ast, ctx).trim();
1583
+ return {
1584
+ sql: rawSql.endsWith(";") ? rawSql : `${rawSql};`,
1585
+ params: [...ctx.params]
1586
+ };
1587
+ }
1588
+ supportsDmlReturningClause() {
1589
+ return false;
1590
+ }
1591
+ compileWhere(where, ctx) {
1592
+ if (!where) return "";
1593
+ return ` WHERE ${this.compileExpression(where, ctx)}`;
1594
+ }
1595
+ compileReturning(returning, _ctx) {
1596
+ void _ctx;
1597
+ if (!returning || returning.length === 0) return "";
1598
+ throw new Error("RETURNING is not supported by this dialect.");
1599
+ }
1600
+ compileSelectForExists(ast, ctx) {
1601
+ const normalized = this.normalizeSelectAst(ast);
1602
+ const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
1603
+ if (normalized.setOps && normalized.setOps.length > 0) {
1604
+ return `SELECT 1 FROM (${full}) AS _exists`;
1605
+ }
1606
+ const upper2 = full.toUpperCase();
1607
+ const fromIndex = upper2.indexOf(" FROM ");
1608
+ if (fromIndex === -1) return full;
1609
+ return `SELECT 1${full.slice(fromIndex)}`;
1610
+ }
1611
+ createCompilerContext() {
1612
+ const params = [];
1613
+ let counter = 0;
1614
+ return {
1615
+ params,
1616
+ addParameter: (value) => {
1617
+ counter += 1;
1618
+ params.push(value);
1619
+ return this.formatPlaceholder(counter);
1620
+ }
1621
+ };
1622
+ }
1623
+ formatPlaceholder(_index) {
1624
+ void _index;
1625
+ return "?";
1626
+ }
1627
+ supportsSetOperation(_kind) {
1628
+ void _kind;
1629
+ return true;
1630
+ }
1631
+ normalizeSelectAst(ast) {
1632
+ return this.selectAstNormalizer.normalize(ast);
1633
+ }
1634
+ registerExpressionCompiler(type, compiler) {
1635
+ this.expressionCompilerRegistry.registerExpressionCompiler(type, compiler);
1636
+ }
1637
+ registerOperandCompiler(type, compiler) {
1638
+ this.expressionCompilerRegistry.registerOperandCompiler(type, compiler);
1639
+ }
1640
+ compileExpression(node, ctx) {
1641
+ return this.expressionCompilerRegistry.compileExpression(node, ctx);
1642
+ }
1643
+ compileOperand(node, ctx) {
1644
+ return this.expressionCompilerRegistry.compileOperand(node, ctx);
1645
+ }
1646
+ compileOrderingTerm(term, ctx) {
1647
+ return this.expressionCompilerRegistry.compileOrderingTerm(term, ctx);
1648
+ }
1721
1649
  compileJsonPath(_node) {
1722
1650
  void _node;
1723
1651
  throw new Error("JSON Path not supported by this dialect");
1724
1652
  }
1725
- /**
1726
- * Compiles a function operand, using the dialect's function strategy.
1727
- */
1728
1653
  compileFunctionOperand(fnNode, ctx) {
1729
1654
  const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
1730
1655
  const renderer = this.functionStrategy.getRenderer(fnNode.name);
@@ -1737,98 +1662,62 @@ var Dialect = class _Dialect {
1737
1662
  }
1738
1663
  return `${fnNode.name}(${compiledArgs.join(", ")})`;
1739
1664
  }
1665
+ /** Creates a minimal dialect implementation for isolated compiler tests. */
1666
+ static create(functionStrategy, tableFunctionStrategy) {
1667
+ class TestDialect extends _DialectBase {
1668
+ dialect = "sqlite";
1669
+ quoteIdentifier(id) {
1670
+ return `"${id}"`;
1671
+ }
1672
+ compileSelectAst() {
1673
+ throw new Error("Not implemented");
1674
+ }
1675
+ compileInsertAst() {
1676
+ throw new Error("Not implemented");
1677
+ }
1678
+ compileUpdateAst() {
1679
+ throw new Error("Not implemented");
1680
+ }
1681
+ compileDeleteAst() {
1682
+ throw new Error("Not implemented");
1683
+ }
1684
+ }
1685
+ return new TestDialect(functionStrategy, tableFunctionStrategy);
1686
+ }
1740
1687
  };
1741
1688
 
1742
1689
  // src/core/dialect/base/function-table-formatter.ts
1743
1690
  var FunctionTableFormatter = class {
1744
- /**
1745
- * Formats a function table node into SQL syntax.
1746
- * @param fn - The function table node containing schema, name, args, and aliases.
1747
- * @param ctx - Optional compiler context for operand compilation.
1748
- * @param dialect - The dialect instance for compiling operands.
1749
- * @returns SQL function table expression (e.g., "LATERAL schema.func(args) WITH ORDINALITY AS alias(col1, col2)").
1750
- */
1751
- static format(fn9, ctx, dialect) {
1752
- const schemaPart = this.formatSchema(fn9, dialect);
1753
- const args = this.formatArgs(fn9, ctx, dialect);
1691
+ static format(fn9, ctx, formatter) {
1692
+ const schemaPart = this.formatSchema(fn9, formatter);
1693
+ const args = this.formatArgs(fn9, ctx, formatter);
1754
1694
  const base = this.formatBase(fn9, schemaPart, args);
1755
1695
  const lateral = this.formatLateral(fn9);
1756
- const alias = this.formatAlias(fn9, dialect);
1757
- const colAliases = this.formatColumnAliases(fn9, dialect);
1696
+ const alias = this.formatAlias(fn9, formatter);
1697
+ const colAliases = this.formatColumnAliases(fn9, formatter);
1758
1698
  return `${lateral}${base}${alias}${colAliases}`;
1759
1699
  }
1760
- /**
1761
- * Formats the schema prefix for the function name.
1762
- * @param fn - The function table node.
1763
- * @param dialect - The dialect instance for quoting identifiers.
1764
- * @returns Schema prefix (e.g., "schema.") or empty string.
1765
- * @internal
1766
- */
1767
- static formatSchema(fn9, dialect) {
1700
+ static formatSchema(fn9, formatter) {
1768
1701
  if (!fn9.schema) return "";
1769
- const quoted = dialect ? dialect.quoteIdentifier(fn9.schema) : fn9.schema;
1770
- return `${quoted}.`;
1702
+ return `${formatter.quoteIdentifier(fn9.schema)}.`;
1771
1703
  }
1772
- /**
1773
- * Formats function arguments into SQL syntax.
1774
- * @param fn - The function table node containing arguments.
1775
- * @param ctx - Optional compiler context for operand compilation.
1776
- * @param dialect - The dialect instance for compiling operands.
1777
- * @returns Comma-separated function arguments.
1778
- * @internal
1779
- */
1780
- static formatArgs(fn9, ctx, dialect) {
1781
- return (fn9.args || []).map((a) => {
1782
- if (ctx && dialect) {
1783
- return dialect.compileOperand(a, ctx);
1784
- }
1785
- return String(a);
1786
- }).join(", ");
1704
+ static formatArgs(fn9, ctx, formatter) {
1705
+ return (fn9.args || []).map((arg) => ctx ? formatter.compileOperand(arg, ctx) : String(arg)).join(", ");
1787
1706
  }
1788
- /**
1789
- * Formats the base function call with WITH ORDINALITY if present.
1790
- * @param fn - The function table node.
1791
- * @param schemaPart - Formatted schema prefix.
1792
- * @param args - Formatted function arguments.
1793
- * @param dialect - The dialect instance for quoting identifiers.
1794
- * @returns Base function call expression (e.g., "schema.func(args) WITH ORDINALITY").
1795
- * @internal
1796
- */
1797
1707
  static formatBase(fn9, schemaPart, args) {
1798
1708
  const ordinality = fn9.withOrdinality ? " WITH ORDINALITY" : "";
1799
1709
  return `${schemaPart}${fn9.name}(${args})${ordinality}`;
1800
1710
  }
1801
- /**
1802
- * Formats the LATERAL keyword if present.
1803
- * @param fn - The function table node.
1804
- * @returns "LATERAL " or empty string.
1805
- * @internal
1806
- */
1807
1711
  static formatLateral(fn9) {
1808
1712
  return fn9.lateral ? "LATERAL " : "";
1809
1713
  }
1810
- /**
1811
- * Formats the table alias for the function table.
1812
- * @param fn - The function table node.
1813
- * @param dialect - The dialect instance for quoting identifiers.
1814
- * @returns " AS alias" or empty string.
1815
- * @internal
1816
- */
1817
- static formatAlias(fn9, dialect) {
1714
+ static formatAlias(fn9, formatter) {
1818
1715
  if (!fn9.alias) return "";
1819
- const quoted = dialect ? dialect.quoteIdentifier(fn9.alias) : fn9.alias;
1820
- return ` AS ${quoted}`;
1716
+ return ` AS ${formatter.quoteIdentifier(fn9.alias)}`;
1821
1717
  }
1822
- /**
1823
- * Formats column aliases for the function table result columns.
1824
- * @param fn - The function table node containing column aliases.
1825
- * @param dialect - The dialect instance for quoting identifiers.
1826
- * @returns "(col1, col2, ...)" or empty string.
1827
- * @internal
1828
- */
1829
- static formatColumnAliases(fn9, dialect) {
1718
+ static formatColumnAliases(fn9, formatter) {
1830
1719
  if (!fn9.columnAliases || !fn9.columnAliases.length) return "";
1831
- const aliases = fn9.columnAliases.map((col2) => dialect ? dialect.quoteIdentifier(col2) : col2).join(", ");
1720
+ const aliases = fn9.columnAliases.map((col2) => formatter.quoteIdentifier(col2)).join(", ");
1832
1721
  return `(${aliases})`;
1833
1722
  }
1834
1723
  };
@@ -1954,7 +1843,7 @@ var OrderByCompiler = class {
1954
1843
  };
1955
1844
 
1956
1845
  // src/core/dialect/base/sql-dialect.ts
1957
- var SqlDialectBase = class extends Dialect {
1846
+ var SqlDialectBase = class extends DialectBase {
1958
1847
  paginationStrategy = new StandardLimitOffsetPagination();
1959
1848
  returningStrategy = new NoReturningStrategy();
1960
1849
  compileSelectAst(ast, ctx) {
@@ -1964,14 +1853,12 @@ var SqlDialectBase = class extends Dialect {
1964
1853
  ctx,
1965
1854
  this.quoteIdentifier.bind(this),
1966
1855
  this.compileSelectAst.bind(this),
1967
- this.normalizeSelectAst?.bind(this) ?? ((a) => a),
1856
+ this.normalizeSelectAst.bind(this),
1968
1857
  this.stripTrailingSemicolon.bind(this)
1969
1858
  );
1970
1859
  const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
1971
1860
  const baseSelect = this.compileSelectCore(baseAst, ctx);
1972
- if (!hasSetOps) {
1973
- return `${ctes}${baseSelect}`;
1974
- }
1861
+ if (!hasSetOps) return `${ctes}${baseSelect}`;
1975
1862
  return this.compileSelectWithSetOps(ast, baseSelect, ctes, ctx);
1976
1863
  }
1977
1864
  compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
@@ -2020,9 +1907,7 @@ var SqlDialectBase = class extends Dialect {
2020
1907
  return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
2021
1908
  }
2022
1909
  ensureConflictColumns(clause, message) {
2023
- if (!clause.target.columns.length) {
2024
- throw new Error(message);
2025
- }
1910
+ if (!clause.target.columns.length) throw new Error(message);
2026
1911
  }
2027
1912
  compileSelectCore(ast, ctx) {
2028
1913
  const columns = this.compileSelectColumns(ast, ctx);
@@ -2055,8 +1940,7 @@ var SqlDialectBase = class extends Dialect {
2055
1940
  }
2056
1941
  compileUpdateAssignments(assignments, table, ctx) {
2057
1942
  return assignments.map((assignment) => {
2058
- const col2 = assignment.column;
2059
- const target = this.compileSetTarget(col2, table);
1943
+ const target = this.compileSetTarget(assignment.column, table);
2060
1944
  const value = this.compileOperand(assignment.value, ctx);
2061
1945
  return `${target} = ${value}`;
2062
1946
  }).join(", ");
@@ -2069,9 +1953,7 @@ var SqlDialectBase = class extends Dialect {
2069
1953
  const alias = table.alias;
2070
1954
  const columnTable = column.table ?? alias ?? baseTableName;
2071
1955
  const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
2072
- if (!tableQualifier) {
2073
- return this.quoteIdentifier(column.name);
2074
- }
1956
+ if (!tableQualifier) return this.quoteIdentifier(column.name);
2075
1957
  return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
2076
1958
  }
2077
1959
  compileDeleteAst(ast, ctx) {
@@ -2088,27 +1970,20 @@ var SqlDialectBase = class extends Dialect {
2088
1970
  return ast.distinct ? "DISTINCT " : "";
2089
1971
  }
2090
1972
  compileSelectColumns(ast, ctx) {
2091
- if (!ast.columns || ast.columns.length === 0) {
2092
- return "*";
2093
- }
2094
- return ast.columns.map((c) => {
2095
- const expr = this.compileOperand(c, ctx);
2096
- if (c.alias) {
2097
- if (c.alias.includes("(")) return c.alias;
2098
- return `${expr} AS ${this.quoteIdentifier(c.alias)}`;
1973
+ if (!ast.columns || ast.columns.length === 0) return "*";
1974
+ return ast.columns.map((column) => {
1975
+ const expr = this.compileOperand(column, ctx);
1976
+ if (column.alias) {
1977
+ if (column.alias.includes("(")) return column.alias;
1978
+ return `${expr} AS ${this.quoteIdentifier(column.alias)}`;
2099
1979
  }
2100
1980
  return expr;
2101
1981
  }).join(", ");
2102
1982
  }
2103
1983
  compileFrom(ast, ctx) {
2104
- const tableSource = ast;
2105
- if (tableSource.type === "FunctionTable") {
2106
- return this.compileFunctionTable(tableSource, ctx);
2107
- }
2108
- if (tableSource.type === "DerivedTable") {
2109
- return this.compileDerivedTable(tableSource, ctx);
2110
- }
2111
- return this.compileTableSource(tableSource);
1984
+ if (ast.type === "FunctionTable") return this.compileFunctionTable(ast, ctx);
1985
+ if (ast.type === "DerivedTable") return this.compileDerivedTable(ast, ctx);
1986
+ return this.compileTableSource(ast);
2112
1987
  }
2113
1988
  compileFunctionTable(fn9, ctx) {
2114
1989
  const key = fn9.key ?? fn9.name;
@@ -2127,23 +2002,20 @@ var SqlDialectBase = class extends Dialect {
2127
2002
  throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
2128
2003
  }
2129
2004
  }
2130
- return FunctionTableFormatter.format(fn9, ctx, this);
2005
+ return FunctionTableFormatter.format(fn9, ctx, {
2006
+ quoteIdentifier: (id) => this.quoteIdentifier(id),
2007
+ compileOperand: (node, compilerContext) => this.compileOperand(node, compilerContext)
2008
+ });
2131
2009
  }
2132
2010
  compileDerivedTable(table, ctx) {
2133
- if (!table.alias) {
2134
- throw new Error("Derived tables must have an alias.");
2135
- }
2011
+ if (!table.alias) throw new Error("Derived tables must have an alias.");
2136
2012
  const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2137
2013
  const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2138
2014
  return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
2139
2015
  }
2140
2016
  compileTableSource(table) {
2141
- if (table.type === "FunctionTable") {
2142
- return this.compileFunctionTable(table);
2143
- }
2144
- if (table.type === "DerivedTable") {
2145
- return this.compileDerivedTable(table);
2146
- }
2017
+ if (table.type === "FunctionTable") return this.compileFunctionTable(table);
2018
+ if (table.type === "DerivedTable") return this.compileDerivedTable(table);
2147
2019
  const base = this.compileTableName(table);
2148
2020
  return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2149
2021
  }
@@ -2159,9 +2031,7 @@ var SqlDialectBase = class extends Dialect {
2159
2031
  }
2160
2032
  compileUpdateFromClause(ast, ctx) {
2161
2033
  if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
2162
- if (!ast.from) {
2163
- throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2164
- }
2034
+ if (!ast.from) throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
2165
2035
  const from = this.compileFrom(ast.from, ctx);
2166
2036
  const joins = JoinCompiler.compileJoins(
2167
2037
  ast.joins,
@@ -2173,9 +2043,7 @@ var SqlDialectBase = class extends Dialect {
2173
2043
  }
2174
2044
  compileDeleteUsingClause(ast, ctx) {
2175
2045
  if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
2176
- if (!ast.using) {
2177
- throw new Error("DELETE with JOINs requires a USING clause.");
2178
- }
2046
+ if (!ast.using) throw new Error("DELETE with JOINs requires a USING clause.");
2179
2047
  const usingTable = this.compileFrom(ast.using, ctx);
2180
2048
  const joins = JoinCompiler.compileJoins(
2181
2049
  ast.joins,
@@ -2193,8 +2061,7 @@ var SqlDialectBase = class extends Dialect {
2193
2061
  return sql.trim().replace(/;$/, "");
2194
2062
  }
2195
2063
  wrapSetOperand(sql) {
2196
- const trimmed = this.stripTrailingSemicolon(sql);
2197
- return `(${trimmed})`;
2064
+ return `(${this.stripTrailingSemicolon(sql)})`;
2198
2065
  }
2199
2066
  renderOrderByNulls(order) {
2200
2067
  return order.nulls ? ` NULLS ${order.nulls}` : "";
@@ -2903,10 +2770,6 @@ var SqliteDialect = class extends SqlDialectBase {
2903
2770
  supportsDmlReturningClause() {
2904
2771
  return true;
2905
2772
  }
2906
- compileProcedureCall(_ast) {
2907
- void _ast;
2908
- throw new Error("Stored procedures are not supported by the SQLite dialect.");
2909
- }
2910
2773
  };
2911
2774
 
2912
2775
  // src/core/dialect/mssql/functions.ts
@@ -3341,9 +3204,8 @@ var DialectFactory = class {
3341
3204
  /**
3342
3205
  * Register (or override) a dialect factory for a key.
3343
3206
  *
3344
- * Examples:
3345
- * DialectFactory.register('sqlite', () => new SqliteDialect());
3346
- * DialectFactory.register('my-tenant-dialect', () => new CustomDialect());
3207
+ * Implementations are structural: extending DialectBase/SqlDialectBase is
3208
+ * optional. A composed object satisfying Dialect is a valid registration.
3347
3209
  */
3348
3210
  static register(key, factory) {
3349
3211
  this.registry.set(key, factory);
@@ -10916,6 +10778,15 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
10916
10778
  };
10917
10779
  var isTableSourceNode2 = (source) => typeof source.type === "string";
10918
10780
 
10781
+ // src/core/dialect/capabilities/procedure-compiler.ts
10782
+ var isProcedureCompiler = (value) => typeof value?.compileProcedureCall === "function";
10783
+ var requireProcedureCompiler = (value) => {
10784
+ if (!isProcedureCompiler(value)) {
10785
+ throw new Error("Stored procedures are not supported by this dialect.");
10786
+ }
10787
+ return value;
10788
+ };
10789
+
10919
10790
  // src/orm/execute-procedure.ts
10920
10791
  var resolveColumnIndex = (columns, expectedName) => {
10921
10792
  const exact = columns.findIndex((column) => column === expectedName);
@@ -10954,7 +10825,7 @@ var extractOutValues = (compiled, resultSets) => {
10954
10825
  };
10955
10826
  var executeProcedureAst = async (session, ast) => {
10956
10827
  const execCtx = session.getExecutionContext();
10957
- const compiled = execCtx.dialect.compileProcedureCall(ast);
10828
+ const compiled = requireProcedureCompiler(execCtx.dialect).compileProcedureCall(ast);
10958
10829
  const payload = await execCtx.interceptors.run(
10959
10830
  { sql: compiled.sql, params: compiled.params },
10960
10831
  execCtx.executor
@@ -11027,8 +10898,7 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
11027
10898
  }
11028
10899
  compile(dialect) {
11029
10900
  const resolved = resolveDialectInput(dialect);
11030
- this.validateMssqlOutDbType(resolved);
11031
- return resolved.compileProcedureCall(this.getAST());
10901
+ return requireProcedureCompiler(resolved).compileProcedureCall(this.getAST());
11032
10902
  }
11033
10903
  toSql(dialect) {
11034
10904
  return this.compile(dialect).sql;
@@ -11041,21 +10911,8 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
11041
10911
  };
11042
10912
  }
11043
10913
  async execute(session) {
11044
- this.validateMssqlOutDbType(session.getExecutionContext().dialect);
11045
10914
  return executeProcedureAst(session, this.getAST());
11046
10915
  }
11047
- validateMssqlOutDbType(dialect) {
11048
- const isMssqlDialect = dialect.constructor.name === "SqlServerDialect";
11049
- if (!isMssqlDialect) return;
11050
- for (const param of this.ast.params) {
11051
- const needsDbType = param.direction === "out" || param.direction === "inout";
11052
- if (needsDbType && !param.dbType) {
11053
- throw new Error(
11054
- `MSSQL requires "dbType" for procedure parameter "${param.name}" with direction "${param.direction}".`
11055
- );
11056
- }
11057
- }
11058
- }
11059
10916
  };
11060
10917
  var callProcedure = (name, options) => new ProcedureCallBuilder(name, options);
11061
10918
 
@@ -21783,6 +21640,8 @@ export {
21783
21640
  DefaultMorphToReference,
21784
21641
  DefaultTypeStrategy,
21785
21642
  DeleteQueryBuilder,
21643
+ DialectBase,
21644
+ DialectFactory,
21786
21645
  DomainEventBus,
21787
21646
  Email,
21788
21647
  Entity,
@@ -22010,6 +21869,7 @@ export {
22010
21869
  isNull,
22011
21870
  isNullableColumn,
22012
21871
  isOperandNode,
21872
+ isProcedureCompiler,
22013
21873
  isSingleTargetRelation,
22014
21874
  isTableDef2 as isTableDef,
22015
21875
  isTreeConfig,
@@ -22107,6 +21967,8 @@ export {
22107
21967
  repeat,
22108
21968
  replace,
22109
21969
  replaceWithRefs,
21970
+ requireProcedureCompiler,
21971
+ resolveDialectInput,
22110
21972
  resolveTreeConfig,
22111
21973
  resolveValidator,
22112
21974
  responseToRef,