metal-orm 1.0.58 → 1.0.60
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 +1583 -901
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +400 -129
- package/dist/index.d.ts +400 -129
- package/dist/index.js +1575 -901
- 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/index.ts +7 -7
- 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 +329 -221
- 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,17 +4159,274 @@ var RelationService = class {
|
|
|
4343
4159
|
}
|
|
4344
4160
|
return candidate;
|
|
4345
4161
|
}
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4162
|
+
astService(state) {
|
|
4163
|
+
return this.createQueryAstService(this.table, state);
|
|
4164
|
+
}
|
|
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));
|
|
4349
4173
|
}
|
|
4350
|
-
|
|
4351
|
-
|
|
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);
|
|
4183
|
+
}
|
|
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 };
|
|
4190
|
+
}
|
|
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 };
|
|
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
|
|
4271
|
+
};
|
|
4272
|
+
|
|
4273
|
+
// src/query-builder/relation-service.ts
|
|
4274
|
+
var RelationService = class {
|
|
4275
|
+
/**
|
|
4276
|
+
* Creates a new RelationService instance
|
|
4277
|
+
* @param table - Table definition
|
|
4278
|
+
* @param state - Current query state
|
|
4279
|
+
* @param hydration - Hydration manager
|
|
4280
|
+
*/
|
|
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);
|
|
4292
|
+
}
|
|
4293
|
+
projectionHelper;
|
|
4294
|
+
joinPlanner;
|
|
4295
|
+
cteBuilder;
|
|
4296
|
+
/**
|
|
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
|
|
4302
|
+
*/
|
|
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 };
|
|
4314
|
+
}
|
|
4315
|
+
/**
|
|
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
|
|
4320
|
+
*/
|
|
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 };
|
|
4328
|
+
}
|
|
4329
|
+
/**
|
|
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);
|
|
4352
4349
|
}
|
|
4353
|
-
|
|
4354
|
-
|
|
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;
|
|
4355
4362
|
}
|
|
4356
|
-
|
|
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
|
+
};
|
|
4357
4430
|
}
|
|
4358
4431
|
/**
|
|
4359
4432
|
* Gets a relation definition by name
|
|
@@ -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) {
|
|
@@ -5489,156 +5614,61 @@ var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, o
|
|
|
5489
5614
|
const targetSelectedColumns = targetRequestedColumns ? [...targetRequestedColumns] : Object.keys(relation.target.columns);
|
|
5490
5615
|
if (!targetSelectedColumns.includes(targetKey)) {
|
|
5491
5616
|
targetSelectedColumns.push(targetKey);
|
|
5492
|
-
}
|
|
5493
|
-
const targetSelection = buildColumnSelection(
|
|
5494
|
-
relation.target,
|
|
5495
|
-
targetSelectedColumns,
|
|
5496
|
-
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5497
|
-
);
|
|
5498
|
-
const targetRows = await fetchRowsForKeys(
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
var relationLoaderCache = (meta, relationName, factory) => {
|
|
5519
|
-
if (meta.relationCache.has(relationName)) {
|
|
5520
|
-
return meta.relationCache.get(relationName);
|
|
5521
|
-
}
|
|
5522
|
-
const promise = factory().then((value) => {
|
|
5523
|
-
for (const tracked of meta.ctx.getEntitiesForTable(meta.table)) {
|
|
5524
|
-
const otherMeta = getEntityMeta(tracked.entity);
|
|
5525
|
-
if (!otherMeta) continue;
|
|
5526
|
-
otherMeta.relationHydration.set(relationName, value);
|
|
5527
|
-
}
|
|
5528
|
-
return value;
|
|
5529
|
-
});
|
|
5530
|
-
meta.relationCache.set(relationName, promise);
|
|
5531
|
-
for (const tracked of meta.ctx.getEntitiesForTable(meta.table)) {
|
|
5532
|
-
const otherMeta = getEntityMeta(tracked.entity);
|
|
5533
|
-
if (!otherMeta) continue;
|
|
5534
|
-
otherMeta.relationCache.set(relationName, promise);
|
|
5535
|
-
}
|
|
5536
|
-
return promise;
|
|
5537
|
-
};
|
|
5538
|
-
var createEntityProxy = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
5539
|
-
const target = { ...row };
|
|
5540
|
-
const meta = {
|
|
5541
|
-
ctx,
|
|
5542
|
-
table,
|
|
5543
|
-
lazyRelations: [...lazyRelations],
|
|
5544
|
-
lazyRelationOptions: new Map(lazyRelationOptions),
|
|
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
|
-
};
|
|
5567
|
-
}
|
|
5568
|
-
if (typeof prop === "string" && table.relations[prop]) {
|
|
5569
|
-
return getRelationWrapper(meta, prop, receiver);
|
|
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;
|
|
5617
|
+
}
|
|
5618
|
+
const targetSelection = buildColumnSelection(
|
|
5619
|
+
relation.target,
|
|
5620
|
+
targetSelectedColumns,
|
|
5621
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5622
|
+
);
|
|
5623
|
+
const targetRows = await fetchRowsForKeys(
|
|
5624
|
+
ctx,
|
|
5625
|
+
relation.target,
|
|
5626
|
+
targetPkColumn,
|
|
5627
|
+
targetIds,
|
|
5628
|
+
targetSelection,
|
|
5629
|
+
options?.filter
|
|
5630
|
+
);
|
|
5631
|
+
const targetMap = groupRowsByUnique(targetRows, targetKey);
|
|
5632
|
+
const targetVisibleColumns = new Set(targetSelectedColumns);
|
|
5633
|
+
const result = /* @__PURE__ */ new Map();
|
|
5634
|
+
for (const [rootId, entries] of rootLookup.entries()) {
|
|
5635
|
+
const bucket = [];
|
|
5636
|
+
for (const entry of entries) {
|
|
5637
|
+
const targetRow = targetMap.get(toKey7(entry.targetId));
|
|
5638
|
+
if (!targetRow) continue;
|
|
5639
|
+
bucket.push({
|
|
5640
|
+
...targetRequestedColumns ? filterRow(targetRow, targetVisibleColumns) : targetRow,
|
|
5641
|
+
_pivot: entry.pivot
|
|
5642
|
+
});
|
|
5626
5643
|
}
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5644
|
+
result.set(rootId, bucket);
|
|
5645
|
+
}
|
|
5646
|
+
return result;
|
|
5647
|
+
};
|
|
5648
|
+
|
|
5649
|
+
// src/orm/entity-relation-cache.ts
|
|
5650
|
+
var relationLoaderCache = (meta, relationName, factory) => {
|
|
5651
|
+
if (meta.relationCache.has(relationName)) {
|
|
5652
|
+
return meta.relationCache.get(relationName);
|
|
5653
|
+
}
|
|
5654
|
+
const promise = factory().then((value) => {
|
|
5655
|
+
for (const tracked of meta.ctx.getEntitiesForTable(meta.table)) {
|
|
5656
|
+
const otherMeta = getEntityMeta(tracked.entity);
|
|
5657
|
+
if (!otherMeta) continue;
|
|
5658
|
+
otherMeta.relationHydration.set(relationName, value);
|
|
5639
5659
|
}
|
|
5660
|
+
return value;
|
|
5661
|
+
});
|
|
5662
|
+
meta.relationCache.set(relationName, promise);
|
|
5663
|
+
for (const tracked of meta.ctx.getEntitiesForTable(meta.table)) {
|
|
5664
|
+
const otherMeta = getEntityMeta(tracked.entity);
|
|
5665
|
+
if (!otherMeta) continue;
|
|
5666
|
+
otherMeta.relationCache.set(relationName, promise);
|
|
5640
5667
|
}
|
|
5668
|
+
return promise;
|
|
5641
5669
|
};
|
|
5670
|
+
|
|
5671
|
+
// src/orm/entity-relations.ts
|
|
5642
5672
|
var proxifyRelationWrapper = (wrapper) => {
|
|
5643
5673
|
return new Proxy(wrapper, {
|
|
5644
5674
|
get(target, prop, receiver) {
|
|
@@ -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,6 +5816,71 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
5791
5816
|
}
|
|
5792
5817
|
};
|
|
5793
5818
|
|
|
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
|
+
|
|
5794
5884
|
// src/orm/execute.ts
|
|
5795
5885
|
var flattenResults = (results) => {
|
|
5796
5886
|
const rows = [];
|
|
@@ -5880,14 +5970,416 @@ var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOp
|
|
|
5880
5970
|
}
|
|
5881
5971
|
};
|
|
5882
5972
|
|
|
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
|
-
}
|
|
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;
|
|
6301
|
+
}
|
|
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 };
|
|
6313
|
+
}
|
|
6314
|
+
};
|
|
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;
|
|
6324
|
+
}
|
|
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);
|
|
6366
|
+
}
|
|
6367
|
+
};
|
|
5888
6368
|
|
|
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
|
|
@@ -5928,14 +6428,11 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5928
6428
|
/**
|
|
5929
6429
|
* Applies an alias to the root FROM table.
|
|
5930
6430
|
* @param alias - Alias to apply
|
|
6431
|
+
* @example
|
|
6432
|
+
* const qb = new SelectQueryBuilder(userTable).as('u');
|
|
5931
6433
|
*/
|
|
5932
6434
|
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));
|
|
6435
|
+
const nextContext = this.fromFacet.as(this.context, alias);
|
|
5939
6436
|
return this.clone(nextContext);
|
|
5940
6437
|
}
|
|
5941
6438
|
/**
|
|
@@ -5960,29 +6457,6 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5960
6457
|
createChildBuilder(table) {
|
|
5961
6458
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
5962
6459
|
}
|
|
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
6460
|
/**
|
|
5987
6461
|
* Applies a set operation to the query
|
|
5988
6462
|
* @param operator - Set operation kind
|
|
@@ -5991,12 +6465,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5991
6465
|
*/
|
|
5992
6466
|
applySetOperation(operator, query) {
|
|
5993
6467
|
const subAst = resolveSelectQuery(query);
|
|
5994
|
-
return this.
|
|
6468
|
+
return this.setOpFacet.applySetOperation(this.context, operator, subAst);
|
|
5995
6469
|
}
|
|
5996
6470
|
select(...args) {
|
|
5997
6471
|
if (args.length === 1 && typeof args[0] === "object" && args[0] !== null && typeof args[0] !== "string") {
|
|
5998
6472
|
const columns = args[0];
|
|
5999
|
-
return this.clone(this.
|
|
6473
|
+
return this.clone(this.projectionFacet.select(this.context, columns));
|
|
6000
6474
|
}
|
|
6001
6475
|
const cols = args;
|
|
6002
6476
|
const selection = {};
|
|
@@ -6007,15 +6481,17 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6007
6481
|
}
|
|
6008
6482
|
selection[key] = col2;
|
|
6009
6483
|
}
|
|
6010
|
-
return this.clone(this.
|
|
6484
|
+
return this.clone(this.projectionFacet.select(this.context, selection));
|
|
6011
6485
|
}
|
|
6012
6486
|
/**
|
|
6013
6487
|
* Selects raw column expressions
|
|
6014
6488
|
* @param cols - Column expressions as strings
|
|
6015
6489
|
* @returns New query builder instance with raw column selections
|
|
6490
|
+
* @example
|
|
6491
|
+
* qb.selectRaw('COUNT(*) as total', 'UPPER(name) as upper_name');
|
|
6016
6492
|
*/
|
|
6017
6493
|
selectRaw(...cols) {
|
|
6018
|
-
return this.clone(this.
|
|
6494
|
+
return this.clone(this.projectionFacet.selectRaw(this.context, cols));
|
|
6019
6495
|
}
|
|
6020
6496
|
/**
|
|
6021
6497
|
* Adds a Common Table Expression (CTE) to the query
|
|
@@ -6023,10 +6499,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6023
6499
|
* @param query - Query builder or query node for the CTE
|
|
6024
6500
|
* @param columns - Optional column names for the CTE
|
|
6025
6501
|
* @returns New query builder instance with the CTE
|
|
6502
|
+
* @example
|
|
6503
|
+
* const recentUsers = new SelectQueryBuilder(userTable)
|
|
6504
|
+
* .where(gt(userTable.columns.createdAt, subDays(now(), 30)));
|
|
6505
|
+
* const qb = new SelectQueryBuilder(userTable)
|
|
6506
|
+
* .with('recent_users', recentUsers)
|
|
6507
|
+
* .from('recent_users');
|
|
6026
6508
|
*/
|
|
6027
6509
|
with(name, query, columns) {
|
|
6028
6510
|
const subAst = resolveSelectQuery(query);
|
|
6029
|
-
const nextContext = this.
|
|
6511
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, false);
|
|
6030
6512
|
return this.clone(nextContext);
|
|
6031
6513
|
}
|
|
6032
6514
|
/**
|
|
@@ -6035,10 +6517,23 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6035
6517
|
* @param query - Query builder or query node for the CTE
|
|
6036
6518
|
* @param columns - Optional column names for the CTE
|
|
6037
6519
|
* @returns New query builder instance with the recursive CTE
|
|
6520
|
+
* @example
|
|
6521
|
+
* // Base case: select root nodes
|
|
6522
|
+
* const baseQuery = new SelectQueryBuilder(orgTable)
|
|
6523
|
+
* .where(eq(orgTable.columns.parentId, 1));
|
|
6524
|
+
* // Recursive case: join with the CTE itself
|
|
6525
|
+
* const recursiveQuery = new SelectQueryBuilder(orgTable)
|
|
6526
|
+
* .join('org_hierarchy', 'oh', eq(orgTable.columns.parentId, col('oh.id')));
|
|
6527
|
+
* // Combine base and recursive parts
|
|
6528
|
+
* const orgHierarchy = baseQuery.union(recursiveQuery);
|
|
6529
|
+
* // Use in main query
|
|
6530
|
+
* const qb = new SelectQueryBuilder(orgTable)
|
|
6531
|
+
* .withRecursive('org_hierarchy', orgHierarchy)
|
|
6532
|
+
* .from('org_hierarchy');
|
|
6038
6533
|
*/
|
|
6039
6534
|
withRecursive(name, query, columns) {
|
|
6040
6535
|
const subAst = resolveSelectQuery(query);
|
|
6041
|
-
const nextContext = this.
|
|
6536
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, true);
|
|
6042
6537
|
return this.clone(nextContext);
|
|
6043
6538
|
}
|
|
6044
6539
|
/**
|
|
@@ -6047,11 +6542,15 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6047
6542
|
* @param alias - Alias for the derived table
|
|
6048
6543
|
* @param columnAliases - Optional column alias list
|
|
6049
6544
|
* @returns New query builder instance with updated FROM
|
|
6545
|
+
* @example
|
|
6546
|
+
* const subquery = new SelectQueryBuilder(userTable)
|
|
6547
|
+
* .select('id', 'name')
|
|
6548
|
+
* .where(gt(userTable.columns.score, 100));
|
|
6549
|
+
* qb.fromSubquery(subquery, 'high_scorers', ['userId', 'userName']);
|
|
6050
6550
|
*/
|
|
6051
6551
|
fromSubquery(subquery, alias, columnAliases) {
|
|
6052
6552
|
const subAst = resolveSelectQuery(subquery);
|
|
6053
|
-
const
|
|
6054
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
|
|
6553
|
+
const nextContext = this.fromFacet.fromSubquery(this.context, subAst, alias, columnAliases);
|
|
6055
6554
|
return this.clone(nextContext);
|
|
6056
6555
|
}
|
|
6057
6556
|
/**
|
|
@@ -6060,10 +6559,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6060
6559
|
* @param args - Optional function arguments
|
|
6061
6560
|
* @param alias - Optional alias for the function table
|
|
6062
6561
|
* @param options - Optional function-table metadata (lateral, ordinality, column aliases, schema)
|
|
6562
|
+
* @example
|
|
6563
|
+
* qb.fromFunctionTable(
|
|
6564
|
+
* 'generate_series',
|
|
6565
|
+
* [literal(1), literal(10), literal(1)],
|
|
6566
|
+
* 'series',
|
|
6567
|
+
* { columnAliases: ['value'] }
|
|
6568
|
+
* );
|
|
6063
6569
|
*/
|
|
6064
6570
|
fromFunctionTable(name, args = [], alias, options) {
|
|
6065
|
-
const
|
|
6066
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(functionTable));
|
|
6571
|
+
const nextContext = this.fromFacet.fromFunctionTable(this.context, name, args, alias, options);
|
|
6067
6572
|
return this.clone(nextContext);
|
|
6068
6573
|
}
|
|
6069
6574
|
/**
|
|
@@ -6071,10 +6576,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6071
6576
|
* @param alias - Alias for the subquery column
|
|
6072
6577
|
* @param sub - Query builder or query node for the subquery
|
|
6073
6578
|
* @returns New query builder instance with the subquery selection
|
|
6579
|
+
* @example
|
|
6580
|
+
* const postCount = new SelectQueryBuilder(postTable)
|
|
6581
|
+
* .select(count(postTable.columns.id))
|
|
6582
|
+
* .where(eq(postTable.columns.userId, col('u.id')));
|
|
6583
|
+
* qb.select('id', 'name')
|
|
6584
|
+
* .selectSubquery('postCount', postCount);
|
|
6074
6585
|
*/
|
|
6075
6586
|
selectSubquery(alias, sub2) {
|
|
6076
6587
|
const query = resolveSelectQuery(sub2);
|
|
6077
|
-
return this.clone(this.
|
|
6588
|
+
return this.clone(this.projectionFacet.selectSubquery(this.context, alias, query));
|
|
6078
6589
|
}
|
|
6079
6590
|
/**
|
|
6080
6591
|
* Adds a JOIN against a derived table (subquery with alias)
|
|
@@ -6084,11 +6595,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6084
6595
|
* @param joinKind - Join kind (defaults to INNER)
|
|
6085
6596
|
* @param columnAliases - Optional column alias list for the derived table
|
|
6086
6597
|
* @returns New query builder instance with the derived-table join
|
|
6598
|
+
* @example
|
|
6599
|
+
* const activeUsers = new SelectQueryBuilder(userTable)
|
|
6600
|
+
* .where(eq(userTable.columns.active, true));
|
|
6601
|
+
* qb.joinSubquery(
|
|
6602
|
+
* activeUsers,
|
|
6603
|
+
* 'au',
|
|
6604
|
+
* eq(col('t.userId'), col('au.id')),
|
|
6605
|
+
* JOIN_KINDS.LEFT
|
|
6606
|
+
* );
|
|
6087
6607
|
*/
|
|
6088
6608
|
joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
|
|
6089
6609
|
const subAst = resolveSelectQuery(subquery);
|
|
6090
|
-
const
|
|
6091
|
-
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
6610
|
+
const nextContext = this.joinFacet.joinSubquery(this.context, subAst, alias, condition, joinKind, columnAliases);
|
|
6092
6611
|
return this.clone(nextContext);
|
|
6093
6612
|
}
|
|
6094
6613
|
/**
|
|
@@ -6099,11 +6618,18 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6099
6618
|
* @param condition - Join condition expression
|
|
6100
6619
|
* @param joinKind - Kind of join (defaults to INNER)
|
|
6101
6620
|
* @param options - Optional metadata (lateral, ordinality, column aliases, schema)
|
|
6621
|
+
* @example
|
|
6622
|
+
* qb.joinFunctionTable(
|
|
6623
|
+
* 'generate_series',
|
|
6624
|
+
* [literal(1), literal(10)],
|
|
6625
|
+
* 'gs',
|
|
6626
|
+
* eq(col('t.value'), col('gs.value')),
|
|
6627
|
+
* JOIN_KINDS.INNER,
|
|
6628
|
+
* { columnAliases: ['value'] }
|
|
6629
|
+
* );
|
|
6102
6630
|
*/
|
|
6103
6631
|
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));
|
|
6632
|
+
const nextContext = this.joinFacet.joinFunctionTable(this.context, name, args, alias, condition, joinKind, options);
|
|
6107
6633
|
return this.clone(nextContext);
|
|
6108
6634
|
}
|
|
6109
6635
|
/**
|
|
@@ -6111,9 +6637,14 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6111
6637
|
* @param table - Table to join
|
|
6112
6638
|
* @param condition - Join condition expression
|
|
6113
6639
|
* @returns New query builder instance with the INNER JOIN
|
|
6640
|
+
* @example
|
|
6641
|
+
* qb.innerJoin(
|
|
6642
|
+
* postTable,
|
|
6643
|
+
* eq(userTable.columns.id, postTable.columns.userId)
|
|
6644
|
+
* );
|
|
6114
6645
|
*/
|
|
6115
6646
|
innerJoin(table, condition) {
|
|
6116
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
6647
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
6117
6648
|
return this.clone(nextContext);
|
|
6118
6649
|
}
|
|
6119
6650
|
/**
|
|
@@ -6121,9 +6652,14 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6121
6652
|
* @param table - Table to join
|
|
6122
6653
|
* @param condition - Join condition expression
|
|
6123
6654
|
* @returns New query builder instance with the LEFT JOIN
|
|
6655
|
+
* @example
|
|
6656
|
+
* qb.leftJoin(
|
|
6657
|
+
* postTable,
|
|
6658
|
+
* eq(userTable.columns.id, postTable.columns.userId)
|
|
6659
|
+
* );
|
|
6124
6660
|
*/
|
|
6125
6661
|
leftJoin(table, condition) {
|
|
6126
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
6662
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
6127
6663
|
return this.clone(nextContext);
|
|
6128
6664
|
}
|
|
6129
6665
|
/**
|
|
@@ -6131,9 +6667,14 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6131
6667
|
* @param table - Table to join
|
|
6132
6668
|
* @param condition - Join condition expression
|
|
6133
6669
|
* @returns New query builder instance with the RIGHT JOIN
|
|
6670
|
+
* @example
|
|
6671
|
+
* qb.rightJoin(
|
|
6672
|
+
* postTable,
|
|
6673
|
+
* eq(userTable.columns.id, postTable.columns.userId)
|
|
6674
|
+
* );
|
|
6134
6675
|
*/
|
|
6135
6676
|
rightJoin(table, condition) {
|
|
6136
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
6677
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
6137
6678
|
return this.clone(nextContext);
|
|
6138
6679
|
}
|
|
6139
6680
|
/**
|
|
@@ -6141,9 +6682,11 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6141
6682
|
* @param relationName - Name of the relationship to match
|
|
6142
6683
|
* @param predicate - Optional predicate expression
|
|
6143
6684
|
* @returns New query builder instance with the relationship match
|
|
6685
|
+
* @example
|
|
6686
|
+
* qb.match('posts', eq(postTable.columns.published, true));
|
|
6144
6687
|
*/
|
|
6145
6688
|
match(relationName, predicate) {
|
|
6146
|
-
const nextContext = this.
|
|
6689
|
+
const nextContext = this.relationFacet.match(this.context, relationName, predicate);
|
|
6147
6690
|
return this.clone(nextContext);
|
|
6148
6691
|
}
|
|
6149
6692
|
/**
|
|
@@ -6152,9 +6695,13 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6152
6695
|
* @param joinKind - Type of join (defaults to INNER)
|
|
6153
6696
|
* @param extraCondition - Optional additional join condition
|
|
6154
6697
|
* @returns New query builder instance with the relationship join
|
|
6698
|
+
* @example
|
|
6699
|
+
* qb.joinRelation('posts', JOIN_KINDS.LEFT);
|
|
6700
|
+
* @example
|
|
6701
|
+
* qb.joinRelation('posts', JOIN_KINDS.INNER, eq(postTable.columns.published, true));
|
|
6155
6702
|
*/
|
|
6156
6703
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
6157
|
-
const nextContext = this.
|
|
6704
|
+
const nextContext = this.relationFacet.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
6158
6705
|
return this.clone(nextContext);
|
|
6159
6706
|
}
|
|
6160
6707
|
/**
|
|
@@ -6162,9 +6709,18 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6162
6709
|
* @param relationName - Name of the relationship to include
|
|
6163
6710
|
* @param options - Optional include options
|
|
6164
6711
|
* @returns New query builder instance with the relationship inclusion
|
|
6712
|
+
* @example
|
|
6713
|
+
* qb.include('posts');
|
|
6714
|
+
* @example
|
|
6715
|
+
* qb.include('posts', { columns: ['id', 'title', 'published'] });
|
|
6716
|
+
* @example
|
|
6717
|
+
* qb.include('posts', {
|
|
6718
|
+
* columns: ['id', 'title'],
|
|
6719
|
+
* where: eq(postTable.columns.published, true)
|
|
6720
|
+
* });
|
|
6165
6721
|
*/
|
|
6166
6722
|
include(relationName, options) {
|
|
6167
|
-
const nextContext = this.
|
|
6723
|
+
const nextContext = this.relationFacet.include(this.context, relationName, options);
|
|
6168
6724
|
return this.clone(nextContext);
|
|
6169
6725
|
}
|
|
6170
6726
|
/**
|
|
@@ -6172,6 +6728,11 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6172
6728
|
* @param relationName - Name of the relation to include lazily
|
|
6173
6729
|
* @param options - Optional include options for lazy loading
|
|
6174
6730
|
* @returns New query builder instance with lazy relation inclusion
|
|
6731
|
+
* @example
|
|
6732
|
+
* const qb = new SelectQueryBuilder(userTable).includeLazy('posts');
|
|
6733
|
+
* const users = await qb.execute(session);
|
|
6734
|
+
* // Access posts later - they will be loaded on demand
|
|
6735
|
+
* const posts = await users[0].posts;
|
|
6175
6736
|
*/
|
|
6176
6737
|
includeLazy(relationName, options) {
|
|
6177
6738
|
let nextContext = this.context;
|
|
@@ -6201,14 +6762,22 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6201
6762
|
}
|
|
6202
6763
|
/**
|
|
6203
6764
|
* Convenience alias for including only specific columns from a relation.
|
|
6765
|
+
* @example
|
|
6766
|
+
* qb.includePick('posts', ['id', 'title', 'createdAt']);
|
|
6204
6767
|
*/
|
|
6205
6768
|
includePick(relationName, cols) {
|
|
6206
|
-
|
|
6769
|
+
const options = { columns: cols };
|
|
6770
|
+
return this.include(relationName, options);
|
|
6207
6771
|
}
|
|
6208
6772
|
/**
|
|
6209
6773
|
* Selects columns for the root table and relations from an array of entries
|
|
6210
6774
|
* @param config - Configuration array for deep column selection
|
|
6211
6775
|
* @returns New query builder instance with deep column selections
|
|
6776
|
+
* @example
|
|
6777
|
+
* qb.selectColumnsDeep([
|
|
6778
|
+
* { type: 'root', columns: ['id', 'name'] },
|
|
6779
|
+
* { type: 'relation', relationName: 'posts', columns: ['id', 'title'] }
|
|
6780
|
+
* ]);
|
|
6212
6781
|
*/
|
|
6213
6782
|
selectColumnsDeep(config) {
|
|
6214
6783
|
let currBuilder = this;
|
|
@@ -6216,7 +6785,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6216
6785
|
if (entry.type === "root") {
|
|
6217
6786
|
currBuilder = currBuilder.select(...entry.columns);
|
|
6218
6787
|
} else {
|
|
6219
|
-
|
|
6788
|
+
const options = { columns: entry.columns };
|
|
6789
|
+
currBuilder = currBuilder.include(entry.relationName, options);
|
|
6220
6790
|
}
|
|
6221
6791
|
}
|
|
6222
6792
|
return currBuilder;
|
|
@@ -6246,61 +6816,41 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6246
6816
|
* Executes the query and returns hydrated results
|
|
6247
6817
|
* @param ctx - ORM session context
|
|
6248
6818
|
* @returns Promise of entity instances
|
|
6819
|
+
* @example
|
|
6820
|
+
* const users = await qb.select('id', 'name')
|
|
6821
|
+
* .where(eq(userTable.columns.active, true))
|
|
6822
|
+
* .execute(session);
|
|
6249
6823
|
*/
|
|
6250
6824
|
async execute(ctx) {
|
|
6251
6825
|
return executeHydrated(ctx, this);
|
|
6252
6826
|
}
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
return this.clone(nextContext);
|
|
6260
|
-
}
|
|
6827
|
+
/**
|
|
6828
|
+
* Executes a count query for the current builder without LIMIT/OFFSET clauses.
|
|
6829
|
+
*
|
|
6830
|
+
* @example
|
|
6831
|
+
* const total = await qb.count(session);
|
|
6832
|
+
*/
|
|
6261
6833
|
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);
|
|
6834
|
+
return executeCount(this.context, this.env, session);
|
|
6283
6835
|
}
|
|
6836
|
+
/**
|
|
6837
|
+
* Executes the query and returns both the paged items and the total.
|
|
6838
|
+
*
|
|
6839
|
+
* @example
|
|
6840
|
+
* const { items, totalItems } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
6841
|
+
*/
|
|
6284
6842
|
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 };
|
|
6843
|
+
return executePagedQuery(this, session, options, (sess) => this.count(sess));
|
|
6298
6844
|
}
|
|
6299
6845
|
/**
|
|
6300
6846
|
* Executes the query with provided execution and hydration contexts
|
|
6301
6847
|
* @param execCtx - Execution context
|
|
6302
6848
|
* @param hydCtx - Hydration context
|
|
6303
6849
|
* @returns Promise of entity instances
|
|
6850
|
+
* @example
|
|
6851
|
+
* const execCtx = new ExecutionContext(session);
|
|
6852
|
+
* const hydCtx = new HydrationContext();
|
|
6853
|
+
* const users = await qb.executeWithContexts(execCtx, hydCtx);
|
|
6304
6854
|
*/
|
|
6305
6855
|
async executeWithContexts(execCtx, hydCtx) {
|
|
6306
6856
|
return executeHydratedWithContexts(execCtx, hydCtx, this);
|
|
@@ -6309,27 +6859,41 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6309
6859
|
* Adds a WHERE condition to the query
|
|
6310
6860
|
* @param expr - Expression for the WHERE clause
|
|
6311
6861
|
* @returns New query builder instance with the WHERE condition
|
|
6862
|
+
* @example
|
|
6863
|
+
* qb.where(eq(userTable.columns.id, 1));
|
|
6864
|
+
* @example
|
|
6865
|
+
* qb.where(and(
|
|
6866
|
+
* eq(userTable.columns.active, true),
|
|
6867
|
+
* gt(userTable.columns.createdAt, subDays(now(), 30))
|
|
6868
|
+
* ));
|
|
6312
6869
|
*/
|
|
6313
6870
|
where(expr) {
|
|
6314
|
-
const nextContext = this.
|
|
6871
|
+
const nextContext = this.predicateFacet.where(this.context, expr);
|
|
6315
6872
|
return this.clone(nextContext);
|
|
6316
6873
|
}
|
|
6317
6874
|
/**
|
|
6318
6875
|
* Adds a GROUP BY clause to the query
|
|
6319
6876
|
* @param term - Column definition or ordering term to group by
|
|
6320
6877
|
* @returns New query builder instance with the GROUP BY clause
|
|
6878
|
+
* @example
|
|
6879
|
+
* qb.select('departmentId', count(userTable.columns.id))
|
|
6880
|
+
* .groupBy(userTable.columns.departmentId);
|
|
6321
6881
|
*/
|
|
6322
6882
|
groupBy(term) {
|
|
6323
|
-
const nextContext = this.
|
|
6883
|
+
const nextContext = this.predicateFacet.groupBy(this.context, term);
|
|
6324
6884
|
return this.clone(nextContext);
|
|
6325
6885
|
}
|
|
6326
6886
|
/**
|
|
6327
6887
|
* Adds a HAVING condition to the query
|
|
6328
6888
|
* @param expr - Expression for the HAVING clause
|
|
6329
6889
|
* @returns New query builder instance with the HAVING condition
|
|
6890
|
+
* @example
|
|
6891
|
+
* qb.select('departmentId', count(userTable.columns.id))
|
|
6892
|
+
* .groupBy(userTable.columns.departmentId)
|
|
6893
|
+
* .having(gt(count(userTable.columns.id), 5));
|
|
6330
6894
|
*/
|
|
6331
6895
|
having(expr) {
|
|
6332
|
-
const nextContext = this.
|
|
6896
|
+
const nextContext = this.predicateFacet.having(this.context, expr);
|
|
6333
6897
|
return this.clone(nextContext);
|
|
6334
6898
|
}
|
|
6335
6899
|
/**
|
|
@@ -6337,46 +6901,62 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6337
6901
|
* @param term - Column definition or ordering term to order by
|
|
6338
6902
|
* @param directionOrOptions - Order direction or options (defaults to ASC)
|
|
6339
6903
|
* @returns New query builder instance with the ORDER BY clause
|
|
6904
|
+
*
|
|
6905
|
+
* @example
|
|
6906
|
+
* qb.orderBy(userTable.columns.createdAt, 'DESC');
|
|
6340
6907
|
*/
|
|
6341
6908
|
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
|
-
);
|
|
6909
|
+
const nextContext = applyOrderBy(this.context, this.predicateFacet, term, directionOrOptions);
|
|
6348
6910
|
return this.clone(nextContext);
|
|
6349
6911
|
}
|
|
6350
6912
|
/**
|
|
6351
6913
|
* Adds a DISTINCT clause to the query
|
|
6352
6914
|
* @param cols - Columns to make distinct
|
|
6353
6915
|
* @returns New query builder instance with the DISTINCT clause
|
|
6916
|
+
* @example
|
|
6917
|
+
* qb.distinct(userTable.columns.email);
|
|
6918
|
+
* @example
|
|
6919
|
+
* qb.distinct(userTable.columns.firstName, userTable.columns.lastName);
|
|
6354
6920
|
*/
|
|
6355
6921
|
distinct(...cols) {
|
|
6356
|
-
return this.clone(this.
|
|
6922
|
+
return this.clone(this.projectionFacet.distinct(this.context, cols));
|
|
6357
6923
|
}
|
|
6358
6924
|
/**
|
|
6359
6925
|
* Adds a LIMIT clause to the query
|
|
6360
6926
|
* @param n - Maximum number of rows to return
|
|
6361
6927
|
* @returns New query builder instance with the LIMIT clause
|
|
6928
|
+
* @example
|
|
6929
|
+
* qb.limit(10);
|
|
6930
|
+
* @example
|
|
6931
|
+
* qb.limit(20).offset(40); // Pagination: page 3 with 20 items per page
|
|
6362
6932
|
*/
|
|
6363
6933
|
limit(n) {
|
|
6364
|
-
const nextContext = this.
|
|
6934
|
+
const nextContext = this.predicateFacet.limit(this.context, n);
|
|
6365
6935
|
return this.clone(nextContext);
|
|
6366
6936
|
}
|
|
6367
6937
|
/**
|
|
6368
6938
|
* Adds an OFFSET clause to the query
|
|
6369
6939
|
* @param n - Number of rows to skip
|
|
6370
6940
|
* @returns New query builder instance with the OFFSET clause
|
|
6941
|
+
* @example
|
|
6942
|
+
* qb.offset(10);
|
|
6943
|
+
* @example
|
|
6944
|
+
* qb.limit(20).offset(40); // Pagination: page 3 with 20 items per page
|
|
6371
6945
|
*/
|
|
6372
6946
|
offset(n) {
|
|
6373
|
-
const nextContext = this.
|
|
6947
|
+
const nextContext = this.predicateFacet.offset(this.context, n);
|
|
6374
6948
|
return this.clone(nextContext);
|
|
6375
6949
|
}
|
|
6376
6950
|
/**
|
|
6377
6951
|
* Combines this query with another using UNION
|
|
6378
6952
|
* @param query - Query to union with
|
|
6379
6953
|
* @returns New query builder instance with the set operation
|
|
6954
|
+
* @example
|
|
6955
|
+
* const activeUsers = new SelectQueryBuilder(userTable)
|
|
6956
|
+
* .where(eq(userTable.columns.active, true));
|
|
6957
|
+
* const inactiveUsers = new SelectQueryBuilder(userTable)
|
|
6958
|
+
* .where(eq(userTable.columns.active, false));
|
|
6959
|
+
* qb.union(activeUsers).union(inactiveUsers);
|
|
6380
6960
|
*/
|
|
6381
6961
|
union(query) {
|
|
6382
6962
|
return this.clone(this.applySetOperation("UNION", query));
|
|
@@ -6385,6 +6965,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6385
6965
|
* Combines this query with another using UNION ALL
|
|
6386
6966
|
* @param query - Query to union with
|
|
6387
6967
|
* @returns New query builder instance with the set operation
|
|
6968
|
+
* @example
|
|
6969
|
+
* const q1 = new SelectQueryBuilder(userTable).where(gt(userTable.columns.score, 80));
|
|
6970
|
+
* const q2 = new SelectQueryBuilder(userTable).where(lt(userTable.columns.score, 20));
|
|
6971
|
+
* qb.unionAll(q1).unionAll(q2);
|
|
6388
6972
|
*/
|
|
6389
6973
|
unionAll(query) {
|
|
6390
6974
|
return this.clone(this.applySetOperation("UNION ALL", query));
|
|
@@ -6393,6 +6977,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6393
6977
|
* Combines this query with another using INTERSECT
|
|
6394
6978
|
* @param query - Query to intersect with
|
|
6395
6979
|
* @returns New query builder instance with the set operation
|
|
6980
|
+
* @example
|
|
6981
|
+
* const activeUsers = new SelectQueryBuilder(userTable)
|
|
6982
|
+
* .where(eq(userTable.columns.active, true));
|
|
6983
|
+
* const premiumUsers = new SelectQueryBuilder(userTable)
|
|
6984
|
+
* .where(eq(userTable.columns.premium, true));
|
|
6985
|
+
* qb.intersect(activeUsers).intersect(premiumUsers);
|
|
6396
6986
|
*/
|
|
6397
6987
|
intersect(query) {
|
|
6398
6988
|
return this.clone(this.applySetOperation("INTERSECT", query));
|
|
@@ -6401,6 +6991,11 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6401
6991
|
* Combines this query with another using EXCEPT
|
|
6402
6992
|
* @param query - Query to subtract
|
|
6403
6993
|
* @returns New query builder instance with the set operation
|
|
6994
|
+
* @example
|
|
6995
|
+
* const allUsers = new SelectQueryBuilder(userTable);
|
|
6996
|
+
* const inactiveUsers = new SelectQueryBuilder(userTable)
|
|
6997
|
+
* .where(eq(userTable.columns.active, false));
|
|
6998
|
+
* qb.except(allUsers).except(inactiveUsers); // Only active users
|
|
6404
6999
|
*/
|
|
6405
7000
|
except(query) {
|
|
6406
7001
|
return this.clone(this.applySetOperation("EXCEPT", query));
|
|
@@ -6409,6 +7004,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6409
7004
|
* Adds a WHERE EXISTS condition to the query
|
|
6410
7005
|
* @param subquery - Subquery to check for existence
|
|
6411
7006
|
* @returns New query builder instance with the WHERE EXISTS condition
|
|
7007
|
+
* @example
|
|
7008
|
+
* const postsQuery = new SelectQueryBuilder(postTable)
|
|
7009
|
+
* .where(eq(postTable.columns.userId, col('u.id')));
|
|
7010
|
+
* qb.whereExists(postsQuery);
|
|
6412
7011
|
*/
|
|
6413
7012
|
whereExists(subquery, correlate) {
|
|
6414
7013
|
const subAst = resolveSelectQuery(subquery);
|
|
@@ -6419,6 +7018,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6419
7018
|
* Adds a WHERE NOT EXISTS condition to the query
|
|
6420
7019
|
* @param subquery - Subquery to check for non-existence
|
|
6421
7020
|
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
7021
|
+
* @example
|
|
7022
|
+
* const postsQuery = new SelectQueryBuilder(postTable)
|
|
7023
|
+
* .where(eq(postTable.columns.userId, col('u.id')));
|
|
7024
|
+
* qb.whereNotExists(postsQuery); // Users without posts
|
|
6422
7025
|
*/
|
|
6423
7026
|
whereNotExists(subquery, correlate) {
|
|
6424
7027
|
const subAst = resolveSelectQuery(subquery);
|
|
@@ -6430,47 +7033,54 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6430
7033
|
* @param relationName - Name of the relationship to check
|
|
6431
7034
|
* @param callback - Optional callback to modify the relationship query
|
|
6432
7035
|
* @returns New query builder instance with the relationship existence check
|
|
7036
|
+
*
|
|
7037
|
+
* @example
|
|
7038
|
+
* qb.whereHas('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
6433
7039
|
*/
|
|
6434
7040
|
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));
|
|
7041
|
+
const predicate = buildWhereHasPredicate(
|
|
7042
|
+
this.env,
|
|
7043
|
+
this.context,
|
|
7044
|
+
this.relationFacet,
|
|
7045
|
+
(table) => this.createChildBuilder(table),
|
|
7046
|
+
relationName,
|
|
7047
|
+
callbackOrOptions,
|
|
7048
|
+
maybeOptions,
|
|
7049
|
+
false
|
|
7050
|
+
);
|
|
7051
|
+
return this.where(predicate);
|
|
6448
7052
|
}
|
|
6449
7053
|
/**
|
|
6450
7054
|
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
6451
7055
|
* @param relationName - Name of the relationship to check
|
|
6452
7056
|
* @param callback - Optional callback to modify the relationship query
|
|
6453
7057
|
* @returns New query builder instance with the relationship non-existence check
|
|
7058
|
+
*
|
|
7059
|
+
* @example
|
|
7060
|
+
* qb.whereHasNot('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
6454
7061
|
*/
|
|
6455
7062
|
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));
|
|
7063
|
+
const predicate = buildWhereHasPredicate(
|
|
7064
|
+
this.env,
|
|
7065
|
+
this.context,
|
|
7066
|
+
this.relationFacet,
|
|
7067
|
+
(table) => this.createChildBuilder(table),
|
|
7068
|
+
relationName,
|
|
7069
|
+
callbackOrOptions,
|
|
7070
|
+
maybeOptions,
|
|
7071
|
+
true
|
|
7072
|
+
);
|
|
7073
|
+
return this.where(predicate);
|
|
6469
7074
|
}
|
|
6470
7075
|
/**
|
|
6471
7076
|
* Compiles the query to SQL for a specific dialect
|
|
6472
7077
|
* @param dialect - Database dialect to compile for
|
|
6473
7078
|
* @returns Compiled query with SQL and parameters
|
|
7079
|
+
* @example
|
|
7080
|
+
* const compiled = qb.select('id', 'name')
|
|
7081
|
+
* .where(eq(userTable.columns.active, true))
|
|
7082
|
+
* .compile('postgres');
|
|
7083
|
+
* console.log(compiled.sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
|
|
6474
7084
|
*/
|
|
6475
7085
|
compile(dialect) {
|
|
6476
7086
|
const resolved = resolveDialectInput(dialect);
|
|
@@ -6480,6 +7090,11 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6480
7090
|
* Converts the query to SQL string for a specific dialect
|
|
6481
7091
|
* @param dialect - Database dialect to generate SQL for
|
|
6482
7092
|
* @returns SQL string representation of the query
|
|
7093
|
+
* @example
|
|
7094
|
+
* const sql = qb.select('id', 'name')
|
|
7095
|
+
* .where(eq(userTable.columns.active, true))
|
|
7096
|
+
* .toSql('postgres');
|
|
7097
|
+
* console.log(sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
|
|
6483
7098
|
*/
|
|
6484
7099
|
toSql(dialect) {
|
|
6485
7100
|
return this.compile(dialect).sql;
|
|
@@ -6487,6 +7102,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6487
7102
|
/**
|
|
6488
7103
|
* Gets the hydration plan for the query
|
|
6489
7104
|
* @returns Hydration plan or undefined if none exists
|
|
7105
|
+
* @example
|
|
7106
|
+
* const plan = qb.include('posts').getHydrationPlan();
|
|
7107
|
+
* console.log(plan?.relations); // Information about included relations
|
|
6490
7108
|
*/
|
|
6491
7109
|
getHydrationPlan() {
|
|
6492
7110
|
return this.context.hydration.getPlan();
|
|
@@ -6494,6 +7112,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6494
7112
|
/**
|
|
6495
7113
|
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
6496
7114
|
* @returns Query AST with hydration applied
|
|
7115
|
+
* @example
|
|
7116
|
+
* const ast = qb.select('id', 'name').getAST();
|
|
7117
|
+
* console.log(ast.columns); // Array of column nodes
|
|
7118
|
+
* console.log(ast.from); // From clause information
|
|
6497
7119
|
*/
|
|
6498
7120
|
getAST() {
|
|
6499
7121
|
return this.context.hydration.applyToAst(this.context.state.ast);
|
|
@@ -6597,23 +7219,44 @@ var resolveTableTarget = (target, tableMap) => {
|
|
|
6597
7219
|
}
|
|
6598
7220
|
return table;
|
|
6599
7221
|
};
|
|
7222
|
+
var toSnakeCase = (value) => {
|
|
7223
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
7224
|
+
};
|
|
7225
|
+
var normalizeEntityName = (value) => {
|
|
7226
|
+
const stripped = value.replace(/Entity$/i, "");
|
|
7227
|
+
const normalized = toSnakeCase(stripped || value);
|
|
7228
|
+
return normalized || "unknown";
|
|
7229
|
+
};
|
|
7230
|
+
var getPivotKeyBaseFromTarget = (target) => {
|
|
7231
|
+
const resolved = unwrapTarget(target);
|
|
7232
|
+
if (isTableDef(resolved)) {
|
|
7233
|
+
return toSnakeCase(resolved.name || "unknown");
|
|
7234
|
+
}
|
|
7235
|
+
const ctor = resolved;
|
|
7236
|
+
return normalizeEntityName(ctor.name || "unknown");
|
|
7237
|
+
};
|
|
7238
|
+
var getPivotKeyBaseFromRoot = (meta) => {
|
|
7239
|
+
return normalizeEntityName(meta.target.name || meta.tableName || "unknown");
|
|
7240
|
+
};
|
|
6600
7241
|
var buildRelationDefinitions = (meta, tableMap) => {
|
|
6601
7242
|
const relations = {};
|
|
6602
7243
|
for (const [name, relation] of Object.entries(meta.relations)) {
|
|
6603
7244
|
switch (relation.kind) {
|
|
6604
7245
|
case RelationKinds.HasOne: {
|
|
7246
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6605
7247
|
relations[name] = hasOne(
|
|
6606
7248
|
resolveTableTarget(relation.target, tableMap),
|
|
6607
|
-
|
|
7249
|
+
foreignKey,
|
|
6608
7250
|
relation.localKey,
|
|
6609
7251
|
relation.cascade
|
|
6610
7252
|
);
|
|
6611
7253
|
break;
|
|
6612
7254
|
}
|
|
6613
7255
|
case RelationKinds.HasMany: {
|
|
7256
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6614
7257
|
relations[name] = hasMany(
|
|
6615
7258
|
resolveTableTarget(relation.target, tableMap),
|
|
6616
|
-
|
|
7259
|
+
foreignKey,
|
|
6617
7260
|
relation.localKey,
|
|
6618
7261
|
relation.cascade
|
|
6619
7262
|
);
|
|
@@ -6629,12 +7272,14 @@ var buildRelationDefinitions = (meta, tableMap) => {
|
|
|
6629
7272
|
break;
|
|
6630
7273
|
}
|
|
6631
7274
|
case RelationKinds.BelongsToMany: {
|
|
7275
|
+
const pivotForeignKeyToRoot = relation.pivotForeignKeyToRoot ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
7276
|
+
const pivotForeignKeyToTarget = relation.pivotForeignKeyToTarget ?? `${getPivotKeyBaseFromTarget(relation.target)}_id`;
|
|
6632
7277
|
relations[name] = belongsToMany(
|
|
6633
7278
|
resolveTableTarget(relation.target, tableMap),
|
|
6634
7279
|
resolveTableTarget(relation.pivotTable, tableMap),
|
|
6635
7280
|
{
|
|
6636
|
-
pivotForeignKeyToRoot
|
|
6637
|
-
pivotForeignKeyToTarget
|
|
7281
|
+
pivotForeignKeyToRoot,
|
|
7282
|
+
pivotForeignKeyToTarget,
|
|
6638
7283
|
localKey: relation.localKey,
|
|
6639
7284
|
targetKey: relation.targetKey,
|
|
6640
7285
|
pivotPrimaryKey: relation.pivotPrimaryKey,
|
|
@@ -6715,6 +7360,8 @@ function esel(entity, ...props) {
|
|
|
6715
7360
|
|
|
6716
7361
|
// src/query-builder/insert-query-state.ts
|
|
6717
7362
|
var InsertQueryState = class _InsertQueryState {
|
|
7363
|
+
table;
|
|
7364
|
+
ast;
|
|
6718
7365
|
/**
|
|
6719
7366
|
* Creates a new InsertQueryState instance
|
|
6720
7367
|
* @param table - The table definition for the INSERT query
|
|
@@ -6835,6 +7482,8 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
6835
7482
|
|
|
6836
7483
|
// src/query-builder/insert.ts
|
|
6837
7484
|
var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
7485
|
+
table;
|
|
7486
|
+
state;
|
|
6838
7487
|
/**
|
|
6839
7488
|
* Creates a new InsertQueryBuilder instance
|
|
6840
7489
|
* @param table - The table definition for the INSERT query
|
|
@@ -6934,6 +7583,8 @@ var isUpdateValue = (value) => {
|
|
|
6934
7583
|
}
|
|
6935
7584
|
};
|
|
6936
7585
|
var UpdateQueryState = class _UpdateQueryState {
|
|
7586
|
+
table;
|
|
7587
|
+
ast;
|
|
6937
7588
|
/**
|
|
6938
7589
|
* Creates a new UpdateQueryState instance
|
|
6939
7590
|
* @param table - Table definition for the update
|
|
@@ -7044,6 +7695,8 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
7044
7695
|
|
|
7045
7696
|
// src/query-builder/update.ts
|
|
7046
7697
|
var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
7698
|
+
table;
|
|
7699
|
+
state;
|
|
7047
7700
|
/**
|
|
7048
7701
|
* Creates a new UpdateQueryBuilder instance
|
|
7049
7702
|
* @param table - The table definition for the UPDATE query
|
|
@@ -7161,6 +7814,8 @@ var isTableSourceNode = (source) => typeof source.type === "string";
|
|
|
7161
7814
|
|
|
7162
7815
|
// src/query-builder/delete-query-state.ts
|
|
7163
7816
|
var DeleteQueryState = class _DeleteQueryState {
|
|
7817
|
+
table;
|
|
7818
|
+
ast;
|
|
7164
7819
|
/**
|
|
7165
7820
|
* Creates a new DeleteQueryState instance
|
|
7166
7821
|
* @param table - The table definition for the DELETE query
|
|
@@ -7239,6 +7894,8 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
7239
7894
|
|
|
7240
7895
|
// src/query-builder/delete.ts
|
|
7241
7896
|
var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
7897
|
+
table;
|
|
7898
|
+
state;
|
|
7242
7899
|
/**
|
|
7243
7900
|
* Creates a new DeleteQueryBuilder instance
|
|
7244
7901
|
* @param table - The table definition for the DELETE query
|
|
@@ -7345,6 +8002,39 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
7345
8002
|
};
|
|
7346
8003
|
var isTableSourceNode2 = (source) => typeof source.type === "string";
|
|
7347
8004
|
|
|
8005
|
+
// src/query/target.ts
|
|
8006
|
+
var resolveEntityTarget = (ctor) => {
|
|
8007
|
+
const table = getTableDefFromEntity(ctor);
|
|
8008
|
+
if (!table) {
|
|
8009
|
+
throw new Error(`Entity '${ctor.name}' is not registered with decorators`);
|
|
8010
|
+
}
|
|
8011
|
+
return table;
|
|
8012
|
+
};
|
|
8013
|
+
var resolveTable = (target) => {
|
|
8014
|
+
if (isTableDef(target)) {
|
|
8015
|
+
return target;
|
|
8016
|
+
}
|
|
8017
|
+
return resolveEntityTarget(target);
|
|
8018
|
+
};
|
|
8019
|
+
|
|
8020
|
+
// src/query/index.ts
|
|
8021
|
+
var selectFrom = (target) => {
|
|
8022
|
+
const table = resolveTable(target);
|
|
8023
|
+
return new SelectQueryBuilder(table);
|
|
8024
|
+
};
|
|
8025
|
+
var insertInto = (target) => {
|
|
8026
|
+
const table = resolveTable(target);
|
|
8027
|
+
return new InsertQueryBuilder(table);
|
|
8028
|
+
};
|
|
8029
|
+
var update = (target) => {
|
|
8030
|
+
const table = resolveTable(target);
|
|
8031
|
+
return new UpdateQueryBuilder(table);
|
|
8032
|
+
};
|
|
8033
|
+
var deleteFrom = (target) => {
|
|
8034
|
+
const table = resolveTable(target);
|
|
8035
|
+
return new DeleteQueryBuilder(table);
|
|
8036
|
+
};
|
|
8037
|
+
|
|
7348
8038
|
// src/core/ddl/sql-writing.ts
|
|
7349
8039
|
var resolvePrimaryKey = (table) => {
|
|
7350
8040
|
if (Array.isArray(table.primaryKey) && table.primaryKey.length > 0) {
|
|
@@ -7366,7 +8056,8 @@ var renderColumnDefinition = (table, col2, dialect, options = {}) => {
|
|
|
7366
8056
|
if (col2.default !== void 0) {
|
|
7367
8057
|
parts.push(`DEFAULT ${dialect.renderDefault(col2.default, col2)}`);
|
|
7368
8058
|
}
|
|
7369
|
-
|
|
8059
|
+
const autoIncIncludesPrimary = typeof autoInc === "string" && /\bPRIMARY\s+KEY\b/i.test(autoInc);
|
|
8060
|
+
if (options.includePrimary && col2.primary && !autoIncIncludesPrimary) {
|
|
7370
8061
|
parts.push("PRIMARY KEY");
|
|
7371
8062
|
}
|
|
7372
8063
|
if (col2.check) {
|
|
@@ -7424,6 +8115,16 @@ var generateSchemaSql = (tables, dialect) => {
|
|
|
7424
8115
|
});
|
|
7425
8116
|
return statements;
|
|
7426
8117
|
};
|
|
8118
|
+
var generateSchemaSqlFor = (dialect, ...tables) => generateSchemaSql(tables, dialect);
|
|
8119
|
+
var executeSchemaSql = async (executor, tables, dialect) => {
|
|
8120
|
+
const statements = generateSchemaSql(tables, dialect);
|
|
8121
|
+
for (const sql of statements) {
|
|
8122
|
+
await executor.executeSql(sql);
|
|
8123
|
+
}
|
|
8124
|
+
};
|
|
8125
|
+
var executeSchemaSqlFor = async (executor, dialect, ...tables) => {
|
|
8126
|
+
await executeSchemaSql(executor, tables, dialect);
|
|
8127
|
+
};
|
|
7427
8128
|
var orderTablesByDependencies = (tables) => {
|
|
7428
8129
|
const map = /* @__PURE__ */ new Map();
|
|
7429
8130
|
tables.forEach((t) => map.set(t.name, t));
|
|
@@ -9330,6 +10031,7 @@ var arrayAppend = (array, value) => fn7("ARRAY_APPEND", [array, value]);
|
|
|
9330
10031
|
|
|
9331
10032
|
// src/orm/als.ts
|
|
9332
10033
|
var AsyncLocalStorage = class {
|
|
10034
|
+
store;
|
|
9333
10035
|
/**
|
|
9334
10036
|
* Executes a callback function within a context containing the specified store value.
|
|
9335
10037
|
* The store value is only available during the callback's execution and is automatically
|
|
@@ -9826,9 +10528,7 @@ var TypeScriptGenerator = class {
|
|
|
9826
10528
|
|
|
9827
10529
|
// src/orm/identity-map.ts
|
|
9828
10530
|
var IdentityMap = class {
|
|
9829
|
-
|
|
9830
|
-
this.buckets = /* @__PURE__ */ new Map();
|
|
9831
|
-
}
|
|
10531
|
+
buckets = /* @__PURE__ */ new Map();
|
|
9832
10532
|
get bucketsMap() {
|
|
9833
10533
|
return this.buckets;
|
|
9834
10534
|
}
|
|
@@ -9898,8 +10598,8 @@ var UnitOfWork = class {
|
|
|
9898
10598
|
this.executor = executor;
|
|
9899
10599
|
this.identityMap = identityMap;
|
|
9900
10600
|
this.hookContext = hookContext;
|
|
9901
|
-
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
9902
10601
|
}
|
|
10602
|
+
trackedEntities = /* @__PURE__ */ new Map();
|
|
9903
10603
|
/**
|
|
9904
10604
|
* Gets the identity buckets map.
|
|
9905
10605
|
*/
|
|
@@ -10229,12 +10929,12 @@ var UnitOfWork = class {
|
|
|
10229
10929
|
|
|
10230
10930
|
// src/orm/domain-event-bus.ts
|
|
10231
10931
|
var DomainEventBus = class {
|
|
10932
|
+
handlers = /* @__PURE__ */ new Map();
|
|
10232
10933
|
/**
|
|
10233
10934
|
* Creates a new DomainEventBus instance.
|
|
10234
10935
|
* @param initialHandlers - Optional initial event handlers
|
|
10235
10936
|
*/
|
|
10236
10937
|
constructor(initialHandlers) {
|
|
10237
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
10238
10938
|
if (initialHandlers) {
|
|
10239
10939
|
for (const key in initialHandlers) {
|
|
10240
10940
|
const type = key;
|
|
@@ -10303,8 +11003,8 @@ var RelationChangeProcessor = class {
|
|
|
10303
11003
|
this.unitOfWork = unitOfWork;
|
|
10304
11004
|
this.dialect = dialect;
|
|
10305
11005
|
this.executor = executor;
|
|
10306
|
-
this.relationChanges = [];
|
|
10307
11006
|
}
|
|
11007
|
+
relationChanges = [];
|
|
10308
11008
|
/**
|
|
10309
11009
|
* Registers a relation change for processing.
|
|
10310
11010
|
* @param entry - The relation change entry
|
|
@@ -10738,25 +11438,24 @@ var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
|
|
|
10738
11438
|
|
|
10739
11439
|
// src/orm/orm-session.ts
|
|
10740
11440
|
var OrmSession = class {
|
|
11441
|
+
/** The ORM instance */
|
|
11442
|
+
orm;
|
|
11443
|
+
/** The database executor */
|
|
11444
|
+
executor;
|
|
11445
|
+
/** The identity map for tracking entity instances */
|
|
11446
|
+
identityMap;
|
|
11447
|
+
/** The unit of work for tracking entity changes */
|
|
11448
|
+
unitOfWork;
|
|
11449
|
+
/** The domain event bus */
|
|
11450
|
+
domainEvents;
|
|
11451
|
+
/** The relation change processor */
|
|
11452
|
+
relationChanges;
|
|
11453
|
+
interceptors;
|
|
10741
11454
|
/**
|
|
10742
11455
|
* Creates a new OrmSession instance.
|
|
10743
11456
|
* @param opts - Session options
|
|
10744
11457
|
*/
|
|
10745
11458
|
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
11459
|
this.orm = opts.orm;
|
|
10761
11460
|
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
10762
11461
|
this.interceptors = [...opts.interceptors ?? []];
|
|
@@ -10845,6 +11544,20 @@ var OrmSession = class {
|
|
|
10845
11544
|
markRemoved(entity) {
|
|
10846
11545
|
this.unitOfWork.markRemoved(entity);
|
|
10847
11546
|
}
|
|
11547
|
+
/**
|
|
11548
|
+
* Registers a relation change.
|
|
11549
|
+
* @param root - The root entity
|
|
11550
|
+
* @param relationKey - The relation key
|
|
11551
|
+
* @param rootTable - The root table definition
|
|
11552
|
+
* @param relationName - The relation name
|
|
11553
|
+
* @param relation - The relation definition
|
|
11554
|
+
* @param change - The relation change
|
|
11555
|
+
*/
|
|
11556
|
+
registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
11557
|
+
this.relationChanges.registerChange(
|
|
11558
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
11559
|
+
);
|
|
11560
|
+
};
|
|
10848
11561
|
/**
|
|
10849
11562
|
* Gets all tracked entities for a specific table.
|
|
10850
11563
|
* @param table - The table definition
|
|
@@ -11050,9 +11763,7 @@ var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, rela
|
|
|
11050
11763
|
|
|
11051
11764
|
// src/orm/interceptor-pipeline.ts
|
|
11052
11765
|
var InterceptorPipeline = class {
|
|
11053
|
-
|
|
11054
|
-
this.interceptors = [];
|
|
11055
|
-
}
|
|
11766
|
+
interceptors = [];
|
|
11056
11767
|
use(interceptor) {
|
|
11057
11768
|
this.interceptors.push(interceptor);
|
|
11058
11769
|
}
|
|
@@ -11071,6 +11782,13 @@ var InterceptorPipeline = class {
|
|
|
11071
11782
|
|
|
11072
11783
|
// src/orm/orm.ts
|
|
11073
11784
|
var Orm = class {
|
|
11785
|
+
/** The database dialect */
|
|
11786
|
+
dialect;
|
|
11787
|
+
/** The interceptors pipeline */
|
|
11788
|
+
interceptors;
|
|
11789
|
+
/** The naming strategy */
|
|
11790
|
+
namingStrategy;
|
|
11791
|
+
executorFactory;
|
|
11074
11792
|
/**
|
|
11075
11793
|
* Creates a new ORM instance.
|
|
11076
11794
|
* @param opts - ORM options
|
|
@@ -11127,17 +11845,13 @@ var jsonify = (value) => {
|
|
|
11127
11845
|
|
|
11128
11846
|
// src/decorators/decorator-metadata.ts
|
|
11129
11847
|
var METADATA_KEY = "metal-orm:decorators";
|
|
11130
|
-
var isStandardDecoratorContext = (value) => {
|
|
11131
|
-
return typeof value === "object" && value !== null && "kind" in value;
|
|
11132
|
-
};
|
|
11133
11848
|
var getOrCreateMetadataBag = (context) => {
|
|
11134
11849
|
const metadata = context.metadata || (context.metadata = {});
|
|
11135
|
-
|
|
11136
|
-
if (
|
|
11137
|
-
|
|
11850
|
+
let bag = metadata[METADATA_KEY];
|
|
11851
|
+
if (!bag) {
|
|
11852
|
+
bag = { columns: [], relations: [] };
|
|
11853
|
+
metadata[METADATA_KEY] = bag;
|
|
11138
11854
|
}
|
|
11139
|
-
const bag = { columns: [], relations: [] };
|
|
11140
|
-
metadata[METADATA_KEY] = bag;
|
|
11141
11855
|
return bag;
|
|
11142
11856
|
};
|
|
11143
11857
|
var readMetadataBag = (context) => {
|
|
@@ -11152,57 +11866,50 @@ var readMetadataBagFromConstructor = (ctor) => {
|
|
|
11152
11866
|
var getDecoratorMetadata = (ctor) => readMetadataBagFromConstructor(ctor);
|
|
11153
11867
|
|
|
11154
11868
|
// src/decorators/entity.ts
|
|
11155
|
-
var
|
|
11869
|
+
var toSnakeCase2 = (value) => {
|
|
11156
11870
|
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
11157
11871
|
};
|
|
11158
11872
|
var deriveTableNameFromConstructor = (ctor) => {
|
|
11159
11873
|
const fallback = "unknown";
|
|
11160
11874
|
const rawName = ctor.name || fallback;
|
|
11161
11875
|
const strippedName = rawName.replace(/Entity$/i, "");
|
|
11162
|
-
const normalized =
|
|
11876
|
+
const normalized = toSnakeCase2(strippedName || rawName);
|
|
11163
11877
|
if (!normalized) {
|
|
11164
11878
|
return fallback;
|
|
11165
11879
|
}
|
|
11166
11880
|
return normalized.endsWith("s") ? normalized : `${normalized}s`;
|
|
11167
11881
|
};
|
|
11168
11882
|
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) => {
|
|
11883
|
+
return function(value, context) {
|
|
11175
11884
|
const ctor = value;
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
}
|
|
11187
|
-
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11885
|
+
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
11886
|
+
setEntityTableName(ctor, tableName, options.hooks);
|
|
11887
|
+
const bag = readMetadataBag(context);
|
|
11888
|
+
if (bag) {
|
|
11889
|
+
const meta = ensureEntityMetadata(ctor);
|
|
11890
|
+
for (const entry of bag.columns) {
|
|
11891
|
+
if (meta.columns[entry.propertyName]) {
|
|
11892
|
+
throw new Error(
|
|
11893
|
+
`Column '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11894
|
+
);
|
|
11188
11895
|
}
|
|
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);
|
|
11896
|
+
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11897
|
+
}
|
|
11898
|
+
for (const entry of bag.relations) {
|
|
11899
|
+
if (meta.relations[entry.propertyName]) {
|
|
11900
|
+
throw new Error(
|
|
11901
|
+
`Relation '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11902
|
+
);
|
|
11200
11903
|
}
|
|
11904
|
+
const relationCopy = entry.relation.kind === RelationKinds.BelongsToMany ? {
|
|
11905
|
+
...entry.relation,
|
|
11906
|
+
defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
|
|
11907
|
+
} : { ...entry.relation };
|
|
11908
|
+
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
11201
11909
|
}
|
|
11202
11910
|
}
|
|
11203
11911
|
return ctor;
|
|
11204
11912
|
};
|
|
11205
|
-
return decoratorWithContext;
|
|
11206
11913
|
}
|
|
11207
11914
|
|
|
11208
11915
|
// src/decorators/column-decorator.ts
|
|
@@ -11235,26 +11942,13 @@ var normalizePropertyName = (name) => {
|
|
|
11235
11942
|
}
|
|
11236
11943
|
return name;
|
|
11237
11944
|
};
|
|
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
11945
|
var registerColumnFromContext = (context, column) => {
|
|
11255
11946
|
if (!context.name) {
|
|
11256
11947
|
throw new Error("Column decorator requires a property name");
|
|
11257
11948
|
}
|
|
11949
|
+
if (context.private) {
|
|
11950
|
+
throw new Error("Column decorator does not support private fields");
|
|
11951
|
+
}
|
|
11258
11952
|
const propertyName = normalizePropertyName(context.name);
|
|
11259
11953
|
const bag = getOrCreateMetadataBag(context);
|
|
11260
11954
|
if (!bag.columns.some((entry) => entry.propertyName === propertyName)) {
|
|
@@ -11263,19 +11957,9 @@ var registerColumnFromContext = (context, column) => {
|
|
|
11263
11957
|
};
|
|
11264
11958
|
function Column(definition) {
|
|
11265
11959
|
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 });
|
|
11960
|
+
return function(_value, context) {
|
|
11961
|
+
registerColumnFromContext(context, normalized);
|
|
11277
11962
|
};
|
|
11278
|
-
return decorator;
|
|
11279
11963
|
}
|
|
11280
11964
|
function PrimaryKey(definition) {
|
|
11281
11965
|
const normalized = normalizeColumnInput(definition);
|
|
@@ -11290,41 +11974,21 @@ var normalizePropertyName2 = (name) => {
|
|
|
11290
11974
|
}
|
|
11291
11975
|
return name;
|
|
11292
11976
|
};
|
|
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
11977
|
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;
|
|
11978
|
+
return function(_value, context) {
|
|
11979
|
+
if (!context.name) {
|
|
11980
|
+
throw new Error("Relation decorator requires a property name");
|
|
11319
11981
|
}
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11982
|
+
if (context.private) {
|
|
11983
|
+
throw new Error("Relation decorator does not support private fields");
|
|
11984
|
+
}
|
|
11985
|
+
const propertyName = normalizePropertyName2(context.name);
|
|
11986
|
+
const bag = getOrCreateMetadataBag(context);
|
|
11987
|
+
const relationMetadata = metadataFactory(propertyName);
|
|
11988
|
+
if (!bag.relations.some((entry) => entry.propertyName === propertyName)) {
|
|
11989
|
+
bag.relations.push({ propertyName, relation: relationMetadata });
|
|
11324
11990
|
}
|
|
11325
|
-
registerRelation(ctor, propertyName, metadataFactory(propertyName));
|
|
11326
11991
|
};
|
|
11327
|
-
return decorator;
|
|
11328
11992
|
};
|
|
11329
11993
|
function HasMany(options) {
|
|
11330
11994
|
return createFieldDecorator((propertyName) => ({
|
|
@@ -11351,7 +12015,7 @@ function BelongsTo(options) {
|
|
|
11351
12015
|
kind: RelationKinds.BelongsTo,
|
|
11352
12016
|
propertyKey: propertyName,
|
|
11353
12017
|
target: options.target,
|
|
11354
|
-
foreignKey: options.foreignKey
|
|
12018
|
+
foreignKey: options.foreignKey ?? `${propertyName}_id`,
|
|
11355
12019
|
localKey: options.localKey,
|
|
11356
12020
|
cascade: options.cascade
|
|
11357
12021
|
}));
|
|
@@ -11427,13 +12091,15 @@ var deferred = () => {
|
|
|
11427
12091
|
return { promise, resolve, reject };
|
|
11428
12092
|
};
|
|
11429
12093
|
var Pool = class {
|
|
12094
|
+
adapter;
|
|
12095
|
+
options;
|
|
12096
|
+
destroyed = false;
|
|
12097
|
+
creating = 0;
|
|
12098
|
+
leased = 0;
|
|
12099
|
+
idle = [];
|
|
12100
|
+
waiters = [];
|
|
12101
|
+
reapTimer = null;
|
|
11430
12102
|
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
12103
|
if (!Number.isFinite(options.max) || options.max <= 0) {
|
|
11438
12104
|
throw new Error("Pool options.max must be a positive number");
|
|
11439
12105
|
}
|
|
@@ -11986,6 +12652,7 @@ export {
|
|
|
11986
12652
|
dayOfWeek,
|
|
11987
12653
|
defineTable,
|
|
11988
12654
|
degrees,
|
|
12655
|
+
deleteFrom,
|
|
11989
12656
|
denseRank,
|
|
11990
12657
|
diffSchema,
|
|
11991
12658
|
div,
|
|
@@ -11995,6 +12662,8 @@ export {
|
|
|
11995
12662
|
esel,
|
|
11996
12663
|
executeHydrated,
|
|
11997
12664
|
executeHydratedWithContexts,
|
|
12665
|
+
executeSchemaSql,
|
|
12666
|
+
executeSchemaSqlFor,
|
|
11998
12667
|
exists,
|
|
11999
12668
|
exp,
|
|
12000
12669
|
extract,
|
|
@@ -12003,6 +12672,7 @@ export {
|
|
|
12003
12672
|
fromUnixTime,
|
|
12004
12673
|
generateCreateTableSql,
|
|
12005
12674
|
generateSchemaSql,
|
|
12675
|
+
generateSchemaSqlFor,
|
|
12006
12676
|
getColumn,
|
|
12007
12677
|
getDecoratorMetadata,
|
|
12008
12678
|
getSchemaIntrospector,
|
|
@@ -12019,6 +12689,7 @@ export {
|
|
|
12019
12689
|
inList,
|
|
12020
12690
|
inSubquery,
|
|
12021
12691
|
initcap,
|
|
12692
|
+
insertInto,
|
|
12022
12693
|
instr,
|
|
12023
12694
|
introspectSchema,
|
|
12024
12695
|
isCaseExpressionNode,
|
|
@@ -12107,7 +12778,9 @@ export {
|
|
|
12107
12778
|
rtrim,
|
|
12108
12779
|
second,
|
|
12109
12780
|
sel,
|
|
12781
|
+
selectFrom,
|
|
12110
12782
|
selectFromEntity,
|
|
12783
|
+
setRelations,
|
|
12111
12784
|
sha1,
|
|
12112
12785
|
sha2,
|
|
12113
12786
|
shiftLeft,
|
|
@@ -12129,6 +12802,7 @@ export {
|
|
|
12129
12802
|
trunc,
|
|
12130
12803
|
truncate,
|
|
12131
12804
|
unixTimestamp,
|
|
12805
|
+
update,
|
|
12132
12806
|
upper,
|
|
12133
12807
|
utcNow,
|
|
12134
12808
|
valueToOperand,
|