metal-orm 1.0.58 → 1.0.59
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 +34 -31
- package/dist/index.cjs +1463 -1003
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +148 -129
- package/dist/index.d.ts +148 -129
- package/dist/index.js +1459 -1003
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ddl/schema-generator.ts +44 -1
- package/src/decorators/bootstrap.ts +183 -146
- package/src/decorators/column-decorator.ts +8 -49
- package/src/decorators/decorator-metadata.ts +10 -46
- package/src/decorators/entity.ts +30 -40
- package/src/decorators/relations.ts +30 -56
- package/src/orm/entity-hydration.ts +72 -0
- package/src/orm/entity-meta.ts +13 -11
- package/src/orm/entity-metadata.ts +240 -238
- package/src/orm/entity-relation-cache.ts +39 -0
- package/src/orm/entity-relations.ts +207 -0
- package/src/orm/entity.ts +124 -410
- package/src/orm/execute.ts +4 -4
- package/src/orm/lazy-batch/belongs-to-many.ts +134 -0
- package/src/orm/lazy-batch/belongs-to.ts +108 -0
- package/src/orm/lazy-batch/has-many.ts +69 -0
- package/src/orm/lazy-batch/has-one.ts +68 -0
- package/src/orm/lazy-batch/shared.ts +125 -0
- package/src/orm/lazy-batch.ts +4 -492
- package/src/orm/relations/many-to-many.ts +2 -1
- package/src/query-builder/relation-cte-builder.ts +63 -0
- package/src/query-builder/relation-filter-utils.ts +159 -0
- package/src/query-builder/relation-include-strategies.ts +177 -0
- package/src/query-builder/relation-join-planner.ts +80 -0
- package/src/query-builder/relation-service.ts +119 -479
- package/src/query-builder/relation-types.ts +41 -10
- package/src/query-builder/select/projection-facet.ts +23 -23
- package/src/query-builder/select/select-operations.ts +145 -0
- package/src/query-builder/select.ts +351 -422
- package/src/schema/relation.ts +22 -18
- package/src/schema/table.ts +22 -9
- package/src/schema/types.ts +14 -12
package/dist/index.js
CHANGED
|
@@ -51,6 +51,9 @@ var defineTable = (name, columns, relations = {}, hooks, options = {}) => {
|
|
|
51
51
|
collation: options.collation
|
|
52
52
|
};
|
|
53
53
|
};
|
|
54
|
+
function setRelations(table, relations) {
|
|
55
|
+
table.relations = relations;
|
|
56
|
+
}
|
|
54
57
|
var TABLE_REF_CACHE = /* @__PURE__ */ new WeakMap();
|
|
55
58
|
var withColumnProps = (table) => {
|
|
56
59
|
const cached = TABLE_REF_CACHE.get(table);
|
|
@@ -694,6 +697,7 @@ var variance = buildAggregate("VARIANCE");
|
|
|
694
697
|
|
|
695
698
|
// src/core/ast/expression-visitor.ts
|
|
696
699
|
var DispatcherRegistry = class _DispatcherRegistry {
|
|
700
|
+
dispatchers;
|
|
697
701
|
constructor(dispatchers = /* @__PURE__ */ new Map()) {
|
|
698
702
|
this.dispatchers = dispatchers;
|
|
699
703
|
}
|
|
@@ -827,61 +831,9 @@ var toTableRef = (table) => ({
|
|
|
827
831
|
alias: hasAlias(table) ? table.alias : void 0
|
|
828
832
|
});
|
|
829
833
|
|
|
830
|
-
// src/core/ast/builders.ts
|
|
831
|
-
var isColumnNode = (col2) => "type" in col2 && col2.type === "Column";
|
|
832
|
-
var resolveTableName = (def, table) => {
|
|
833
|
-
if (!def.table) {
|
|
834
|
-
return table.alias || table.name;
|
|
835
|
-
}
|
|
836
|
-
if (table.alias && def.table === table.name) {
|
|
837
|
-
return table.alias;
|
|
838
|
-
}
|
|
839
|
-
return def.table;
|
|
840
|
-
};
|
|
841
|
-
var buildColumnNode = (table, column) => {
|
|
842
|
-
if (isColumnNode(column)) {
|
|
843
|
-
return column;
|
|
844
|
-
}
|
|
845
|
-
const def = column;
|
|
846
|
-
const baseTable = resolveTableName(def, table);
|
|
847
|
-
return {
|
|
848
|
-
type: "Column",
|
|
849
|
-
table: baseTable,
|
|
850
|
-
name: def.name
|
|
851
|
-
};
|
|
852
|
-
};
|
|
853
|
-
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
854
|
-
type: "Column",
|
|
855
|
-
table: table.alias || table.name,
|
|
856
|
-
name
|
|
857
|
-
}));
|
|
858
|
-
var createTableNode = (table) => ({
|
|
859
|
-
type: "Table",
|
|
860
|
-
name: table.name,
|
|
861
|
-
schema: table.schema
|
|
862
|
-
});
|
|
863
|
-
var fnTable = (name, args = [], alias, opts) => ({
|
|
864
|
-
type: "FunctionTable",
|
|
865
|
-
name,
|
|
866
|
-
args,
|
|
867
|
-
alias,
|
|
868
|
-
lateral: opts?.lateral,
|
|
869
|
-
withOrdinality: opts?.withOrdinality,
|
|
870
|
-
columnAliases: opts?.columnAliases,
|
|
871
|
-
schema: opts?.schema
|
|
872
|
-
});
|
|
873
|
-
var derivedTable = (query, alias, columnAliases) => ({
|
|
874
|
-
type: "DerivedTable",
|
|
875
|
-
query,
|
|
876
|
-
alias,
|
|
877
|
-
columnAliases
|
|
878
|
-
});
|
|
879
|
-
|
|
880
834
|
// src/core/functions/function-registry.ts
|
|
881
835
|
var FunctionRegistry = class {
|
|
882
|
-
|
|
883
|
-
this.renderers = /* @__PURE__ */ new Map();
|
|
884
|
-
}
|
|
836
|
+
renderers = /* @__PURE__ */ new Map();
|
|
885
837
|
/**
|
|
886
838
|
* Registers or overrides a renderer for the given function name.
|
|
887
839
|
*/
|
|
@@ -1176,6 +1128,7 @@ function renderStandardGroupConcat(ctx) {
|
|
|
1176
1128
|
|
|
1177
1129
|
// src/core/functions/standard-strategy.ts
|
|
1178
1130
|
var StandardFunctionStrategy = class {
|
|
1131
|
+
registry;
|
|
1179
1132
|
/**
|
|
1180
1133
|
* Creates a new StandardFunctionStrategy and registers standard functions.
|
|
1181
1134
|
*/
|
|
@@ -1241,17 +1194,13 @@ var StandardFunctionStrategy = class {
|
|
|
1241
1194
|
getGroupConcatSeparatorOperand(ctx) {
|
|
1242
1195
|
return getGroupConcatSeparatorOperand(ctx);
|
|
1243
1196
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
this.DEFAULT_GROUP_CONCAT_SEPARATOR = DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
1247
|
-
}
|
|
1197
|
+
/** Default separator for GROUP_CONCAT, a comma. */
|
|
1198
|
+
static DEFAULT_GROUP_CONCAT_SEPARATOR = DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
1248
1199
|
};
|
|
1249
1200
|
|
|
1250
1201
|
// src/core/functions/standard-table-strategy.ts
|
|
1251
1202
|
var StandardTableFunctionStrategy = class {
|
|
1252
|
-
|
|
1253
|
-
this.renderers = /* @__PURE__ */ new Map();
|
|
1254
|
-
}
|
|
1203
|
+
renderers = /* @__PURE__ */ new Map();
|
|
1255
1204
|
add(key, renderer) {
|
|
1256
1205
|
this.renderers.set(key, renderer);
|
|
1257
1206
|
}
|
|
@@ -1430,6 +1379,10 @@ var Dialect = class _Dialect {
|
|
|
1430
1379
|
const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
|
|
1431
1380
|
return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
|
|
1432
1381
|
}
|
|
1382
|
+
expressionCompilers;
|
|
1383
|
+
operandCompilers;
|
|
1384
|
+
functionStrategy;
|
|
1385
|
+
tableFunctionStrategy;
|
|
1433
1386
|
constructor(functionStrategy, tableFunctionStrategy) {
|
|
1434
1387
|
this.expressionCompilers = /* @__PURE__ */ new Map();
|
|
1435
1388
|
this.operandCompilers = /* @__PURE__ */ new Map();
|
|
@@ -1445,10 +1398,7 @@ var Dialect = class _Dialect {
|
|
|
1445
1398
|
*/
|
|
1446
1399
|
static create(functionStrategy, tableFunctionStrategy) {
|
|
1447
1400
|
class TestDialect extends _Dialect {
|
|
1448
|
-
|
|
1449
|
-
super(...arguments);
|
|
1450
|
-
this.dialect = "sqlite";
|
|
1451
|
-
}
|
|
1401
|
+
dialect = "sqlite";
|
|
1452
1402
|
quoteIdentifier(id) {
|
|
1453
1403
|
return `"${id}"`;
|
|
1454
1404
|
}
|
|
@@ -1888,11 +1838,8 @@ var OrderByCompiler = class {
|
|
|
1888
1838
|
|
|
1889
1839
|
// src/core/dialect/base/sql-dialect.ts
|
|
1890
1840
|
var SqlDialectBase = class extends Dialect {
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
this.paginationStrategy = new StandardLimitOffsetPagination();
|
|
1894
|
-
this.returningStrategy = new NoReturningStrategy();
|
|
1895
|
-
}
|
|
1841
|
+
paginationStrategy = new StandardLimitOffsetPagination();
|
|
1842
|
+
returningStrategy = new NoReturningStrategy();
|
|
1896
1843
|
compileSelectAst(ast, ctx) {
|
|
1897
1844
|
const hasSetOps = !!(ast.setOps && ast.setOps.length);
|
|
1898
1845
|
const ctes = CteCompiler.compileCtes(
|
|
@@ -2280,12 +2227,12 @@ var PostgresTableFunctionStrategy = class extends StandardTableFunctionStrategy
|
|
|
2280
2227
|
|
|
2281
2228
|
// src/core/dialect/postgres/index.ts
|
|
2282
2229
|
var PostgresDialect = class extends SqlDialectBase {
|
|
2230
|
+
dialect = "postgres";
|
|
2283
2231
|
/**
|
|
2284
2232
|
* Creates a new PostgresDialect instance
|
|
2285
2233
|
*/
|
|
2286
2234
|
constructor() {
|
|
2287
2235
|
super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
|
|
2288
|
-
this.dialect = "postgres";
|
|
2289
2236
|
this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
|
|
2290
2237
|
const left2 = this.compileOperand(node.left, ctx);
|
|
2291
2238
|
const right2 = this.compileOperand(node.right, ctx);
|
|
@@ -2419,12 +2366,12 @@ var MysqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2419
2366
|
|
|
2420
2367
|
// src/core/dialect/mysql/index.ts
|
|
2421
2368
|
var MySqlDialect = class extends SqlDialectBase {
|
|
2369
|
+
dialect = "mysql";
|
|
2422
2370
|
/**
|
|
2423
2371
|
* Creates a new MySqlDialect instance
|
|
2424
2372
|
*/
|
|
2425
2373
|
constructor() {
|
|
2426
2374
|
super(new MysqlFunctionStrategy());
|
|
2427
|
-
this.dialect = "mysql";
|
|
2428
2375
|
}
|
|
2429
2376
|
/**
|
|
2430
2377
|
* Quotes an identifier using MySQL backtick syntax
|
|
@@ -2575,12 +2522,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2575
2522
|
|
|
2576
2523
|
// src/core/dialect/sqlite/index.ts
|
|
2577
2524
|
var SqliteDialect = class extends SqlDialectBase {
|
|
2525
|
+
dialect = "sqlite";
|
|
2578
2526
|
/**
|
|
2579
2527
|
* Creates a new SqliteDialect instance
|
|
2580
2528
|
*/
|
|
2581
2529
|
constructor() {
|
|
2582
2530
|
super(new SqliteFunctionStrategy());
|
|
2583
|
-
this.dialect = "sqlite";
|
|
2584
2531
|
this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
|
|
2585
2532
|
const left2 = this.compileOperand(node.left, ctx);
|
|
2586
2533
|
const right2 = this.compileOperand(node.right, ctx);
|
|
@@ -2753,12 +2700,12 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2753
2700
|
|
|
2754
2701
|
// src/core/dialect/mssql/index.ts
|
|
2755
2702
|
var SqlServerDialect = class extends SqlDialectBase {
|
|
2703
|
+
dialect = "mssql";
|
|
2756
2704
|
/**
|
|
2757
2705
|
* Creates a new SqlServerDialect instance
|
|
2758
2706
|
*/
|
|
2759
2707
|
constructor() {
|
|
2760
2708
|
super(new MssqlFunctionStrategy());
|
|
2761
|
-
this.dialect = "mssql";
|
|
2762
2709
|
}
|
|
2763
2710
|
/**
|
|
2764
2711
|
* Quotes an identifier using SQL Server bracket syntax
|
|
@@ -2885,12 +2832,8 @@ var SqlServerDialect = class extends SqlDialectBase {
|
|
|
2885
2832
|
|
|
2886
2833
|
// src/core/dialect/dialect-factory.ts
|
|
2887
2834
|
var DialectFactory = class {
|
|
2888
|
-
static
|
|
2889
|
-
|
|
2890
|
-
}
|
|
2891
|
-
static {
|
|
2892
|
-
this.defaultsInitialized = false;
|
|
2893
|
-
}
|
|
2835
|
+
static registry = /* @__PURE__ */ new Map();
|
|
2836
|
+
static defaultsInitialized = false;
|
|
2894
2837
|
static ensureDefaults() {
|
|
2895
2838
|
if (this.defaultsInitialized) return;
|
|
2896
2839
|
this.defaultsInitialized = true;
|
|
@@ -2949,8 +2892,66 @@ var resolveDialectInput = (dialect) => {
|
|
|
2949
2892
|
return dialect;
|
|
2950
2893
|
};
|
|
2951
2894
|
|
|
2895
|
+
// src/core/ast/builders.ts
|
|
2896
|
+
var isColumnNode = (col2) => "type" in col2 && col2.type === "Column";
|
|
2897
|
+
var resolveTableName = (def, table) => {
|
|
2898
|
+
if (!def.table) {
|
|
2899
|
+
return table.alias || table.name;
|
|
2900
|
+
}
|
|
2901
|
+
if (table.alias && def.table === table.name) {
|
|
2902
|
+
return table.alias;
|
|
2903
|
+
}
|
|
2904
|
+
return def.table;
|
|
2905
|
+
};
|
|
2906
|
+
var buildColumnNode = (table, column) => {
|
|
2907
|
+
if (isColumnNode(column)) {
|
|
2908
|
+
return column;
|
|
2909
|
+
}
|
|
2910
|
+
const def = column;
|
|
2911
|
+
const baseTable = resolveTableName(def, table);
|
|
2912
|
+
return {
|
|
2913
|
+
type: "Column",
|
|
2914
|
+
table: baseTable,
|
|
2915
|
+
name: def.name
|
|
2916
|
+
};
|
|
2917
|
+
};
|
|
2918
|
+
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
2919
|
+
type: "Column",
|
|
2920
|
+
table: table.alias || table.name,
|
|
2921
|
+
name
|
|
2922
|
+
}));
|
|
2923
|
+
var createTableNode = (table) => ({
|
|
2924
|
+
type: "Table",
|
|
2925
|
+
name: table.name,
|
|
2926
|
+
schema: table.schema
|
|
2927
|
+
});
|
|
2928
|
+
var fnTable = (name, args = [], alias, opts) => ({
|
|
2929
|
+
type: "FunctionTable",
|
|
2930
|
+
name,
|
|
2931
|
+
args,
|
|
2932
|
+
alias,
|
|
2933
|
+
lateral: opts?.lateral,
|
|
2934
|
+
withOrdinality: opts?.withOrdinality,
|
|
2935
|
+
columnAliases: opts?.columnAliases,
|
|
2936
|
+
schema: opts?.schema
|
|
2937
|
+
});
|
|
2938
|
+
var derivedTable = (query, alias, columnAliases) => ({
|
|
2939
|
+
type: "DerivedTable",
|
|
2940
|
+
query,
|
|
2941
|
+
alias,
|
|
2942
|
+
columnAliases
|
|
2943
|
+
});
|
|
2944
|
+
|
|
2952
2945
|
// src/query-builder/select-query-state.ts
|
|
2953
2946
|
var SelectQueryState = class _SelectQueryState {
|
|
2947
|
+
/**
|
|
2948
|
+
* Table definition for the query
|
|
2949
|
+
*/
|
|
2950
|
+
table;
|
|
2951
|
+
/**
|
|
2952
|
+
* Abstract Syntax Tree (AST) representation of the query
|
|
2953
|
+
*/
|
|
2954
|
+
ast;
|
|
2954
2955
|
/**
|
|
2955
2956
|
* Creates a new SelectQueryState instance
|
|
2956
2957
|
* @param table - Table definition
|
|
@@ -3920,199 +3921,150 @@ var buildRelationCorrelation = (root, relation, rootAlias, targetTableName) => {
|
|
|
3920
3921
|
// src/core/ast/join-metadata.ts
|
|
3921
3922
|
var getJoinRelationName = (join) => join.meta?.relationName;
|
|
3922
3923
|
|
|
3923
|
-
// src/query-builder/relation-
|
|
3924
|
-
var
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
this.state = state;
|
|
3935
|
-
this.hydration = hydration;
|
|
3936
|
-
this.createQueryAstService = createQueryAstService;
|
|
3937
|
-
this.projectionHelper = new RelationProjectionHelper(
|
|
3938
|
-
table,
|
|
3939
|
-
(state2, hydration2, columns) => this.selectColumns(state2, hydration2, columns)
|
|
3940
|
-
);
|
|
3941
|
-
}
|
|
3942
|
-
/**
|
|
3943
|
-
* Joins a relation to the query
|
|
3944
|
-
* @param relationName - Name of the relation to join
|
|
3945
|
-
* @param joinKind - Type of join to use
|
|
3946
|
-
* @param extraCondition - Additional join condition
|
|
3947
|
-
* @returns Relation result with updated state and hydration
|
|
3948
|
-
*/
|
|
3949
|
-
joinRelation(relationName, joinKind, extraCondition, tableSource) {
|
|
3950
|
-
const nextState = this.withJoin(this.state, relationName, joinKind, extraCondition, tableSource);
|
|
3951
|
-
return { state: nextState, hydration: this.hydration };
|
|
3924
|
+
// src/query-builder/relation-filter-utils.ts
|
|
3925
|
+
var splitFilterExpressions = (filter, allowedTables) => {
|
|
3926
|
+
const terms = flattenAnd(filter);
|
|
3927
|
+
const selfFilters = [];
|
|
3928
|
+
const crossFilters = [];
|
|
3929
|
+
for (const term of terms) {
|
|
3930
|
+
if (isExpressionSelfContained(term, allowedTables)) {
|
|
3931
|
+
selfFilters.push(term);
|
|
3932
|
+
} else {
|
|
3933
|
+
crossFilters.push(term);
|
|
3934
|
+
}
|
|
3952
3935
|
}
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
match(relationName, predicate) {
|
|
3960
|
-
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
3961
|
-
const pk = findPrimaryKey(this.table);
|
|
3962
|
-
const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
|
|
3963
|
-
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
3964
|
-
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
3965
|
-
return { state: nextState, hydration: joined.hydration };
|
|
3936
|
+
return { selfFilters, crossFilters };
|
|
3937
|
+
};
|
|
3938
|
+
var flattenAnd = (node) => {
|
|
3939
|
+
if (!node) return [];
|
|
3940
|
+
if (node.type === "LogicalExpression" && node.operator === "AND") {
|
|
3941
|
+
return node.operands.flatMap((operand) => flattenAnd(operand));
|
|
3966
3942
|
}
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
const relation = this.getRelation(relationName);
|
|
3977
|
-
const aliasPrefix = options?.aliasPrefix ?? relationName;
|
|
3978
|
-
const alreadyJoined = state.ast.joins.some((j) => getJoinRelationName(j) === relationName);
|
|
3979
|
-
const { selfFilters, crossFilters } = this.splitFilterExpressions(
|
|
3980
|
-
options?.filter,
|
|
3981
|
-
/* @__PURE__ */ new Set([relation.target.name])
|
|
3982
|
-
);
|
|
3983
|
-
const canUseCte = !alreadyJoined && selfFilters.length > 0;
|
|
3984
|
-
const joinFilters = [...crossFilters];
|
|
3985
|
-
if (!canUseCte) {
|
|
3986
|
-
joinFilters.push(...selfFilters);
|
|
3987
|
-
}
|
|
3988
|
-
const joinCondition = this.combineWithAnd(joinFilters);
|
|
3989
|
-
let tableSourceOverride;
|
|
3990
|
-
if (canUseCte) {
|
|
3991
|
-
const cteInfo = this.createFilteredRelationCte(state, relationName, relation, selfFilters);
|
|
3992
|
-
state = cteInfo.state;
|
|
3993
|
-
tableSourceOverride = cteInfo.table;
|
|
3994
|
-
}
|
|
3995
|
-
if (!alreadyJoined) {
|
|
3996
|
-
state = this.withJoin(
|
|
3997
|
-
state,
|
|
3998
|
-
relationName,
|
|
3999
|
-
options?.joinKind ?? JOIN_KINDS.LEFT,
|
|
4000
|
-
joinCondition,
|
|
4001
|
-
tableSourceOverride
|
|
4002
|
-
);
|
|
3943
|
+
return [node];
|
|
3944
|
+
};
|
|
3945
|
+
var isExpressionSelfContained = (expr, allowedTables) => {
|
|
3946
|
+
const collector = collectReferencedTables(expr);
|
|
3947
|
+
if (collector.hasSubquery) return false;
|
|
3948
|
+
if (collector.tables.size === 0) return true;
|
|
3949
|
+
for (const table of collector.tables) {
|
|
3950
|
+
if (!allowedTables.has(table)) {
|
|
3951
|
+
return false;
|
|
4003
3952
|
}
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
3953
|
+
}
|
|
3954
|
+
return true;
|
|
3955
|
+
};
|
|
3956
|
+
var collectReferencedTables = (expr) => {
|
|
3957
|
+
const collector = {
|
|
3958
|
+
tables: /* @__PURE__ */ new Set(),
|
|
3959
|
+
hasSubquery: false
|
|
3960
|
+
};
|
|
3961
|
+
collectFromExpression(expr, collector);
|
|
3962
|
+
return collector;
|
|
3963
|
+
};
|
|
3964
|
+
var collectFromExpression = (expr, collector) => {
|
|
3965
|
+
switch (expr.type) {
|
|
3966
|
+
case "BinaryExpression":
|
|
3967
|
+
collectFromOperand(expr.left, collector);
|
|
3968
|
+
collectFromOperand(expr.right, collector);
|
|
3969
|
+
break;
|
|
3970
|
+
case "LogicalExpression":
|
|
3971
|
+
expr.operands.forEach((operand) => collectFromExpression(operand, collector));
|
|
3972
|
+
break;
|
|
3973
|
+
case "NullExpression":
|
|
3974
|
+
collectFromOperand(expr.left, collector);
|
|
3975
|
+
break;
|
|
3976
|
+
case "InExpression":
|
|
3977
|
+
collectFromOperand(expr.left, collector);
|
|
3978
|
+
if (Array.isArray(expr.right)) {
|
|
3979
|
+
expr.right.forEach((value) => collectFromOperand(value, collector));
|
|
3980
|
+
} else {
|
|
3981
|
+
collector.hasSubquery = true;
|
|
4023
3982
|
}
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
};
|
|
4041
|
-
const targetSelection = buildTypedSelection(
|
|
4042
|
-
relation.target.columns,
|
|
4043
|
-
aliasPrefix,
|
|
4044
|
-
targetColumns,
|
|
4045
|
-
(key) => `Column '${key}' not found on relation '${relationName}'`
|
|
4046
|
-
);
|
|
4047
|
-
if (relation.type !== RelationKinds.BelongsToMany) {
|
|
4048
|
-
const relationSelectionResult2 = this.selectColumns(state, hydration, targetSelection);
|
|
4049
|
-
state = relationSelectionResult2.state;
|
|
4050
|
-
hydration = relationSelectionResult2.hydration;
|
|
4051
|
-
hydration = hydration.onRelationIncluded(
|
|
4052
|
-
state,
|
|
4053
|
-
relation,
|
|
4054
|
-
relationName,
|
|
4055
|
-
aliasPrefix,
|
|
4056
|
-
targetColumns
|
|
4057
|
-
);
|
|
4058
|
-
return { state, hydration };
|
|
4059
|
-
}
|
|
4060
|
-
const many = relation;
|
|
4061
|
-
const pivotAliasPrefix = options?.pivot?.aliasPrefix ?? `${aliasPrefix}_pivot`;
|
|
4062
|
-
const pivotPk = many.pivotPrimaryKey || findPrimaryKey(many.pivotTable);
|
|
4063
|
-
const pivotColumns = options?.pivot?.columns ?? many.defaultPivotColumns ?? buildDefaultPivotColumns(many, pivotPk);
|
|
4064
|
-
const pivotSelection = buildTypedSelection(
|
|
4065
|
-
many.pivotTable.columns,
|
|
4066
|
-
pivotAliasPrefix,
|
|
4067
|
-
pivotColumns,
|
|
4068
|
-
(key) => `Column '${key}' not found on pivot table '${many.pivotTable.name}'`
|
|
4069
|
-
);
|
|
4070
|
-
const combinedSelection = {
|
|
4071
|
-
...targetSelection,
|
|
4072
|
-
...pivotSelection
|
|
4073
|
-
};
|
|
4074
|
-
const relationSelectionResult = this.selectColumns(state, hydration, combinedSelection);
|
|
4075
|
-
state = relationSelectionResult.state;
|
|
4076
|
-
hydration = relationSelectionResult.hydration;
|
|
4077
|
-
hydration = hydration.onRelationIncluded(
|
|
4078
|
-
state,
|
|
4079
|
-
relation,
|
|
4080
|
-
relationName,
|
|
4081
|
-
aliasPrefix,
|
|
4082
|
-
targetColumns,
|
|
4083
|
-
{ aliasPrefix: pivotAliasPrefix, columns: pivotColumns }
|
|
4084
|
-
);
|
|
4085
|
-
return { state, hydration };
|
|
3983
|
+
break;
|
|
3984
|
+
case "ExistsExpression":
|
|
3985
|
+
collector.hasSubquery = true;
|
|
3986
|
+
break;
|
|
3987
|
+
case "BetweenExpression":
|
|
3988
|
+
collectFromOperand(expr.left, collector);
|
|
3989
|
+
collectFromOperand(expr.lower, collector);
|
|
3990
|
+
collectFromOperand(expr.upper, collector);
|
|
3991
|
+
break;
|
|
3992
|
+
case "ArithmeticExpression":
|
|
3993
|
+
case "BitwiseExpression":
|
|
3994
|
+
collectFromOperand(expr.left, collector);
|
|
3995
|
+
collectFromOperand(expr.right, collector);
|
|
3996
|
+
break;
|
|
3997
|
+
default:
|
|
3998
|
+
break;
|
|
4086
3999
|
}
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4000
|
+
};
|
|
4001
|
+
var collectFromOperand = (node, collector) => {
|
|
4002
|
+
switch (node.type) {
|
|
4003
|
+
case "Column":
|
|
4004
|
+
collector.tables.add(node.table);
|
|
4005
|
+
break;
|
|
4006
|
+
case "Function":
|
|
4007
|
+
node.args.forEach((arg) => collectFromOperand(arg, collector));
|
|
4008
|
+
if (node.separator) {
|
|
4009
|
+
collectFromOperand(node.separator, collector);
|
|
4010
|
+
}
|
|
4011
|
+
if (node.orderBy) {
|
|
4012
|
+
node.orderBy.forEach((order) => collectFromOrderingTerm(order.term, collector));
|
|
4013
|
+
}
|
|
4014
|
+
break;
|
|
4015
|
+
case "JsonPath":
|
|
4016
|
+
collectFromOperand(node.column, collector);
|
|
4017
|
+
break;
|
|
4018
|
+
case "ScalarSubquery":
|
|
4019
|
+
collector.hasSubquery = true;
|
|
4020
|
+
break;
|
|
4021
|
+
case "CaseExpression":
|
|
4022
|
+
node.conditions.forEach(({ when, then }) => {
|
|
4023
|
+
collectFromExpression(when, collector);
|
|
4024
|
+
collectFromOperand(then, collector);
|
|
4025
|
+
});
|
|
4026
|
+
if (node.else) {
|
|
4027
|
+
collectFromOperand(node.else, collector);
|
|
4028
|
+
}
|
|
4029
|
+
break;
|
|
4030
|
+
case "Cast":
|
|
4031
|
+
collectFromOperand(node.expression, collector);
|
|
4032
|
+
break;
|
|
4033
|
+
case "WindowFunction":
|
|
4034
|
+
node.args.forEach((arg) => collectFromOperand(arg, collector));
|
|
4035
|
+
node.partitionBy?.forEach((part) => collectFromOperand(part, collector));
|
|
4036
|
+
node.orderBy?.forEach((order) => collectFromOrderingTerm(order.term, collector));
|
|
4037
|
+
break;
|
|
4038
|
+
case "Collate":
|
|
4039
|
+
collectFromOperand(node.expression, collector);
|
|
4040
|
+
break;
|
|
4041
|
+
case "ArithmeticExpression":
|
|
4042
|
+
case "BitwiseExpression":
|
|
4043
|
+
collectFromOperand(node.left, collector);
|
|
4044
|
+
collectFromOperand(node.right, collector);
|
|
4045
|
+
break;
|
|
4046
|
+
case "Literal":
|
|
4047
|
+
case "AliasRef":
|
|
4048
|
+
break;
|
|
4049
|
+
default:
|
|
4050
|
+
break;
|
|
4105
4051
|
}
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4052
|
+
};
|
|
4053
|
+
var collectFromOrderingTerm = (term, collector) => {
|
|
4054
|
+
if (isOperandNode(term)) {
|
|
4055
|
+
collectFromOperand(term, collector);
|
|
4056
|
+
return;
|
|
4057
|
+
}
|
|
4058
|
+
collectFromExpression(term, collector);
|
|
4059
|
+
};
|
|
4060
|
+
|
|
4061
|
+
// src/query-builder/relation-join-planner.ts
|
|
4062
|
+
var RelationJoinPlanner = class {
|
|
4063
|
+
constructor(table, createQueryAstService) {
|
|
4064
|
+
this.table = table;
|
|
4065
|
+
this.createQueryAstService = createQueryAstService;
|
|
4066
|
+
}
|
|
4067
|
+
withJoin(state, relationName, relation, joinKind, extraCondition, tableSource) {
|
|
4116
4068
|
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
4117
4069
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
4118
4070
|
const targetTableSource = tableSource ?? {
|
|
@@ -4149,167 +4101,31 @@ var RelationService = class {
|
|
|
4149
4101
|
const joinNode = createJoinNode(joinKind, targetTable, condition, relationName);
|
|
4150
4102
|
return this.astService(state).withJoin(joinNode);
|
|
4151
4103
|
}
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
* @param state - Current query state
|
|
4155
|
-
* @param hydration - Hydration manager
|
|
4156
|
-
* @param columns - Columns to select
|
|
4157
|
-
* @returns Relation result with updated state and hydration
|
|
4158
|
-
*/
|
|
4159
|
-
selectColumns(state, hydration, columns) {
|
|
4160
|
-
const { state: nextState, addedColumns } = this.astService(state).select(columns);
|
|
4161
|
-
return {
|
|
4162
|
-
state: nextState,
|
|
4163
|
-
hydration: hydration.onColumnsSelected(nextState, addedColumns)
|
|
4164
|
-
};
|
|
4165
|
-
}
|
|
4166
|
-
combineWithAnd(expressions) {
|
|
4167
|
-
if (expressions.length === 0) return void 0;
|
|
4168
|
-
if (expressions.length === 1) return expressions[0];
|
|
4169
|
-
return {
|
|
4170
|
-
type: "LogicalExpression",
|
|
4171
|
-
operator: "AND",
|
|
4172
|
-
operands: expressions
|
|
4173
|
-
};
|
|
4174
|
-
}
|
|
4175
|
-
splitFilterExpressions(filter, allowedTables) {
|
|
4176
|
-
const terms = this.flattenAnd(filter);
|
|
4177
|
-
const selfFilters = [];
|
|
4178
|
-
const crossFilters = [];
|
|
4179
|
-
for (const term of terms) {
|
|
4180
|
-
if (this.isExpressionSelfContained(term, allowedTables)) {
|
|
4181
|
-
selfFilters.push(term);
|
|
4182
|
-
} else {
|
|
4183
|
-
crossFilters.push(term);
|
|
4184
|
-
}
|
|
4185
|
-
}
|
|
4186
|
-
return { selfFilters, crossFilters };
|
|
4187
|
-
}
|
|
4188
|
-
flattenAnd(node) {
|
|
4189
|
-
if (!node) return [];
|
|
4190
|
-
if (node.type === "LogicalExpression" && node.operator === "AND") {
|
|
4191
|
-
return node.operands.flatMap((operand) => this.flattenAnd(operand));
|
|
4192
|
-
}
|
|
4193
|
-
return [node];
|
|
4104
|
+
astService(state) {
|
|
4105
|
+
return this.createQueryAstService(this.table, state);
|
|
4194
4106
|
}
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
if (collector.tables.size === 0) return true;
|
|
4199
|
-
for (const table of collector.tables) {
|
|
4200
|
-
if (!allowedTables.has(table)) {
|
|
4201
|
-
return false;
|
|
4202
|
-
}
|
|
4107
|
+
resolveTargetTableName(target, relation) {
|
|
4108
|
+
if (target.type === "Table") {
|
|
4109
|
+
return target.alias ?? target.name;
|
|
4203
4110
|
}
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
collectReferencedTables(expr) {
|
|
4207
|
-
const collector = {
|
|
4208
|
-
tables: /* @__PURE__ */ new Set(),
|
|
4209
|
-
hasSubquery: false
|
|
4210
|
-
};
|
|
4211
|
-
this.collectFromExpression(expr, collector);
|
|
4212
|
-
return collector;
|
|
4213
|
-
}
|
|
4214
|
-
collectFromExpression(expr, collector) {
|
|
4215
|
-
switch (expr.type) {
|
|
4216
|
-
case "BinaryExpression":
|
|
4217
|
-
this.collectFromOperand(expr.left, collector);
|
|
4218
|
-
this.collectFromOperand(expr.right, collector);
|
|
4219
|
-
break;
|
|
4220
|
-
case "LogicalExpression":
|
|
4221
|
-
expr.operands.forEach((operand) => this.collectFromExpression(operand, collector));
|
|
4222
|
-
break;
|
|
4223
|
-
case "NullExpression":
|
|
4224
|
-
this.collectFromOperand(expr.left, collector);
|
|
4225
|
-
break;
|
|
4226
|
-
case "InExpression":
|
|
4227
|
-
this.collectFromOperand(expr.left, collector);
|
|
4228
|
-
if (Array.isArray(expr.right)) {
|
|
4229
|
-
expr.right.forEach((value) => this.collectFromOperand(value, collector));
|
|
4230
|
-
} else {
|
|
4231
|
-
collector.hasSubquery = true;
|
|
4232
|
-
}
|
|
4233
|
-
break;
|
|
4234
|
-
case "ExistsExpression":
|
|
4235
|
-
collector.hasSubquery = true;
|
|
4236
|
-
break;
|
|
4237
|
-
case "BetweenExpression":
|
|
4238
|
-
this.collectFromOperand(expr.left, collector);
|
|
4239
|
-
this.collectFromOperand(expr.lower, collector);
|
|
4240
|
-
this.collectFromOperand(expr.upper, collector);
|
|
4241
|
-
break;
|
|
4242
|
-
case "ArithmeticExpression":
|
|
4243
|
-
case "BitwiseExpression":
|
|
4244
|
-
this.collectFromOperand(expr.left, collector);
|
|
4245
|
-
this.collectFromOperand(expr.right, collector);
|
|
4246
|
-
break;
|
|
4247
|
-
default:
|
|
4248
|
-
break;
|
|
4111
|
+
if (target.type === "DerivedTable") {
|
|
4112
|
+
return target.alias;
|
|
4249
4113
|
}
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
switch (node.type) {
|
|
4253
|
-
case "Column":
|
|
4254
|
-
collector.tables.add(node.table);
|
|
4255
|
-
break;
|
|
4256
|
-
case "Function":
|
|
4257
|
-
node.args.forEach((arg) => this.collectFromOperand(arg, collector));
|
|
4258
|
-
if (node.separator) {
|
|
4259
|
-
this.collectFromOperand(node.separator, collector);
|
|
4260
|
-
}
|
|
4261
|
-
if (node.orderBy) {
|
|
4262
|
-
node.orderBy.forEach((order) => this.collectFromOrderingTerm(order.term, collector));
|
|
4263
|
-
}
|
|
4264
|
-
break;
|
|
4265
|
-
case "JsonPath":
|
|
4266
|
-
this.collectFromOperand(node.column, collector);
|
|
4267
|
-
break;
|
|
4268
|
-
case "ScalarSubquery":
|
|
4269
|
-
collector.hasSubquery = true;
|
|
4270
|
-
break;
|
|
4271
|
-
case "CaseExpression":
|
|
4272
|
-
node.conditions.forEach(({ when, then }) => {
|
|
4273
|
-
this.collectFromExpression(when, collector);
|
|
4274
|
-
this.collectFromOperand(then, collector);
|
|
4275
|
-
});
|
|
4276
|
-
if (node.else) {
|
|
4277
|
-
this.collectFromOperand(node.else, collector);
|
|
4278
|
-
}
|
|
4279
|
-
break;
|
|
4280
|
-
case "Cast":
|
|
4281
|
-
this.collectFromOperand(node.expression, collector);
|
|
4282
|
-
break;
|
|
4283
|
-
case "WindowFunction":
|
|
4284
|
-
node.args.forEach((arg) => this.collectFromOperand(arg, collector));
|
|
4285
|
-
node.partitionBy?.forEach((part) => this.collectFromOperand(part, collector));
|
|
4286
|
-
node.orderBy?.forEach((order) => this.collectFromOrderingTerm(order.term, collector));
|
|
4287
|
-
break;
|
|
4288
|
-
case "Collate":
|
|
4289
|
-
this.collectFromOperand(node.expression, collector);
|
|
4290
|
-
break;
|
|
4291
|
-
case "ArithmeticExpression":
|
|
4292
|
-
case "BitwiseExpression":
|
|
4293
|
-
this.collectFromOperand(node.left, collector);
|
|
4294
|
-
this.collectFromOperand(node.right, collector);
|
|
4295
|
-
break;
|
|
4296
|
-
case "Literal":
|
|
4297
|
-
case "AliasRef":
|
|
4298
|
-
break;
|
|
4299
|
-
default:
|
|
4300
|
-
break;
|
|
4114
|
+
if (target.type === "FunctionTable") {
|
|
4115
|
+
return target.alias ?? relation.target.name;
|
|
4301
4116
|
}
|
|
4117
|
+
return relation.target.name;
|
|
4302
4118
|
}
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
this.
|
|
4119
|
+
};
|
|
4120
|
+
|
|
4121
|
+
// src/query-builder/relation-cte-builder.ts
|
|
4122
|
+
var RelationCteBuilder = class {
|
|
4123
|
+
constructor(table, createQueryAstService) {
|
|
4124
|
+
this.table = table;
|
|
4125
|
+
this.createQueryAstService = createQueryAstService;
|
|
4309
4126
|
}
|
|
4310
|
-
createFilteredRelationCte(state, relationName, relation,
|
|
4127
|
+
createFilteredRelationCte(state, relationName, relation, predicate) {
|
|
4311
4128
|
const cteName = this.generateUniqueCteName(state, relationName);
|
|
4312
|
-
const predicate = this.combineWithAnd(filters);
|
|
4313
4129
|
if (!predicate) {
|
|
4314
4130
|
throw new Error("Unable to build filter CTE without predicates.");
|
|
4315
4131
|
}
|
|
@@ -4343,82 +4159,339 @@ var RelationService = class {
|
|
|
4343
4159
|
}
|
|
4344
4160
|
return candidate;
|
|
4345
4161
|
}
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
return target.alias ?? target.name;
|
|
4349
|
-
}
|
|
4350
|
-
if (target.type === "DerivedTable") {
|
|
4351
|
-
return target.alias;
|
|
4352
|
-
}
|
|
4353
|
-
if (target.type === "FunctionTable") {
|
|
4354
|
-
return target.alias ?? relation.target.name;
|
|
4355
|
-
}
|
|
4356
|
-
return relation.target.name;
|
|
4162
|
+
astService(state) {
|
|
4163
|
+
return this.createQueryAstService(this.table, state);
|
|
4357
4164
|
}
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
if (!relation) {
|
|
4367
|
-
throw new Error(`Relation '${relationName}' not found on table '${this.table.name}'`);
|
|
4165
|
+
};
|
|
4166
|
+
|
|
4167
|
+
// src/query-builder/relation-include-strategies.ts
|
|
4168
|
+
var buildTypedSelection = (columns, prefix, keys, missingMsg) => {
|
|
4169
|
+
return keys.reduce((acc, key) => {
|
|
4170
|
+
const def = columns[key];
|
|
4171
|
+
if (!def) {
|
|
4172
|
+
throw new Error(missingMsg(key));
|
|
4368
4173
|
}
|
|
4369
|
-
|
|
4174
|
+
acc[makeRelationAlias(prefix, key)] = def;
|
|
4175
|
+
return acc;
|
|
4176
|
+
}, {});
|
|
4177
|
+
};
|
|
4178
|
+
var resolveTargetColumns = (relation, options) => {
|
|
4179
|
+
const requestedColumns = options?.columns?.length ? [...options.columns] : Object.keys(relation.target.columns);
|
|
4180
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
4181
|
+
if (!requestedColumns.includes(targetPrimaryKey)) {
|
|
4182
|
+
requestedColumns.push(targetPrimaryKey);
|
|
4370
4183
|
}
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
return this.createQueryAstService(this.table, state);
|
|
4184
|
+
return requestedColumns;
|
|
4185
|
+
};
|
|
4186
|
+
var ensureRootForeignKeySelected = (context, relation) => {
|
|
4187
|
+
const fkColumn = context.rootTable.columns[relation.foreignKey];
|
|
4188
|
+
if (!fkColumn) {
|
|
4189
|
+
return { state: context.state, hydration: context.hydration };
|
|
4378
4190
|
}
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4191
|
+
const hasForeignKeySelected = context.state.ast.columns.some((col2) => {
|
|
4192
|
+
if (col2.type !== "Column") return false;
|
|
4193
|
+
const node = col2;
|
|
4194
|
+
const alias = node.alias ?? node.name;
|
|
4195
|
+
return alias === relation.foreignKey;
|
|
4196
|
+
});
|
|
4197
|
+
if (hasForeignKeySelected) {
|
|
4198
|
+
return { state: context.state, hydration: context.hydration };
|
|
4383
4199
|
}
|
|
4200
|
+
return context.selectColumns(context.state, context.hydration, {
|
|
4201
|
+
[relation.foreignKey]: fkColumn
|
|
4202
|
+
});
|
|
4203
|
+
};
|
|
4204
|
+
var standardIncludeStrategy = (context) => {
|
|
4205
|
+
const relation = context.relation;
|
|
4206
|
+
let { state, hydration } = context;
|
|
4207
|
+
const fkSelectionResult = ensureRootForeignKeySelected(context, relation);
|
|
4208
|
+
state = fkSelectionResult.state;
|
|
4209
|
+
hydration = fkSelectionResult.hydration;
|
|
4210
|
+
const targetColumns = resolveTargetColumns(relation, context.options);
|
|
4211
|
+
const targetSelection = buildTypedSelection(
|
|
4212
|
+
relation.target.columns,
|
|
4213
|
+
context.aliasPrefix,
|
|
4214
|
+
targetColumns,
|
|
4215
|
+
(key) => `Column '${key}' not found on relation '${context.relationName}'`
|
|
4216
|
+
);
|
|
4217
|
+
const relationSelectionResult = context.selectColumns(state, hydration, targetSelection);
|
|
4218
|
+
state = relationSelectionResult.state;
|
|
4219
|
+
hydration = relationSelectionResult.hydration;
|
|
4220
|
+
hydration = hydration.onRelationIncluded(
|
|
4221
|
+
state,
|
|
4222
|
+
relation,
|
|
4223
|
+
context.relationName,
|
|
4224
|
+
context.aliasPrefix,
|
|
4225
|
+
targetColumns
|
|
4226
|
+
);
|
|
4227
|
+
return { state, hydration };
|
|
4228
|
+
};
|
|
4229
|
+
var belongsToManyStrategy = (context) => {
|
|
4230
|
+
const relation = context.relation;
|
|
4231
|
+
let { state, hydration } = context;
|
|
4232
|
+
const targetColumns = resolveTargetColumns(relation, context.options);
|
|
4233
|
+
const targetSelection = buildTypedSelection(
|
|
4234
|
+
relation.target.columns,
|
|
4235
|
+
context.aliasPrefix,
|
|
4236
|
+
targetColumns,
|
|
4237
|
+
(key) => `Column '${key}' not found on relation '${context.relationName}'`
|
|
4238
|
+
);
|
|
4239
|
+
const pivotAliasPrefix = context.options?.pivot?.aliasPrefix ?? `${context.aliasPrefix}_pivot`;
|
|
4240
|
+
const pivotPk = relation.pivotPrimaryKey || findPrimaryKey(relation.pivotTable);
|
|
4241
|
+
const defaultPivotColumns = relation.defaultPivotColumns ?? buildDefaultPivotColumns(relation, pivotPk);
|
|
4242
|
+
const pivotColumns = context.options?.pivot?.columns ? [...context.options.pivot.columns] : [...defaultPivotColumns];
|
|
4243
|
+
const pivotSelection = buildTypedSelection(
|
|
4244
|
+
relation.pivotTable.columns,
|
|
4245
|
+
pivotAliasPrefix,
|
|
4246
|
+
pivotColumns,
|
|
4247
|
+
(key) => `Column '${key}' not found on pivot table '${relation.pivotTable.name}'`
|
|
4248
|
+
);
|
|
4249
|
+
const combinedSelection = {
|
|
4250
|
+
...targetSelection,
|
|
4251
|
+
...pivotSelection
|
|
4252
|
+
};
|
|
4253
|
+
const relationSelectionResult = context.selectColumns(state, hydration, combinedSelection);
|
|
4254
|
+
state = relationSelectionResult.state;
|
|
4255
|
+
hydration = relationSelectionResult.hydration;
|
|
4256
|
+
hydration = hydration.onRelationIncluded(
|
|
4257
|
+
state,
|
|
4258
|
+
relation,
|
|
4259
|
+
context.relationName,
|
|
4260
|
+
context.aliasPrefix,
|
|
4261
|
+
targetColumns,
|
|
4262
|
+
{ aliasPrefix: pivotAliasPrefix, columns: pivotColumns }
|
|
4263
|
+
);
|
|
4264
|
+
return { state, hydration };
|
|
4265
|
+
};
|
|
4266
|
+
var relationIncludeStrategies = {
|
|
4267
|
+
[RelationKinds.HasMany]: standardIncludeStrategy,
|
|
4268
|
+
[RelationKinds.HasOne]: standardIncludeStrategy,
|
|
4269
|
+
[RelationKinds.BelongsTo]: standardIncludeStrategy,
|
|
4270
|
+
[RelationKinds.BelongsToMany]: belongsToManyStrategy
|
|
4384
4271
|
};
|
|
4385
4272
|
|
|
4386
|
-
// src/query-builder/
|
|
4387
|
-
var
|
|
4273
|
+
// src/query-builder/relation-service.ts
|
|
4274
|
+
var RelationService = class {
|
|
4388
4275
|
/**
|
|
4389
|
-
* Creates a new
|
|
4390
|
-
* @param
|
|
4276
|
+
* Creates a new RelationService instance
|
|
4277
|
+
* @param table - Table definition
|
|
4278
|
+
* @param state - Current query state
|
|
4279
|
+
* @param hydration - Hydration manager
|
|
4391
4280
|
*/
|
|
4392
|
-
constructor(
|
|
4393
|
-
this.
|
|
4281
|
+
constructor(table, state, hydration, createQueryAstService) {
|
|
4282
|
+
this.table = table;
|
|
4283
|
+
this.state = state;
|
|
4284
|
+
this.hydration = hydration;
|
|
4285
|
+
this.createQueryAstService = createQueryAstService;
|
|
4286
|
+
this.projectionHelper = new RelationProjectionHelper(
|
|
4287
|
+
table,
|
|
4288
|
+
(state2, hydration2, columns) => this.selectColumns(state2, hydration2, columns)
|
|
4289
|
+
);
|
|
4290
|
+
this.joinPlanner = new RelationJoinPlanner(table, createQueryAstService);
|
|
4291
|
+
this.cteBuilder = new RelationCteBuilder(table, createQueryAstService);
|
|
4394
4292
|
}
|
|
4293
|
+
projectionHelper;
|
|
4294
|
+
joinPlanner;
|
|
4295
|
+
cteBuilder;
|
|
4395
4296
|
/**
|
|
4396
|
-
*
|
|
4397
|
-
* @param
|
|
4398
|
-
* @param
|
|
4399
|
-
* @
|
|
4297
|
+
* Joins a relation to the query
|
|
4298
|
+
* @param relationName - Name of the relation to join
|
|
4299
|
+
* @param joinKind - Type of join to use
|
|
4300
|
+
* @param extraCondition - Additional join condition
|
|
4301
|
+
* @returns Relation result with updated state and hydration
|
|
4400
4302
|
*/
|
|
4401
|
-
|
|
4402
|
-
const
|
|
4403
|
-
const
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4303
|
+
joinRelation(relationName, joinKind, extraCondition, tableSource) {
|
|
4304
|
+
const relation = this.getRelation(relationName);
|
|
4305
|
+
const nextState = this.joinPlanner.withJoin(
|
|
4306
|
+
this.state,
|
|
4307
|
+
relationName,
|
|
4308
|
+
relation,
|
|
4309
|
+
joinKind,
|
|
4310
|
+
extraCondition,
|
|
4311
|
+
tableSource
|
|
4312
|
+
);
|
|
4313
|
+
return { state: nextState, hydration: this.hydration };
|
|
4408
4314
|
}
|
|
4409
4315
|
/**
|
|
4410
|
-
*
|
|
4411
|
-
* @param
|
|
4412
|
-
* @param
|
|
4413
|
-
* @returns
|
|
4316
|
+
* Matches records based on a relation with an optional predicate
|
|
4317
|
+
* @param relationName - Name of the relation to match
|
|
4318
|
+
* @param predicate - Optional predicate expression
|
|
4319
|
+
* @returns Relation result with updated state and hydration
|
|
4414
4320
|
*/
|
|
4415
|
-
|
|
4416
|
-
const
|
|
4417
|
-
const
|
|
4418
|
-
|
|
4321
|
+
match(relationName, predicate) {
|
|
4322
|
+
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
4323
|
+
const pk = findPrimaryKey(this.table);
|
|
4324
|
+
const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
|
|
4325
|
+
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
4326
|
+
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
4327
|
+
return { state: nextState, hydration: joined.hydration };
|
|
4419
4328
|
}
|
|
4420
4329
|
/**
|
|
4421
|
-
*
|
|
4330
|
+
* Includes a relation in the query result
|
|
4331
|
+
* @param relationName - Name of the relation to include
|
|
4332
|
+
* @param options - Options for relation inclusion
|
|
4333
|
+
* @returns Relation result with updated state and hydration
|
|
4334
|
+
*/
|
|
4335
|
+
include(relationName, options) {
|
|
4336
|
+
let state = this.state;
|
|
4337
|
+
let hydration = this.hydration;
|
|
4338
|
+
const relation = this.getRelation(relationName);
|
|
4339
|
+
const aliasPrefix = options?.aliasPrefix ?? relationName;
|
|
4340
|
+
const alreadyJoined = state.ast.joins.some((j) => getJoinRelationName(j) === relationName);
|
|
4341
|
+
const { selfFilters, crossFilters } = splitFilterExpressions(
|
|
4342
|
+
options?.filter,
|
|
4343
|
+
/* @__PURE__ */ new Set([relation.target.name])
|
|
4344
|
+
);
|
|
4345
|
+
const canUseCte = !alreadyJoined && selfFilters.length > 0;
|
|
4346
|
+
const joinFilters = [...crossFilters];
|
|
4347
|
+
if (!canUseCte) {
|
|
4348
|
+
joinFilters.push(...selfFilters);
|
|
4349
|
+
}
|
|
4350
|
+
const joinCondition = this.combineWithAnd(joinFilters);
|
|
4351
|
+
let tableSourceOverride;
|
|
4352
|
+
if (canUseCte) {
|
|
4353
|
+
const predicate = this.combineWithAnd(selfFilters);
|
|
4354
|
+
const cteInfo = this.cteBuilder.createFilteredRelationCte(
|
|
4355
|
+
state,
|
|
4356
|
+
relationName,
|
|
4357
|
+
relation,
|
|
4358
|
+
predicate
|
|
4359
|
+
);
|
|
4360
|
+
state = cteInfo.state;
|
|
4361
|
+
tableSourceOverride = cteInfo.table;
|
|
4362
|
+
}
|
|
4363
|
+
if (!alreadyJoined) {
|
|
4364
|
+
state = this.joinPlanner.withJoin(
|
|
4365
|
+
state,
|
|
4366
|
+
relationName,
|
|
4367
|
+
relation,
|
|
4368
|
+
options?.joinKind ?? JOIN_KINDS.LEFT,
|
|
4369
|
+
joinCondition,
|
|
4370
|
+
tableSourceOverride
|
|
4371
|
+
);
|
|
4372
|
+
}
|
|
4373
|
+
const projectionResult = this.projectionHelper.ensureBaseProjection(state, hydration);
|
|
4374
|
+
state = projectionResult.state;
|
|
4375
|
+
hydration = projectionResult.hydration;
|
|
4376
|
+
const strategy = relationIncludeStrategies[relation.type];
|
|
4377
|
+
const result = strategy({
|
|
4378
|
+
rootTable: this.table,
|
|
4379
|
+
state,
|
|
4380
|
+
hydration,
|
|
4381
|
+
relation,
|
|
4382
|
+
relationName,
|
|
4383
|
+
aliasPrefix,
|
|
4384
|
+
options,
|
|
4385
|
+
selectColumns: (nextState, nextHydration, columns) => this.selectColumns(nextState, nextHydration, columns)
|
|
4386
|
+
});
|
|
4387
|
+
return { state: result.state, hydration: result.hydration };
|
|
4388
|
+
}
|
|
4389
|
+
/**
|
|
4390
|
+
* Applies relation correlation to a query AST
|
|
4391
|
+
* @param relationName - Name of the relation
|
|
4392
|
+
* @param ast - Query AST to modify
|
|
4393
|
+
* @returns Modified query AST with relation correlation
|
|
4394
|
+
*/
|
|
4395
|
+
applyRelationCorrelation(relationName, ast, additionalCorrelation) {
|
|
4396
|
+
const relation = this.getRelation(relationName);
|
|
4397
|
+
const rootAlias = this.state.ast.from.type === "Table" ? this.state.ast.from.alias : void 0;
|
|
4398
|
+
let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
|
|
4399
|
+
if (additionalCorrelation) {
|
|
4400
|
+
correlation = and(correlation, additionalCorrelation);
|
|
4401
|
+
}
|
|
4402
|
+
const whereInSubquery = ast.where ? and(correlation, ast.where) : correlation;
|
|
4403
|
+
return {
|
|
4404
|
+
...ast,
|
|
4405
|
+
where: whereInSubquery
|
|
4406
|
+
};
|
|
4407
|
+
}
|
|
4408
|
+
/**
|
|
4409
|
+
* Selects columns for a relation
|
|
4410
|
+
* @param state - Current query state
|
|
4411
|
+
* @param hydration - Hydration manager
|
|
4412
|
+
* @param columns - Columns to select
|
|
4413
|
+
* @returns Relation result with updated state and hydration
|
|
4414
|
+
*/
|
|
4415
|
+
selectColumns(state, hydration, columns) {
|
|
4416
|
+
const { state: nextState, addedColumns } = this.astService(state).select(columns);
|
|
4417
|
+
return {
|
|
4418
|
+
state: nextState,
|
|
4419
|
+
hydration: hydration.onColumnsSelected(nextState, addedColumns)
|
|
4420
|
+
};
|
|
4421
|
+
}
|
|
4422
|
+
combineWithAnd(expressions) {
|
|
4423
|
+
if (expressions.length === 0) return void 0;
|
|
4424
|
+
if (expressions.length === 1) return expressions[0];
|
|
4425
|
+
return {
|
|
4426
|
+
type: "LogicalExpression",
|
|
4427
|
+
operator: "AND",
|
|
4428
|
+
operands: expressions
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4431
|
+
/**
|
|
4432
|
+
* Gets a relation definition by name
|
|
4433
|
+
* @param relationName - Name of the relation
|
|
4434
|
+
* @returns Relation definition
|
|
4435
|
+
* @throws Error if relation is not found
|
|
4436
|
+
*/
|
|
4437
|
+
getRelation(relationName) {
|
|
4438
|
+
const relation = this.table.relations[relationName];
|
|
4439
|
+
if (!relation) {
|
|
4440
|
+
throw new Error(`Relation '${relationName}' not found on table '${this.table.name}'`);
|
|
4441
|
+
}
|
|
4442
|
+
return relation;
|
|
4443
|
+
}
|
|
4444
|
+
/**
|
|
4445
|
+
* Creates a QueryAstService instance
|
|
4446
|
+
* @param state - Current query state
|
|
4447
|
+
* @returns QueryAstService instance
|
|
4448
|
+
*/
|
|
4449
|
+
astService(state = this.state) {
|
|
4450
|
+
return this.createQueryAstService(this.table, state);
|
|
4451
|
+
}
|
|
4452
|
+
rootTableName() {
|
|
4453
|
+
const from = this.state.ast.from;
|
|
4454
|
+
if (from.type === "Table" && from.alias) return from.alias;
|
|
4455
|
+
return this.table.name;
|
|
4456
|
+
}
|
|
4457
|
+
};
|
|
4458
|
+
|
|
4459
|
+
// src/query-builder/column-selector.ts
|
|
4460
|
+
var ColumnSelector = class {
|
|
4461
|
+
/**
|
|
4462
|
+
* Creates a new ColumnSelector instance
|
|
4463
|
+
* @param env - Query builder environment
|
|
4464
|
+
*/
|
|
4465
|
+
constructor(env) {
|
|
4466
|
+
this.env = env;
|
|
4467
|
+
}
|
|
4468
|
+
/**
|
|
4469
|
+
* Selects columns for the query
|
|
4470
|
+
* @param context - Current query context
|
|
4471
|
+
* @param columns - Columns to select
|
|
4472
|
+
* @returns Updated query context with selected columns
|
|
4473
|
+
*/
|
|
4474
|
+
select(context, columns) {
|
|
4475
|
+
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
4476
|
+
const { state: nextState, addedColumns } = astService.select(columns);
|
|
4477
|
+
return {
|
|
4478
|
+
state: nextState,
|
|
4479
|
+
hydration: context.hydration.onColumnsSelected(nextState, addedColumns)
|
|
4480
|
+
};
|
|
4481
|
+
}
|
|
4482
|
+
/**
|
|
4483
|
+
* Selects raw column expressions
|
|
4484
|
+
* @param context - Current query context
|
|
4485
|
+
* @param columns - Raw column expressions
|
|
4486
|
+
* @returns Updated query context with raw column selections
|
|
4487
|
+
*/
|
|
4488
|
+
selectRaw(context, columns) {
|
|
4489
|
+
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
4490
|
+
const nextState = astService.selectRaw(columns).state;
|
|
4491
|
+
return { state: nextState, hydration: context.hydration };
|
|
4492
|
+
}
|
|
4493
|
+
/**
|
|
4494
|
+
* Selects a subquery as a column
|
|
4422
4495
|
* @param context - Current query context
|
|
4423
4496
|
* @param alias - Alias for the subquery
|
|
4424
4497
|
* @param query - Subquery to select
|
|
@@ -4643,8 +4716,52 @@ var hasEntityMeta = (entity) => {
|
|
|
4643
4716
|
return Boolean(getEntityMeta(entity));
|
|
4644
4717
|
};
|
|
4645
4718
|
|
|
4646
|
-
// src/orm/
|
|
4719
|
+
// src/orm/entity-hydration.ts
|
|
4647
4720
|
var toKey2 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4721
|
+
var populateHydrationCache = (entity, row, meta) => {
|
|
4722
|
+
for (const relationName of Object.keys(meta.table.relations)) {
|
|
4723
|
+
const relation = meta.table.relations[relationName];
|
|
4724
|
+
const data = row[relationName];
|
|
4725
|
+
if (relation.type === RelationKinds.HasOne) {
|
|
4726
|
+
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
4727
|
+
const rootValue = entity[localKey];
|
|
4728
|
+
if (rootValue === void 0 || rootValue === null) continue;
|
|
4729
|
+
if (!data || typeof data !== "object") continue;
|
|
4730
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4731
|
+
cache.set(toKey2(rootValue), data);
|
|
4732
|
+
meta.relationHydration.set(relationName, cache);
|
|
4733
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
4734
|
+
continue;
|
|
4735
|
+
}
|
|
4736
|
+
if (!Array.isArray(data)) continue;
|
|
4737
|
+
if (relation.type === RelationKinds.HasMany || relation.type === RelationKinds.BelongsToMany) {
|
|
4738
|
+
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
4739
|
+
const rootValue = entity[localKey];
|
|
4740
|
+
if (rootValue === void 0 || rootValue === null) continue;
|
|
4741
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4742
|
+
cache.set(toKey2(rootValue), data);
|
|
4743
|
+
meta.relationHydration.set(relationName, cache);
|
|
4744
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
4745
|
+
continue;
|
|
4746
|
+
}
|
|
4747
|
+
if (relation.type === RelationKinds.BelongsTo) {
|
|
4748
|
+
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
4749
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4750
|
+
for (const item of data) {
|
|
4751
|
+
const pkValue = item[targetKey];
|
|
4752
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
4753
|
+
cache.set(toKey2(pkValue), item);
|
|
4754
|
+
}
|
|
4755
|
+
if (cache.size) {
|
|
4756
|
+
meta.relationHydration.set(relationName, cache);
|
|
4757
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4761
|
+
};
|
|
4762
|
+
|
|
4763
|
+
// src/orm/relations/has-many.ts
|
|
4764
|
+
var toKey3 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4648
4765
|
var hideInternal = (obj, keys) => {
|
|
4649
4766
|
for (const key of keys) {
|
|
4650
4767
|
Object.defineProperty(obj, key, {
|
|
@@ -4678,13 +4795,13 @@ var DefaultHasManyCollection = class {
|
|
|
4678
4795
|
this.loader = loader;
|
|
4679
4796
|
this.createEntity = createEntity;
|
|
4680
4797
|
this.localKey = localKey;
|
|
4681
|
-
this.loaded = false;
|
|
4682
|
-
this.items = [];
|
|
4683
|
-
this.added = /* @__PURE__ */ new Set();
|
|
4684
|
-
this.removed = /* @__PURE__ */ new Set();
|
|
4685
4798
|
hideInternal(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
4686
4799
|
this.hydrateFromCache();
|
|
4687
4800
|
}
|
|
4801
|
+
loaded = false;
|
|
4802
|
+
items = [];
|
|
4803
|
+
added = /* @__PURE__ */ new Set();
|
|
4804
|
+
removed = /* @__PURE__ */ new Set();
|
|
4688
4805
|
/**
|
|
4689
4806
|
* Loads the related entities if not already loaded.
|
|
4690
4807
|
* @returns Promise resolving to the array of child entities
|
|
@@ -4692,7 +4809,7 @@ var DefaultHasManyCollection = class {
|
|
|
4692
4809
|
async load() {
|
|
4693
4810
|
if (this.loaded) return this.items;
|
|
4694
4811
|
const map = await this.loader();
|
|
4695
|
-
const key =
|
|
4812
|
+
const key = toKey3(this.root[this.localKey]);
|
|
4696
4813
|
const rows = map.get(key) ?? [];
|
|
4697
4814
|
this.items = rows.map((row) => this.createEntity(row));
|
|
4698
4815
|
this.loaded = true;
|
|
@@ -4804,7 +4921,7 @@ var DefaultHasManyCollection = class {
|
|
|
4804
4921
|
};
|
|
4805
4922
|
|
|
4806
4923
|
// src/orm/relations/has-one.ts
|
|
4807
|
-
var
|
|
4924
|
+
var toKey4 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4808
4925
|
var hideInternal2 = (obj, keys) => {
|
|
4809
4926
|
for (const key of keys) {
|
|
4810
4927
|
Object.defineProperty(obj, key, {
|
|
@@ -4837,8 +4954,6 @@ var DefaultHasOneReference = class {
|
|
|
4837
4954
|
this.loader = loader;
|
|
4838
4955
|
this.createEntity = createEntity;
|
|
4839
4956
|
this.localKey = localKey;
|
|
4840
|
-
this.loaded = false;
|
|
4841
|
-
this.current = null;
|
|
4842
4957
|
hideInternal2(this, [
|
|
4843
4958
|
"ctx",
|
|
4844
4959
|
"meta",
|
|
@@ -4852,6 +4967,8 @@ var DefaultHasOneReference = class {
|
|
|
4852
4967
|
]);
|
|
4853
4968
|
this.populateFromHydrationCache();
|
|
4854
4969
|
}
|
|
4970
|
+
loaded = false;
|
|
4971
|
+
current = null;
|
|
4855
4972
|
async load() {
|
|
4856
4973
|
if (this.loaded) return this.current;
|
|
4857
4974
|
const map = await this.loader();
|
|
@@ -4860,7 +4977,7 @@ var DefaultHasOneReference = class {
|
|
|
4860
4977
|
this.loaded = true;
|
|
4861
4978
|
return this.current;
|
|
4862
4979
|
}
|
|
4863
|
-
const row = map.get(
|
|
4980
|
+
const row = map.get(toKey4(keyValue));
|
|
4864
4981
|
this.current = row ? this.createEntity(row) : null;
|
|
4865
4982
|
this.loaded = true;
|
|
4866
4983
|
return this.current;
|
|
@@ -4932,7 +5049,7 @@ var DefaultHasOneReference = class {
|
|
|
4932
5049
|
};
|
|
4933
5050
|
|
|
4934
5051
|
// src/orm/relations/belongs-to.ts
|
|
4935
|
-
var
|
|
5052
|
+
var toKey5 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4936
5053
|
var hideInternal3 = (obj, keys) => {
|
|
4937
5054
|
for (const key of keys) {
|
|
4938
5055
|
Object.defineProperty(obj, key, {
|
|
@@ -4965,11 +5082,11 @@ var DefaultBelongsToReference = class {
|
|
|
4965
5082
|
this.loader = loader;
|
|
4966
5083
|
this.createEntity = createEntity;
|
|
4967
5084
|
this.targetKey = targetKey;
|
|
4968
|
-
this.loaded = false;
|
|
4969
|
-
this.current = null;
|
|
4970
5085
|
hideInternal3(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "targetKey"]);
|
|
4971
5086
|
this.populateFromHydrationCache();
|
|
4972
5087
|
}
|
|
5088
|
+
loaded = false;
|
|
5089
|
+
current = null;
|
|
4973
5090
|
async load() {
|
|
4974
5091
|
if (this.loaded) return this.current;
|
|
4975
5092
|
const map = await this.loader();
|
|
@@ -4977,7 +5094,7 @@ var DefaultBelongsToReference = class {
|
|
|
4977
5094
|
if (fkValue === null || fkValue === void 0) {
|
|
4978
5095
|
this.current = null;
|
|
4979
5096
|
} else {
|
|
4980
|
-
const row = map.get(
|
|
5097
|
+
const row = map.get(toKey5(fkValue));
|
|
4981
5098
|
this.current = row ? this.createEntity(row) : null;
|
|
4982
5099
|
}
|
|
4983
5100
|
this.loaded = true;
|
|
@@ -5034,7 +5151,7 @@ var DefaultBelongsToReference = class {
|
|
|
5034
5151
|
};
|
|
5035
5152
|
|
|
5036
5153
|
// src/orm/relations/many-to-many.ts
|
|
5037
|
-
var
|
|
5154
|
+
var toKey6 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
5038
5155
|
var hideInternal4 = (obj, keys) => {
|
|
5039
5156
|
for (const key of keys) {
|
|
5040
5157
|
Object.defineProperty(obj, key, {
|
|
@@ -5067,11 +5184,11 @@ var DefaultManyToManyCollection = class {
|
|
|
5067
5184
|
this.loader = loader;
|
|
5068
5185
|
this.createEntity = createEntity;
|
|
5069
5186
|
this.localKey = localKey;
|
|
5070
|
-
this.loaded = false;
|
|
5071
|
-
this.items = [];
|
|
5072
5187
|
hideInternal4(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
5073
5188
|
this.hydrateFromCache();
|
|
5074
5189
|
}
|
|
5190
|
+
loaded = false;
|
|
5191
|
+
items = [];
|
|
5075
5192
|
/**
|
|
5076
5193
|
* Loads the collection items if not already loaded.
|
|
5077
5194
|
* @returns A promise that resolves to the array of target entities.
|
|
@@ -5079,7 +5196,7 @@ var DefaultManyToManyCollection = class {
|
|
|
5079
5196
|
async load() {
|
|
5080
5197
|
if (this.loaded) return this.items;
|
|
5081
5198
|
const map = await this.loader();
|
|
5082
|
-
const key =
|
|
5199
|
+
const key = toKey6(this.root[this.localKey]);
|
|
5083
5200
|
const rows = map.get(key) ?? [];
|
|
5084
5201
|
this.items = rows.map((row) => {
|
|
5085
5202
|
const entity = this.createEntity(row);
|
|
@@ -5161,15 +5278,15 @@ var DefaultManyToManyCollection = class {
|
|
|
5161
5278
|
*/
|
|
5162
5279
|
async syncByIds(ids) {
|
|
5163
5280
|
await this.load();
|
|
5164
|
-
const normalized = new Set(ids.map((id) =>
|
|
5165
|
-
const currentIds = new Set(this.items.map((item) =>
|
|
5281
|
+
const normalized = new Set(ids.map((id) => toKey6(id)));
|
|
5282
|
+
const currentIds = new Set(this.items.map((item) => toKey6(this.extractId(item))));
|
|
5166
5283
|
for (const id of normalized) {
|
|
5167
5284
|
if (!currentIds.has(id)) {
|
|
5168
5285
|
this.attach(id);
|
|
5169
5286
|
}
|
|
5170
5287
|
}
|
|
5171
5288
|
for (const item of [...this.items]) {
|
|
5172
|
-
const itemId =
|
|
5289
|
+
const itemId = toKey6(this.extractId(item));
|
|
5173
5290
|
if (!normalized.has(itemId)) {
|
|
5174
5291
|
this.detach(item);
|
|
5175
5292
|
}
|
|
@@ -5216,7 +5333,7 @@ var DefaultManyToManyCollection = class {
|
|
|
5216
5333
|
}
|
|
5217
5334
|
};
|
|
5218
5335
|
|
|
5219
|
-
// src/orm/lazy-batch.ts
|
|
5336
|
+
// src/orm/lazy-batch/shared.ts
|
|
5220
5337
|
var hasColumns = (columns) => Boolean(columns && columns.length > 0);
|
|
5221
5338
|
var buildColumnSelection = (table, columns, missingMsg) => {
|
|
5222
5339
|
return columns.reduce((acc, column) => {
|
|
@@ -5257,7 +5374,7 @@ var executeQuery = async (ctx, qb) => {
|
|
|
5257
5374
|
const results = await ctx.executor.executeSql(compiled.sql, compiled.params);
|
|
5258
5375
|
return rowsFromResults(results);
|
|
5259
5376
|
};
|
|
5260
|
-
var
|
|
5377
|
+
var toKey7 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
5261
5378
|
var collectKeysFromRoots = (roots, key) => {
|
|
5262
5379
|
const collected = /* @__PURE__ */ new Set();
|
|
5263
5380
|
for (const tracked of roots) {
|
|
@@ -5282,7 +5399,7 @@ var groupRowsByMany = (rows, keyColumn) => {
|
|
|
5282
5399
|
for (const row of rows) {
|
|
5283
5400
|
const value = row[keyColumn];
|
|
5284
5401
|
if (value === null || value === void 0) continue;
|
|
5285
|
-
const key =
|
|
5402
|
+
const key = toKey7(value);
|
|
5286
5403
|
const bucket = grouped.get(key) ?? [];
|
|
5287
5404
|
bucket.push(row);
|
|
5288
5405
|
grouped.set(key, bucket);
|
|
@@ -5294,13 +5411,15 @@ var groupRowsByUnique = (rows, keyColumn) => {
|
|
|
5294
5411
|
for (const row of rows) {
|
|
5295
5412
|
const value = row[keyColumn];
|
|
5296
5413
|
if (value === null || value === void 0) continue;
|
|
5297
|
-
const key =
|
|
5414
|
+
const key = toKey7(value);
|
|
5298
5415
|
if (!lookup.has(key)) {
|
|
5299
5416
|
lookup.set(key, row);
|
|
5300
5417
|
}
|
|
5301
5418
|
}
|
|
5302
5419
|
return lookup;
|
|
5303
5420
|
};
|
|
5421
|
+
|
|
5422
|
+
// src/orm/lazy-batch/has-many.ts
|
|
5304
5423
|
var loadHasManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5305
5424
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5306
5425
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
@@ -5333,6 +5452,8 @@ var loadHasManyRelation = async (ctx, rootTable, relationName, relation, options
|
|
|
5333
5452
|
}
|
|
5334
5453
|
return filtered;
|
|
5335
5454
|
};
|
|
5455
|
+
|
|
5456
|
+
// src/orm/lazy-batch/has-one.ts
|
|
5336
5457
|
var loadHasOneRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5337
5458
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5338
5459
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
@@ -5365,6 +5486,8 @@ var loadHasOneRelation = async (ctx, rootTable, relationName, relation, options)
|
|
|
5365
5486
|
}
|
|
5366
5487
|
return filtered;
|
|
5367
5488
|
};
|
|
5489
|
+
|
|
5490
|
+
// src/orm/lazy-batch/belongs-to.ts
|
|
5368
5491
|
var loadBelongsToRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5369
5492
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5370
5493
|
const getForeignKeys = () => collectKeysFromRoots(roots, relation.foreignKey);
|
|
@@ -5433,6 +5556,8 @@ var loadBelongsToRelation = async (ctx, rootTable, relationName, relation, optio
|
|
|
5433
5556
|
}
|
|
5434
5557
|
return filtered;
|
|
5435
5558
|
};
|
|
5559
|
+
|
|
5560
|
+
// src/orm/lazy-batch/belongs-to-many.ts
|
|
5436
5561
|
var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5437
5562
|
const rootKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5438
5563
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
@@ -5471,12 +5596,12 @@ var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, o
|
|
|
5471
5596
|
if (rootValue === null || rootValue === void 0 || targetValue === null || targetValue === void 0) {
|
|
5472
5597
|
continue;
|
|
5473
5598
|
}
|
|
5474
|
-
const bucket = rootLookup.get(
|
|
5599
|
+
const bucket = rootLookup.get(toKey7(rootValue)) ?? [];
|
|
5475
5600
|
bucket.push({
|
|
5476
5601
|
targetId: targetValue,
|
|
5477
5602
|
pivot: pivotVisibleColumns.size ? filterRow(pivot, pivotVisibleColumns) : {}
|
|
5478
5603
|
});
|
|
5479
|
-
rootLookup.set(
|
|
5604
|
+
rootLookup.set(toKey7(rootValue), bucket);
|
|
5480
5605
|
targetIds.add(targetValue);
|
|
5481
5606
|
}
|
|
5482
5607
|
if (!targetIds.size) {
|
|
@@ -5495,14 +5620,21 @@ var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, o
|
|
|
5495
5620
|
targetSelectedColumns,
|
|
5496
5621
|
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5497
5622
|
);
|
|
5498
|
-
const targetRows = await fetchRowsForKeys(
|
|
5623
|
+
const targetRows = await fetchRowsForKeys(
|
|
5624
|
+
ctx,
|
|
5625
|
+
relation.target,
|
|
5626
|
+
targetPkColumn,
|
|
5627
|
+
targetIds,
|
|
5628
|
+
targetSelection,
|
|
5629
|
+
options?.filter
|
|
5630
|
+
);
|
|
5499
5631
|
const targetMap = groupRowsByUnique(targetRows, targetKey);
|
|
5500
5632
|
const targetVisibleColumns = new Set(targetSelectedColumns);
|
|
5501
5633
|
const result = /* @__PURE__ */ new Map();
|
|
5502
5634
|
for (const [rootId, entries] of rootLookup.entries()) {
|
|
5503
5635
|
const bucket = [];
|
|
5504
5636
|
for (const entry of entries) {
|
|
5505
|
-
const targetRow = targetMap.get(
|
|
5637
|
+
const targetRow = targetMap.get(toKey7(entry.targetId));
|
|
5506
5638
|
if (!targetRow) continue;
|
|
5507
5639
|
bucket.push({
|
|
5508
5640
|
...targetRequestedColumns ? filterRow(targetRow, targetVisibleColumns) : targetRow,
|
|
@@ -5514,7 +5646,7 @@ var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, o
|
|
|
5514
5646
|
return result;
|
|
5515
5647
|
};
|
|
5516
5648
|
|
|
5517
|
-
// src/orm/entity.ts
|
|
5649
|
+
// src/orm/entity-relation-cache.ts
|
|
5518
5650
|
var relationLoaderCache = (meta, relationName, factory) => {
|
|
5519
5651
|
if (meta.relationCache.has(relationName)) {
|
|
5520
5652
|
return meta.relationCache.get(relationName);
|
|
@@ -5535,118 +5667,16 @@ var relationLoaderCache = (meta, relationName, factory) => {
|
|
|
5535
5667
|
}
|
|
5536
5668
|
return promise;
|
|
5537
5669
|
};
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
relationCache: /* @__PURE__ */ new Map(),
|
|
5546
|
-
relationHydration: /* @__PURE__ */ new Map(),
|
|
5547
|
-
relationWrappers: /* @__PURE__ */ new Map()
|
|
5548
|
-
};
|
|
5549
|
-
Object.defineProperty(target, ENTITY_META, {
|
|
5550
|
-
value: meta,
|
|
5551
|
-
enumerable: false,
|
|
5552
|
-
writable: false
|
|
5553
|
-
});
|
|
5554
|
-
const handler = {
|
|
5555
|
-
get(targetObj, prop, receiver) {
|
|
5556
|
-
if (prop === ENTITY_META) {
|
|
5557
|
-
return meta;
|
|
5558
|
-
}
|
|
5559
|
-
if (prop === "$load") {
|
|
5560
|
-
return async (relationName) => {
|
|
5561
|
-
const wrapper = getRelationWrapper(meta, relationName, receiver);
|
|
5562
|
-
if (wrapper && typeof wrapper.load === "function") {
|
|
5563
|
-
return wrapper.load();
|
|
5564
|
-
}
|
|
5565
|
-
return void 0;
|
|
5566
|
-
};
|
|
5670
|
+
|
|
5671
|
+
// src/orm/entity-relations.ts
|
|
5672
|
+
var proxifyRelationWrapper = (wrapper) => {
|
|
5673
|
+
return new Proxy(wrapper, {
|
|
5674
|
+
get(target, prop, receiver) {
|
|
5675
|
+
if (typeof prop === "symbol") {
|
|
5676
|
+
return Reflect.get(target, prop, receiver);
|
|
5567
5677
|
}
|
|
5568
|
-
if (
|
|
5569
|
-
return
|
|
5570
|
-
}
|
|
5571
|
-
return Reflect.get(targetObj, prop, receiver);
|
|
5572
|
-
},
|
|
5573
|
-
set(targetObj, prop, value, receiver) {
|
|
5574
|
-
const result = Reflect.set(targetObj, prop, value, receiver);
|
|
5575
|
-
if (typeof prop === "string" && table.columns[prop]) {
|
|
5576
|
-
ctx.markDirty(receiver);
|
|
5577
|
-
}
|
|
5578
|
-
return result;
|
|
5579
|
-
}
|
|
5580
|
-
};
|
|
5581
|
-
const proxy = new Proxy(target, handler);
|
|
5582
|
-
populateHydrationCache(proxy, row, meta);
|
|
5583
|
-
return proxy;
|
|
5584
|
-
};
|
|
5585
|
-
var createEntityFromRow = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
5586
|
-
const pkName = findPrimaryKey(table);
|
|
5587
|
-
const pkValue = row[pkName];
|
|
5588
|
-
if (pkValue !== void 0 && pkValue !== null) {
|
|
5589
|
-
const tracked = ctx.getEntity(table, pkValue);
|
|
5590
|
-
if (tracked) return tracked;
|
|
5591
|
-
}
|
|
5592
|
-
const entity = createEntityProxy(ctx, table, row, lazyRelations, lazyRelationOptions);
|
|
5593
|
-
if (pkValue !== void 0 && pkValue !== null) {
|
|
5594
|
-
ctx.trackManaged(table, pkValue, entity);
|
|
5595
|
-
} else {
|
|
5596
|
-
ctx.trackNew(table, entity);
|
|
5597
|
-
}
|
|
5598
|
-
return entity;
|
|
5599
|
-
};
|
|
5600
|
-
var toKey7 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
5601
|
-
var populateHydrationCache = (entity, row, meta) => {
|
|
5602
|
-
for (const relationName of Object.keys(meta.table.relations)) {
|
|
5603
|
-
const relation = meta.table.relations[relationName];
|
|
5604
|
-
const data = row[relationName];
|
|
5605
|
-
if (relation.type === RelationKinds.HasOne) {
|
|
5606
|
-
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
5607
|
-
const rootValue = entity[localKey];
|
|
5608
|
-
if (rootValue === void 0 || rootValue === null) continue;
|
|
5609
|
-
if (!data || typeof data !== "object") continue;
|
|
5610
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5611
|
-
cache.set(toKey7(rootValue), data);
|
|
5612
|
-
meta.relationHydration.set(relationName, cache);
|
|
5613
|
-
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5614
|
-
continue;
|
|
5615
|
-
}
|
|
5616
|
-
if (!Array.isArray(data)) continue;
|
|
5617
|
-
if (relation.type === RelationKinds.HasMany || relation.type === RelationKinds.BelongsToMany) {
|
|
5618
|
-
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
5619
|
-
const rootValue = entity[localKey];
|
|
5620
|
-
if (rootValue === void 0 || rootValue === null) continue;
|
|
5621
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5622
|
-
cache.set(toKey7(rootValue), data);
|
|
5623
|
-
meta.relationHydration.set(relationName, cache);
|
|
5624
|
-
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5625
|
-
continue;
|
|
5626
|
-
}
|
|
5627
|
-
if (relation.type === RelationKinds.BelongsTo) {
|
|
5628
|
-
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
5629
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5630
|
-
for (const item of data) {
|
|
5631
|
-
const pkValue = item[targetKey];
|
|
5632
|
-
if (pkValue === void 0 || pkValue === null) continue;
|
|
5633
|
-
cache.set(toKey7(pkValue), item);
|
|
5634
|
-
}
|
|
5635
|
-
if (cache.size) {
|
|
5636
|
-
meta.relationHydration.set(relationName, cache);
|
|
5637
|
-
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5638
|
-
}
|
|
5639
|
-
}
|
|
5640
|
-
}
|
|
5641
|
-
};
|
|
5642
|
-
var proxifyRelationWrapper = (wrapper) => {
|
|
5643
|
-
return new Proxy(wrapper, {
|
|
5644
|
-
get(target, prop, receiver) {
|
|
5645
|
-
if (typeof prop === "symbol") {
|
|
5646
|
-
return Reflect.get(target, prop, receiver);
|
|
5647
|
-
}
|
|
5648
|
-
if (prop in target) {
|
|
5649
|
-
return Reflect.get(target, prop, receiver);
|
|
5678
|
+
if (prop in target) {
|
|
5679
|
+
return Reflect.get(target, prop, receiver);
|
|
5650
5680
|
}
|
|
5651
5681
|
const getItems = target.getItems;
|
|
5652
5682
|
if (typeof getItems === "function") {
|
|
@@ -5691,98 +5721,93 @@ var proxifyRelationWrapper = (wrapper) => {
|
|
|
5691
5721
|
}
|
|
5692
5722
|
});
|
|
5693
5723
|
};
|
|
5694
|
-
var getRelationWrapper = (meta, relationName, owner) => {
|
|
5695
|
-
|
|
5696
|
-
|
|
5724
|
+
var getRelationWrapper = (meta, relationName, owner, createEntity) => {
|
|
5725
|
+
const relationKey = relationName;
|
|
5726
|
+
if (meta.relationWrappers.has(relationKey)) {
|
|
5727
|
+
return meta.relationWrappers.get(relationKey);
|
|
5697
5728
|
}
|
|
5698
|
-
const relation = meta.table.relations[
|
|
5729
|
+
const relation = meta.table.relations[relationKey];
|
|
5699
5730
|
if (!relation) return void 0;
|
|
5700
|
-
const wrapper = instantiateWrapper(meta,
|
|
5731
|
+
const wrapper = instantiateWrapper(meta, relationKey, relation, owner, createEntity);
|
|
5701
5732
|
if (!wrapper) return void 0;
|
|
5702
5733
|
const proxied = proxifyRelationWrapper(wrapper);
|
|
5703
|
-
meta.relationWrappers.set(
|
|
5734
|
+
meta.relationWrappers.set(relationKey, proxied);
|
|
5704
5735
|
return proxied;
|
|
5705
5736
|
};
|
|
5706
|
-
var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
5737
|
+
var instantiateWrapper = (meta, relationName, relation, owner, createEntity) => {
|
|
5738
|
+
const metaBase = meta;
|
|
5707
5739
|
const lazyOptions = meta.lazyRelationOptions.get(relationName);
|
|
5740
|
+
const loadCached = (factory) => relationLoaderCache(metaBase, relationName, factory);
|
|
5708
5741
|
switch (relation.type) {
|
|
5709
5742
|
case RelationKinds.HasOne: {
|
|
5710
5743
|
const hasOne2 = relation;
|
|
5711
5744
|
const localKey = hasOne2.localKey || findPrimaryKey(meta.table);
|
|
5712
|
-
const loader = () =>
|
|
5713
|
-
meta,
|
|
5714
|
-
relationName,
|
|
5745
|
+
const loader = () => loadCached(
|
|
5715
5746
|
() => loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne2, lazyOptions)
|
|
5716
5747
|
);
|
|
5717
5748
|
return new DefaultHasOneReference(
|
|
5718
5749
|
meta.ctx,
|
|
5719
|
-
|
|
5750
|
+
metaBase,
|
|
5720
5751
|
owner,
|
|
5721
5752
|
relationName,
|
|
5722
5753
|
hasOne2,
|
|
5723
5754
|
meta.table,
|
|
5724
5755
|
loader,
|
|
5725
|
-
(row) =>
|
|
5756
|
+
(row) => createEntity(hasOne2.target, row),
|
|
5726
5757
|
localKey
|
|
5727
5758
|
);
|
|
5728
5759
|
}
|
|
5729
5760
|
case RelationKinds.HasMany: {
|
|
5730
5761
|
const hasMany2 = relation;
|
|
5731
5762
|
const localKey = hasMany2.localKey || findPrimaryKey(meta.table);
|
|
5732
|
-
const loader = () =>
|
|
5733
|
-
meta,
|
|
5734
|
-
relationName,
|
|
5763
|
+
const loader = () => loadCached(
|
|
5735
5764
|
() => loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany2, lazyOptions)
|
|
5736
5765
|
);
|
|
5737
5766
|
return new DefaultHasManyCollection(
|
|
5738
5767
|
meta.ctx,
|
|
5739
|
-
|
|
5768
|
+
metaBase,
|
|
5740
5769
|
owner,
|
|
5741
5770
|
relationName,
|
|
5742
5771
|
hasMany2,
|
|
5743
5772
|
meta.table,
|
|
5744
5773
|
loader,
|
|
5745
|
-
(row) =>
|
|
5774
|
+
(row) => createEntity(relation.target, row),
|
|
5746
5775
|
localKey
|
|
5747
5776
|
);
|
|
5748
5777
|
}
|
|
5749
5778
|
case RelationKinds.BelongsTo: {
|
|
5750
5779
|
const belongsTo2 = relation;
|
|
5751
5780
|
const targetKey = belongsTo2.localKey || findPrimaryKey(belongsTo2.target);
|
|
5752
|
-
const loader = () =>
|
|
5753
|
-
meta,
|
|
5754
|
-
relationName,
|
|
5781
|
+
const loader = () => loadCached(
|
|
5755
5782
|
() => loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo2, lazyOptions)
|
|
5756
5783
|
);
|
|
5757
5784
|
return new DefaultBelongsToReference(
|
|
5758
5785
|
meta.ctx,
|
|
5759
|
-
|
|
5786
|
+
metaBase,
|
|
5760
5787
|
owner,
|
|
5761
5788
|
relationName,
|
|
5762
5789
|
belongsTo2,
|
|
5763
5790
|
meta.table,
|
|
5764
5791
|
loader,
|
|
5765
|
-
(row) =>
|
|
5792
|
+
(row) => createEntity(relation.target, row),
|
|
5766
5793
|
targetKey
|
|
5767
5794
|
);
|
|
5768
5795
|
}
|
|
5769
5796
|
case RelationKinds.BelongsToMany: {
|
|
5770
5797
|
const many = relation;
|
|
5771
5798
|
const localKey = many.localKey || findPrimaryKey(meta.table);
|
|
5772
|
-
const loader = () =>
|
|
5773
|
-
meta,
|
|
5774
|
-
relationName,
|
|
5799
|
+
const loader = () => loadCached(
|
|
5775
5800
|
() => loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many, lazyOptions)
|
|
5776
5801
|
);
|
|
5777
5802
|
return new DefaultManyToManyCollection(
|
|
5778
5803
|
meta.ctx,
|
|
5779
|
-
|
|
5804
|
+
metaBase,
|
|
5780
5805
|
owner,
|
|
5781
5806
|
relationName,
|
|
5782
5807
|
many,
|
|
5783
5808
|
meta.table,
|
|
5784
5809
|
loader,
|
|
5785
|
-
(row) =>
|
|
5810
|
+
(row) => createEntity(relation.target, row),
|
|
5786
5811
|
localKey
|
|
5787
5812
|
);
|
|
5788
5813
|
}
|
|
@@ -5791,103 +5816,570 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
5791
5816
|
}
|
|
5792
5817
|
};
|
|
5793
5818
|
|
|
5794
|
-
// src/orm/
|
|
5795
|
-
var
|
|
5796
|
-
const
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5819
|
+
// src/orm/entity.ts
|
|
5820
|
+
var createEntityProxy = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
5821
|
+
const target = { ...row };
|
|
5822
|
+
const meta = {
|
|
5823
|
+
ctx,
|
|
5824
|
+
table,
|
|
5825
|
+
lazyRelations: [...lazyRelations],
|
|
5826
|
+
lazyRelationOptions: new Map(lazyRelationOptions),
|
|
5827
|
+
relationCache: /* @__PURE__ */ new Map(),
|
|
5828
|
+
relationHydration: /* @__PURE__ */ new Map(),
|
|
5829
|
+
relationWrappers: /* @__PURE__ */ new Map()
|
|
5830
|
+
};
|
|
5831
|
+
const createRelationEntity = (relationTable, relationRow) => createEntityFromRow(meta.ctx, relationTable, relationRow);
|
|
5832
|
+
Object.defineProperty(target, ENTITY_META, {
|
|
5833
|
+
value: meta,
|
|
5834
|
+
enumerable: false,
|
|
5835
|
+
writable: false
|
|
5836
|
+
});
|
|
5837
|
+
const handler = {
|
|
5838
|
+
get(targetObj, prop, receiver) {
|
|
5839
|
+
if (prop === ENTITY_META) {
|
|
5840
|
+
return meta;
|
|
5841
|
+
}
|
|
5842
|
+
if (prop === "$load") {
|
|
5843
|
+
return async (relationName) => {
|
|
5844
|
+
const wrapper = getRelationWrapper(meta, relationName, receiver, createRelationEntity);
|
|
5845
|
+
if (wrapper && typeof wrapper.load === "function") {
|
|
5846
|
+
return wrapper.load();
|
|
5847
|
+
}
|
|
5848
|
+
return void 0;
|
|
5849
|
+
};
|
|
5850
|
+
}
|
|
5851
|
+
if (typeof prop === "string" && table.relations[prop]) {
|
|
5852
|
+
return getRelationWrapper(meta, prop, receiver, createRelationEntity);
|
|
5853
|
+
}
|
|
5854
|
+
return Reflect.get(targetObj, prop, receiver);
|
|
5855
|
+
},
|
|
5856
|
+
set(targetObj, prop, value, receiver) {
|
|
5857
|
+
const result = Reflect.set(targetObj, prop, value, receiver);
|
|
5858
|
+
if (typeof prop === "string" && table.columns[prop]) {
|
|
5859
|
+
ctx.markDirty(receiver);
|
|
5860
|
+
}
|
|
5861
|
+
return result;
|
|
5862
|
+
}
|
|
5863
|
+
};
|
|
5864
|
+
const proxy = new Proxy(target, handler);
|
|
5865
|
+
populateHydrationCache(proxy, row, meta);
|
|
5866
|
+
return proxy;
|
|
5867
|
+
};
|
|
5868
|
+
var createEntityFromRow = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
5869
|
+
const pkName = findPrimaryKey(table);
|
|
5870
|
+
const pkValue = row[pkName];
|
|
5871
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
5872
|
+
const tracked = ctx.getEntity(table, pkValue);
|
|
5873
|
+
if (tracked) return tracked;
|
|
5874
|
+
}
|
|
5875
|
+
const entity = createEntityProxy(ctx, table, row, lazyRelations, lazyRelationOptions);
|
|
5876
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
5877
|
+
ctx.trackManaged(table, pkValue, entity);
|
|
5878
|
+
} else {
|
|
5879
|
+
ctx.trackNew(table, entity);
|
|
5880
|
+
}
|
|
5881
|
+
return entity;
|
|
5882
|
+
};
|
|
5883
|
+
|
|
5884
|
+
// src/orm/execute.ts
|
|
5885
|
+
var flattenResults = (results) => {
|
|
5886
|
+
const rows = [];
|
|
5887
|
+
for (const result of results) {
|
|
5888
|
+
const { columns, values } = result;
|
|
5889
|
+
for (const valueRow of values) {
|
|
5890
|
+
const row = {};
|
|
5891
|
+
columns.forEach((column, idx) => {
|
|
5892
|
+
row[column] = valueRow[idx];
|
|
5893
|
+
});
|
|
5894
|
+
rows.push(row);
|
|
5895
|
+
}
|
|
5896
|
+
}
|
|
5897
|
+
return rows;
|
|
5898
|
+
};
|
|
5899
|
+
var executeWithContexts = async (execCtx, entityCtx, qb) => {
|
|
5900
|
+
const ast = qb.getAST();
|
|
5901
|
+
const compiled = execCtx.dialect.compileSelect(ast);
|
|
5902
|
+
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
5903
|
+
const rows = flattenResults(executed);
|
|
5904
|
+
const lazyRelations = qb.getLazyRelations();
|
|
5905
|
+
const lazyRelationOptions = qb.getLazyRelationOptions();
|
|
5906
|
+
if (ast.setOps && ast.setOps.length > 0) {
|
|
5907
|
+
const proxies = rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
5908
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5909
|
+
return proxies;
|
|
5910
|
+
}
|
|
5911
|
+
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
5912
|
+
const entities = hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
5913
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5914
|
+
return entities;
|
|
5915
|
+
};
|
|
5916
|
+
async function executeHydrated(session, qb) {
|
|
5917
|
+
return executeWithContexts(session.getExecutionContext(), session, qb);
|
|
5918
|
+
}
|
|
5919
|
+
async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
|
|
5920
|
+
const entityCtx = hydCtx.entityContext;
|
|
5921
|
+
if (!entityCtx) {
|
|
5922
|
+
throw new Error("Hydration context is missing an EntityContext");
|
|
5923
|
+
}
|
|
5924
|
+
return executeWithContexts(execCtx, entityCtx, qb);
|
|
5925
|
+
}
|
|
5926
|
+
var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOptions) => {
|
|
5927
|
+
if (!lazyRelations.length) return;
|
|
5928
|
+
const tracked = ctx.getEntitiesForTable(table);
|
|
5929
|
+
if (!tracked.length) return;
|
|
5930
|
+
const meta = getEntityMeta(tracked[0].entity);
|
|
5931
|
+
if (!meta) return;
|
|
5932
|
+
for (const relationName of lazyRelations) {
|
|
5933
|
+
const relation = table.relations[relationName];
|
|
5934
|
+
if (!relation) continue;
|
|
5935
|
+
const key = relationName;
|
|
5936
|
+
const options = lazyRelationOptions.get(key);
|
|
5937
|
+
if (!options) {
|
|
5938
|
+
continue;
|
|
5939
|
+
}
|
|
5940
|
+
switch (relation.type) {
|
|
5941
|
+
case RelationKinds.HasOne:
|
|
5942
|
+
await relationLoaderCache(
|
|
5943
|
+
meta,
|
|
5944
|
+
key,
|
|
5945
|
+
() => loadHasOneRelation(ctx, table, key, relation, options)
|
|
5946
|
+
);
|
|
5947
|
+
break;
|
|
5948
|
+
case RelationKinds.HasMany:
|
|
5949
|
+
await relationLoaderCache(
|
|
5950
|
+
meta,
|
|
5951
|
+
key,
|
|
5952
|
+
() => loadHasManyRelation(ctx, table, key, relation, options)
|
|
5953
|
+
);
|
|
5954
|
+
break;
|
|
5955
|
+
case RelationKinds.BelongsTo:
|
|
5956
|
+
await relationLoaderCache(
|
|
5957
|
+
meta,
|
|
5958
|
+
key,
|
|
5959
|
+
() => loadBelongsToRelation(ctx, table, key, relation, options)
|
|
5960
|
+
);
|
|
5961
|
+
break;
|
|
5962
|
+
case RelationKinds.BelongsToMany:
|
|
5963
|
+
await relationLoaderCache(
|
|
5964
|
+
meta,
|
|
5965
|
+
key,
|
|
5966
|
+
() => loadBelongsToManyRelation(ctx, table, key, relation, options)
|
|
5967
|
+
);
|
|
5968
|
+
break;
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
};
|
|
5972
|
+
|
|
5973
|
+
// src/query-builder/query-resolution.ts
|
|
5974
|
+
function resolveSelectQuery(query) {
|
|
5975
|
+
const candidate = query;
|
|
5976
|
+
return typeof candidate.getAST === "function" && candidate.getAST ? candidate.getAST() : query;
|
|
5977
|
+
}
|
|
5978
|
+
|
|
5979
|
+
// src/query-builder/select/select-operations.ts
|
|
5980
|
+
function applyOrderBy(context, predicateFacet, term, directionOrOptions) {
|
|
5981
|
+
const options = typeof directionOrOptions === "string" ? { direction: directionOrOptions } : directionOrOptions;
|
|
5982
|
+
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
5983
|
+
return predicateFacet.orderBy(context, term, dir, options.nulls, options.collation);
|
|
5984
|
+
}
|
|
5985
|
+
async function executeCount(context, env, session) {
|
|
5986
|
+
const unpagedAst = {
|
|
5987
|
+
...context.state.ast,
|
|
5988
|
+
orderBy: void 0,
|
|
5989
|
+
limit: void 0,
|
|
5990
|
+
offset: void 0
|
|
5991
|
+
};
|
|
5992
|
+
const nextState = new SelectQueryState(env.table, unpagedAst);
|
|
5993
|
+
const nextContext = {
|
|
5994
|
+
...context,
|
|
5995
|
+
state: nextState
|
|
5996
|
+
};
|
|
5997
|
+
const subAst = nextContext.hydration.applyToAst(nextState.ast);
|
|
5998
|
+
const countQuery = {
|
|
5999
|
+
type: "SelectQuery",
|
|
6000
|
+
from: derivedTable(subAst, "__metal_count"),
|
|
6001
|
+
columns: [{ type: "Function", name: "COUNT", args: [], alias: "total" }],
|
|
6002
|
+
joins: []
|
|
6003
|
+
};
|
|
6004
|
+
const execCtx = session.getExecutionContext();
|
|
6005
|
+
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
6006
|
+
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
6007
|
+
const value = results[0]?.values?.[0]?.[0];
|
|
6008
|
+
if (typeof value === "number") return value;
|
|
6009
|
+
if (typeof value === "bigint") return Number(value);
|
|
6010
|
+
if (typeof value === "string") return Number(value);
|
|
6011
|
+
return value === null || value === void 0 ? 0 : Number(value);
|
|
6012
|
+
}
|
|
6013
|
+
async function executePagedQuery(builder, session, options, countCallback) {
|
|
6014
|
+
const { page, pageSize } = options;
|
|
6015
|
+
if (!Number.isInteger(page) || page < 1) {
|
|
6016
|
+
throw new Error("executePaged: page must be an integer >= 1");
|
|
6017
|
+
}
|
|
6018
|
+
if (!Number.isInteger(pageSize) || pageSize < 1) {
|
|
6019
|
+
throw new Error("executePaged: pageSize must be an integer >= 1");
|
|
6020
|
+
}
|
|
6021
|
+
const offset = (page - 1) * pageSize;
|
|
6022
|
+
const [items, totalItems] = await Promise.all([
|
|
6023
|
+
builder.limit(pageSize).offset(offset).execute(session),
|
|
6024
|
+
countCallback(session)
|
|
6025
|
+
]);
|
|
6026
|
+
return { items, totalItems };
|
|
6027
|
+
}
|
|
6028
|
+
function buildWhereHasPredicate(env, context, relationFacet, createChildBuilder, relationName, callbackOrOptions, maybeOptions, negate = false) {
|
|
6029
|
+
const relation = env.table.relations[relationName];
|
|
6030
|
+
if (!relation) {
|
|
6031
|
+
throw new Error(`Relation '${relationName}' not found on table '${env.table.name}'`);
|
|
6032
|
+
}
|
|
6033
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
6034
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
6035
|
+
let subQb = createChildBuilder(relation.target);
|
|
6036
|
+
if (callback) {
|
|
6037
|
+
subQb = callback(subQb);
|
|
6038
|
+
}
|
|
6039
|
+
const subAst = subQb.getAST();
|
|
6040
|
+
const finalSubAst = relationFacet.applyRelationCorrelation(
|
|
6041
|
+
context,
|
|
6042
|
+
relationName,
|
|
6043
|
+
subAst,
|
|
6044
|
+
options?.correlate
|
|
6045
|
+
);
|
|
6046
|
+
return negate ? notExists(finalSubAst) : exists(finalSubAst);
|
|
6047
|
+
}
|
|
6048
|
+
|
|
6049
|
+
// src/query-builder/select/from-facet.ts
|
|
6050
|
+
var SelectFromFacet = class {
|
|
6051
|
+
/**
|
|
6052
|
+
* Creates a new SelectFromFacet instance
|
|
6053
|
+
* @param env - Query builder environment
|
|
6054
|
+
* @param createAstService - Function to create AST service
|
|
6055
|
+
*/
|
|
6056
|
+
constructor(env, createAstService) {
|
|
6057
|
+
this.env = env;
|
|
6058
|
+
this.createAstService = createAstService;
|
|
6059
|
+
}
|
|
6060
|
+
/**
|
|
6061
|
+
* Applies an alias to the FROM table
|
|
6062
|
+
* @param context - Current query context
|
|
6063
|
+
* @param alias - Alias to apply
|
|
6064
|
+
* @returns Updated query context with aliased FROM
|
|
6065
|
+
*/
|
|
6066
|
+
as(context, alias) {
|
|
6067
|
+
const from = context.state.ast.from;
|
|
6068
|
+
if (from.type !== "Table") {
|
|
6069
|
+
throw new Error("Cannot alias non-table FROM sources");
|
|
6070
|
+
}
|
|
6071
|
+
const nextFrom = { ...from, alias };
|
|
6072
|
+
const astService = this.createAstService(context.state);
|
|
6073
|
+
const nextState = astService.withFrom(nextFrom);
|
|
6074
|
+
return { state: nextState, hydration: context.hydration };
|
|
6075
|
+
}
|
|
6076
|
+
/**
|
|
6077
|
+
* Sets the FROM clause to a subquery
|
|
6078
|
+
* @param context - Current query context
|
|
6079
|
+
* @param subAst - Subquery AST
|
|
6080
|
+
* @param alias - Alias for the subquery
|
|
6081
|
+
* @param columnAliases - Optional column aliases
|
|
6082
|
+
* @returns Updated query context with subquery FROM
|
|
6083
|
+
*/
|
|
6084
|
+
fromSubquery(context, subAst, alias, columnAliases) {
|
|
6085
|
+
const fromNode = derivedTable(subAst, alias, columnAliases);
|
|
6086
|
+
const astService = this.createAstService(context.state);
|
|
6087
|
+
const nextState = astService.withFrom(fromNode);
|
|
6088
|
+
return { state: nextState, hydration: context.hydration };
|
|
6089
|
+
}
|
|
6090
|
+
/**
|
|
6091
|
+
* Sets the FROM clause to a function table
|
|
6092
|
+
* @param context - Current query context
|
|
6093
|
+
* @param name - Function name
|
|
6094
|
+
* @param args - Function arguments
|
|
6095
|
+
* @param alias - Optional alias for the function table
|
|
6096
|
+
* @param options - Optional function table options
|
|
6097
|
+
* @returns Updated query context with function table FROM
|
|
6098
|
+
*/
|
|
6099
|
+
fromFunctionTable(context, name, args, alias, options) {
|
|
6100
|
+
const functionTable = fnTable(name, args, alias, options);
|
|
6101
|
+
const astService = this.createAstService(context.state);
|
|
6102
|
+
const nextState = astService.withFrom(functionTable);
|
|
6103
|
+
return { state: nextState, hydration: context.hydration };
|
|
6104
|
+
}
|
|
6105
|
+
};
|
|
6106
|
+
|
|
6107
|
+
// src/query-builder/select/join-facet.ts
|
|
6108
|
+
var SelectJoinFacet = class {
|
|
6109
|
+
constructor(env, createAstService) {
|
|
6110
|
+
this.env = env;
|
|
6111
|
+
this.createAstService = createAstService;
|
|
6112
|
+
}
|
|
6113
|
+
applyJoin(context, table, condition, kind) {
|
|
6114
|
+
const joinNode = createJoinNode(kind, { type: "Table", name: table.name, schema: table.schema }, condition);
|
|
6115
|
+
const astService = this.createAstService(context.state);
|
|
6116
|
+
const nextState = astService.withJoin(joinNode);
|
|
6117
|
+
return { state: nextState, hydration: context.hydration };
|
|
6118
|
+
}
|
|
6119
|
+
joinSubquery(context, subAst, alias, condition, joinKind, columnAliases) {
|
|
6120
|
+
const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
|
|
6121
|
+
const astService = this.createAstService(context.state);
|
|
6122
|
+
const nextState = astService.withJoin(joinNode);
|
|
6123
|
+
return { state: nextState, hydration: context.hydration };
|
|
6124
|
+
}
|
|
6125
|
+
joinFunctionTable(context, name, args, alias, condition, joinKind, options) {
|
|
6126
|
+
const functionTable = fnTable(name, args, alias, options);
|
|
6127
|
+
const joinNode = createJoinNode(joinKind, functionTable, condition);
|
|
6128
|
+
const astService = this.createAstService(context.state);
|
|
6129
|
+
const nextState = astService.withJoin(joinNode);
|
|
6130
|
+
return { state: nextState, hydration: context.hydration };
|
|
6131
|
+
}
|
|
6132
|
+
};
|
|
6133
|
+
|
|
6134
|
+
// src/query-builder/select/projection-facet.ts
|
|
6135
|
+
var SelectProjectionFacet = class {
|
|
6136
|
+
/**
|
|
6137
|
+
* Creates a new SelectProjectionFacet instance
|
|
6138
|
+
* @param columnSelector - Column selector dependency
|
|
6139
|
+
*/
|
|
6140
|
+
constructor(columnSelector) {
|
|
6141
|
+
this.columnSelector = columnSelector;
|
|
6142
|
+
}
|
|
6143
|
+
/**
|
|
6144
|
+
* Selects columns for the query
|
|
6145
|
+
* @param context - Current query context
|
|
6146
|
+
* @param columns - Columns to select
|
|
6147
|
+
* @returns Updated query context with selected columns
|
|
6148
|
+
*/
|
|
6149
|
+
select(context, columns) {
|
|
6150
|
+
return this.columnSelector.select(context, columns);
|
|
6151
|
+
}
|
|
6152
|
+
/**
|
|
6153
|
+
* Selects raw column expressions
|
|
6154
|
+
* @param context - Current query context
|
|
6155
|
+
* @param cols - Raw column expressions
|
|
6156
|
+
* @returns Updated query context with raw column selections
|
|
6157
|
+
*/
|
|
6158
|
+
selectRaw(context, cols) {
|
|
6159
|
+
return this.columnSelector.selectRaw(context, cols);
|
|
6160
|
+
}
|
|
6161
|
+
/**
|
|
6162
|
+
* Selects a subquery as a column
|
|
6163
|
+
* @param context - Current query context
|
|
6164
|
+
* @param alias - Alias for the subquery
|
|
6165
|
+
* @param query - Subquery to select
|
|
6166
|
+
* @returns Updated query context with subquery selection
|
|
6167
|
+
*/
|
|
6168
|
+
selectSubquery(context, alias, query) {
|
|
6169
|
+
return this.columnSelector.selectSubquery(context, alias, query);
|
|
6170
|
+
}
|
|
6171
|
+
/**
|
|
6172
|
+
* Adds DISTINCT clause to the query
|
|
6173
|
+
* @param context - Current query context
|
|
6174
|
+
* @param cols - Columns to make distinct
|
|
6175
|
+
* @returns Updated query context with DISTINCT clause
|
|
6176
|
+
*/
|
|
6177
|
+
distinct(context, cols) {
|
|
6178
|
+
return this.columnSelector.distinct(context, cols);
|
|
6179
|
+
}
|
|
6180
|
+
};
|
|
6181
|
+
|
|
6182
|
+
// src/query-builder/select/predicate-facet.ts
|
|
6183
|
+
var SelectPredicateFacet = class {
|
|
6184
|
+
/**
|
|
6185
|
+
* Creates a new SelectPredicateFacet instance
|
|
6186
|
+
* @param env - Query builder environment
|
|
6187
|
+
* @param createAstService - Function to create AST service
|
|
6188
|
+
*/
|
|
6189
|
+
constructor(env, createAstService) {
|
|
6190
|
+
this.env = env;
|
|
6191
|
+
this.createAstService = createAstService;
|
|
6192
|
+
}
|
|
6193
|
+
/**
|
|
6194
|
+
* Adds a WHERE condition to the query
|
|
6195
|
+
* @param context - Current query context
|
|
6196
|
+
* @param expr - WHERE expression
|
|
6197
|
+
* @returns Updated query context with WHERE condition
|
|
6198
|
+
*/
|
|
6199
|
+
where(context, expr) {
|
|
6200
|
+
const astService = this.createAstService(context.state);
|
|
6201
|
+
const nextState = astService.withWhere(expr);
|
|
6202
|
+
return { state: nextState, hydration: context.hydration };
|
|
6203
|
+
}
|
|
6204
|
+
/**
|
|
6205
|
+
* Adds a GROUP BY clause to the query
|
|
6206
|
+
* @param context - Current query context
|
|
6207
|
+
* @param term - Column or ordering term to group by
|
|
6208
|
+
* @returns Updated query context with GROUP BY clause
|
|
6209
|
+
*/
|
|
6210
|
+
groupBy(context, term) {
|
|
6211
|
+
const astService = this.createAstService(context.state);
|
|
6212
|
+
const nextState = astService.withGroupBy(term);
|
|
6213
|
+
return { state: nextState, hydration: context.hydration };
|
|
6214
|
+
}
|
|
6215
|
+
/**
|
|
6216
|
+
* Adds a HAVING condition to the query
|
|
6217
|
+
* @param context - Current query context
|
|
6218
|
+
* @param expr - HAVING expression
|
|
6219
|
+
* @returns Updated query context with HAVING condition
|
|
6220
|
+
*/
|
|
6221
|
+
having(context, expr) {
|
|
6222
|
+
const astService = this.createAstService(context.state);
|
|
6223
|
+
const nextState = astService.withHaving(expr);
|
|
6224
|
+
return { state: nextState, hydration: context.hydration };
|
|
6225
|
+
}
|
|
6226
|
+
/**
|
|
6227
|
+
* Adds an ORDER BY clause to the query
|
|
6228
|
+
* @param context - Current query context
|
|
6229
|
+
* @param term - Column or ordering term to order by
|
|
6230
|
+
* @param direction - Order direction
|
|
6231
|
+
* @param nulls - Nulls ordering
|
|
6232
|
+
* @param collation - Collation
|
|
6233
|
+
* @returns Updated query context with ORDER BY clause
|
|
6234
|
+
*/
|
|
6235
|
+
orderBy(context, term, direction, nulls, collation) {
|
|
6236
|
+
const astService = this.createAstService(context.state);
|
|
6237
|
+
const nextState = astService.withOrderBy(term, direction, nulls, collation);
|
|
6238
|
+
return { state: nextState, hydration: context.hydration };
|
|
6239
|
+
}
|
|
6240
|
+
/**
|
|
6241
|
+
* Adds a LIMIT clause to the query
|
|
6242
|
+
* @param context - Current query context
|
|
6243
|
+
* @param n - Maximum number of rows
|
|
6244
|
+
* @returns Updated query context with LIMIT clause
|
|
6245
|
+
*/
|
|
6246
|
+
limit(context, n) {
|
|
6247
|
+
const astService = this.createAstService(context.state);
|
|
6248
|
+
const nextState = astService.withLimit(n);
|
|
6249
|
+
return { state: nextState, hydration: context.hydration };
|
|
6250
|
+
}
|
|
6251
|
+
/**
|
|
6252
|
+
* Adds an OFFSET clause to the query
|
|
6253
|
+
* @param context - Current query context
|
|
6254
|
+
* @param n - Number of rows to skip
|
|
6255
|
+
* @returns Updated query context with OFFSET clause
|
|
6256
|
+
*/
|
|
6257
|
+
offset(context, n) {
|
|
6258
|
+
const astService = this.createAstService(context.state);
|
|
6259
|
+
const nextState = astService.withOffset(n);
|
|
6260
|
+
return { state: nextState, hydration: context.hydration };
|
|
6261
|
+
}
|
|
6262
|
+
};
|
|
6263
|
+
|
|
6264
|
+
// src/query-builder/select/cte-facet.ts
|
|
6265
|
+
var SelectCTEFacet = class {
|
|
6266
|
+
/**
|
|
6267
|
+
* Creates a new SelectCTEFacet instance
|
|
6268
|
+
* @param env - Query builder environment
|
|
6269
|
+
* @param createAstService - Function to create AST service
|
|
6270
|
+
*/
|
|
6271
|
+
constructor(env, createAstService) {
|
|
6272
|
+
this.env = env;
|
|
6273
|
+
this.createAstService = createAstService;
|
|
6274
|
+
}
|
|
6275
|
+
/**
|
|
6276
|
+
* Adds a Common Table Expression to the query
|
|
6277
|
+
* @param context - Current query context
|
|
6278
|
+
* @param name - CTE name
|
|
6279
|
+
* @param subAst - CTE query AST
|
|
6280
|
+
* @param columns - Optional column names
|
|
6281
|
+
* @param recursive - Whether the CTE is recursive
|
|
6282
|
+
* @returns Updated query context with CTE
|
|
6283
|
+
*/
|
|
6284
|
+
withCTE(context, name, subAst, columns, recursive) {
|
|
6285
|
+
const astService = this.createAstService(context.state);
|
|
6286
|
+
const nextState = astService.withCte(name, subAst, columns, recursive);
|
|
6287
|
+
return { state: nextState, hydration: context.hydration };
|
|
6288
|
+
}
|
|
6289
|
+
};
|
|
6290
|
+
|
|
6291
|
+
// src/query-builder/select/setop-facet.ts
|
|
6292
|
+
var SelectSetOpFacet = class {
|
|
6293
|
+
/**
|
|
6294
|
+
* Creates a new SelectSetOpFacet instance
|
|
6295
|
+
* @param env - Query builder environment
|
|
6296
|
+
* @param createAstService - Function to create AST service
|
|
6297
|
+
*/
|
|
6298
|
+
constructor(env, createAstService) {
|
|
6299
|
+
this.env = env;
|
|
6300
|
+
this.createAstService = createAstService;
|
|
5806
6301
|
}
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5819
|
-
return proxies;
|
|
6302
|
+
/**
|
|
6303
|
+
* Applies a set operation to the query
|
|
6304
|
+
* @param context - Current query context
|
|
6305
|
+
* @param operator - Set operation kind
|
|
6306
|
+
* @param subAst - Subquery AST to combine
|
|
6307
|
+
* @returns Updated query context with set operation
|
|
6308
|
+
*/
|
|
6309
|
+
applySetOperation(context, operator, subAst) {
|
|
6310
|
+
const astService = this.createAstService(context.state);
|
|
6311
|
+
const nextState = astService.withSetOperation(operator, subAst);
|
|
6312
|
+
return { state: nextState, hydration: context.hydration };
|
|
5820
6313
|
}
|
|
5821
|
-
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
5822
|
-
const entities = hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
5823
|
-
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5824
|
-
return entities;
|
|
5825
6314
|
};
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
6315
|
+
|
|
6316
|
+
// src/query-builder/select/relation-facet.ts
|
|
6317
|
+
var SelectRelationFacet = class {
|
|
6318
|
+
/**
|
|
6319
|
+
* Creates a new SelectRelationFacet instance
|
|
6320
|
+
* @param relationManager - Relation manager dependency
|
|
6321
|
+
*/
|
|
6322
|
+
constructor(relationManager) {
|
|
6323
|
+
this.relationManager = relationManager;
|
|
5833
6324
|
}
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
key,
|
|
5876
|
-
() => loadBelongsToManyRelation(ctx, table, key, relation, options)
|
|
5877
|
-
);
|
|
5878
|
-
break;
|
|
5879
|
-
}
|
|
6325
|
+
/**
|
|
6326
|
+
* Matches records based on a relationship
|
|
6327
|
+
* @param context - Current query context
|
|
6328
|
+
* @param relationName - Name of the relationship
|
|
6329
|
+
* @param predicate - Optional predicate
|
|
6330
|
+
* @returns Updated query context with relation match
|
|
6331
|
+
*/
|
|
6332
|
+
match(context, relationName, predicate) {
|
|
6333
|
+
return this.relationManager.match(context, relationName, predicate);
|
|
6334
|
+
}
|
|
6335
|
+
/**
|
|
6336
|
+
* Joins a related table
|
|
6337
|
+
* @param context - Current query context
|
|
6338
|
+
* @param relationName - Name of the relationship
|
|
6339
|
+
* @param joinKind - Type of join
|
|
6340
|
+
* @param extraCondition - Optional additional condition
|
|
6341
|
+
* @returns Updated query context with relation join
|
|
6342
|
+
*/
|
|
6343
|
+
joinRelation(context, relationName, joinKind, extraCondition) {
|
|
6344
|
+
return this.relationManager.joinRelation(context, relationName, joinKind, extraCondition);
|
|
6345
|
+
}
|
|
6346
|
+
/**
|
|
6347
|
+
* Includes related data in the query results
|
|
6348
|
+
* @param context - Current query context
|
|
6349
|
+
* @param relationName - Name of the relationship to include
|
|
6350
|
+
* @param options - Optional include options
|
|
6351
|
+
* @returns Updated query context with relation inclusion
|
|
6352
|
+
*/
|
|
6353
|
+
include(context, relationName, options) {
|
|
6354
|
+
return this.relationManager.include(context, relationName, options);
|
|
6355
|
+
}
|
|
6356
|
+
/**
|
|
6357
|
+
* Applies correlation for relation-based subqueries
|
|
6358
|
+
* @param context - Current query context
|
|
6359
|
+
* @param relationName - Name of the relationship
|
|
6360
|
+
* @param subAst - Subquery AST
|
|
6361
|
+
* @param extraCorrelate - Optional additional correlation
|
|
6362
|
+
* @returns Modified subquery AST with correlation
|
|
6363
|
+
*/
|
|
6364
|
+
applyRelationCorrelation(context, relationName, subAst, extraCorrelate) {
|
|
6365
|
+
return this.relationManager.applyRelationCorrelation(context, relationName, subAst, extraCorrelate);
|
|
5880
6366
|
}
|
|
5881
6367
|
};
|
|
5882
6368
|
|
|
5883
|
-
// src/query-builder/query-resolution.ts
|
|
5884
|
-
function resolveSelectQuery(query) {
|
|
5885
|
-
const candidate = query;
|
|
5886
|
-
return typeof candidate.getAST === "function" && candidate.getAST ? candidate.getAST() : query;
|
|
5887
|
-
}
|
|
5888
|
-
|
|
5889
6369
|
// src/query-builder/select.ts
|
|
5890
6370
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
6371
|
+
env;
|
|
6372
|
+
context;
|
|
6373
|
+
columnSelector;
|
|
6374
|
+
fromFacet;
|
|
6375
|
+
joinFacet;
|
|
6376
|
+
projectionFacet;
|
|
6377
|
+
predicateFacet;
|
|
6378
|
+
cteFacet;
|
|
6379
|
+
setOpFacet;
|
|
6380
|
+
relationFacet;
|
|
6381
|
+
lazyRelations;
|
|
6382
|
+
lazyRelationOptions;
|
|
5891
6383
|
/**
|
|
5892
6384
|
* Creates a new SelectQueryBuilder instance
|
|
5893
6385
|
* @param table - Table definition to query
|
|
@@ -5898,6 +6390,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5898
6390
|
constructor(table, state, hydration, dependencies, lazyRelations, lazyRelationOptions) {
|
|
5899
6391
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
5900
6392
|
this.env = { table, deps };
|
|
6393
|
+
const createAstService = (nextState) => deps.createQueryAstService(table, nextState);
|
|
5901
6394
|
const initialState = state ?? deps.createState(table);
|
|
5902
6395
|
const initialHydration = hydration ?? deps.createHydration(table);
|
|
5903
6396
|
this.context = {
|
|
@@ -5907,7 +6400,14 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5907
6400
|
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
5908
6401
|
this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
|
|
5909
6402
|
this.columnSelector = deps.createColumnSelector(this.env);
|
|
5910
|
-
|
|
6403
|
+
const relationManager = deps.createRelationManager(this.env);
|
|
6404
|
+
this.fromFacet = new SelectFromFacet(this.env, createAstService);
|
|
6405
|
+
this.joinFacet = new SelectJoinFacet(this.env, createAstService);
|
|
6406
|
+
this.projectionFacet = new SelectProjectionFacet(this.columnSelector);
|
|
6407
|
+
this.predicateFacet = new SelectPredicateFacet(this.env, createAstService);
|
|
6408
|
+
this.cteFacet = new SelectCTEFacet(this.env, createAstService);
|
|
6409
|
+
this.setOpFacet = new SelectSetOpFacet(this.env, createAstService);
|
|
6410
|
+
this.relationFacet = new SelectRelationFacet(relationManager);
|
|
5911
6411
|
}
|
|
5912
6412
|
/**
|
|
5913
6413
|
* Creates a new SelectQueryBuilder instance with updated context and lazy relations
|
|
@@ -5930,12 +6430,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5930
6430
|
* @param alias - Alias to apply
|
|
5931
6431
|
*/
|
|
5932
6432
|
as(alias) {
|
|
5933
|
-
const
|
|
5934
|
-
if (from.type !== "Table") {
|
|
5935
|
-
throw new Error("Cannot alias non-table FROM sources");
|
|
5936
|
-
}
|
|
5937
|
-
const nextFrom = { ...from, alias };
|
|
5938
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
|
|
6433
|
+
const nextContext = this.fromFacet.as(this.context, alias);
|
|
5939
6434
|
return this.clone(nextContext);
|
|
5940
6435
|
}
|
|
5941
6436
|
/**
|
|
@@ -5960,29 +6455,6 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5960
6455
|
createChildBuilder(table) {
|
|
5961
6456
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
5962
6457
|
}
|
|
5963
|
-
/**
|
|
5964
|
-
* Applies an AST mutation using the query AST service
|
|
5965
|
-
* @param context - Current query context
|
|
5966
|
-
* @param mutator - Function that mutates the AST
|
|
5967
|
-
* @returns Updated query context
|
|
5968
|
-
*/
|
|
5969
|
-
applyAst(context, mutator) {
|
|
5970
|
-
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
5971
|
-
const nextState = mutator(astService);
|
|
5972
|
-
return { state: nextState, hydration: context.hydration };
|
|
5973
|
-
}
|
|
5974
|
-
/**
|
|
5975
|
-
* Applies a join to the query context
|
|
5976
|
-
* @param context - Current query context
|
|
5977
|
-
* @param table - Table to join
|
|
5978
|
-
* @param condition - Join condition
|
|
5979
|
-
* @param kind - Join kind
|
|
5980
|
-
* @returns Updated query context with join applied
|
|
5981
|
-
*/
|
|
5982
|
-
applyJoin(context, table, condition, kind) {
|
|
5983
|
-
const joinNode = createJoinNode(kind, { type: "Table", name: table.name, schema: table.schema }, condition);
|
|
5984
|
-
return this.applyAst(context, (service) => service.withJoin(joinNode));
|
|
5985
|
-
}
|
|
5986
6458
|
/**
|
|
5987
6459
|
* Applies a set operation to the query
|
|
5988
6460
|
* @param operator - Set operation kind
|
|
@@ -5991,12 +6463,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5991
6463
|
*/
|
|
5992
6464
|
applySetOperation(operator, query) {
|
|
5993
6465
|
const subAst = resolveSelectQuery(query);
|
|
5994
|
-
return this.
|
|
6466
|
+
return this.setOpFacet.applySetOperation(this.context, operator, subAst);
|
|
5995
6467
|
}
|
|
5996
6468
|
select(...args) {
|
|
5997
6469
|
if (args.length === 1 && typeof args[0] === "object" && args[0] !== null && typeof args[0] !== "string") {
|
|
5998
6470
|
const columns = args[0];
|
|
5999
|
-
return this.clone(this.
|
|
6471
|
+
return this.clone(this.projectionFacet.select(this.context, columns));
|
|
6000
6472
|
}
|
|
6001
6473
|
const cols = args;
|
|
6002
6474
|
const selection = {};
|
|
@@ -6007,7 +6479,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6007
6479
|
}
|
|
6008
6480
|
selection[key] = col2;
|
|
6009
6481
|
}
|
|
6010
|
-
return this.clone(this.
|
|
6482
|
+
return this.clone(this.projectionFacet.select(this.context, selection));
|
|
6011
6483
|
}
|
|
6012
6484
|
/**
|
|
6013
6485
|
* Selects raw column expressions
|
|
@@ -6015,7 +6487,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6015
6487
|
* @returns New query builder instance with raw column selections
|
|
6016
6488
|
*/
|
|
6017
6489
|
selectRaw(...cols) {
|
|
6018
|
-
return this.clone(this.
|
|
6490
|
+
return this.clone(this.projectionFacet.selectRaw(this.context, cols));
|
|
6019
6491
|
}
|
|
6020
6492
|
/**
|
|
6021
6493
|
* Adds a Common Table Expression (CTE) to the query
|
|
@@ -6026,7 +6498,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6026
6498
|
*/
|
|
6027
6499
|
with(name, query, columns) {
|
|
6028
6500
|
const subAst = resolveSelectQuery(query);
|
|
6029
|
-
const nextContext = this.
|
|
6501
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, false);
|
|
6030
6502
|
return this.clone(nextContext);
|
|
6031
6503
|
}
|
|
6032
6504
|
/**
|
|
@@ -6038,7 +6510,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6038
6510
|
*/
|
|
6039
6511
|
withRecursive(name, query, columns) {
|
|
6040
6512
|
const subAst = resolveSelectQuery(query);
|
|
6041
|
-
const nextContext = this.
|
|
6513
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, true);
|
|
6042
6514
|
return this.clone(nextContext);
|
|
6043
6515
|
}
|
|
6044
6516
|
/**
|
|
@@ -6050,8 +6522,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6050
6522
|
*/
|
|
6051
6523
|
fromSubquery(subquery, alias, columnAliases) {
|
|
6052
6524
|
const subAst = resolveSelectQuery(subquery);
|
|
6053
|
-
const
|
|
6054
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
|
|
6525
|
+
const nextContext = this.fromFacet.fromSubquery(this.context, subAst, alias, columnAliases);
|
|
6055
6526
|
return this.clone(nextContext);
|
|
6056
6527
|
}
|
|
6057
6528
|
/**
|
|
@@ -6062,8 +6533,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6062
6533
|
* @param options - Optional function-table metadata (lateral, ordinality, column aliases, schema)
|
|
6063
6534
|
*/
|
|
6064
6535
|
fromFunctionTable(name, args = [], alias, options) {
|
|
6065
|
-
const
|
|
6066
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(functionTable));
|
|
6536
|
+
const nextContext = this.fromFacet.fromFunctionTable(this.context, name, args, alias, options);
|
|
6067
6537
|
return this.clone(nextContext);
|
|
6068
6538
|
}
|
|
6069
6539
|
/**
|
|
@@ -6074,7 +6544,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6074
6544
|
*/
|
|
6075
6545
|
selectSubquery(alias, sub2) {
|
|
6076
6546
|
const query = resolveSelectQuery(sub2);
|
|
6077
|
-
return this.clone(this.
|
|
6547
|
+
return this.clone(this.projectionFacet.selectSubquery(this.context, alias, query));
|
|
6078
6548
|
}
|
|
6079
6549
|
/**
|
|
6080
6550
|
* Adds a JOIN against a derived table (subquery with alias)
|
|
@@ -6087,8 +6557,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6087
6557
|
*/
|
|
6088
6558
|
joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
|
|
6089
6559
|
const subAst = resolveSelectQuery(subquery);
|
|
6090
|
-
const
|
|
6091
|
-
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
6560
|
+
const nextContext = this.joinFacet.joinSubquery(this.context, subAst, alias, condition, joinKind, columnAliases);
|
|
6092
6561
|
return this.clone(nextContext);
|
|
6093
6562
|
}
|
|
6094
6563
|
/**
|
|
@@ -6101,9 +6570,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6101
6570
|
* @param options - Optional metadata (lateral, ordinality, column aliases, schema)
|
|
6102
6571
|
*/
|
|
6103
6572
|
joinFunctionTable(name, args = [], alias, condition, joinKind = JOIN_KINDS.INNER, options) {
|
|
6104
|
-
const
|
|
6105
|
-
const joinNode = createJoinNode(joinKind, functionTable, condition);
|
|
6106
|
-
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
6573
|
+
const nextContext = this.joinFacet.joinFunctionTable(this.context, name, args, alias, condition, joinKind, options);
|
|
6107
6574
|
return this.clone(nextContext);
|
|
6108
6575
|
}
|
|
6109
6576
|
/**
|
|
@@ -6113,7 +6580,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6113
6580
|
* @returns New query builder instance with the INNER JOIN
|
|
6114
6581
|
*/
|
|
6115
6582
|
innerJoin(table, condition) {
|
|
6116
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
6583
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
6117
6584
|
return this.clone(nextContext);
|
|
6118
6585
|
}
|
|
6119
6586
|
/**
|
|
@@ -6123,7 +6590,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6123
6590
|
* @returns New query builder instance with the LEFT JOIN
|
|
6124
6591
|
*/
|
|
6125
6592
|
leftJoin(table, condition) {
|
|
6126
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
6593
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
6127
6594
|
return this.clone(nextContext);
|
|
6128
6595
|
}
|
|
6129
6596
|
/**
|
|
@@ -6133,7 +6600,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6133
6600
|
* @returns New query builder instance with the RIGHT JOIN
|
|
6134
6601
|
*/
|
|
6135
6602
|
rightJoin(table, condition) {
|
|
6136
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
6603
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
6137
6604
|
return this.clone(nextContext);
|
|
6138
6605
|
}
|
|
6139
6606
|
/**
|
|
@@ -6143,7 +6610,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6143
6610
|
* @returns New query builder instance with the relationship match
|
|
6144
6611
|
*/
|
|
6145
6612
|
match(relationName, predicate) {
|
|
6146
|
-
const nextContext = this.
|
|
6613
|
+
const nextContext = this.relationFacet.match(this.context, relationName, predicate);
|
|
6147
6614
|
return this.clone(nextContext);
|
|
6148
6615
|
}
|
|
6149
6616
|
/**
|
|
@@ -6154,7 +6621,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6154
6621
|
* @returns New query builder instance with the relationship join
|
|
6155
6622
|
*/
|
|
6156
6623
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
6157
|
-
const nextContext = this.
|
|
6624
|
+
const nextContext = this.relationFacet.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
6158
6625
|
return this.clone(nextContext);
|
|
6159
6626
|
}
|
|
6160
6627
|
/**
|
|
@@ -6164,7 +6631,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6164
6631
|
* @returns New query builder instance with the relationship inclusion
|
|
6165
6632
|
*/
|
|
6166
6633
|
include(relationName, options) {
|
|
6167
|
-
const nextContext = this.
|
|
6634
|
+
const nextContext = this.relationFacet.include(this.context, relationName, options);
|
|
6168
6635
|
return this.clone(nextContext);
|
|
6169
6636
|
}
|
|
6170
6637
|
/**
|
|
@@ -6203,7 +6670,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6203
6670
|
* Convenience alias for including only specific columns from a relation.
|
|
6204
6671
|
*/
|
|
6205
6672
|
includePick(relationName, cols) {
|
|
6206
|
-
|
|
6673
|
+
const options = { columns: cols };
|
|
6674
|
+
return this.include(relationName, options);
|
|
6207
6675
|
}
|
|
6208
6676
|
/**
|
|
6209
6677
|
* Selects columns for the root table and relations from an array of entries
|
|
@@ -6216,7 +6684,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6216
6684
|
if (entry.type === "root") {
|
|
6217
6685
|
currBuilder = currBuilder.select(...entry.columns);
|
|
6218
6686
|
} else {
|
|
6219
|
-
|
|
6687
|
+
const options = { columns: entry.columns };
|
|
6688
|
+
currBuilder = currBuilder.include(entry.relationName, options);
|
|
6220
6689
|
}
|
|
6221
6690
|
}
|
|
6222
6691
|
return currBuilder;
|
|
@@ -6250,51 +6719,23 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6250
6719
|
async execute(ctx) {
|
|
6251
6720
|
return executeHydrated(ctx, this);
|
|
6252
6721
|
}
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
return this.clone(nextContext);
|
|
6260
|
-
}
|
|
6722
|
+
/**
|
|
6723
|
+
* Executes a count query for the current builder without LIMIT/OFFSET clauses.
|
|
6724
|
+
*
|
|
6725
|
+
* @example
|
|
6726
|
+
* const total = await qb.count(session);
|
|
6727
|
+
*/
|
|
6261
6728
|
async count(session) {
|
|
6262
|
-
|
|
6263
|
-
...this.context.state.ast,
|
|
6264
|
-
orderBy: void 0,
|
|
6265
|
-
limit: void 0,
|
|
6266
|
-
offset: void 0
|
|
6267
|
-
};
|
|
6268
|
-
const subAst = this.withAst(unpagedAst).getAST();
|
|
6269
|
-
const countQuery = {
|
|
6270
|
-
type: "SelectQuery",
|
|
6271
|
-
from: derivedTable(subAst, "__metal_count"),
|
|
6272
|
-
columns: [{ type: "Function", name: "COUNT", args: [], alias: "total" }],
|
|
6273
|
-
joins: []
|
|
6274
|
-
};
|
|
6275
|
-
const execCtx = session.getExecutionContext();
|
|
6276
|
-
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
6277
|
-
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
6278
|
-
const value = results[0]?.values?.[0]?.[0];
|
|
6279
|
-
if (typeof value === "number") return value;
|
|
6280
|
-
if (typeof value === "bigint") return Number(value);
|
|
6281
|
-
if (typeof value === "string") return Number(value);
|
|
6282
|
-
return value === null || value === void 0 ? 0 : Number(value);
|
|
6729
|
+
return executeCount(this.context, this.env, session);
|
|
6283
6730
|
}
|
|
6731
|
+
/**
|
|
6732
|
+
* Executes the query and returns both the paged items and the total.
|
|
6733
|
+
*
|
|
6734
|
+
* @example
|
|
6735
|
+
* const { items, totalItems } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
6736
|
+
*/
|
|
6284
6737
|
async executePaged(session, options) {
|
|
6285
|
-
|
|
6286
|
-
if (!Number.isInteger(page) || page < 1) {
|
|
6287
|
-
throw new Error("executePaged: page must be an integer >= 1");
|
|
6288
|
-
}
|
|
6289
|
-
if (!Number.isInteger(pageSize) || pageSize < 1) {
|
|
6290
|
-
throw new Error("executePaged: pageSize must be an integer >= 1");
|
|
6291
|
-
}
|
|
6292
|
-
const offset = (page - 1) * pageSize;
|
|
6293
|
-
const [items, totalItems] = await Promise.all([
|
|
6294
|
-
this.limit(pageSize).offset(offset).execute(session),
|
|
6295
|
-
this.count(session)
|
|
6296
|
-
]);
|
|
6297
|
-
return { items, totalItems };
|
|
6738
|
+
return executePagedQuery(this, session, options, (sess) => this.count(sess));
|
|
6298
6739
|
}
|
|
6299
6740
|
/**
|
|
6300
6741
|
* Executes the query with provided execution and hydration contexts
|
|
@@ -6311,7 +6752,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6311
6752
|
* @returns New query builder instance with the WHERE condition
|
|
6312
6753
|
*/
|
|
6313
6754
|
where(expr) {
|
|
6314
|
-
const nextContext = this.
|
|
6755
|
+
const nextContext = this.predicateFacet.where(this.context, expr);
|
|
6315
6756
|
return this.clone(nextContext);
|
|
6316
6757
|
}
|
|
6317
6758
|
/**
|
|
@@ -6320,7 +6761,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6320
6761
|
* @returns New query builder instance with the GROUP BY clause
|
|
6321
6762
|
*/
|
|
6322
6763
|
groupBy(term) {
|
|
6323
|
-
const nextContext = this.
|
|
6764
|
+
const nextContext = this.predicateFacet.groupBy(this.context, term);
|
|
6324
6765
|
return this.clone(nextContext);
|
|
6325
6766
|
}
|
|
6326
6767
|
/**
|
|
@@ -6329,7 +6770,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6329
6770
|
* @returns New query builder instance with the HAVING condition
|
|
6330
6771
|
*/
|
|
6331
6772
|
having(expr) {
|
|
6332
|
-
const nextContext = this.
|
|
6773
|
+
const nextContext = this.predicateFacet.having(this.context, expr);
|
|
6333
6774
|
return this.clone(nextContext);
|
|
6334
6775
|
}
|
|
6335
6776
|
/**
|
|
@@ -6337,14 +6778,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6337
6778
|
* @param term - Column definition or ordering term to order by
|
|
6338
6779
|
* @param directionOrOptions - Order direction or options (defaults to ASC)
|
|
6339
6780
|
* @returns New query builder instance with the ORDER BY clause
|
|
6781
|
+
*
|
|
6782
|
+
* @example
|
|
6783
|
+
* qb.orderBy(userTable.columns.createdAt, 'DESC');
|
|
6340
6784
|
*/
|
|
6341
6785
|
orderBy(term, directionOrOptions = ORDER_DIRECTIONS.ASC) {
|
|
6342
|
-
const
|
|
6343
|
-
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
6344
|
-
const nextContext = this.applyAst(
|
|
6345
|
-
this.context,
|
|
6346
|
-
(service) => service.withOrderBy(term, dir, options.nulls, options.collation)
|
|
6347
|
-
);
|
|
6786
|
+
const nextContext = applyOrderBy(this.context, this.predicateFacet, term, directionOrOptions);
|
|
6348
6787
|
return this.clone(nextContext);
|
|
6349
6788
|
}
|
|
6350
6789
|
/**
|
|
@@ -6353,7 +6792,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6353
6792
|
* @returns New query builder instance with the DISTINCT clause
|
|
6354
6793
|
*/
|
|
6355
6794
|
distinct(...cols) {
|
|
6356
|
-
return this.clone(this.
|
|
6795
|
+
return this.clone(this.projectionFacet.distinct(this.context, cols));
|
|
6357
6796
|
}
|
|
6358
6797
|
/**
|
|
6359
6798
|
* Adds a LIMIT clause to the query
|
|
@@ -6361,7 +6800,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6361
6800
|
* @returns New query builder instance with the LIMIT clause
|
|
6362
6801
|
*/
|
|
6363
6802
|
limit(n) {
|
|
6364
|
-
const nextContext = this.
|
|
6803
|
+
const nextContext = this.predicateFacet.limit(this.context, n);
|
|
6365
6804
|
return this.clone(nextContext);
|
|
6366
6805
|
}
|
|
6367
6806
|
/**
|
|
@@ -6370,7 +6809,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6370
6809
|
* @returns New query builder instance with the OFFSET clause
|
|
6371
6810
|
*/
|
|
6372
6811
|
offset(n) {
|
|
6373
|
-
const nextContext = this.
|
|
6812
|
+
const nextContext = this.predicateFacet.offset(this.context, n);
|
|
6374
6813
|
return this.clone(nextContext);
|
|
6375
6814
|
}
|
|
6376
6815
|
/**
|
|
@@ -6430,42 +6869,44 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6430
6869
|
* @param relationName - Name of the relationship to check
|
|
6431
6870
|
* @param callback - Optional callback to modify the relationship query
|
|
6432
6871
|
* @returns New query builder instance with the relationship existence check
|
|
6872
|
+
*
|
|
6873
|
+
* @example
|
|
6874
|
+
* qb.whereHas('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
6433
6875
|
*/
|
|
6434
6876
|
whereHas(relationName, callbackOrOptions, maybeOptions) {
|
|
6435
|
-
const
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
6447
|
-
return this.where(exists(finalSubAst));
|
|
6877
|
+
const predicate = buildWhereHasPredicate(
|
|
6878
|
+
this.env,
|
|
6879
|
+
this.context,
|
|
6880
|
+
this.relationFacet,
|
|
6881
|
+
(table) => this.createChildBuilder(table),
|
|
6882
|
+
relationName,
|
|
6883
|
+
callbackOrOptions,
|
|
6884
|
+
maybeOptions,
|
|
6885
|
+
false
|
|
6886
|
+
);
|
|
6887
|
+
return this.where(predicate);
|
|
6448
6888
|
}
|
|
6449
6889
|
/**
|
|
6450
6890
|
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
6451
6891
|
* @param relationName - Name of the relationship to check
|
|
6452
6892
|
* @param callback - Optional callback to modify the relationship query
|
|
6453
6893
|
* @returns New query builder instance with the relationship non-existence check
|
|
6894
|
+
*
|
|
6895
|
+
* @example
|
|
6896
|
+
* qb.whereHasNot('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
6454
6897
|
*/
|
|
6455
6898
|
whereHasNot(relationName, callbackOrOptions, maybeOptions) {
|
|
6456
|
-
const
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
6468
|
-
return this.where(notExists(finalSubAst));
|
|
6899
|
+
const predicate = buildWhereHasPredicate(
|
|
6900
|
+
this.env,
|
|
6901
|
+
this.context,
|
|
6902
|
+
this.relationFacet,
|
|
6903
|
+
(table) => this.createChildBuilder(table),
|
|
6904
|
+
relationName,
|
|
6905
|
+
callbackOrOptions,
|
|
6906
|
+
maybeOptions,
|
|
6907
|
+
true
|
|
6908
|
+
);
|
|
6909
|
+
return this.where(predicate);
|
|
6469
6910
|
}
|
|
6470
6911
|
/**
|
|
6471
6912
|
* Compiles the query to SQL for a specific dialect
|
|
@@ -6597,23 +7038,44 @@ var resolveTableTarget = (target, tableMap) => {
|
|
|
6597
7038
|
}
|
|
6598
7039
|
return table;
|
|
6599
7040
|
};
|
|
7041
|
+
var toSnakeCase = (value) => {
|
|
7042
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
7043
|
+
};
|
|
7044
|
+
var normalizeEntityName = (value) => {
|
|
7045
|
+
const stripped = value.replace(/Entity$/i, "");
|
|
7046
|
+
const normalized = toSnakeCase(stripped || value);
|
|
7047
|
+
return normalized || "unknown";
|
|
7048
|
+
};
|
|
7049
|
+
var getPivotKeyBaseFromTarget = (target) => {
|
|
7050
|
+
const resolved = unwrapTarget(target);
|
|
7051
|
+
if (isTableDef(resolved)) {
|
|
7052
|
+
return toSnakeCase(resolved.name || "unknown");
|
|
7053
|
+
}
|
|
7054
|
+
const ctor = resolved;
|
|
7055
|
+
return normalizeEntityName(ctor.name || "unknown");
|
|
7056
|
+
};
|
|
7057
|
+
var getPivotKeyBaseFromRoot = (meta) => {
|
|
7058
|
+
return normalizeEntityName(meta.target.name || meta.tableName || "unknown");
|
|
7059
|
+
};
|
|
6600
7060
|
var buildRelationDefinitions = (meta, tableMap) => {
|
|
6601
7061
|
const relations = {};
|
|
6602
7062
|
for (const [name, relation] of Object.entries(meta.relations)) {
|
|
6603
7063
|
switch (relation.kind) {
|
|
6604
7064
|
case RelationKinds.HasOne: {
|
|
7065
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6605
7066
|
relations[name] = hasOne(
|
|
6606
7067
|
resolveTableTarget(relation.target, tableMap),
|
|
6607
|
-
|
|
7068
|
+
foreignKey,
|
|
6608
7069
|
relation.localKey,
|
|
6609
7070
|
relation.cascade
|
|
6610
7071
|
);
|
|
6611
7072
|
break;
|
|
6612
7073
|
}
|
|
6613
7074
|
case RelationKinds.HasMany: {
|
|
7075
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6614
7076
|
relations[name] = hasMany(
|
|
6615
7077
|
resolveTableTarget(relation.target, tableMap),
|
|
6616
|
-
|
|
7078
|
+
foreignKey,
|
|
6617
7079
|
relation.localKey,
|
|
6618
7080
|
relation.cascade
|
|
6619
7081
|
);
|
|
@@ -6629,12 +7091,14 @@ var buildRelationDefinitions = (meta, tableMap) => {
|
|
|
6629
7091
|
break;
|
|
6630
7092
|
}
|
|
6631
7093
|
case RelationKinds.BelongsToMany: {
|
|
7094
|
+
const pivotForeignKeyToRoot = relation.pivotForeignKeyToRoot ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
7095
|
+
const pivotForeignKeyToTarget = relation.pivotForeignKeyToTarget ?? `${getPivotKeyBaseFromTarget(relation.target)}_id`;
|
|
6632
7096
|
relations[name] = belongsToMany(
|
|
6633
7097
|
resolveTableTarget(relation.target, tableMap),
|
|
6634
7098
|
resolveTableTarget(relation.pivotTable, tableMap),
|
|
6635
7099
|
{
|
|
6636
|
-
pivotForeignKeyToRoot
|
|
6637
|
-
pivotForeignKeyToTarget
|
|
7100
|
+
pivotForeignKeyToRoot,
|
|
7101
|
+
pivotForeignKeyToTarget,
|
|
6638
7102
|
localKey: relation.localKey,
|
|
6639
7103
|
targetKey: relation.targetKey,
|
|
6640
7104
|
pivotPrimaryKey: relation.pivotPrimaryKey,
|
|
@@ -6715,6 +7179,8 @@ function esel(entity, ...props) {
|
|
|
6715
7179
|
|
|
6716
7180
|
// src/query-builder/insert-query-state.ts
|
|
6717
7181
|
var InsertQueryState = class _InsertQueryState {
|
|
7182
|
+
table;
|
|
7183
|
+
ast;
|
|
6718
7184
|
/**
|
|
6719
7185
|
* Creates a new InsertQueryState instance
|
|
6720
7186
|
* @param table - The table definition for the INSERT query
|
|
@@ -6835,6 +7301,8 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
6835
7301
|
|
|
6836
7302
|
// src/query-builder/insert.ts
|
|
6837
7303
|
var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
7304
|
+
table;
|
|
7305
|
+
state;
|
|
6838
7306
|
/**
|
|
6839
7307
|
* Creates a new InsertQueryBuilder instance
|
|
6840
7308
|
* @param table - The table definition for the INSERT query
|
|
@@ -6934,6 +7402,8 @@ var isUpdateValue = (value) => {
|
|
|
6934
7402
|
}
|
|
6935
7403
|
};
|
|
6936
7404
|
var UpdateQueryState = class _UpdateQueryState {
|
|
7405
|
+
table;
|
|
7406
|
+
ast;
|
|
6937
7407
|
/**
|
|
6938
7408
|
* Creates a new UpdateQueryState instance
|
|
6939
7409
|
* @param table - Table definition for the update
|
|
@@ -7044,6 +7514,8 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
7044
7514
|
|
|
7045
7515
|
// src/query-builder/update.ts
|
|
7046
7516
|
var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
7517
|
+
table;
|
|
7518
|
+
state;
|
|
7047
7519
|
/**
|
|
7048
7520
|
* Creates a new UpdateQueryBuilder instance
|
|
7049
7521
|
* @param table - The table definition for the UPDATE query
|
|
@@ -7161,6 +7633,8 @@ var isTableSourceNode = (source) => typeof source.type === "string";
|
|
|
7161
7633
|
|
|
7162
7634
|
// src/query-builder/delete-query-state.ts
|
|
7163
7635
|
var DeleteQueryState = class _DeleteQueryState {
|
|
7636
|
+
table;
|
|
7637
|
+
ast;
|
|
7164
7638
|
/**
|
|
7165
7639
|
* Creates a new DeleteQueryState instance
|
|
7166
7640
|
* @param table - The table definition for the DELETE query
|
|
@@ -7239,6 +7713,8 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
7239
7713
|
|
|
7240
7714
|
// src/query-builder/delete.ts
|
|
7241
7715
|
var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
7716
|
+
table;
|
|
7717
|
+
state;
|
|
7242
7718
|
/**
|
|
7243
7719
|
* Creates a new DeleteQueryBuilder instance
|
|
7244
7720
|
* @param table - The table definition for the DELETE query
|
|
@@ -7366,7 +7842,8 @@ var renderColumnDefinition = (table, col2, dialect, options = {}) => {
|
|
|
7366
7842
|
if (col2.default !== void 0) {
|
|
7367
7843
|
parts.push(`DEFAULT ${dialect.renderDefault(col2.default, col2)}`);
|
|
7368
7844
|
}
|
|
7369
|
-
|
|
7845
|
+
const autoIncIncludesPrimary = typeof autoInc === "string" && /\bPRIMARY\s+KEY\b/i.test(autoInc);
|
|
7846
|
+
if (options.includePrimary && col2.primary && !autoIncIncludesPrimary) {
|
|
7370
7847
|
parts.push("PRIMARY KEY");
|
|
7371
7848
|
}
|
|
7372
7849
|
if (col2.check) {
|
|
@@ -7424,6 +7901,16 @@ var generateSchemaSql = (tables, dialect) => {
|
|
|
7424
7901
|
});
|
|
7425
7902
|
return statements;
|
|
7426
7903
|
};
|
|
7904
|
+
var generateSchemaSqlFor = (dialect, ...tables) => generateSchemaSql(tables, dialect);
|
|
7905
|
+
var executeSchemaSql = async (executor, tables, dialect) => {
|
|
7906
|
+
const statements = generateSchemaSql(tables, dialect);
|
|
7907
|
+
for (const sql of statements) {
|
|
7908
|
+
await executor.executeSql(sql);
|
|
7909
|
+
}
|
|
7910
|
+
};
|
|
7911
|
+
var executeSchemaSqlFor = async (executor, dialect, ...tables) => {
|
|
7912
|
+
await executeSchemaSql(executor, tables, dialect);
|
|
7913
|
+
};
|
|
7427
7914
|
var orderTablesByDependencies = (tables) => {
|
|
7428
7915
|
const map = /* @__PURE__ */ new Map();
|
|
7429
7916
|
tables.forEach((t) => map.set(t.name, t));
|
|
@@ -9330,6 +9817,7 @@ var arrayAppend = (array, value) => fn7("ARRAY_APPEND", [array, value]);
|
|
|
9330
9817
|
|
|
9331
9818
|
// src/orm/als.ts
|
|
9332
9819
|
var AsyncLocalStorage = class {
|
|
9820
|
+
store;
|
|
9333
9821
|
/**
|
|
9334
9822
|
* Executes a callback function within a context containing the specified store value.
|
|
9335
9823
|
* The store value is only available during the callback's execution and is automatically
|
|
@@ -9826,9 +10314,7 @@ var TypeScriptGenerator = class {
|
|
|
9826
10314
|
|
|
9827
10315
|
// src/orm/identity-map.ts
|
|
9828
10316
|
var IdentityMap = class {
|
|
9829
|
-
|
|
9830
|
-
this.buckets = /* @__PURE__ */ new Map();
|
|
9831
|
-
}
|
|
10317
|
+
buckets = /* @__PURE__ */ new Map();
|
|
9832
10318
|
get bucketsMap() {
|
|
9833
10319
|
return this.buckets;
|
|
9834
10320
|
}
|
|
@@ -9898,8 +10384,8 @@ var UnitOfWork = class {
|
|
|
9898
10384
|
this.executor = executor;
|
|
9899
10385
|
this.identityMap = identityMap;
|
|
9900
10386
|
this.hookContext = hookContext;
|
|
9901
|
-
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
9902
10387
|
}
|
|
10388
|
+
trackedEntities = /* @__PURE__ */ new Map();
|
|
9903
10389
|
/**
|
|
9904
10390
|
* Gets the identity buckets map.
|
|
9905
10391
|
*/
|
|
@@ -10229,12 +10715,12 @@ var UnitOfWork = class {
|
|
|
10229
10715
|
|
|
10230
10716
|
// src/orm/domain-event-bus.ts
|
|
10231
10717
|
var DomainEventBus = class {
|
|
10718
|
+
handlers = /* @__PURE__ */ new Map();
|
|
10232
10719
|
/**
|
|
10233
10720
|
* Creates a new DomainEventBus instance.
|
|
10234
10721
|
* @param initialHandlers - Optional initial event handlers
|
|
10235
10722
|
*/
|
|
10236
10723
|
constructor(initialHandlers) {
|
|
10237
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
10238
10724
|
if (initialHandlers) {
|
|
10239
10725
|
for (const key in initialHandlers) {
|
|
10240
10726
|
const type = key;
|
|
@@ -10303,8 +10789,8 @@ var RelationChangeProcessor = class {
|
|
|
10303
10789
|
this.unitOfWork = unitOfWork;
|
|
10304
10790
|
this.dialect = dialect;
|
|
10305
10791
|
this.executor = executor;
|
|
10306
|
-
this.relationChanges = [];
|
|
10307
10792
|
}
|
|
10793
|
+
relationChanges = [];
|
|
10308
10794
|
/**
|
|
10309
10795
|
* Registers a relation change for processing.
|
|
10310
10796
|
* @param entry - The relation change entry
|
|
@@ -10738,25 +11224,24 @@ var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
|
|
|
10738
11224
|
|
|
10739
11225
|
// src/orm/orm-session.ts
|
|
10740
11226
|
var OrmSession = class {
|
|
11227
|
+
/** The ORM instance */
|
|
11228
|
+
orm;
|
|
11229
|
+
/** The database executor */
|
|
11230
|
+
executor;
|
|
11231
|
+
/** The identity map for tracking entity instances */
|
|
11232
|
+
identityMap;
|
|
11233
|
+
/** The unit of work for tracking entity changes */
|
|
11234
|
+
unitOfWork;
|
|
11235
|
+
/** The domain event bus */
|
|
11236
|
+
domainEvents;
|
|
11237
|
+
/** The relation change processor */
|
|
11238
|
+
relationChanges;
|
|
11239
|
+
interceptors;
|
|
10741
11240
|
/**
|
|
10742
11241
|
* Creates a new OrmSession instance.
|
|
10743
11242
|
* @param opts - Session options
|
|
10744
11243
|
*/
|
|
10745
11244
|
constructor(opts) {
|
|
10746
|
-
/**
|
|
10747
|
-
* Registers a relation change.
|
|
10748
|
-
* @param root - The root entity
|
|
10749
|
-
* @param relationKey - The relation key
|
|
10750
|
-
* @param rootTable - The root table definition
|
|
10751
|
-
* @param relationName - The relation name
|
|
10752
|
-
* @param relation - The relation definition
|
|
10753
|
-
* @param change - The relation change
|
|
10754
|
-
*/
|
|
10755
|
-
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
10756
|
-
this.relationChanges.registerChange(
|
|
10757
|
-
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
10758
|
-
);
|
|
10759
|
-
};
|
|
10760
11245
|
this.orm = opts.orm;
|
|
10761
11246
|
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
10762
11247
|
this.interceptors = [...opts.interceptors ?? []];
|
|
@@ -10845,6 +11330,20 @@ var OrmSession = class {
|
|
|
10845
11330
|
markRemoved(entity) {
|
|
10846
11331
|
this.unitOfWork.markRemoved(entity);
|
|
10847
11332
|
}
|
|
11333
|
+
/**
|
|
11334
|
+
* Registers a relation change.
|
|
11335
|
+
* @param root - The root entity
|
|
11336
|
+
* @param relationKey - The relation key
|
|
11337
|
+
* @param rootTable - The root table definition
|
|
11338
|
+
* @param relationName - The relation name
|
|
11339
|
+
* @param relation - The relation definition
|
|
11340
|
+
* @param change - The relation change
|
|
11341
|
+
*/
|
|
11342
|
+
registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
11343
|
+
this.relationChanges.registerChange(
|
|
11344
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
11345
|
+
);
|
|
11346
|
+
};
|
|
10848
11347
|
/**
|
|
10849
11348
|
* Gets all tracked entities for a specific table.
|
|
10850
11349
|
* @param table - The table definition
|
|
@@ -11050,9 +11549,7 @@ var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, rela
|
|
|
11050
11549
|
|
|
11051
11550
|
// src/orm/interceptor-pipeline.ts
|
|
11052
11551
|
var InterceptorPipeline = class {
|
|
11053
|
-
|
|
11054
|
-
this.interceptors = [];
|
|
11055
|
-
}
|
|
11552
|
+
interceptors = [];
|
|
11056
11553
|
use(interceptor) {
|
|
11057
11554
|
this.interceptors.push(interceptor);
|
|
11058
11555
|
}
|
|
@@ -11071,6 +11568,13 @@ var InterceptorPipeline = class {
|
|
|
11071
11568
|
|
|
11072
11569
|
// src/orm/orm.ts
|
|
11073
11570
|
var Orm = class {
|
|
11571
|
+
/** The database dialect */
|
|
11572
|
+
dialect;
|
|
11573
|
+
/** The interceptors pipeline */
|
|
11574
|
+
interceptors;
|
|
11575
|
+
/** The naming strategy */
|
|
11576
|
+
namingStrategy;
|
|
11577
|
+
executorFactory;
|
|
11074
11578
|
/**
|
|
11075
11579
|
* Creates a new ORM instance.
|
|
11076
11580
|
* @param opts - ORM options
|
|
@@ -11127,17 +11631,13 @@ var jsonify = (value) => {
|
|
|
11127
11631
|
|
|
11128
11632
|
// src/decorators/decorator-metadata.ts
|
|
11129
11633
|
var METADATA_KEY = "metal-orm:decorators";
|
|
11130
|
-
var isStandardDecoratorContext = (value) => {
|
|
11131
|
-
return typeof value === "object" && value !== null && "kind" in value;
|
|
11132
|
-
};
|
|
11133
11634
|
var getOrCreateMetadataBag = (context) => {
|
|
11134
11635
|
const metadata = context.metadata || (context.metadata = {});
|
|
11135
|
-
|
|
11136
|
-
if (
|
|
11137
|
-
|
|
11636
|
+
let bag = metadata[METADATA_KEY];
|
|
11637
|
+
if (!bag) {
|
|
11638
|
+
bag = { columns: [], relations: [] };
|
|
11639
|
+
metadata[METADATA_KEY] = bag;
|
|
11138
11640
|
}
|
|
11139
|
-
const bag = { columns: [], relations: [] };
|
|
11140
|
-
metadata[METADATA_KEY] = bag;
|
|
11141
11641
|
return bag;
|
|
11142
11642
|
};
|
|
11143
11643
|
var readMetadataBag = (context) => {
|
|
@@ -11152,57 +11652,50 @@ var readMetadataBagFromConstructor = (ctor) => {
|
|
|
11152
11652
|
var getDecoratorMetadata = (ctor) => readMetadataBagFromConstructor(ctor);
|
|
11153
11653
|
|
|
11154
11654
|
// src/decorators/entity.ts
|
|
11155
|
-
var
|
|
11655
|
+
var toSnakeCase2 = (value) => {
|
|
11156
11656
|
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
11157
11657
|
};
|
|
11158
11658
|
var deriveTableNameFromConstructor = (ctor) => {
|
|
11159
11659
|
const fallback = "unknown";
|
|
11160
11660
|
const rawName = ctor.name || fallback;
|
|
11161
11661
|
const strippedName = rawName.replace(/Entity$/i, "");
|
|
11162
|
-
const normalized =
|
|
11662
|
+
const normalized = toSnakeCase2(strippedName || rawName);
|
|
11163
11663
|
if (!normalized) {
|
|
11164
11664
|
return fallback;
|
|
11165
11665
|
}
|
|
11166
11666
|
return normalized.endsWith("s") ? normalized : `${normalized}s`;
|
|
11167
11667
|
};
|
|
11168
11668
|
function Entity(options = {}) {
|
|
11169
|
-
|
|
11170
|
-
const tableName = options.tableName ?? deriveTableNameFromConstructor(value);
|
|
11171
|
-
setEntityTableName(value, tableName, options.hooks);
|
|
11172
|
-
return value;
|
|
11173
|
-
};
|
|
11174
|
-
const decoratorWithContext = (value, context) => {
|
|
11669
|
+
return function(value, context) {
|
|
11175
11670
|
const ctor = value;
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
}
|
|
11187
|
-
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11671
|
+
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
11672
|
+
setEntityTableName(ctor, tableName, options.hooks);
|
|
11673
|
+
const bag = readMetadataBag(context);
|
|
11674
|
+
if (bag) {
|
|
11675
|
+
const meta = ensureEntityMetadata(ctor);
|
|
11676
|
+
for (const entry of bag.columns) {
|
|
11677
|
+
if (meta.columns[entry.propertyName]) {
|
|
11678
|
+
throw new Error(
|
|
11679
|
+
`Column '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11680
|
+
);
|
|
11188
11681
|
}
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
...entry.relation,
|
|
11197
|
-
defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
|
|
11198
|
-
} : { ...entry.relation };
|
|
11199
|
-
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
11682
|
+
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11683
|
+
}
|
|
11684
|
+
for (const entry of bag.relations) {
|
|
11685
|
+
if (meta.relations[entry.propertyName]) {
|
|
11686
|
+
throw new Error(
|
|
11687
|
+
`Relation '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11688
|
+
);
|
|
11200
11689
|
}
|
|
11690
|
+
const relationCopy = entry.relation.kind === RelationKinds.BelongsToMany ? {
|
|
11691
|
+
...entry.relation,
|
|
11692
|
+
defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
|
|
11693
|
+
} : { ...entry.relation };
|
|
11694
|
+
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
11201
11695
|
}
|
|
11202
11696
|
}
|
|
11203
11697
|
return ctor;
|
|
11204
11698
|
};
|
|
11205
|
-
return decoratorWithContext;
|
|
11206
11699
|
}
|
|
11207
11700
|
|
|
11208
11701
|
// src/decorators/column-decorator.ts
|
|
@@ -11235,26 +11728,13 @@ var normalizePropertyName = (name) => {
|
|
|
11235
11728
|
}
|
|
11236
11729
|
return name;
|
|
11237
11730
|
};
|
|
11238
|
-
var resolveConstructor = (target) => {
|
|
11239
|
-
if (typeof target === "function") {
|
|
11240
|
-
return target;
|
|
11241
|
-
}
|
|
11242
|
-
if (target && typeof target.constructor === "function") {
|
|
11243
|
-
return target.constructor;
|
|
11244
|
-
}
|
|
11245
|
-
return void 0;
|
|
11246
|
-
};
|
|
11247
|
-
var registerColumn = (ctor, propertyName, column) => {
|
|
11248
|
-
const meta = ensureEntityMetadata(ctor);
|
|
11249
|
-
if (meta.columns[propertyName]) {
|
|
11250
|
-
return;
|
|
11251
|
-
}
|
|
11252
|
-
addColumnMetadata(ctor, propertyName, column);
|
|
11253
|
-
};
|
|
11254
11731
|
var registerColumnFromContext = (context, column) => {
|
|
11255
11732
|
if (!context.name) {
|
|
11256
11733
|
throw new Error("Column decorator requires a property name");
|
|
11257
11734
|
}
|
|
11735
|
+
if (context.private) {
|
|
11736
|
+
throw new Error("Column decorator does not support private fields");
|
|
11737
|
+
}
|
|
11258
11738
|
const propertyName = normalizePropertyName(context.name);
|
|
11259
11739
|
const bag = getOrCreateMetadataBag(context);
|
|
11260
11740
|
if (!bag.columns.some((entry) => entry.propertyName === propertyName)) {
|
|
@@ -11263,19 +11743,9 @@ var registerColumnFromContext = (context, column) => {
|
|
|
11263
11743
|
};
|
|
11264
11744
|
function Column(definition) {
|
|
11265
11745
|
const normalized = normalizeColumnInput(definition);
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
registerColumnFromContext(propertyKeyOrContext, normalized);
|
|
11269
|
-
return;
|
|
11270
|
-
}
|
|
11271
|
-
const propertyName = normalizePropertyName(propertyKeyOrContext);
|
|
11272
|
-
const ctor = resolveConstructor(targetOrValue);
|
|
11273
|
-
if (!ctor) {
|
|
11274
|
-
throw new Error("Unable to resolve constructor when registering column metadata");
|
|
11275
|
-
}
|
|
11276
|
-
registerColumn(ctor, propertyName, { ...normalized });
|
|
11746
|
+
return function(_value, context) {
|
|
11747
|
+
registerColumnFromContext(context, normalized);
|
|
11277
11748
|
};
|
|
11278
|
-
return decorator;
|
|
11279
11749
|
}
|
|
11280
11750
|
function PrimaryKey(definition) {
|
|
11281
11751
|
const normalized = normalizeColumnInput(definition);
|
|
@@ -11290,41 +11760,21 @@ var normalizePropertyName2 = (name) => {
|
|
|
11290
11760
|
}
|
|
11291
11761
|
return name;
|
|
11292
11762
|
};
|
|
11293
|
-
var resolveConstructor2 = (instanceOrCtor) => {
|
|
11294
|
-
if (typeof instanceOrCtor === "function") {
|
|
11295
|
-
return instanceOrCtor;
|
|
11296
|
-
}
|
|
11297
|
-
if (instanceOrCtor && typeof instanceOrCtor.constructor === "function") {
|
|
11298
|
-
return instanceOrCtor.constructor;
|
|
11299
|
-
}
|
|
11300
|
-
return void 0;
|
|
11301
|
-
};
|
|
11302
|
-
var registerRelation = (ctor, propertyName, metadata) => {
|
|
11303
|
-
addRelationMetadata(ctor, propertyName, metadata);
|
|
11304
|
-
};
|
|
11305
11763
|
var createFieldDecorator = (metadataFactory) => {
|
|
11306
|
-
|
|
11307
|
-
if (
|
|
11308
|
-
|
|
11309
|
-
if (!ctx.name) {
|
|
11310
|
-
throw new Error("Relation decorator requires a property name");
|
|
11311
|
-
}
|
|
11312
|
-
const propertyName2 = normalizePropertyName2(ctx.name);
|
|
11313
|
-
const bag = getOrCreateMetadataBag(ctx);
|
|
11314
|
-
const relationMetadata = metadataFactory(propertyName2);
|
|
11315
|
-
if (!bag.relations.some((entry) => entry.propertyName === propertyName2)) {
|
|
11316
|
-
bag.relations.push({ propertyName: propertyName2, relation: relationMetadata });
|
|
11317
|
-
}
|
|
11318
|
-
return;
|
|
11764
|
+
return function(_value, context) {
|
|
11765
|
+
if (!context.name) {
|
|
11766
|
+
throw new Error("Relation decorator requires a property name");
|
|
11319
11767
|
}
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11768
|
+
if (context.private) {
|
|
11769
|
+
throw new Error("Relation decorator does not support private fields");
|
|
11770
|
+
}
|
|
11771
|
+
const propertyName = normalizePropertyName2(context.name);
|
|
11772
|
+
const bag = getOrCreateMetadataBag(context);
|
|
11773
|
+
const relationMetadata = metadataFactory(propertyName);
|
|
11774
|
+
if (!bag.relations.some((entry) => entry.propertyName === propertyName)) {
|
|
11775
|
+
bag.relations.push({ propertyName, relation: relationMetadata });
|
|
11324
11776
|
}
|
|
11325
|
-
registerRelation(ctor, propertyName, metadataFactory(propertyName));
|
|
11326
11777
|
};
|
|
11327
|
-
return decorator;
|
|
11328
11778
|
};
|
|
11329
11779
|
function HasMany(options) {
|
|
11330
11780
|
return createFieldDecorator((propertyName) => ({
|
|
@@ -11351,7 +11801,7 @@ function BelongsTo(options) {
|
|
|
11351
11801
|
kind: RelationKinds.BelongsTo,
|
|
11352
11802
|
propertyKey: propertyName,
|
|
11353
11803
|
target: options.target,
|
|
11354
|
-
foreignKey: options.foreignKey
|
|
11804
|
+
foreignKey: options.foreignKey ?? `${propertyName}_id`,
|
|
11355
11805
|
localKey: options.localKey,
|
|
11356
11806
|
cascade: options.cascade
|
|
11357
11807
|
}));
|
|
@@ -11427,13 +11877,15 @@ var deferred = () => {
|
|
|
11427
11877
|
return { promise, resolve, reject };
|
|
11428
11878
|
};
|
|
11429
11879
|
var Pool = class {
|
|
11880
|
+
adapter;
|
|
11881
|
+
options;
|
|
11882
|
+
destroyed = false;
|
|
11883
|
+
creating = 0;
|
|
11884
|
+
leased = 0;
|
|
11885
|
+
idle = [];
|
|
11886
|
+
waiters = [];
|
|
11887
|
+
reapTimer = null;
|
|
11430
11888
|
constructor(adapter, options) {
|
|
11431
|
-
this.destroyed = false;
|
|
11432
|
-
this.creating = 0;
|
|
11433
|
-
this.leased = 0;
|
|
11434
|
-
this.idle = [];
|
|
11435
|
-
this.waiters = [];
|
|
11436
|
-
this.reapTimer = null;
|
|
11437
11889
|
if (!Number.isFinite(options.max) || options.max <= 0) {
|
|
11438
11890
|
throw new Error("Pool options.max must be a positive number");
|
|
11439
11891
|
}
|
|
@@ -11995,6 +12447,8 @@ export {
|
|
|
11995
12447
|
esel,
|
|
11996
12448
|
executeHydrated,
|
|
11997
12449
|
executeHydratedWithContexts,
|
|
12450
|
+
executeSchemaSql,
|
|
12451
|
+
executeSchemaSqlFor,
|
|
11998
12452
|
exists,
|
|
11999
12453
|
exp,
|
|
12000
12454
|
extract,
|
|
@@ -12003,6 +12457,7 @@ export {
|
|
|
12003
12457
|
fromUnixTime,
|
|
12004
12458
|
generateCreateTableSql,
|
|
12005
12459
|
generateSchemaSql,
|
|
12460
|
+
generateSchemaSqlFor,
|
|
12006
12461
|
getColumn,
|
|
12007
12462
|
getDecoratorMetadata,
|
|
12008
12463
|
getSchemaIntrospector,
|
|
@@ -12108,6 +12563,7 @@ export {
|
|
|
12108
12563
|
second,
|
|
12109
12564
|
sel,
|
|
12110
12565
|
selectFromEntity,
|
|
12566
|
+
setRelations,
|
|
12111
12567
|
sha1,
|
|
12112
12568
|
sha2,
|
|
12113
12569
|
shiftLeft,
|