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.cjs
CHANGED
|
@@ -48,10 +48,12 @@ __export(index_exports, {
|
|
|
48
48
|
DefaultHasManyCollection: () => DefaultHasManyCollection,
|
|
49
49
|
DefaultManyToManyCollection: () => DefaultManyToManyCollection,
|
|
50
50
|
DeleteQueryBuilder: () => DeleteQueryBuilder,
|
|
51
|
+
DomainEventBus: () => DomainEventBus,
|
|
51
52
|
EntityStatus: () => EntityStatus,
|
|
52
53
|
InsertQueryBuilder: () => InsertQueryBuilder,
|
|
53
54
|
MySqlDialect: () => MySqlDialect,
|
|
54
|
-
|
|
55
|
+
Orm: () => Orm,
|
|
56
|
+
OrmSession: () => OrmSession,
|
|
55
57
|
PostgresDialect: () => PostgresDialect,
|
|
56
58
|
RelationKinds: () => RelationKinds,
|
|
57
59
|
SelectQueryBuilder: () => SelectQueryBuilder,
|
|
@@ -93,6 +95,7 @@ __export(index_exports, {
|
|
|
93
95
|
createMssqlExecutor: () => createMssqlExecutor,
|
|
94
96
|
createMysqlExecutor: () => createMysqlExecutor,
|
|
95
97
|
createPostgresExecutor: () => createPostgresExecutor,
|
|
98
|
+
createQueryLoggingExecutor: () => createQueryLoggingExecutor,
|
|
96
99
|
createSqliteExecutor: () => createSqliteExecutor,
|
|
97
100
|
currentDate: () => currentDate,
|
|
98
101
|
currentTime: () => currentTime,
|
|
@@ -109,7 +112,9 @@ __export(index_exports, {
|
|
|
109
112
|
diffSchema: () => diffSchema,
|
|
110
113
|
endOfMonth: () => endOfMonth,
|
|
111
114
|
eq: () => eq,
|
|
115
|
+
esel: () => esel,
|
|
112
116
|
executeHydrated: () => executeHydrated,
|
|
117
|
+
executeHydratedWithContexts: () => executeHydratedWithContexts,
|
|
113
118
|
exists: () => exists,
|
|
114
119
|
exp: () => exp,
|
|
115
120
|
extract: () => extract,
|
|
@@ -119,6 +124,7 @@ __export(index_exports, {
|
|
|
119
124
|
generateCreateTableSql: () => generateCreateTableSql,
|
|
120
125
|
generateSchemaSql: () => generateSchemaSql,
|
|
121
126
|
getSchemaIntrospector: () => getSchemaIntrospector,
|
|
127
|
+
groupConcat: () => groupConcat,
|
|
122
128
|
gt: () => gt,
|
|
123
129
|
gte: () => gte,
|
|
124
130
|
hasMany: () => hasMany,
|
|
@@ -133,6 +139,7 @@ __export(index_exports, {
|
|
|
133
139
|
isNotNull: () => isNotNull,
|
|
134
140
|
isNull: () => isNull,
|
|
135
141
|
isOperandNode: () => isOperandNode,
|
|
142
|
+
isValueOperandInput: () => isValueOperandInput,
|
|
136
143
|
isWindowFunctionNode: () => isWindowFunctionNode,
|
|
137
144
|
jsonPath: () => jsonPath,
|
|
138
145
|
lag: () => lag,
|
|
@@ -155,6 +162,8 @@ __export(index_exports, {
|
|
|
155
162
|
lt: () => lt,
|
|
156
163
|
lte: () => lte,
|
|
157
164
|
ltrim: () => ltrim,
|
|
165
|
+
max: () => max,
|
|
166
|
+
min: () => min,
|
|
158
167
|
mod: () => mod,
|
|
159
168
|
month: () => month,
|
|
160
169
|
neq: () => neq,
|
|
@@ -185,6 +194,7 @@ __export(index_exports, {
|
|
|
185
194
|
rowsToQueryResult: () => rowsToQueryResult,
|
|
186
195
|
rpad: () => rpad,
|
|
187
196
|
rtrim: () => rtrim,
|
|
197
|
+
sel: () => sel,
|
|
188
198
|
sign: () => sign,
|
|
189
199
|
sin: () => sin,
|
|
190
200
|
space: () => space,
|
|
@@ -418,10 +428,13 @@ var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressi
|
|
|
418
428
|
|
|
419
429
|
// src/core/ast/expression-builders.ts
|
|
420
430
|
var valueToOperand = (value) => {
|
|
421
|
-
if (value
|
|
422
|
-
return
|
|
431
|
+
if (isOperandNode(value)) {
|
|
432
|
+
return value;
|
|
423
433
|
}
|
|
424
|
-
return
|
|
434
|
+
return {
|
|
435
|
+
type: "Literal",
|
|
436
|
+
value
|
|
437
|
+
};
|
|
425
438
|
};
|
|
426
439
|
var toNode = (col2) => {
|
|
427
440
|
if (isOperandNode(col2)) return col2;
|
|
@@ -432,10 +445,11 @@ var toLiteralNode = (value) => ({
|
|
|
432
445
|
type: "Literal",
|
|
433
446
|
value
|
|
434
447
|
});
|
|
448
|
+
var isLiteralValue = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
449
|
+
var isValueOperandInput = (value) => isOperandNode(value) || isLiteralValue(value);
|
|
435
450
|
var toOperand = (val) => {
|
|
436
|
-
if (val
|
|
437
|
-
|
|
438
|
-
return { type: "Literal", value: val };
|
|
451
|
+
if (isLiteralValue(val)) {
|
|
452
|
+
return valueToOperand(val);
|
|
439
453
|
}
|
|
440
454
|
return toNode(val);
|
|
441
455
|
};
|
|
@@ -581,6 +595,62 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
|
|
|
581
595
|
return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
|
|
582
596
|
};
|
|
583
597
|
|
|
598
|
+
// src/core/sql/sql.ts
|
|
599
|
+
var SQL_OPERATORS = {
|
|
600
|
+
/** Equality operator */
|
|
601
|
+
EQUALS: "=",
|
|
602
|
+
/** Not equals operator */
|
|
603
|
+
NOT_EQUALS: "!=",
|
|
604
|
+
/** Greater than operator */
|
|
605
|
+
GREATER_THAN: ">",
|
|
606
|
+
/** Greater than or equal operator */
|
|
607
|
+
GREATER_OR_EQUAL: ">=",
|
|
608
|
+
/** Less than operator */
|
|
609
|
+
LESS_THAN: "<",
|
|
610
|
+
/** Less than or equal operator */
|
|
611
|
+
LESS_OR_EQUAL: "<=",
|
|
612
|
+
/** LIKE pattern matching operator */
|
|
613
|
+
LIKE: "LIKE",
|
|
614
|
+
/** NOT LIKE pattern matching operator */
|
|
615
|
+
NOT_LIKE: "NOT LIKE",
|
|
616
|
+
/** IN membership operator */
|
|
617
|
+
IN: "IN",
|
|
618
|
+
/** NOT IN membership operator */
|
|
619
|
+
NOT_IN: "NOT IN",
|
|
620
|
+
/** BETWEEN range operator */
|
|
621
|
+
BETWEEN: "BETWEEN",
|
|
622
|
+
/** NOT BETWEEN range operator */
|
|
623
|
+
NOT_BETWEEN: "NOT BETWEEN",
|
|
624
|
+
/** IS NULL null check operator */
|
|
625
|
+
IS_NULL: "IS NULL",
|
|
626
|
+
/** IS NOT NULL null check operator */
|
|
627
|
+
IS_NOT_NULL: "IS NOT NULL",
|
|
628
|
+
/** Logical AND operator */
|
|
629
|
+
AND: "AND",
|
|
630
|
+
/** Logical OR operator */
|
|
631
|
+
OR: "OR",
|
|
632
|
+
/** EXISTS operator */
|
|
633
|
+
EXISTS: "EXISTS",
|
|
634
|
+
/** NOT EXISTS operator */
|
|
635
|
+
NOT_EXISTS: "NOT EXISTS"
|
|
636
|
+
};
|
|
637
|
+
var JOIN_KINDS = {
|
|
638
|
+
/** INNER JOIN type */
|
|
639
|
+
INNER: "INNER",
|
|
640
|
+
/** LEFT JOIN type */
|
|
641
|
+
LEFT: "LEFT",
|
|
642
|
+
/** RIGHT JOIN type */
|
|
643
|
+
RIGHT: "RIGHT",
|
|
644
|
+
/** CROSS JOIN type */
|
|
645
|
+
CROSS: "CROSS"
|
|
646
|
+
};
|
|
647
|
+
var ORDER_DIRECTIONS = {
|
|
648
|
+
/** Ascending order */
|
|
649
|
+
ASC: "ASC",
|
|
650
|
+
/** Descending order */
|
|
651
|
+
DESC: "DESC"
|
|
652
|
+
};
|
|
653
|
+
|
|
584
654
|
// src/core/ast/aggregate-functions.ts
|
|
585
655
|
var buildAggregate = (name) => (col2) => ({
|
|
586
656
|
type: "Function",
|
|
@@ -590,6 +660,20 @@ var buildAggregate = (name) => (col2) => ({
|
|
|
590
660
|
var count = buildAggregate("COUNT");
|
|
591
661
|
var sum = buildAggregate("SUM");
|
|
592
662
|
var avg = buildAggregate("AVG");
|
|
663
|
+
var min = buildAggregate("MIN");
|
|
664
|
+
var max = buildAggregate("MAX");
|
|
665
|
+
var toOrderByNode = (order) => ({
|
|
666
|
+
type: "OrderBy",
|
|
667
|
+
column: columnOperand(order.column),
|
|
668
|
+
direction: order.direction ?? ORDER_DIRECTIONS.ASC
|
|
669
|
+
});
|
|
670
|
+
var groupConcat = (col2, options) => ({
|
|
671
|
+
type: "Function",
|
|
672
|
+
name: "GROUP_CONCAT",
|
|
673
|
+
args: [columnOperand(col2)],
|
|
674
|
+
orderBy: options?.orderBy?.map(toOrderByNode),
|
|
675
|
+
separator: options?.separator !== void 0 ? valueToOperand(options.separator) : void 0
|
|
676
|
+
});
|
|
593
677
|
|
|
594
678
|
// src/core/ast/expression-visitor.ts
|
|
595
679
|
var expressionDispatchers = /* @__PURE__ */ new Map();
|
|
@@ -681,12 +765,17 @@ var toTableRef = (table) => ({
|
|
|
681
765
|
});
|
|
682
766
|
|
|
683
767
|
// src/core/functions/standard-strategy.ts
|
|
684
|
-
var StandardFunctionStrategy = class {
|
|
768
|
+
var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
685
769
|
constructor() {
|
|
686
770
|
this.renderers = /* @__PURE__ */ new Map();
|
|
687
771
|
this.registerStandard();
|
|
688
772
|
}
|
|
689
773
|
registerStandard() {
|
|
774
|
+
this.add("COUNT", ({ compiledArgs }) => `COUNT(${compiledArgs.join(", ")})`);
|
|
775
|
+
this.add("SUM", ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
|
|
776
|
+
this.add("AVG", ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
|
|
777
|
+
this.add("MIN", ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
|
|
778
|
+
this.add("MAX", ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
|
|
690
779
|
this.add("ABS", ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
|
|
691
780
|
this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
|
|
692
781
|
this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
|
|
@@ -713,6 +802,7 @@ var StandardFunctionStrategy = class {
|
|
|
713
802
|
this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
|
|
714
803
|
this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
|
|
715
804
|
this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
805
|
+
this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
|
|
716
806
|
}
|
|
717
807
|
add(name, renderer) {
|
|
718
808
|
this.renderers.set(name, renderer);
|
|
@@ -720,10 +810,40 @@ var StandardFunctionStrategy = class {
|
|
|
720
810
|
getRenderer(name) {
|
|
721
811
|
return this.renderers.get(name);
|
|
722
812
|
}
|
|
813
|
+
renderGroupConcat(ctx) {
|
|
814
|
+
const arg = ctx.compiledArgs[0];
|
|
815
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
816
|
+
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
817
|
+
const separatorClause = this.formatGroupConcatSeparator(ctx);
|
|
818
|
+
return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
|
|
819
|
+
}
|
|
820
|
+
buildOrderByExpression(ctx) {
|
|
821
|
+
const orderBy = ctx.node.orderBy;
|
|
822
|
+
if (!orderBy || orderBy.length === 0) {
|
|
823
|
+
return "";
|
|
824
|
+
}
|
|
825
|
+
const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
|
|
826
|
+
return `ORDER BY ${parts.join(", ")}`;
|
|
827
|
+
}
|
|
828
|
+
formatGroupConcatSeparator(ctx) {
|
|
829
|
+
if (!ctx.node.separator) {
|
|
830
|
+
return "";
|
|
831
|
+
}
|
|
832
|
+
return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
|
|
833
|
+
}
|
|
834
|
+
getGroupConcatSeparatorOperand(ctx) {
|
|
835
|
+
return ctx.node.separator ?? _StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
836
|
+
}
|
|
837
|
+
static {
|
|
838
|
+
this.DEFAULT_GROUP_CONCAT_SEPARATOR = {
|
|
839
|
+
type: "Literal",
|
|
840
|
+
value: ","
|
|
841
|
+
};
|
|
842
|
+
}
|
|
723
843
|
};
|
|
724
844
|
|
|
725
845
|
// src/core/dialect/abstract.ts
|
|
726
|
-
var Dialect = class {
|
|
846
|
+
var Dialect = class _Dialect {
|
|
727
847
|
/**
|
|
728
848
|
* Compiles a SELECT query AST to SQL
|
|
729
849
|
* @param ast - Query AST to compile
|
|
@@ -896,6 +1016,35 @@ var Dialect = class {
|
|
|
896
1016
|
this.registerDefaultOperandCompilers();
|
|
897
1017
|
this.registerDefaultExpressionCompilers();
|
|
898
1018
|
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Creates a new Dialect instance (for testing purposes)
|
|
1021
|
+
* @param functionStrategy - Optional function strategy
|
|
1022
|
+
* @returns New Dialect instance
|
|
1023
|
+
*/
|
|
1024
|
+
static create(functionStrategy) {
|
|
1025
|
+
class TestDialect extends _Dialect {
|
|
1026
|
+
constructor() {
|
|
1027
|
+
super(...arguments);
|
|
1028
|
+
this.dialect = "sqlite";
|
|
1029
|
+
}
|
|
1030
|
+
quoteIdentifier(id) {
|
|
1031
|
+
return `"${id}"`;
|
|
1032
|
+
}
|
|
1033
|
+
compileSelectAst() {
|
|
1034
|
+
throw new Error("Not implemented");
|
|
1035
|
+
}
|
|
1036
|
+
compileInsertAst() {
|
|
1037
|
+
throw new Error("Not implemented");
|
|
1038
|
+
}
|
|
1039
|
+
compileUpdateAst() {
|
|
1040
|
+
throw new Error("Not implemented");
|
|
1041
|
+
}
|
|
1042
|
+
compileDeleteAst() {
|
|
1043
|
+
throw new Error("Not implemented");
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return new TestDialect(functionStrategy);
|
|
1047
|
+
}
|
|
899
1048
|
/**
|
|
900
1049
|
* Registers an expression compiler for a specific node type
|
|
901
1050
|
* @param type - Expression node type
|
|
@@ -1037,7 +1186,11 @@ var Dialect = class {
|
|
|
1037
1186
|
const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
|
|
1038
1187
|
const renderer = this.functionStrategy.getRenderer(fnNode.name);
|
|
1039
1188
|
if (renderer) {
|
|
1040
|
-
return renderer({
|
|
1189
|
+
return renderer({
|
|
1190
|
+
node: fnNode,
|
|
1191
|
+
compiledArgs,
|
|
1192
|
+
compileOperand: (operand) => this.compileOperand(operand, ctx)
|
|
1193
|
+
});
|
|
1041
1194
|
}
|
|
1042
1195
|
return `${fnNode.name}(${compiledArgs.join(", ")})`;
|
|
1043
1196
|
}
|
|
@@ -1460,6 +1613,14 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1460
1613
|
const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
|
|
1461
1614
|
return `DATE_TRUNC('${partClean}', ${date})`;
|
|
1462
1615
|
});
|
|
1616
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1617
|
+
const arg = ctx.compiledArgs[0];
|
|
1618
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
1619
|
+
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
1620
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1621
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1622
|
+
return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
|
|
1623
|
+
});
|
|
1463
1624
|
}
|
|
1464
1625
|
};
|
|
1465
1626
|
|
|
@@ -1704,6 +1865,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1704
1865
|
}
|
|
1705
1866
|
return `date(${date}, 'start of ${partClean}')`;
|
|
1706
1867
|
});
|
|
1868
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1869
|
+
const arg = ctx.compiledArgs[0];
|
|
1870
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1871
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1872
|
+
return `GROUP_CONCAT(${arg}, ${separator})`;
|
|
1873
|
+
});
|
|
1707
1874
|
}
|
|
1708
1875
|
};
|
|
1709
1876
|
|
|
@@ -1820,6 +1987,14 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1820
1987
|
const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
|
|
1821
1988
|
return `DATETRUNC(${partClean}, ${date})`;
|
|
1822
1989
|
});
|
|
1990
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1991
|
+
const arg = ctx.compiledArgs[0];
|
|
1992
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1993
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1994
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
1995
|
+
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
|
|
1996
|
+
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
1997
|
+
});
|
|
1823
1998
|
}
|
|
1824
1999
|
};
|
|
1825
2000
|
|
|
@@ -2189,62 +2364,6 @@ var createJoinNode = (kind, tableName, condition, relationName) => ({
|
|
|
2189
2364
|
meta: relationName ? { relationName } : void 0
|
|
2190
2365
|
});
|
|
2191
2366
|
|
|
2192
|
-
// src/core/sql/sql.ts
|
|
2193
|
-
var SQL_OPERATORS = {
|
|
2194
|
-
/** Equality operator */
|
|
2195
|
-
EQUALS: "=",
|
|
2196
|
-
/** Not equals operator */
|
|
2197
|
-
NOT_EQUALS: "!=",
|
|
2198
|
-
/** Greater than operator */
|
|
2199
|
-
GREATER_THAN: ">",
|
|
2200
|
-
/** Greater than or equal operator */
|
|
2201
|
-
GREATER_OR_EQUAL: ">=",
|
|
2202
|
-
/** Less than operator */
|
|
2203
|
-
LESS_THAN: "<",
|
|
2204
|
-
/** Less than or equal operator */
|
|
2205
|
-
LESS_OR_EQUAL: "<=",
|
|
2206
|
-
/** LIKE pattern matching operator */
|
|
2207
|
-
LIKE: "LIKE",
|
|
2208
|
-
/** NOT LIKE pattern matching operator */
|
|
2209
|
-
NOT_LIKE: "NOT LIKE",
|
|
2210
|
-
/** IN membership operator */
|
|
2211
|
-
IN: "IN",
|
|
2212
|
-
/** NOT IN membership operator */
|
|
2213
|
-
NOT_IN: "NOT IN",
|
|
2214
|
-
/** BETWEEN range operator */
|
|
2215
|
-
BETWEEN: "BETWEEN",
|
|
2216
|
-
/** NOT BETWEEN range operator */
|
|
2217
|
-
NOT_BETWEEN: "NOT BETWEEN",
|
|
2218
|
-
/** IS NULL null check operator */
|
|
2219
|
-
IS_NULL: "IS NULL",
|
|
2220
|
-
/** IS NOT NULL null check operator */
|
|
2221
|
-
IS_NOT_NULL: "IS NOT NULL",
|
|
2222
|
-
/** Logical AND operator */
|
|
2223
|
-
AND: "AND",
|
|
2224
|
-
/** Logical OR operator */
|
|
2225
|
-
OR: "OR",
|
|
2226
|
-
/** EXISTS operator */
|
|
2227
|
-
EXISTS: "EXISTS",
|
|
2228
|
-
/** NOT EXISTS operator */
|
|
2229
|
-
NOT_EXISTS: "NOT EXISTS"
|
|
2230
|
-
};
|
|
2231
|
-
var JOIN_KINDS = {
|
|
2232
|
-
/** INNER JOIN type */
|
|
2233
|
-
INNER: "INNER",
|
|
2234
|
-
/** LEFT JOIN type */
|
|
2235
|
-
LEFT: "LEFT",
|
|
2236
|
-
/** RIGHT JOIN type */
|
|
2237
|
-
RIGHT: "RIGHT",
|
|
2238
|
-
/** CROSS JOIN type */
|
|
2239
|
-
CROSS: "CROSS"
|
|
2240
|
-
};
|
|
2241
|
-
var ORDER_DIRECTIONS = {
|
|
2242
|
-
/** Ascending order */
|
|
2243
|
-
ASC: "ASC",
|
|
2244
|
-
/** Descending order */
|
|
2245
|
-
DESC: "DESC"
|
|
2246
|
-
};
|
|
2247
|
-
|
|
2248
2367
|
// src/query-builder/hydration-manager.ts
|
|
2249
2368
|
var HydrationManager = class _HydrationManager {
|
|
2250
2369
|
/**
|
|
@@ -4288,31 +4407,43 @@ var flattenResults = (results) => {
|
|
|
4288
4407
|
}
|
|
4289
4408
|
return rows;
|
|
4290
4409
|
};
|
|
4291
|
-
async
|
|
4410
|
+
var executeWithEntityContext = async (entityCtx, qb) => {
|
|
4292
4411
|
const ast = qb.getAST();
|
|
4293
|
-
const compiled =
|
|
4294
|
-
const executed = await
|
|
4412
|
+
const compiled = entityCtx.dialect.compileSelect(ast);
|
|
4413
|
+
const executed = await entityCtx.executor.executeSql(compiled.sql, compiled.params);
|
|
4295
4414
|
const rows = flattenResults(executed);
|
|
4296
4415
|
if (ast.setOps && ast.setOps.length > 0) {
|
|
4297
|
-
return rows.map(
|
|
4298
|
-
(row) => createEntityProxy(ctx, qb.getTable(), row, qb.getLazyRelations())
|
|
4299
|
-
);
|
|
4416
|
+
return rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4300
4417
|
}
|
|
4301
4418
|
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
4302
|
-
return hydrated.map(
|
|
4303
|
-
|
|
4304
|
-
|
|
4419
|
+
return hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
4420
|
+
};
|
|
4421
|
+
async function executeHydrated(session, qb) {
|
|
4422
|
+
return executeWithEntityContext(session, qb);
|
|
4423
|
+
}
|
|
4424
|
+
async function executeHydratedWithContexts(_execCtx, hydCtx, qb) {
|
|
4425
|
+
const entityCtx = hydCtx.entityContext;
|
|
4426
|
+
if (!entityCtx) {
|
|
4427
|
+
throw new Error("Hydration context is missing an EntityContext");
|
|
4428
|
+
}
|
|
4429
|
+
return executeWithEntityContext(entityCtx, qb);
|
|
4305
4430
|
}
|
|
4306
4431
|
|
|
4307
4432
|
// src/query-builder/select.ts
|
|
4308
4433
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
4309
4434
|
/**
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4435
|
+
|
|
4436
|
+
* Creates a new SelectQueryBuilder instance
|
|
4437
|
+
|
|
4438
|
+
* @param table - Table definition to query
|
|
4439
|
+
|
|
4440
|
+
* @param state - Optional initial query state
|
|
4441
|
+
|
|
4442
|
+
* @param hydration - Optional hydration manager
|
|
4443
|
+
|
|
4444
|
+
* @param dependencies - Optional query builder dependencies
|
|
4445
|
+
|
|
4446
|
+
*/
|
|
4316
4447
|
constructor(table, state, hydration, dependencies, lazyRelations) {
|
|
4317
4448
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
4318
4449
|
this.env = { table, deps };
|
|
@@ -4349,112 +4480,183 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4349
4480
|
return this.applyAst(this.context, (service) => service.withSetOperation(operator, subAst));
|
|
4350
4481
|
}
|
|
4351
4482
|
/**
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4483
|
+
|
|
4484
|
+
* Selects specific columns for the query
|
|
4485
|
+
|
|
4486
|
+
* @param columns - Record of column definitions, function nodes, case expressions, or window functions
|
|
4487
|
+
|
|
4488
|
+
* @returns New query builder instance with selected columns
|
|
4489
|
+
|
|
4490
|
+
*/
|
|
4356
4491
|
select(columns) {
|
|
4357
4492
|
return this.clone(this.columnSelector.select(this.context, columns));
|
|
4358
4493
|
}
|
|
4359
4494
|
/**
|
|
4360
|
-
* Selects
|
|
4361
|
-
* @param cols - Column
|
|
4362
|
-
* @returns New query builder instance with raw column selections
|
|
4495
|
+
* Selects columns from the root table by name (typed).
|
|
4496
|
+
* @param cols - Column names on the root table
|
|
4363
4497
|
*/
|
|
4498
|
+
selectColumns(...cols) {
|
|
4499
|
+
const selection = {};
|
|
4500
|
+
for (const key of cols) {
|
|
4501
|
+
const col2 = this.env.table.columns[key];
|
|
4502
|
+
if (!col2) {
|
|
4503
|
+
throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
|
|
4504
|
+
}
|
|
4505
|
+
selection[key] = col2;
|
|
4506
|
+
}
|
|
4507
|
+
return this.select(selection);
|
|
4508
|
+
}
|
|
4509
|
+
/**
|
|
4510
|
+
|
|
4511
|
+
* Selects raw column expressions
|
|
4512
|
+
|
|
4513
|
+
* @param cols - Column expressions as strings
|
|
4514
|
+
|
|
4515
|
+
* @returns New query builder instance with raw column selections
|
|
4516
|
+
|
|
4517
|
+
*/
|
|
4364
4518
|
selectRaw(...cols) {
|
|
4365
4519
|
return this.clone(this.columnSelector.selectRaw(this.context, cols));
|
|
4366
4520
|
}
|
|
4367
4521
|
/**
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4522
|
+
|
|
4523
|
+
* Adds a Common Table Expression (CTE) to the query
|
|
4524
|
+
|
|
4525
|
+
* @param name - Name of the CTE
|
|
4526
|
+
|
|
4527
|
+
* @param query - Query builder or query node for the CTE
|
|
4528
|
+
|
|
4529
|
+
* @param columns - Optional column names for the CTE
|
|
4530
|
+
|
|
4531
|
+
* @returns New query builder instance with the CTE
|
|
4532
|
+
|
|
4533
|
+
*/
|
|
4374
4534
|
with(name, query, columns) {
|
|
4375
4535
|
const subAst = this.resolveQueryNode(query);
|
|
4376
4536
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, false));
|
|
4377
4537
|
return this.clone(nextContext);
|
|
4378
4538
|
}
|
|
4379
4539
|
/**
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4540
|
+
|
|
4541
|
+
* Adds a recursive Common Table Expression (CTE) to the query
|
|
4542
|
+
|
|
4543
|
+
* @param name - Name of the CTE
|
|
4544
|
+
|
|
4545
|
+
* @param query - Query builder or query node for the CTE
|
|
4546
|
+
|
|
4547
|
+
* @param columns - Optional column names for the CTE
|
|
4548
|
+
|
|
4549
|
+
* @returns New query builder instance with the recursive CTE
|
|
4550
|
+
|
|
4551
|
+
*/
|
|
4386
4552
|
withRecursive(name, query, columns) {
|
|
4387
4553
|
const subAst = this.resolveQueryNode(query);
|
|
4388
4554
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4389
4555
|
return this.clone(nextContext);
|
|
4390
4556
|
}
|
|
4391
4557
|
/**
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4558
|
+
|
|
4559
|
+
* Selects a subquery as a column
|
|
4560
|
+
|
|
4561
|
+
* @param alias - Alias for the subquery column
|
|
4562
|
+
|
|
4563
|
+
* @param sub - Query builder or query node for the subquery
|
|
4564
|
+
|
|
4565
|
+
* @returns New query builder instance with the subquery selection
|
|
4566
|
+
|
|
4567
|
+
*/
|
|
4397
4568
|
selectSubquery(alias, sub) {
|
|
4398
4569
|
const query = this.resolveQueryNode(sub);
|
|
4399
4570
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4400
4571
|
}
|
|
4401
4572
|
/**
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4573
|
+
|
|
4574
|
+
* Adds an INNER JOIN to the query
|
|
4575
|
+
|
|
4576
|
+
* @param table - Table to join
|
|
4577
|
+
|
|
4578
|
+
* @param condition - Join condition expression
|
|
4579
|
+
|
|
4580
|
+
* @returns New query builder instance with the INNER JOIN
|
|
4581
|
+
|
|
4582
|
+
*/
|
|
4407
4583
|
innerJoin(table, condition) {
|
|
4408
4584
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
4409
4585
|
return this.clone(nextContext);
|
|
4410
4586
|
}
|
|
4411
4587
|
/**
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4588
|
+
|
|
4589
|
+
* Adds a LEFT JOIN to the query
|
|
4590
|
+
|
|
4591
|
+
* @param table - Table to join
|
|
4592
|
+
|
|
4593
|
+
* @param condition - Join condition expression
|
|
4594
|
+
|
|
4595
|
+
* @returns New query builder instance with the LEFT JOIN
|
|
4596
|
+
|
|
4597
|
+
*/
|
|
4417
4598
|
leftJoin(table, condition) {
|
|
4418
4599
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
4419
4600
|
return this.clone(nextContext);
|
|
4420
4601
|
}
|
|
4421
4602
|
/**
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4603
|
+
|
|
4604
|
+
* Adds a RIGHT JOIN to the query
|
|
4605
|
+
|
|
4606
|
+
* @param table - Table to join
|
|
4607
|
+
|
|
4608
|
+
* @param condition - Join condition expression
|
|
4609
|
+
|
|
4610
|
+
* @returns New query builder instance with the RIGHT JOIN
|
|
4611
|
+
|
|
4612
|
+
*/
|
|
4427
4613
|
rightJoin(table, condition) {
|
|
4428
4614
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
4429
4615
|
return this.clone(nextContext);
|
|
4430
4616
|
}
|
|
4431
4617
|
/**
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4618
|
+
|
|
4619
|
+
* Matches records based on a relationship
|
|
4620
|
+
|
|
4621
|
+
* @param relationName - Name of the relationship to match
|
|
4622
|
+
|
|
4623
|
+
* @param predicate - Optional predicate expression
|
|
4624
|
+
|
|
4625
|
+
* @returns New query builder instance with the relationship match
|
|
4626
|
+
|
|
4627
|
+
*/
|
|
4437
4628
|
match(relationName, predicate) {
|
|
4438
4629
|
const nextContext = this.relationManager.match(this.context, relationName, predicate);
|
|
4439
4630
|
return this.clone(nextContext);
|
|
4440
4631
|
}
|
|
4441
4632
|
/**
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4633
|
+
|
|
4634
|
+
* Joins a related table
|
|
4635
|
+
|
|
4636
|
+
* @param relationName - Name of the relationship to join
|
|
4637
|
+
|
|
4638
|
+
* @param joinKind - Type of join (defaults to INNER)
|
|
4639
|
+
|
|
4640
|
+
* @param extraCondition - Optional additional join condition
|
|
4641
|
+
|
|
4642
|
+
* @returns New query builder instance with the relationship join
|
|
4643
|
+
|
|
4644
|
+
*/
|
|
4448
4645
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
4449
4646
|
const nextContext = this.relationManager.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
4450
4647
|
return this.clone(nextContext);
|
|
4451
4648
|
}
|
|
4452
4649
|
/**
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4650
|
+
|
|
4651
|
+
* Includes related data in the query results
|
|
4652
|
+
|
|
4653
|
+
* @param relationName - Name of the relationship to include
|
|
4654
|
+
|
|
4655
|
+
* @param options - Optional include options
|
|
4656
|
+
|
|
4657
|
+
* @returns New query builder instance with the relationship inclusion
|
|
4658
|
+
|
|
4659
|
+
*/
|
|
4458
4660
|
include(relationName, options) {
|
|
4459
4661
|
const nextContext = this.relationManager.include(this.context, relationName, options);
|
|
4460
4662
|
return this.clone(nextContext);
|
|
@@ -4464,6 +4666,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4464
4666
|
nextLazy.add(relationName);
|
|
4465
4667
|
return this.clone(this.context, nextLazy);
|
|
4466
4668
|
}
|
|
4669
|
+
/**
|
|
4670
|
+
* Selects columns for a related table in a single hop.
|
|
4671
|
+
*/
|
|
4672
|
+
selectRelationColumns(relationName, ...cols) {
|
|
4673
|
+
const relation = this.env.table.relations[relationName];
|
|
4674
|
+
if (!relation) {
|
|
4675
|
+
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4676
|
+
}
|
|
4677
|
+
const target = relation.target;
|
|
4678
|
+
for (const col2 of cols) {
|
|
4679
|
+
if (!target.columns[col2]) {
|
|
4680
|
+
throw new Error(
|
|
4681
|
+
`Column '${col2}' not found on related table '${target.name}' for relation '${relationName}'`
|
|
4682
|
+
);
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
return this.include(relationName, { columns: cols });
|
|
4686
|
+
}
|
|
4687
|
+
/**
|
|
4688
|
+
* Convenience alias for selecting specific columns from a relation.
|
|
4689
|
+
*/
|
|
4690
|
+
includePick(relationName, cols) {
|
|
4691
|
+
return this.selectRelationColumns(relationName, ...cols);
|
|
4692
|
+
}
|
|
4693
|
+
/**
|
|
4694
|
+
* Selects columns for the root table and relations from a single config object.
|
|
4695
|
+
*/
|
|
4696
|
+
selectColumnsDeep(config) {
|
|
4697
|
+
let qb = this;
|
|
4698
|
+
if (config.root?.length) {
|
|
4699
|
+
qb = qb.selectColumns(...config.root);
|
|
4700
|
+
}
|
|
4701
|
+
for (const key of Object.keys(config)) {
|
|
4702
|
+
if (key === "root") continue;
|
|
4703
|
+
const relName = key;
|
|
4704
|
+
const cols = config[relName];
|
|
4705
|
+
if (!cols || !cols.length) continue;
|
|
4706
|
+
qb = qb.selectRelationColumns(relName, ...cols);
|
|
4707
|
+
}
|
|
4708
|
+
return qb;
|
|
4709
|
+
}
|
|
4467
4710
|
getLazyRelations() {
|
|
4468
4711
|
return Array.from(this.lazyRelations);
|
|
4469
4712
|
}
|
|
@@ -4473,125 +4716,186 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4473
4716
|
async execute(ctx) {
|
|
4474
4717
|
return executeHydrated(ctx, this);
|
|
4475
4718
|
}
|
|
4719
|
+
async executeWithContexts(execCtx, hydCtx) {
|
|
4720
|
+
return executeHydratedWithContexts(execCtx, hydCtx, this);
|
|
4721
|
+
}
|
|
4476
4722
|
/**
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4723
|
+
|
|
4724
|
+
* Adds a WHERE condition to the query
|
|
4725
|
+
|
|
4726
|
+
* @param expr - Expression for the WHERE clause
|
|
4727
|
+
|
|
4728
|
+
* @returns New query builder instance with the WHERE condition
|
|
4729
|
+
|
|
4730
|
+
*/
|
|
4481
4731
|
where(expr) {
|
|
4482
4732
|
const nextContext = this.applyAst(this.context, (service) => service.withWhere(expr));
|
|
4483
4733
|
return this.clone(nextContext);
|
|
4484
4734
|
}
|
|
4485
4735
|
/**
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4736
|
+
|
|
4737
|
+
* Adds a GROUP BY clause to the query
|
|
4738
|
+
|
|
4739
|
+
* @param col - Column definition or column node to group by
|
|
4740
|
+
|
|
4741
|
+
* @returns New query builder instance with the GROUP BY clause
|
|
4742
|
+
|
|
4743
|
+
*/
|
|
4490
4744
|
groupBy(col2) {
|
|
4491
4745
|
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(col2));
|
|
4492
4746
|
return this.clone(nextContext);
|
|
4493
4747
|
}
|
|
4494
4748
|
/**
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4749
|
+
|
|
4750
|
+
* Adds a HAVING condition to the query
|
|
4751
|
+
|
|
4752
|
+
* @param expr - Expression for the HAVING clause
|
|
4753
|
+
|
|
4754
|
+
* @returns New query builder instance with the HAVING condition
|
|
4755
|
+
|
|
4756
|
+
*/
|
|
4499
4757
|
having(expr) {
|
|
4500
4758
|
const nextContext = this.applyAst(this.context, (service) => service.withHaving(expr));
|
|
4501
4759
|
return this.clone(nextContext);
|
|
4502
4760
|
}
|
|
4503
4761
|
/**
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4762
|
+
|
|
4763
|
+
* Adds an ORDER BY clause to the query
|
|
4764
|
+
|
|
4765
|
+
* @param col - Column definition or column node to order by
|
|
4766
|
+
|
|
4767
|
+
* @param direction - Order direction (defaults to ASC)
|
|
4768
|
+
|
|
4769
|
+
* @returns New query builder instance with the ORDER BY clause
|
|
4770
|
+
|
|
4771
|
+
*/
|
|
4509
4772
|
orderBy(col2, direction = ORDER_DIRECTIONS.ASC) {
|
|
4510
4773
|
const nextContext = this.applyAst(this.context, (service) => service.withOrderBy(col2, direction));
|
|
4511
4774
|
return this.clone(nextContext);
|
|
4512
4775
|
}
|
|
4513
4776
|
/**
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4777
|
+
|
|
4778
|
+
* Adds a DISTINCT clause to the query
|
|
4779
|
+
|
|
4780
|
+
* @param cols - Columns to make distinct
|
|
4781
|
+
|
|
4782
|
+
* @returns New query builder instance with the DISTINCT clause
|
|
4783
|
+
|
|
4784
|
+
*/
|
|
4518
4785
|
distinct(...cols) {
|
|
4519
4786
|
return this.clone(this.columnSelector.distinct(this.context, cols));
|
|
4520
4787
|
}
|
|
4521
4788
|
/**
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4789
|
+
|
|
4790
|
+
* Adds a LIMIT clause to the query
|
|
4791
|
+
|
|
4792
|
+
* @param n - Maximum number of rows to return
|
|
4793
|
+
|
|
4794
|
+
* @returns New query builder instance with the LIMIT clause
|
|
4795
|
+
|
|
4796
|
+
*/
|
|
4526
4797
|
limit(n) {
|
|
4527
4798
|
const nextContext = this.applyAst(this.context, (service) => service.withLimit(n));
|
|
4528
4799
|
return this.clone(nextContext);
|
|
4529
4800
|
}
|
|
4530
4801
|
/**
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4802
|
+
|
|
4803
|
+
* Adds an OFFSET clause to the query
|
|
4804
|
+
|
|
4805
|
+
* @param n - Number of rows to skip
|
|
4806
|
+
|
|
4807
|
+
* @returns New query builder instance with the OFFSET clause
|
|
4808
|
+
|
|
4809
|
+
*/
|
|
4535
4810
|
offset(n) {
|
|
4536
4811
|
const nextContext = this.applyAst(this.context, (service) => service.withOffset(n));
|
|
4537
4812
|
return this.clone(nextContext);
|
|
4538
4813
|
}
|
|
4539
4814
|
/**
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4815
|
+
|
|
4816
|
+
* Combines this query with another using UNION
|
|
4817
|
+
|
|
4818
|
+
* @param query - Query to union with
|
|
4819
|
+
|
|
4820
|
+
* @returns New query builder instance with the set operation
|
|
4821
|
+
|
|
4822
|
+
*/
|
|
4544
4823
|
union(query) {
|
|
4545
4824
|
return this.clone(this.applySetOperation("UNION", query));
|
|
4546
4825
|
}
|
|
4547
4826
|
/**
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4827
|
+
|
|
4828
|
+
* Combines this query with another using UNION ALL
|
|
4829
|
+
|
|
4830
|
+
* @param query - Query to union with
|
|
4831
|
+
|
|
4832
|
+
* @returns New query builder instance with the set operation
|
|
4833
|
+
|
|
4834
|
+
*/
|
|
4552
4835
|
unionAll(query) {
|
|
4553
4836
|
return this.clone(this.applySetOperation("UNION ALL", query));
|
|
4554
4837
|
}
|
|
4555
4838
|
/**
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4839
|
+
|
|
4840
|
+
* Combines this query with another using INTERSECT
|
|
4841
|
+
|
|
4842
|
+
* @param query - Query to intersect with
|
|
4843
|
+
|
|
4844
|
+
* @returns New query builder instance with the set operation
|
|
4845
|
+
|
|
4846
|
+
*/
|
|
4560
4847
|
intersect(query) {
|
|
4561
4848
|
return this.clone(this.applySetOperation("INTERSECT", query));
|
|
4562
4849
|
}
|
|
4563
4850
|
/**
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4851
|
+
|
|
4852
|
+
* Combines this query with another using EXCEPT
|
|
4853
|
+
|
|
4854
|
+
* @param query - Query to subtract
|
|
4855
|
+
|
|
4856
|
+
* @returns New query builder instance with the set operation
|
|
4857
|
+
|
|
4858
|
+
*/
|
|
4568
4859
|
except(query) {
|
|
4569
4860
|
return this.clone(this.applySetOperation("EXCEPT", query));
|
|
4570
4861
|
}
|
|
4571
4862
|
/**
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4863
|
+
|
|
4864
|
+
* Adds a WHERE EXISTS condition to the query
|
|
4865
|
+
|
|
4866
|
+
* @param subquery - Subquery to check for existence
|
|
4867
|
+
|
|
4868
|
+
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4869
|
+
|
|
4870
|
+
*/
|
|
4576
4871
|
whereExists(subquery) {
|
|
4577
4872
|
const subAst = this.resolveQueryNode(subquery);
|
|
4578
4873
|
return this.where(exists(subAst));
|
|
4579
4874
|
}
|
|
4580
4875
|
/**
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4876
|
+
|
|
4877
|
+
* Adds a WHERE NOT EXISTS condition to the query
|
|
4878
|
+
|
|
4879
|
+
* @param subquery - Subquery to check for non-existence
|
|
4880
|
+
|
|
4881
|
+
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4882
|
+
|
|
4883
|
+
*/
|
|
4585
4884
|
whereNotExists(subquery) {
|
|
4586
4885
|
const subAst = this.resolveQueryNode(subquery);
|
|
4587
4886
|
return this.where(notExists(subAst));
|
|
4588
4887
|
}
|
|
4589
4888
|
/**
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4889
|
+
|
|
4890
|
+
* Adds a WHERE EXISTS condition based on a relationship
|
|
4891
|
+
|
|
4892
|
+
* @param relationName - Name of the relationship to check
|
|
4893
|
+
|
|
4894
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4895
|
+
|
|
4896
|
+
* @returns New query builder instance with the relationship existence check
|
|
4897
|
+
|
|
4898
|
+
*/
|
|
4595
4899
|
whereHas(relationName, callback) {
|
|
4596
4900
|
const relation = this.env.table.relations[relationName];
|
|
4597
4901
|
if (!relation) {
|
|
@@ -4606,11 +4910,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4606
4910
|
return this.where(exists(finalSubAst));
|
|
4607
4911
|
}
|
|
4608
4912
|
/**
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4913
|
+
|
|
4914
|
+
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
4915
|
+
|
|
4916
|
+
* @param relationName - Name of the relationship to check
|
|
4917
|
+
|
|
4918
|
+
* @param callback - Optional callback to modify the relationship query
|
|
4919
|
+
|
|
4920
|
+
* @returns New query builder instance with the relationship non-existence check
|
|
4921
|
+
|
|
4922
|
+
*/
|
|
4614
4923
|
whereHasNot(relationName, callback) {
|
|
4615
4924
|
const relation = this.env.table.relations[relationName];
|
|
4616
4925
|
if (!relation) {
|
|
@@ -4625,33 +4934,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4625
4934
|
return this.where(notExists(finalSubAst));
|
|
4626
4935
|
}
|
|
4627
4936
|
/**
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4937
|
+
|
|
4938
|
+
* Compiles the query to SQL for a specific dialect
|
|
4939
|
+
|
|
4940
|
+
* @param dialect - Database dialect to compile for
|
|
4941
|
+
|
|
4942
|
+
* @returns Compiled query with SQL and parameters
|
|
4943
|
+
|
|
4944
|
+
*/
|
|
4632
4945
|
compile(dialect) {
|
|
4633
4946
|
const resolved = resolveDialectInput(dialect);
|
|
4634
4947
|
return resolved.compileSelect(this.context.state.ast);
|
|
4635
4948
|
}
|
|
4636
4949
|
/**
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4950
|
+
|
|
4951
|
+
* Converts the query to SQL string for a specific dialect
|
|
4952
|
+
|
|
4953
|
+
* @param dialect - Database dialect to generate SQL for
|
|
4954
|
+
|
|
4955
|
+
* @returns SQL string representation of the query
|
|
4956
|
+
|
|
4957
|
+
*/
|
|
4641
4958
|
toSql(dialect) {
|
|
4642
4959
|
return this.compile(dialect).sql;
|
|
4643
4960
|
}
|
|
4644
4961
|
/**
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4962
|
+
|
|
4963
|
+
* Gets the hydration plan for the query
|
|
4964
|
+
|
|
4965
|
+
* @returns Hydration plan or undefined if none exists
|
|
4966
|
+
|
|
4967
|
+
*/
|
|
4648
4968
|
getHydrationPlan() {
|
|
4649
4969
|
return this.context.hydration.getPlan();
|
|
4650
4970
|
}
|
|
4651
4971
|
/**
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4972
|
+
|
|
4973
|
+
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
4974
|
+
|
|
4975
|
+
* @returns Query AST with hydration applied
|
|
4976
|
+
|
|
4977
|
+
*/
|
|
4655
4978
|
getAST() {
|
|
4656
4979
|
return this.context.hydration.applyToAst(this.context.state.ast);
|
|
4657
4980
|
}
|
|
@@ -4659,6 +4982,54 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4659
4982
|
var createColumn = (table, name) => ({ type: "Column", table, name });
|
|
4660
4983
|
var createLiteral = (val) => ({ type: "Literal", value: val });
|
|
4661
4984
|
|
|
4985
|
+
// src/orm/entity-metadata.ts
|
|
4986
|
+
var metadataMap = /* @__PURE__ */ new Map();
|
|
4987
|
+
var getEntityMetadata = (target) => {
|
|
4988
|
+
return metadataMap.get(target);
|
|
4989
|
+
};
|
|
4990
|
+
|
|
4991
|
+
// src/decorators/bootstrap.ts
|
|
4992
|
+
var getTableDefFromEntity = (ctor) => {
|
|
4993
|
+
const meta = getEntityMetadata(ctor);
|
|
4994
|
+
if (!meta) return void 0;
|
|
4995
|
+
return meta.table;
|
|
4996
|
+
};
|
|
4997
|
+
var selectFromEntity = (ctor) => {
|
|
4998
|
+
const table = getTableDefFromEntity(ctor);
|
|
4999
|
+
if (!table) {
|
|
5000
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
5001
|
+
}
|
|
5002
|
+
return new SelectQueryBuilder(table);
|
|
5003
|
+
};
|
|
5004
|
+
|
|
5005
|
+
// src/query-builder/select-helpers.ts
|
|
5006
|
+
function sel(table, ...cols) {
|
|
5007
|
+
const selection = {};
|
|
5008
|
+
for (const col2 of cols) {
|
|
5009
|
+
const def = table.columns[col2];
|
|
5010
|
+
if (!def) {
|
|
5011
|
+
throw new Error(`Column '${col2}' not found on table '${table.name}'`);
|
|
5012
|
+
}
|
|
5013
|
+
selection[col2] = def;
|
|
5014
|
+
}
|
|
5015
|
+
return selection;
|
|
5016
|
+
}
|
|
5017
|
+
function esel(entity, ...props) {
|
|
5018
|
+
const table = getTableDefFromEntity(entity);
|
|
5019
|
+
if (!table) {
|
|
5020
|
+
throw new Error(`No table definition registered for entity '${entity.name}'`);
|
|
5021
|
+
}
|
|
5022
|
+
const selection = {};
|
|
5023
|
+
for (const prop of props) {
|
|
5024
|
+
const col2 = table.columns[prop];
|
|
5025
|
+
if (!col2) {
|
|
5026
|
+
throw new Error(`No column '${prop}' found for entity '${entity.name}'`);
|
|
5027
|
+
}
|
|
5028
|
+
selection[prop] = col2;
|
|
5029
|
+
}
|
|
5030
|
+
return selection;
|
|
5031
|
+
}
|
|
5032
|
+
|
|
4662
5033
|
// src/query-builder/insert-query-state.ts
|
|
4663
5034
|
var InsertQueryState = class _InsertQueryState {
|
|
4664
5035
|
constructor(table, ast) {
|
|
@@ -4677,7 +5048,15 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
4677
5048
|
if (!rows.length) return this;
|
|
4678
5049
|
const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
|
|
4679
5050
|
const newRows = rows.map(
|
|
4680
|
-
(row) => definedColumns.map((column) =>
|
|
5051
|
+
(row, rowIndex) => definedColumns.map((column) => {
|
|
5052
|
+
const rawValue = row[column.name];
|
|
5053
|
+
if (!isValueOperandInput(rawValue)) {
|
|
5054
|
+
throw new Error(
|
|
5055
|
+
`Invalid insert value for column "${column.name}" in row ${rowIndex}: only primitives, null, or OperandNodes are allowed`
|
|
5056
|
+
);
|
|
5057
|
+
}
|
|
5058
|
+
return valueToOperand(rawValue);
|
|
5059
|
+
})
|
|
4681
5060
|
);
|
|
4682
5061
|
return this.clone({
|
|
4683
5062
|
...this.ast,
|
|
@@ -4728,6 +5107,17 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
4728
5107
|
};
|
|
4729
5108
|
|
|
4730
5109
|
// src/query-builder/update-query-state.ts
|
|
5110
|
+
var isUpdateValue = (value) => {
|
|
5111
|
+
if (value === null) return true;
|
|
5112
|
+
switch (typeof value) {
|
|
5113
|
+
case "string":
|
|
5114
|
+
case "number":
|
|
5115
|
+
case "boolean":
|
|
5116
|
+
return true;
|
|
5117
|
+
default:
|
|
5118
|
+
return isOperandNode(value);
|
|
5119
|
+
}
|
|
5120
|
+
};
|
|
4731
5121
|
var UpdateQueryState = class _UpdateQueryState {
|
|
4732
5122
|
constructor(table, ast) {
|
|
4733
5123
|
this.table = table;
|
|
@@ -4741,14 +5131,21 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
4741
5131
|
return new _UpdateQueryState(this.table, nextAst);
|
|
4742
5132
|
}
|
|
4743
5133
|
withSet(values) {
|
|
4744
|
-
const assignments = Object.entries(values).map(([column,
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
}
|
|
4750
|
-
|
|
4751
|
-
|
|
5134
|
+
const assignments = Object.entries(values).map(([column, rawValue]) => {
|
|
5135
|
+
if (!isUpdateValue(rawValue)) {
|
|
5136
|
+
throw new Error(
|
|
5137
|
+
`Invalid update value for column "${column}": only primitives, null, or OperandNodes are allowed`
|
|
5138
|
+
);
|
|
5139
|
+
}
|
|
5140
|
+
return {
|
|
5141
|
+
column: {
|
|
5142
|
+
type: "Column",
|
|
5143
|
+
table: this.table.name,
|
|
5144
|
+
name: column
|
|
5145
|
+
},
|
|
5146
|
+
value: valueToOperand(rawValue)
|
|
5147
|
+
};
|
|
5148
|
+
});
|
|
4752
5149
|
return this.clone({
|
|
4753
5150
|
...this.ast,
|
|
4754
5151
|
set: assignments
|
|
@@ -5949,20 +6346,55 @@ var SQL_OPERATOR_REGISTRY = {
|
|
|
5949
6346
|
[SQL_OPERATORS.NOT_EXISTS]: { sql: SQL_OPERATORS.NOT_EXISTS, tsName: "notExists" }
|
|
5950
6347
|
};
|
|
5951
6348
|
|
|
5952
|
-
// src/codegen/
|
|
5953
|
-
var
|
|
5954
|
-
var assertNever2 = (value) => {
|
|
5955
|
-
throw new Error(`Unhandled SQL operator: ${value}`);
|
|
5956
|
-
};
|
|
5957
|
-
var TypeScriptGenerator = class {
|
|
6349
|
+
// src/codegen/naming-strategy.ts
|
|
6350
|
+
var DefaultNamingStrategy = class {
|
|
5958
6351
|
/**
|
|
5959
|
-
*
|
|
5960
|
-
* @param
|
|
5961
|
-
* @returns
|
|
6352
|
+
* Converts table names to TypeScript symbols
|
|
6353
|
+
* @param table - Table node, function table node, or string name
|
|
6354
|
+
* @returns Capitalized table name (handles schema-qualified names)
|
|
5962
6355
|
*/
|
|
5963
|
-
|
|
5964
|
-
const
|
|
5965
|
-
|
|
6356
|
+
tableToSymbol(table) {
|
|
6357
|
+
const tableName = typeof table === "string" ? table : table.name;
|
|
6358
|
+
if (tableName.includes(".")) {
|
|
6359
|
+
return tableName.split(".").map((part) => this.capitalize(part)).join("");
|
|
6360
|
+
}
|
|
6361
|
+
return this.capitalize(tableName);
|
|
6362
|
+
}
|
|
6363
|
+
/**
|
|
6364
|
+
* Converts column references to property names
|
|
6365
|
+
* @param column - Column node
|
|
6366
|
+
* @returns Column name as-is (for backward compatibility)
|
|
6367
|
+
*/
|
|
6368
|
+
columnToProperty(column) {
|
|
6369
|
+
return column.name;
|
|
6370
|
+
}
|
|
6371
|
+
/**
|
|
6372
|
+
* Capitalizes the first letter of a string
|
|
6373
|
+
* @param s - String to capitalize
|
|
6374
|
+
* @returns Capitalized string
|
|
6375
|
+
*/
|
|
6376
|
+
capitalize(s) {
|
|
6377
|
+
if (!s) return s;
|
|
6378
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
6379
|
+
}
|
|
6380
|
+
};
|
|
6381
|
+
|
|
6382
|
+
// src/codegen/typescript.ts
|
|
6383
|
+
var assertNever2 = (value) => {
|
|
6384
|
+
throw new Error(`Unhandled SQL operator: ${value}`);
|
|
6385
|
+
};
|
|
6386
|
+
var TypeScriptGenerator = class {
|
|
6387
|
+
constructor(namingStrategy = new DefaultNamingStrategy()) {
|
|
6388
|
+
this.namingStrategy = namingStrategy;
|
|
6389
|
+
}
|
|
6390
|
+
/**
|
|
6391
|
+
* Generates TypeScript code from a query AST
|
|
6392
|
+
* @param ast - Query AST to generate code from
|
|
6393
|
+
* @returns Generated TypeScript code
|
|
6394
|
+
*/
|
|
6395
|
+
generate(ast) {
|
|
6396
|
+
const chainLines = this.buildSelectLines(ast);
|
|
6397
|
+
const lines = chainLines.map((line, index) => index === 0 ? `const query = ${line}` : line);
|
|
5966
6398
|
lines.push(";", "", "await query.execute();");
|
|
5967
6399
|
return lines.join("\n");
|
|
5968
6400
|
}
|
|
@@ -5981,13 +6413,13 @@ var TypeScriptGenerator = class {
|
|
|
5981
6413
|
return `${key}: ${this.printOperand(operand)}`;
|
|
5982
6414
|
});
|
|
5983
6415
|
lines.push(`db.select({`);
|
|
5984
|
-
selections.forEach((
|
|
5985
|
-
lines.push(` ${
|
|
6416
|
+
selections.forEach((sel2, index) => {
|
|
6417
|
+
lines.push(` ${sel2}${index < selections.length - 1 ? "," : ""}`);
|
|
5986
6418
|
});
|
|
5987
6419
|
lines.push(`})`);
|
|
5988
|
-
lines.push(`.from(${
|
|
6420
|
+
lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
|
|
5989
6421
|
if (ast.distinct && ast.distinct.length) {
|
|
5990
|
-
const cols = ast.distinct.map((c) => `${
|
|
6422
|
+
const cols = ast.distinct.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
5991
6423
|
lines.push(`.distinct(${cols})`);
|
|
5992
6424
|
}
|
|
5993
6425
|
ast.joins.forEach((join) => {
|
|
@@ -6002,7 +6434,7 @@ var TypeScriptGenerator = class {
|
|
|
6002
6434
|
lines.push(`.joinRelation('${relationName}', '${join.kind}')`);
|
|
6003
6435
|
}
|
|
6004
6436
|
} else {
|
|
6005
|
-
const table =
|
|
6437
|
+
const table = this.namingStrategy.tableToSymbol(join.table);
|
|
6006
6438
|
const cond = this.printExpression(join.condition);
|
|
6007
6439
|
let method = "innerJoin";
|
|
6008
6440
|
if (join.kind === "LEFT") method = "leftJoin";
|
|
@@ -6023,7 +6455,7 @@ var TypeScriptGenerator = class {
|
|
|
6023
6455
|
lines.push(`.where(${this.printExpression(ast.where)})`);
|
|
6024
6456
|
}
|
|
6025
6457
|
if (ast.groupBy && ast.groupBy.length) {
|
|
6026
|
-
const cols = ast.groupBy.map((c) => `${
|
|
6458
|
+
const cols = ast.groupBy.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
|
|
6027
6459
|
lines.push(`.groupBy(${cols})`);
|
|
6028
6460
|
}
|
|
6029
6461
|
if (ast.having) {
|
|
@@ -6031,7 +6463,7 @@ var TypeScriptGenerator = class {
|
|
|
6031
6463
|
}
|
|
6032
6464
|
if (ast.orderBy && ast.orderBy.length) {
|
|
6033
6465
|
ast.orderBy.forEach((o) => {
|
|
6034
|
-
lines.push(`.orderBy(${
|
|
6466
|
+
lines.push(`.orderBy(${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name}, '${o.direction}')`);
|
|
6035
6467
|
});
|
|
6036
6468
|
}
|
|
6037
6469
|
if (ast.limit) lines.push(`.limit(${ast.limit})`);
|
|
@@ -6170,7 +6602,7 @@ var TypeScriptGenerator = class {
|
|
|
6170
6602
|
* @returns TypeScript code representation
|
|
6171
6603
|
*/
|
|
6172
6604
|
printColumnOperand(column) {
|
|
6173
|
-
return `${
|
|
6605
|
+
return `${this.namingStrategy.tableToSymbol(column.table)}.${column.name}`;
|
|
6174
6606
|
}
|
|
6175
6607
|
/**
|
|
6176
6608
|
* Prints a literal operand to TypeScript code
|
|
@@ -6196,7 +6628,7 @@ var TypeScriptGenerator = class {
|
|
|
6196
6628
|
* @returns TypeScript code representation
|
|
6197
6629
|
*/
|
|
6198
6630
|
printJsonPathOperand(json) {
|
|
6199
|
-
return `jsonPath(${
|
|
6631
|
+
return `jsonPath(${this.namingStrategy.tableToSymbol(json.column.table)}.${json.column.name}, '${json.path}')`;
|
|
6200
6632
|
}
|
|
6201
6633
|
/**
|
|
6202
6634
|
* Prints a scalar subquery operand to TypeScript code
|
|
@@ -6232,11 +6664,11 @@ var TypeScriptGenerator = class {
|
|
|
6232
6664
|
result += ") OVER (";
|
|
6233
6665
|
const parts = [];
|
|
6234
6666
|
if (node.partitionBy && node.partitionBy.length > 0) {
|
|
6235
|
-
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${
|
|
6667
|
+
const partitionClause = "PARTITION BY " + node.partitionBy.map((col2) => `${this.namingStrategy.tableToSymbol(col2.table)}.${col2.name}`).join(", ");
|
|
6236
6668
|
parts.push(partitionClause);
|
|
6237
6669
|
}
|
|
6238
6670
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
6239
|
-
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${
|
|
6671
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => `${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name} ${o.direction}`).join(", ");
|
|
6240
6672
|
parts.push(orderClause);
|
|
6241
6673
|
}
|
|
6242
6674
|
result += parts.join(" ");
|
|
@@ -6265,48 +6697,6 @@ var TypeScriptGenerator = class {
|
|
|
6265
6697
|
}
|
|
6266
6698
|
};
|
|
6267
6699
|
|
|
6268
|
-
// src/orm/domain-event-bus.ts
|
|
6269
|
-
var DomainEventBus = class {
|
|
6270
|
-
constructor(initialHandlers) {
|
|
6271
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
6272
|
-
const handlers = initialHandlers ?? {};
|
|
6273
|
-
Object.entries(handlers).forEach(([name, list]) => {
|
|
6274
|
-
this.handlers.set(name, [...list]);
|
|
6275
|
-
});
|
|
6276
|
-
}
|
|
6277
|
-
register(name, handler) {
|
|
6278
|
-
const existing = this.handlers.get(name) ?? [];
|
|
6279
|
-
existing.push(handler);
|
|
6280
|
-
this.handlers.set(name, existing);
|
|
6281
|
-
}
|
|
6282
|
-
async dispatch(trackedEntities, ctx) {
|
|
6283
|
-
for (const tracked of trackedEntities) {
|
|
6284
|
-
const entity = tracked.entity;
|
|
6285
|
-
if (!entity.domainEvents || !entity.domainEvents.length) continue;
|
|
6286
|
-
for (const event of entity.domainEvents) {
|
|
6287
|
-
const eventName = this.getEventName(event);
|
|
6288
|
-
const handlers = this.handlers.get(eventName);
|
|
6289
|
-
if (!handlers) continue;
|
|
6290
|
-
for (const handler of handlers) {
|
|
6291
|
-
await handler(event, ctx);
|
|
6292
|
-
}
|
|
6293
|
-
}
|
|
6294
|
-
entity.domainEvents = [];
|
|
6295
|
-
}
|
|
6296
|
-
}
|
|
6297
|
-
getEventName(event) {
|
|
6298
|
-
if (!event) return "Unknown";
|
|
6299
|
-
if (typeof event === "string") return event;
|
|
6300
|
-
return event.constructor?.name ?? "Unknown";
|
|
6301
|
-
}
|
|
6302
|
-
};
|
|
6303
|
-
var addDomainEvent = (entity, event) => {
|
|
6304
|
-
if (!entity.domainEvents) {
|
|
6305
|
-
entity.domainEvents = [];
|
|
6306
|
-
}
|
|
6307
|
-
entity.domainEvents.push(event);
|
|
6308
|
-
};
|
|
6309
|
-
|
|
6310
6700
|
// src/orm/identity-map.ts
|
|
6311
6701
|
var IdentityMap = class {
|
|
6312
6702
|
constructor() {
|
|
@@ -6334,169 +6724,14 @@ var IdentityMap = class {
|
|
|
6334
6724
|
const bucket = this.buckets.get(table.name);
|
|
6335
6725
|
return bucket ? Array.from(bucket.values()) : [];
|
|
6336
6726
|
}
|
|
6727
|
+
clear() {
|
|
6728
|
+
this.buckets.clear();
|
|
6729
|
+
}
|
|
6337
6730
|
toIdentityKey(pk) {
|
|
6338
6731
|
return String(pk);
|
|
6339
6732
|
}
|
|
6340
6733
|
};
|
|
6341
6734
|
|
|
6342
|
-
// src/orm/relation-change-processor.ts
|
|
6343
|
-
var RelationChangeProcessor = class {
|
|
6344
|
-
constructor(unitOfWork, dialect, executor) {
|
|
6345
|
-
this.unitOfWork = unitOfWork;
|
|
6346
|
-
this.dialect = dialect;
|
|
6347
|
-
this.executor = executor;
|
|
6348
|
-
this.relationChanges = [];
|
|
6349
|
-
}
|
|
6350
|
-
registerChange(entry) {
|
|
6351
|
-
this.relationChanges.push(entry);
|
|
6352
|
-
}
|
|
6353
|
-
async process() {
|
|
6354
|
-
if (!this.relationChanges.length) return;
|
|
6355
|
-
const entries = [...this.relationChanges];
|
|
6356
|
-
this.relationChanges.length = 0;
|
|
6357
|
-
for (const entry of entries) {
|
|
6358
|
-
switch (entry.relation.type) {
|
|
6359
|
-
case RelationKinds.HasMany:
|
|
6360
|
-
await this.handleHasManyChange(entry);
|
|
6361
|
-
break;
|
|
6362
|
-
case RelationKinds.HasOne:
|
|
6363
|
-
await this.handleHasOneChange(entry);
|
|
6364
|
-
break;
|
|
6365
|
-
case RelationKinds.BelongsToMany:
|
|
6366
|
-
await this.handleBelongsToManyChange(entry);
|
|
6367
|
-
break;
|
|
6368
|
-
case RelationKinds.BelongsTo:
|
|
6369
|
-
await this.handleBelongsToChange(entry);
|
|
6370
|
-
break;
|
|
6371
|
-
}
|
|
6372
|
-
}
|
|
6373
|
-
}
|
|
6374
|
-
async handleHasManyChange(entry) {
|
|
6375
|
-
const relation = entry.relation;
|
|
6376
|
-
const target = entry.change.entity;
|
|
6377
|
-
if (!target) return;
|
|
6378
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6379
|
-
if (!tracked) return;
|
|
6380
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6381
|
-
const rootValue = entry.root[localKey];
|
|
6382
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6383
|
-
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
6384
|
-
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
6385
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6386
|
-
return;
|
|
6387
|
-
}
|
|
6388
|
-
if (entry.change.kind === "remove") {
|
|
6389
|
-
this.detachHasManyChild(tracked.entity, relation);
|
|
6390
|
-
}
|
|
6391
|
-
}
|
|
6392
|
-
async handleHasOneChange(entry) {
|
|
6393
|
-
const relation = entry.relation;
|
|
6394
|
-
const target = entry.change.entity;
|
|
6395
|
-
if (!target) return;
|
|
6396
|
-
const tracked = this.unitOfWork.findTracked(target);
|
|
6397
|
-
if (!tracked) return;
|
|
6398
|
-
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6399
|
-
const rootValue = entry.root[localKey];
|
|
6400
|
-
if (rootValue === void 0 || rootValue === null) return;
|
|
6401
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6402
|
-
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
6403
|
-
this.unitOfWork.markDirty(tracked.entity);
|
|
6404
|
-
return;
|
|
6405
|
-
}
|
|
6406
|
-
if (entry.change.kind === "remove") {
|
|
6407
|
-
this.detachHasOneChild(tracked.entity, relation);
|
|
6408
|
-
}
|
|
6409
|
-
}
|
|
6410
|
-
async handleBelongsToChange(_entry) {
|
|
6411
|
-
}
|
|
6412
|
-
async handleBelongsToManyChange(entry) {
|
|
6413
|
-
const relation = entry.relation;
|
|
6414
|
-
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
6415
|
-
const rootId = entry.root[rootKey];
|
|
6416
|
-
if (rootId === void 0 || rootId === null) return;
|
|
6417
|
-
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
6418
|
-
if (targetId === null) return;
|
|
6419
|
-
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
6420
|
-
await this.insertPivotRow(relation, rootId, targetId);
|
|
6421
|
-
return;
|
|
6422
|
-
}
|
|
6423
|
-
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
6424
|
-
await this.deletePivotRow(relation, rootId, targetId);
|
|
6425
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6426
|
-
this.unitOfWork.markRemoved(entry.change.entity);
|
|
6427
|
-
}
|
|
6428
|
-
}
|
|
6429
|
-
}
|
|
6430
|
-
assignHasManyForeignKey(child, relation, rootValue) {
|
|
6431
|
-
const current = child[relation.foreignKey];
|
|
6432
|
-
if (current === rootValue) return;
|
|
6433
|
-
child[relation.foreignKey] = rootValue;
|
|
6434
|
-
}
|
|
6435
|
-
detachHasManyChild(child, relation) {
|
|
6436
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6437
|
-
this.unitOfWork.markRemoved(child);
|
|
6438
|
-
return;
|
|
6439
|
-
}
|
|
6440
|
-
child[relation.foreignKey] = null;
|
|
6441
|
-
this.unitOfWork.markDirty(child);
|
|
6442
|
-
}
|
|
6443
|
-
assignHasOneForeignKey(child, relation, rootValue) {
|
|
6444
|
-
const current = child[relation.foreignKey];
|
|
6445
|
-
if (current === rootValue) return;
|
|
6446
|
-
child[relation.foreignKey] = rootValue;
|
|
6447
|
-
}
|
|
6448
|
-
detachHasOneChild(child, relation) {
|
|
6449
|
-
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
6450
|
-
this.unitOfWork.markRemoved(child);
|
|
6451
|
-
return;
|
|
6452
|
-
}
|
|
6453
|
-
child[relation.foreignKey] = null;
|
|
6454
|
-
this.unitOfWork.markDirty(child);
|
|
6455
|
-
}
|
|
6456
|
-
async insertPivotRow(relation, rootId, targetId) {
|
|
6457
|
-
const payload = {
|
|
6458
|
-
[relation.pivotForeignKeyToRoot]: rootId,
|
|
6459
|
-
[relation.pivotForeignKeyToTarget]: targetId
|
|
6460
|
-
};
|
|
6461
|
-
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
6462
|
-
const compiled = builder.compile(this.dialect);
|
|
6463
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6464
|
-
}
|
|
6465
|
-
async deletePivotRow(relation, rootId, targetId) {
|
|
6466
|
-
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
6467
|
-
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
6468
|
-
if (!rootCol || !targetCol) return;
|
|
6469
|
-
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
6470
|
-
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
6471
|
-
);
|
|
6472
|
-
const compiled = builder.compile(this.dialect);
|
|
6473
|
-
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
6474
|
-
}
|
|
6475
|
-
resolvePrimaryKeyValue(entity, table) {
|
|
6476
|
-
if (!entity) return null;
|
|
6477
|
-
const key = findPrimaryKey(table);
|
|
6478
|
-
const value = entity[key];
|
|
6479
|
-
if (value === void 0 || value === null) return null;
|
|
6480
|
-
return value;
|
|
6481
|
-
}
|
|
6482
|
-
};
|
|
6483
|
-
|
|
6484
|
-
// src/orm/transaction-runner.ts
|
|
6485
|
-
var runInTransaction = async (executor, action) => {
|
|
6486
|
-
if (!executor.beginTransaction) {
|
|
6487
|
-
await action();
|
|
6488
|
-
return;
|
|
6489
|
-
}
|
|
6490
|
-
await executor.beginTransaction();
|
|
6491
|
-
try {
|
|
6492
|
-
await action();
|
|
6493
|
-
await executor.commitTransaction?.();
|
|
6494
|
-
} catch (error) {
|
|
6495
|
-
await executor.rollbackTransaction?.();
|
|
6496
|
-
throw error;
|
|
6497
|
-
}
|
|
6498
|
-
};
|
|
6499
|
-
|
|
6500
6735
|
// src/orm/runtime-types.ts
|
|
6501
6736
|
var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
6502
6737
|
EntityStatus2["New"] = "new";
|
|
@@ -6601,6 +6836,10 @@ var UnitOfWork = class {
|
|
|
6601
6836
|
}
|
|
6602
6837
|
}
|
|
6603
6838
|
}
|
|
6839
|
+
reset() {
|
|
6840
|
+
this.trackedEntities.clear();
|
|
6841
|
+
this.identityMap.clear();
|
|
6842
|
+
}
|
|
6604
6843
|
async flushInsert(tracked) {
|
|
6605
6844
|
await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
|
|
6606
6845
|
const payload = this.extractColumns(tracked.table, tracked.entity);
|
|
@@ -6670,6 +6909,7 @@ var UnitOfWork = class {
|
|
|
6670
6909
|
extractColumns(table, entity) {
|
|
6671
6910
|
const payload = {};
|
|
6672
6911
|
for (const column of Object.keys(table.columns)) {
|
|
6912
|
+
if (entity[column] === void 0) continue;
|
|
6673
6913
|
payload[column] = entity[column];
|
|
6674
6914
|
}
|
|
6675
6915
|
return payload;
|
|
@@ -6720,6 +6960,194 @@ var UnitOfWork = class {
|
|
|
6720
6960
|
}
|
|
6721
6961
|
};
|
|
6722
6962
|
|
|
6963
|
+
// src/orm/domain-event-bus.ts
|
|
6964
|
+
var DomainEventBus = class {
|
|
6965
|
+
constructor(initialHandlers) {
|
|
6966
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
6967
|
+
if (initialHandlers) {
|
|
6968
|
+
for (const key in initialHandlers) {
|
|
6969
|
+
const type = key;
|
|
6970
|
+
const list = initialHandlers[type] ?? [];
|
|
6971
|
+
this.handlers.set(type, [...list]);
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6974
|
+
}
|
|
6975
|
+
on(type, handler) {
|
|
6976
|
+
const key = type;
|
|
6977
|
+
const existing = this.handlers.get(key) ?? [];
|
|
6978
|
+
existing.push(handler);
|
|
6979
|
+
this.handlers.set(key, existing);
|
|
6980
|
+
}
|
|
6981
|
+
register(type, handler) {
|
|
6982
|
+
this.on(type, handler);
|
|
6983
|
+
}
|
|
6984
|
+
async dispatch(trackedEntities, ctx) {
|
|
6985
|
+
for (const tracked of trackedEntities) {
|
|
6986
|
+
const entity = tracked.entity;
|
|
6987
|
+
if (!entity.domainEvents?.length) continue;
|
|
6988
|
+
for (const event of entity.domainEvents) {
|
|
6989
|
+
const handlers = this.handlers.get(event.type);
|
|
6990
|
+
if (!handlers?.length) continue;
|
|
6991
|
+
for (const handler of handlers) {
|
|
6992
|
+
await handler(event, ctx);
|
|
6993
|
+
}
|
|
6994
|
+
}
|
|
6995
|
+
entity.domainEvents = [];
|
|
6996
|
+
}
|
|
6997
|
+
}
|
|
6998
|
+
};
|
|
6999
|
+
var addDomainEvent = (entity, event) => {
|
|
7000
|
+
if (!entity.domainEvents) {
|
|
7001
|
+
entity.domainEvents = [];
|
|
7002
|
+
}
|
|
7003
|
+
entity.domainEvents.push(event);
|
|
7004
|
+
};
|
|
7005
|
+
|
|
7006
|
+
// src/orm/relation-change-processor.ts
|
|
7007
|
+
var RelationChangeProcessor = class {
|
|
7008
|
+
constructor(unitOfWork, dialect, executor) {
|
|
7009
|
+
this.unitOfWork = unitOfWork;
|
|
7010
|
+
this.dialect = dialect;
|
|
7011
|
+
this.executor = executor;
|
|
7012
|
+
this.relationChanges = [];
|
|
7013
|
+
}
|
|
7014
|
+
registerChange(entry) {
|
|
7015
|
+
this.relationChanges.push(entry);
|
|
7016
|
+
}
|
|
7017
|
+
reset() {
|
|
7018
|
+
this.relationChanges.length = 0;
|
|
7019
|
+
}
|
|
7020
|
+
async process() {
|
|
7021
|
+
if (!this.relationChanges.length) return;
|
|
7022
|
+
const entries = [...this.relationChanges];
|
|
7023
|
+
this.relationChanges.length = 0;
|
|
7024
|
+
for (const entry of entries) {
|
|
7025
|
+
switch (entry.relation.type) {
|
|
7026
|
+
case RelationKinds.HasMany:
|
|
7027
|
+
await this.handleHasManyChange(entry);
|
|
7028
|
+
break;
|
|
7029
|
+
case RelationKinds.HasOne:
|
|
7030
|
+
await this.handleHasOneChange(entry);
|
|
7031
|
+
break;
|
|
7032
|
+
case RelationKinds.BelongsToMany:
|
|
7033
|
+
await this.handleBelongsToManyChange(entry);
|
|
7034
|
+
break;
|
|
7035
|
+
case RelationKinds.BelongsTo:
|
|
7036
|
+
await this.handleBelongsToChange(entry);
|
|
7037
|
+
break;
|
|
7038
|
+
}
|
|
7039
|
+
}
|
|
7040
|
+
}
|
|
7041
|
+
async handleHasManyChange(entry) {
|
|
7042
|
+
const relation = entry.relation;
|
|
7043
|
+
const target = entry.change.entity;
|
|
7044
|
+
if (!target) return;
|
|
7045
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
7046
|
+
if (!tracked) return;
|
|
7047
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
7048
|
+
const rootValue = entry.root[localKey];
|
|
7049
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
7050
|
+
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
7051
|
+
this.assignHasManyForeignKey(tracked.entity, relation, rootValue);
|
|
7052
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
7053
|
+
return;
|
|
7054
|
+
}
|
|
7055
|
+
if (entry.change.kind === "remove") {
|
|
7056
|
+
this.detachHasManyChild(tracked.entity, relation);
|
|
7057
|
+
}
|
|
7058
|
+
}
|
|
7059
|
+
async handleHasOneChange(entry) {
|
|
7060
|
+
const relation = entry.relation;
|
|
7061
|
+
const target = entry.change.entity;
|
|
7062
|
+
if (!target) return;
|
|
7063
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
7064
|
+
if (!tracked) return;
|
|
7065
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
7066
|
+
const rootValue = entry.root[localKey];
|
|
7067
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
7068
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
7069
|
+
this.assignHasOneForeignKey(tracked.entity, relation, rootValue);
|
|
7070
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
7071
|
+
return;
|
|
7072
|
+
}
|
|
7073
|
+
if (entry.change.kind === "remove") {
|
|
7074
|
+
this.detachHasOneChild(tracked.entity, relation);
|
|
7075
|
+
}
|
|
7076
|
+
}
|
|
7077
|
+
async handleBelongsToChange(_entry) {
|
|
7078
|
+
}
|
|
7079
|
+
async handleBelongsToManyChange(entry) {
|
|
7080
|
+
const relation = entry.relation;
|
|
7081
|
+
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
7082
|
+
const rootId = entry.root[rootKey];
|
|
7083
|
+
if (rootId === void 0 || rootId === null) return;
|
|
7084
|
+
const targetId = this.resolvePrimaryKeyValue(entry.change.entity, relation.target);
|
|
7085
|
+
if (targetId === null) return;
|
|
7086
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
7087
|
+
await this.insertPivotRow(relation, rootId, targetId);
|
|
7088
|
+
return;
|
|
7089
|
+
}
|
|
7090
|
+
if (entry.change.kind === "detach" || entry.change.kind === "remove") {
|
|
7091
|
+
await this.deletePivotRow(relation, rootId, targetId);
|
|
7092
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
7093
|
+
this.unitOfWork.markRemoved(entry.change.entity);
|
|
7094
|
+
}
|
|
7095
|
+
}
|
|
7096
|
+
}
|
|
7097
|
+
assignHasManyForeignKey(child, relation, rootValue) {
|
|
7098
|
+
const current = child[relation.foreignKey];
|
|
7099
|
+
if (current === rootValue) return;
|
|
7100
|
+
child[relation.foreignKey] = rootValue;
|
|
7101
|
+
}
|
|
7102
|
+
detachHasManyChild(child, relation) {
|
|
7103
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
7104
|
+
this.unitOfWork.markRemoved(child);
|
|
7105
|
+
return;
|
|
7106
|
+
}
|
|
7107
|
+
child[relation.foreignKey] = null;
|
|
7108
|
+
this.unitOfWork.markDirty(child);
|
|
7109
|
+
}
|
|
7110
|
+
assignHasOneForeignKey(child, relation, rootValue) {
|
|
7111
|
+
const current = child[relation.foreignKey];
|
|
7112
|
+
if (current === rootValue) return;
|
|
7113
|
+
child[relation.foreignKey] = rootValue;
|
|
7114
|
+
}
|
|
7115
|
+
detachHasOneChild(child, relation) {
|
|
7116
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
7117
|
+
this.unitOfWork.markRemoved(child);
|
|
7118
|
+
return;
|
|
7119
|
+
}
|
|
7120
|
+
child[relation.foreignKey] = null;
|
|
7121
|
+
this.unitOfWork.markDirty(child);
|
|
7122
|
+
}
|
|
7123
|
+
async insertPivotRow(relation, rootId, targetId) {
|
|
7124
|
+
const payload = {
|
|
7125
|
+
[relation.pivotForeignKeyToRoot]: rootId,
|
|
7126
|
+
[relation.pivotForeignKeyToTarget]: targetId
|
|
7127
|
+
};
|
|
7128
|
+
const builder = new InsertQueryBuilder(relation.pivotTable).values(payload);
|
|
7129
|
+
const compiled = builder.compile(this.dialect);
|
|
7130
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
7131
|
+
}
|
|
7132
|
+
async deletePivotRow(relation, rootId, targetId) {
|
|
7133
|
+
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
7134
|
+
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
7135
|
+
if (!rootCol || !targetCol) return;
|
|
7136
|
+
const builder = new DeleteQueryBuilder(relation.pivotTable).where(
|
|
7137
|
+
and(eq(rootCol, rootId), eq(targetCol, targetId))
|
|
7138
|
+
);
|
|
7139
|
+
const compiled = builder.compile(this.dialect);
|
|
7140
|
+
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
7141
|
+
}
|
|
7142
|
+
resolvePrimaryKeyValue(entity, table) {
|
|
7143
|
+
if (!entity) return null;
|
|
7144
|
+
const key = findPrimaryKey(table);
|
|
7145
|
+
const value = entity[key];
|
|
7146
|
+
if (value === void 0 || value === null) return null;
|
|
7147
|
+
return value;
|
|
7148
|
+
}
|
|
7149
|
+
};
|
|
7150
|
+
|
|
6723
7151
|
// src/orm/query-logger.ts
|
|
6724
7152
|
var createQueryLoggingExecutor = (executor, logger) => {
|
|
6725
7153
|
if (!logger) {
|
|
@@ -6743,31 +7171,40 @@ var createQueryLoggingExecutor = (executor, logger) => {
|
|
|
6743
7171
|
return wrapped;
|
|
6744
7172
|
};
|
|
6745
7173
|
|
|
6746
|
-
// src/orm/
|
|
6747
|
-
var
|
|
6748
|
-
|
|
6749
|
-
|
|
7174
|
+
// src/orm/transaction-runner.ts
|
|
7175
|
+
var runInTransaction = async (executor, action) => {
|
|
7176
|
+
if (!executor.beginTransaction) {
|
|
7177
|
+
await action();
|
|
7178
|
+
return;
|
|
7179
|
+
}
|
|
7180
|
+
await executor.beginTransaction();
|
|
7181
|
+
try {
|
|
7182
|
+
await action();
|
|
7183
|
+
await executor.commitTransaction?.();
|
|
7184
|
+
} catch (error) {
|
|
7185
|
+
await executor.rollbackTransaction?.();
|
|
7186
|
+
throw error;
|
|
7187
|
+
}
|
|
7188
|
+
};
|
|
7189
|
+
|
|
7190
|
+
// src/orm/orm-session.ts
|
|
7191
|
+
var OrmSession = class {
|
|
7192
|
+
constructor(opts) {
|
|
7193
|
+
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
7194
|
+
this.relationChanges.registerChange(
|
|
7195
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
7196
|
+
);
|
|
7197
|
+
};
|
|
7198
|
+
this.orm = opts.orm;
|
|
7199
|
+
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
7200
|
+
this.interceptors = [...opts.interceptors ?? []];
|
|
6750
7201
|
this.identityMap = new IdentityMap();
|
|
6751
|
-
this.
|
|
6752
|
-
this.
|
|
6753
|
-
this.
|
|
6754
|
-
options.dialect,
|
|
6755
|
-
this.executorWithLogging,
|
|
6756
|
-
this.identityMap,
|
|
6757
|
-
() => this
|
|
6758
|
-
);
|
|
6759
|
-
this.relationChanges = new RelationChangeProcessor(
|
|
6760
|
-
this.unitOfWork,
|
|
6761
|
-
options.dialect,
|
|
6762
|
-
this.executorWithLogging
|
|
6763
|
-
);
|
|
6764
|
-
this.domainEvents = new DomainEventBus(options.domainEventHandlers);
|
|
7202
|
+
this.unitOfWork = new UnitOfWork(this.orm.dialect, this.executor, this.identityMap, () => this);
|
|
7203
|
+
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
7204
|
+
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
6765
7205
|
}
|
|
6766
7206
|
get dialect() {
|
|
6767
|
-
return this.
|
|
6768
|
-
}
|
|
6769
|
-
get executor() {
|
|
6770
|
-
return this.executorWithLogging;
|
|
7207
|
+
return this.orm.dialect;
|
|
6771
7208
|
}
|
|
6772
7209
|
get identityBuckets() {
|
|
6773
7210
|
return this.unitOfWork.identityBuckets;
|
|
@@ -6793,24 +7230,64 @@ var OrmContext = class {
|
|
|
6793
7230
|
markRemoved(entity) {
|
|
6794
7231
|
this.unitOfWork.markRemoved(entity);
|
|
6795
7232
|
}
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
root,
|
|
6799
|
-
relationKey,
|
|
6800
|
-
rootTable,
|
|
6801
|
-
relationName,
|
|
6802
|
-
relation,
|
|
6803
|
-
change
|
|
6804
|
-
};
|
|
6805
|
-
this.relationChanges.registerChange(entry);
|
|
7233
|
+
getEntitiesForTable(table) {
|
|
7234
|
+
return this.unitOfWork.getEntitiesForTable(table);
|
|
6806
7235
|
}
|
|
6807
7236
|
registerInterceptor(interceptor) {
|
|
6808
7237
|
this.interceptors.push(interceptor);
|
|
6809
7238
|
}
|
|
6810
|
-
registerDomainEventHandler(
|
|
6811
|
-
this.domainEvents.
|
|
7239
|
+
registerDomainEventHandler(type, handler) {
|
|
7240
|
+
this.domainEvents.on(type, handler);
|
|
7241
|
+
}
|
|
7242
|
+
async find(entityClass, id) {
|
|
7243
|
+
const table = getTableDefFromEntity(entityClass);
|
|
7244
|
+
if (!table) {
|
|
7245
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
7246
|
+
}
|
|
7247
|
+
const primaryKey = findPrimaryKey(table);
|
|
7248
|
+
const column = table.columns[primaryKey];
|
|
7249
|
+
if (!column) {
|
|
7250
|
+
throw new Error("Entity table does not expose a primary key");
|
|
7251
|
+
}
|
|
7252
|
+
const columnSelections = Object.values(table.columns).reduce((acc, col2) => {
|
|
7253
|
+
acc[col2.name] = col2;
|
|
7254
|
+
return acc;
|
|
7255
|
+
}, {});
|
|
7256
|
+
const qb = selectFromEntity(entityClass).select(columnSelections).where(eq(column, id)).limit(1);
|
|
7257
|
+
const rows = await executeHydrated(this, qb);
|
|
7258
|
+
return rows[0] ?? null;
|
|
7259
|
+
}
|
|
7260
|
+
async findOne(qb) {
|
|
7261
|
+
const limited = qb.limit(1);
|
|
7262
|
+
const rows = await executeHydrated(this, limited);
|
|
7263
|
+
return rows[0] ?? null;
|
|
7264
|
+
}
|
|
7265
|
+
async findMany(qb) {
|
|
7266
|
+
return executeHydrated(this, qb);
|
|
7267
|
+
}
|
|
7268
|
+
async persist(entity) {
|
|
7269
|
+
if (this.unitOfWork.findTracked(entity)) {
|
|
7270
|
+
return;
|
|
7271
|
+
}
|
|
7272
|
+
const table = getTableDefFromEntity(entity.constructor);
|
|
7273
|
+
if (!table) {
|
|
7274
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
7275
|
+
}
|
|
7276
|
+
const primaryKey = findPrimaryKey(table);
|
|
7277
|
+
const pkValue = entity[primaryKey];
|
|
7278
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
7279
|
+
this.trackManaged(table, pkValue, entity);
|
|
7280
|
+
} else {
|
|
7281
|
+
this.trackNew(table, entity);
|
|
7282
|
+
}
|
|
7283
|
+
}
|
|
7284
|
+
async remove(entity) {
|
|
7285
|
+
this.markRemoved(entity);
|
|
7286
|
+
}
|
|
7287
|
+
async flush() {
|
|
7288
|
+
await this.unitOfWork.flush();
|
|
6812
7289
|
}
|
|
6813
|
-
async
|
|
7290
|
+
async commit() {
|
|
6814
7291
|
await runInTransaction(this.executor, async () => {
|
|
6815
7292
|
for (const interceptor of this.interceptors) {
|
|
6816
7293
|
await interceptor.beforeFlush?.(this);
|
|
@@ -6824,8 +7301,82 @@ var OrmContext = class {
|
|
|
6824
7301
|
});
|
|
6825
7302
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
6826
7303
|
}
|
|
6827
|
-
|
|
6828
|
-
|
|
7304
|
+
async rollback() {
|
|
7305
|
+
await this.executor.rollbackTransaction?.();
|
|
7306
|
+
this.unitOfWork.reset();
|
|
7307
|
+
this.relationChanges.reset();
|
|
7308
|
+
}
|
|
7309
|
+
getExecutionContext() {
|
|
7310
|
+
return {
|
|
7311
|
+
dialect: this.orm.dialect,
|
|
7312
|
+
executor: this.executor,
|
|
7313
|
+
interceptors: this.orm.interceptors
|
|
7314
|
+
};
|
|
7315
|
+
}
|
|
7316
|
+
getHydrationContext() {
|
|
7317
|
+
return {
|
|
7318
|
+
identityMap: this.identityMap,
|
|
7319
|
+
unitOfWork: this.unitOfWork,
|
|
7320
|
+
domainEvents: this.domainEvents,
|
|
7321
|
+
relationChanges: this.relationChanges,
|
|
7322
|
+
entityContext: this
|
|
7323
|
+
};
|
|
7324
|
+
}
|
|
7325
|
+
};
|
|
7326
|
+
var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, relation, change) => ({
|
|
7327
|
+
root,
|
|
7328
|
+
relationKey,
|
|
7329
|
+
rootTable,
|
|
7330
|
+
relationName,
|
|
7331
|
+
relation,
|
|
7332
|
+
change
|
|
7333
|
+
});
|
|
7334
|
+
|
|
7335
|
+
// src/orm/interceptor-pipeline.ts
|
|
7336
|
+
var InterceptorPipeline = class {
|
|
7337
|
+
constructor() {
|
|
7338
|
+
this.interceptors = [];
|
|
7339
|
+
}
|
|
7340
|
+
use(interceptor) {
|
|
7341
|
+
this.interceptors.push(interceptor);
|
|
7342
|
+
}
|
|
7343
|
+
async run(ctx, executor) {
|
|
7344
|
+
let i = 0;
|
|
7345
|
+
const dispatch = async () => {
|
|
7346
|
+
const interceptor = this.interceptors[i++];
|
|
7347
|
+
if (!interceptor) {
|
|
7348
|
+
return executor.executeSql(ctx.sql, ctx.params);
|
|
7349
|
+
}
|
|
7350
|
+
return interceptor(ctx, dispatch);
|
|
7351
|
+
};
|
|
7352
|
+
return dispatch();
|
|
7353
|
+
}
|
|
7354
|
+
};
|
|
7355
|
+
|
|
7356
|
+
// src/orm/orm.ts
|
|
7357
|
+
var Orm = class {
|
|
7358
|
+
constructor(opts) {
|
|
7359
|
+
this.dialect = opts.dialect;
|
|
7360
|
+
this.interceptors = opts.interceptors ?? new InterceptorPipeline();
|
|
7361
|
+
this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
|
|
7362
|
+
this.executorFactory = opts.executorFactory;
|
|
7363
|
+
}
|
|
7364
|
+
createSession(options) {
|
|
7365
|
+
const executor = this.executorFactory.createExecutor(options?.tx);
|
|
7366
|
+
return new OrmSession({ orm: this, executor });
|
|
7367
|
+
}
|
|
7368
|
+
async transaction(fn4) {
|
|
7369
|
+
const executor = this.executorFactory.createTransactionalExecutor();
|
|
7370
|
+
const session = new OrmSession({ orm: this, executor });
|
|
7371
|
+
try {
|
|
7372
|
+
const result = await fn4(session);
|
|
7373
|
+
await session.commit();
|
|
7374
|
+
return result;
|
|
7375
|
+
} catch (err) {
|
|
7376
|
+
await session.rollback();
|
|
7377
|
+
throw err;
|
|
7378
|
+
} finally {
|
|
7379
|
+
}
|
|
6829
7380
|
}
|
|
6830
7381
|
};
|
|
6831
7382
|
|
|
@@ -6941,10 +7492,12 @@ function createMssqlExecutor(client) {
|
|
|
6941
7492
|
DefaultHasManyCollection,
|
|
6942
7493
|
DefaultManyToManyCollection,
|
|
6943
7494
|
DeleteQueryBuilder,
|
|
7495
|
+
DomainEventBus,
|
|
6944
7496
|
EntityStatus,
|
|
6945
7497
|
InsertQueryBuilder,
|
|
6946
7498
|
MySqlDialect,
|
|
6947
|
-
|
|
7499
|
+
Orm,
|
|
7500
|
+
OrmSession,
|
|
6948
7501
|
PostgresDialect,
|
|
6949
7502
|
RelationKinds,
|
|
6950
7503
|
SelectQueryBuilder,
|
|
@@ -6986,6 +7539,7 @@ function createMssqlExecutor(client) {
|
|
|
6986
7539
|
createMssqlExecutor,
|
|
6987
7540
|
createMysqlExecutor,
|
|
6988
7541
|
createPostgresExecutor,
|
|
7542
|
+
createQueryLoggingExecutor,
|
|
6989
7543
|
createSqliteExecutor,
|
|
6990
7544
|
currentDate,
|
|
6991
7545
|
currentTime,
|
|
@@ -7002,7 +7556,9 @@ function createMssqlExecutor(client) {
|
|
|
7002
7556
|
diffSchema,
|
|
7003
7557
|
endOfMonth,
|
|
7004
7558
|
eq,
|
|
7559
|
+
esel,
|
|
7005
7560
|
executeHydrated,
|
|
7561
|
+
executeHydratedWithContexts,
|
|
7006
7562
|
exists,
|
|
7007
7563
|
exp,
|
|
7008
7564
|
extract,
|
|
@@ -7012,6 +7568,7 @@ function createMssqlExecutor(client) {
|
|
|
7012
7568
|
generateCreateTableSql,
|
|
7013
7569
|
generateSchemaSql,
|
|
7014
7570
|
getSchemaIntrospector,
|
|
7571
|
+
groupConcat,
|
|
7015
7572
|
gt,
|
|
7016
7573
|
gte,
|
|
7017
7574
|
hasMany,
|
|
@@ -7026,6 +7583,7 @@ function createMssqlExecutor(client) {
|
|
|
7026
7583
|
isNotNull,
|
|
7027
7584
|
isNull,
|
|
7028
7585
|
isOperandNode,
|
|
7586
|
+
isValueOperandInput,
|
|
7029
7587
|
isWindowFunctionNode,
|
|
7030
7588
|
jsonPath,
|
|
7031
7589
|
lag,
|
|
@@ -7048,6 +7606,8 @@ function createMssqlExecutor(client) {
|
|
|
7048
7606
|
lt,
|
|
7049
7607
|
lte,
|
|
7050
7608
|
ltrim,
|
|
7609
|
+
max,
|
|
7610
|
+
min,
|
|
7051
7611
|
mod,
|
|
7052
7612
|
month,
|
|
7053
7613
|
neq,
|
|
@@ -7078,6 +7638,7 @@ function createMssqlExecutor(client) {
|
|
|
7078
7638
|
rowsToQueryResult,
|
|
7079
7639
|
rpad,
|
|
7080
7640
|
rtrim,
|
|
7641
|
+
sel,
|
|
7081
7642
|
sign,
|
|
7082
7643
|
sin,
|
|
7083
7644
|
space,
|