metal-orm 1.0.15 → 1.0.17
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 +64 -61
- package/dist/decorators/index.cjs +490 -175
- package/dist/decorators/index.cjs.map +1 -1
- package/dist/decorators/index.d.cts +1 -5
- package/dist/decorators/index.d.ts +1 -5
- package/dist/decorators/index.js +490 -175
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +1044 -483
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -15
- package/dist/index.d.ts +67 -15
- package/dist/index.js +1033 -482
- package/dist/index.js.map +1 -1
- package/dist/{select-Bkv8g8u_.d.cts → select-BPCn6MOH.d.cts} +486 -32
- package/dist/{select-Bkv8g8u_.d.ts → select-BPCn6MOH.d.ts} +486 -32
- package/package.json +2 -1
- package/src/codegen/naming-strategy.ts +64 -0
- package/src/codegen/typescript.ts +48 -53
- package/src/core/ast/aggregate-functions.ts +50 -4
- package/src/core/ast/expression-builders.ts +22 -15
- package/src/core/ast/expression-nodes.ts +6 -0
- package/src/core/ddl/introspect/functions/postgres.ts +2 -6
- package/src/core/ddl/schema-generator.ts +3 -2
- package/src/core/ddl/schema-introspect.ts +1 -1
- package/src/core/dialect/abstract.ts +40 -8
- package/src/core/dialect/mssql/functions.ts +24 -15
- package/src/core/dialect/postgres/functions.ts +33 -24
- package/src/core/dialect/sqlite/functions.ts +19 -12
- package/src/core/functions/datetime.ts +2 -1
- package/src/core/functions/numeric.ts +2 -1
- package/src/core/functions/standard-strategy.ts +52 -12
- package/src/core/functions/text.ts +2 -1
- package/src/core/functions/types.ts +8 -8
- package/src/decorators/column.ts +13 -4
- package/src/index.ts +13 -5
- package/src/orm/domain-event-bus.ts +43 -25
- package/src/orm/entity-context.ts +30 -0
- package/src/orm/entity-meta.ts +42 -2
- package/src/orm/entity-metadata.ts +1 -6
- package/src/orm/entity.ts +88 -88
- package/src/orm/execute.ts +42 -25
- package/src/orm/execution-context.ts +18 -0
- package/src/orm/hydration-context.ts +16 -0
- package/src/orm/identity-map.ts +4 -0
- package/src/orm/interceptor-pipeline.ts +29 -0
- package/src/orm/lazy-batch.ts +6 -6
- package/src/orm/orm-session.ts +245 -0
- package/src/orm/orm.ts +58 -0
- package/src/orm/query-logger.ts +15 -0
- package/src/orm/relation-change-processor.ts +5 -1
- package/src/orm/relations/belongs-to.ts +45 -44
- package/src/orm/relations/has-many.ts +44 -43
- package/src/orm/relations/has-one.ts +140 -139
- package/src/orm/relations/many-to-many.ts +46 -45
- package/src/orm/runtime-types.ts +60 -2
- package/src/orm/transaction-runner.ts +7 -0
- package/src/orm/unit-of-work.ts +7 -1
- package/src/query-builder/insert-query-state.ts +13 -3
- package/src/query-builder/select-helpers.ts +50 -0
- package/src/query-builder/select.ts +616 -18
- package/src/query-builder/update-query-state.ts +31 -9
- package/src/schema/types.ts +16 -6
- package/src/orm/orm-context.ts +0 -159
package/dist/index.js
CHANGED
|
@@ -237,10 +237,13 @@ var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressi
|
|
|
237
237
|
|
|
238
238
|
// src/core/ast/expression-builders.ts
|
|
239
239
|
var valueToOperand = (value) => {
|
|
240
|
-
if (value
|
|
241
|
-
return
|
|
240
|
+
if (isOperandNode(value)) {
|
|
241
|
+
return value;
|
|
242
242
|
}
|
|
243
|
-
return
|
|
243
|
+
return {
|
|
244
|
+
type: "Literal",
|
|
245
|
+
value
|
|
246
|
+
};
|
|
244
247
|
};
|
|
245
248
|
var toNode = (col2) => {
|
|
246
249
|
if (isOperandNode(col2)) return col2;
|
|
@@ -251,10 +254,11 @@ var toLiteralNode = (value) => ({
|
|
|
251
254
|
type: "Literal",
|
|
252
255
|
value
|
|
253
256
|
});
|
|
257
|
+
var isLiteralValue = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
258
|
+
var isValueOperandInput = (value) => isOperandNode(value) || isLiteralValue(value);
|
|
254
259
|
var toOperand = (val) => {
|
|
255
|
-
if (val
|
|
256
|
-
|
|
257
|
-
return { type: "Literal", value: val };
|
|
260
|
+
if (isLiteralValue(val)) {
|
|
261
|
+
return valueToOperand(val);
|
|
258
262
|
}
|
|
259
263
|
return toNode(val);
|
|
260
264
|
};
|
|
@@ -400,6 +404,62 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
|
|
|
400
404
|
return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
|
|
401
405
|
};
|
|
402
406
|
|
|
407
|
+
// src/core/sql/sql.ts
|
|
408
|
+
var SQL_OPERATORS = {
|
|
409
|
+
/** Equality operator */
|
|
410
|
+
EQUALS: "=",
|
|
411
|
+
/** Not equals operator */
|
|
412
|
+
NOT_EQUALS: "!=",
|
|
413
|
+
/** Greater than operator */
|
|
414
|
+
GREATER_THAN: ">",
|
|
415
|
+
/** Greater than or equal operator */
|
|
416
|
+
GREATER_OR_EQUAL: ">=",
|
|
417
|
+
/** Less than operator */
|
|
418
|
+
LESS_THAN: "<",
|
|
419
|
+
/** Less than or equal operator */
|
|
420
|
+
LESS_OR_EQUAL: "<=",
|
|
421
|
+
/** LIKE pattern matching operator */
|
|
422
|
+
LIKE: "LIKE",
|
|
423
|
+
/** NOT LIKE pattern matching operator */
|
|
424
|
+
NOT_LIKE: "NOT LIKE",
|
|
425
|
+
/** IN membership operator */
|
|
426
|
+
IN: "IN",
|
|
427
|
+
/** NOT IN membership operator */
|
|
428
|
+
NOT_IN: "NOT IN",
|
|
429
|
+
/** BETWEEN range operator */
|
|
430
|
+
BETWEEN: "BETWEEN",
|
|
431
|
+
/** NOT BETWEEN range operator */
|
|
432
|
+
NOT_BETWEEN: "NOT BETWEEN",
|
|
433
|
+
/** IS NULL null check operator */
|
|
434
|
+
IS_NULL: "IS NULL",
|
|
435
|
+
/** IS NOT NULL null check operator */
|
|
436
|
+
IS_NOT_NULL: "IS NOT NULL",
|
|
437
|
+
/** Logical AND operator */
|
|
438
|
+
AND: "AND",
|
|
439
|
+
/** Logical OR operator */
|
|
440
|
+
OR: "OR",
|
|
441
|
+
/** EXISTS operator */
|
|
442
|
+
EXISTS: "EXISTS",
|
|
443
|
+
/** NOT EXISTS operator */
|
|
444
|
+
NOT_EXISTS: "NOT EXISTS"
|
|
445
|
+
};
|
|
446
|
+
var JOIN_KINDS = {
|
|
447
|
+
/** INNER JOIN type */
|
|
448
|
+
INNER: "INNER",
|
|
449
|
+
/** LEFT JOIN type */
|
|
450
|
+
LEFT: "LEFT",
|
|
451
|
+
/** RIGHT JOIN type */
|
|
452
|
+
RIGHT: "RIGHT",
|
|
453
|
+
/** CROSS JOIN type */
|
|
454
|
+
CROSS: "CROSS"
|
|
455
|
+
};
|
|
456
|
+
var ORDER_DIRECTIONS = {
|
|
457
|
+
/** Ascending order */
|
|
458
|
+
ASC: "ASC",
|
|
459
|
+
/** Descending order */
|
|
460
|
+
DESC: "DESC"
|
|
461
|
+
};
|
|
462
|
+
|
|
403
463
|
// src/core/ast/aggregate-functions.ts
|
|
404
464
|
var buildAggregate = (name) => (col2) => ({
|
|
405
465
|
type: "Function",
|
|
@@ -409,6 +469,20 @@ var buildAggregate = (name) => (col2) => ({
|
|
|
409
469
|
var count = buildAggregate("COUNT");
|
|
410
470
|
var sum = buildAggregate("SUM");
|
|
411
471
|
var avg = buildAggregate("AVG");
|
|
472
|
+
var min = buildAggregate("MIN");
|
|
473
|
+
var max = buildAggregate("MAX");
|
|
474
|
+
var toOrderByNode = (order) => ({
|
|
475
|
+
type: "OrderBy",
|
|
476
|
+
column: columnOperand(order.column),
|
|
477
|
+
direction: order.direction ?? ORDER_DIRECTIONS.ASC
|
|
478
|
+
});
|
|
479
|
+
var groupConcat = (col2, options) => ({
|
|
480
|
+
type: "Function",
|
|
481
|
+
name: "GROUP_CONCAT",
|
|
482
|
+
args: [columnOperand(col2)],
|
|
483
|
+
orderBy: options?.orderBy?.map(toOrderByNode),
|
|
484
|
+
separator: options?.separator !== void 0 ? valueToOperand(options.separator) : void 0
|
|
485
|
+
});
|
|
412
486
|
|
|
413
487
|
// src/core/ast/expression-visitor.ts
|
|
414
488
|
var expressionDispatchers = /* @__PURE__ */ new Map();
|
|
@@ -500,12 +574,17 @@ var toTableRef = (table) => ({
|
|
|
500
574
|
});
|
|
501
575
|
|
|
502
576
|
// src/core/functions/standard-strategy.ts
|
|
503
|
-
var StandardFunctionStrategy = class {
|
|
577
|
+
var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
504
578
|
constructor() {
|
|
505
579
|
this.renderers = /* @__PURE__ */ new Map();
|
|
506
580
|
this.registerStandard();
|
|
507
581
|
}
|
|
508
582
|
registerStandard() {
|
|
583
|
+
this.add("COUNT", ({ compiledArgs }) => `COUNT(${compiledArgs.join(", ")})`);
|
|
584
|
+
this.add("SUM", ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
|
|
585
|
+
this.add("AVG", ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
|
|
586
|
+
this.add("MIN", ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
|
|
587
|
+
this.add("MAX", ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
|
|
509
588
|
this.add("ABS", ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
|
|
510
589
|
this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
|
|
511
590
|
this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
|
|
@@ -532,6 +611,7 @@ var StandardFunctionStrategy = class {
|
|
|
532
611
|
this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
|
|
533
612
|
this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
|
|
534
613
|
this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
614
|
+
this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
|
|
535
615
|
}
|
|
536
616
|
add(name, renderer) {
|
|
537
617
|
this.renderers.set(name, renderer);
|
|
@@ -539,10 +619,40 @@ var StandardFunctionStrategy = class {
|
|
|
539
619
|
getRenderer(name) {
|
|
540
620
|
return this.renderers.get(name);
|
|
541
621
|
}
|
|
622
|
+
renderGroupConcat(ctx) {
|
|
623
|
+
const arg = ctx.compiledArgs[0];
|
|
624
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
625
|
+
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
626
|
+
const separatorClause = this.formatGroupConcatSeparator(ctx);
|
|
627
|
+
return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
|
|
628
|
+
}
|
|
629
|
+
buildOrderByExpression(ctx) {
|
|
630
|
+
const orderBy = ctx.node.orderBy;
|
|
631
|
+
if (!orderBy || orderBy.length === 0) {
|
|
632
|
+
return "";
|
|
633
|
+
}
|
|
634
|
+
const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
|
|
635
|
+
return `ORDER BY ${parts.join(", ")}`;
|
|
636
|
+
}
|
|
637
|
+
formatGroupConcatSeparator(ctx) {
|
|
638
|
+
if (!ctx.node.separator) {
|
|
639
|
+
return "";
|
|
640
|
+
}
|
|
641
|
+
return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
|
|
642
|
+
}
|
|
643
|
+
getGroupConcatSeparatorOperand(ctx) {
|
|
644
|
+
return ctx.node.separator ?? _StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
645
|
+
}
|
|
646
|
+
static {
|
|
647
|
+
this.DEFAULT_GROUP_CONCAT_SEPARATOR = {
|
|
648
|
+
type: "Literal",
|
|
649
|
+
value: ","
|
|
650
|
+
};
|
|
651
|
+
}
|
|
542
652
|
};
|
|
543
653
|
|
|
544
654
|
// src/core/dialect/abstract.ts
|
|
545
|
-
var Dialect = class {
|
|
655
|
+
var Dialect = class _Dialect {
|
|
546
656
|
/**
|
|
547
657
|
* Compiles a SELECT query AST to SQL
|
|
548
658
|
* @param ast - Query AST to compile
|
|
@@ -715,6 +825,35 @@ var Dialect = class {
|
|
|
715
825
|
this.registerDefaultOperandCompilers();
|
|
716
826
|
this.registerDefaultExpressionCompilers();
|
|
717
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* Creates a new Dialect instance (for testing purposes)
|
|
830
|
+
* @param functionStrategy - Optional function strategy
|
|
831
|
+
* @returns New Dialect instance
|
|
832
|
+
*/
|
|
833
|
+
static create(functionStrategy) {
|
|
834
|
+
class TestDialect extends _Dialect {
|
|
835
|
+
constructor() {
|
|
836
|
+
super(...arguments);
|
|
837
|
+
this.dialect = "sqlite";
|
|
838
|
+
}
|
|
839
|
+
quoteIdentifier(id) {
|
|
840
|
+
return `"${id}"`;
|
|
841
|
+
}
|
|
842
|
+
compileSelectAst() {
|
|
843
|
+
throw new Error("Not implemented");
|
|
844
|
+
}
|
|
845
|
+
compileInsertAst() {
|
|
846
|
+
throw new Error("Not implemented");
|
|
847
|
+
}
|
|
848
|
+
compileUpdateAst() {
|
|
849
|
+
throw new Error("Not implemented");
|
|
850
|
+
}
|
|
851
|
+
compileDeleteAst() {
|
|
852
|
+
throw new Error("Not implemented");
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
return new TestDialect(functionStrategy);
|
|
856
|
+
}
|
|
718
857
|
/**
|
|
719
858
|
* Registers an expression compiler for a specific node type
|
|
720
859
|
* @param type - Expression node type
|
|
@@ -856,7 +995,11 @@ var Dialect = class {
|
|
|
856
995
|
const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
|
|
857
996
|
const renderer = this.functionStrategy.getRenderer(fnNode.name);
|
|
858
997
|
if (renderer) {
|
|
859
|
-
return renderer({
|
|
998
|
+
return renderer({
|
|
999
|
+
node: fnNode,
|
|
1000
|
+
compiledArgs,
|
|
1001
|
+
compileOperand: (operand) => this.compileOperand(operand, ctx)
|
|
1002
|
+
});
|
|
860
1003
|
}
|
|
861
1004
|
return `${fnNode.name}(${compiledArgs.join(", ")})`;
|
|
862
1005
|
}
|
|
@@ -1279,6 +1422,14 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1279
1422
|
const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
|
|
1280
1423
|
return `DATE_TRUNC('${partClean}', ${date})`;
|
|
1281
1424
|
});
|
|
1425
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1426
|
+
const arg = ctx.compiledArgs[0];
|
|
1427
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
1428
|
+
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
1429
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1430
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1431
|
+
return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
|
|
1432
|
+
});
|
|
1282
1433
|
}
|
|
1283
1434
|
};
|
|
1284
1435
|
|
|
@@ -1523,6 +1674,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1523
1674
|
}
|
|
1524
1675
|
return `date(${date}, 'start of ${partClean}')`;
|
|
1525
1676
|
});
|
|
1677
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1678
|
+
const arg = ctx.compiledArgs[0];
|
|
1679
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1680
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1681
|
+
return `GROUP_CONCAT(${arg}, ${separator})`;
|
|
1682
|
+
});
|
|
1526
1683
|
}
|
|
1527
1684
|
};
|
|
1528
1685
|
|
|
@@ -1639,6 +1796,14 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1639
1796
|
const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
|
|
1640
1797
|
return `DATETRUNC(${partClean}, ${date})`;
|
|
1641
1798
|
});
|
|
1799
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1800
|
+
const arg = ctx.compiledArgs[0];
|
|
1801
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1802
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1803
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
1804
|
+
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
|
|
1805
|
+
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
1806
|
+
});
|
|
1642
1807
|
}
|
|
1643
1808
|
};
|
|
1644
1809
|
|
|
@@ -2008,62 +2173,6 @@ var createJoinNode = (kind, tableName, condition, relationName) => ({
|
|
|
2008
2173
|
meta: relationName ? { relationName } : void 0
|
|
2009
2174
|
});
|
|
2010
2175
|
|
|
2011
|
-
// src/core/sql/sql.ts
|
|
2012
|
-
var SQL_OPERATORS = {
|
|
2013
|
-
/** Equality operator */
|
|
2014
|
-
EQUALS: "=",
|
|
2015
|
-
/** Not equals operator */
|
|
2016
|
-
NOT_EQUALS: "!=",
|
|
2017
|
-
/** Greater than operator */
|
|
2018
|
-
GREATER_THAN: ">",
|
|
2019
|
-
/** Greater than or equal operator */
|
|
2020
|
-
GREATER_OR_EQUAL: ">=",
|
|
2021
|
-
/** Less than operator */
|
|
2022
|
-
LESS_THAN: "<",
|
|
2023
|
-
/** Less than or equal operator */
|
|
2024
|
-
LESS_OR_EQUAL: "<=",
|
|
2025
|
-
/** LIKE pattern matching operator */
|
|
2026
|
-
LIKE: "LIKE",
|
|
2027
|
-
/** NOT LIKE pattern matching operator */
|
|
2028
|
-
NOT_LIKE: "NOT LIKE",
|
|
2029
|
-
/** IN membership operator */
|
|
2030
|
-
IN: "IN",
|
|
2031
|
-
/** NOT IN membership operator */
|
|
2032
|
-
NOT_IN: "NOT IN",
|
|
2033
|
-
/** BETWEEN range operator */
|
|
2034
|
-
BETWEEN: "BETWEEN",
|
|
2035
|
-
/** NOT BETWEEN range operator */
|
|
2036
|
-
NOT_BETWEEN: "NOT BETWEEN",
|
|
2037
|
-
/** IS NULL null check operator */
|
|
2038
|
-
IS_NULL: "IS NULL",
|
|
2039
|
-
/** IS NOT NULL null check operator */
|
|
2040
|
-
IS_NOT_NULL: "IS NOT NULL",
|
|
2041
|
-
/** Logical AND operator */
|
|
2042
|
-
AND: "AND",
|
|
2043
|
-
/** Logical OR operator */
|
|
2044
|
-
OR: "OR",
|
|
2045
|
-
/** EXISTS operator */
|
|
2046
|
-
EXISTS: "EXISTS",
|
|
2047
|
-
/** NOT EXISTS operator */
|
|
2048
|
-
NOT_EXISTS: "NOT EXISTS"
|
|
2049
|
-
};
|
|
2050
|
-
var JOIN_KINDS = {
|
|
2051
|
-
/** INNER JOIN type */
|
|
2052
|
-
INNER: "INNER",
|
|
2053
|
-
/** LEFT JOIN type */
|
|
2054
|
-
LEFT: "LEFT",
|
|
2055
|
-
/** RIGHT JOIN type */
|
|
2056
|
-
RIGHT: "RIGHT",
|
|
2057
|
-
/** CROSS JOIN type */
|
|
2058
|
-
CROSS: "CROSS"
|
|
2059
|
-
};
|
|
2060
|
-
var ORDER_DIRECTIONS = {
|
|
2061
|
-
/** Ascending order */
|
|
2062
|
-
ASC: "ASC",
|
|
2063
|
-
/** Descending order */
|
|
2064
|
-
DESC: "DESC"
|
|
2065
|
-
};
|
|
2066
|
-
|
|
2067
2176
|
// src/query-builder/hydration-manager.ts
|
|
2068
2177
|
var HydrationManager = class _HydrationManager {
|
|
2069
2178
|
/**
|
|
@@ -4107,31 +4216,43 @@ var flattenResults = (results) => {
|
|
|
4107
4216
|
}
|
|
4108
4217
|
return rows;
|
|
4109
4218
|
};
|
|
4110
|
-
async
|
|
4219
|
+
var executeWithEntityContext = async (entityCtx, qb) => {
|
|
4111
4220
|
const ast = qb.getAST();
|
|
4112
|
-
const compiled =
|
|
4113
|
-
const executed = await
|
|
4221
|
+
const compiled = entityCtx.dialect.compileSelect(ast);
|
|
4222
|
+
const executed = await entityCtx.executor.executeSql(compiled.sql, compiled.params);
|
|
4114
4223
|
const rows = flattenResults(executed);
|
|
4115
4224
|
if (ast.setOps && ast.setOps.length > 0) {
|
|
4116
|
-
return rows.map(
|
|
4117
|
-
(row) => createEntityProxy(ctx, qb.getTable(), row, qb.getLazyRelations())
|
|
4118
|
-
);
|
|
4225
|
+
return rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4119
4226
|
}
|
|
4120
4227
|
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
4121
|
-
return hydrated.map(
|
|
4122
|
-
|
|
4123
|
-
|
|
4228
|
+
return hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4229
|
+
};
|
|
4230
|
+
async function executeHydrated(session, qb) {
|
|
4231
|
+
return executeWithEntityContext(session, qb);
|
|
4232
|
+
}
|
|
4233
|
+
async function executeHydratedWithContexts(_execCtx, hydCtx, qb) {
|
|
4234
|
+
const entityCtx = hydCtx.entityContext;
|
|
4235
|
+
if (!entityCtx) {
|
|
4236
|
+
throw new Error("Hydration context is missing an EntityContext");
|
|
4237
|
+
}
|
|
4238
|
+
return executeWithEntityContext(entityCtx, qb);
|
|
4124
4239
|
}
|
|
4125
4240
|
|
|
4126
4241
|
// src/query-builder/select.ts
|
|
4127
4242
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
4128
4243
|
/**
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4244
|
+
|
|
4245
|
+
* Creates a new SelectQueryBuilder instance
|
|
4246
|
+
|
|
4247
|
+
* @param table - Table definition to query
|
|
4248
|
+
|
|
4249
|
+
* @param state - Optional initial query state
|
|
4250
|
+
|
|
4251
|
+
* @param hydration - Optional hydration manager
|
|
4252
|
+
|
|
4253
|
+
* @param dependencies - Optional query builder dependencies
|
|
4254
|
+
|
|
4255
|
+
*/
|
|
4135
4256
|
constructor(table, state, hydration, dependencies, lazyRelations) {
|
|
4136
4257
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
4137
4258
|
this.env = { table, deps };
|
|
@@ -4168,112 +4289,183 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4168
4289
|
return this.applyAst(this.context, (service) => service.withSetOperation(operator, subAst));
|
|
4169
4290
|
}
|
|
4170
4291
|
/**
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4292
|
+
|
|
4293
|
+
* Selects specific columns for the query
|
|
4294
|
+
|
|
4295
|
+
* @param columns - Record of column definitions, function nodes, case expressions, or window functions
|
|
4296
|
+
|
|
4297
|
+
* @returns New query builder instance with selected columns
|
|
4298
|
+
|
|
4299
|
+
*/
|
|
4175
4300
|
select(columns) {
|
|
4176
4301
|
return this.clone(this.columnSelector.select(this.context, columns));
|
|
4177
4302
|
}
|
|
4178
4303
|
/**
|
|
4179
|
-
* Selects
|
|
4180
|
-
* @param cols - Column
|
|
4181
|
-
* @returns New query builder instance with raw column selections
|
|
4304
|
+
* Selects columns from the root table by name (typed).
|
|
4305
|
+
* @param cols - Column names on the root table
|
|
4182
4306
|
*/
|
|
4307
|
+
selectColumns(...cols) {
|
|
4308
|
+
const selection = {};
|
|
4309
|
+
for (const key of cols) {
|
|
4310
|
+
const col2 = this.env.table.columns[key];
|
|
4311
|
+
if (!col2) {
|
|
4312
|
+
throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
|
|
4313
|
+
}
|
|
4314
|
+
selection[key] = col2;
|
|
4315
|
+
}
|
|
4316
|
+
return this.select(selection);
|
|
4317
|
+
}
|
|
4318
|
+
/**
|
|
4319
|
+
|
|
4320
|
+
* Selects raw column expressions
|
|
4321
|
+
|
|
4322
|
+
* @param cols - Column expressions as strings
|
|
4323
|
+
|
|
4324
|
+
* @returns New query builder instance with raw column selections
|
|
4325
|
+
|
|
4326
|
+
*/
|
|
4183
4327
|
selectRaw(...cols) {
|
|
4184
4328
|
return this.clone(this.columnSelector.selectRaw(this.context, cols));
|
|
4185
4329
|
}
|
|
4186
4330
|
/**
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4331
|
+
|
|
4332
|
+
* Adds a Common Table Expression (CTE) to the query
|
|
4333
|
+
|
|
4334
|
+
* @param name - Name of the CTE
|
|
4335
|
+
|
|
4336
|
+
* @param query - Query builder or query node for the CTE
|
|
4337
|
+
|
|
4338
|
+
* @param columns - Optional column names for the CTE
|
|
4339
|
+
|
|
4340
|
+
* @returns New query builder instance with the CTE
|
|
4341
|
+
|
|
4342
|
+
*/
|
|
4193
4343
|
with(name, query, columns) {
|
|
4194
4344
|
const subAst = this.resolveQueryNode(query);
|
|
4195
4345
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, false));
|
|
4196
4346
|
return this.clone(nextContext);
|
|
4197
4347
|
}
|
|
4198
4348
|
/**
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4349
|
+
|
|
4350
|
+
* Adds a recursive Common Table Expression (CTE) to the query
|
|
4351
|
+
|
|
4352
|
+
* @param name - Name of the CTE
|
|
4353
|
+
|
|
4354
|
+
* @param query - Query builder or query node for the CTE
|
|
4355
|
+
|
|
4356
|
+
* @param columns - Optional column names for the CTE
|
|
4357
|
+
|
|
4358
|
+
* @returns New query builder instance with the recursive CTE
|
|
4359
|
+
|
|
4360
|
+
*/
|
|
4205
4361
|
withRecursive(name, query, columns) {
|
|
4206
4362
|
const subAst = this.resolveQueryNode(query);
|
|
4207
4363
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4208
4364
|
return this.clone(nextContext);
|
|
4209
4365
|
}
|
|
4210
4366
|
/**
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4367
|
+
|
|
4368
|
+
* Selects a subquery as a column
|
|
4369
|
+
|
|
4370
|
+
* @param alias - Alias for the subquery column
|
|
4371
|
+
|
|
4372
|
+
* @param sub - Query builder or query node for the subquery
|
|
4373
|
+
|
|
4374
|
+
* @returns New query builder instance with the subquery selection
|
|
4375
|
+
|
|
4376
|
+
*/
|
|
4216
4377
|
selectSubquery(alias, sub) {
|
|
4217
4378
|
const query = this.resolveQueryNode(sub);
|
|
4218
4379
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4219
4380
|
}
|
|
4220
4381
|
/**
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4382
|
+
|
|
4383
|
+
* Adds an INNER JOIN to the query
|
|
4384
|
+
|
|
4385
|
+
* @param table - Table to join
|
|
4386
|
+
|
|
4387
|
+
* @param condition - Join condition expression
|
|
4388
|
+
|
|
4389
|
+
* @returns New query builder instance with the INNER JOIN
|
|
4390
|
+
|
|
4391
|
+
*/
|
|
4226
4392
|
innerJoin(table, condition) {
|
|
4227
4393
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
4228
4394
|
return this.clone(nextContext);
|
|
4229
4395
|
}
|
|
4230
4396
|
/**
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4397
|
+
|
|
4398
|
+
* Adds a LEFT JOIN to the query
|
|
4399
|
+
|
|
4400
|
+
* @param table - Table to join
|
|
4401
|
+
|
|
4402
|
+
* @param condition - Join condition expression
|
|
4403
|
+
|
|
4404
|
+
* @returns New query builder instance with the LEFT JOIN
|
|
4405
|
+
|
|
4406
|
+
*/
|
|
4236
4407
|
leftJoin(table, condition) {
|
|
4237
4408
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
4238
4409
|
return this.clone(nextContext);
|
|
4239
4410
|
}
|
|
4240
4411
|
/**
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4412
|
+
|
|
4413
|
+
* Adds a RIGHT JOIN to the query
|
|
4414
|
+
|
|
4415
|
+
* @param table - Table to join
|
|
4416
|
+
|
|
4417
|
+
* @param condition - Join condition expression
|
|
4418
|
+
|
|
4419
|
+
* @returns New query builder instance with the RIGHT JOIN
|
|
4420
|
+
|
|
4421
|
+
*/
|
|
4246
4422
|
rightJoin(table, condition) {
|
|
4247
4423
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
4248
4424
|
return this.clone(nextContext);
|
|
4249
4425
|
}
|
|
4250
4426
|
/**
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4427
|
+
|
|
4428
|
+
* Matches records based on a relationship
|
|
4429
|
+
|
|
4430
|
+
* @param relationName - Name of the relationship to match
|
|
4431
|
+
|
|
4432
|
+
* @param predicate - Optional predicate expression
|
|
4433
|
+
|
|
4434
|
+
* @returns New query builder instance with the relationship match
|
|
4435
|
+
|
|
4436
|
+
*/
|
|
4256
4437
|
match(relationName, predicate) {
|
|
4257
4438
|
const nextContext = this.relationManager.match(this.context, relationName, predicate);
|
|
4258
4439
|
return this.clone(nextContext);
|
|
4259
4440
|
}
|
|
4260
4441
|
/**
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4442
|
+
|
|
4443
|
+
* Joins a related table
|
|
4444
|
+
|
|
4445
|
+
* @param relationName - Name of the relationship to join
|
|
4446
|
+
|
|
4447
|
+
* @param joinKind - Type of join (defaults to INNER)
|
|
4448
|
+
|
|
4449
|
+
* @param extraCondition - Optional additional join condition
|
|
4450
|
+
|
|
4451
|
+
* @returns New query builder instance with the relationship join
|
|
4452
|
+
|
|
4453
|
+
*/
|
|
4267
4454
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
4268
4455
|
const nextContext = this.relationManager.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
4269
4456
|
return this.clone(nextContext);
|
|
4270
4457
|
}
|
|
4271
4458
|
/**
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4459
|
+
|
|
4460
|
+
* Includes related data in the query results
|
|
4461
|
+
|
|
4462
|
+
* @param relationName - Name of the relationship to include
|
|
4463
|
+
|
|
4464
|
+
* @param options - Optional include options
|
|
4465
|
+
|
|
4466
|
+
* @returns New query builder instance with the relationship inclusion
|
|
4467
|
+
|
|
4468
|
+
*/
|
|
4277
4469
|
include(relationName, options) {
|
|
4278
4470
|
const nextContext = this.relationManager.include(this.context, relationName, options);
|
|
4279
4471
|
return this.clone(nextContext);
|
|
@@ -4283,6 +4475,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4283
4475
|
nextLazy.add(relationName);
|
|
4284
4476
|
return this.clone(this.context, nextLazy);
|
|
4285
4477
|
}
|
|
4478
|
+
/**
|
|
4479
|
+
* Selects columns for a related table in a single hop.
|
|
4480
|
+
*/
|
|
4481
|
+
selectRelationColumns(relationName, ...cols) {
|
|
4482
|
+
const relation = this.env.table.relations[relationName];
|
|
4483
|
+
if (!relation) {
|
|
4484
|
+
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4485
|
+
}
|
|
4486
|
+
const target = relation.target;
|
|
4487
|
+
for (const col2 of cols) {
|
|
4488
|
+
if (!target.columns[col2]) {
|
|
4489
|
+
throw new Error(
|
|
4490
|
+
`Column '${col2}' not found on related table '${target.name}' for relation '${relationName}'`
|
|
4491
|
+
);
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
return this.include(relationName, { columns: cols });
|
|
4495
|
+
}
|
|
4496
|
+
/**
|
|
4497
|
+
* Convenience alias for selecting specific columns from a relation.
|
|
4498
|
+
*/
|
|
4499
|
+
includePick(relationName, cols) {
|
|
4500
|
+
return this.selectRelationColumns(relationName, ...cols);
|
|
4501
|
+
}
|
|
4502
|
+
/**
|
|
4503
|
+
* Selects columns for the root table and relations from a single config object.
|
|
4504
|
+
*/
|
|
4505
|
+
selectColumnsDeep(config) {
|
|
4506
|
+
let qb = this;
|
|
4507
|
+
if (config.root?.length) {
|
|
4508
|
+
qb = qb.selectColumns(...config.root);
|
|
4509
|
+
}
|
|
4510
|
+
for (const key of Object.keys(config)) {
|
|
4511
|
+
if (key === "root") continue;
|
|
4512
|
+
const relName = key;
|
|
4513
|
+
const cols = config[relName];
|
|
4514
|
+
if (!cols || !cols.length) continue;
|
|
4515
|
+
qb = qb.selectRelationColumns(relName, ...cols);
|
|
4516
|
+
}
|
|
4517
|
+
return qb;
|
|
4518
|
+
}
|
|
4286
4519
|
getLazyRelations() {
|
|
4287
4520
|
return Array.from(this.lazyRelations);
|
|
4288
4521
|
}
|
|
@@ -4292,125 +4525,186 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4292
4525
|
async execute(ctx) {
|
|
4293
4526
|
return executeHydrated(ctx, this);
|
|
4294
4527
|
}
|
|
4528
|
+
async executeWithContexts(execCtx, hydCtx) {
|
|
4529
|
+
return executeHydratedWithContexts(execCtx, hydCtx, this);
|
|
4530
|
+
}
|
|
4295
4531
|
/**
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4532
|
+
|
|
4533
|
+
* Adds a WHERE condition to the query
|
|
4534
|
+
|
|
4535
|
+
* @param expr - Expression for the WHERE clause
|
|
4536
|
+
|
|
4537
|
+
* @returns New query builder instance with the WHERE condition
|
|
4538
|
+
|
|
4539
|
+
*/
|
|
4300
4540
|
where(expr) {
|
|
4301
4541
|
const nextContext = this.applyAst(this.context, (service) => service.withWhere(expr));
|
|
4302
4542
|
return this.clone(nextContext);
|
|
4303
4543
|
}
|
|
4304
4544
|
/**
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4545
|
+
|
|
4546
|
+
* Adds a GROUP BY clause to the query
|
|
4547
|
+
|
|
4548
|
+
* @param col - Column definition or column node to group by
|
|
4549
|
+
|
|
4550
|
+
* @returns New query builder instance with the GROUP BY clause
|
|
4551
|
+
|
|
4552
|
+
*/
|
|
4309
4553
|
groupBy(col2) {
|
|
4310
4554
|
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(col2));
|
|
4311
4555
|
return this.clone(nextContext);
|
|
4312
4556
|
}
|
|
4313
4557
|
/**
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4558
|
+
|
|
4559
|
+
* Adds a HAVING condition to the query
|
|
4560
|
+
|
|
4561
|
+
* @param expr - Expression for the HAVING clause
|
|
4562
|
+
|
|
4563
|
+
* @returns New query builder instance with the HAVING condition
|
|
4564
|
+
|
|
4565
|
+
*/
|
|
4318
4566
|
having(expr) {
|
|
4319
4567
|
const nextContext = this.applyAst(this.context, (service) => service.withHaving(expr));
|
|
4320
4568
|
return this.clone(nextContext);
|
|
4321
4569
|
}
|
|
4322
4570
|
/**
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4571
|
+
|
|
4572
|
+
* Adds an ORDER BY clause to the query
|
|
4573
|
+
|
|
4574
|
+
* @param col - Column definition or column node to order by
|
|
4575
|
+
|
|
4576
|
+
* @param direction - Order direction (defaults to ASC)
|
|
4577
|
+
|
|
4578
|
+
* @returns New query builder instance with the ORDER BY clause
|
|
4579
|
+
|
|
4580
|
+
*/
|
|
4328
4581
|
orderBy(col2, direction = ORDER_DIRECTIONS.ASC) {
|
|
4329
4582
|
const nextContext = this.applyAst(this.context, (service) => service.withOrderBy(col2, direction));
|
|
4330
4583
|
return this.clone(nextContext);
|
|
4331
4584
|
}
|
|
4332
4585
|
/**
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4586
|
+
|
|
4587
|
+
* Adds a DISTINCT clause to the query
|
|
4588
|
+
|
|
4589
|
+
* @param cols - Columns to make distinct
|
|
4590
|
+
|
|
4591
|
+
* @returns New query builder instance with the DISTINCT clause
|
|
4592
|
+
|
|
4593
|
+
*/
|
|
4337
4594
|
distinct(...cols) {
|
|
4338
4595
|
return this.clone(this.columnSelector.distinct(this.context, cols));
|
|
4339
4596
|
}
|
|
4340
4597
|
/**
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4598
|
+
|
|
4599
|
+
* Adds a LIMIT clause to the query
|
|
4600
|
+
|
|
4601
|
+
* @param n - Maximum number of rows to return
|
|
4602
|
+
|
|
4603
|
+
* @returns New query builder instance with the LIMIT clause
|
|
4604
|
+
|
|
4605
|
+
*/
|
|
4345
4606
|
limit(n) {
|
|
4346
4607
|
const nextContext = this.applyAst(this.context, (service) => service.withLimit(n));
|
|
4347
4608
|
return this.clone(nextContext);
|
|
4348
4609
|
}
|
|
4349
4610
|
/**
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4611
|
+
|
|
4612
|
+
* Adds an OFFSET clause to the query
|
|
4613
|
+
|
|
4614
|
+
* @param n - Number of rows to skip
|
|
4615
|
+
|
|
4616
|
+
* @returns New query builder instance with the OFFSET clause
|
|
4617
|
+
|
|
4618
|
+
*/
|
|
4354
4619
|
offset(n) {
|
|
4355
4620
|
const nextContext = this.applyAst(this.context, (service) => service.withOffset(n));
|
|
4356
4621
|
return this.clone(nextContext);
|
|
4357
4622
|
}
|
|
4358
4623
|
/**
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4624
|
+
|
|
4625
|
+
* Combines this query with another using UNION
|
|
4626
|
+
|
|
4627
|
+
* @param query - Query to union with
|
|
4628
|
+
|
|
4629
|
+
* @returns New query builder instance with the set operation
|
|
4630
|
+
|
|
4631
|
+
*/
|
|
4363
4632
|
union(query) {
|
|
4364
4633
|
return this.clone(this.applySetOperation("UNION", query));
|
|
4365
4634
|
}
|
|
4366
4635
|
/**
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4636
|
+
|
|
4637
|
+
* Combines this query with another using UNION ALL
|
|
4638
|
+
|
|
4639
|
+
* @param query - Query to union with
|
|
4640
|
+
|
|
4641
|
+
* @returns New query builder instance with the set operation
|
|
4642
|
+
|
|
4643
|
+
*/
|
|
4371
4644
|
unionAll(query) {
|
|
4372
4645
|
return this.clone(this.applySetOperation("UNION ALL", query));
|
|
4373
4646
|
}
|
|
4374
4647
|
/**
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4648
|
+
|
|
4649
|
+
* Combines this query with another using INTERSECT
|
|
4650
|
+
|
|
4651
|
+
* @param query - Query to intersect with
|
|
4652
|
+
|
|
4653
|
+
* @returns New query builder instance with the set operation
|
|
4654
|
+
|
|
4655
|
+
*/
|
|
4379
4656
|
intersect(query) {
|
|
4380
4657
|
return this.clone(this.applySetOperation("INTERSECT", query));
|
|
4381
4658
|
}
|
|
4382
4659
|
/**
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4660
|
+
|
|
4661
|
+
* Combines this query with another using EXCEPT
|
|
4662
|
+
|
|
4663
|
+
* @param query - Query to subtract
|
|
4664
|
+
|
|
4665
|
+
* @returns New query builder instance with the set operation
|
|
4666
|
+
|
|
4667
|
+
*/
|
|
4387
4668
|
except(query) {
|
|
4388
4669
|
return this.clone(this.applySetOperation("EXCEPT", query));
|
|
4389
4670
|
}
|
|
4390
4671
|
/**
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4672
|
+
|
|
4673
|
+
* Adds a WHERE EXISTS condition to the query
|
|
4674
|
+
|
|
4675
|
+
* @param subquery - Subquery to check for existence
|
|
4676
|
+
|
|
4677
|
+
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4678
|
+
|
|
4679
|
+
*/
|
|
4395
4680
|
whereExists(subquery) {
|
|
4396
4681
|
const subAst = this.resolveQueryNode(subquery);
|
|
4397
4682
|
return this.where(exists(subAst));
|
|
4398
4683
|
}
|
|
4399
4684
|
/**
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4685
|
+
|
|
4686
|
+
* Adds a WHERE NOT EXISTS condition to the query
|
|
4687
|
+
|
|
4688
|
+
* @param subquery - Subquery to check for non-existence
|
|
4689
|
+
|
|
4690
|
+
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4691
|
+
|
|
4692
|
+
*/
|
|
4404
4693
|
whereNotExists(subquery) {
|
|
4405
4694
|
const subAst = this.resolveQueryNode(subquery);
|
|
4406
4695
|
return this.where(notExists(subAst));
|
|
4407
4696
|
}
|
|
4408
4697
|
/**
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4698
|
+
|
|
4699
|
+
* Adds a WHERE EXISTS condition based on a relationship
|
|
4700
|
+
|
|
4701
|
+
* @param relationName - Name of the relationship to check
|
|
4702
|
+
|
|
4703
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4704
|
+
|
|
4705
|
+
* @returns New query builder instance with the relationship existence check
|
|
4706
|
+
|
|
4707
|
+
*/
|
|
4414
4708
|
whereHas(relationName, callback) {
|
|
4415
4709
|
const relation = this.env.table.relations[relationName];
|
|
4416
4710
|
if (!relation) {
|
|
@@ -4425,11 +4719,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4425
4719
|
return this.where(exists(finalSubAst));
|
|
4426
4720
|
}
|
|
4427
4721
|
/**
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4722
|
+
|
|
4723
|
+
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
4724
|
+
|
|
4725
|
+
* @param relationName - Name of the relationship to check
|
|
4726
|
+
|
|
4727
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4728
|
+
|
|
4729
|
+
* @returns New query builder instance with the relationship non-existence check
|
|
4730
|
+
|
|
4731
|
+
*/
|
|
4433
4732
|
whereHasNot(relationName, callback) {
|
|
4434
4733
|
const relation = this.env.table.relations[relationName];
|
|
4435
4734
|
if (!relation) {
|
|
@@ -4444,33 +4743,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4444
4743
|
return this.where(notExists(finalSubAst));
|
|
4445
4744
|
}
|
|
4446
4745
|
/**
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4746
|
+
|
|
4747
|
+
* Compiles the query to SQL for a specific dialect
|
|
4748
|
+
|
|
4749
|
+
* @param dialect - Database dialect to compile for
|
|
4750
|
+
|
|
4751
|
+
* @returns Compiled query with SQL and parameters
|
|
4752
|
+
|
|
4753
|
+
*/
|
|
4451
4754
|
compile(dialect) {
|
|
4452
4755
|
const resolved = resolveDialectInput(dialect);
|
|
4453
4756
|
return resolved.compileSelect(this.context.state.ast);
|
|
4454
4757
|
}
|
|
4455
4758
|
/**
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4759
|
+
|
|
4760
|
+
* Converts the query to SQL string for a specific dialect
|
|
4761
|
+
|
|
4762
|
+
* @param dialect - Database dialect to generate SQL for
|
|
4763
|
+
|
|
4764
|
+
* @returns SQL string representation of the query
|
|
4765
|
+
|
|
4766
|
+
*/
|
|
4460
4767
|
toSql(dialect) {
|
|
4461
4768
|
return this.compile(dialect).sql;
|
|
4462
4769
|
}
|
|
4463
4770
|
/**
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4771
|
+
|
|
4772
|
+
* Gets the hydration plan for the query
|
|
4773
|
+
|
|
4774
|
+
* @returns Hydration plan or undefined if none exists
|
|
4775
|
+
|
|
4776
|
+
*/
|
|
4467
4777
|
getHydrationPlan() {
|
|
4468
4778
|
return this.context.hydration.getPlan();
|
|
4469
4779
|
}
|
|
4470
4780
|
/**
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4781
|
+
|
|
4782
|
+
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
4783
|
+
|
|
4784
|
+
* @returns Query AST with hydration applied
|
|
4785
|
+
|
|
4786
|
+
*/
|
|
4474
4787
|
getAST() {
|
|
4475
4788
|
return this.context.hydration.applyToAst(this.context.state.ast);
|
|
4476
4789
|
}
|
|
@@ -4478,6 +4791,54 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4478
4791
|
var createColumn = (table, name) => ({ type: "Column", table, name });
|
|
4479
4792
|
var createLiteral = (val) => ({ type: "Literal", value: val });
|
|
4480
4793
|
|
|
4794
|
+
// src/orm/entity-metadata.ts
|
|
4795
|
+
var metadataMap = /* @__PURE__ */ new Map();
|
|
4796
|
+
var getEntityMetadata = (target) => {
|
|
4797
|
+
return metadataMap.get(target);
|
|
4798
|
+
};
|
|
4799
|
+
|
|
4800
|
+
// src/decorators/bootstrap.ts
|
|
4801
|
+
var getTableDefFromEntity = (ctor) => {
|
|
4802
|
+
const meta = getEntityMetadata(ctor);
|
|
4803
|
+
if (!meta) return void 0;
|
|
4804
|
+
return meta.table;
|
|
4805
|
+
};
|
|
4806
|
+
var selectFromEntity = (ctor) => {
|
|
4807
|
+
const table = getTableDefFromEntity(ctor);
|
|
4808
|
+
if (!table) {
|
|
4809
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
4810
|
+
}
|
|
4811
|
+
return new SelectQueryBuilder(table);
|
|
4812
|
+
};
|
|
4813
|
+
|
|
4814
|
+
// src/query-builder/select-helpers.ts
|
|
4815
|
+
function sel(table, ...cols) {
|
|
4816
|
+
const selection = {};
|
|
4817
|
+
for (const col2 of cols) {
|
|
4818
|
+
const def = table.columns[col2];
|
|
4819
|
+
if (!def) {
|
|
4820
|
+
throw new Error(`Column '${col2}' not found on table '${table.name}'`);
|
|
4821
|
+
}
|
|
4822
|
+
selection[col2] = def;
|
|
4823
|
+
}
|
|
4824
|
+
return selection;
|
|
4825
|
+
}
|
|
4826
|
+
function esel(entity, ...props) {
|
|
4827
|
+
const table = getTableDefFromEntity(entity);
|
|
4828
|
+
if (!table) {
|
|
4829
|
+
throw new Error(`No table definition registered for entity '${entity.name}'`);
|
|
4830
|
+
}
|
|
4831
|
+
const selection = {};
|
|
4832
|
+
for (const prop of props) {
|
|
4833
|
+
const col2 = table.columns[prop];
|
|
4834
|
+
if (!col2) {
|
|
4835
|
+
throw new Error(`No column '${prop}' found for entity '${entity.name}'`);
|
|
4836
|
+
}
|
|
4837
|
+
selection[prop] = col2;
|
|
4838
|
+
}
|
|
4839
|
+
return selection;
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4481
4842
|
// src/query-builder/insert-query-state.ts
|
|
4482
4843
|
var InsertQueryState = class _InsertQueryState {
|
|
4483
4844
|
constructor(table, ast) {
|
|
@@ -4496,7 +4857,15 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
4496
4857
|
if (!rows.length) return this;
|
|
4497
4858
|
const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
|
|
4498
4859
|
const newRows = rows.map(
|
|
4499
|
-
(row) => definedColumns.map((column) =>
|
|
4860
|
+
(row, rowIndex) => definedColumns.map((column) => {
|
|
4861
|
+
const rawValue = row[column.name];
|
|
4862
|
+
if (!isValueOperandInput(rawValue)) {
|
|
4863
|
+
throw new Error(
|
|
4864
|
+
`Invalid insert value for column "${column.name}" in row ${rowIndex}: only primitives, null, or OperandNodes are allowed`
|
|
4865
|
+
);
|
|
4866
|
+
}
|
|
4867
|
+
return valueToOperand(rawValue);
|
|
4868
|
+
})
|
|
4500
4869
|
);
|
|
4501
4870
|
return this.clone({
|
|
4502
4871
|
...this.ast,
|
|
@@ -4547,6 +4916,17 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
4547
4916
|
};
|
|
4548
4917
|
|
|
4549
4918
|
// src/query-builder/update-query-state.ts
|
|
4919
|
+
var isUpdateValue = (value) => {
|
|
4920
|
+
if (value === null) return true;
|
|
4921
|
+
switch (typeof value) {
|
|
4922
|
+
case "string":
|
|
4923
|
+
case "number":
|
|
4924
|
+
case "boolean":
|
|
4925
|
+
return true;
|
|
4926
|
+
default:
|
|
4927
|
+
return isOperandNode(value);
|
|
4928
|
+
}
|
|
4929
|
+
};
|
|
4550
4930
|
var UpdateQueryState = class _UpdateQueryState {
|
|
4551
4931
|
constructor(table, ast) {
|
|
4552
4932
|
this.table = table;
|
|
@@ -4560,14 +4940,21 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
4560
4940
|
return new _UpdateQueryState(this.table, nextAst);
|
|
4561
4941
|
}
|
|
4562
4942
|
withSet(values) {
|
|
4563
|
-
const assignments = Object.entries(values).map(([column,
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
}
|
|
4569
|
-
|
|
4570
|
-
|
|
4943
|
+
const assignments = Object.entries(values).map(([column, rawValue]) => {
|
|
4944
|
+
if (!isUpdateValue(rawValue)) {
|
|
4945
|
+
throw new Error(
|
|
4946
|
+
`Invalid update value for column "${column}": only primitives, null, or OperandNodes are allowed`
|
|
4947
|
+
);
|
|
4948
|
+
}
|
|
4949
|
+
return {
|
|
4950
|
+
column: {
|
|
4951
|
+
type: "Column",
|
|
4952
|
+
table: this.table.name,
|
|
4953
|
+
name: column
|
|
4954
|
+
},
|
|
4955
|
+
value: valueToOperand(rawValue)
|
|
4956
|
+
};
|
|
4957
|
+
});
|
|
4571
4958
|
return this.clone({
|
|
4572
4959
|
...this.ast,
|
|
4573
4960
|
set: assignments
|
|
@@ -5768,20 +6155,55 @@ var SQL_OPERATOR_REGISTRY = {
|
|
|
5768
6155
|
[SQL_OPERATORS.NOT_EXISTS]: { sql: SQL_OPERATORS.NOT_EXISTS, tsName: "notExists" }
|
|
5769
6156
|
};
|
|
5770
6157
|
|
|
5771
|
-
// src/codegen/
|
|
5772
|
-
var
|
|
5773
|
-
var assertNever2 = (value) => {
|
|
5774
|
-
throw new Error(`Unhandled SQL operator: ${value}`);
|
|
5775
|
-
};
|
|
5776
|
-
var TypeScriptGenerator = class {
|
|
6158
|
+
// src/codegen/naming-strategy.ts
|
|
6159
|
+
var DefaultNamingStrategy = class {
|
|
5777
6160
|
/**
|
|
5778
|
-
*
|
|
5779
|
-
* @param
|
|
5780
|
-
* @returns
|
|
6161
|
+
* Converts table names to TypeScript symbols
|
|
6162
|
+
* @param table - Table node, function table node, or string name
|
|
6163
|
+
* @returns Capitalized table name (handles schema-qualified names)
|
|
5781
6164
|
*/
|
|
5782
|
-
|
|
5783
|
-
const
|
|
5784
|
-
|
|
6165
|
+
tableToSymbol(table) {
|
|
6166
|
+
const tableName = typeof table === "string" ? table : table.name;
|
|
6167
|
+
if (tableName.includes(".")) {
|
|
6168
|
+
return tableName.split(".").map((part) => this.capitalize(part)).join("");
|
|
6169
|
+
}
|
|
6170
|
+
return this.capitalize(tableName);
|
|
6171
|
+
}
|
|
6172
|
+
/**
|
|
6173
|
+
* Converts column references to property names
|
|
6174
|
+
* @param column - Column node
|
|
6175
|
+
* @returns Column name as-is (for backward compatibility)
|
|
6176
|
+
*/
|
|
6177
|
+
columnToProperty(column) {
|
|
6178
|
+
return column.name;
|
|
6179
|
+
}
|
|
6180
|
+
/**
|
|
6181
|
+
* Capitalizes the first letter of a string
|
|
6182
|
+
* @param s - String to capitalize
|
|
6183
|
+
* @returns Capitalized string
|
|
6184
|
+
*/
|
|
6185
|
+
capitalize(s) {
|
|
6186
|
+
if (!s) return s;
|
|
6187
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
6188
|
+
}
|
|
6189
|
+
};
|
|
6190
|
+
|
|
6191
|
+
// src/codegen/typescript.ts
|
|
6192
|
+
var assertNever2 = (value) => {
|
|
6193
|
+
throw new Error(`Unhandled SQL operator: ${value}`);
|
|
6194
|
+
};
|
|
6195
|
+
var TypeScriptGenerator = class {
|
|
6196
|
+
constructor(namingStrategy = new DefaultNamingStrategy()) {
|
|
6197
|
+
this.namingStrategy = namingStrategy;
|
|
6198
|
+
}
|
|
6199
|
+
/**
|
|
6200
|
+
* Generates TypeScript code from a query AST
|
|
6201
|
+
* @param ast - Query AST to generate code from
|
|
6202
|
+
* @returns Generated TypeScript code
|
|
6203
|
+
*/
|
|
6204
|
+
generate(ast) {
|
|
6205
|
+
const chainLines = this.buildSelectLines(ast);
|
|
6206
|
+
const lines = chainLines.map((line, index) => index === 0 ? `const query = ${line}` : line);
|
|
5785
6207
|
lines.push(";", "", "await query.execute();");
|
|
5786
6208
|
return lines.join("\n");
|
|
5787
6209
|
}
|
|
@@ -5800,13 +6222,13 @@ var TypeScriptGenerator = class {
|
|
|
5800
6222
|
return `${key}: ${this.printOperand(operand)}`;
|
|
5801
6223
|
});
|
|
5802
6224
|
lines.push(`db.select({`);
|
|
5803
|
-
selections.forEach((
|
|
5804
|
-
lines.push(` ${
|
|
6225
|
+
selections.forEach((sel2, index) => {
|
|
6226
|
+
lines.push(` ${sel2}${index < selections.length - 1 ? "," : ""}`);
|
|
5805
6227
|
});
|
|
5806
6228
|
lines.push(`})`);
|
|
5807
|
-
lines.push(`.from(${
|
|
6229
|
+
lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
|
|
5808
6230
|
if (ast.distinct && ast.distinct.length) {
|
|
5809
|
-
const cols = ast.distinct.map((c) => `${
|
|
6231
|
+
const cols = ast.distinct.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
5810
6232
|
lines.push(`.distinct(${cols})`);
|
|
5811
6233
|
}
|
|
5812
6234
|
ast.joins.forEach((join) => {
|
|
@@ -5821,7 +6243,7 @@ var TypeScriptGenerator = class {
|
|
|
5821
6243
|
lines.push(`.joinRelation('${relationName}', '${join.kind}')`);
|
|
5822
6244
|
}
|
|
5823
6245
|
} else {
|
|
5824
|
-
const table =
|
|
6246
|
+
const table = this.namingStrategy.tableToSymbol(join.table);
|
|
5825
6247
|
const cond = this.printExpression(join.condition);
|
|
5826
6248
|
let method = "innerJoin";
|
|
5827
6249
|
if (join.kind === "LEFT") method = "leftJoin";
|
|
@@ -5842,7 +6264,7 @@ var TypeScriptGenerator = class {
|
|
|
5842
6264
|
lines.push(`.where(${this.printExpression(ast.where)})`);
|
|
5843
6265
|
}
|
|
5844
6266
|
if (ast.groupBy && ast.groupBy.length) {
|
|
5845
|
-
const cols = ast.groupBy.map((c) => `${
|
|
6267
|
+
const cols = ast.groupBy.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
5846
6268
|
lines.push(`.groupBy(${cols})`);
|
|
5847
6269
|
}
|
|
5848
6270
|
if (ast.having) {
|
|
@@ -5850,7 +6272,7 @@ var TypeScriptGenerator = class {
|
|
|
5850
6272
|
}
|
|
5851
6273
|
if (ast.orderBy && ast.orderBy.length) {
|
|
5852
6274
|
ast.orderBy.forEach((o) => {
|
|
5853
|
-
lines.push(`.orderBy(${
|
|
6275
|
+
lines.push(`.orderBy(${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name}, '${o.direction}')`);
|
|
5854
6276
|
});
|
|
5855
6277
|
}
|
|
5856
6278
|
if (ast.limit) lines.push(`.limit(${ast.limit})`);
|
|
@@ -5989,7 +6411,7 @@ var TypeScriptGenerator = class {
|
|
|
5989
6411
|
* @returns TypeScript code representation
|
|
5990
6412
|
*/
|
|
5991
6413
|
printColumnOperand(column) {
|
|
5992
|
-
return `${
|
|
6414
|
+
return `${this.namingStrategy.tableToSymbol(column.table)}.${column.name}`;
|
|
5993
6415
|
}
|
|
5994
6416
|
/**
|
|
5995
6417
|
* Prints a literal operand to TypeScript code
|
|
@@ -6015,7 +6437,7 @@ var TypeScriptGenerator = class {
|
|
|
6015
6437
|
* @returns TypeScript code representation
|
|
6016
6438
|
*/
|
|
6017
6439
|
printJsonPathOperand(json) {
|
|
6018
|
-
return `jsonPath(${
|
|
6440
|
+
return `jsonPath(${this.namingStrategy.tableToSymbol(json.column.table)}.${json.column.name}, '${json.path}')`;
|
|
6019
6441
|
}
|
|
6020
6442
|
/**
|
|
6021
6443
|
* Prints a scalar subquery operand to TypeScript code
|
|
@@ -6051,11 +6473,11 @@ var TypeScriptGenerator = class {
|
|
|
6051
6473
|
result += ") OVER (";
|
|
6052
6474
|
const parts = [];
|
|
6053
6475
|
if (node.partitionBy && node.partitionBy.length > 0) {
|
|
6054
|
-
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${
|
|
6476
|
+
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${this.namingStrategy.tableToSymbol(col2.table)}.${col2.name}`).join(", ");
|
|
6055
6477
|
parts.push(partitionClause);
|
|
6056
6478
|
}
|
|
6057
6479
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
6058
|
-
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${
|
|
6480
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name} ${o.direction}`).join(", ");
|
|
6059
6481
|
parts.push(orderClause);
|
|
6060
6482
|
}
|
|
6061
6483
|
result += parts.join(" ");
|
|
@@ -6084,48 +6506,6 @@ var TypeScriptGenerator = class {
|
|
|
6084
6506
|
}
|
|
6085
6507
|
};
|
|
6086
6508
|
|
|
6087
|
-
// src/orm/domain-event-bus.ts
|
|
6088
|
-
var DomainEventBus = class {
|
|
6089
|
-
constructor(initialHandlers) {
|
|
6090
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
6091
|
-
const handlers = initialHandlers ?? {};
|
|
6092
|
-
Object.entries(handlers).forEach(([name, list]) => {
|
|
6093
|
-
this.handlers.set(name, [...list]);
|
|
6094
|
-
});
|
|
6095
|
-
}
|
|
6096
|
-
register(name, handler) {
|
|
6097
|
-
const existing = this.handlers.get(name) ?? [];
|
|
6098
|
-
existing.push(handler);
|
|
6099
|
-
this.handlers.set(name, existing);
|
|
6100
|
-
}
|
|
6101
|
-
async dispatch(trackedEntities, ctx) {
|
|
6102
|
-
for (const tracked of trackedEntities) {
|
|
6103
|
-
const entity = tracked.entity;
|
|
6104
|
-
if (!entity.domainEvents || !entity.domainEvents.length) continue;
|
|
6105
|
-
for (const event of entity.domainEvents) {
|
|
6106
|
-
const eventName = this.getEventName(event);
|
|
6107
|
-
const handlers = this.handlers.get(eventName);
|
|
6108
|
-
if (!handlers) continue;
|
|
6109
|
-
for (const handler of handlers) {
|
|
6110
|
-
await handler(event, ctx);
|
|
6111
|
-
}
|
|
6112
|
-
}
|
|
6113
|
-
entity.domainEvents = [];
|
|
6114
|
-
}
|
|
6115
|
-
}
|
|
6116
|
-
getEventName(event) {
|
|
6117
|
-
if (!event) return "Unknown";
|
|
6118
|
-
if (typeof event === "string") return event;
|
|
6119
|
-
return event.constructor?.name ?? "Unknown";
|
|
6120
|
-
}
|
|
6121
|
-
};
|
|
6122
|
-
var addDomainEvent = (entity, event) => {
|
|
6123
|
-
if (!entity.domainEvents) {
|
|
6124
|
-
entity.domainEvents = [];
|
|
6125
|
-
}
|
|
6126
|
-
entity.domainEvents.push(event);
|
|
6127
|
-
};
|
|
6128
|
-
|
|
6129
6509
|
// src/orm/identity-map.ts
|
|
6130
6510
|
var IdentityMap = class {
|
|
6131
6511
|
constructor() {
|
|
@@ -6153,169 +6533,14 @@ var IdentityMap = class {
|
|
|
6153
6533
|
const bucket = this.buckets.get(table.name);
|
|
6154
6534
|
return bucket ? Array.from(bucket.values()) : [];
|
|
6155
6535
|
}
|
|
6536
|
+
clear() {
|
|
6537
|
+
this.buckets.clear();
|
|
6538
|
+
}
|
|
6156
6539
|
toIdentityKey(pk) {
|
|
6157
6540
|
return String(pk);
|
|
6158
6541
|
}
|
|
6159
6542
|
};
|
|
6160
6543
|
|
|
6161
|
-
// src/orm/relation-change-processor.ts
|
|
6162
|
-
var RelationChangeProcessor = class {
|
|
6163
|
-
constructor(unitOfWork, dialect, executor) {
|
|
6164
|
-
this.unitOfWork = unitOfWork;
|
|
6165
|
-
this.dialect = dialect;
|
|
6166
|
-
this.executor = executor;
|
|
6167
|
-
this.relationChanges = [];
|
|
6168
|
-
}
|
|
6169
|
-
registerChange(entry) {
|
|
6170
|
-
this.relationChanges.push(entry);
|
|
6171
|
-
}
|
|
6172
|
-
async process() {
|
|
6173
|
-
if (!this.relationChanges.length) return;
|
|
6174
|
-
const entries = [...this.relationChanges];
|
|
6175
|
-
this.relationChanges.length = 0;
|
|
6176
|
-
for (const entry of entries) {
|
|
6177
|
-
switch (entry.relation.type) {
|
|
6178
|
-
case RelationKinds.HasMany:
|
|
6179
|
-
await this.handleHasManyChange(entry);
|
|
6180
|
-
break;
|
|
6181
|
-
case RelationKinds.HasOne:
|
|
6182
|
-
await this.handleHasOneChange(entry);
|
|
6183
|
-
break;
|
|
6184
|
-
case RelationKinds.BelongsToMany:
|
|
6185
|
-
await this.handleBelongsToManyChange(entry);
|
|
6186
|
-
break;
|
|
6187
|
-
case RelationKinds.BelongsTo:
|
|
6188
|
-
await this.handleBelongsToChange(entry);
|
|
6189
|
-
break;
|
|
6190
|
-
}
|
|
6191
|
-
}
|
|
6192
|
-
}
|
|
6193
|
-
async handleHasManyChange(entry) {
|
|
6194
|
-
const relation = entry.relation;
|
|
6195
|
-
const target = entry.change.entity;
|
|
6196
|
-
if (!target) return;
|
|
6197
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6198
|
-
if (!tracked) return;
|
|
6199
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6200
|
-
const rootValue = entry.root[localKey];
|
|
6201
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6202
|
-
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
6203
|
-
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
6204
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6205
|
-
return;
|
|
6206
|
-
}
|
|
6207
|
-
if (entry.change.kind === "remove") {
|
|
6208
|
-
this.detachHasManyChild(tracked.entity, relation);
|
|
6209
|
-
}
|
|
6210
|
-
}
|
|
6211
|
-
async handleHasOneChange(entry) {
|
|
6212
|
-
const relation = entry.relation;
|
|
6213
|
-
const target = entry.change.entity;
|
|
6214
|
-
if (!target) return;
|
|
6215
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6216
|
-
if (!tracked) return;
|
|
6217
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6218
|
-
const rootValue = entry.root[localKey];
|
|
6219
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6220
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6221
|
-
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
6222
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6223
|
-
return;
|
|
6224
|
-
}
|
|
6225
|
-
if (entry.change.kind === "remove") {
|
|
6226
|
-
this.detachHasOneChild(tracked.entity, relation);
|
|
6227
|
-
}
|
|
6228
|
-
}
|
|
6229
|
-
async handleBelongsToChange(_entry) {
|
|
6230
|
-
}
|
|
6231
|
-
async handleBelongsToManyChange(entry) {
|
|
6232
|
-
const relation = entry.relation;
|
|
6233
|
-
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6234
|
-
const rootId = entry.root[rootKey];
|
|
6235
|
-
if (rootId === void 0 || rootId === null) return;
|
|
6236
|
-
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
6237
|
-
if (targetId === null) return;
|
|
6238
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6239
|
-
await this.insertPivotRow(relation, rootId, targetId);
|
|
6240
|
-
return;
|
|
6241
|
-
}
|
|
6242
|
-
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
6243
|
-
await this.deletePivotRow(relation, rootId, targetId);
|
|
6244
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6245
|
-
this.unitOfWork.markRemoved(entry.change.entity);
|
|
6246
|
-
}
|
|
6247
|
-
}
|
|
6248
|
-
}
|
|
6249
|
-
assignHasManyForeignKey(child, relation, rootValue) {
|
|
6250
|
-
const current = child[relation.foreignKey];
|
|
6251
|
-
if (current === rootValue) return;
|
|
6252
|
-
child[relation.foreignKey] = rootValue;
|
|
6253
|
-
}
|
|
6254
|
-
detachHasManyChild(child, relation) {
|
|
6255
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6256
|
-
this.unitOfWork.markRemoved(child);
|
|
6257
|
-
return;
|
|
6258
|
-
}
|
|
6259
|
-
child[relation.foreignKey] = null;
|
|
6260
|
-
this.unitOfWork.markDirty(child);
|
|
6261
|
-
}
|
|
6262
|
-
assignHasOneForeignKey(child, relation, rootValue) {
|
|
6263
|
-
const current = child[relation.foreignKey];
|
|
6264
|
-
if (current === rootValue) return;
|
|
6265
|
-
child[relation.foreignKey] = rootValue;
|
|
6266
|
-
}
|
|
6267
|
-
detachHasOneChild(child, relation) {
|
|
6268
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6269
|
-
this.unitOfWork.markRemoved(child);
|
|
6270
|
-
return;
|
|
6271
|
-
}
|
|
6272
|
-
child[relation.foreignKey] = null;
|
|
6273
|
-
this.unitOfWork.markDirty(child);
|
|
6274
|
-
}
|
|
6275
|
-
async insertPivotRow(relation, rootId, targetId) {
|
|
6276
|
-
const payload = {
|
|
6277
|
-
[relation.pivotForeignKeyToRoot]: rootId,
|
|
6278
|
-
[relation.pivotForeignKeyToTarget]: targetId
|
|
6279
|
-
};
|
|
6280
|
-
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
6281
|
-
const compiled = builder.compile(this.dialect);
|
|
6282
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6283
|
-
}
|
|
6284
|
-
async deletePivotRow(relation, rootId, targetId) {
|
|
6285
|
-
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
6286
|
-
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
6287
|
-
if (!rootCol || !targetCol) return;
|
|
6288
|
-
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
6289
|
-
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
6290
|
-
);
|
|
6291
|
-
const compiled = builder.compile(this.dialect);
|
|
6292
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6293
|
-
}
|
|
6294
|
-
resolvePrimaryKeyValue(entity, table) {
|
|
6295
|
-
if (!entity) return null;
|
|
6296
|
-
const key = findPrimaryKey(table);
|
|
6297
|
-
const value = entity[key];
|
|
6298
|
-
if (value === void 0 || value === null) return null;
|
|
6299
|
-
return value;
|
|
6300
|
-
}
|
|
6301
|
-
};
|
|
6302
|
-
|
|
6303
|
-
// src/orm/transaction-runner.ts
|
|
6304
|
-
var runInTransaction = async (executor, action) => {
|
|
6305
|
-
if (!executor.beginTransaction) {
|
|
6306
|
-
await action();
|
|
6307
|
-
return;
|
|
6308
|
-
}
|
|
6309
|
-
await executor.beginTransaction();
|
|
6310
|
-
try {
|
|
6311
|
-
await action();
|
|
6312
|
-
await executor.commitTransaction?.();
|
|
6313
|
-
} catch (error) {
|
|
6314
|
-
await executor.rollbackTransaction?.();
|
|
6315
|
-
throw error;
|
|
6316
|
-
}
|
|
6317
|
-
};
|
|
6318
|
-
|
|
6319
6544
|
// src/orm/runtime-types.ts
|
|
6320
6545
|
var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
6321
6546
|
EntityStatus2["New"] = "new";
|
|
@@ -6420,6 +6645,10 @@ var UnitOfWork = class {
|
|
|
6420
6645
|
}
|
|
6421
6646
|
}
|
|
6422
6647
|
}
|
|
6648
|
+
reset() {
|
|
6649
|
+
this.trackedEntities.clear();
|
|
6650
|
+
this.identityMap.clear();
|
|
6651
|
+
}
|
|
6423
6652
|
async flushInsert(tracked) {
|
|
6424
6653
|
await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
|
|
6425
6654
|
const payload = this.extractColumns(tracked.table, tracked.entity);
|
|
@@ -6489,6 +6718,7 @@ var UnitOfWork = class {
|
|
|
6489
6718
|
extractColumns(table, entity) {
|
|
6490
6719
|
const payload = {};
|
|
6491
6720
|
for (const column of Object.keys(table.columns)) {
|
|
6721
|
+
if (entity[column] === void 0) continue;
|
|
6492
6722
|
payload[column] = entity[column];
|
|
6493
6723
|
}
|
|
6494
6724
|
return payload;
|
|
@@ -6539,6 +6769,194 @@ var UnitOfWork = class {
|
|
|
6539
6769
|
}
|
|
6540
6770
|
};
|
|
6541
6771
|
|
|
6772
|
+
// src/orm/domain-event-bus.ts
|
|
6773
|
+
var DomainEventBus = class {
|
|
6774
|
+
constructor(initialHandlers) {
|
|
6775
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
6776
|
+
if (initialHandlers) {
|
|
6777
|
+
for (const key in initialHandlers) {
|
|
6778
|
+
const type = key;
|
|
6779
|
+
const list = initialHandlers[type] ?? [];
|
|
6780
|
+
this.handlers.set(type, [...list]);
|
|
6781
|
+
}
|
|
6782
|
+
}
|
|
6783
|
+
}
|
|
6784
|
+
on(type, handler) {
|
|
6785
|
+
const key = type;
|
|
6786
|
+
const existing = this.handlers.get(key) ?? [];
|
|
6787
|
+
existing.push(handler);
|
|
6788
|
+
this.handlers.set(key, existing);
|
|
6789
|
+
}
|
|
6790
|
+
register(type, handler) {
|
|
6791
|
+
this.on(type, handler);
|
|
6792
|
+
}
|
|
6793
|
+
async dispatch(trackedEntities, ctx) {
|
|
6794
|
+
for (const tracked of trackedEntities) {
|
|
6795
|
+
const entity = tracked.entity;
|
|
6796
|
+
if (!entity.domainEvents?.length) continue;
|
|
6797
|
+
for (const event of entity.domainEvents) {
|
|
6798
|
+
const handlers = this.handlers.get(event.type);
|
|
6799
|
+
if (!handlers?.length) continue;
|
|
6800
|
+
for (const handler of handlers) {
|
|
6801
|
+
await handler(event, ctx);
|
|
6802
|
+
}
|
|
6803
|
+
}
|
|
6804
|
+
entity.domainEvents = [];
|
|
6805
|
+
}
|
|
6806
|
+
}
|
|
6807
|
+
};
|
|
6808
|
+
var addDomainEvent = (entity, event) => {
|
|
6809
|
+
if (!entity.domainEvents) {
|
|
6810
|
+
entity.domainEvents = [];
|
|
6811
|
+
}
|
|
6812
|
+
entity.domainEvents.push(event);
|
|
6813
|
+
};
|
|
6814
|
+
|
|
6815
|
+
// src/orm/relation-change-processor.ts
|
|
6816
|
+
var RelationChangeProcessor = class {
|
|
6817
|
+
constructor(unitOfWork, dialect, executor) {
|
|
6818
|
+
this.unitOfWork = unitOfWork;
|
|
6819
|
+
this.dialect = dialect;
|
|
6820
|
+
this.executor = executor;
|
|
6821
|
+
this.relationChanges = [];
|
|
6822
|
+
}
|
|
6823
|
+
registerChange(entry) {
|
|
6824
|
+
this.relationChanges.push(entry);
|
|
6825
|
+
}
|
|
6826
|
+
reset() {
|
|
6827
|
+
this.relationChanges.length = 0;
|
|
6828
|
+
}
|
|
6829
|
+
async process() {
|
|
6830
|
+
if (!this.relationChanges.length) return;
|
|
6831
|
+
const entries = [...this.relationChanges];
|
|
6832
|
+
this.relationChanges.length = 0;
|
|
6833
|
+
for (const entry of entries) {
|
|
6834
|
+
switch (entry.relation.type) {
|
|
6835
|
+
case RelationKinds.HasMany:
|
|
6836
|
+
await this.handleHasManyChange(entry);
|
|
6837
|
+
break;
|
|
6838
|
+
case RelationKinds.HasOne:
|
|
6839
|
+
await this.handleHasOneChange(entry);
|
|
6840
|
+
break;
|
|
6841
|
+
case RelationKinds.BelongsToMany:
|
|
6842
|
+
await this.handleBelongsToManyChange(entry);
|
|
6843
|
+
break;
|
|
6844
|
+
case RelationKinds.BelongsTo:
|
|
6845
|
+
await this.handleBelongsToChange(entry);
|
|
6846
|
+
break;
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6850
|
+
async handleHasManyChange(entry) {
|
|
6851
|
+
const relation = entry.relation;
|
|
6852
|
+
const target = entry.change.entity;
|
|
6853
|
+
if (!target) return;
|
|
6854
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
6855
|
+
if (!tracked) return;
|
|
6856
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6857
|
+
const rootValue = entry.root[localKey];
|
|
6858
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
6859
|
+
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
6860
|
+
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
6861
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
6862
|
+
return;
|
|
6863
|
+
}
|
|
6864
|
+
if (entry.change.kind === "remove") {
|
|
6865
|
+
this.detachHasManyChild(tracked.entity, relation);
|
|
6866
|
+
}
|
|
6867
|
+
}
|
|
6868
|
+
async handleHasOneChange(entry) {
|
|
6869
|
+
const relation = entry.relation;
|
|
6870
|
+
const target = entry.change.entity;
|
|
6871
|
+
if (!target) return;
|
|
6872
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
6873
|
+
if (!tracked) return;
|
|
6874
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6875
|
+
const rootValue = entry.root[localKey];
|
|
6876
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
6877
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6878
|
+
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
6879
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
6880
|
+
return;
|
|
6881
|
+
}
|
|
6882
|
+
if (entry.change.kind === "remove") {
|
|
6883
|
+
this.detachHasOneChild(tracked.entity, relation);
|
|
6884
|
+
}
|
|
6885
|
+
}
|
|
6886
|
+
async handleBelongsToChange(_entry) {
|
|
6887
|
+
}
|
|
6888
|
+
async handleBelongsToManyChange(entry) {
|
|
6889
|
+
const relation = entry.relation;
|
|
6890
|
+
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6891
|
+
const rootId = entry.root[rootKey];
|
|
6892
|
+
if (rootId === void 0 || rootId === null) return;
|
|
6893
|
+
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
6894
|
+
if (targetId === null) return;
|
|
6895
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6896
|
+
await this.insertPivotRow(relation, rootId, targetId);
|
|
6897
|
+
return;
|
|
6898
|
+
}
|
|
6899
|
+
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
6900
|
+
await this.deletePivotRow(relation, rootId, targetId);
|
|
6901
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6902
|
+
this.unitOfWork.markRemoved(entry.change.entity);
|
|
6903
|
+
}
|
|
6904
|
+
}
|
|
6905
|
+
}
|
|
6906
|
+
assignHasManyForeignKey(child, relation, rootValue) {
|
|
6907
|
+
const current = child[relation.foreignKey];
|
|
6908
|
+
if (current === rootValue) return;
|
|
6909
|
+
child[relation.foreignKey] = rootValue;
|
|
6910
|
+
}
|
|
6911
|
+
detachHasManyChild(child, relation) {
|
|
6912
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6913
|
+
this.unitOfWork.markRemoved(child);
|
|
6914
|
+
return;
|
|
6915
|
+
}
|
|
6916
|
+
child[relation.foreignKey] = null;
|
|
6917
|
+
this.unitOfWork.markDirty(child);
|
|
6918
|
+
}
|
|
6919
|
+
assignHasOneForeignKey(child, relation, rootValue) {
|
|
6920
|
+
const current = child[relation.foreignKey];
|
|
6921
|
+
if (current === rootValue) return;
|
|
6922
|
+
child[relation.foreignKey] = rootValue;
|
|
6923
|
+
}
|
|
6924
|
+
detachHasOneChild(child, relation) {
|
|
6925
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6926
|
+
this.unitOfWork.markRemoved(child);
|
|
6927
|
+
return;
|
|
6928
|
+
}
|
|
6929
|
+
child[relation.foreignKey] = null;
|
|
6930
|
+
this.unitOfWork.markDirty(child);
|
|
6931
|
+
}
|
|
6932
|
+
async insertPivotRow(relation, rootId, targetId) {
|
|
6933
|
+
const payload = {
|
|
6934
|
+
[relation.pivotForeignKeyToRoot]: rootId,
|
|
6935
|
+
[relation.pivotForeignKeyToTarget]: targetId
|
|
6936
|
+
};
|
|
6937
|
+
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
6938
|
+
const compiled = builder.compile(this.dialect);
|
|
6939
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6940
|
+
}
|
|
6941
|
+
async deletePivotRow(relation, rootId, targetId) {
|
|
6942
|
+
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
6943
|
+
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
6944
|
+
if (!rootCol || !targetCol) return;
|
|
6945
|
+
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
6946
|
+
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
6947
|
+
);
|
|
6948
|
+
const compiled = builder.compile(this.dialect);
|
|
6949
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6950
|
+
}
|
|
6951
|
+
resolvePrimaryKeyValue(entity, table) {
|
|
6952
|
+
if (!entity) return null;
|
|
6953
|
+
const key = findPrimaryKey(table);
|
|
6954
|
+
const value = entity[key];
|
|
6955
|
+
if (value === void 0 || value === null) return null;
|
|
6956
|
+
return value;
|
|
6957
|
+
}
|
|
6958
|
+
};
|
|
6959
|
+
|
|
6542
6960
|
// src/orm/query-logger.ts
|
|
6543
6961
|
var createQueryLoggingExecutor = (executor, logger) => {
|
|
6544
6962
|
if (!logger) {
|
|
@@ -6562,31 +6980,40 @@ var createQueryLoggingExecutor = (executor, logger) => {
|
|
|
6562
6980
|
return wrapped;
|
|
6563
6981
|
};
|
|
6564
6982
|
|
|
6565
|
-
// src/orm/
|
|
6566
|
-
var
|
|
6567
|
-
|
|
6568
|
-
|
|
6983
|
+
// src/orm/transaction-runner.ts
|
|
6984
|
+
var runInTransaction = async (executor, action) => {
|
|
6985
|
+
if (!executor.beginTransaction) {
|
|
6986
|
+
await action();
|
|
6987
|
+
return;
|
|
6988
|
+
}
|
|
6989
|
+
await executor.beginTransaction();
|
|
6990
|
+
try {
|
|
6991
|
+
await action();
|
|
6992
|
+
await executor.commitTransaction?.();
|
|
6993
|
+
} catch (error) {
|
|
6994
|
+
await executor.rollbackTransaction?.();
|
|
6995
|
+
throw error;
|
|
6996
|
+
}
|
|
6997
|
+
};
|
|
6998
|
+
|
|
6999
|
+
// src/orm/orm-session.ts
|
|
7000
|
+
var OrmSession = class {
|
|
7001
|
+
constructor(opts) {
|
|
7002
|
+
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
7003
|
+
this.relationChanges.registerChange(
|
|
7004
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
7005
|
+
);
|
|
7006
|
+
};
|
|
7007
|
+
this.orm = opts.orm;
|
|
7008
|
+
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
7009
|
+
this.interceptors = [...opts.interceptors ?? []];
|
|
6569
7010
|
this.identityMap = new IdentityMap();
|
|
6570
|
-
this.
|
|
6571
|
-
this.
|
|
6572
|
-
this.
|
|
6573
|
-
options.dialect,
|
|
6574
|
-
this.executorWithLogging,
|
|
6575
|
-
this.identityMap,
|
|
6576
|
-
() => this
|
|
6577
|
-
);
|
|
6578
|
-
this.relationChanges = new RelationChangeProcessor(
|
|
6579
|
-
this.unitOfWork,
|
|
6580
|
-
options.dialect,
|
|
6581
|
-
this.executorWithLogging
|
|
6582
|
-
);
|
|
6583
|
-
this.domainEvents = new DomainEventBus(options.domainEventHandlers);
|
|
7011
|
+
this.unitOfWork = new UnitOfWork(this.orm.dialect, this.executor, this.identityMap, () => this);
|
|
7012
|
+
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
7013
|
+
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
6584
7014
|
}
|
|
6585
7015
|
get dialect() {
|
|
6586
|
-
return this.
|
|
6587
|
-
}
|
|
6588
|
-
get executor() {
|
|
6589
|
-
return this.executorWithLogging;
|
|
7016
|
+
return this.orm.dialect;
|
|
6590
7017
|
}
|
|
6591
7018
|
get identityBuckets() {
|
|
6592
7019
|
return this.unitOfWork.identityBuckets;
|
|
@@ -6612,24 +7039,64 @@ var OrmContext = class {
|
|
|
6612
7039
|
markRemoved(entity) {
|
|
6613
7040
|
this.unitOfWork.markRemoved(entity);
|
|
6614
7041
|
}
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
root,
|
|
6618
|
-
relationKey,
|
|
6619
|
-
rootTable,
|
|
6620
|
-
relationName,
|
|
6621
|
-
relation,
|
|
6622
|
-
change
|
|
6623
|
-
};
|
|
6624
|
-
this.relationChanges.registerChange(entry);
|
|
7042
|
+
getEntitiesForTable(table) {
|
|
7043
|
+
return this.unitOfWork.getEntitiesForTable(table);
|
|
6625
7044
|
}
|
|
6626
7045
|
registerInterceptor(interceptor) {
|
|
6627
7046
|
this.interceptors.push(interceptor);
|
|
6628
7047
|
}
|
|
6629
|
-
registerDomainEventHandler(
|
|
6630
|
-
this.domainEvents.
|
|
7048
|
+
registerDomainEventHandler(type, handler) {
|
|
7049
|
+
this.domainEvents.on(type, handler);
|
|
7050
|
+
}
|
|
7051
|
+
async find(entityClass, id) {
|
|
7052
|
+
const table = getTableDefFromEntity(entityClass);
|
|
7053
|
+
if (!table) {
|
|
7054
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
7055
|
+
}
|
|
7056
|
+
const primaryKey = findPrimaryKey(table);
|
|
7057
|
+
const column = table.columns[primaryKey];
|
|
7058
|
+
if (!column) {
|
|
7059
|
+
throw new Error("Entity table does not expose a primary key");
|
|
7060
|
+
}
|
|
7061
|
+
const columnSelections = Object.values(table.columns).reduce((acc, col2) => {
|
|
7062
|
+
acc[col2.name] = col2;
|
|
7063
|
+
return acc;
|
|
7064
|
+
}, {});
|
|
7065
|
+
const qb = selectFromEntity(entityClass).select(columnSelections).where(eq(column, id)).limit(1);
|
|
7066
|
+
const rows = await executeHydrated(this, qb);
|
|
7067
|
+
return rows[0] ?? null;
|
|
7068
|
+
}
|
|
7069
|
+
async findOne(qb) {
|
|
7070
|
+
const limited = qb.limit(1);
|
|
7071
|
+
const rows = await executeHydrated(this, limited);
|
|
7072
|
+
return rows[0] ?? null;
|
|
7073
|
+
}
|
|
7074
|
+
async findMany(qb) {
|
|
7075
|
+
return executeHydrated(this, qb);
|
|
7076
|
+
}
|
|
7077
|
+
async persist(entity) {
|
|
7078
|
+
if (this.unitOfWork.findTracked(entity)) {
|
|
7079
|
+
return;
|
|
7080
|
+
}
|
|
7081
|
+
const table = getTableDefFromEntity(entity.constructor);
|
|
7082
|
+
if (!table) {
|
|
7083
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
7084
|
+
}
|
|
7085
|
+
const primaryKey = findPrimaryKey(table);
|
|
7086
|
+
const pkValue = entity[primaryKey];
|
|
7087
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
7088
|
+
this.trackManaged(table, pkValue, entity);
|
|
7089
|
+
} else {
|
|
7090
|
+
this.trackNew(table, entity);
|
|
7091
|
+
}
|
|
7092
|
+
}
|
|
7093
|
+
async remove(entity) {
|
|
7094
|
+
this.markRemoved(entity);
|
|
7095
|
+
}
|
|
7096
|
+
async flush() {
|
|
7097
|
+
await this.unitOfWork.flush();
|
|
6631
7098
|
}
|
|
6632
|
-
async
|
|
7099
|
+
async commit() {
|
|
6633
7100
|
await runInTransaction(this.executor, async () => {
|
|
6634
7101
|
for (const interceptor of this.interceptors) {
|
|
6635
7102
|
await interceptor.beforeFlush?.(this);
|
|
@@ -6643,8 +7110,82 @@ var OrmContext = class {
|
|
|
6643
7110
|
});
|
|
6644
7111
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
6645
7112
|
}
|
|
6646
|
-
|
|
6647
|
-
|
|
7113
|
+
async rollback() {
|
|
7114
|
+
await this.executor.rollbackTransaction?.();
|
|
7115
|
+
this.unitOfWork.reset();
|
|
7116
|
+
this.relationChanges.reset();
|
|
7117
|
+
}
|
|
7118
|
+
getExecutionContext() {
|
|
7119
|
+
return {
|
|
7120
|
+
dialect: this.orm.dialect,
|
|
7121
|
+
executor: this.executor,
|
|
7122
|
+
interceptors: this.orm.interceptors
|
|
7123
|
+
};
|
|
7124
|
+
}
|
|
7125
|
+
getHydrationContext() {
|
|
7126
|
+
return {
|
|
7127
|
+
identityMap: this.identityMap,
|
|
7128
|
+
unitOfWork: this.unitOfWork,
|
|
7129
|
+
domainEvents: this.domainEvents,
|
|
7130
|
+
relationChanges: this.relationChanges,
|
|
7131
|
+
entityContext: this
|
|
7132
|
+
};
|
|
7133
|
+
}
|
|
7134
|
+
};
|
|
7135
|
+
var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, relation, change) => ({
|
|
7136
|
+
root,
|
|
7137
|
+
relationKey,
|
|
7138
|
+
rootTable,
|
|
7139
|
+
relationName,
|
|
7140
|
+
relation,
|
|
7141
|
+
change
|
|
7142
|
+
});
|
|
7143
|
+
|
|
7144
|
+
// src/orm/interceptor-pipeline.ts
|
|
7145
|
+
var InterceptorPipeline = class {
|
|
7146
|
+
constructor() {
|
|
7147
|
+
this.interceptors = [];
|
|
7148
|
+
}
|
|
7149
|
+
use(interceptor) {
|
|
7150
|
+
this.interceptors.push(interceptor);
|
|
7151
|
+
}
|
|
7152
|
+
async run(ctx, executor) {
|
|
7153
|
+
let i = 0;
|
|
7154
|
+
const dispatch = async () => {
|
|
7155
|
+
const interceptor = this.interceptors[i++];
|
|
7156
|
+
if (!interceptor) {
|
|
7157
|
+
return executor.executeSql(ctx.sql, ctx.params);
|
|
7158
|
+
}
|
|
7159
|
+
return interceptor(ctx, dispatch);
|
|
7160
|
+
};
|
|
7161
|
+
return dispatch();
|
|
7162
|
+
}
|
|
7163
|
+
};
|
|
7164
|
+
|
|
7165
|
+
// src/orm/orm.ts
|
|
7166
|
+
var Orm = class {
|
|
7167
|
+
constructor(opts) {
|
|
7168
|
+
this.dialect = opts.dialect;
|
|
7169
|
+
this.interceptors = opts.interceptors ?? new InterceptorPipeline();
|
|
7170
|
+
this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
|
|
7171
|
+
this.executorFactory = opts.executorFactory;
|
|
7172
|
+
}
|
|
7173
|
+
createSession(options) {
|
|
7174
|
+
const executor = this.executorFactory.createExecutor(options?.tx);
|
|
7175
|
+
return new OrmSession({ orm: this, executor });
|
|
7176
|
+
}
|
|
7177
|
+
async transaction(fn4) {
|
|
7178
|
+
const executor = this.executorFactory.createTransactionalExecutor();
|
|
7179
|
+
const session = new OrmSession({ orm: this, executor });
|
|
7180
|
+
try {
|
|
7181
|
+
const result = await fn4(session);
|
|
7182
|
+
await session.commit();
|
|
7183
|
+
return result;
|
|
7184
|
+
} catch (err) {
|
|
7185
|
+
await session.rollback();
|
|
7186
|
+
throw err;
|
|
7187
|
+
} finally {
|
|
7188
|
+
}
|
|
6648
7189
|
}
|
|
6649
7190
|
};
|
|
6650
7191
|
|
|
@@ -6759,10 +7300,12 @@ export {
|
|
|
6759
7300
|
DefaultHasManyCollection,
|
|
6760
7301
|
DefaultManyToManyCollection,
|
|
6761
7302
|
DeleteQueryBuilder,
|
|
7303
|
+
DomainEventBus,
|
|
6762
7304
|
EntityStatus,
|
|
6763
7305
|
InsertQueryBuilder,
|
|
6764
7306
|
MySqlDialect,
|
|
6765
|
-
|
|
7307
|
+
Orm,
|
|
7308
|
+
OrmSession,
|
|
6766
7309
|
PostgresDialect,
|
|
6767
7310
|
RelationKinds,
|
|
6768
7311
|
SelectQueryBuilder,
|
|
@@ -6804,6 +7347,7 @@ export {
|
|
|
6804
7347
|
createMssqlExecutor,
|
|
6805
7348
|
createMysqlExecutor,
|
|
6806
7349
|
createPostgresExecutor,
|
|
7350
|
+
createQueryLoggingExecutor,
|
|
6807
7351
|
createSqliteExecutor,
|
|
6808
7352
|
currentDate,
|
|
6809
7353
|
currentTime,
|
|
@@ -6820,7 +7364,9 @@ export {
|
|
|
6820
7364
|
diffSchema,
|
|
6821
7365
|
endOfMonth,
|
|
6822
7366
|
eq,
|
|
7367
|
+
esel,
|
|
6823
7368
|
executeHydrated,
|
|
7369
|
+
executeHydratedWithContexts,
|
|
6824
7370
|
exists,
|
|
6825
7371
|
exp,
|
|
6826
7372
|
extract,
|
|
@@ -6830,6 +7376,7 @@ export {
|
|
|
6830
7376
|
generateCreateTableSql,
|
|
6831
7377
|
generateSchemaSql,
|
|
6832
7378
|
getSchemaIntrospector,
|
|
7379
|
+
groupConcat,
|
|
6833
7380
|
gt,
|
|
6834
7381
|
gte,
|
|
6835
7382
|
hasMany,
|
|
@@ -6844,6 +7391,7 @@ export {
|
|
|
6844
7391
|
isNotNull,
|
|
6845
7392
|
isNull,
|
|
6846
7393
|
isOperandNode,
|
|
7394
|
+
isValueOperandInput,
|
|
6847
7395
|
isWindowFunctionNode,
|
|
6848
7396
|
jsonPath,
|
|
6849
7397
|
lag,
|
|
@@ -6866,6 +7414,8 @@ export {
|
|
|
6866
7414
|
lt,
|
|
6867
7415
|
lte,
|
|
6868
7416
|
ltrim,
|
|
7417
|
+
max,
|
|
7418
|
+
min,
|
|
6869
7419
|
mod,
|
|
6870
7420
|
month,
|
|
6871
7421
|
neq,
|
|
@@ -6896,6 +7446,7 @@ export {
|
|
|
6896
7446
|
rowsToQueryResult,
|
|
6897
7447
|
rpad,
|
|
6898
7448
|
rtrim,
|
|
7449
|
+
sel,
|
|
6899
7450
|
sign,
|
|
6900
7451
|
sin,
|
|
6901
7452
|
space,
|