metal-orm 1.1.21 → 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.cjs +379 -474
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -173
- package/dist/index.d.ts +145 -173
- package/dist/index.js +374 -474
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ddl/introspect/catalogs/mssql.ts +0 -8
- package/src/core/ddl/introspect/catalogs/mysql.ts +0 -5
- package/src/core/ddl/introspect/catalogs/postgres.ts +0 -9
- package/src/core/ddl/introspect/catalogs/sqlite.ts +0 -3
- package/src/core/dialect/abstract.ts +94 -417
- package/src/core/dialect/base/expression-compiler-registry.ts +254 -0
- package/src/core/dialect/base/function-table-formatter.ts +40 -78
- package/src/core/dialect/base/select-ast-normalizer.ts +61 -0
- package/src/core/dialect/base/sql-dialect.ts +36 -59
- package/src/core/dialect/capabilities/procedure-compiler.ts +30 -0
- package/src/core/dialect/dialect-factory.ts +3 -4
- package/src/core/dialect/mssql/index.ts +3 -2
- package/src/core/dialect/mysql/index.ts +3 -2
- package/src/core/dialect/postgres/index.ts +3 -2
- package/src/core/dialect/sqlite/index.ts +1 -7
- package/src/decorators/entity.ts +2 -3
- package/src/index.ts +4 -0
- package/src/orm/entity-metadata.ts +6 -11
- package/src/orm/execute-procedure.ts +3 -2
- package/src/orm/lifecycle.ts +20 -0
- package/src/orm/orm-session.ts +37 -3
- package/src/orm/unit-of-work.ts +15 -9
- package/src/query-builder/procedure-call.ts +4 -18
- package/src/schema/table.ts +10 -25
- package/src/tree/tree-manager.ts +111 -43
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var init_schema_plan_executor = __esm({
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
// src/schema/table.ts
|
|
39
|
-
var defineTable = (name, columns, relations = {},
|
|
39
|
+
var defineTable = (name, columns, relations = {}, options = {}) => {
|
|
40
40
|
const colsWithNames = Object.entries(columns).reduce((acc, [key, def]) => {
|
|
41
41
|
const colDef = { ...def, name: key, table: name };
|
|
42
42
|
acc[key] = colDef;
|
|
@@ -47,7 +47,6 @@ var defineTable = (name, columns, relations = {}, hooks, options = {}) => {
|
|
|
47
47
|
schema: options.schema,
|
|
48
48
|
columns: colsWithNames,
|
|
49
49
|
relations,
|
|
50
|
-
hooks,
|
|
51
50
|
primaryKey: options.primaryKey,
|
|
52
51
|
indexes: options.indexes,
|
|
53
52
|
checks: options.checks,
|
|
@@ -1315,268 +1314,40 @@ var StandardTableFunctionStrategy = class {
|
|
|
1315
1314
|
}
|
|
1316
1315
|
};
|
|
1317
1316
|
|
|
1318
|
-
// src/core/dialect/
|
|
1319
|
-
var
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
* @param ast - Query AST to compile
|
|
1323
|
-
* @returns Compiled query with SQL and parameters
|
|
1324
|
-
*/
|
|
1325
|
-
compileSelect(ast) {
|
|
1326
|
-
const ctx = this.createCompilerContext();
|
|
1327
|
-
const normalized = this.normalizeSelectAst(ast);
|
|
1328
|
-
const rawSql = this.compileSelectAst(normalized, ctx).trim();
|
|
1329
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1330
|
-
return {
|
|
1331
|
-
sql,
|
|
1332
|
-
params: [...ctx.params]
|
|
1333
|
-
};
|
|
1334
|
-
}
|
|
1335
|
-
compileInsert(ast) {
|
|
1336
|
-
const ctx = this.createCompilerContext();
|
|
1337
|
-
const rawSql = this.compileInsertAst(ast, ctx).trim();
|
|
1338
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1339
|
-
return {
|
|
1340
|
-
sql,
|
|
1341
|
-
params: [...ctx.params]
|
|
1342
|
-
};
|
|
1343
|
-
}
|
|
1344
|
-
compileUpdate(ast) {
|
|
1345
|
-
const ctx = this.createCompilerContext();
|
|
1346
|
-
const rawSql = this.compileUpdateAst(ast, ctx).trim();
|
|
1347
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1348
|
-
return {
|
|
1349
|
-
sql,
|
|
1350
|
-
params: [...ctx.params]
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
compileDelete(ast) {
|
|
1354
|
-
const ctx = this.createCompilerContext();
|
|
1355
|
-
const rawSql = this.compileDeleteAst(ast, ctx).trim();
|
|
1356
|
-
const sql = rawSql.endsWith(";") ? rawSql : `${rawSql};`;
|
|
1357
|
-
return {
|
|
1358
|
-
sql,
|
|
1359
|
-
params: [...ctx.params]
|
|
1360
|
-
};
|
|
1361
|
-
}
|
|
1362
|
-
supportsDmlReturningClause() {
|
|
1363
|
-
return false;
|
|
1364
|
-
}
|
|
1365
|
-
/**
|
|
1366
|
-
* Compiles a WHERE clause
|
|
1367
|
-
* @param where - WHERE expression
|
|
1368
|
-
* @param ctx - Compiler context
|
|
1369
|
-
* @returns SQL WHERE clause or empty string
|
|
1370
|
-
*/
|
|
1371
|
-
compileWhere(where, ctx) {
|
|
1372
|
-
if (!where) return "";
|
|
1373
|
-
return ` WHERE ${this.compileExpression(where, ctx)}`;
|
|
1374
|
-
}
|
|
1375
|
-
compileReturning(returning, _ctx) {
|
|
1376
|
-
void _ctx;
|
|
1377
|
-
if (!returning || returning.length === 0) return "";
|
|
1378
|
-
throw new Error("RETURNING is not supported by this dialect.");
|
|
1379
|
-
}
|
|
1380
|
-
/**
|
|
1381
|
-
* Generates subquery for EXISTS expressions
|
|
1382
|
-
* Rule: Always forces SELECT 1, ignoring column list
|
|
1383
|
-
* Maintains FROM, JOINs, WHERE, GROUP BY, ORDER BY, LIMIT/OFFSET
|
|
1384
|
-
* Does not add ';' at the end
|
|
1385
|
-
* @param ast - Query AST
|
|
1386
|
-
* @param ctx - Compiler context
|
|
1387
|
-
* @returns SQL for EXISTS subquery
|
|
1388
|
-
*/
|
|
1389
|
-
compileSelectForExists(ast, ctx) {
|
|
1390
|
-
const normalized = this.normalizeSelectAst(ast);
|
|
1391
|
-
const full = this.compileSelectAst(normalized, ctx).trim().replace(/;$/, "");
|
|
1392
|
-
if (normalized.setOps && normalized.setOps.length > 0) {
|
|
1393
|
-
return `SELECT 1 FROM (${full}) AS _exists`;
|
|
1394
|
-
}
|
|
1395
|
-
const upper2 = full.toUpperCase();
|
|
1396
|
-
const fromIndex = upper2.indexOf(" FROM ");
|
|
1397
|
-
if (fromIndex === -1) {
|
|
1398
|
-
return full;
|
|
1399
|
-
}
|
|
1400
|
-
const tail = full.slice(fromIndex);
|
|
1401
|
-
return `SELECT 1${tail}`;
|
|
1402
|
-
}
|
|
1403
|
-
/**
|
|
1404
|
-
* Creates a new compiler context
|
|
1405
|
-
* @returns Compiler context with parameter management
|
|
1406
|
-
*/
|
|
1407
|
-
createCompilerContext() {
|
|
1408
|
-
const params = [];
|
|
1409
|
-
let counter = 0;
|
|
1410
|
-
return {
|
|
1411
|
-
params,
|
|
1412
|
-
addParameter: (value) => {
|
|
1413
|
-
counter += 1;
|
|
1414
|
-
params.push(value);
|
|
1415
|
-
return this.formatPlaceholder(counter);
|
|
1416
|
-
}
|
|
1417
|
-
};
|
|
1418
|
-
}
|
|
1419
|
-
/**
|
|
1420
|
-
* Formats a parameter placeholder
|
|
1421
|
-
* @param index - Parameter index
|
|
1422
|
-
* @returns Formatted placeholder string
|
|
1423
|
-
*/
|
|
1424
|
-
formatPlaceholder(_index) {
|
|
1425
|
-
void _index;
|
|
1426
|
-
return "?";
|
|
1427
|
-
}
|
|
1428
|
-
/**
|
|
1429
|
-
* Whether the current dialect supports a given set operation.
|
|
1430
|
-
* Override in concrete dialects to restrict support.
|
|
1431
|
-
*/
|
|
1432
|
-
supportsSetOperation(_kind) {
|
|
1433
|
-
void _kind;
|
|
1434
|
-
return true;
|
|
1435
|
-
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Validates set-operation semantics:
|
|
1438
|
-
* - Ensures the dialect supports requested operators.
|
|
1439
|
-
* - Enforces that only the outermost compound query may have ORDER/LIMIT/OFFSET.
|
|
1440
|
-
* @param ast - Query to validate
|
|
1441
|
-
* @param isOutermost - Whether this node is the outermost compound query
|
|
1442
|
-
*/
|
|
1443
|
-
validateSetOperations(ast, isOutermost = true) {
|
|
1444
|
-
const hasSetOps = !!(ast.setOps && ast.setOps.length);
|
|
1445
|
-
if (!isOutermost && (ast.orderBy || ast.limit !== void 0 || ast.offset !== void 0)) {
|
|
1446
|
-
throw new Error("ORDER BY / LIMIT / OFFSET are only allowed on the outermost compound query.");
|
|
1447
|
-
}
|
|
1448
|
-
if (hasSetOps) {
|
|
1449
|
-
for (const op of ast.setOps) {
|
|
1450
|
-
if (!this.supportsSetOperation(op.operator)) {
|
|
1451
|
-
throw new Error(`Set operation ${op.operator} is not supported by this dialect.`);
|
|
1452
|
-
}
|
|
1453
|
-
this.validateSetOperations(op.query, false);
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
/**
|
|
1458
|
-
* Hoists CTEs from set-operation operands to the outermost query so WITH appears once.
|
|
1459
|
-
* @param ast - Query AST
|
|
1460
|
-
* @returns Normalized AST without inner CTEs and a list of hoisted CTEs
|
|
1461
|
-
*/
|
|
1462
|
-
hoistCtes(ast) {
|
|
1463
|
-
let hoisted = [];
|
|
1464
|
-
const normalizedSetOps = ast.setOps?.map((op) => {
|
|
1465
|
-
const { normalized: child, hoistedCtes: childHoisted } = this.hoistCtes(op.query);
|
|
1466
|
-
const childCtes = child.ctes ?? [];
|
|
1467
|
-
if (childCtes.length) {
|
|
1468
|
-
hoisted = hoisted.concat(childCtes);
|
|
1469
|
-
}
|
|
1470
|
-
hoisted = hoisted.concat(childHoisted);
|
|
1471
|
-
const queryWithoutCtes = childCtes.length ? { ...child, ctes: void 0 } : child;
|
|
1472
|
-
return { ...op, query: queryWithoutCtes };
|
|
1473
|
-
});
|
|
1474
|
-
const normalized = normalizedSetOps ? { ...ast, setOps: normalizedSetOps } : ast;
|
|
1475
|
-
return { normalized, hoistedCtes: hoisted };
|
|
1476
|
-
}
|
|
1477
|
-
/**
|
|
1478
|
-
* Normalizes a SELECT AST before compilation (validation + CTE hoisting).
|
|
1479
|
-
* @param ast - Query AST
|
|
1480
|
-
* @returns Normalized query AST
|
|
1481
|
-
*/
|
|
1482
|
-
normalizeSelectAst(ast) {
|
|
1483
|
-
this.validateSetOperations(ast, true);
|
|
1484
|
-
const { normalized, hoistedCtes } = this.hoistCtes(ast);
|
|
1485
|
-
const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
|
|
1486
|
-
return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
|
|
1487
|
-
}
|
|
1488
|
-
expressionCompilers;
|
|
1489
|
-
operandCompilers;
|
|
1490
|
-
functionStrategy;
|
|
1491
|
-
tableFunctionStrategy;
|
|
1492
|
-
constructor(functionStrategy, tableFunctionStrategy) {
|
|
1493
|
-
this.expressionCompilers = /* @__PURE__ */ new Map();
|
|
1494
|
-
this.operandCompilers = /* @__PURE__ */ new Map();
|
|
1495
|
-
this.functionStrategy = functionStrategy || new StandardFunctionStrategy();
|
|
1496
|
-
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;
|
|
1497
1321
|
this.registerDefaultOperandCompilers();
|
|
1498
1322
|
this.registerDefaultExpressionCompilers();
|
|
1499
1323
|
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
* @param functionStrategy - Optional function strategy
|
|
1503
|
-
* @returns New Dialect instance
|
|
1504
|
-
*/
|
|
1505
|
-
static create(functionStrategy, tableFunctionStrategy) {
|
|
1506
|
-
class TestDialect extends _Dialect {
|
|
1507
|
-
dialect = "sqlite";
|
|
1508
|
-
quoteIdentifier(id) {
|
|
1509
|
-
return `"${id}"`;
|
|
1510
|
-
}
|
|
1511
|
-
compileSelectAst() {
|
|
1512
|
-
throw new Error("Not implemented");
|
|
1513
|
-
}
|
|
1514
|
-
compileInsertAst() {
|
|
1515
|
-
throw new Error("Not implemented");
|
|
1516
|
-
}
|
|
1517
|
-
compileUpdateAst() {
|
|
1518
|
-
throw new Error("Not implemented");
|
|
1519
|
-
}
|
|
1520
|
-
compileDeleteAst() {
|
|
1521
|
-
throw new Error("Not implemented");
|
|
1522
|
-
}
|
|
1523
|
-
compileProcedureCall() {
|
|
1524
|
-
throw new Error("Not implemented");
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
return new TestDialect(functionStrategy, tableFunctionStrategy);
|
|
1528
|
-
}
|
|
1529
|
-
/**
|
|
1530
|
-
* Registers an expression compiler for a specific node type
|
|
1531
|
-
* @param type - Expression node type
|
|
1532
|
-
* @param compiler - Compiler function
|
|
1533
|
-
*/
|
|
1324
|
+
expressionCompilers = /* @__PURE__ */ new Map();
|
|
1325
|
+
operandCompilers = /* @__PURE__ */ new Map();
|
|
1534
1326
|
registerExpressionCompiler(type, compiler) {
|
|
1535
1327
|
this.expressionCompilers.set(type, compiler);
|
|
1536
1328
|
}
|
|
1537
|
-
/**
|
|
1538
|
-
* Registers an operand compiler for a specific node type
|
|
1539
|
-
* @param type - Operand node type
|
|
1540
|
-
* @param compiler - Compiler function
|
|
1541
|
-
*/
|
|
1542
1329
|
registerOperandCompiler(type, compiler) {
|
|
1543
1330
|
this.operandCompilers.set(type, compiler);
|
|
1544
1331
|
}
|
|
1545
|
-
/**
|
|
1546
|
-
* Compiles an expression node
|
|
1547
|
-
* @param node - Expression node to compile
|
|
1548
|
-
* @param ctx - Compiler context
|
|
1549
|
-
* @returns Compiled SQL expression
|
|
1550
|
-
*/
|
|
1551
1332
|
compileExpression(node, ctx) {
|
|
1552
1333
|
const compiler = this.expressionCompilers.get(node.type);
|
|
1553
1334
|
if (!compiler) {
|
|
1554
|
-
throw new Error(`Unsupported expression node type "${node.type}" for ${this.
|
|
1335
|
+
throw new Error(`Unsupported expression node type "${node.type}" for ${this.host.describe()}`);
|
|
1555
1336
|
}
|
|
1556
1337
|
return compiler(node, ctx);
|
|
1557
1338
|
}
|
|
1558
|
-
/**
|
|
1559
|
-
* Compiles an operand node
|
|
1560
|
-
* @param node - Operand node to compile
|
|
1561
|
-
* @param ctx - Compiler context
|
|
1562
|
-
* @returns Compiled SQL operand
|
|
1563
|
-
*/
|
|
1564
1339
|
compileOperand(node, ctx) {
|
|
1565
1340
|
const compiler = this.operandCompilers.get(node.type);
|
|
1566
1341
|
if (!compiler) {
|
|
1567
|
-
throw new Error(`Unsupported operand node type "${node.type}" for ${this.
|
|
1342
|
+
throw new Error(`Unsupported operand node type "${node.type}" for ${this.host.describe()}`);
|
|
1568
1343
|
}
|
|
1569
1344
|
return compiler(node, ctx);
|
|
1570
1345
|
}
|
|
1571
|
-
/**
|
|
1572
|
-
* Compiles an ordering term (operand, expression, or alias reference).
|
|
1573
|
-
*/
|
|
1574
1346
|
compileOrderingTerm(term, ctx) {
|
|
1575
1347
|
if (isOperandNode(term)) {
|
|
1576
1348
|
return this.compileOperand(term, ctx);
|
|
1577
1349
|
}
|
|
1578
|
-
|
|
1579
|
-
return `(${expr})`;
|
|
1350
|
+
return `(${this.compileExpression(term, ctx)})`;
|
|
1580
1351
|
}
|
|
1581
1352
|
registerDefaultExpressionCompilers() {
|
|
1582
1353
|
this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
|
|
@@ -1611,11 +1382,11 @@ var Dialect = class _Dialect {
|
|
|
1611
1382
|
const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
|
|
1612
1383
|
return `${left2} ${inExpr.operator} (${values})`;
|
|
1613
1384
|
}
|
|
1614
|
-
const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
|
|
1385
|
+
const subquerySql = this.host.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
|
|
1615
1386
|
return `${left2} ${inExpr.operator} (${subquerySql})`;
|
|
1616
1387
|
});
|
|
1617
1388
|
this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
|
|
1618
|
-
const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
|
|
1389
|
+
const subquerySql = this.host.compileSelectForExists(existsExpr.subquery, ctx);
|
|
1619
1390
|
return `${existsExpr.operator} (${subquerySql})`;
|
|
1620
1391
|
});
|
|
1621
1392
|
this.registerExpressionCompiler("BetweenExpression", (betweenExpr, ctx) => {
|
|
@@ -1641,25 +1412,28 @@ var Dialect = class _Dialect {
|
|
|
1641
1412
|
});
|
|
1642
1413
|
}
|
|
1643
1414
|
registerDefaultOperandCompilers() {
|
|
1644
|
-
this.registerOperandCompiler(
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
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
|
+
);
|
|
1653
1427
|
this.registerOperandCompiler(
|
|
1654
1428
|
"Function",
|
|
1655
|
-
(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)
|
|
1656
1434
|
);
|
|
1657
|
-
this.registerOperandCompiler("JsonPath", (path, _ctx) => {
|
|
1658
|
-
void _ctx;
|
|
1659
|
-
return this.compileJsonPath(path);
|
|
1660
|
-
});
|
|
1661
1435
|
this.registerOperandCompiler("ScalarSubquery", (node, ctx) => {
|
|
1662
|
-
const sql = this.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
|
|
1436
|
+
const sql = this.host.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
|
|
1663
1437
|
return `(${sql})`;
|
|
1664
1438
|
});
|
|
1665
1439
|
this.registerOperandCompiler("CaseExpression", (node, ctx) => {
|
|
@@ -1686,7 +1460,7 @@ var Dialect = class _Dialect {
|
|
|
1686
1460
|
const parts = [];
|
|
1687
1461
|
if (node.partitionBy && node.partitionBy.length > 0) {
|
|
1688
1462
|
const partitionClause = "PARTITION BY " + node.partitionBy.map(
|
|
1689
|
-
(col2) => `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`
|
|
1463
|
+
(col2) => `${this.host.quoteIdentifier(col2.table)}.${this.host.quoteIdentifier(col2.name)}`
|
|
1690
1464
|
).join(", ");
|
|
1691
1465
|
parts.push(partitionClause);
|
|
1692
1466
|
}
|
|
@@ -1718,14 +1492,164 @@ var Dialect = class _Dialect {
|
|
|
1718
1492
|
return `${expr} COLLATE ${node.collation}`;
|
|
1719
1493
|
});
|
|
1720
1494
|
}
|
|
1721
|
-
|
|
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
|
+
}
|
|
1722
1649
|
compileJsonPath(_node) {
|
|
1723
1650
|
void _node;
|
|
1724
1651
|
throw new Error("JSON Path not supported by this dialect");
|
|
1725
1652
|
}
|
|
1726
|
-
/**
|
|
1727
|
-
* Compiles a function operand, using the dialect's function strategy.
|
|
1728
|
-
*/
|
|
1729
1653
|
compileFunctionOperand(fnNode, ctx) {
|
|
1730
1654
|
const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
|
|
1731
1655
|
const renderer = this.functionStrategy.getRenderer(fnNode.name);
|
|
@@ -1738,98 +1662,62 @@ var Dialect = class _Dialect {
|
|
|
1738
1662
|
}
|
|
1739
1663
|
return `${fnNode.name}(${compiledArgs.join(", ")})`;
|
|
1740
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
|
+
}
|
|
1741
1687
|
};
|
|
1742
1688
|
|
|
1743
1689
|
// src/core/dialect/base/function-table-formatter.ts
|
|
1744
1690
|
var FunctionTableFormatter = class {
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
* @param ctx - Optional compiler context for operand compilation.
|
|
1749
|
-
* @param dialect - The dialect instance for compiling operands.
|
|
1750
|
-
* @returns SQL function table expression (e.g., "LATERAL schema.func(args) WITH ORDINALITY AS alias(col1, col2)").
|
|
1751
|
-
*/
|
|
1752
|
-
static format(fn9, ctx, dialect) {
|
|
1753
|
-
const schemaPart = this.formatSchema(fn9, dialect);
|
|
1754
|
-
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);
|
|
1755
1694
|
const base = this.formatBase(fn9, schemaPart, args);
|
|
1756
1695
|
const lateral = this.formatLateral(fn9);
|
|
1757
|
-
const alias = this.formatAlias(fn9,
|
|
1758
|
-
const colAliases = this.formatColumnAliases(fn9,
|
|
1696
|
+
const alias = this.formatAlias(fn9, formatter);
|
|
1697
|
+
const colAliases = this.formatColumnAliases(fn9, formatter);
|
|
1759
1698
|
return `${lateral}${base}${alias}${colAliases}`;
|
|
1760
1699
|
}
|
|
1761
|
-
|
|
1762
|
-
* Formats the schema prefix for the function name.
|
|
1763
|
-
* @param fn - The function table node.
|
|
1764
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
1765
|
-
* @returns Schema prefix (e.g., "schema.") or empty string.
|
|
1766
|
-
* @internal
|
|
1767
|
-
*/
|
|
1768
|
-
static formatSchema(fn9, dialect) {
|
|
1700
|
+
static formatSchema(fn9, formatter) {
|
|
1769
1701
|
if (!fn9.schema) return "";
|
|
1770
|
-
|
|
1771
|
-
return `${quoted}.`;
|
|
1702
|
+
return `${formatter.quoteIdentifier(fn9.schema)}.`;
|
|
1772
1703
|
}
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
* @param fn - The function table node containing arguments.
|
|
1776
|
-
* @param ctx - Optional compiler context for operand compilation.
|
|
1777
|
-
* @param dialect - The dialect instance for compiling operands.
|
|
1778
|
-
* @returns Comma-separated function arguments.
|
|
1779
|
-
* @internal
|
|
1780
|
-
*/
|
|
1781
|
-
static formatArgs(fn9, ctx, dialect) {
|
|
1782
|
-
return (fn9.args || []).map((a) => {
|
|
1783
|
-
if (ctx && dialect) {
|
|
1784
|
-
return dialect.compileOperand(a, ctx);
|
|
1785
|
-
}
|
|
1786
|
-
return String(a);
|
|
1787
|
-
}).join(", ");
|
|
1704
|
+
static formatArgs(fn9, ctx, formatter) {
|
|
1705
|
+
return (fn9.args || []).map((arg) => ctx ? formatter.compileOperand(arg, ctx) : String(arg)).join(", ");
|
|
1788
1706
|
}
|
|
1789
|
-
/**
|
|
1790
|
-
* Formats the base function call with WITH ORDINALITY if present.
|
|
1791
|
-
* @param fn - The function table node.
|
|
1792
|
-
* @param schemaPart - Formatted schema prefix.
|
|
1793
|
-
* @param args - Formatted function arguments.
|
|
1794
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
1795
|
-
* @returns Base function call expression (e.g., "schema.func(args) WITH ORDINALITY").
|
|
1796
|
-
* @internal
|
|
1797
|
-
*/
|
|
1798
1707
|
static formatBase(fn9, schemaPart, args) {
|
|
1799
1708
|
const ordinality = fn9.withOrdinality ? " WITH ORDINALITY" : "";
|
|
1800
1709
|
return `${schemaPart}${fn9.name}(${args})${ordinality}`;
|
|
1801
1710
|
}
|
|
1802
|
-
/**
|
|
1803
|
-
* Formats the LATERAL keyword if present.
|
|
1804
|
-
* @param fn - The function table node.
|
|
1805
|
-
* @returns "LATERAL " or empty string.
|
|
1806
|
-
* @internal
|
|
1807
|
-
*/
|
|
1808
1711
|
static formatLateral(fn9) {
|
|
1809
1712
|
return fn9.lateral ? "LATERAL " : "";
|
|
1810
1713
|
}
|
|
1811
|
-
|
|
1812
|
-
* Formats the table alias for the function table.
|
|
1813
|
-
* @param fn - The function table node.
|
|
1814
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
1815
|
-
* @returns " AS alias" or empty string.
|
|
1816
|
-
* @internal
|
|
1817
|
-
*/
|
|
1818
|
-
static formatAlias(fn9, dialect) {
|
|
1714
|
+
static formatAlias(fn9, formatter) {
|
|
1819
1715
|
if (!fn9.alias) return "";
|
|
1820
|
-
|
|
1821
|
-
return ` AS ${quoted}`;
|
|
1716
|
+
return ` AS ${formatter.quoteIdentifier(fn9.alias)}`;
|
|
1822
1717
|
}
|
|
1823
|
-
|
|
1824
|
-
* Formats column aliases for the function table result columns.
|
|
1825
|
-
* @param fn - The function table node containing column aliases.
|
|
1826
|
-
* @param dialect - The dialect instance for quoting identifiers.
|
|
1827
|
-
* @returns "(col1, col2, ...)" or empty string.
|
|
1828
|
-
* @internal
|
|
1829
|
-
*/
|
|
1830
|
-
static formatColumnAliases(fn9, dialect) {
|
|
1718
|
+
static formatColumnAliases(fn9, formatter) {
|
|
1831
1719
|
if (!fn9.columnAliases || !fn9.columnAliases.length) return "";
|
|
1832
|
-
const aliases = fn9.columnAliases.map((col2) =>
|
|
1720
|
+
const aliases = fn9.columnAliases.map((col2) => formatter.quoteIdentifier(col2)).join(", ");
|
|
1833
1721
|
return `(${aliases})`;
|
|
1834
1722
|
}
|
|
1835
1723
|
};
|
|
@@ -1955,7 +1843,7 @@ var OrderByCompiler = class {
|
|
|
1955
1843
|
};
|
|
1956
1844
|
|
|
1957
1845
|
// src/core/dialect/base/sql-dialect.ts
|
|
1958
|
-
var SqlDialectBase = class extends
|
|
1846
|
+
var SqlDialectBase = class extends DialectBase {
|
|
1959
1847
|
paginationStrategy = new StandardLimitOffsetPagination();
|
|
1960
1848
|
returningStrategy = new NoReturningStrategy();
|
|
1961
1849
|
compileSelectAst(ast, ctx) {
|
|
@@ -1965,14 +1853,12 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1965
1853
|
ctx,
|
|
1966
1854
|
this.quoteIdentifier.bind(this),
|
|
1967
1855
|
this.compileSelectAst.bind(this),
|
|
1968
|
-
this.normalizeSelectAst
|
|
1856
|
+
this.normalizeSelectAst.bind(this),
|
|
1969
1857
|
this.stripTrailingSemicolon.bind(this)
|
|
1970
1858
|
);
|
|
1971
1859
|
const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
|
|
1972
1860
|
const baseSelect = this.compileSelectCore(baseAst, ctx);
|
|
1973
|
-
if (!hasSetOps) {
|
|
1974
|
-
return `${ctes}${baseSelect}`;
|
|
1975
|
-
}
|
|
1861
|
+
if (!hasSetOps) return `${ctes}${baseSelect}`;
|
|
1976
1862
|
return this.compileSelectWithSetOps(ast, baseSelect, ctes, ctx);
|
|
1977
1863
|
}
|
|
1978
1864
|
compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
|
|
@@ -2021,9 +1907,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2021
1907
|
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
2022
1908
|
}
|
|
2023
1909
|
ensureConflictColumns(clause, message) {
|
|
2024
|
-
if (!clause.target.columns.length)
|
|
2025
|
-
throw new Error(message);
|
|
2026
|
-
}
|
|
1910
|
+
if (!clause.target.columns.length) throw new Error(message);
|
|
2027
1911
|
}
|
|
2028
1912
|
compileSelectCore(ast, ctx) {
|
|
2029
1913
|
const columns = this.compileSelectColumns(ast, ctx);
|
|
@@ -2056,8 +1940,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2056
1940
|
}
|
|
2057
1941
|
compileUpdateAssignments(assignments, table, ctx) {
|
|
2058
1942
|
return assignments.map((assignment) => {
|
|
2059
|
-
const
|
|
2060
|
-
const target = this.compileSetTarget(col2, table);
|
|
1943
|
+
const target = this.compileSetTarget(assignment.column, table);
|
|
2061
1944
|
const value = this.compileOperand(assignment.value, ctx);
|
|
2062
1945
|
return `${target} = ${value}`;
|
|
2063
1946
|
}).join(", ");
|
|
@@ -2070,9 +1953,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2070
1953
|
const alias = table.alias;
|
|
2071
1954
|
const columnTable = column.table ?? alias ?? baseTableName;
|
|
2072
1955
|
const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
|
|
2073
|
-
if (!tableQualifier)
|
|
2074
|
-
return this.quoteIdentifier(column.name);
|
|
2075
|
-
}
|
|
1956
|
+
if (!tableQualifier) return this.quoteIdentifier(column.name);
|
|
2076
1957
|
return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
|
|
2077
1958
|
}
|
|
2078
1959
|
compileDeleteAst(ast, ctx) {
|
|
@@ -2089,27 +1970,20 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2089
1970
|
return ast.distinct ? "DISTINCT " : "";
|
|
2090
1971
|
}
|
|
2091
1972
|
compileSelectColumns(ast, ctx) {
|
|
2092
|
-
if (!ast.columns || ast.columns.length === 0)
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
if (c.alias.includes("(")) return c.alias;
|
|
2099
|
-
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)}`;
|
|
2100
1979
|
}
|
|
2101
1980
|
return expr;
|
|
2102
1981
|
}).join(", ");
|
|
2103
1982
|
}
|
|
2104
1983
|
compileFrom(ast, ctx) {
|
|
2105
|
-
|
|
2106
|
-
if (
|
|
2107
|
-
|
|
2108
|
-
}
|
|
2109
|
-
if (tableSource.type === "DerivedTable") {
|
|
2110
|
-
return this.compileDerivedTable(tableSource, ctx);
|
|
2111
|
-
}
|
|
2112
|
-
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);
|
|
2113
1987
|
}
|
|
2114
1988
|
compileFunctionTable(fn9, ctx) {
|
|
2115
1989
|
const key = fn9.key ?? fn9.name;
|
|
@@ -2128,23 +2002,20 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2128
2002
|
throw new Error(`Table function "${key}" is not supported by dialect "${this.dialect}".`);
|
|
2129
2003
|
}
|
|
2130
2004
|
}
|
|
2131
|
-
return FunctionTableFormatter.format(fn9, ctx,
|
|
2005
|
+
return FunctionTableFormatter.format(fn9, ctx, {
|
|
2006
|
+
quoteIdentifier: (id) => this.quoteIdentifier(id),
|
|
2007
|
+
compileOperand: (node, compilerContext) => this.compileOperand(node, compilerContext)
|
|
2008
|
+
});
|
|
2132
2009
|
}
|
|
2133
2010
|
compileDerivedTable(table, ctx) {
|
|
2134
|
-
if (!table.alias)
|
|
2135
|
-
throw new Error("Derived tables must have an alias.");
|
|
2136
|
-
}
|
|
2011
|
+
if (!table.alias) throw new Error("Derived tables must have an alias.");
|
|
2137
2012
|
const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
2138
2013
|
const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
2139
2014
|
return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
|
|
2140
2015
|
}
|
|
2141
2016
|
compileTableSource(table) {
|
|
2142
|
-
if (table.type === "FunctionTable")
|
|
2143
|
-
|
|
2144
|
-
}
|
|
2145
|
-
if (table.type === "DerivedTable") {
|
|
2146
|
-
return this.compileDerivedTable(table);
|
|
2147
|
-
}
|
|
2017
|
+
if (table.type === "FunctionTable") return this.compileFunctionTable(table);
|
|
2018
|
+
if (table.type === "DerivedTable") return this.compileDerivedTable(table);
|
|
2148
2019
|
const base = this.compileTableName(table);
|
|
2149
2020
|
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
2150
2021
|
}
|
|
@@ -2160,9 +2031,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2160
2031
|
}
|
|
2161
2032
|
compileUpdateFromClause(ast, ctx) {
|
|
2162
2033
|
if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
|
|
2163
|
-
if (!ast.from)
|
|
2164
|
-
throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
|
|
2165
|
-
}
|
|
2034
|
+
if (!ast.from) throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
|
|
2166
2035
|
const from = this.compileFrom(ast.from, ctx);
|
|
2167
2036
|
const joins = JoinCompiler.compileJoins(
|
|
2168
2037
|
ast.joins,
|
|
@@ -2174,9 +2043,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2174
2043
|
}
|
|
2175
2044
|
compileDeleteUsingClause(ast, ctx) {
|
|
2176
2045
|
if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
|
|
2177
|
-
if (!ast.using)
|
|
2178
|
-
throw new Error("DELETE with JOINs requires a USING clause.");
|
|
2179
|
-
}
|
|
2046
|
+
if (!ast.using) throw new Error("DELETE with JOINs requires a USING clause.");
|
|
2180
2047
|
const usingTable = this.compileFrom(ast.using, ctx);
|
|
2181
2048
|
const joins = JoinCompiler.compileJoins(
|
|
2182
2049
|
ast.joins,
|
|
@@ -2194,8 +2061,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
2194
2061
|
return sql.trim().replace(/;$/, "");
|
|
2195
2062
|
}
|
|
2196
2063
|
wrapSetOperand(sql) {
|
|
2197
|
-
|
|
2198
|
-
return `(${trimmed})`;
|
|
2064
|
+
return `(${this.stripTrailingSemicolon(sql)})`;
|
|
2199
2065
|
}
|
|
2200
2066
|
renderOrderByNulls(order) {
|
|
2201
2067
|
return order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
@@ -2904,10 +2770,6 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
2904
2770
|
supportsDmlReturningClause() {
|
|
2905
2771
|
return true;
|
|
2906
2772
|
}
|
|
2907
|
-
compileProcedureCall(_ast) {
|
|
2908
|
-
void _ast;
|
|
2909
|
-
throw new Error("Stored procedures are not supported by the SQLite dialect.");
|
|
2910
|
-
}
|
|
2911
2773
|
};
|
|
2912
2774
|
|
|
2913
2775
|
// src/core/dialect/mssql/functions.ts
|
|
@@ -3342,9 +3204,8 @@ var DialectFactory = class {
|
|
|
3342
3204
|
/**
|
|
3343
3205
|
* Register (or override) a dialect factory for a key.
|
|
3344
3206
|
*
|
|
3345
|
-
*
|
|
3346
|
-
*
|
|
3347
|
-
* 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.
|
|
3348
3209
|
*/
|
|
3349
3210
|
static register(key, factory) {
|
|
3350
3211
|
this.registry.set(key, factory);
|
|
@@ -7963,14 +7824,11 @@ var addTransformerMetadata = (target, propertyKey, transformer) => {
|
|
|
7963
7824
|
const meta = ensureEntityMetadata(target);
|
|
7964
7825
|
meta.transformers[propertyKey] = transformer;
|
|
7965
7826
|
};
|
|
7966
|
-
var setEntityTableName = (target, tableName,
|
|
7827
|
+
var setEntityTableName = (target, tableName, type) => {
|
|
7967
7828
|
const meta = ensureEntityMetadata(target);
|
|
7968
7829
|
if (tableName && tableName.length > 0) {
|
|
7969
7830
|
meta.tableName = tableName;
|
|
7970
7831
|
}
|
|
7971
|
-
if (hooks) {
|
|
7972
|
-
meta.hooks = hooks;
|
|
7973
|
-
}
|
|
7974
7832
|
if (type) {
|
|
7975
7833
|
meta.type = type;
|
|
7976
7834
|
}
|
|
@@ -7987,7 +7845,7 @@ var buildTableDef = (meta) => {
|
|
|
7987
7845
|
table: meta.tableName
|
|
7988
7846
|
};
|
|
7989
7847
|
}
|
|
7990
|
-
const table = defineTable(meta.tableName, columns
|
|
7848
|
+
const table = defineTable(meta.tableName, columns);
|
|
7991
7849
|
meta.table = table;
|
|
7992
7850
|
return table;
|
|
7993
7851
|
};
|
|
@@ -10920,6 +10778,15 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
10920
10778
|
};
|
|
10921
10779
|
var isTableSourceNode2 = (source) => typeof source.type === "string";
|
|
10922
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
|
+
|
|
10923
10790
|
// src/orm/execute-procedure.ts
|
|
10924
10791
|
var resolveColumnIndex = (columns, expectedName) => {
|
|
10925
10792
|
const exact = columns.findIndex((column) => column === expectedName);
|
|
@@ -10958,7 +10825,7 @@ var extractOutValues = (compiled, resultSets) => {
|
|
|
10958
10825
|
};
|
|
10959
10826
|
var executeProcedureAst = async (session, ast) => {
|
|
10960
10827
|
const execCtx = session.getExecutionContext();
|
|
10961
|
-
const compiled = execCtx.dialect.compileProcedureCall(ast);
|
|
10828
|
+
const compiled = requireProcedureCompiler(execCtx.dialect).compileProcedureCall(ast);
|
|
10962
10829
|
const payload = await execCtx.interceptors.run(
|
|
10963
10830
|
{ sql: compiled.sql, params: compiled.params },
|
|
10964
10831
|
execCtx.executor
|
|
@@ -11031,8 +10898,7 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
|
|
|
11031
10898
|
}
|
|
11032
10899
|
compile(dialect) {
|
|
11033
10900
|
const resolved = resolveDialectInput(dialect);
|
|
11034
|
-
this.
|
|
11035
|
-
return resolved.compileProcedureCall(this.getAST());
|
|
10901
|
+
return requireProcedureCompiler(resolved).compileProcedureCall(this.getAST());
|
|
11036
10902
|
}
|
|
11037
10903
|
toSql(dialect) {
|
|
11038
10904
|
return this.compile(dialect).sql;
|
|
@@ -11045,21 +10911,8 @@ var ProcedureCallBuilder = class _ProcedureCallBuilder {
|
|
|
11045
10911
|
};
|
|
11046
10912
|
}
|
|
11047
10913
|
async execute(session) {
|
|
11048
|
-
this.validateMssqlOutDbType(session.getExecutionContext().dialect);
|
|
11049
10914
|
return executeProcedureAst(session, this.getAST());
|
|
11050
10915
|
}
|
|
11051
|
-
validateMssqlOutDbType(dialect) {
|
|
11052
|
-
const isMssqlDialect = dialect.constructor.name === "SqlServerDialect";
|
|
11053
|
-
if (!isMssqlDialect) return;
|
|
11054
|
-
for (const param of this.ast.params) {
|
|
11055
|
-
const needsDbType = param.direction === "out" || param.direction === "inout";
|
|
11056
|
-
if (needsDbType && !param.dbType) {
|
|
11057
|
-
throw new Error(
|
|
11058
|
-
`MSSQL requires "dbType" for procedure parameter "${param.name}" with direction "${param.direction}".`
|
|
11059
|
-
);
|
|
11060
|
-
}
|
|
11061
|
-
}
|
|
11062
|
-
}
|
|
11063
10916
|
};
|
|
11064
10917
|
var callProcedure = (name, options) => new ProcedureCallBuilder(name, options);
|
|
11065
10918
|
|
|
@@ -11409,7 +11262,6 @@ var PgInformationSchemaColumns = defineTable(
|
|
|
11409
11262
|
ordinal_position: col.int()
|
|
11410
11263
|
},
|
|
11411
11264
|
{},
|
|
11412
|
-
void 0,
|
|
11413
11265
|
{ schema: "information_schema" }
|
|
11414
11266
|
);
|
|
11415
11267
|
var PgClass = defineTable(
|
|
@@ -11421,7 +11273,6 @@ var PgClass = defineTable(
|
|
|
11421
11273
|
relkind: col.varchar(1)
|
|
11422
11274
|
},
|
|
11423
11275
|
{},
|
|
11424
|
-
void 0,
|
|
11425
11276
|
{ schema: "pg_catalog" }
|
|
11426
11277
|
);
|
|
11427
11278
|
var PgNamespace = defineTable(
|
|
@@ -11431,7 +11282,6 @@ var PgNamespace = defineTable(
|
|
|
11431
11282
|
nspname: col.varchar(255)
|
|
11432
11283
|
},
|
|
11433
11284
|
{},
|
|
11434
|
-
void 0,
|
|
11435
11285
|
{ schema: "pg_catalog" }
|
|
11436
11286
|
);
|
|
11437
11287
|
var PgIndex = defineTable(
|
|
@@ -11444,7 +11294,6 @@ var PgIndex = defineTable(
|
|
|
11444
11294
|
indpred: col.varchar(1024)
|
|
11445
11295
|
},
|
|
11446
11296
|
{},
|
|
11447
|
-
void 0,
|
|
11448
11297
|
{ schema: "pg_catalog" }
|
|
11449
11298
|
);
|
|
11450
11299
|
var PgAttribute = defineTable(
|
|
@@ -11455,7 +11304,6 @@ var PgAttribute = defineTable(
|
|
|
11455
11304
|
attnum: col.int()
|
|
11456
11305
|
},
|
|
11457
11306
|
{},
|
|
11458
|
-
void 0,
|
|
11459
11307
|
{ schema: "pg_catalog" }
|
|
11460
11308
|
);
|
|
11461
11309
|
var PgTableConstraints = defineTable(
|
|
@@ -11470,7 +11318,6 @@ var PgTableConstraints = defineTable(
|
|
|
11470
11318
|
constraint_type: col.varchar(255)
|
|
11471
11319
|
},
|
|
11472
11320
|
{},
|
|
11473
|
-
void 0,
|
|
11474
11321
|
{ schema: "information_schema" }
|
|
11475
11322
|
);
|
|
11476
11323
|
var PgKeyColumnUsage = defineTable(
|
|
@@ -11486,7 +11333,6 @@ var PgKeyColumnUsage = defineTable(
|
|
|
11486
11333
|
ordinal_position: col.int()
|
|
11487
11334
|
},
|
|
11488
11335
|
{},
|
|
11489
|
-
void 0,
|
|
11490
11336
|
{ schema: "information_schema" }
|
|
11491
11337
|
);
|
|
11492
11338
|
var PgConstraintColumnUsage = defineTable(
|
|
@@ -11501,7 +11347,6 @@ var PgConstraintColumnUsage = defineTable(
|
|
|
11501
11347
|
column_name: col.varchar(255)
|
|
11502
11348
|
},
|
|
11503
11349
|
{},
|
|
11504
|
-
void 0,
|
|
11505
11350
|
{ schema: "information_schema" }
|
|
11506
11351
|
);
|
|
11507
11352
|
var PgReferentialConstraints = defineTable(
|
|
@@ -11518,7 +11363,6 @@ var PgReferentialConstraints = defineTable(
|
|
|
11518
11363
|
delete_rule: col.varchar(64)
|
|
11519
11364
|
},
|
|
11520
11365
|
{},
|
|
11521
|
-
void 0,
|
|
11522
11366
|
{ schema: "information_schema" }
|
|
11523
11367
|
);
|
|
11524
11368
|
|
|
@@ -11900,7 +11744,6 @@ var InformationSchemaTables = defineTable(
|
|
|
11900
11744
|
table_comment: col.varchar(1024)
|
|
11901
11745
|
},
|
|
11902
11746
|
{},
|
|
11903
|
-
void 0,
|
|
11904
11747
|
{ schema: INFORMATION_SCHEMA }
|
|
11905
11748
|
);
|
|
11906
11749
|
var InformationSchemaColumns = defineTable(
|
|
@@ -11918,7 +11761,6 @@ var InformationSchemaColumns = defineTable(
|
|
|
11918
11761
|
ordinal_position: col.int()
|
|
11919
11762
|
},
|
|
11920
11763
|
{},
|
|
11921
|
-
void 0,
|
|
11922
11764
|
{ schema: INFORMATION_SCHEMA }
|
|
11923
11765
|
);
|
|
11924
11766
|
var InformationSchemaKeyColumnUsage = defineTable(
|
|
@@ -11935,7 +11777,6 @@ var InformationSchemaKeyColumnUsage = defineTable(
|
|
|
11935
11777
|
referenced_column_name: col.varchar(255)
|
|
11936
11778
|
},
|
|
11937
11779
|
{},
|
|
11938
|
-
void 0,
|
|
11939
11780
|
{ schema: INFORMATION_SCHEMA }
|
|
11940
11781
|
);
|
|
11941
11782
|
var InformationSchemaReferentialConstraints = defineTable(
|
|
@@ -11947,7 +11788,6 @@ var InformationSchemaReferentialConstraints = defineTable(
|
|
|
11947
11788
|
update_rule: col.varchar(255)
|
|
11948
11789
|
},
|
|
11949
11790
|
{},
|
|
11950
|
-
void 0,
|
|
11951
11791
|
{ schema: INFORMATION_SCHEMA }
|
|
11952
11792
|
);
|
|
11953
11793
|
var InformationSchemaStatistics = defineTable(
|
|
@@ -11961,7 +11801,6 @@ var InformationSchemaStatistics = defineTable(
|
|
|
11961
11801
|
seq_in_index: col.int()
|
|
11962
11802
|
},
|
|
11963
11803
|
{},
|
|
11964
|
-
void 0,
|
|
11965
11804
|
{ schema: INFORMATION_SCHEMA }
|
|
11966
11805
|
);
|
|
11967
11806
|
|
|
@@ -12582,7 +12421,6 @@ var SysColumns = defineTable(
|
|
|
12582
12421
|
user_type_id: col.int()
|
|
12583
12422
|
},
|
|
12584
12423
|
{},
|
|
12585
|
-
void 0,
|
|
12586
12424
|
{ schema: "sys" }
|
|
12587
12425
|
);
|
|
12588
12426
|
var SysTables = defineTable(
|
|
@@ -12594,7 +12432,6 @@ var SysTables = defineTable(
|
|
|
12594
12432
|
is_ms_shipped: col.boolean()
|
|
12595
12433
|
},
|
|
12596
12434
|
{},
|
|
12597
|
-
void 0,
|
|
12598
12435
|
{ schema: "sys" }
|
|
12599
12436
|
);
|
|
12600
12437
|
var SysSchemas = defineTable(
|
|
@@ -12604,7 +12441,6 @@ var SysSchemas = defineTable(
|
|
|
12604
12441
|
name: col.varchar(255)
|
|
12605
12442
|
},
|
|
12606
12443
|
{},
|
|
12607
|
-
void 0,
|
|
12608
12444
|
{ schema: "sys" }
|
|
12609
12445
|
);
|
|
12610
12446
|
var SysTypes = defineTable(
|
|
@@ -12614,7 +12450,6 @@ var SysTypes = defineTable(
|
|
|
12614
12450
|
name: col.varchar(255)
|
|
12615
12451
|
},
|
|
12616
12452
|
{},
|
|
12617
|
-
void 0,
|
|
12618
12453
|
{ schema: "sys" }
|
|
12619
12454
|
);
|
|
12620
12455
|
var SysIndexes = defineTable(
|
|
@@ -12630,7 +12465,6 @@ var SysIndexes = defineTable(
|
|
|
12630
12465
|
is_hypothetical: col.boolean()
|
|
12631
12466
|
},
|
|
12632
12467
|
{},
|
|
12633
|
-
void 0,
|
|
12634
12468
|
{ schema: "sys" }
|
|
12635
12469
|
);
|
|
12636
12470
|
var SysIndexColumns = defineTable(
|
|
@@ -12642,7 +12476,6 @@ var SysIndexColumns = defineTable(
|
|
|
12642
12476
|
key_ordinal: col.int()
|
|
12643
12477
|
},
|
|
12644
12478
|
{},
|
|
12645
|
-
void 0,
|
|
12646
12479
|
{ schema: "sys" }
|
|
12647
12480
|
);
|
|
12648
12481
|
var SysForeignKeys = defineTable(
|
|
@@ -12654,7 +12487,6 @@ var SysForeignKeys = defineTable(
|
|
|
12654
12487
|
update_referential_action_desc: col.varchar(64)
|
|
12655
12488
|
},
|
|
12656
12489
|
{},
|
|
12657
|
-
void 0,
|
|
12658
12490
|
{ schema: "sys" }
|
|
12659
12491
|
);
|
|
12660
12492
|
var SysForeignKeyColumns = defineTable(
|
|
@@ -12668,7 +12500,6 @@ var SysForeignKeyColumns = defineTable(
|
|
|
12668
12500
|
constraint_column_id: col.int()
|
|
12669
12501
|
},
|
|
12670
12502
|
{},
|
|
12671
|
-
void 0,
|
|
12672
12503
|
{ schema: "sys" }
|
|
12673
12504
|
);
|
|
12674
12505
|
|
|
@@ -14093,12 +13924,14 @@ var UnitOfWork = class {
|
|
|
14093
13924
|
* @param executor - The database executor
|
|
14094
13925
|
* @param identityMap - The identity map
|
|
14095
13926
|
* @param hookContext - Function to get the hook context
|
|
13927
|
+
* @param resolveTableHooks - Session/runtime lifecycle hook resolver
|
|
14096
13928
|
*/
|
|
14097
|
-
constructor(dialect, executor, identityMap, hookContext) {
|
|
13929
|
+
constructor(dialect, executor, identityMap, hookContext, resolveTableHooks = () => void 0) {
|
|
14098
13930
|
this.dialect = dialect;
|
|
14099
13931
|
this.executor = executor;
|
|
14100
13932
|
this.identityMap = identityMap;
|
|
14101
13933
|
this.hookContext = hookContext;
|
|
13934
|
+
this.resolveTableHooks = resolveTableHooks;
|
|
14102
13935
|
}
|
|
14103
13936
|
trackedEntities = /* @__PURE__ */ new Map();
|
|
14104
13937
|
/**
|
|
@@ -14250,7 +14083,8 @@ var UnitOfWork = class {
|
|
|
14250
14083
|
* @param tracked - The tracked entity to insert
|
|
14251
14084
|
*/
|
|
14252
14085
|
async flushInsert(tracked) {
|
|
14253
|
-
|
|
14086
|
+
const hooks = this.resolveTableHooks(tracked.table);
|
|
14087
|
+
await this.runHook(hooks?.beforeInsert, tracked);
|
|
14254
14088
|
const payload = this.extractColumns(tracked.table, tracked.entity);
|
|
14255
14089
|
let builder = new InsertQueryBuilder(tracked.table).values(payload);
|
|
14256
14090
|
if (this.dialect.supportsDmlReturningClause()) {
|
|
@@ -14264,7 +14098,7 @@ var UnitOfWork = class {
|
|
|
14264
14098
|
tracked.original = this.createSnapshot(tracked.table, tracked.entity);
|
|
14265
14099
|
tracked.pk = this.getPrimaryKeyValue(tracked);
|
|
14266
14100
|
this.registerIdentity(tracked);
|
|
14267
|
-
await this.runHook(
|
|
14101
|
+
await this.runHook(hooks?.afterInsert, tracked);
|
|
14268
14102
|
}
|
|
14269
14103
|
/**
|
|
14270
14104
|
* Flushes an update operation for a modified entity.
|
|
@@ -14277,7 +14111,8 @@ var UnitOfWork = class {
|
|
|
14277
14111
|
tracked.status = "managed" /* Managed */;
|
|
14278
14112
|
return;
|
|
14279
14113
|
}
|
|
14280
|
-
|
|
14114
|
+
const hooks = this.resolveTableHooks(tracked.table);
|
|
14115
|
+
await this.runHook(hooks?.beforeUpdate, tracked);
|
|
14281
14116
|
const pkColumn = tracked.table.columns[findPrimaryKey(tracked.table)];
|
|
14282
14117
|
if (!pkColumn) return;
|
|
14283
14118
|
let builder = new UpdateQueryBuilder(tracked.table).set(changes).where(eq(pkColumn, tracked.pk));
|
|
@@ -14290,7 +14125,7 @@ var UnitOfWork = class {
|
|
|
14290
14125
|
tracked.status = "managed" /* Managed */;
|
|
14291
14126
|
tracked.original = this.createSnapshot(tracked.table, tracked.entity);
|
|
14292
14127
|
this.registerIdentity(tracked);
|
|
14293
|
-
await this.runHook(
|
|
14128
|
+
await this.runHook(hooks?.afterUpdate, tracked);
|
|
14294
14129
|
}
|
|
14295
14130
|
/**
|
|
14296
14131
|
* Flushes a delete operation for a removed entity.
|
|
@@ -14298,7 +14133,8 @@ var UnitOfWork = class {
|
|
|
14298
14133
|
*/
|
|
14299
14134
|
async flushDelete(tracked) {
|
|
14300
14135
|
if (tracked.pk == null) return;
|
|
14301
|
-
|
|
14136
|
+
const hooks = this.resolveTableHooks(tracked.table);
|
|
14137
|
+
await this.runHook(hooks?.beforeDelete, tracked);
|
|
14302
14138
|
const pkColumn = tracked.table.columns[findPrimaryKey(tracked.table)];
|
|
14303
14139
|
if (!pkColumn) return;
|
|
14304
14140
|
const builder = new DeleteQueryBuilder(tracked.table).where(eq(pkColumn, tracked.pk));
|
|
@@ -14307,10 +14143,10 @@ var UnitOfWork = class {
|
|
|
14307
14143
|
tracked.status = "detached" /* Detached */;
|
|
14308
14144
|
this.trackedEntities.delete(tracked.entity);
|
|
14309
14145
|
this.identityMap.remove(tracked);
|
|
14310
|
-
await this.runHook(
|
|
14146
|
+
await this.runHook(hooks?.afterDelete, tracked);
|
|
14311
14147
|
}
|
|
14312
14148
|
/**
|
|
14313
|
-
* Runs a
|
|
14149
|
+
* Runs a lifecycle hook if defined.
|
|
14314
14150
|
* @param hook - The hook function
|
|
14315
14151
|
* @param tracked - The tracked entity
|
|
14316
14152
|
*/
|
|
@@ -15215,6 +15051,7 @@ var OrmSession = class {
|
|
|
15215
15051
|
/** The tenant ID for multi-tenancy support */
|
|
15216
15052
|
tenantId;
|
|
15217
15053
|
interceptors;
|
|
15054
|
+
tableHooks = /* @__PURE__ */ new WeakMap();
|
|
15218
15055
|
saveGraphDefaults;
|
|
15219
15056
|
transactionDepth = 0;
|
|
15220
15057
|
savepointCounter = 0;
|
|
@@ -15228,7 +15065,13 @@ var OrmSession = class {
|
|
|
15228
15065
|
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
15229
15066
|
this.interceptors = [...opts.interceptors ?? []];
|
|
15230
15067
|
this.identityMap = new IdentityMap();
|
|
15231
|
-
this.unitOfWork = new UnitOfWork(
|
|
15068
|
+
this.unitOfWork = new UnitOfWork(
|
|
15069
|
+
this.orm.dialect,
|
|
15070
|
+
this.executor,
|
|
15071
|
+
this.identityMap,
|
|
15072
|
+
() => this,
|
|
15073
|
+
(table) => this.tableHooks.get(table)
|
|
15074
|
+
);
|
|
15232
15075
|
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
15233
15076
|
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
15234
15077
|
this.cacheManager = opts.cacheManager;
|
|
@@ -15336,6 +15179,18 @@ var OrmSession = class {
|
|
|
15336
15179
|
getEntitiesForTable(table) {
|
|
15337
15180
|
return this.unitOfWork.getEntitiesForTable(table);
|
|
15338
15181
|
}
|
|
15182
|
+
/**
|
|
15183
|
+
* Registers INSERT/UPDATE/DELETE lifecycle hooks for this Session only.
|
|
15184
|
+
* The target can be a TableDef or a decorated entity constructor.
|
|
15185
|
+
* Registering again for the same table replaces the previous hook set.
|
|
15186
|
+
*/
|
|
15187
|
+
registerTableHooks(target, hooks) {
|
|
15188
|
+
const table = typeof target === "function" ? getTableDefFromEntity(target) : target;
|
|
15189
|
+
if (!table) {
|
|
15190
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
15191
|
+
}
|
|
15192
|
+
this.tableHooks.set(table, hooks);
|
|
15193
|
+
}
|
|
15339
15194
|
/**
|
|
15340
15195
|
* Registers an interceptor for flush lifecycle hooks.
|
|
15341
15196
|
* @param interceptor - The interceptor to register
|
|
@@ -15346,7 +15201,7 @@ var OrmSession = class {
|
|
|
15346
15201
|
/**
|
|
15347
15202
|
* Registers a domain event handler.
|
|
15348
15203
|
* @param type - The event type
|
|
15349
|
-
* @param handler - The event handler
|
|
15204
|
+
* @param handler - The domain event handler
|
|
15350
15205
|
*/
|
|
15351
15206
|
registerDomainEventHandler(type, handler) {
|
|
15352
15207
|
this.domainEvents.on(type, handler);
|
|
@@ -15520,7 +15375,9 @@ var OrmSession = class {
|
|
|
15520
15375
|
this.markRemoved(entity);
|
|
15521
15376
|
}
|
|
15522
15377
|
/**
|
|
15523
|
-
* Flushes pending changes to the database without session
|
|
15378
|
+
* Flushes pending changes to the database without session interceptors,
|
|
15379
|
+
* relation processing, or domain events. Table lifecycle hooks still run
|
|
15380
|
+
* because they are part of the Unit of Work.
|
|
15524
15381
|
*/
|
|
15525
15382
|
async flush() {
|
|
15526
15383
|
await this.unitOfWork.flush();
|
|
@@ -16415,7 +16272,7 @@ function Entity(options = {}) {
|
|
|
16415
16272
|
return function(value, context) {
|
|
16416
16273
|
const ctor = value;
|
|
16417
16274
|
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
16418
|
-
setEntityTableName(ctor, tableName, options.
|
|
16275
|
+
setEntityTableName(ctor, tableName, options.type);
|
|
16419
16276
|
const bag = context ? readMetadataBag(context) : readMetadataBagFromConstructor(ctor);
|
|
16420
16277
|
if (bag) {
|
|
16421
16278
|
const meta = ensureEntityMetadata(ctor);
|
|
@@ -20635,7 +20492,7 @@ var TreeManager = class _TreeManager {
|
|
|
20635
20492
|
* Moves a node to be the last child of a new parent.
|
|
20636
20493
|
*/
|
|
20637
20494
|
async moveTo(node, newParentId) {
|
|
20638
|
-
NestedSetStrategy.subtreeWidth(node.lft, node.rght);
|
|
20495
|
+
const width = NestedSetStrategy.subtreeWidth(node.lft, node.rght);
|
|
20639
20496
|
let newPos;
|
|
20640
20497
|
if (newParentId === null) {
|
|
20641
20498
|
const maxRght = await this.getMaxRght();
|
|
@@ -20650,7 +20507,8 @@ var TreeManager = class _TreeManager {
|
|
|
20650
20507
|
newParent.depth ?? await this.getLevel(newParent)
|
|
20651
20508
|
);
|
|
20652
20509
|
}
|
|
20653
|
-
|
|
20510
|
+
const targetLft = newPos.lft > node.rght ? newPos.lft - width : newPos.lft;
|
|
20511
|
+
await this.moveSubtree(node, targetLft, newParentId, newPos.depth);
|
|
20654
20512
|
}
|
|
20655
20513
|
/**
|
|
20656
20514
|
* Inserts a new node as a child of a parent.
|
|
@@ -20689,7 +20547,10 @@ var TreeManager = class _TreeManager {
|
|
|
20689
20547
|
if (insertData[this.pkName] !== void 0) {
|
|
20690
20548
|
return insertData[this.pkName];
|
|
20691
20549
|
}
|
|
20692
|
-
const
|
|
20550
|
+
const scopeExpressions = this.getScopeExpressions();
|
|
20551
|
+
const lftCondition = eq(this.table.columns[this.config.leftKey], insertPos.lft);
|
|
20552
|
+
const findCondition = scopeExpressions.length > 0 ? and(lftCondition, ...scopeExpressions) : lftCondition;
|
|
20553
|
+
const findQuery = selectFrom(this.table).where(findCondition);
|
|
20693
20554
|
const { sql: findSql, params: findParams } = findQuery.compile(this.dialect);
|
|
20694
20555
|
const results = await this.executor.executeSql(findSql, findParams);
|
|
20695
20556
|
const rows = queryResultsToRows(results);
|
|
@@ -20699,23 +20560,37 @@ var TreeManager = class _TreeManager {
|
|
|
20699
20560
|
return void 0;
|
|
20700
20561
|
}
|
|
20701
20562
|
/**
|
|
20702
|
-
* Removes a node
|
|
20563
|
+
* Removes a node from its current tree position, promotes its direct children
|
|
20564
|
+
* to the removed node's parent, and retains the removed row as a standalone root.
|
|
20703
20565
|
*/
|
|
20704
20566
|
async removeFromTree(node) {
|
|
20705
20567
|
const nodeId = node.data[this.pkName];
|
|
20568
|
+
const originalMaxRght = await this.getMaxRght();
|
|
20706
20569
|
await this.executeUpdate(
|
|
20707
20570
|
eq(this.table.columns[this.config.parentKey], nodeId),
|
|
20708
20571
|
{ [this.config.parentKey]: node.parentId }
|
|
20709
20572
|
);
|
|
20710
|
-
|
|
20573
|
+
if (node.rght - node.lft > 1) {
|
|
20574
|
+
let sql = `UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} - 1, ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} - 1`;
|
|
20575
|
+
if (this.config.depthKey) {
|
|
20576
|
+
sql += `, ${this.quoteCol(this.config.depthKey)} = ${this.quoteCol(this.config.depthKey)} - 1`;
|
|
20577
|
+
}
|
|
20578
|
+
sql += ` WHERE ${this.quoteCol(this.config.leftKey)} > ? AND ${this.quoteCol(this.config.rightKey)} < ?`;
|
|
20579
|
+
await this.executeRawUpdate(sql, [node.lft, node.rght]);
|
|
20580
|
+
}
|
|
20711
20581
|
await this.shiftForDelete(node.rght, 2);
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
|
|
20582
|
+
const detachedData = {
|
|
20583
|
+
[this.config.parentKey]: null,
|
|
20584
|
+
[this.config.leftKey]: originalMaxRght - 1,
|
|
20585
|
+
[this.config.rightKey]: originalMaxRght
|
|
20586
|
+
};
|
|
20587
|
+
if (this.config.depthKey) {
|
|
20588
|
+
detachedData[this.config.depthKey] = 0;
|
|
20718
20589
|
}
|
|
20590
|
+
await this.executeUpdate(
|
|
20591
|
+
eq(this.table.columns[this.pkName], nodeId),
|
|
20592
|
+
detachedData
|
|
20593
|
+
);
|
|
20719
20594
|
}
|
|
20720
20595
|
/**
|
|
20721
20596
|
* Deletes a node and all its descendants.
|
|
@@ -20840,22 +20715,32 @@ var TreeManager = class _TreeManager {
|
|
|
20840
20715
|
}
|
|
20841
20716
|
return "id";
|
|
20842
20717
|
}
|
|
20718
|
+
getScopeEntries() {
|
|
20719
|
+
return Object.entries(buildScopeConditions(this.config.scope, this.scopeValues));
|
|
20720
|
+
}
|
|
20721
|
+
getScopeExpressions() {
|
|
20722
|
+
return this.getScopeEntries().map(
|
|
20723
|
+
([key, value]) => eq(this.table.columns[key], value)
|
|
20724
|
+
);
|
|
20725
|
+
}
|
|
20843
20726
|
async getMaxRght() {
|
|
20844
20727
|
const query = selectFrom(this.table).selectRaw(`MAX(${this.config.rightKey}) as max_rght`);
|
|
20845
|
-
const
|
|
20728
|
+
const scopeExpressions = this.getScopeExpressions();
|
|
20729
|
+
const finalQuery = scopeExpressions.length > 0 ? query.where(and(...scopeExpressions)) : query;
|
|
20730
|
+
const { sql, params } = finalQuery.compile(this.dialect);
|
|
20846
20731
|
const queryResults = await this.executor.executeSql(sql, params);
|
|
20847
20732
|
const rows = queryResultsToRows(queryResults);
|
|
20848
20733
|
const maxRght = rows[0]?.max_rght;
|
|
20849
20734
|
return typeof maxRght === "number" ? maxRght : 0;
|
|
20850
20735
|
}
|
|
20851
|
-
async shiftForInsert(insertPoint) {
|
|
20736
|
+
async shiftForInsert(insertPoint, width = 2) {
|
|
20852
20737
|
await this.executeRawUpdate(
|
|
20853
|
-
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} +
|
|
20854
|
-
[insertPoint]
|
|
20738
|
+
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ? WHERE ${this.quoteCol(this.config.rightKey)} >= ?`,
|
|
20739
|
+
[width, insertPoint]
|
|
20855
20740
|
);
|
|
20856
20741
|
await this.executeRawUpdate(
|
|
20857
|
-
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} +
|
|
20858
|
-
[insertPoint]
|
|
20742
|
+
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} + ? WHERE ${this.quoteCol(this.config.leftKey)} > ?`,
|
|
20743
|
+
[width, insertPoint]
|
|
20859
20744
|
);
|
|
20860
20745
|
}
|
|
20861
20746
|
async shiftForDelete(deletedRght, width) {
|
|
@@ -20891,28 +20776,27 @@ var TreeManager = class _TreeManager {
|
|
|
20891
20776
|
}
|
|
20892
20777
|
async moveSubtree(node, newLft, newParentId, newDepth) {
|
|
20893
20778
|
const width = NestedSetStrategy.subtreeWidth(node.lft, node.rght);
|
|
20894
|
-
const
|
|
20895
|
-
const depthDelta = this.config.depthKey ? newDepth -
|
|
20779
|
+
const oldDepth = this.config.depthKey ? node.depth ?? await this.getLevel(node) : 0;
|
|
20780
|
+
const depthDelta = this.config.depthKey ? newDepth - oldDepth : 0;
|
|
20896
20781
|
const nodeId = node.data[this.pkName];
|
|
20897
|
-
const
|
|
20898
|
-
|
|
20899
|
-
|
|
20900
|
-
[tempOffset, node.lft, node.rght]
|
|
20901
|
-
);
|
|
20782
|
+
const isolateDelta = -1e7 - node.rght;
|
|
20783
|
+
const isolatedLft = node.lft + isolateDelta;
|
|
20784
|
+
const isolatedRght = node.rght + isolateDelta;
|
|
20902
20785
|
await this.executeRawUpdate(
|
|
20903
|
-
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ? WHERE ${this.quoteCol(this.config.leftKey)} >= ? AND ${this.quoteCol(this.config.rightKey)} <= ?`,
|
|
20904
|
-
[
|
|
20786
|
+
`UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} + ?, ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ? WHERE ${this.quoteCol(this.config.leftKey)} >= ? AND ${this.quoteCol(this.config.rightKey)} <= ?`,
|
|
20787
|
+
[isolateDelta, isolateDelta, node.lft, node.rght]
|
|
20905
20788
|
);
|
|
20906
20789
|
await this.shiftForDelete(node.rght, width);
|
|
20907
|
-
await this.shiftForInsert(newLft);
|
|
20908
|
-
|
|
20909
|
-
|
|
20790
|
+
await this.shiftForInsert(newLft, width);
|
|
20791
|
+
const restoreDelta = newLft - node.lft - isolateDelta;
|
|
20792
|
+
let updateSql = `UPDATE ${this.quoteTable()} SET ${this.quoteCol(this.config.leftKey)} = ${this.quoteCol(this.config.leftKey)} + ?, ${this.quoteCol(this.config.rightKey)} = ${this.quoteCol(this.config.rightKey)} + ?`;
|
|
20793
|
+
const updateParams = [restoreDelta, restoreDelta];
|
|
20910
20794
|
if (this.config.depthKey && depthDelta !== 0) {
|
|
20911
20795
|
updateSql += `, ${this.quoteCol(this.config.depthKey)} = ${this.quoteCol(this.config.depthKey)} + ?`;
|
|
20912
20796
|
updateParams.push(depthDelta);
|
|
20913
20797
|
}
|
|
20914
|
-
updateSql += ` WHERE ${this.quoteCol(this.config.leftKey)} >= ?`;
|
|
20915
|
-
updateParams.push(
|
|
20798
|
+
updateSql += ` WHERE ${this.quoteCol(this.config.leftKey)} >= ? AND ${this.quoteCol(this.config.rightKey)} <= ?`;
|
|
20799
|
+
updateParams.push(isolatedLft, isolatedRght);
|
|
20916
20800
|
await this.executeRawUpdate(updateSql, updateParams);
|
|
20917
20801
|
await this.executeUpdate(
|
|
20918
20802
|
eq(this.table.columns[this.pkName], nodeId),
|
|
@@ -20937,12 +20821,23 @@ var TreeManager = class _TreeManager {
|
|
|
20937
20821
|
}));
|
|
20938
20822
|
}
|
|
20939
20823
|
async executeUpdate(condition, data) {
|
|
20940
|
-
const
|
|
20824
|
+
const scopeExpressions = this.getScopeExpressions();
|
|
20825
|
+
const finalCondition = scopeExpressions.length > 0 ? and(condition, ...scopeExpressions) : condition;
|
|
20826
|
+
const query = update(this.table).set(data).where(finalCondition);
|
|
20941
20827
|
const { sql, params } = query.compile(this.dialect);
|
|
20942
20828
|
await this.executor.executeSql(sql, params);
|
|
20943
20829
|
}
|
|
20944
20830
|
async executeRawUpdate(sql, params) {
|
|
20945
|
-
|
|
20831
|
+
let scopedSql = sql;
|
|
20832
|
+
const scopedParams = [...params];
|
|
20833
|
+
let hasWhere = /\bWHERE\b/i.test(scopedSql);
|
|
20834
|
+
for (const [key, value] of this.getScopeEntries()) {
|
|
20835
|
+
scopedSql += hasWhere ? " AND " : " WHERE ";
|
|
20836
|
+
scopedSql += `${this.quoteCol(key)} = ?`;
|
|
20837
|
+
scopedParams.push(value);
|
|
20838
|
+
hasWhere = true;
|
|
20839
|
+
}
|
|
20840
|
+
await this.executor.executeSql(scopedSql, scopedParams);
|
|
20946
20841
|
}
|
|
20947
20842
|
quoteTable() {
|
|
20948
20843
|
const quote = this.getQuoteChar();
|
|
@@ -21745,6 +21640,8 @@ export {
|
|
|
21745
21640
|
DefaultMorphToReference,
|
|
21746
21641
|
DefaultTypeStrategy,
|
|
21747
21642
|
DeleteQueryBuilder,
|
|
21643
|
+
DialectBase,
|
|
21644
|
+
DialectFactory,
|
|
21748
21645
|
DomainEventBus,
|
|
21749
21646
|
Email,
|
|
21750
21647
|
Entity,
|
|
@@ -21972,6 +21869,7 @@ export {
|
|
|
21972
21869
|
isNull,
|
|
21973
21870
|
isNullableColumn,
|
|
21974
21871
|
isOperandNode,
|
|
21872
|
+
isProcedureCompiler,
|
|
21975
21873
|
isSingleTargetRelation,
|
|
21976
21874
|
isTableDef2 as isTableDef,
|
|
21977
21875
|
isTreeConfig,
|
|
@@ -22069,6 +21967,8 @@ export {
|
|
|
22069
21967
|
repeat,
|
|
22070
21968
|
replace,
|
|
22071
21969
|
replaceWithRefs,
|
|
21970
|
+
requireProcedureCompiler,
|
|
21971
|
+
resolveDialectInput,
|
|
22072
21972
|
resolveTreeConfig,
|
|
22073
21973
|
resolveValidator,
|
|
22074
21974
|
responseToRef,
|