metal-orm 1.0.40 → 1.0.42
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/README.md +53 -14
- package/dist/index.cjs +1298 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +676 -30
- package/dist/index.d.ts +676 -30
- package/dist/index.js +1293 -126
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen/typescript.ts +6 -2
- package/src/core/ast/expression-builders.ts +25 -4
- package/src/core/ast/expression-nodes.ts +3 -1
- package/src/core/ast/expression.ts +2 -2
- package/src/core/ast/query.ts +24 -2
- package/src/core/dialect/abstract.ts +6 -2
- package/src/core/dialect/base/join-compiler.ts +9 -12
- package/src/core/dialect/base/sql-dialect.ts +98 -17
- package/src/core/dialect/mssql/index.ts +30 -62
- package/src/core/dialect/sqlite/index.ts +39 -34
- package/src/core/execution/db-executor.ts +46 -6
- package/src/core/execution/executors/mssql-executor.ts +39 -22
- package/src/core/execution/executors/mysql-executor.ts +23 -6
- package/src/core/execution/executors/sqlite-executor.ts +29 -3
- package/src/core/execution/pooling/pool-types.ts +30 -0
- package/src/core/execution/pooling/pool.ts +268 -0
- package/src/decorators/bootstrap.ts +7 -7
- package/src/index.ts +6 -0
- package/src/orm/domain-event-bus.ts +49 -0
- package/src/orm/entity-metadata.ts +9 -9
- package/src/orm/entity.ts +58 -0
- package/src/orm/orm-session.ts +465 -270
- package/src/orm/orm.ts +61 -11
- package/src/orm/pooled-executor-factory.ts +131 -0
- package/src/orm/query-logger.ts +6 -12
- package/src/orm/relation-change-processor.ts +75 -0
- package/src/orm/relations/many-to-many.ts +4 -2
- package/src/orm/save-graph.ts +303 -0
- package/src/orm/transaction-runner.ts +3 -3
- package/src/orm/unit-of-work.ts +128 -0
- package/src/query-builder/delete-query-state.ts +67 -38
- package/src/query-builder/delete.ts +37 -1
- package/src/query-builder/insert-query-state.ts +131 -61
- package/src/query-builder/insert.ts +27 -1
- package/src/query-builder/update-query-state.ts +114 -77
- package/src/query-builder/update.ts +38 -1
- package/src/schema/table.ts +210 -115
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(index_exports, {
|
|
|
60
60
|
MySqlDialect: () => MySqlDialect,
|
|
61
61
|
Orm: () => Orm,
|
|
62
62
|
OrmSession: () => OrmSession,
|
|
63
|
+
Pool: () => Pool,
|
|
63
64
|
PostgresDialect: () => PostgresDialect,
|
|
64
65
|
PrimaryKey: () => PrimaryKey,
|
|
65
66
|
RelationKinds: () => RelationKinds,
|
|
@@ -105,6 +106,7 @@ __export(index_exports, {
|
|
|
105
106
|
createLiteral: () => createLiteral,
|
|
106
107
|
createMssqlExecutor: () => createMssqlExecutor,
|
|
107
108
|
createMysqlExecutor: () => createMysqlExecutor,
|
|
109
|
+
createPooledExecutorFactory: () => createPooledExecutorFactory,
|
|
108
110
|
createPostgresExecutor: () => createPostgresExecutor,
|
|
109
111
|
createQueryLoggingExecutor: () => createQueryLoggingExecutor,
|
|
110
112
|
createSqliteExecutor: () => createSqliteExecutor,
|
|
@@ -146,6 +148,7 @@ __export(index_exports, {
|
|
|
146
148
|
hasOne: () => hasOne,
|
|
147
149
|
hydrateRows: () => hydrateRows,
|
|
148
150
|
inList: () => inList,
|
|
151
|
+
inSubquery: () => inSubquery,
|
|
149
152
|
instr: () => instr,
|
|
150
153
|
introspectSchema: () => introspectSchema,
|
|
151
154
|
isCaseExpressionNode: () => isCaseExpressionNode,
|
|
@@ -186,6 +189,7 @@ __export(index_exports, {
|
|
|
186
189
|
notBetween: () => notBetween,
|
|
187
190
|
notExists: () => notExists,
|
|
188
191
|
notInList: () => notInList,
|
|
192
|
+
notInSubquery: () => notInSubquery,
|
|
189
193
|
notLike: () => notLike,
|
|
190
194
|
now: () => now,
|
|
191
195
|
ntile: () => ntile,
|
|
@@ -221,6 +225,7 @@ __export(index_exports, {
|
|
|
221
225
|
substr: () => substr,
|
|
222
226
|
sum: () => sum,
|
|
223
227
|
synchronizeSchema: () => synchronizeSchema,
|
|
228
|
+
tableRef: () => tableRef,
|
|
224
229
|
tan: () => tan,
|
|
225
230
|
toColumnRef: () => toColumnRef,
|
|
226
231
|
toTableRef: () => toTableRef,
|
|
@@ -260,6 +265,54 @@ var defineTable = (name, columns, relations = {}, hooks, options = {}) => {
|
|
|
260
265
|
collation: options.collation
|
|
261
266
|
};
|
|
262
267
|
};
|
|
268
|
+
var TABLE_REF_CACHE = /* @__PURE__ */ new WeakMap();
|
|
269
|
+
var withColumnProps = (table) => {
|
|
270
|
+
const cached = TABLE_REF_CACHE.get(table);
|
|
271
|
+
if (cached) return cached;
|
|
272
|
+
const proxy = new Proxy(table, {
|
|
273
|
+
get(target, prop, receiver) {
|
|
274
|
+
if (prop === "$") return target.columns;
|
|
275
|
+
if (Reflect.has(target, prop)) return Reflect.get(target, prop, receiver);
|
|
276
|
+
if (typeof prop === "string" && prop in target.columns) return target.columns[prop];
|
|
277
|
+
return void 0;
|
|
278
|
+
},
|
|
279
|
+
has(target, prop) {
|
|
280
|
+
return prop === "$" || Reflect.has(target, prop) || typeof prop === "string" && prop in target.columns;
|
|
281
|
+
},
|
|
282
|
+
ownKeys(target) {
|
|
283
|
+
const base = Reflect.ownKeys(target);
|
|
284
|
+
const cols = Object.keys(target.columns);
|
|
285
|
+
for (const k of cols) {
|
|
286
|
+
if (!base.includes(k)) base.push(k);
|
|
287
|
+
}
|
|
288
|
+
if (!base.includes("$")) base.push("$");
|
|
289
|
+
return base;
|
|
290
|
+
},
|
|
291
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
292
|
+
if (prop === "$") {
|
|
293
|
+
return {
|
|
294
|
+
configurable: true,
|
|
295
|
+
enumerable: false,
|
|
296
|
+
get() {
|
|
297
|
+
return target.columns;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (typeof prop === "string" && prop in target.columns && !Reflect.has(target, prop)) {
|
|
302
|
+
return {
|
|
303
|
+
configurable: true,
|
|
304
|
+
enumerable: true,
|
|
305
|
+
value: target.columns[prop],
|
|
306
|
+
writable: false
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
TABLE_REF_CACHE.set(table, proxy);
|
|
313
|
+
return proxy;
|
|
314
|
+
};
|
|
315
|
+
var tableRef = (table) => withColumnProps(table);
|
|
263
316
|
|
|
264
317
|
// src/schema/column.ts
|
|
265
318
|
var col = {
|
|
@@ -497,6 +550,12 @@ var toOperand = (val) => {
|
|
|
497
550
|
}
|
|
498
551
|
return toNode(val);
|
|
499
552
|
};
|
|
553
|
+
var hasQueryAst = (value) => typeof value.getAST === "function";
|
|
554
|
+
var resolveSelectQueryNode = (query) => hasQueryAst(query) ? query.getAST() : query;
|
|
555
|
+
var toScalarSubqueryNode = (query) => ({
|
|
556
|
+
type: "ScalarSubquery",
|
|
557
|
+
query: resolveSelectQueryNode(query)
|
|
558
|
+
});
|
|
500
559
|
var columnOperand = (col2) => toNode(col2);
|
|
501
560
|
var outerRef = (col2) => ({
|
|
502
561
|
...columnOperand(col2),
|
|
@@ -547,14 +606,16 @@ var isNotNull = (left2) => ({
|
|
|
547
606
|
left: toNode(left2),
|
|
548
607
|
operator: "IS NOT NULL"
|
|
549
608
|
});
|
|
550
|
-
var createInExpression = (operator, left2,
|
|
609
|
+
var createInExpression = (operator, left2, right2) => ({
|
|
551
610
|
type: "InExpression",
|
|
552
611
|
left: toNode(left2),
|
|
553
612
|
operator,
|
|
554
|
-
right:
|
|
613
|
+
right: right2
|
|
555
614
|
});
|
|
556
|
-
var inList = (left2, values) => createInExpression("IN", left2, values);
|
|
557
|
-
var notInList = (left2, values) => createInExpression("NOT IN", left2, values);
|
|
615
|
+
var inList = (left2, values) => createInExpression("IN", left2, values.map((v) => toOperand(v)));
|
|
616
|
+
var notInList = (left2, values) => createInExpression("NOT IN", left2, values.map((v) => toOperand(v)));
|
|
617
|
+
var inSubquery = (left2, subquery) => createInExpression("IN", left2, toScalarSubqueryNode(subquery));
|
|
618
|
+
var notInSubquery = (left2, subquery) => createInExpression("NOT IN", left2, toScalarSubqueryNode(subquery));
|
|
558
619
|
var createBetweenExpression = (operator, left2, lower2, upper2) => ({
|
|
559
620
|
type: "BetweenExpression",
|
|
560
621
|
left: toNode(left2),
|
|
@@ -1237,8 +1298,12 @@ var Dialect = class _Dialect {
|
|
|
1237
1298
|
});
|
|
1238
1299
|
this.registerExpressionCompiler("InExpression", (inExpr, ctx) => {
|
|
1239
1300
|
const left2 = this.compileOperand(inExpr.left, ctx);
|
|
1240
|
-
|
|
1241
|
-
|
|
1301
|
+
if (Array.isArray(inExpr.right)) {
|
|
1302
|
+
const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
|
|
1303
|
+
return `${left2} ${inExpr.operator} (${values})`;
|
|
1304
|
+
}
|
|
1305
|
+
const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
|
|
1306
|
+
return `${left2} ${inExpr.operator} (${subquerySql})`;
|
|
1242
1307
|
});
|
|
1243
1308
|
this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
|
|
1244
1309
|
const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
|
|
@@ -1496,17 +1561,9 @@ var NoReturningStrategy = class {
|
|
|
1496
1561
|
|
|
1497
1562
|
// src/core/dialect/base/join-compiler.ts
|
|
1498
1563
|
var JoinCompiler = class {
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
* @param ctx - The compiler context for expression compilation.
|
|
1503
|
-
* @param compileFrom - Function to compile table sources (tables or subqueries).
|
|
1504
|
-
* @param compileExpression - Function to compile join condition expressions.
|
|
1505
|
-
* @returns SQL JOIN clauses (e.g., " LEFT JOIN table ON condition") or empty string if no joins.
|
|
1506
|
-
*/
|
|
1507
|
-
static compileJoins(ast, ctx, compileFrom, compileExpression) {
|
|
1508
|
-
if (!ast.joins || ast.joins.length === 0) return "";
|
|
1509
|
-
const parts = ast.joins.map((j) => {
|
|
1564
|
+
static compileJoins(joins, ctx, compileFrom, compileExpression) {
|
|
1565
|
+
if (!joins || joins.length === 0) return "";
|
|
1566
|
+
const parts = joins.map((j) => {
|
|
1510
1567
|
const table = compileFrom(j.table, ctx);
|
|
1511
1568
|
const cond = compileExpression(j.condition, ctx);
|
|
1512
1569
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
@@ -1589,25 +1646,41 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1589
1646
|
return `${ctes}${combined}${orderBy}${pagination}`;
|
|
1590
1647
|
}
|
|
1591
1648
|
compileInsertAst(ast, ctx) {
|
|
1649
|
+
if (!ast.columns.length) {
|
|
1650
|
+
throw new Error("INSERT queries must specify columns.");
|
|
1651
|
+
}
|
|
1592
1652
|
const table = this.compileTableName(ast.into);
|
|
1593
1653
|
const columnList = this.compileInsertColumnList(ast.columns);
|
|
1594
|
-
const
|
|
1654
|
+
const source = this.compileInsertSource(ast.source, ctx);
|
|
1595
1655
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
1596
|
-
return `INSERT INTO ${table} (${columnList})
|
|
1656
|
+
return `INSERT INTO ${table} (${columnList}) ${source}${returning}`;
|
|
1597
1657
|
}
|
|
1598
1658
|
compileReturning(returning, ctx) {
|
|
1599
1659
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
1600
1660
|
}
|
|
1661
|
+
compileInsertSource(source, ctx) {
|
|
1662
|
+
if (source.type === "InsertValues") {
|
|
1663
|
+
if (!source.rows.length) {
|
|
1664
|
+
throw new Error("INSERT ... VALUES requires at least one row.");
|
|
1665
|
+
}
|
|
1666
|
+
const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
1667
|
+
return `VALUES ${values}`;
|
|
1668
|
+
}
|
|
1669
|
+
const normalized = this.normalizeSelectAst(source.query);
|
|
1670
|
+
return this.compileSelectAst(normalized, ctx).trim();
|
|
1671
|
+
}
|
|
1601
1672
|
compileInsertColumnList(columns) {
|
|
1602
1673
|
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
1603
1674
|
}
|
|
1604
|
-
compileInsertValues(values, ctx) {
|
|
1605
|
-
return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
1606
|
-
}
|
|
1607
1675
|
compileSelectCore(ast, ctx) {
|
|
1608
1676
|
const columns = this.compileSelectColumns(ast, ctx);
|
|
1609
1677
|
const from = this.compileFrom(ast.from, ctx);
|
|
1610
|
-
const joins = JoinCompiler.compileJoins(
|
|
1678
|
+
const joins = JoinCompiler.compileJoins(
|
|
1679
|
+
ast.joins,
|
|
1680
|
+
ctx,
|
|
1681
|
+
this.compileFrom.bind(this),
|
|
1682
|
+
this.compileExpression.bind(this)
|
|
1683
|
+
);
|
|
1611
1684
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1612
1685
|
const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
|
|
1613
1686
|
const having = this.compileHaving(ast, ctx);
|
|
@@ -1621,25 +1694,37 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1621
1694
|
return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
|
|
1622
1695
|
}
|
|
1623
1696
|
compileUpdateAst(ast, ctx) {
|
|
1624
|
-
const
|
|
1625
|
-
const assignments = this.compileUpdateAssignments(ast.set, ctx);
|
|
1697
|
+
const target = this.compileTableReference(ast.table);
|
|
1698
|
+
const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
|
|
1699
|
+
const fromClause = this.compileUpdateFromClause(ast, ctx);
|
|
1626
1700
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1627
1701
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
1628
|
-
return `UPDATE ${
|
|
1702
|
+
return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
|
|
1629
1703
|
}
|
|
1630
|
-
compileUpdateAssignments(assignments, ctx) {
|
|
1704
|
+
compileUpdateAssignments(assignments, table, ctx) {
|
|
1631
1705
|
return assignments.map((assignment) => {
|
|
1632
1706
|
const col2 = assignment.column;
|
|
1633
|
-
const target = this.
|
|
1707
|
+
const target = this.compileQualifiedColumn(col2, table);
|
|
1634
1708
|
const value = this.compileOperand(assignment.value, ctx);
|
|
1635
1709
|
return `${target} = ${value}`;
|
|
1636
1710
|
}).join(", ");
|
|
1637
1711
|
}
|
|
1712
|
+
compileQualifiedColumn(column, table) {
|
|
1713
|
+
const baseTableName = table.name;
|
|
1714
|
+
const alias = table.alias;
|
|
1715
|
+
const columnTable = column.table ?? alias ?? baseTableName;
|
|
1716
|
+
const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
|
|
1717
|
+
if (!tableQualifier) {
|
|
1718
|
+
return this.quoteIdentifier(column.name);
|
|
1719
|
+
}
|
|
1720
|
+
return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
|
|
1721
|
+
}
|
|
1638
1722
|
compileDeleteAst(ast, ctx) {
|
|
1639
|
-
const
|
|
1723
|
+
const target = this.compileTableReference(ast.from);
|
|
1724
|
+
const usingClause = this.compileDeleteUsingClause(ast, ctx);
|
|
1640
1725
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1641
1726
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
1642
|
-
return `DELETE FROM ${
|
|
1727
|
+
return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
|
|
1643
1728
|
}
|
|
1644
1729
|
formatReturningColumns(returning) {
|
|
1645
1730
|
return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
|
|
@@ -1694,6 +1779,38 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1694
1779
|
}
|
|
1695
1780
|
return this.quoteIdentifier(table.name);
|
|
1696
1781
|
}
|
|
1782
|
+
compileTableReference(table) {
|
|
1783
|
+
const base = this.compileTableName(table);
|
|
1784
|
+
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
1785
|
+
}
|
|
1786
|
+
compileUpdateFromClause(ast, ctx) {
|
|
1787
|
+
if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
|
|
1788
|
+
if (!ast.from) {
|
|
1789
|
+
throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
|
|
1790
|
+
}
|
|
1791
|
+
const from = this.compileFrom(ast.from, ctx);
|
|
1792
|
+
const joins = JoinCompiler.compileJoins(
|
|
1793
|
+
ast.joins,
|
|
1794
|
+
ctx,
|
|
1795
|
+
this.compileFrom.bind(this),
|
|
1796
|
+
this.compileExpression.bind(this)
|
|
1797
|
+
);
|
|
1798
|
+
return ` FROM ${from}${joins}`;
|
|
1799
|
+
}
|
|
1800
|
+
compileDeleteUsingClause(ast, ctx) {
|
|
1801
|
+
if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
|
|
1802
|
+
if (!ast.using) {
|
|
1803
|
+
throw new Error("DELETE with JOINs requires a USING clause.");
|
|
1804
|
+
}
|
|
1805
|
+
const usingTable = this.compileFrom(ast.using, ctx);
|
|
1806
|
+
const joins = JoinCompiler.compileJoins(
|
|
1807
|
+
ast.joins,
|
|
1808
|
+
ctx,
|
|
1809
|
+
this.compileFrom.bind(this),
|
|
1810
|
+
this.compileExpression.bind(this)
|
|
1811
|
+
);
|
|
1812
|
+
return ` USING ${usingTable}${joins}`;
|
|
1813
|
+
}
|
|
1697
1814
|
compileHaving(ast, ctx) {
|
|
1698
1815
|
if (!ast.having) return "";
|
|
1699
1816
|
return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
|
|
@@ -2074,6 +2191,9 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
2074
2191
|
const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
2075
2192
|
return `json_extract(${col2}, '${node.path}')`;
|
|
2076
2193
|
}
|
|
2194
|
+
compileQualifiedColumn(column, _table) {
|
|
2195
|
+
return this.quoteIdentifier(column.name);
|
|
2196
|
+
}
|
|
2077
2197
|
compileReturning(returning, ctx) {
|
|
2078
2198
|
if (!returning || returning.length === 0) return "";
|
|
2079
2199
|
const columns = this.formatReturningColumns(returning);
|
|
@@ -2179,7 +2299,7 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2179
2299
|
};
|
|
2180
2300
|
|
|
2181
2301
|
// src/core/dialect/mssql/index.ts
|
|
2182
|
-
var SqlServerDialect = class extends
|
|
2302
|
+
var SqlServerDialect = class extends SqlDialectBase {
|
|
2183
2303
|
/**
|
|
2184
2304
|
* Creates a new SqlServerDialect instance
|
|
2185
2305
|
*/
|
|
@@ -2222,7 +2342,7 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2222
2342
|
const hasSetOps = !!(ast.setOps && ast.setOps.length);
|
|
2223
2343
|
const ctes = this.compileCtes(ast, ctx);
|
|
2224
2344
|
const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
|
|
2225
|
-
const baseSelect = this.
|
|
2345
|
+
const baseSelect = this.compileSelectCoreForMssql(baseAst, ctx);
|
|
2226
2346
|
if (!hasSetOps) {
|
|
2227
2347
|
return `${ctes}${baseSelect}`;
|
|
2228
2348
|
}
|
|
@@ -2233,32 +2353,26 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2233
2353
|
const tail = pagination || orderBy;
|
|
2234
2354
|
return `${ctes}${combined}${tail}`;
|
|
2235
2355
|
}
|
|
2236
|
-
compileInsertAst(ast, ctx) {
|
|
2237
|
-
const table = this.quoteIdentifier(ast.into.name);
|
|
2238
|
-
const columnList = ast.columns.map((column) => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(", ");
|
|
2239
|
-
const values = ast.values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
2240
|
-
return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
|
|
2241
|
-
}
|
|
2242
|
-
compileUpdateAst(ast, ctx) {
|
|
2243
|
-
const table = this.quoteIdentifier(ast.table.name);
|
|
2244
|
-
const assignments = ast.set.map((assignment) => {
|
|
2245
|
-
const col2 = assignment.column;
|
|
2246
|
-
const target = `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`;
|
|
2247
|
-
const value = this.compileOperand(assignment.value, ctx);
|
|
2248
|
-
return `${target} = ${value}`;
|
|
2249
|
-
}).join(", ");
|
|
2250
|
-
const whereClause = this.compileWhere(ast.where, ctx);
|
|
2251
|
-
return `UPDATE ${table} SET ${assignments}${whereClause};`;
|
|
2252
|
-
}
|
|
2253
2356
|
compileDeleteAst(ast, ctx) {
|
|
2357
|
+
if (ast.using) {
|
|
2358
|
+
throw new Error("DELETE ... USING is not supported in the MSSQL dialect; use join() instead.");
|
|
2359
|
+
}
|
|
2254
2360
|
if (ast.from.type !== "Table") {
|
|
2255
2361
|
throw new Error("DELETE only supports base tables in the MSSQL dialect.");
|
|
2256
2362
|
}
|
|
2257
|
-
const
|
|
2363
|
+
const alias = ast.from.alias ?? ast.from.name;
|
|
2364
|
+
const target = this.compileTableReference(ast.from);
|
|
2365
|
+
const joins = JoinCompiler.compileJoins(
|
|
2366
|
+
ast.joins,
|
|
2367
|
+
ctx,
|
|
2368
|
+
this.compileFrom.bind(this),
|
|
2369
|
+
this.compileExpression.bind(this)
|
|
2370
|
+
);
|
|
2258
2371
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
2259
|
-
|
|
2372
|
+
const returning = this.compileReturning(ast.returning, ctx);
|
|
2373
|
+
return `DELETE ${this.quoteIdentifier(alias)} FROM ${target}${joins}${whereClause}${returning}`;
|
|
2260
2374
|
}
|
|
2261
|
-
|
|
2375
|
+
compileSelectCoreForMssql(ast, ctx) {
|
|
2262
2376
|
const columns = ast.columns.map((c) => {
|
|
2263
2377
|
let expr = "";
|
|
2264
2378
|
if (c.type === "Function") {
|
|
@@ -2277,9 +2391,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2277
2391
|
return expr;
|
|
2278
2392
|
}).join(", ");
|
|
2279
2393
|
const distinct = ast.distinct ? "DISTINCT " : "";
|
|
2280
|
-
const from = this.compileTableSource(ast.from
|
|
2394
|
+
const from = this.compileTableSource(ast.from);
|
|
2281
2395
|
const joins = ast.joins.map((j) => {
|
|
2282
|
-
const table = this.compileTableSource(j.table
|
|
2396
|
+
const table = this.compileTableSource(j.table);
|
|
2283
2397
|
const cond = this.compileExpression(j.condition, ctx);
|
|
2284
2398
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
2285
2399
|
}).join(" ");
|
|
@@ -2313,27 +2427,6 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2313
2427
|
}
|
|
2314
2428
|
return pagination;
|
|
2315
2429
|
}
|
|
2316
|
-
renderOrderByNulls(order) {
|
|
2317
|
-
return order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
2318
|
-
}
|
|
2319
|
-
renderOrderByCollation(order) {
|
|
2320
|
-
return order.collation ? ` COLLATE ${order.collation}` : "";
|
|
2321
|
-
}
|
|
2322
|
-
compileTableSource(table, ctx) {
|
|
2323
|
-
if (table.type === "FunctionTable") {
|
|
2324
|
-
return FunctionTableFormatter.format(table, ctx, this);
|
|
2325
|
-
}
|
|
2326
|
-
if (table.type === "DerivedTable") {
|
|
2327
|
-
return this.compileDerivedTable(table, ctx);
|
|
2328
|
-
}
|
|
2329
|
-
const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
|
|
2330
|
-
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
2331
|
-
}
|
|
2332
|
-
compileDerivedTable(table, ctx) {
|
|
2333
|
-
const sub2 = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
2334
|
-
const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
2335
|
-
return `(${sub2}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
|
|
2336
|
-
}
|
|
2337
2430
|
compileCtes(ast, ctx) {
|
|
2338
2431
|
if (!ast.ctes || ast.ctes.length === 0) return "";
|
|
2339
2432
|
const defs = ast.ctes.map((cte) => {
|
|
@@ -2344,10 +2437,6 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2344
2437
|
}).join(", ");
|
|
2345
2438
|
return `WITH ${defs} `;
|
|
2346
2439
|
}
|
|
2347
|
-
wrapSetOperand(sql) {
|
|
2348
|
-
const trimmed = sql.trim().replace(/;$/, "");
|
|
2349
|
-
return `(${trimmed})`;
|
|
2350
|
-
}
|
|
2351
2440
|
};
|
|
2352
2441
|
|
|
2353
2442
|
// src/core/dialect/dialect-factory.ts
|
|
@@ -3174,7 +3263,7 @@ var QueryAstService = class {
|
|
|
3174
3263
|
}
|
|
3175
3264
|
normalizeOrderingTerm(term) {
|
|
3176
3265
|
const from = this.state.ast.from;
|
|
3177
|
-
const
|
|
3266
|
+
const tableRef2 = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
3178
3267
|
const termType = term?.type;
|
|
3179
3268
|
if (termType === "Column") {
|
|
3180
3269
|
return term;
|
|
@@ -3188,7 +3277,7 @@ var QueryAstService = class {
|
|
|
3188
3277
|
if (termType === "BinaryExpression" || termType === "LogicalExpression" || termType === "NullExpression" || termType === "InExpression" || termType === "ExistsExpression" || termType === "BetweenExpression" || termType === "ArithmeticExpression") {
|
|
3189
3278
|
return term;
|
|
3190
3279
|
}
|
|
3191
|
-
return buildColumnNode(
|
|
3280
|
+
return buildColumnNode(tableRef2, term);
|
|
3192
3281
|
}
|
|
3193
3282
|
};
|
|
3194
3283
|
|
|
@@ -3594,8 +3683,8 @@ var ColumnSelector = class {
|
|
|
3594
3683
|
*/
|
|
3595
3684
|
distinct(context, columns) {
|
|
3596
3685
|
const from = context.state.ast.from;
|
|
3597
|
-
const
|
|
3598
|
-
const nodes = columns.map((col2) => buildColumnNode(
|
|
3686
|
+
const tableRef2 = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
|
|
3687
|
+
const nodes = columns.map((col2) => buildColumnNode(tableRef2, col2));
|
|
3599
3688
|
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
3600
3689
|
const nextState = astService.withDistinct(nodes);
|
|
3601
3690
|
return { state: nextState, hydration: context.hydration };
|
|
@@ -4142,8 +4231,10 @@ var DefaultManyToManyCollection = class {
|
|
|
4142
4231
|
attach(target) {
|
|
4143
4232
|
const entity = this.ensureEntity(target);
|
|
4144
4233
|
const id = this.extractId(entity);
|
|
4145
|
-
if (id
|
|
4146
|
-
|
|
4234
|
+
if (id != null && this.items.some((item) => this.extractId(item) === id)) {
|
|
4235
|
+
return;
|
|
4236
|
+
}
|
|
4237
|
+
if (id == null && this.items.includes(entity)) {
|
|
4147
4238
|
return;
|
|
4148
4239
|
}
|
|
4149
4240
|
this.items.push(entity);
|
|
@@ -5466,15 +5557,36 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
5466
5557
|
type: "InsertQuery",
|
|
5467
5558
|
into: createTableNode(table),
|
|
5468
5559
|
columns: [],
|
|
5469
|
-
|
|
5560
|
+
source: {
|
|
5561
|
+
type: "InsertValues",
|
|
5562
|
+
rows: []
|
|
5563
|
+
}
|
|
5470
5564
|
};
|
|
5471
5565
|
}
|
|
5472
5566
|
clone(nextAst) {
|
|
5473
5567
|
return new _InsertQueryState(this.table, nextAst);
|
|
5474
5568
|
}
|
|
5569
|
+
ensureColumnsFromRow(rows) {
|
|
5570
|
+
if (this.ast.columns.length) return this.ast.columns;
|
|
5571
|
+
return buildColumnNodes(this.table, Object.keys(rows[0]));
|
|
5572
|
+
}
|
|
5573
|
+
appendValues(rows) {
|
|
5574
|
+
if (this.ast.source.type === "InsertValues") {
|
|
5575
|
+
return [...this.ast.source.rows, ...rows];
|
|
5576
|
+
}
|
|
5577
|
+
return rows;
|
|
5578
|
+
}
|
|
5579
|
+
getTableColumns() {
|
|
5580
|
+
const names = Object.keys(this.table.columns);
|
|
5581
|
+
if (!names.length) return [];
|
|
5582
|
+
return buildColumnNodes(this.table, names);
|
|
5583
|
+
}
|
|
5475
5584
|
withValues(rows) {
|
|
5476
5585
|
if (!rows.length) return this;
|
|
5477
|
-
|
|
5586
|
+
if (this.ast.source.type === "InsertSelect") {
|
|
5587
|
+
throw new Error("Cannot mix INSERT ... VALUES with INSERT ... SELECT source.");
|
|
5588
|
+
}
|
|
5589
|
+
const definedColumns = this.ensureColumnsFromRow(rows);
|
|
5478
5590
|
const newRows = rows.map(
|
|
5479
5591
|
(row, rowIndex) => definedColumns.map((column) => {
|
|
5480
5592
|
const rawValue = row[column.name];
|
|
@@ -5489,7 +5601,34 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
5489
5601
|
return this.clone({
|
|
5490
5602
|
...this.ast,
|
|
5491
5603
|
columns: definedColumns,
|
|
5492
|
-
|
|
5604
|
+
source: {
|
|
5605
|
+
type: "InsertValues",
|
|
5606
|
+
rows: this.appendValues(newRows)
|
|
5607
|
+
}
|
|
5608
|
+
});
|
|
5609
|
+
}
|
|
5610
|
+
withColumns(columns) {
|
|
5611
|
+
if (!columns.length) return this;
|
|
5612
|
+
return this.clone({
|
|
5613
|
+
...this.ast,
|
|
5614
|
+
columns: [...columns]
|
|
5615
|
+
});
|
|
5616
|
+
}
|
|
5617
|
+
withSelect(query, columns) {
|
|
5618
|
+
const targetColumns = columns.length ? columns : this.ast.columns.length ? this.ast.columns : this.getTableColumns();
|
|
5619
|
+
if (!targetColumns.length) {
|
|
5620
|
+
throw new Error("INSERT ... SELECT requires specifying destination columns.");
|
|
5621
|
+
}
|
|
5622
|
+
if (this.ast.source.type === "InsertValues" && this.ast.source.rows.length) {
|
|
5623
|
+
throw new Error("Cannot mix INSERT ... SELECT with INSERT ... VALUES source.");
|
|
5624
|
+
}
|
|
5625
|
+
return this.clone({
|
|
5626
|
+
...this.ast,
|
|
5627
|
+
columns: [...targetColumns],
|
|
5628
|
+
source: {
|
|
5629
|
+
type: "InsertSelect",
|
|
5630
|
+
query
|
|
5631
|
+
}
|
|
5493
5632
|
});
|
|
5494
5633
|
}
|
|
5495
5634
|
withReturning(columns) {
|
|
@@ -5514,11 +5653,27 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
5514
5653
|
if (!rows.length) return this;
|
|
5515
5654
|
return this.clone(this.state.withValues(rows));
|
|
5516
5655
|
}
|
|
5656
|
+
columns(...columns) {
|
|
5657
|
+
if (!columns.length) return this;
|
|
5658
|
+
return this.clone(this.state.withColumns(this.resolveColumnNodes(columns)));
|
|
5659
|
+
}
|
|
5660
|
+
fromSelect(query, columns = []) {
|
|
5661
|
+
const ast = this.resolveSelectQuery(query);
|
|
5662
|
+
const nodes = columns.length ? this.resolveColumnNodes(columns) : [];
|
|
5663
|
+
return this.clone(this.state.withSelect(ast, nodes));
|
|
5664
|
+
}
|
|
5517
5665
|
returning(...columns) {
|
|
5518
5666
|
if (!columns.length) return this;
|
|
5519
5667
|
const nodes = columns.map((column) => buildColumnNode(this.table, column));
|
|
5520
5668
|
return this.clone(this.state.withReturning(nodes));
|
|
5521
5669
|
}
|
|
5670
|
+
// Helpers for column/AST resolution
|
|
5671
|
+
resolveColumnNodes(columns) {
|
|
5672
|
+
return columns.map((column) => buildColumnNode(this.table, column));
|
|
5673
|
+
}
|
|
5674
|
+
resolveSelectQuery(query) {
|
|
5675
|
+
return typeof query.getAST === "function" ? query.getAST() : query;
|
|
5676
|
+
}
|
|
5522
5677
|
compile(arg) {
|
|
5523
5678
|
if (typeof arg.compileInsert === "function") {
|
|
5524
5679
|
return arg.compileInsert(this.state.ast);
|
|
@@ -5552,7 +5707,8 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
5552
5707
|
this.ast = ast ?? {
|
|
5553
5708
|
type: "UpdateQuery",
|
|
5554
5709
|
table: createTableNode(table),
|
|
5555
|
-
set: []
|
|
5710
|
+
set: [],
|
|
5711
|
+
joins: []
|
|
5556
5712
|
};
|
|
5557
5713
|
}
|
|
5558
5714
|
clone(nextAst) {
|
|
@@ -5591,6 +5747,27 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
5591
5747
|
returning: [...columns]
|
|
5592
5748
|
});
|
|
5593
5749
|
}
|
|
5750
|
+
withFrom(from) {
|
|
5751
|
+
return this.clone({
|
|
5752
|
+
...this.ast,
|
|
5753
|
+
from
|
|
5754
|
+
});
|
|
5755
|
+
}
|
|
5756
|
+
withJoin(join) {
|
|
5757
|
+
return this.clone({
|
|
5758
|
+
...this.ast,
|
|
5759
|
+
joins: [...this.ast.joins ?? [], join]
|
|
5760
|
+
});
|
|
5761
|
+
}
|
|
5762
|
+
withTableAlias(alias) {
|
|
5763
|
+
return this.clone({
|
|
5764
|
+
...this.ast,
|
|
5765
|
+
table: {
|
|
5766
|
+
...this.ast.table,
|
|
5767
|
+
alias
|
|
5768
|
+
}
|
|
5769
|
+
});
|
|
5770
|
+
}
|
|
5594
5771
|
};
|
|
5595
5772
|
|
|
5596
5773
|
// src/query-builder/update.ts
|
|
@@ -5602,6 +5779,18 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
5602
5779
|
clone(state) {
|
|
5603
5780
|
return new _UpdateQueryBuilder(this.table, state);
|
|
5604
5781
|
}
|
|
5782
|
+
as(alias) {
|
|
5783
|
+
return this.clone(this.state.withTableAlias(alias));
|
|
5784
|
+
}
|
|
5785
|
+
from(source) {
|
|
5786
|
+
const tableSource = this.resolveTableSource(source);
|
|
5787
|
+
return this.clone(this.state.withFrom(tableSource));
|
|
5788
|
+
}
|
|
5789
|
+
join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
|
|
5790
|
+
const joinTarget = this.resolveJoinTarget(table);
|
|
5791
|
+
const joinNode = createJoinNode(kind, joinTarget, condition, relationName);
|
|
5792
|
+
return this.clone(this.state.withJoin(joinNode));
|
|
5793
|
+
}
|
|
5605
5794
|
set(values) {
|
|
5606
5795
|
return this.clone(this.state.withSet(values));
|
|
5607
5796
|
}
|
|
@@ -5613,6 +5802,16 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
5613
5802
|
const nodes = columns.map((column) => buildColumnNode(this.table, column));
|
|
5614
5803
|
return this.clone(this.state.withReturning(nodes));
|
|
5615
5804
|
}
|
|
5805
|
+
resolveTableSource(source) {
|
|
5806
|
+
if (isTableSourceNode(source)) {
|
|
5807
|
+
return source;
|
|
5808
|
+
}
|
|
5809
|
+
return { type: "Table", name: source.name, schema: source.schema };
|
|
5810
|
+
}
|
|
5811
|
+
resolveJoinTarget(table) {
|
|
5812
|
+
if (typeof table === "string") return table;
|
|
5813
|
+
return this.resolveTableSource(table);
|
|
5814
|
+
}
|
|
5616
5815
|
compile(arg) {
|
|
5617
5816
|
if (typeof arg.compileUpdate === "function") {
|
|
5618
5817
|
return arg.compileUpdate(this.state.ast);
|
|
@@ -5627,6 +5826,7 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
5627
5826
|
return this.state.ast;
|
|
5628
5827
|
}
|
|
5629
5828
|
};
|
|
5829
|
+
var isTableSourceNode = (source) => typeof source.type === "string";
|
|
5630
5830
|
|
|
5631
5831
|
// src/query-builder/delete-query-state.ts
|
|
5632
5832
|
var DeleteQueryState = class _DeleteQueryState {
|
|
@@ -5634,7 +5834,8 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
5634
5834
|
this.table = table;
|
|
5635
5835
|
this.ast = ast ?? {
|
|
5636
5836
|
type: "DeleteQuery",
|
|
5637
|
-
from: createTableNode(table)
|
|
5837
|
+
from: createTableNode(table),
|
|
5838
|
+
joins: []
|
|
5638
5839
|
};
|
|
5639
5840
|
}
|
|
5640
5841
|
clone(nextAst) {
|
|
@@ -5652,6 +5853,27 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
5652
5853
|
returning: [...columns]
|
|
5653
5854
|
});
|
|
5654
5855
|
}
|
|
5856
|
+
withUsing(source) {
|
|
5857
|
+
return this.clone({
|
|
5858
|
+
...this.ast,
|
|
5859
|
+
using: source
|
|
5860
|
+
});
|
|
5861
|
+
}
|
|
5862
|
+
withJoin(join) {
|
|
5863
|
+
return this.clone({
|
|
5864
|
+
...this.ast,
|
|
5865
|
+
joins: [...this.ast.joins ?? [], join]
|
|
5866
|
+
});
|
|
5867
|
+
}
|
|
5868
|
+
withTableAlias(alias) {
|
|
5869
|
+
return this.clone({
|
|
5870
|
+
...this.ast,
|
|
5871
|
+
from: {
|
|
5872
|
+
...this.ast.from,
|
|
5873
|
+
alias
|
|
5874
|
+
}
|
|
5875
|
+
});
|
|
5876
|
+
}
|
|
5655
5877
|
};
|
|
5656
5878
|
|
|
5657
5879
|
// src/query-builder/delete.ts
|
|
@@ -5666,11 +5888,32 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
5666
5888
|
where(expr) {
|
|
5667
5889
|
return this.clone(this.state.withWhere(expr));
|
|
5668
5890
|
}
|
|
5891
|
+
as(alias) {
|
|
5892
|
+
return this.clone(this.state.withTableAlias(alias));
|
|
5893
|
+
}
|
|
5894
|
+
using(source) {
|
|
5895
|
+
return this.clone(this.state.withUsing(this.resolveTableSource(source)));
|
|
5896
|
+
}
|
|
5897
|
+
join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
|
|
5898
|
+
const target = this.resolveJoinTarget(table);
|
|
5899
|
+
const joinNode = createJoinNode(kind, target, condition, relationName);
|
|
5900
|
+
return this.clone(this.state.withJoin(joinNode));
|
|
5901
|
+
}
|
|
5669
5902
|
returning(...columns) {
|
|
5670
5903
|
if (!columns.length) return this;
|
|
5671
5904
|
const nodes = columns.map((column) => buildColumnNode(this.table, column));
|
|
5672
5905
|
return this.clone(this.state.withReturning(nodes));
|
|
5673
5906
|
}
|
|
5907
|
+
resolveTableSource(source) {
|
|
5908
|
+
if (isTableSourceNode2(source)) {
|
|
5909
|
+
return source;
|
|
5910
|
+
}
|
|
5911
|
+
return { type: "Table", name: source.name, schema: source.schema };
|
|
5912
|
+
}
|
|
5913
|
+
resolveJoinTarget(table) {
|
|
5914
|
+
if (typeof table === "string") return table;
|
|
5915
|
+
return this.resolveTableSource(table);
|
|
5916
|
+
}
|
|
5674
5917
|
compile(arg) {
|
|
5675
5918
|
if (typeof arg.compileDelete === "function") {
|
|
5676
5919
|
return arg.compileDelete(this.state.ast);
|
|
@@ -5685,6 +5928,7 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
5685
5928
|
return this.state.ast;
|
|
5686
5929
|
}
|
|
5687
5930
|
};
|
|
5931
|
+
var isTableSourceNode2 = (source) => typeof source.type === "string";
|
|
5688
5932
|
|
|
5689
5933
|
// src/core/ddl/sql-writing.ts
|
|
5690
5934
|
var resolvePrimaryKey = (table) => {
|
|
@@ -7033,9 +7277,13 @@ var TypeScriptGenerator = class {
|
|
|
7033
7277
|
*/
|
|
7034
7278
|
printInExpression(inExpr) {
|
|
7035
7279
|
const left2 = this.printOperand(inExpr.left);
|
|
7036
|
-
const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
|
|
7037
7280
|
const fn4 = this.mapOp(inExpr.operator);
|
|
7038
|
-
|
|
7281
|
+
if (Array.isArray(inExpr.right)) {
|
|
7282
|
+
const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
|
|
7283
|
+
return `${fn4}(${left2}, [${values}])`;
|
|
7284
|
+
}
|
|
7285
|
+
const subquery = this.inlineChain(this.buildSelectLines(inExpr.right.query));
|
|
7286
|
+
return `${fn4}(${left2}, (${subquery}))`;
|
|
7039
7287
|
}
|
|
7040
7288
|
/**
|
|
7041
7289
|
* Prints a null expression to TypeScript code
|
|
@@ -7220,6 +7468,13 @@ var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
|
7220
7468
|
|
|
7221
7469
|
// src/orm/unit-of-work.ts
|
|
7222
7470
|
var UnitOfWork = class {
|
|
7471
|
+
/**
|
|
7472
|
+
* Creates a new UnitOfWork instance.
|
|
7473
|
+
* @param dialect - The database dialect
|
|
7474
|
+
* @param executor - The database executor
|
|
7475
|
+
* @param identityMap - The identity map
|
|
7476
|
+
* @param hookContext - Function to get the hook context
|
|
7477
|
+
*/
|
|
7223
7478
|
constructor(dialect, executor, identityMap, hookContext) {
|
|
7224
7479
|
this.dialect = dialect;
|
|
7225
7480
|
this.executor = executor;
|
|
@@ -7227,21 +7482,50 @@ var UnitOfWork = class {
|
|
|
7227
7482
|
this.hookContext = hookContext;
|
|
7228
7483
|
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
7229
7484
|
}
|
|
7485
|
+
/**
|
|
7486
|
+
* Gets the identity buckets map.
|
|
7487
|
+
*/
|
|
7230
7488
|
get identityBuckets() {
|
|
7231
7489
|
return this.identityMap.bucketsMap;
|
|
7232
7490
|
}
|
|
7491
|
+
/**
|
|
7492
|
+
* Gets all tracked entities.
|
|
7493
|
+
* @returns Array of tracked entities
|
|
7494
|
+
*/
|
|
7233
7495
|
getTracked() {
|
|
7234
7496
|
return Array.from(this.trackedEntities.values());
|
|
7235
7497
|
}
|
|
7498
|
+
/**
|
|
7499
|
+
* Gets an entity by table and primary key.
|
|
7500
|
+
* @param table - The table definition
|
|
7501
|
+
* @param pk - The primary key value
|
|
7502
|
+
* @returns The entity or undefined if not found
|
|
7503
|
+
*/
|
|
7236
7504
|
getEntity(table, pk) {
|
|
7237
7505
|
return this.identityMap.getEntity(table, pk);
|
|
7238
7506
|
}
|
|
7507
|
+
/**
|
|
7508
|
+
* Gets all tracked entities for a specific table.
|
|
7509
|
+
* @param table - The table definition
|
|
7510
|
+
* @returns Array of tracked entities
|
|
7511
|
+
*/
|
|
7239
7512
|
getEntitiesForTable(table) {
|
|
7240
7513
|
return this.identityMap.getEntitiesForTable(table);
|
|
7241
7514
|
}
|
|
7515
|
+
/**
|
|
7516
|
+
* Finds a tracked entity.
|
|
7517
|
+
* @param entity - The entity to find
|
|
7518
|
+
* @returns The tracked entity or undefined if not found
|
|
7519
|
+
*/
|
|
7242
7520
|
findTracked(entity) {
|
|
7243
7521
|
return this.trackedEntities.get(entity);
|
|
7244
7522
|
}
|
|
7523
|
+
/**
|
|
7524
|
+
* Sets an entity in the identity map.
|
|
7525
|
+
* @param table - The table definition
|
|
7526
|
+
* @param pk - The primary key value
|
|
7527
|
+
* @param entity - The entity instance
|
|
7528
|
+
*/
|
|
7245
7529
|
setEntity(table, pk, entity) {
|
|
7246
7530
|
if (pk === null || pk === void 0) return;
|
|
7247
7531
|
let tracked = this.trackedEntities.get(entity);
|
|
@@ -7259,6 +7543,12 @@ var UnitOfWork = class {
|
|
|
7259
7543
|
}
|
|
7260
7544
|
this.registerIdentity(tracked);
|
|
7261
7545
|
}
|
|
7546
|
+
/**
|
|
7547
|
+
* Tracks a new entity.
|
|
7548
|
+
* @param table - The table definition
|
|
7549
|
+
* @param entity - The entity instance
|
|
7550
|
+
* @param pk - Optional primary key value
|
|
7551
|
+
*/
|
|
7262
7552
|
trackNew(table, entity, pk) {
|
|
7263
7553
|
const tracked = {
|
|
7264
7554
|
table,
|
|
@@ -7272,6 +7562,12 @@ var UnitOfWork = class {
|
|
|
7272
7562
|
this.registerIdentity(tracked);
|
|
7273
7563
|
}
|
|
7274
7564
|
}
|
|
7565
|
+
/**
|
|
7566
|
+
* Tracks a managed entity.
|
|
7567
|
+
* @param table - The table definition
|
|
7568
|
+
* @param pk - The primary key value
|
|
7569
|
+
* @param entity - The entity instance
|
|
7570
|
+
*/
|
|
7275
7571
|
trackManaged(table, pk, entity) {
|
|
7276
7572
|
const tracked = {
|
|
7277
7573
|
table,
|
|
@@ -7283,17 +7579,28 @@ var UnitOfWork = class {
|
|
|
7283
7579
|
this.trackedEntities.set(entity, tracked);
|
|
7284
7580
|
this.registerIdentity(tracked);
|
|
7285
7581
|
}
|
|
7582
|
+
/**
|
|
7583
|
+
* Marks an entity as dirty (modified).
|
|
7584
|
+
* @param entity - The entity to mark as dirty
|
|
7585
|
+
*/
|
|
7286
7586
|
markDirty(entity) {
|
|
7287
7587
|
const tracked = this.trackedEntities.get(entity);
|
|
7288
7588
|
if (!tracked) return;
|
|
7289
7589
|
if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
|
|
7290
7590
|
tracked.status = "dirty" /* Dirty */;
|
|
7291
7591
|
}
|
|
7592
|
+
/**
|
|
7593
|
+
* Marks an entity as removed.
|
|
7594
|
+
* @param entity - The entity to mark as removed
|
|
7595
|
+
*/
|
|
7292
7596
|
markRemoved(entity) {
|
|
7293
7597
|
const tracked = this.trackedEntities.get(entity);
|
|
7294
7598
|
if (!tracked) return;
|
|
7295
7599
|
tracked.status = "removed" /* Removed */;
|
|
7296
7600
|
}
|
|
7601
|
+
/**
|
|
7602
|
+
* Flushes pending changes to the database.
|
|
7603
|
+
*/
|
|
7297
7604
|
async flush() {
|
|
7298
7605
|
const toFlush = Array.from(this.trackedEntities.values());
|
|
7299
7606
|
for (const tracked of toFlush) {
|
|
@@ -7312,10 +7619,17 @@ var UnitOfWork = class {
|
|
|
7312
7619
|
}
|
|
7313
7620
|
}
|
|
7314
7621
|
}
|
|
7622
|
+
/**
|
|
7623
|
+
* Resets the unit of work by clearing all tracked entities and identity map.
|
|
7624
|
+
*/
|
|
7315
7625
|
reset() {
|
|
7316
7626
|
this.trackedEntities.clear();
|
|
7317
7627
|
this.identityMap.clear();
|
|
7318
7628
|
}
|
|
7629
|
+
/**
|
|
7630
|
+
* Flushes an insert operation for a new entity.
|
|
7631
|
+
* @param tracked - The tracked entity to insert
|
|
7632
|
+
*/
|
|
7319
7633
|
async flushInsert(tracked) {
|
|
7320
7634
|
await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
|
|
7321
7635
|
const payload = this.extractColumns(tracked.table, tracked.entity);
|
|
@@ -7332,6 +7646,10 @@ var UnitOfWork = class {
|
|
|
7332
7646
|
this.registerIdentity(tracked);
|
|
7333
7647
|
await this.runHook(tracked.table.hooks?.afterInsert, tracked);
|
|
7334
7648
|
}
|
|
7649
|
+
/**
|
|
7650
|
+
* Flushes an update operation for a modified entity.
|
|
7651
|
+
* @param tracked - The tracked entity to update
|
|
7652
|
+
*/
|
|
7335
7653
|
async flushUpdate(tracked) {
|
|
7336
7654
|
if (tracked.pk == null) return;
|
|
7337
7655
|
const changes = this.computeChanges(tracked);
|
|
@@ -7354,6 +7672,10 @@ var UnitOfWork = class {
|
|
|
7354
7672
|
this.registerIdentity(tracked);
|
|
7355
7673
|
await this.runHook(tracked.table.hooks?.afterUpdate, tracked);
|
|
7356
7674
|
}
|
|
7675
|
+
/**
|
|
7676
|
+
* Flushes a delete operation for a removed entity.
|
|
7677
|
+
* @param tracked - The tracked entity to delete
|
|
7678
|
+
*/
|
|
7357
7679
|
async flushDelete(tracked) {
|
|
7358
7680
|
if (tracked.pk == null) return;
|
|
7359
7681
|
await this.runHook(tracked.table.hooks?.beforeDelete, tracked);
|
|
@@ -7367,10 +7689,20 @@ var UnitOfWork = class {
|
|
|
7367
7689
|
this.identityMap.remove(tracked);
|
|
7368
7690
|
await this.runHook(tracked.table.hooks?.afterDelete, tracked);
|
|
7369
7691
|
}
|
|
7692
|
+
/**
|
|
7693
|
+
* Runs a table hook if defined.
|
|
7694
|
+
* @param hook - The hook function
|
|
7695
|
+
* @param tracked - The tracked entity
|
|
7696
|
+
*/
|
|
7370
7697
|
async runHook(hook, tracked) {
|
|
7371
7698
|
if (!hook) return;
|
|
7372
7699
|
await hook(this.hookContext(), tracked.entity);
|
|
7373
7700
|
}
|
|
7701
|
+
/**
|
|
7702
|
+
* Computes changes between current entity state and original snapshot.
|
|
7703
|
+
* @param tracked - The tracked entity
|
|
7704
|
+
* @returns Object with changed column values
|
|
7705
|
+
*/
|
|
7374
7706
|
computeChanges(tracked) {
|
|
7375
7707
|
const snapshot = tracked.original ?? {};
|
|
7376
7708
|
const changes = {};
|
|
@@ -7382,6 +7714,12 @@ var UnitOfWork = class {
|
|
|
7382
7714
|
}
|
|
7383
7715
|
return changes;
|
|
7384
7716
|
}
|
|
7717
|
+
/**
|
|
7718
|
+
* Extracts column values from an entity.
|
|
7719
|
+
* @param table - The table definition
|
|
7720
|
+
* @param entity - The entity instance
|
|
7721
|
+
* @returns Object with column values
|
|
7722
|
+
*/
|
|
7385
7723
|
extractColumns(table, entity) {
|
|
7386
7724
|
const payload = {};
|
|
7387
7725
|
for (const column of Object.keys(table.columns)) {
|
|
@@ -7390,9 +7728,19 @@ var UnitOfWork = class {
|
|
|
7390
7728
|
}
|
|
7391
7729
|
return payload;
|
|
7392
7730
|
}
|
|
7731
|
+
/**
|
|
7732
|
+
* Executes a compiled query.
|
|
7733
|
+
* @param compiled - The compiled query
|
|
7734
|
+
* @returns Query results
|
|
7735
|
+
*/
|
|
7393
7736
|
async executeCompiled(compiled) {
|
|
7394
7737
|
return this.executor.executeSql(compiled.sql, compiled.params);
|
|
7395
7738
|
}
|
|
7739
|
+
/**
|
|
7740
|
+
* Gets columns for RETURNING clause.
|
|
7741
|
+
* @param table - The table definition
|
|
7742
|
+
* @returns Array of column nodes
|
|
7743
|
+
*/
|
|
7396
7744
|
getReturningColumns(table) {
|
|
7397
7745
|
return Object.values(table.columns).map((column) => ({
|
|
7398
7746
|
type: "Column",
|
|
@@ -7401,6 +7749,11 @@ var UnitOfWork = class {
|
|
|
7401
7749
|
alias: column.name
|
|
7402
7750
|
}));
|
|
7403
7751
|
}
|
|
7752
|
+
/**
|
|
7753
|
+
* Applies RETURNING clause results to the tracked entity.
|
|
7754
|
+
* @param tracked - The tracked entity
|
|
7755
|
+
* @param results - Query results
|
|
7756
|
+
*/
|
|
7404
7757
|
applyReturningResults(tracked, results) {
|
|
7405
7758
|
if (!this.dialect.supportsReturning()) return;
|
|
7406
7759
|
const first = results[0];
|
|
@@ -7412,15 +7765,30 @@ var UnitOfWork = class {
|
|
|
7412
7765
|
tracked.entity[columnName] = row[i];
|
|
7413
7766
|
}
|
|
7414
7767
|
}
|
|
7768
|
+
/**
|
|
7769
|
+
* Normalizes a column name by removing quotes and table prefixes.
|
|
7770
|
+
* @param column - The column name to normalize
|
|
7771
|
+
* @returns Normalized column name
|
|
7772
|
+
*/
|
|
7415
7773
|
normalizeColumnName(column) {
|
|
7416
7774
|
const parts = column.split(".");
|
|
7417
7775
|
const candidate = parts[parts.length - 1];
|
|
7418
7776
|
return candidate.replace(/^["`[\]]+|["`[\]]+$/g, "");
|
|
7419
7777
|
}
|
|
7778
|
+
/**
|
|
7779
|
+
* Registers an entity in the identity map.
|
|
7780
|
+
* @param tracked - The tracked entity to register
|
|
7781
|
+
*/
|
|
7420
7782
|
registerIdentity(tracked) {
|
|
7421
7783
|
if (tracked.pk == null) return;
|
|
7422
7784
|
this.identityMap.register(tracked);
|
|
7423
7785
|
}
|
|
7786
|
+
/**
|
|
7787
|
+
* Creates a snapshot of an entity's current state.
|
|
7788
|
+
* @param table - The table definition
|
|
7789
|
+
* @param entity - The entity instance
|
|
7790
|
+
* @returns Object with entity state
|
|
7791
|
+
*/
|
|
7424
7792
|
createSnapshot(table, entity) {
|
|
7425
7793
|
const snapshot = {};
|
|
7426
7794
|
for (const column of Object.keys(table.columns)) {
|
|
@@ -7428,6 +7796,11 @@ var UnitOfWork = class {
|
|
|
7428
7796
|
}
|
|
7429
7797
|
return snapshot;
|
|
7430
7798
|
}
|
|
7799
|
+
/**
|
|
7800
|
+
* Gets the primary key value from a tracked entity.
|
|
7801
|
+
* @param tracked - The tracked entity
|
|
7802
|
+
* @returns Primary key value or null
|
|
7803
|
+
*/
|
|
7431
7804
|
getPrimaryKeyValue(tracked) {
|
|
7432
7805
|
const key = findPrimaryKey(tracked.table);
|
|
7433
7806
|
const val = tracked.entity[key];
|
|
@@ -7438,6 +7811,10 @@ var UnitOfWork = class {
|
|
|
7438
7811
|
|
|
7439
7812
|
// src/orm/domain-event-bus.ts
|
|
7440
7813
|
var DomainEventBus = class {
|
|
7814
|
+
/**
|
|
7815
|
+
* Creates a new DomainEventBus instance.
|
|
7816
|
+
* @param initialHandlers - Optional initial event handlers
|
|
7817
|
+
*/
|
|
7441
7818
|
constructor(initialHandlers) {
|
|
7442
7819
|
this.handlers = /* @__PURE__ */ new Map();
|
|
7443
7820
|
if (initialHandlers) {
|
|
@@ -7448,15 +7825,32 @@ var DomainEventBus = class {
|
|
|
7448
7825
|
}
|
|
7449
7826
|
}
|
|
7450
7827
|
}
|
|
7828
|
+
/**
|
|
7829
|
+
* Registers an event handler for a specific event type.
|
|
7830
|
+
* @template TType - The event type
|
|
7831
|
+
* @param type - The event type
|
|
7832
|
+
* @param handler - The event handler
|
|
7833
|
+
*/
|
|
7451
7834
|
on(type, handler) {
|
|
7452
7835
|
const key = type;
|
|
7453
7836
|
const existing = this.handlers.get(key) ?? [];
|
|
7454
7837
|
existing.push(handler);
|
|
7455
7838
|
this.handlers.set(key, existing);
|
|
7456
7839
|
}
|
|
7840
|
+
/**
|
|
7841
|
+
* Registers an event handler for a specific event type (alias for on).
|
|
7842
|
+
* @template TType - The event type
|
|
7843
|
+
* @param type - The event type
|
|
7844
|
+
* @param handler - The event handler
|
|
7845
|
+
*/
|
|
7457
7846
|
register(type, handler) {
|
|
7458
7847
|
this.on(type, handler);
|
|
7459
7848
|
}
|
|
7849
|
+
/**
|
|
7850
|
+
* Dispatches domain events for tracked entities.
|
|
7851
|
+
* @param trackedEntities - Iterable of tracked entities
|
|
7852
|
+
* @param ctx - The context to pass to handlers
|
|
7853
|
+
*/
|
|
7460
7854
|
async dispatch(trackedEntities, ctx) {
|
|
7461
7855
|
for (const tracked of trackedEntities) {
|
|
7462
7856
|
const entity = tracked.entity;
|
|
@@ -7481,18 +7875,34 @@ var addDomainEvent = (entity, event) => {
|
|
|
7481
7875
|
|
|
7482
7876
|
// src/orm/relation-change-processor.ts
|
|
7483
7877
|
var RelationChangeProcessor = class {
|
|
7878
|
+
/**
|
|
7879
|
+
* Creates a new RelationChangeProcessor instance.
|
|
7880
|
+
* @param unitOfWork - The unit of work instance
|
|
7881
|
+
* @param dialect - The database dialect
|
|
7882
|
+
* @param executor - The database executor
|
|
7883
|
+
*/
|
|
7484
7884
|
constructor(unitOfWork, dialect, executor) {
|
|
7485
7885
|
this.unitOfWork = unitOfWork;
|
|
7486
7886
|
this.dialect = dialect;
|
|
7487
7887
|
this.executor = executor;
|
|
7488
7888
|
this.relationChanges = [];
|
|
7489
7889
|
}
|
|
7890
|
+
/**
|
|
7891
|
+
* Registers a relation change for processing.
|
|
7892
|
+
* @param entry - The relation change entry
|
|
7893
|
+
*/
|
|
7490
7894
|
registerChange(entry) {
|
|
7491
7895
|
this.relationChanges.push(entry);
|
|
7492
7896
|
}
|
|
7897
|
+
/**
|
|
7898
|
+
* Resets the relation change processor by clearing all pending changes.
|
|
7899
|
+
*/
|
|
7493
7900
|
reset() {
|
|
7494
7901
|
this.relationChanges.length = 0;
|
|
7495
7902
|
}
|
|
7903
|
+
/**
|
|
7904
|
+
* Processes all pending relation changes.
|
|
7905
|
+
*/
|
|
7496
7906
|
async process() {
|
|
7497
7907
|
if (!this.relationChanges.length) return;
|
|
7498
7908
|
const entries = [...this.relationChanges];
|
|
@@ -7514,6 +7924,10 @@ var RelationChangeProcessor = class {
|
|
|
7514
7924
|
}
|
|
7515
7925
|
}
|
|
7516
7926
|
}
|
|
7927
|
+
/**
|
|
7928
|
+
* Handles changes for has-many relations.
|
|
7929
|
+
* @param entry - The relation change entry
|
|
7930
|
+
*/
|
|
7517
7931
|
async handleHasManyChange(entry) {
|
|
7518
7932
|
const relation = entry.relation;
|
|
7519
7933
|
const target = entry.change.entity;
|
|
@@ -7532,6 +7946,10 @@ var RelationChangeProcessor = class {
|
|
|
7532
7946
|
this.detachHasManyChild(tracked.entity, relation);
|
|
7533
7947
|
}
|
|
7534
7948
|
}
|
|
7949
|
+
/**
|
|
7950
|
+
* Handles changes for has-one relations.
|
|
7951
|
+
* @param entry - The relation change entry
|
|
7952
|
+
*/
|
|
7535
7953
|
async handleHasOneChange(entry) {
|
|
7536
7954
|
const relation = entry.relation;
|
|
7537
7955
|
const target = entry.change.entity;
|
|
@@ -7550,8 +7968,16 @@ var RelationChangeProcessor = class {
|
|
|
7550
7968
|
this.detachHasOneChild(tracked.entity, relation);
|
|
7551
7969
|
}
|
|
7552
7970
|
}
|
|
7971
|
+
/**
|
|
7972
|
+
* Handles changes for belongs-to relations.
|
|
7973
|
+
* @param _entry - The relation change entry (reserved for future use)
|
|
7974
|
+
*/
|
|
7553
7975
|
async handleBelongsToChange(_entry) {
|
|
7554
7976
|
}
|
|
7977
|
+
/**
|
|
7978
|
+
* Handles changes for belongs-to-many relations.
|
|
7979
|
+
* @param entry - The relation change entry
|
|
7980
|
+
*/
|
|
7555
7981
|
async handleBelongsToManyChange(entry) {
|
|
7556
7982
|
const relation = entry.relation;
|
|
7557
7983
|
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
@@ -7570,11 +7996,22 @@ var RelationChangeProcessor = class {
|
|
|
7570
7996
|
}
|
|
7571
7997
|
}
|
|
7572
7998
|
}
|
|
7999
|
+
/**
|
|
8000
|
+
* Assigns a foreign key for has-many relations.
|
|
8001
|
+
* @param child - The child entity
|
|
8002
|
+
* @param relation - The has-many relation
|
|
8003
|
+
* @param rootValue - The root entity's primary key value
|
|
8004
|
+
*/
|
|
7573
8005
|
assignHasManyForeignKey(child, relation, rootValue) {
|
|
7574
8006
|
const current = child[relation.foreignKey];
|
|
7575
8007
|
if (current === rootValue) return;
|
|
7576
8008
|
child[relation.foreignKey] = rootValue;
|
|
7577
8009
|
}
|
|
8010
|
+
/**
|
|
8011
|
+
* Detaches a child entity from has-many relations.
|
|
8012
|
+
* @param child - The child entity
|
|
8013
|
+
* @param relation - The has-many relation
|
|
8014
|
+
*/
|
|
7578
8015
|
detachHasManyChild(child, relation) {
|
|
7579
8016
|
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
7580
8017
|
this.unitOfWork.markRemoved(child);
|
|
@@ -7583,11 +8020,22 @@ var RelationChangeProcessor = class {
|
|
|
7583
8020
|
child[relation.foreignKey] = null;
|
|
7584
8021
|
this.unitOfWork.markDirty(child);
|
|
7585
8022
|
}
|
|
8023
|
+
/**
|
|
8024
|
+
* Assigns a foreign key for has-one relations.
|
|
8025
|
+
* @param child - The child entity
|
|
8026
|
+
* @param relation - The has-one relation
|
|
8027
|
+
* @param rootValue - The root entity's primary key value
|
|
8028
|
+
*/
|
|
7586
8029
|
assignHasOneForeignKey(child, relation, rootValue) {
|
|
7587
8030
|
const current = child[relation.foreignKey];
|
|
7588
8031
|
if (current === rootValue) return;
|
|
7589
8032
|
child[relation.foreignKey] = rootValue;
|
|
7590
8033
|
}
|
|
8034
|
+
/**
|
|
8035
|
+
* Detaches a child entity from has-one relations.
|
|
8036
|
+
* @param child - The child entity
|
|
8037
|
+
* @param relation - The has-one relation
|
|
8038
|
+
*/
|
|
7591
8039
|
detachHasOneChild(child, relation) {
|
|
7592
8040
|
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
7593
8041
|
this.unitOfWork.markRemoved(child);
|
|
@@ -7596,6 +8044,12 @@ var RelationChangeProcessor = class {
|
|
|
7596
8044
|
child[relation.foreignKey] = null;
|
|
7597
8045
|
this.unitOfWork.markDirty(child);
|
|
7598
8046
|
}
|
|
8047
|
+
/**
|
|
8048
|
+
* Inserts a pivot row for belongs-to-many relations.
|
|
8049
|
+
* @param relation - The belongs-to-many relation
|
|
8050
|
+
* @param rootId - The root entity's primary key value
|
|
8051
|
+
* @param targetId - The target entity's primary key value
|
|
8052
|
+
*/
|
|
7599
8053
|
async insertPivotRow(relation, rootId, targetId) {
|
|
7600
8054
|
const payload = {
|
|
7601
8055
|
[relation.pivotForeignKeyToRoot]: rootId,
|
|
@@ -7605,6 +8059,12 @@ var RelationChangeProcessor = class {
|
|
|
7605
8059
|
const compiled = builder.compile(this.dialect);
|
|
7606
8060
|
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
7607
8061
|
}
|
|
8062
|
+
/**
|
|
8063
|
+
* Deletes a pivot row for belongs-to-many relations.
|
|
8064
|
+
* @param relation - The belongs-to-many relation
|
|
8065
|
+
* @param rootId - The root entity's primary key value
|
|
8066
|
+
* @param targetId - The target entity's primary key value
|
|
8067
|
+
*/
|
|
7608
8068
|
async deletePivotRow(relation, rootId, targetId) {
|
|
7609
8069
|
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
7610
8070
|
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
@@ -7615,6 +8075,12 @@ var RelationChangeProcessor = class {
|
|
|
7615
8075
|
const compiled = builder.compile(this.dialect);
|
|
7616
8076
|
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
7617
8077
|
}
|
|
8078
|
+
/**
|
|
8079
|
+
* Resolves the primary key value from an entity.
|
|
8080
|
+
* @param entity - The entity
|
|
8081
|
+
* @param table - The table definition
|
|
8082
|
+
* @returns The primary key value or null
|
|
8083
|
+
*/
|
|
7618
8084
|
resolvePrimaryKeyValue(entity, table) {
|
|
7619
8085
|
if (!entity) return null;
|
|
7620
8086
|
const key = findPrimaryKey(table);
|
|
@@ -7630,42 +8096,231 @@ var createQueryLoggingExecutor = (executor, logger) => {
|
|
|
7630
8096
|
return executor;
|
|
7631
8097
|
}
|
|
7632
8098
|
const wrapped = {
|
|
8099
|
+
capabilities: executor.capabilities,
|
|
7633
8100
|
async executeSql(sql, params) {
|
|
7634
8101
|
logger({ sql, params });
|
|
7635
8102
|
return executor.executeSql(sql, params);
|
|
7636
|
-
}
|
|
8103
|
+
},
|
|
8104
|
+
beginTransaction: () => executor.beginTransaction(),
|
|
8105
|
+
commitTransaction: () => executor.commitTransaction(),
|
|
8106
|
+
rollbackTransaction: () => executor.rollbackTransaction(),
|
|
8107
|
+
dispose: () => executor.dispose()
|
|
7637
8108
|
};
|
|
7638
|
-
if (executor.beginTransaction) {
|
|
7639
|
-
wrapped.beginTransaction = executor.beginTransaction.bind(executor);
|
|
7640
|
-
}
|
|
7641
|
-
if (executor.commitTransaction) {
|
|
7642
|
-
wrapped.commitTransaction = executor.commitTransaction.bind(executor);
|
|
7643
|
-
}
|
|
7644
|
-
if (executor.rollbackTransaction) {
|
|
7645
|
-
wrapped.rollbackTransaction = executor.rollbackTransaction.bind(executor);
|
|
7646
|
-
}
|
|
7647
8109
|
return wrapped;
|
|
7648
8110
|
};
|
|
7649
8111
|
|
|
7650
8112
|
// src/orm/transaction-runner.ts
|
|
7651
8113
|
var runInTransaction = async (executor, action) => {
|
|
7652
|
-
if (!executor.
|
|
8114
|
+
if (!executor.capabilities.transactions) {
|
|
7653
8115
|
await action();
|
|
7654
8116
|
return;
|
|
7655
8117
|
}
|
|
7656
8118
|
await executor.beginTransaction();
|
|
7657
8119
|
try {
|
|
7658
8120
|
await action();
|
|
7659
|
-
await executor.commitTransaction
|
|
8121
|
+
await executor.commitTransaction();
|
|
7660
8122
|
} catch (error) {
|
|
7661
|
-
await executor.rollbackTransaction
|
|
8123
|
+
await executor.rollbackTransaction();
|
|
7662
8124
|
throw error;
|
|
7663
8125
|
}
|
|
7664
8126
|
};
|
|
7665
8127
|
|
|
8128
|
+
// src/orm/save-graph.ts
|
|
8129
|
+
var toKey8 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
8130
|
+
var pickColumns = (table, payload) => {
|
|
8131
|
+
const columns = {};
|
|
8132
|
+
for (const key of Object.keys(table.columns)) {
|
|
8133
|
+
if (payload[key] !== void 0) {
|
|
8134
|
+
columns[key] = payload[key];
|
|
8135
|
+
}
|
|
8136
|
+
}
|
|
8137
|
+
return columns;
|
|
8138
|
+
};
|
|
8139
|
+
var ensureEntity = (session, table, payload) => {
|
|
8140
|
+
const pk = findPrimaryKey(table);
|
|
8141
|
+
const row = pickColumns(table, payload);
|
|
8142
|
+
const pkValue = payload[pk];
|
|
8143
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
8144
|
+
const tracked = session.getEntity(table, pkValue);
|
|
8145
|
+
if (tracked) {
|
|
8146
|
+
return tracked;
|
|
8147
|
+
}
|
|
8148
|
+
if (row[pk] === void 0) {
|
|
8149
|
+
row[pk] = pkValue;
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
return createEntityFromRow(session, table, row);
|
|
8153
|
+
};
|
|
8154
|
+
var assignColumns = (table, entity, payload) => {
|
|
8155
|
+
for (const key of Object.keys(table.columns)) {
|
|
8156
|
+
if (payload[key] !== void 0) {
|
|
8157
|
+
entity[key] = payload[key];
|
|
8158
|
+
}
|
|
8159
|
+
}
|
|
8160
|
+
};
|
|
8161
|
+
var isEntityInCollection = (items, pkName, entity) => {
|
|
8162
|
+
if (items.includes(entity)) return true;
|
|
8163
|
+
const entityPk = entity[pkName];
|
|
8164
|
+
if (entityPk === void 0 || entityPk === null) return false;
|
|
8165
|
+
return items.some((item) => toKey8(item[pkName]) === toKey8(entityPk));
|
|
8166
|
+
};
|
|
8167
|
+
var findInCollectionByPk = (items, pkName, pkValue) => {
|
|
8168
|
+
if (pkValue === void 0 || pkValue === null) return void 0;
|
|
8169
|
+
return items.find((item) => toKey8(item[pkName]) === toKey8(pkValue));
|
|
8170
|
+
};
|
|
8171
|
+
var handleHasMany = async (session, root, relationName, relation, payload, options) => {
|
|
8172
|
+
if (!Array.isArray(payload)) return;
|
|
8173
|
+
const collection = root[relationName];
|
|
8174
|
+
await collection.load();
|
|
8175
|
+
const targetTable = relation.target;
|
|
8176
|
+
const targetPk = findPrimaryKey(targetTable);
|
|
8177
|
+
const existing = collection.getItems();
|
|
8178
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8179
|
+
for (const item of payload) {
|
|
8180
|
+
if (item === null || item === void 0) continue;
|
|
8181
|
+
const asObj = typeof item === "object" ? item : { [targetPk]: item };
|
|
8182
|
+
const pkValue = asObj[targetPk];
|
|
8183
|
+
const current = findInCollectionByPk(existing, targetPk, pkValue) ?? (pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) : void 0);
|
|
8184
|
+
const entity = current ?? ensureEntity(session, targetTable, asObj);
|
|
8185
|
+
assignColumns(targetTable, entity, asObj);
|
|
8186
|
+
await applyGraphToEntity(session, targetTable, entity, asObj, options);
|
|
8187
|
+
if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
|
|
8188
|
+
collection.attach(entity);
|
|
8189
|
+
}
|
|
8190
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
8191
|
+
seen.add(toKey8(pkValue));
|
|
8192
|
+
}
|
|
8193
|
+
}
|
|
8194
|
+
if (options.pruneMissing) {
|
|
8195
|
+
for (const item of [...collection.getItems()]) {
|
|
8196
|
+
const pkValue = item[targetPk];
|
|
8197
|
+
if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
|
|
8198
|
+
collection.remove(item);
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
}
|
|
8202
|
+
};
|
|
8203
|
+
var handleHasOne = async (session, root, relationName, relation, payload, options) => {
|
|
8204
|
+
const ref = root[relationName];
|
|
8205
|
+
if (payload === void 0) return;
|
|
8206
|
+
if (payload === null) {
|
|
8207
|
+
ref.set(null);
|
|
8208
|
+
return;
|
|
8209
|
+
}
|
|
8210
|
+
const pk = findPrimaryKey(relation.target);
|
|
8211
|
+
if (typeof payload === "number" || typeof payload === "string") {
|
|
8212
|
+
const entity = ref.set({ [pk]: payload });
|
|
8213
|
+
if (entity) {
|
|
8214
|
+
await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
|
|
8215
|
+
}
|
|
8216
|
+
return;
|
|
8217
|
+
}
|
|
8218
|
+
const attached = ref.set(payload);
|
|
8219
|
+
if (attached) {
|
|
8220
|
+
await applyGraphToEntity(session, relation.target, attached, payload, options);
|
|
8221
|
+
}
|
|
8222
|
+
};
|
|
8223
|
+
var handleBelongsTo = async (session, root, relationName, relation, payload, options) => {
|
|
8224
|
+
const ref = root[relationName];
|
|
8225
|
+
if (payload === void 0) return;
|
|
8226
|
+
if (payload === null) {
|
|
8227
|
+
ref.set(null);
|
|
8228
|
+
return;
|
|
8229
|
+
}
|
|
8230
|
+
const pk = relation.localKey || findPrimaryKey(relation.target);
|
|
8231
|
+
if (typeof payload === "number" || typeof payload === "string") {
|
|
8232
|
+
const entity = ref.set({ [pk]: payload });
|
|
8233
|
+
if (entity) {
|
|
8234
|
+
await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
|
|
8235
|
+
}
|
|
8236
|
+
return;
|
|
8237
|
+
}
|
|
8238
|
+
const attached = ref.set(payload);
|
|
8239
|
+
if (attached) {
|
|
8240
|
+
await applyGraphToEntity(session, relation.target, attached, payload, options);
|
|
8241
|
+
}
|
|
8242
|
+
};
|
|
8243
|
+
var handleBelongsToMany = async (session, root, relationName, relation, payload, options) => {
|
|
8244
|
+
if (!Array.isArray(payload)) return;
|
|
8245
|
+
const collection = root[relationName];
|
|
8246
|
+
await collection.load();
|
|
8247
|
+
const targetTable = relation.target;
|
|
8248
|
+
const targetPk = relation.targetKey || findPrimaryKey(targetTable);
|
|
8249
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8250
|
+
for (const item of payload) {
|
|
8251
|
+
if (item === null || item === void 0) continue;
|
|
8252
|
+
if (typeof item === "number" || typeof item === "string") {
|
|
8253
|
+
const id = item;
|
|
8254
|
+
collection.attach(id);
|
|
8255
|
+
seen.add(toKey8(id));
|
|
8256
|
+
continue;
|
|
8257
|
+
}
|
|
8258
|
+
const asObj = item;
|
|
8259
|
+
const pkValue = asObj[targetPk];
|
|
8260
|
+
const entity = pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) ?? ensureEntity(session, targetTable, asObj) : ensureEntity(session, targetTable, asObj);
|
|
8261
|
+
assignColumns(targetTable, entity, asObj);
|
|
8262
|
+
await applyGraphToEntity(session, targetTable, entity, asObj, options);
|
|
8263
|
+
if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
|
|
8264
|
+
collection.attach(entity);
|
|
8265
|
+
}
|
|
8266
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
8267
|
+
seen.add(toKey8(pkValue));
|
|
8268
|
+
}
|
|
8269
|
+
}
|
|
8270
|
+
if (options.pruneMissing) {
|
|
8271
|
+
for (const item of [...collection.getItems()]) {
|
|
8272
|
+
const pkValue = item[targetPk];
|
|
8273
|
+
if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
|
|
8274
|
+
collection.detach(item);
|
|
8275
|
+
}
|
|
8276
|
+
}
|
|
8277
|
+
}
|
|
8278
|
+
};
|
|
8279
|
+
var applyRelation = async (session, table, entity, relationName, relation, payload, options) => {
|
|
8280
|
+
switch (relation.type) {
|
|
8281
|
+
case RelationKinds.HasMany:
|
|
8282
|
+
return handleHasMany(session, entity, relationName, relation, payload, options);
|
|
8283
|
+
case RelationKinds.HasOne:
|
|
8284
|
+
return handleHasOne(session, entity, relationName, relation, payload, options);
|
|
8285
|
+
case RelationKinds.BelongsTo:
|
|
8286
|
+
return handleBelongsTo(session, entity, relationName, relation, payload, options);
|
|
8287
|
+
case RelationKinds.BelongsToMany:
|
|
8288
|
+
return handleBelongsToMany(session, entity, relationName, relation, payload, options);
|
|
8289
|
+
}
|
|
8290
|
+
};
|
|
8291
|
+
var applyGraphToEntity = async (session, table, entity, payload, options) => {
|
|
8292
|
+
assignColumns(table, entity, payload);
|
|
8293
|
+
for (const [relationName, relation] of Object.entries(table.relations)) {
|
|
8294
|
+
if (!(relationName in payload)) continue;
|
|
8295
|
+
await applyRelation(session, table, entity, relationName, relation, payload[relationName], options);
|
|
8296
|
+
}
|
|
8297
|
+
};
|
|
8298
|
+
var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
|
|
8299
|
+
const table = getTableDefFromEntity(entityClass);
|
|
8300
|
+
if (!table) {
|
|
8301
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
8302
|
+
}
|
|
8303
|
+
const root = ensureEntity(session, table, payload);
|
|
8304
|
+
await applyGraphToEntity(session, table, root, payload, options);
|
|
8305
|
+
return root;
|
|
8306
|
+
};
|
|
8307
|
+
|
|
7666
8308
|
// src/orm/orm-session.ts
|
|
7667
8309
|
var OrmSession = class {
|
|
8310
|
+
/**
|
|
8311
|
+
* Creates a new OrmSession instance.
|
|
8312
|
+
* @param opts - Session options
|
|
8313
|
+
*/
|
|
7668
8314
|
constructor(opts) {
|
|
8315
|
+
/**
|
|
8316
|
+
* Registers a relation change.
|
|
8317
|
+
* @param root - The root entity
|
|
8318
|
+
* @param relationKey - The relation key
|
|
8319
|
+
* @param rootTable - The root table definition
|
|
8320
|
+
* @param relationName - The relation name
|
|
8321
|
+
* @param relation - The relation definition
|
|
8322
|
+
* @param change - The relation change
|
|
8323
|
+
*/
|
|
7669
8324
|
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
7670
8325
|
this.relationChanges.registerChange(
|
|
7671
8326
|
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
@@ -7679,42 +8334,117 @@ var OrmSession = class {
|
|
|
7679
8334
|
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
7680
8335
|
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
7681
8336
|
}
|
|
8337
|
+
/**
|
|
8338
|
+
* Releases resources associated with this session (executor/pool leases) and resets tracking.
|
|
8339
|
+
* Must be safe to call multiple times.
|
|
8340
|
+
*/
|
|
8341
|
+
async dispose() {
|
|
8342
|
+
try {
|
|
8343
|
+
await this.executor.dispose();
|
|
8344
|
+
} finally {
|
|
8345
|
+
this.unitOfWork.reset();
|
|
8346
|
+
this.relationChanges.reset();
|
|
8347
|
+
}
|
|
8348
|
+
}
|
|
8349
|
+
/**
|
|
8350
|
+
* Gets the database dialect.
|
|
8351
|
+
*/
|
|
7682
8352
|
get dialect() {
|
|
7683
8353
|
return this.orm.dialect;
|
|
7684
8354
|
}
|
|
8355
|
+
/**
|
|
8356
|
+
* Gets the identity buckets map.
|
|
8357
|
+
*/
|
|
7685
8358
|
get identityBuckets() {
|
|
7686
8359
|
return this.unitOfWork.identityBuckets;
|
|
7687
8360
|
}
|
|
8361
|
+
/**
|
|
8362
|
+
* Gets all tracked entities.
|
|
8363
|
+
*/
|
|
7688
8364
|
get tracked() {
|
|
7689
8365
|
return this.unitOfWork.getTracked();
|
|
7690
8366
|
}
|
|
8367
|
+
/**
|
|
8368
|
+
* Gets an entity by table and primary key.
|
|
8369
|
+
* @param table - The table definition
|
|
8370
|
+
* @param pk - The primary key value
|
|
8371
|
+
* @returns The entity or undefined if not found
|
|
8372
|
+
*/
|
|
7691
8373
|
getEntity(table, pk) {
|
|
7692
8374
|
return this.unitOfWork.getEntity(table, pk);
|
|
7693
8375
|
}
|
|
8376
|
+
/**
|
|
8377
|
+
* Sets an entity in the identity map.
|
|
8378
|
+
* @param table - The table definition
|
|
8379
|
+
* @param pk - The primary key value
|
|
8380
|
+
* @param entity - The entity instance
|
|
8381
|
+
*/
|
|
7694
8382
|
setEntity(table, pk, entity) {
|
|
7695
8383
|
this.unitOfWork.setEntity(table, pk, entity);
|
|
7696
8384
|
}
|
|
8385
|
+
/**
|
|
8386
|
+
* Tracks a new entity.
|
|
8387
|
+
* @param table - The table definition
|
|
8388
|
+
* @param entity - The entity instance
|
|
8389
|
+
* @param pk - Optional primary key value
|
|
8390
|
+
*/
|
|
7697
8391
|
trackNew(table, entity, pk) {
|
|
7698
8392
|
this.unitOfWork.trackNew(table, entity, pk);
|
|
7699
8393
|
}
|
|
8394
|
+
/**
|
|
8395
|
+
* Tracks a managed entity.
|
|
8396
|
+
* @param table - The table definition
|
|
8397
|
+
* @param pk - The primary key value
|
|
8398
|
+
* @param entity - The entity instance
|
|
8399
|
+
*/
|
|
7700
8400
|
trackManaged(table, pk, entity) {
|
|
7701
8401
|
this.unitOfWork.trackManaged(table, pk, entity);
|
|
7702
8402
|
}
|
|
8403
|
+
/**
|
|
8404
|
+
* Marks an entity as dirty (modified).
|
|
8405
|
+
* @param entity - The entity to mark as dirty
|
|
8406
|
+
*/
|
|
7703
8407
|
markDirty(entity) {
|
|
7704
8408
|
this.unitOfWork.markDirty(entity);
|
|
7705
8409
|
}
|
|
8410
|
+
/**
|
|
8411
|
+
* Marks an entity as removed.
|
|
8412
|
+
* @param entity - The entity to mark as removed
|
|
8413
|
+
*/
|
|
7706
8414
|
markRemoved(entity) {
|
|
7707
8415
|
this.unitOfWork.markRemoved(entity);
|
|
7708
8416
|
}
|
|
8417
|
+
/**
|
|
8418
|
+
* Gets all tracked entities for a specific table.
|
|
8419
|
+
* @param table - The table definition
|
|
8420
|
+
* @returns Array of tracked entities
|
|
8421
|
+
*/
|
|
7709
8422
|
getEntitiesForTable(table) {
|
|
7710
8423
|
return this.unitOfWork.getEntitiesForTable(table);
|
|
7711
8424
|
}
|
|
8425
|
+
/**
|
|
8426
|
+
* Registers an interceptor for flush lifecycle hooks.
|
|
8427
|
+
* @param interceptor - The interceptor to register
|
|
8428
|
+
*/
|
|
7712
8429
|
registerInterceptor(interceptor) {
|
|
7713
8430
|
this.interceptors.push(interceptor);
|
|
7714
8431
|
}
|
|
8432
|
+
/**
|
|
8433
|
+
* Registers a domain event handler.
|
|
8434
|
+
* @param type - The event type
|
|
8435
|
+
* @param handler - The event handler
|
|
8436
|
+
*/
|
|
7715
8437
|
registerDomainEventHandler(type, handler) {
|
|
7716
8438
|
this.domainEvents.on(type, handler);
|
|
7717
8439
|
}
|
|
8440
|
+
/**
|
|
8441
|
+
* Finds an entity by its primary key.
|
|
8442
|
+
* @template TCtor - The entity constructor type
|
|
8443
|
+
* @param entityClass - The entity constructor
|
|
8444
|
+
* @param id - The primary key value
|
|
8445
|
+
* @returns The entity instance or null if not found
|
|
8446
|
+
* @throws If entity metadata is not bootstrapped or table has no primary key
|
|
8447
|
+
*/
|
|
7718
8448
|
async find(entityClass, id) {
|
|
7719
8449
|
const table = getTableDefFromEntity(entityClass);
|
|
7720
8450
|
if (!table) {
|
|
@@ -7733,14 +8463,46 @@ var OrmSession = class {
|
|
|
7733
8463
|
const rows = await executeHydrated(this, qb);
|
|
7734
8464
|
return rows[0] ?? null;
|
|
7735
8465
|
}
|
|
8466
|
+
/**
|
|
8467
|
+
* Finds a single entity using a query builder.
|
|
8468
|
+
* @template TTable - The table type
|
|
8469
|
+
* @param qb - The query builder
|
|
8470
|
+
* @returns The first entity instance or null if not found
|
|
8471
|
+
*/
|
|
7736
8472
|
async findOne(qb) {
|
|
7737
8473
|
const limited = qb.limit(1);
|
|
7738
8474
|
const rows = await executeHydrated(this, limited);
|
|
7739
8475
|
return rows[0] ?? null;
|
|
7740
8476
|
}
|
|
8477
|
+
/**
|
|
8478
|
+
* Finds multiple entities using a query builder.
|
|
8479
|
+
* @template TTable - The table type
|
|
8480
|
+
* @param qb - The query builder
|
|
8481
|
+
* @returns Array of entity instances
|
|
8482
|
+
*/
|
|
7741
8483
|
async findMany(qb) {
|
|
7742
8484
|
return executeHydrated(this, qb);
|
|
7743
8485
|
}
|
|
8486
|
+
/**
|
|
8487
|
+
* Saves an entity graph (root + nested relations) based on a DTO-like payload.
|
|
8488
|
+
* @param entityClass - Root entity constructor
|
|
8489
|
+
* @param payload - DTO payload containing column values and nested relations
|
|
8490
|
+
* @param options - Graph save options
|
|
8491
|
+
* @returns The root entity instance
|
|
8492
|
+
*/
|
|
8493
|
+
async saveGraph(entityClass, payload, options) {
|
|
8494
|
+
const { transactional = true, ...graphOptions } = options ?? {};
|
|
8495
|
+
const execute = () => saveGraphInternal(this, entityClass, payload, graphOptions);
|
|
8496
|
+
if (!transactional) {
|
|
8497
|
+
return execute();
|
|
8498
|
+
}
|
|
8499
|
+
return this.transaction(() => execute());
|
|
8500
|
+
}
|
|
8501
|
+
/**
|
|
8502
|
+
* Persists an entity (either inserts or updates).
|
|
8503
|
+
* @param entity - The entity to persist
|
|
8504
|
+
* @throws If entity metadata is not bootstrapped
|
|
8505
|
+
*/
|
|
7744
8506
|
async persist(entity) {
|
|
7745
8507
|
if (this.unitOfWork.findTracked(entity)) {
|
|
7746
8508
|
return;
|
|
@@ -7757,12 +8519,22 @@ var OrmSession = class {
|
|
|
7757
8519
|
this.trackNew(table, entity);
|
|
7758
8520
|
}
|
|
7759
8521
|
}
|
|
8522
|
+
/**
|
|
8523
|
+
* Marks an entity for removal.
|
|
8524
|
+
* @param entity - The entity to remove
|
|
8525
|
+
*/
|
|
7760
8526
|
async remove(entity) {
|
|
7761
8527
|
this.markRemoved(entity);
|
|
7762
8528
|
}
|
|
8529
|
+
/**
|
|
8530
|
+
* Flushes pending changes to the database.
|
|
8531
|
+
*/
|
|
7763
8532
|
async flush() {
|
|
7764
8533
|
await this.unitOfWork.flush();
|
|
7765
8534
|
}
|
|
8535
|
+
/**
|
|
8536
|
+
* Flushes pending changes with interceptors and relation processing.
|
|
8537
|
+
*/
|
|
7766
8538
|
async flushWithHooks() {
|
|
7767
8539
|
for (const interceptor of this.interceptors) {
|
|
7768
8540
|
await interceptor.beforeFlush?.(this);
|
|
@@ -7774,14 +8546,24 @@ var OrmSession = class {
|
|
|
7774
8546
|
await interceptor.afterFlush?.(this);
|
|
7775
8547
|
}
|
|
7776
8548
|
}
|
|
8549
|
+
/**
|
|
8550
|
+
* Commits the current transaction.
|
|
8551
|
+
*/
|
|
7777
8552
|
async commit() {
|
|
7778
8553
|
await runInTransaction(this.executor, async () => {
|
|
7779
8554
|
await this.flushWithHooks();
|
|
7780
8555
|
});
|
|
7781
8556
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
7782
8557
|
}
|
|
8558
|
+
/**
|
|
8559
|
+
* Executes a function within a transaction.
|
|
8560
|
+
* @template T - The return type
|
|
8561
|
+
* @param fn - The function to execute
|
|
8562
|
+
* @returns The result of the function
|
|
8563
|
+
* @throws If the transaction fails
|
|
8564
|
+
*/
|
|
7783
8565
|
async transaction(fn4) {
|
|
7784
|
-
if (!this.executor.
|
|
8566
|
+
if (!this.executor.capabilities.transactions) {
|
|
7785
8567
|
const result = await fn4(this);
|
|
7786
8568
|
await this.commit();
|
|
7787
8569
|
return result;
|
|
@@ -7790,7 +8572,7 @@ var OrmSession = class {
|
|
|
7790
8572
|
try {
|
|
7791
8573
|
const result = await fn4(this);
|
|
7792
8574
|
await this.flushWithHooks();
|
|
7793
|
-
await this.executor.commitTransaction
|
|
8575
|
+
await this.executor.commitTransaction();
|
|
7794
8576
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
7795
8577
|
return result;
|
|
7796
8578
|
} catch (err) {
|
|
@@ -7798,11 +8580,20 @@ var OrmSession = class {
|
|
|
7798
8580
|
throw err;
|
|
7799
8581
|
}
|
|
7800
8582
|
}
|
|
8583
|
+
/**
|
|
8584
|
+
* Rolls back the current transaction.
|
|
8585
|
+
*/
|
|
7801
8586
|
async rollback() {
|
|
7802
|
-
|
|
8587
|
+
if (this.executor.capabilities.transactions) {
|
|
8588
|
+
await this.executor.rollbackTransaction();
|
|
8589
|
+
}
|
|
7803
8590
|
this.unitOfWork.reset();
|
|
7804
8591
|
this.relationChanges.reset();
|
|
7805
8592
|
}
|
|
8593
|
+
/**
|
|
8594
|
+
* Gets the execution context.
|
|
8595
|
+
* @returns The execution context
|
|
8596
|
+
*/
|
|
7806
8597
|
getExecutionContext() {
|
|
7807
8598
|
return {
|
|
7808
8599
|
dialect: this.orm.dialect,
|
|
@@ -7810,6 +8601,10 @@ var OrmSession = class {
|
|
|
7810
8601
|
interceptors: this.orm.interceptors
|
|
7811
8602
|
};
|
|
7812
8603
|
}
|
|
8604
|
+
/**
|
|
8605
|
+
* Gets the hydration context.
|
|
8606
|
+
* @returns The hydration context
|
|
8607
|
+
*/
|
|
7813
8608
|
getHydrationContext() {
|
|
7814
8609
|
return {
|
|
7815
8610
|
identityMap: this.identityMap,
|
|
@@ -7852,29 +8647,49 @@ var InterceptorPipeline = class {
|
|
|
7852
8647
|
|
|
7853
8648
|
// src/orm/orm.ts
|
|
7854
8649
|
var Orm = class {
|
|
8650
|
+
/**
|
|
8651
|
+
* Creates a new ORM instance.
|
|
8652
|
+
* @param opts - ORM options
|
|
8653
|
+
*/
|
|
7855
8654
|
constructor(opts) {
|
|
7856
8655
|
this.dialect = opts.dialect;
|
|
7857
8656
|
this.interceptors = opts.interceptors ?? new InterceptorPipeline();
|
|
7858
8657
|
this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
|
|
7859
8658
|
this.executorFactory = opts.executorFactory;
|
|
7860
8659
|
}
|
|
7861
|
-
|
|
7862
|
-
|
|
8660
|
+
/**
|
|
8661
|
+
* Creates a new ORM session.
|
|
8662
|
+
* @param options - Optional session options
|
|
8663
|
+
* @returns The ORM session
|
|
8664
|
+
*/
|
|
8665
|
+
createSession() {
|
|
8666
|
+
const executor = this.executorFactory.createExecutor();
|
|
7863
8667
|
return new OrmSession({ orm: this, executor });
|
|
7864
8668
|
}
|
|
8669
|
+
/**
|
|
8670
|
+
* Executes a function within a transaction.
|
|
8671
|
+
* @template T - The return type
|
|
8672
|
+
* @param fn - The function to execute
|
|
8673
|
+
* @returns The result of the function
|
|
8674
|
+
* @throws If the transaction fails
|
|
8675
|
+
*/
|
|
7865
8676
|
async transaction(fn4) {
|
|
7866
8677
|
const executor = this.executorFactory.createTransactionalExecutor();
|
|
7867
8678
|
const session = new OrmSession({ orm: this, executor });
|
|
7868
8679
|
try {
|
|
7869
|
-
|
|
7870
|
-
await session.commit();
|
|
7871
|
-
return result;
|
|
8680
|
+
return await session.transaction(() => fn4(session));
|
|
7872
8681
|
} catch (err) {
|
|
7873
|
-
await session.rollback();
|
|
7874
8682
|
throw err;
|
|
7875
8683
|
} finally {
|
|
8684
|
+
await session.dispose();
|
|
7876
8685
|
}
|
|
7877
8686
|
}
|
|
8687
|
+
/**
|
|
8688
|
+
* Shuts down the ORM and releases underlying resources (pools, timers).
|
|
8689
|
+
*/
|
|
8690
|
+
async dispose() {
|
|
8691
|
+
await this.executorFactory.dispose();
|
|
8692
|
+
}
|
|
7878
8693
|
};
|
|
7879
8694
|
|
|
7880
8695
|
// src/decorators/decorator-metadata.ts
|
|
@@ -8133,18 +8948,245 @@ function rowsToQueryResult(rows) {
|
|
|
8133
8948
|
return { columns, values };
|
|
8134
8949
|
}
|
|
8135
8950
|
function createExecutorFromQueryRunner(runner) {
|
|
8951
|
+
const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
|
|
8136
8952
|
return {
|
|
8953
|
+
capabilities: {
|
|
8954
|
+
transactions: supportsTransactions
|
|
8955
|
+
},
|
|
8137
8956
|
async executeSql(sql, params) {
|
|
8138
8957
|
const rows = await runner.query(sql, params);
|
|
8139
8958
|
const result = rowsToQueryResult(rows);
|
|
8140
8959
|
return [result];
|
|
8141
8960
|
},
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8961
|
+
async beginTransaction() {
|
|
8962
|
+
if (!supportsTransactions) {
|
|
8963
|
+
throw new Error("Transactions are not supported by this executor");
|
|
8964
|
+
}
|
|
8965
|
+
await runner.beginTransaction.call(runner);
|
|
8966
|
+
},
|
|
8967
|
+
async commitTransaction() {
|
|
8968
|
+
if (!supportsTransactions) {
|
|
8969
|
+
throw new Error("Transactions are not supported by this executor");
|
|
8970
|
+
}
|
|
8971
|
+
await runner.commitTransaction.call(runner);
|
|
8972
|
+
},
|
|
8973
|
+
async rollbackTransaction() {
|
|
8974
|
+
if (!supportsTransactions) {
|
|
8975
|
+
throw new Error("Transactions are not supported by this executor");
|
|
8976
|
+
}
|
|
8977
|
+
await runner.rollbackTransaction.call(runner);
|
|
8978
|
+
},
|
|
8979
|
+
async dispose() {
|
|
8980
|
+
await runner.dispose?.call(runner);
|
|
8981
|
+
}
|
|
8145
8982
|
};
|
|
8146
8983
|
}
|
|
8147
8984
|
|
|
8985
|
+
// src/core/execution/pooling/pool.ts
|
|
8986
|
+
var deferred = () => {
|
|
8987
|
+
let resolve;
|
|
8988
|
+
let reject;
|
|
8989
|
+
const promise = new Promise((res, rej) => {
|
|
8990
|
+
resolve = res;
|
|
8991
|
+
reject = rej;
|
|
8992
|
+
});
|
|
8993
|
+
return { promise, resolve, reject };
|
|
8994
|
+
};
|
|
8995
|
+
var Pool = class {
|
|
8996
|
+
constructor(adapter, options) {
|
|
8997
|
+
this.destroyed = false;
|
|
8998
|
+
this.creating = 0;
|
|
8999
|
+
this.leased = 0;
|
|
9000
|
+
this.idle = [];
|
|
9001
|
+
this.waiters = [];
|
|
9002
|
+
this.reapTimer = null;
|
|
9003
|
+
if (!Number.isFinite(options.max) || options.max <= 0) {
|
|
9004
|
+
throw new Error("Pool options.max must be a positive number");
|
|
9005
|
+
}
|
|
9006
|
+
this.adapter = adapter;
|
|
9007
|
+
this.options = { max: options.max, ...options };
|
|
9008
|
+
const idleTimeout = this.options.idleTimeoutMillis;
|
|
9009
|
+
if (idleTimeout && idleTimeout > 0) {
|
|
9010
|
+
const interval = this.options.reapIntervalMillis ?? Math.max(1e3, Math.floor(idleTimeout / 2));
|
|
9011
|
+
this.reapTimer = setInterval(() => {
|
|
9012
|
+
void this.reapIdle();
|
|
9013
|
+
}, interval);
|
|
9014
|
+
this.reapTimer.unref?.();
|
|
9015
|
+
}
|
|
9016
|
+
const min2 = this.options.min ?? 0;
|
|
9017
|
+
if (min2 > 0) {
|
|
9018
|
+
void this.warm(min2);
|
|
9019
|
+
}
|
|
9020
|
+
}
|
|
9021
|
+
/**
|
|
9022
|
+
* Acquire a resource lease.
|
|
9023
|
+
* The returned lease MUST be released or destroyed.
|
|
9024
|
+
*/
|
|
9025
|
+
async acquire() {
|
|
9026
|
+
if (this.destroyed) {
|
|
9027
|
+
throw new Error("Pool is destroyed");
|
|
9028
|
+
}
|
|
9029
|
+
const idle = await this.takeIdleValidated();
|
|
9030
|
+
if (idle) {
|
|
9031
|
+
this.leased++;
|
|
9032
|
+
return this.makeLease(idle);
|
|
9033
|
+
}
|
|
9034
|
+
if (this.totalLive() < this.options.max) {
|
|
9035
|
+
this.creating++;
|
|
9036
|
+
try {
|
|
9037
|
+
const created = await this.adapter.create();
|
|
9038
|
+
this.leased++;
|
|
9039
|
+
return this.makeLease(created);
|
|
9040
|
+
} finally {
|
|
9041
|
+
this.creating--;
|
|
9042
|
+
}
|
|
9043
|
+
}
|
|
9044
|
+
const waiter = deferred();
|
|
9045
|
+
this.waiters.push(waiter);
|
|
9046
|
+
const timeout = this.options.acquireTimeoutMillis;
|
|
9047
|
+
let timer = null;
|
|
9048
|
+
if (timeout && timeout > 0) {
|
|
9049
|
+
timer = setTimeout(() => {
|
|
9050
|
+
const idx = this.waiters.indexOf(waiter);
|
|
9051
|
+
if (idx >= 0) this.waiters.splice(idx, 1);
|
|
9052
|
+
waiter.reject(new Error("Pool acquire timeout"));
|
|
9053
|
+
}, timeout);
|
|
9054
|
+
timer.unref?.();
|
|
9055
|
+
}
|
|
9056
|
+
try {
|
|
9057
|
+
return await waiter.promise;
|
|
9058
|
+
} finally {
|
|
9059
|
+
if (timer) clearTimeout(timer);
|
|
9060
|
+
}
|
|
9061
|
+
}
|
|
9062
|
+
/** Destroy pool and all idle resources; waits for in-flight creations to settle. */
|
|
9063
|
+
async destroy() {
|
|
9064
|
+
if (this.destroyed) return;
|
|
9065
|
+
this.destroyed = true;
|
|
9066
|
+
if (this.reapTimer) {
|
|
9067
|
+
clearInterval(this.reapTimer);
|
|
9068
|
+
this.reapTimer = null;
|
|
9069
|
+
}
|
|
9070
|
+
while (this.waiters.length) {
|
|
9071
|
+
this.waiters.shift().reject(new Error("Pool destroyed"));
|
|
9072
|
+
}
|
|
9073
|
+
while (this.idle.length) {
|
|
9074
|
+
const entry = this.idle.shift();
|
|
9075
|
+
await this.adapter.destroy(entry.resource);
|
|
9076
|
+
}
|
|
9077
|
+
}
|
|
9078
|
+
totalLive() {
|
|
9079
|
+
return this.idle.length + this.leased + this.creating;
|
|
9080
|
+
}
|
|
9081
|
+
makeLease(resource) {
|
|
9082
|
+
let done = false;
|
|
9083
|
+
return {
|
|
9084
|
+
resource,
|
|
9085
|
+
release: async () => {
|
|
9086
|
+
if (done) return;
|
|
9087
|
+
done = true;
|
|
9088
|
+
await this.releaseResource(resource);
|
|
9089
|
+
},
|
|
9090
|
+
destroy: async () => {
|
|
9091
|
+
if (done) return;
|
|
9092
|
+
done = true;
|
|
9093
|
+
await this.destroyResource(resource);
|
|
9094
|
+
}
|
|
9095
|
+
};
|
|
9096
|
+
}
|
|
9097
|
+
async releaseResource(resource) {
|
|
9098
|
+
this.leased = Math.max(0, this.leased - 1);
|
|
9099
|
+
if (this.destroyed) {
|
|
9100
|
+
await this.adapter.destroy(resource);
|
|
9101
|
+
return;
|
|
9102
|
+
}
|
|
9103
|
+
const next = this.waiters.shift();
|
|
9104
|
+
if (next) {
|
|
9105
|
+
this.leased++;
|
|
9106
|
+
next.resolve(this.makeLease(resource));
|
|
9107
|
+
return;
|
|
9108
|
+
}
|
|
9109
|
+
this.idle.push({ resource, lastUsedAt: Date.now() });
|
|
9110
|
+
await this.trimToMinMax();
|
|
9111
|
+
}
|
|
9112
|
+
async destroyResource(resource) {
|
|
9113
|
+
this.leased = Math.max(0, this.leased - 1);
|
|
9114
|
+
await this.adapter.destroy(resource);
|
|
9115
|
+
if (!this.destroyed && this.waiters.length && this.totalLive() < this.options.max) {
|
|
9116
|
+
const waiter = this.waiters.shift();
|
|
9117
|
+
this.creating++;
|
|
9118
|
+
try {
|
|
9119
|
+
const created = await this.adapter.create();
|
|
9120
|
+
this.leased++;
|
|
9121
|
+
waiter.resolve(this.makeLease(created));
|
|
9122
|
+
} catch (err) {
|
|
9123
|
+
waiter.reject(err);
|
|
9124
|
+
} finally {
|
|
9125
|
+
this.creating--;
|
|
9126
|
+
}
|
|
9127
|
+
}
|
|
9128
|
+
}
|
|
9129
|
+
async takeIdleValidated() {
|
|
9130
|
+
while (this.idle.length) {
|
|
9131
|
+
const entry = this.idle.pop();
|
|
9132
|
+
if (!this.adapter.validate) {
|
|
9133
|
+
return entry.resource;
|
|
9134
|
+
}
|
|
9135
|
+
const ok = await this.adapter.validate(entry.resource);
|
|
9136
|
+
if (ok) {
|
|
9137
|
+
return entry.resource;
|
|
9138
|
+
}
|
|
9139
|
+
await this.adapter.destroy(entry.resource);
|
|
9140
|
+
}
|
|
9141
|
+
return null;
|
|
9142
|
+
}
|
|
9143
|
+
async reapIdle() {
|
|
9144
|
+
if (this.destroyed) return;
|
|
9145
|
+
const idleTimeout = this.options.idleTimeoutMillis;
|
|
9146
|
+
if (!idleTimeout || idleTimeout <= 0) return;
|
|
9147
|
+
const now2 = Date.now();
|
|
9148
|
+
const min2 = this.options.min ?? 0;
|
|
9149
|
+
const keep = [];
|
|
9150
|
+
const kill = [];
|
|
9151
|
+
for (const entry of this.idle) {
|
|
9152
|
+
const expired = now2 - entry.lastUsedAt >= idleTimeout;
|
|
9153
|
+
if (expired) kill.push(entry);
|
|
9154
|
+
else keep.push(entry);
|
|
9155
|
+
}
|
|
9156
|
+
while (keep.length < min2 && kill.length) {
|
|
9157
|
+
keep.push(kill.pop());
|
|
9158
|
+
}
|
|
9159
|
+
this.idle.length = 0;
|
|
9160
|
+
this.idle.push(...keep);
|
|
9161
|
+
for (const entry of kill) {
|
|
9162
|
+
await this.adapter.destroy(entry.resource);
|
|
9163
|
+
}
|
|
9164
|
+
}
|
|
9165
|
+
async warm(targetMin) {
|
|
9166
|
+
const min2 = Math.max(0, targetMin);
|
|
9167
|
+
while (!this.destroyed && this.idle.length < min2 && this.totalLive() < this.options.max) {
|
|
9168
|
+
this.creating++;
|
|
9169
|
+
try {
|
|
9170
|
+
const created = await this.adapter.create();
|
|
9171
|
+
this.idle.push({ resource: created, lastUsedAt: Date.now() });
|
|
9172
|
+
} catch {
|
|
9173
|
+
break;
|
|
9174
|
+
} finally {
|
|
9175
|
+
this.creating--;
|
|
9176
|
+
}
|
|
9177
|
+
}
|
|
9178
|
+
}
|
|
9179
|
+
async trimToMinMax() {
|
|
9180
|
+
const max2 = this.options.max;
|
|
9181
|
+
const min2 = this.options.min ?? 0;
|
|
9182
|
+
while (this.totalLive() > max2 && this.idle.length > min2) {
|
|
9183
|
+
const entry = this.idle.shift();
|
|
9184
|
+
if (!entry) break;
|
|
9185
|
+
await this.adapter.destroy(entry.resource);
|
|
9186
|
+
}
|
|
9187
|
+
}
|
|
9188
|
+
};
|
|
9189
|
+
|
|
8148
9190
|
// src/core/execution/executors/postgres-executor.ts
|
|
8149
9191
|
function createPostgresExecutor(client) {
|
|
8150
9192
|
return createExecutorFromQueryRunner({
|
|
@@ -8166,7 +9208,11 @@ function createPostgresExecutor(client) {
|
|
|
8166
9208
|
|
|
8167
9209
|
// src/core/execution/executors/mysql-executor.ts
|
|
8168
9210
|
function createMysqlExecutor(client) {
|
|
9211
|
+
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
8169
9212
|
return {
|
|
9213
|
+
capabilities: {
|
|
9214
|
+
transactions: supportsTransactions
|
|
9215
|
+
},
|
|
8170
9216
|
async executeSql(sql, params) {
|
|
8171
9217
|
const [rows] = await client.query(sql, params);
|
|
8172
9218
|
if (!Array.isArray(rows)) {
|
|
@@ -8178,53 +9224,94 @@ function createMysqlExecutor(client) {
|
|
|
8178
9224
|
return [result];
|
|
8179
9225
|
},
|
|
8180
9226
|
async beginTransaction() {
|
|
8181
|
-
if (!
|
|
9227
|
+
if (!supportsTransactions) {
|
|
9228
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9229
|
+
}
|
|
8182
9230
|
await client.beginTransaction();
|
|
8183
9231
|
},
|
|
8184
9232
|
async commitTransaction() {
|
|
8185
|
-
if (!
|
|
9233
|
+
if (!supportsTransactions) {
|
|
9234
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9235
|
+
}
|
|
8186
9236
|
await client.commit();
|
|
8187
9237
|
},
|
|
8188
9238
|
async rollbackTransaction() {
|
|
8189
|
-
if (!
|
|
9239
|
+
if (!supportsTransactions) {
|
|
9240
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9241
|
+
}
|
|
8190
9242
|
await client.rollback();
|
|
9243
|
+
},
|
|
9244
|
+
async dispose() {
|
|
8191
9245
|
}
|
|
8192
9246
|
};
|
|
8193
9247
|
}
|
|
8194
9248
|
|
|
8195
9249
|
// src/core/execution/executors/sqlite-executor.ts
|
|
8196
9250
|
function createSqliteExecutor(client) {
|
|
9251
|
+
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commitTransaction === "function" && typeof client.rollbackTransaction === "function";
|
|
8197
9252
|
return {
|
|
9253
|
+
capabilities: {
|
|
9254
|
+
transactions: supportsTransactions
|
|
9255
|
+
},
|
|
8198
9256
|
async executeSql(sql, params) {
|
|
8199
9257
|
const rows = await client.all(sql, params);
|
|
8200
9258
|
const result = rowsToQueryResult(rows);
|
|
8201
9259
|
return [result];
|
|
8202
9260
|
},
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
9261
|
+
async beginTransaction() {
|
|
9262
|
+
if (!supportsTransactions) {
|
|
9263
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9264
|
+
}
|
|
9265
|
+
await client.beginTransaction();
|
|
9266
|
+
},
|
|
9267
|
+
async commitTransaction() {
|
|
9268
|
+
if (!supportsTransactions) {
|
|
9269
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9270
|
+
}
|
|
9271
|
+
await client.commitTransaction();
|
|
9272
|
+
},
|
|
9273
|
+
async rollbackTransaction() {
|
|
9274
|
+
if (!supportsTransactions) {
|
|
9275
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9276
|
+
}
|
|
9277
|
+
await client.rollbackTransaction();
|
|
9278
|
+
},
|
|
9279
|
+
async dispose() {
|
|
9280
|
+
}
|
|
8206
9281
|
};
|
|
8207
9282
|
}
|
|
8208
9283
|
|
|
8209
9284
|
// src/core/execution/executors/mssql-executor.ts
|
|
8210
9285
|
function createMssqlExecutor(client) {
|
|
9286
|
+
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
8211
9287
|
return {
|
|
9288
|
+
capabilities: {
|
|
9289
|
+
transactions: supportsTransactions
|
|
9290
|
+
},
|
|
8212
9291
|
async executeSql(sql, params) {
|
|
8213
9292
|
const { recordset } = await client.query(sql, params);
|
|
8214
9293
|
const result = rowsToQueryResult(recordset ?? []);
|
|
8215
9294
|
return [result];
|
|
8216
9295
|
},
|
|
8217
9296
|
async beginTransaction() {
|
|
8218
|
-
if (!
|
|
9297
|
+
if (!supportsTransactions) {
|
|
9298
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9299
|
+
}
|
|
8219
9300
|
await client.beginTransaction();
|
|
8220
9301
|
},
|
|
8221
9302
|
async commitTransaction() {
|
|
8222
|
-
if (!
|
|
9303
|
+
if (!supportsTransactions) {
|
|
9304
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9305
|
+
}
|
|
8223
9306
|
await client.commit();
|
|
8224
9307
|
},
|
|
8225
9308
|
async rollbackTransaction() {
|
|
8226
|
-
if (!
|
|
9309
|
+
if (!supportsTransactions) {
|
|
9310
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9311
|
+
}
|
|
8227
9312
|
await client.rollback();
|
|
9313
|
+
},
|
|
9314
|
+
async dispose() {
|
|
8228
9315
|
}
|
|
8229
9316
|
};
|
|
8230
9317
|
}
|
|
@@ -8293,6 +9380,86 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8293
9380
|
const client = createTediousMssqlClient(connection, module2, options);
|
|
8294
9381
|
return createMssqlExecutor(client);
|
|
8295
9382
|
}
|
|
9383
|
+
|
|
9384
|
+
// src/orm/pooled-executor-factory.ts
|
|
9385
|
+
function createPooledExecutorFactory(opts) {
|
|
9386
|
+
const { pool, adapter } = opts;
|
|
9387
|
+
const makeExecutor = (mode) => {
|
|
9388
|
+
let lease = null;
|
|
9389
|
+
const getLease = async () => {
|
|
9390
|
+
if (lease) return lease;
|
|
9391
|
+
lease = await pool.acquire();
|
|
9392
|
+
return lease;
|
|
9393
|
+
};
|
|
9394
|
+
const executeWithConn = async (conn, sql, params) => {
|
|
9395
|
+
const rows = await adapter.query(conn, sql, params);
|
|
9396
|
+
return [rowsToQueryResult(rows)];
|
|
9397
|
+
};
|
|
9398
|
+
return {
|
|
9399
|
+
capabilities: { transactions: true },
|
|
9400
|
+
async executeSql(sql, params) {
|
|
9401
|
+
if (mode === "sticky") {
|
|
9402
|
+
const l2 = await getLease();
|
|
9403
|
+
return executeWithConn(l2.resource, sql, params);
|
|
9404
|
+
}
|
|
9405
|
+
if (lease) {
|
|
9406
|
+
return executeWithConn(lease.resource, sql, params);
|
|
9407
|
+
}
|
|
9408
|
+
const l = await pool.acquire();
|
|
9409
|
+
try {
|
|
9410
|
+
return await executeWithConn(l.resource, sql, params);
|
|
9411
|
+
} finally {
|
|
9412
|
+
await l.release();
|
|
9413
|
+
}
|
|
9414
|
+
},
|
|
9415
|
+
async beginTransaction() {
|
|
9416
|
+
const l = await getLease();
|
|
9417
|
+
await adapter.beginTransaction(l.resource);
|
|
9418
|
+
},
|
|
9419
|
+
async commitTransaction() {
|
|
9420
|
+
if (!lease) {
|
|
9421
|
+
throw new Error("commitTransaction called without an active transaction");
|
|
9422
|
+
}
|
|
9423
|
+
const l = lease;
|
|
9424
|
+
try {
|
|
9425
|
+
await adapter.commitTransaction(l.resource);
|
|
9426
|
+
} finally {
|
|
9427
|
+
lease = null;
|
|
9428
|
+
await l.release();
|
|
9429
|
+
}
|
|
9430
|
+
},
|
|
9431
|
+
async rollbackTransaction() {
|
|
9432
|
+
if (!lease) {
|
|
9433
|
+
return;
|
|
9434
|
+
}
|
|
9435
|
+
const l = lease;
|
|
9436
|
+
try {
|
|
9437
|
+
await adapter.rollbackTransaction(l.resource);
|
|
9438
|
+
} finally {
|
|
9439
|
+
lease = null;
|
|
9440
|
+
await l.release();
|
|
9441
|
+
}
|
|
9442
|
+
},
|
|
9443
|
+
async dispose() {
|
|
9444
|
+
if (!lease) return;
|
|
9445
|
+
const l = lease;
|
|
9446
|
+
lease = null;
|
|
9447
|
+
await l.release();
|
|
9448
|
+
}
|
|
9449
|
+
};
|
|
9450
|
+
};
|
|
9451
|
+
return {
|
|
9452
|
+
createExecutor() {
|
|
9453
|
+
return makeExecutor("session");
|
|
9454
|
+
},
|
|
9455
|
+
createTransactionalExecutor() {
|
|
9456
|
+
return makeExecutor("sticky");
|
|
9457
|
+
},
|
|
9458
|
+
async dispose() {
|
|
9459
|
+
await pool.destroy();
|
|
9460
|
+
}
|
|
9461
|
+
};
|
|
9462
|
+
}
|
|
8296
9463
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8297
9464
|
0 && (module.exports = {
|
|
8298
9465
|
AsyncLocalStorage,
|
|
@@ -8312,6 +9479,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8312
9479
|
MySqlDialect,
|
|
8313
9480
|
Orm,
|
|
8314
9481
|
OrmSession,
|
|
9482
|
+
Pool,
|
|
8315
9483
|
PostgresDialect,
|
|
8316
9484
|
PrimaryKey,
|
|
8317
9485
|
RelationKinds,
|
|
@@ -8357,6 +9525,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8357
9525
|
createLiteral,
|
|
8358
9526
|
createMssqlExecutor,
|
|
8359
9527
|
createMysqlExecutor,
|
|
9528
|
+
createPooledExecutorFactory,
|
|
8360
9529
|
createPostgresExecutor,
|
|
8361
9530
|
createQueryLoggingExecutor,
|
|
8362
9531
|
createSqliteExecutor,
|
|
@@ -8398,6 +9567,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8398
9567
|
hasOne,
|
|
8399
9568
|
hydrateRows,
|
|
8400
9569
|
inList,
|
|
9570
|
+
inSubquery,
|
|
8401
9571
|
instr,
|
|
8402
9572
|
introspectSchema,
|
|
8403
9573
|
isCaseExpressionNode,
|
|
@@ -8438,6 +9608,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8438
9608
|
notBetween,
|
|
8439
9609
|
notExists,
|
|
8440
9610
|
notInList,
|
|
9611
|
+
notInSubquery,
|
|
8441
9612
|
notLike,
|
|
8442
9613
|
now,
|
|
8443
9614
|
ntile,
|
|
@@ -8473,6 +9644,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8473
9644
|
substr,
|
|
8474
9645
|
sum,
|
|
8475
9646
|
synchronizeSchema,
|
|
9647
|
+
tableRef,
|
|
8476
9648
|
tan,
|
|
8477
9649
|
toColumnRef,
|
|
8478
9650
|
toTableRef,
|