metal-orm 1.0.57 → 1.0.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -13
- package/dist/index.cjs +1750 -733
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +244 -157
- package/dist/index.d.ts +244 -157
- package/dist/index.js +1745 -733
- package/dist/index.js.map +1 -1
- package/package.json +69 -69
- package/src/core/ddl/schema-generator.ts +44 -1
- package/src/decorators/bootstrap.ts +186 -113
- package/src/decorators/column-decorator.ts +8 -49
- package/src/decorators/decorator-metadata.ts +10 -46
- package/src/decorators/entity.ts +30 -40
- package/src/decorators/relations.ts +30 -56
- package/src/orm/entity-hydration.ts +72 -0
- package/src/orm/entity-meta.ts +18 -13
- 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 -343
- package/src/orm/execute.ts +87 -20
- 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 -309
- package/src/orm/relations/belongs-to.ts +2 -2
- package/src/orm/relations/has-many.ts +23 -9
- package/src/orm/relations/has-one.ts +2 -2
- package/src/orm/relations/many-to-many.ts +29 -14
- package/src/orm/save-graph-types.ts +2 -2
- package/src/orm/save-graph.ts +18 -18
- package/src/query-builder/relation-conditions.ts +80 -59
- 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 +103 -159
- package/src/query-builder/relation-types.ts +43 -12
- 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 +373 -426
- package/src/schema/relation.ts +22 -18
- package/src/schema/table.ts +22 -9
- package/src/schema/types.ts +103 -84
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
|
|
@@ -3852,20 +3853,21 @@ var RelationProjectionHelper = class {
|
|
|
3852
3853
|
var assertNever = (value) => {
|
|
3853
3854
|
throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
|
|
3854
3855
|
};
|
|
3855
|
-
var baseRelationCondition = (root, relation, rootAlias) => {
|
|
3856
|
+
var baseRelationCondition = (root, relation, rootAlias, targetTableName) => {
|
|
3856
3857
|
const rootTable = rootAlias || root.name;
|
|
3858
|
+
const targetTable = targetTableName ?? relation.target.name;
|
|
3857
3859
|
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
3858
3860
|
const localKey = relation.localKey || defaultLocalKey;
|
|
3859
3861
|
switch (relation.type) {
|
|
3860
3862
|
case RelationKinds.HasMany:
|
|
3861
3863
|
case RelationKinds.HasOne:
|
|
3862
3864
|
return eq(
|
|
3863
|
-
{ type: "Column", table:
|
|
3865
|
+
{ type: "Column", table: targetTable, name: relation.foreignKey },
|
|
3864
3866
|
{ type: "Column", table: rootTable, name: localKey }
|
|
3865
3867
|
);
|
|
3866
3868
|
case RelationKinds.BelongsTo:
|
|
3867
3869
|
return eq(
|
|
3868
|
-
{ type: "Column", table:
|
|
3870
|
+
{ type: "Column", table: targetTable, name: localKey },
|
|
3869
3871
|
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
3870
3872
|
);
|
|
3871
3873
|
case RelationKinds.BelongsToMany:
|
|
@@ -3874,7 +3876,7 @@ var baseRelationCondition = (root, relation, rootAlias) => {
|
|
|
3874
3876
|
return assertNever(relation);
|
|
3875
3877
|
}
|
|
3876
3878
|
};
|
|
3877
|
-
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
|
|
3879
|
+
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias, targetTable, targetTableName) => {
|
|
3878
3880
|
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
3879
3881
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
3880
3882
|
const rootTable = rootAlias || root.name;
|
|
@@ -3887,8 +3889,14 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, ro
|
|
|
3887
3889
|
{ type: "Table", name: relation.pivotTable.name, schema: relation.pivotTable.schema },
|
|
3888
3890
|
pivotCondition
|
|
3889
3891
|
);
|
|
3892
|
+
const targetSource = targetTable ?? {
|
|
3893
|
+
type: "Table",
|
|
3894
|
+
name: relation.target.name,
|
|
3895
|
+
schema: relation.target.schema
|
|
3896
|
+
};
|
|
3897
|
+
const effectiveTargetName = targetTableName ?? relation.target.name;
|
|
3890
3898
|
let targetCondition = eq(
|
|
3891
|
-
{ type: "Column", table:
|
|
3899
|
+
{ type: "Column", table: effectiveTargetName, name: targetKey },
|
|
3892
3900
|
{ type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToTarget }
|
|
3893
3901
|
);
|
|
3894
3902
|
if (extra) {
|
|
@@ -3896,141 +3904,487 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, ro
|
|
|
3896
3904
|
}
|
|
3897
3905
|
const targetJoin = createJoinNode(
|
|
3898
3906
|
joinKind,
|
|
3899
|
-
|
|
3907
|
+
targetSource,
|
|
3900
3908
|
targetCondition,
|
|
3901
3909
|
relationName
|
|
3902
3910
|
);
|
|
3903
3911
|
return [pivotJoin, targetJoin];
|
|
3904
3912
|
};
|
|
3905
|
-
var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
|
|
3906
|
-
const base = baseRelationCondition(root, relation, rootAlias);
|
|
3913
|
+
var buildRelationJoinCondition = (root, relation, extra, rootAlias, targetTableName) => {
|
|
3914
|
+
const base = baseRelationCondition(root, relation, rootAlias, targetTableName);
|
|
3907
3915
|
return extra ? and(base, extra) : base;
|
|
3908
3916
|
};
|
|
3909
|
-
var buildRelationCorrelation = (root, relation, rootAlias) => {
|
|
3910
|
-
return baseRelationCondition(root, relation, rootAlias);
|
|
3917
|
+
var buildRelationCorrelation = (root, relation, rootAlias, targetTableName) => {
|
|
3918
|
+
return baseRelationCondition(root, relation, rootAlias, targetTableName);
|
|
3911
3919
|
};
|
|
3912
3920
|
|
|
3913
3921
|
// src/core/ast/join-metadata.ts
|
|
3914
3922
|
var getJoinRelationName = (join) => join.meta?.relationName;
|
|
3915
3923
|
|
|
3916
|
-
// src/query-builder/relation-
|
|
3917
|
-
var
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
this.hydration = hydration;
|
|
3928
|
-
this.createQueryAstService = createQueryAstService;
|
|
3929
|
-
this.projectionHelper = new RelationProjectionHelper(
|
|
3930
|
-
table,
|
|
3931
|
-
(state2, hydration2, columns) => this.selectColumns(state2, hydration2, columns)
|
|
3932
|
-
);
|
|
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
|
+
}
|
|
3933
3935
|
}
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
*/
|
|
3941
|
-
joinRelation(relationName, joinKind, extraCondition) {
|
|
3942
|
-
const nextState = this.withJoin(this.state, relationName, joinKind, extraCondition);
|
|
3943
|
-
return { state: nextState, hydration: this.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));
|
|
3944
3942
|
}
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
3956
|
-
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
3957
|
-
return { state: nextState, hydration: joined.hydration };
|
|
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;
|
|
3952
|
+
}
|
|
3958
3953
|
}
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
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;
|
|
3982
|
+
}
|
|
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;
|
|
3999
|
+
}
|
|
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;
|
|
4051
|
+
}
|
|
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) {
|
|
4068
|
+
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
4069
|
+
if (relation.type === RelationKinds.BelongsToMany) {
|
|
4070
|
+
const targetTableSource = tableSource ?? {
|
|
4071
|
+
type: "Table",
|
|
4072
|
+
name: relation.target.name,
|
|
4073
|
+
schema: relation.target.schema
|
|
4074
|
+
};
|
|
4075
|
+
const targetName2 = this.resolveTargetTableName(targetTableSource, relation);
|
|
4076
|
+
const joins = buildBelongsToManyJoins(
|
|
4077
|
+
this.table,
|
|
4078
|
+
relationName,
|
|
4079
|
+
relation,
|
|
4080
|
+
joinKind,
|
|
4081
|
+
extraCondition,
|
|
4082
|
+
rootAlias,
|
|
4083
|
+
targetTableSource,
|
|
4084
|
+
targetName2
|
|
4085
|
+
);
|
|
4086
|
+
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
3974
4087
|
}
|
|
3975
|
-
const
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
const buildTypedSelection = (columns, prefix, keys, missingMsg) => {
|
|
3980
|
-
return keys.reduce((acc, key) => {
|
|
3981
|
-
const def = columns[key];
|
|
3982
|
-
if (!def) {
|
|
3983
|
-
throw new Error(missingMsg(key));
|
|
3984
|
-
}
|
|
3985
|
-
acc[makeRelationAlias(prefix, key)] = def;
|
|
3986
|
-
return acc;
|
|
3987
|
-
}, {});
|
|
4088
|
+
const targetTable = tableSource ?? {
|
|
4089
|
+
type: "Table",
|
|
4090
|
+
name: relation.target.name,
|
|
4091
|
+
schema: relation.target.schema
|
|
3988
4092
|
};
|
|
3989
|
-
const
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
4093
|
+
const targetName = this.resolveTargetTableName(targetTable, relation);
|
|
4094
|
+
const condition = buildRelationJoinCondition(
|
|
4095
|
+
this.table,
|
|
4096
|
+
relation,
|
|
4097
|
+
extraCondition,
|
|
4098
|
+
rootAlias,
|
|
4099
|
+
targetName
|
|
3994
4100
|
);
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4101
|
+
const joinNode = createJoinNode(joinKind, targetTable, condition, relationName);
|
|
4102
|
+
return this.astService(state).withJoin(joinNode);
|
|
4103
|
+
}
|
|
4104
|
+
astService(state) {
|
|
4105
|
+
return this.createQueryAstService(this.table, state);
|
|
4106
|
+
}
|
|
4107
|
+
resolveTargetTableName(target, relation) {
|
|
4108
|
+
if (target.type === "Table") {
|
|
4109
|
+
return target.alias ?? target.name;
|
|
4110
|
+
}
|
|
4111
|
+
if (target.type === "DerivedTable") {
|
|
4112
|
+
return target.alias;
|
|
4113
|
+
}
|
|
4114
|
+
if (target.type === "FunctionTable") {
|
|
4115
|
+
return target.alias ?? relation.target.name;
|
|
4116
|
+
}
|
|
4117
|
+
return relation.target.name;
|
|
4118
|
+
}
|
|
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;
|
|
4126
|
+
}
|
|
4127
|
+
createFilteredRelationCte(state, relationName, relation, predicate) {
|
|
4128
|
+
const cteName = this.generateUniqueCteName(state, relationName);
|
|
4129
|
+
if (!predicate) {
|
|
4130
|
+
throw new Error("Unable to build filter CTE without predicates.");
|
|
4131
|
+
}
|
|
4132
|
+
const columns = Object.keys(relation.target.columns).map((name) => ({
|
|
4133
|
+
type: "Column",
|
|
4134
|
+
table: relation.target.name,
|
|
4135
|
+
name
|
|
4136
|
+
}));
|
|
4137
|
+
const cteQuery = {
|
|
4138
|
+
type: "SelectQuery",
|
|
4139
|
+
from: { type: "Table", name: relation.target.name, schema: relation.target.schema },
|
|
4140
|
+
columns,
|
|
4141
|
+
joins: [],
|
|
4142
|
+
where: predicate
|
|
4143
|
+
};
|
|
4144
|
+
const nextState = this.astService(state).withCte(cteName, cteQuery);
|
|
4145
|
+
const tableNode3 = {
|
|
4146
|
+
type: "Table",
|
|
4147
|
+
name: cteName,
|
|
4148
|
+
alias: relation.target.name
|
|
4149
|
+
};
|
|
4150
|
+
return { state: nextState, table: tableNode3 };
|
|
4151
|
+
}
|
|
4152
|
+
generateUniqueCteName(state, relationName) {
|
|
4153
|
+
const existing = new Set((state.ast.ctes ?? []).map((cte) => cte.name));
|
|
4154
|
+
let candidate = `${relationName}__filtered`;
|
|
4155
|
+
let suffix = 1;
|
|
4156
|
+
while (existing.has(candidate)) {
|
|
4157
|
+
candidate = `${relationName}__filtered_${suffix}`;
|
|
4158
|
+
suffix += 1;
|
|
4159
|
+
}
|
|
4160
|
+
return candidate;
|
|
4161
|
+
}
|
|
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));
|
|
4173
|
+
}
|
|
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);
|
|
4349
|
+
}
|
|
4350
|
+
const joinCondition = this.combineWithAnd(joinFilters);
|
|
4351
|
+
let tableSourceOverride;
|
|
4352
|
+
if (canUseCte) {
|
|
4353
|
+
const predicate = this.combineWithAnd(selfFilters);
|
|
4354
|
+
const cteInfo = this.cteBuilder.createFilteredRelationCte(
|
|
4355
|
+
state,
|
|
4356
|
+
relationName,
|
|
4001
4357
|
relation,
|
|
4358
|
+
predicate
|
|
4359
|
+
);
|
|
4360
|
+
state = cteInfo.state;
|
|
4361
|
+
tableSourceOverride = cteInfo.table;
|
|
4362
|
+
}
|
|
4363
|
+
if (!alreadyJoined) {
|
|
4364
|
+
state = this.joinPlanner.withJoin(
|
|
4365
|
+
state,
|
|
4002
4366
|
relationName,
|
|
4003
|
-
|
|
4004
|
-
|
|
4367
|
+
relation,
|
|
4368
|
+
options?.joinKind ?? JOIN_KINDS.LEFT,
|
|
4369
|
+
joinCondition,
|
|
4370
|
+
tableSourceOverride
|
|
4005
4371
|
);
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
const
|
|
4011
|
-
const
|
|
4012
|
-
|
|
4013
|
-
many.pivotTable.columns,
|
|
4014
|
-
pivotAliasPrefix,
|
|
4015
|
-
pivotColumns,
|
|
4016
|
-
(key) => `Column '${key}' not found on pivot table '${many.pivotTable.name}'`
|
|
4017
|
-
);
|
|
4018
|
-
const combinedSelection = {
|
|
4019
|
-
...targetSelection,
|
|
4020
|
-
...pivotSelection
|
|
4021
|
-
};
|
|
4022
|
-
const relationSelectionResult = this.selectColumns(state, hydration, combinedSelection);
|
|
4023
|
-
state = relationSelectionResult.state;
|
|
4024
|
-
hydration = relationSelectionResult.hydration;
|
|
4025
|
-
hydration = hydration.onRelationIncluded(
|
|
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,
|
|
4026
4379
|
state,
|
|
4380
|
+
hydration,
|
|
4027
4381
|
relation,
|
|
4028
4382
|
relationName,
|
|
4029
4383
|
aliasPrefix,
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
);
|
|
4033
|
-
return { state, hydration };
|
|
4384
|
+
options,
|
|
4385
|
+
selectColumns: (nextState, nextHydration, columns) => this.selectColumns(nextState, nextHydration, columns)
|
|
4386
|
+
});
|
|
4387
|
+
return { state: result.state, hydration: result.hydration };
|
|
4034
4388
|
}
|
|
4035
4389
|
/**
|
|
4036
4390
|
* Applies relation correlation to a query AST
|
|
@@ -4051,37 +4405,6 @@ var RelationService = class {
|
|
|
4051
4405
|
where: whereInSubquery
|
|
4052
4406
|
};
|
|
4053
4407
|
}
|
|
4054
|
-
/**
|
|
4055
|
-
* Creates a join node for a relation
|
|
4056
|
-
* @param state - Current query state
|
|
4057
|
-
* @param relationName - Name of the relation
|
|
4058
|
-
* @param joinKind - Type of join to use
|
|
4059
|
-
* @param extraCondition - Additional join condition
|
|
4060
|
-
* @returns Updated query state with join
|
|
4061
|
-
*/
|
|
4062
|
-
withJoin(state, relationName, joinKind, extraCondition) {
|
|
4063
|
-
const relation = this.getRelation(relationName);
|
|
4064
|
-
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
4065
|
-
if (relation.type === RelationKinds.BelongsToMany) {
|
|
4066
|
-
const joins = buildBelongsToManyJoins(
|
|
4067
|
-
this.table,
|
|
4068
|
-
relationName,
|
|
4069
|
-
relation,
|
|
4070
|
-
joinKind,
|
|
4071
|
-
extraCondition,
|
|
4072
|
-
rootAlias
|
|
4073
|
-
);
|
|
4074
|
-
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
4075
|
-
}
|
|
4076
|
-
const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
|
|
4077
|
-
const joinNode = createJoinNode(
|
|
4078
|
-
joinKind,
|
|
4079
|
-
{ type: "Table", name: relation.target.name, schema: relation.target.schema },
|
|
4080
|
-
condition,
|
|
4081
|
-
relationName
|
|
4082
|
-
);
|
|
4083
|
-
return this.astService(state).withJoin(joinNode);
|
|
4084
|
-
}
|
|
4085
4408
|
/**
|
|
4086
4409
|
* Selects columns for a relation
|
|
4087
4410
|
* @param state - Current query state
|
|
@@ -4096,6 +4419,15 @@ var RelationService = class {
|
|
|
4096
4419
|
hydration: hydration.onColumnsSelected(nextState, addedColumns)
|
|
4097
4420
|
};
|
|
4098
4421
|
}
|
|
4422
|
+
combineWithAnd(expressions) {
|
|
4423
|
+
if (expressions.length === 0) return void 0;
|
|
4424
|
+
if (expressions.length === 1) return expressions[0];
|
|
4425
|
+
return {
|
|
4426
|
+
type: "LogicalExpression",
|
|
4427
|
+
operator: "AND",
|
|
4428
|
+
operands: expressions
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4099
4431
|
/**
|
|
4100
4432
|
* Gets a relation definition by name
|
|
4101
4433
|
* @param relationName - Name of the relation
|
|
@@ -4384,8 +4716,52 @@ var hasEntityMeta = (entity) => {
|
|
|
4384
4716
|
return Boolean(getEntityMeta(entity));
|
|
4385
4717
|
};
|
|
4386
4718
|
|
|
4387
|
-
// src/orm/
|
|
4719
|
+
// src/orm/entity-hydration.ts
|
|
4388
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);
|
|
4389
4765
|
var hideInternal = (obj, keys) => {
|
|
4390
4766
|
for (const key of keys) {
|
|
4391
4767
|
Object.defineProperty(obj, key, {
|
|
@@ -4419,13 +4795,13 @@ var DefaultHasManyCollection = class {
|
|
|
4419
4795
|
this.loader = loader;
|
|
4420
4796
|
this.createEntity = createEntity;
|
|
4421
4797
|
this.localKey = localKey;
|
|
4422
|
-
this.loaded = false;
|
|
4423
|
-
this.items = [];
|
|
4424
|
-
this.added = /* @__PURE__ */ new Set();
|
|
4425
|
-
this.removed = /* @__PURE__ */ new Set();
|
|
4426
4798
|
hideInternal(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
4427
4799
|
this.hydrateFromCache();
|
|
4428
4800
|
}
|
|
4801
|
+
loaded = false;
|
|
4802
|
+
items = [];
|
|
4803
|
+
added = /* @__PURE__ */ new Set();
|
|
4804
|
+
removed = /* @__PURE__ */ new Set();
|
|
4429
4805
|
/**
|
|
4430
4806
|
* Loads the related entities if not already loaded.
|
|
4431
4807
|
* @returns Promise resolving to the array of child entities
|
|
@@ -4433,7 +4809,7 @@ var DefaultHasManyCollection = class {
|
|
|
4433
4809
|
async load() {
|
|
4434
4810
|
if (this.loaded) return this.items;
|
|
4435
4811
|
const map = await this.loader();
|
|
4436
|
-
const key =
|
|
4812
|
+
const key = toKey3(this.root[this.localKey]);
|
|
4437
4813
|
const rows = map.get(key) ?? [];
|
|
4438
4814
|
this.items = rows.map((row) => this.createEntity(row));
|
|
4439
4815
|
this.loaded = true;
|
|
@@ -4446,6 +4822,18 @@ var DefaultHasManyCollection = class {
|
|
|
4446
4822
|
getItems() {
|
|
4447
4823
|
return this.items;
|
|
4448
4824
|
}
|
|
4825
|
+
/**
|
|
4826
|
+
* Array-compatible length for testing frameworks.
|
|
4827
|
+
*/
|
|
4828
|
+
get length() {
|
|
4829
|
+
return this.items.length;
|
|
4830
|
+
}
|
|
4831
|
+
/**
|
|
4832
|
+
* Enables iteration over the collection like an array.
|
|
4833
|
+
*/
|
|
4834
|
+
[Symbol.iterator]() {
|
|
4835
|
+
return this.items[Symbol.iterator]();
|
|
4836
|
+
}
|
|
4449
4837
|
/**
|
|
4450
4838
|
* Adds a new child entity to the collection.
|
|
4451
4839
|
* @param data - Partial data for the new entity
|
|
@@ -4533,7 +4921,7 @@ var DefaultHasManyCollection = class {
|
|
|
4533
4921
|
};
|
|
4534
4922
|
|
|
4535
4923
|
// src/orm/relations/has-one.ts
|
|
4536
|
-
var
|
|
4924
|
+
var toKey4 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4537
4925
|
var hideInternal2 = (obj, keys) => {
|
|
4538
4926
|
for (const key of keys) {
|
|
4539
4927
|
Object.defineProperty(obj, key, {
|
|
@@ -4566,8 +4954,6 @@ var DefaultHasOneReference = class {
|
|
|
4566
4954
|
this.loader = loader;
|
|
4567
4955
|
this.createEntity = createEntity;
|
|
4568
4956
|
this.localKey = localKey;
|
|
4569
|
-
this.loaded = false;
|
|
4570
|
-
this.current = null;
|
|
4571
4957
|
hideInternal2(this, [
|
|
4572
4958
|
"ctx",
|
|
4573
4959
|
"meta",
|
|
@@ -4581,6 +4967,8 @@ var DefaultHasOneReference = class {
|
|
|
4581
4967
|
]);
|
|
4582
4968
|
this.populateFromHydrationCache();
|
|
4583
4969
|
}
|
|
4970
|
+
loaded = false;
|
|
4971
|
+
current = null;
|
|
4584
4972
|
async load() {
|
|
4585
4973
|
if (this.loaded) return this.current;
|
|
4586
4974
|
const map = await this.loader();
|
|
@@ -4589,7 +4977,7 @@ var DefaultHasOneReference = class {
|
|
|
4589
4977
|
this.loaded = true;
|
|
4590
4978
|
return this.current;
|
|
4591
4979
|
}
|
|
4592
|
-
const row = map.get(
|
|
4980
|
+
const row = map.get(toKey4(keyValue));
|
|
4593
4981
|
this.current = row ? this.createEntity(row) : null;
|
|
4594
4982
|
this.loaded = true;
|
|
4595
4983
|
return this.current;
|
|
@@ -4661,7 +5049,7 @@ var DefaultHasOneReference = class {
|
|
|
4661
5049
|
};
|
|
4662
5050
|
|
|
4663
5051
|
// src/orm/relations/belongs-to.ts
|
|
4664
|
-
var
|
|
5052
|
+
var toKey5 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4665
5053
|
var hideInternal3 = (obj, keys) => {
|
|
4666
5054
|
for (const key of keys) {
|
|
4667
5055
|
Object.defineProperty(obj, key, {
|
|
@@ -4694,11 +5082,11 @@ var DefaultBelongsToReference = class {
|
|
|
4694
5082
|
this.loader = loader;
|
|
4695
5083
|
this.createEntity = createEntity;
|
|
4696
5084
|
this.targetKey = targetKey;
|
|
4697
|
-
this.loaded = false;
|
|
4698
|
-
this.current = null;
|
|
4699
5085
|
hideInternal3(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "targetKey"]);
|
|
4700
5086
|
this.populateFromHydrationCache();
|
|
4701
5087
|
}
|
|
5088
|
+
loaded = false;
|
|
5089
|
+
current = null;
|
|
4702
5090
|
async load() {
|
|
4703
5091
|
if (this.loaded) return this.current;
|
|
4704
5092
|
const map = await this.loader();
|
|
@@ -4706,7 +5094,7 @@ var DefaultBelongsToReference = class {
|
|
|
4706
5094
|
if (fkValue === null || fkValue === void 0) {
|
|
4707
5095
|
this.current = null;
|
|
4708
5096
|
} else {
|
|
4709
|
-
const row = map.get(
|
|
5097
|
+
const row = map.get(toKey5(fkValue));
|
|
4710
5098
|
this.current = row ? this.createEntity(row) : null;
|
|
4711
5099
|
}
|
|
4712
5100
|
this.loaded = true;
|
|
@@ -4763,7 +5151,7 @@ var DefaultBelongsToReference = class {
|
|
|
4763
5151
|
};
|
|
4764
5152
|
|
|
4765
5153
|
// src/orm/relations/many-to-many.ts
|
|
4766
|
-
var
|
|
5154
|
+
var toKey6 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4767
5155
|
var hideInternal4 = (obj, keys) => {
|
|
4768
5156
|
for (const key of keys) {
|
|
4769
5157
|
Object.defineProperty(obj, key, {
|
|
@@ -4796,11 +5184,11 @@ var DefaultManyToManyCollection = class {
|
|
|
4796
5184
|
this.loader = loader;
|
|
4797
5185
|
this.createEntity = createEntity;
|
|
4798
5186
|
this.localKey = localKey;
|
|
4799
|
-
this.loaded = false;
|
|
4800
|
-
this.items = [];
|
|
4801
5187
|
hideInternal4(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
4802
5188
|
this.hydrateFromCache();
|
|
4803
5189
|
}
|
|
5190
|
+
loaded = false;
|
|
5191
|
+
items = [];
|
|
4804
5192
|
/**
|
|
4805
5193
|
* Loads the collection items if not already loaded.
|
|
4806
5194
|
* @returns A promise that resolves to the array of target entities.
|
|
@@ -4808,7 +5196,7 @@ var DefaultManyToManyCollection = class {
|
|
|
4808
5196
|
async load() {
|
|
4809
5197
|
if (this.loaded) return this.items;
|
|
4810
5198
|
const map = await this.loader();
|
|
4811
|
-
const key =
|
|
5199
|
+
const key = toKey6(this.root[this.localKey]);
|
|
4812
5200
|
const rows = map.get(key) ?? [];
|
|
4813
5201
|
this.items = rows.map((row) => {
|
|
4814
5202
|
const entity = this.createEntity(row);
|
|
@@ -4827,6 +5215,18 @@ var DefaultManyToManyCollection = class {
|
|
|
4827
5215
|
getItems() {
|
|
4828
5216
|
return this.items;
|
|
4829
5217
|
}
|
|
5218
|
+
/**
|
|
5219
|
+
* Array-compatible length for testing frameworks.
|
|
5220
|
+
*/
|
|
5221
|
+
get length() {
|
|
5222
|
+
return this.items.length;
|
|
5223
|
+
}
|
|
5224
|
+
/**
|
|
5225
|
+
* Enables iteration over the collection like an array.
|
|
5226
|
+
*/
|
|
5227
|
+
[Symbol.iterator]() {
|
|
5228
|
+
return this.items[Symbol.iterator]();
|
|
5229
|
+
}
|
|
4830
5230
|
/**
|
|
4831
5231
|
* Attaches an entity to the collection.
|
|
4832
5232
|
* Registers an 'attach' change in the entity context.
|
|
@@ -4878,15 +5278,15 @@ var DefaultManyToManyCollection = class {
|
|
|
4878
5278
|
*/
|
|
4879
5279
|
async syncByIds(ids) {
|
|
4880
5280
|
await this.load();
|
|
4881
|
-
const normalized = new Set(ids.map((id) =>
|
|
4882
|
-
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))));
|
|
4883
5283
|
for (const id of normalized) {
|
|
4884
5284
|
if (!currentIds.has(id)) {
|
|
4885
5285
|
this.attach(id);
|
|
4886
5286
|
}
|
|
4887
5287
|
}
|
|
4888
5288
|
for (const item of [...this.items]) {
|
|
4889
|
-
const itemId =
|
|
5289
|
+
const itemId = toKey6(this.extractId(item));
|
|
4890
5290
|
if (!normalized.has(itemId)) {
|
|
4891
5291
|
this.detach(item);
|
|
4892
5292
|
}
|
|
@@ -4933,11 +5333,28 @@ var DefaultManyToManyCollection = class {
|
|
|
4933
5333
|
}
|
|
4934
5334
|
};
|
|
4935
5335
|
|
|
4936
|
-
// src/orm/lazy-batch.ts
|
|
4937
|
-
var
|
|
4938
|
-
|
|
4939
|
-
return acc
|
|
4940
|
-
|
|
5336
|
+
// src/orm/lazy-batch/shared.ts
|
|
5337
|
+
var hasColumns = (columns) => Boolean(columns && columns.length > 0);
|
|
5338
|
+
var buildColumnSelection = (table, columns, missingMsg) => {
|
|
5339
|
+
return columns.reduce((acc, column) => {
|
|
5340
|
+
const def = table.columns[column];
|
|
5341
|
+
if (!def) {
|
|
5342
|
+
throw new Error(missingMsg(column));
|
|
5343
|
+
}
|
|
5344
|
+
acc[column] = def;
|
|
5345
|
+
return acc;
|
|
5346
|
+
}, {});
|
|
5347
|
+
};
|
|
5348
|
+
var filterRow = (row, columns) => {
|
|
5349
|
+
const filtered = {};
|
|
5350
|
+
for (const column of columns) {
|
|
5351
|
+
if (column in row) {
|
|
5352
|
+
filtered[column] = row[column];
|
|
5353
|
+
}
|
|
5354
|
+
}
|
|
5355
|
+
return filtered;
|
|
5356
|
+
};
|
|
5357
|
+
var filterRows = (rows, columns) => rows.map((row) => filterRow(row, columns));
|
|
4941
5358
|
var rowsFromResults = (results) => {
|
|
4942
5359
|
const rows = [];
|
|
4943
5360
|
for (const result of results) {
|
|
@@ -4957,7 +5374,7 @@ var executeQuery = async (ctx, qb) => {
|
|
|
4957
5374
|
const results = await ctx.executor.executeSql(compiled.sql, compiled.params);
|
|
4958
5375
|
return rowsFromResults(results);
|
|
4959
5376
|
};
|
|
4960
|
-
var
|
|
5377
|
+
var toKey7 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4961
5378
|
var collectKeysFromRoots = (roots, key) => {
|
|
4962
5379
|
const collected = /* @__PURE__ */ new Set();
|
|
4963
5380
|
for (const tracked of roots) {
|
|
@@ -4969,9 +5386,12 @@ var collectKeysFromRoots = (roots, key) => {
|
|
|
4969
5386
|
return collected;
|
|
4970
5387
|
};
|
|
4971
5388
|
var buildInListValues = (keys) => Array.from(keys);
|
|
4972
|
-
var fetchRowsForKeys = async (ctx, table, column, keys) => {
|
|
4973
|
-
|
|
4974
|
-
qb.where(inList(column, buildInListValues(keys)));
|
|
5389
|
+
var fetchRowsForKeys = async (ctx, table, column, keys, selection, filter) => {
|
|
5390
|
+
let qb = new SelectQueryBuilder(table).select(selection);
|
|
5391
|
+
qb = qb.where(inList(column, buildInListValues(keys)));
|
|
5392
|
+
if (filter) {
|
|
5393
|
+
qb = qb.where(filter);
|
|
5394
|
+
}
|
|
4975
5395
|
return executeQuery(ctx, qb);
|
|
4976
5396
|
};
|
|
4977
5397
|
var groupRowsByMany = (rows, keyColumn) => {
|
|
@@ -4979,7 +5399,7 @@ var groupRowsByMany = (rows, keyColumn) => {
|
|
|
4979
5399
|
for (const row of rows) {
|
|
4980
5400
|
const value = row[keyColumn];
|
|
4981
5401
|
if (value === null || value === void 0) continue;
|
|
4982
|
-
const key =
|
|
5402
|
+
const key = toKey7(value);
|
|
4983
5403
|
const bucket = grouped.get(key) ?? [];
|
|
4984
5404
|
bucket.push(row);
|
|
4985
5405
|
grouped.set(key, bucket);
|
|
@@ -4991,14 +5411,16 @@ var groupRowsByUnique = (rows, keyColumn) => {
|
|
|
4991
5411
|
for (const row of rows) {
|
|
4992
5412
|
const value = row[keyColumn];
|
|
4993
5413
|
if (value === null || value === void 0) continue;
|
|
4994
|
-
const key =
|
|
5414
|
+
const key = toKey7(value);
|
|
4995
5415
|
if (!lookup.has(key)) {
|
|
4996
5416
|
lookup.set(key, row);
|
|
4997
5417
|
}
|
|
4998
5418
|
}
|
|
4999
5419
|
return lookup;
|
|
5000
5420
|
};
|
|
5001
|
-
|
|
5421
|
+
|
|
5422
|
+
// src/orm/lazy-batch/has-many.ts
|
|
5423
|
+
var loadHasManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5002
5424
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5003
5425
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5004
5426
|
const keys = collectKeysFromRoots(roots, localKey);
|
|
@@ -5007,10 +5429,32 @@ var loadHasManyRelation = async (ctx, rootTable, _relationName, relation) => {
|
|
|
5007
5429
|
}
|
|
5008
5430
|
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
5009
5431
|
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
5010
|
-
const
|
|
5011
|
-
|
|
5432
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5433
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
5434
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5435
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
5436
|
+
selectedColumns.push(targetPrimaryKey);
|
|
5437
|
+
}
|
|
5438
|
+
const queryColumns = new Set(selectedColumns);
|
|
5439
|
+
queryColumns.add(relation.foreignKey);
|
|
5440
|
+
const selection = buildColumnSelection(
|
|
5441
|
+
relation.target,
|
|
5442
|
+
Array.from(queryColumns),
|
|
5443
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5444
|
+
);
|
|
5445
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
|
|
5446
|
+
const grouped = groupRowsByMany(rows, relation.foreignKey);
|
|
5447
|
+
if (!requestedColumns) return grouped;
|
|
5448
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5449
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5450
|
+
for (const [key, bucket] of grouped.entries()) {
|
|
5451
|
+
filtered.set(key, filterRows(bucket, visibleColumns));
|
|
5452
|
+
}
|
|
5453
|
+
return filtered;
|
|
5012
5454
|
};
|
|
5013
|
-
|
|
5455
|
+
|
|
5456
|
+
// src/orm/lazy-batch/has-one.ts
|
|
5457
|
+
var loadHasOneRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5014
5458
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5015
5459
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5016
5460
|
const keys = collectKeysFromRoots(roots, localKey);
|
|
@@ -5019,22 +5463,102 @@ var loadHasOneRelation = async (ctx, rootTable, _relationName, relation) => {
|
|
|
5019
5463
|
}
|
|
5020
5464
|
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
5021
5465
|
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
5022
|
-
const
|
|
5023
|
-
|
|
5466
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5467
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
5468
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5469
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
5470
|
+
selectedColumns.push(targetPrimaryKey);
|
|
5471
|
+
}
|
|
5472
|
+
const queryColumns = new Set(selectedColumns);
|
|
5473
|
+
queryColumns.add(relation.foreignKey);
|
|
5474
|
+
const selection = buildColumnSelection(
|
|
5475
|
+
relation.target,
|
|
5476
|
+
Array.from(queryColumns),
|
|
5477
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5478
|
+
);
|
|
5479
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
|
|
5480
|
+
const grouped = groupRowsByUnique(rows, relation.foreignKey);
|
|
5481
|
+
if (!requestedColumns) return grouped;
|
|
5482
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5483
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5484
|
+
for (const [key, row] of grouped.entries()) {
|
|
5485
|
+
filtered.set(key, filterRow(row, visibleColumns));
|
|
5486
|
+
}
|
|
5487
|
+
return filtered;
|
|
5024
5488
|
};
|
|
5025
|
-
|
|
5489
|
+
|
|
5490
|
+
// src/orm/lazy-batch/belongs-to.ts
|
|
5491
|
+
var loadBelongsToRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5026
5492
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5027
|
-
const
|
|
5493
|
+
const getForeignKeys = () => collectKeysFromRoots(roots, relation.foreignKey);
|
|
5494
|
+
let foreignKeys = getForeignKeys();
|
|
5495
|
+
if (!foreignKeys.size) {
|
|
5496
|
+
const pkName = findPrimaryKey(rootTable);
|
|
5497
|
+
const pkColumn2 = rootTable.columns[pkName];
|
|
5498
|
+
const fkColumn = rootTable.columns[relation.foreignKey];
|
|
5499
|
+
if (pkColumn2 && fkColumn) {
|
|
5500
|
+
const missingKeys = /* @__PURE__ */ new Set();
|
|
5501
|
+
const entityByPk = /* @__PURE__ */ new Map();
|
|
5502
|
+
for (const tracked of roots) {
|
|
5503
|
+
const entity = tracked.entity;
|
|
5504
|
+
const pkValue = entity[pkName];
|
|
5505
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
5506
|
+
const fkValue = entity[relation.foreignKey];
|
|
5507
|
+
if (fkValue === void 0 || fkValue === null) {
|
|
5508
|
+
missingKeys.add(pkValue);
|
|
5509
|
+
entityByPk.set(pkValue, entity);
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
if (missingKeys.size) {
|
|
5513
|
+
const selection2 = buildColumnSelection(
|
|
5514
|
+
rootTable,
|
|
5515
|
+
[pkName, relation.foreignKey],
|
|
5516
|
+
(column) => `Column '${column}' not found on table '${rootTable.name}'`
|
|
5517
|
+
);
|
|
5518
|
+
const keyRows = await fetchRowsForKeys(ctx, rootTable, pkColumn2, missingKeys, selection2);
|
|
5519
|
+
for (const row of keyRows) {
|
|
5520
|
+
const pkValue = row[pkName];
|
|
5521
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
5522
|
+
const entity = entityByPk.get(pkValue);
|
|
5523
|
+
if (!entity) continue;
|
|
5524
|
+
const fkValue = row[relation.foreignKey];
|
|
5525
|
+
if (fkValue !== void 0 && fkValue !== null) {
|
|
5526
|
+
entity[relation.foreignKey] = fkValue;
|
|
5527
|
+
}
|
|
5528
|
+
}
|
|
5529
|
+
foreignKeys = getForeignKeys();
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5532
|
+
}
|
|
5028
5533
|
if (!foreignKeys.size) {
|
|
5029
5534
|
return /* @__PURE__ */ new Map();
|
|
5030
5535
|
}
|
|
5031
5536
|
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
5032
5537
|
const pkColumn = relation.target.columns[targetKey];
|
|
5033
5538
|
if (!pkColumn) return /* @__PURE__ */ new Map();
|
|
5034
|
-
const
|
|
5035
|
-
|
|
5539
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5540
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5541
|
+
if (!selectedColumns.includes(targetKey)) {
|
|
5542
|
+
selectedColumns.push(targetKey);
|
|
5543
|
+
}
|
|
5544
|
+
const selection = buildColumnSelection(
|
|
5545
|
+
relation.target,
|
|
5546
|
+
selectedColumns,
|
|
5547
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5548
|
+
);
|
|
5549
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, pkColumn, foreignKeys, selection, options?.filter);
|
|
5550
|
+
const grouped = groupRowsByUnique(rows, targetKey);
|
|
5551
|
+
if (!requestedColumns) return grouped;
|
|
5552
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5553
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5554
|
+
for (const [key, row] of grouped.entries()) {
|
|
5555
|
+
filtered.set(key, filterRow(row, visibleColumns));
|
|
5556
|
+
}
|
|
5557
|
+
return filtered;
|
|
5036
5558
|
};
|
|
5037
|
-
|
|
5559
|
+
|
|
5560
|
+
// src/orm/lazy-batch/belongs-to-many.ts
|
|
5561
|
+
var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5038
5562
|
const rootKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5039
5563
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5040
5564
|
const rootIds = collectKeysFromRoots(roots, rootKey);
|
|
@@ -5043,21 +5567,41 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
5043
5567
|
}
|
|
5044
5568
|
const pivotColumn = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
5045
5569
|
if (!pivotColumn) return /* @__PURE__ */ new Map();
|
|
5046
|
-
const
|
|
5570
|
+
const pivotColumnsRequested = hasColumns(options?.pivot?.columns) ? [...options.pivot.columns] : void 0;
|
|
5571
|
+
const useIncludeDefaults = options !== void 0;
|
|
5572
|
+
let pivotSelectedColumns;
|
|
5573
|
+
if (pivotColumnsRequested) {
|
|
5574
|
+
pivotSelectedColumns = [...pivotColumnsRequested];
|
|
5575
|
+
} else if (useIncludeDefaults) {
|
|
5576
|
+
const pivotPk = relation.pivotPrimaryKey || findPrimaryKey(relation.pivotTable);
|
|
5577
|
+
pivotSelectedColumns = relation.defaultPivotColumns ?? buildDefaultPivotColumns(relation, pivotPk);
|
|
5578
|
+
} else {
|
|
5579
|
+
pivotSelectedColumns = Object.keys(relation.pivotTable.columns);
|
|
5580
|
+
}
|
|
5581
|
+
const pivotQueryColumns = new Set(pivotSelectedColumns);
|
|
5582
|
+
pivotQueryColumns.add(relation.pivotForeignKeyToRoot);
|
|
5583
|
+
pivotQueryColumns.add(relation.pivotForeignKeyToTarget);
|
|
5584
|
+
const pivotSelection = buildColumnSelection(
|
|
5585
|
+
relation.pivotTable,
|
|
5586
|
+
Array.from(pivotQueryColumns),
|
|
5587
|
+
(column) => `Column '${column}' not found on pivot table '${relation.pivotTable.name}'`
|
|
5588
|
+
);
|
|
5589
|
+
const pivotRows = await fetchRowsForKeys(ctx, relation.pivotTable, pivotColumn, rootIds, pivotSelection);
|
|
5047
5590
|
const rootLookup = /* @__PURE__ */ new Map();
|
|
5048
5591
|
const targetIds = /* @__PURE__ */ new Set();
|
|
5592
|
+
const pivotVisibleColumns = new Set(pivotSelectedColumns);
|
|
5049
5593
|
for (const pivot of pivotRows) {
|
|
5050
5594
|
const rootValue = pivot[relation.pivotForeignKeyToRoot];
|
|
5051
5595
|
const targetValue = pivot[relation.pivotForeignKeyToTarget];
|
|
5052
5596
|
if (rootValue === null || rootValue === void 0 || targetValue === null || targetValue === void 0) {
|
|
5053
5597
|
continue;
|
|
5054
5598
|
}
|
|
5055
|
-
const bucket = rootLookup.get(
|
|
5599
|
+
const bucket = rootLookup.get(toKey7(rootValue)) ?? [];
|
|
5056
5600
|
bucket.push({
|
|
5057
5601
|
targetId: targetValue,
|
|
5058
|
-
pivot:
|
|
5602
|
+
pivot: pivotVisibleColumns.size ? filterRow(pivot, pivotVisibleColumns) : {}
|
|
5059
5603
|
});
|
|
5060
|
-
rootLookup.set(
|
|
5604
|
+
rootLookup.set(toKey7(rootValue), bucket);
|
|
5061
5605
|
targetIds.add(targetValue);
|
|
5062
5606
|
}
|
|
5063
5607
|
if (!targetIds.size) {
|
|
@@ -5066,16 +5610,34 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
5066
5610
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
5067
5611
|
const targetPkColumn = relation.target.columns[targetKey];
|
|
5068
5612
|
if (!targetPkColumn) return /* @__PURE__ */ new Map();
|
|
5069
|
-
const
|
|
5613
|
+
const targetRequestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5614
|
+
const targetSelectedColumns = targetRequestedColumns ? [...targetRequestedColumns] : Object.keys(relation.target.columns);
|
|
5615
|
+
if (!targetSelectedColumns.includes(targetKey)) {
|
|
5616
|
+
targetSelectedColumns.push(targetKey);
|
|
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
|
+
);
|
|
5070
5631
|
const targetMap = groupRowsByUnique(targetRows, targetKey);
|
|
5632
|
+
const targetVisibleColumns = new Set(targetSelectedColumns);
|
|
5071
5633
|
const result = /* @__PURE__ */ new Map();
|
|
5072
5634
|
for (const [rootId, entries] of rootLookup.entries()) {
|
|
5073
5635
|
const bucket = [];
|
|
5074
5636
|
for (const entry of entries) {
|
|
5075
|
-
const targetRow = targetMap.get(
|
|
5637
|
+
const targetRow = targetMap.get(toKey7(entry.targetId));
|
|
5076
5638
|
if (!targetRow) continue;
|
|
5077
5639
|
bucket.push({
|
|
5078
|
-
...targetRow,
|
|
5640
|
+
...targetRequestedColumns ? filterRow(targetRow, targetVisibleColumns) : targetRow,
|
|
5079
5641
|
_pivot: entry.pivot
|
|
5080
5642
|
});
|
|
5081
5643
|
}
|
|
@@ -5084,7 +5646,7 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
5084
5646
|
return result;
|
|
5085
5647
|
};
|
|
5086
5648
|
|
|
5087
|
-
// src/orm/entity.ts
|
|
5649
|
+
// src/orm/entity-relation-cache.ts
|
|
5088
5650
|
var relationLoaderCache = (meta, relationName, factory) => {
|
|
5089
5651
|
if (meta.relationCache.has(relationName)) {
|
|
5090
5652
|
return meta.relationCache.get(relationName);
|
|
@@ -5105,200 +5667,147 @@ var relationLoaderCache = (meta, relationName, factory) => {
|
|
|
5105
5667
|
}
|
|
5106
5668
|
return promise;
|
|
5107
5669
|
};
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
relationHydration: /* @__PURE__ */ new Map(),
|
|
5116
|
-
relationWrappers: /* @__PURE__ */ new Map()
|
|
5117
|
-
};
|
|
5118
|
-
Object.defineProperty(target, ENTITY_META, {
|
|
5119
|
-
value: meta,
|
|
5120
|
-
enumerable: false,
|
|
5121
|
-
writable: false
|
|
5122
|
-
});
|
|
5123
|
-
const handler = {
|
|
5124
|
-
get(targetObj, prop, receiver) {
|
|
5125
|
-
if (prop === ENTITY_META) {
|
|
5126
|
-
return meta;
|
|
5670
|
+
|
|
5671
|
+
// src/orm/entity-relations.ts
|
|
5672
|
+
var proxifyRelationWrapper = (wrapper) => {
|
|
5673
|
+
return new Proxy(wrapper, {
|
|
5674
|
+
get(target, prop, receiver) {
|
|
5675
|
+
if (typeof prop === "symbol") {
|
|
5676
|
+
return Reflect.get(target, prop, receiver);
|
|
5127
5677
|
}
|
|
5128
|
-
if (prop
|
|
5129
|
-
return
|
|
5130
|
-
const wrapper = getRelationWrapper(meta, relationName, receiver);
|
|
5131
|
-
if (wrapper && typeof wrapper.load === "function") {
|
|
5132
|
-
return wrapper.load();
|
|
5133
|
-
}
|
|
5134
|
-
return void 0;
|
|
5135
|
-
};
|
|
5678
|
+
if (prop in target) {
|
|
5679
|
+
return Reflect.get(target, prop, receiver);
|
|
5136
5680
|
}
|
|
5137
|
-
|
|
5138
|
-
|
|
5681
|
+
const getItems = target.getItems;
|
|
5682
|
+
if (typeof getItems === "function") {
|
|
5683
|
+
const items = getItems.call(target);
|
|
5684
|
+
if (items && prop in items) {
|
|
5685
|
+
const propName = prop;
|
|
5686
|
+
const value = items[propName];
|
|
5687
|
+
return typeof value === "function" ? value.bind(items) : value;
|
|
5688
|
+
}
|
|
5139
5689
|
}
|
|
5140
|
-
|
|
5690
|
+
const getRef = target.get;
|
|
5691
|
+
if (typeof getRef === "function") {
|
|
5692
|
+
const current = getRef.call(target);
|
|
5693
|
+
if (current && prop in current) {
|
|
5694
|
+
const propName = prop;
|
|
5695
|
+
const value = current[propName];
|
|
5696
|
+
return typeof value === "function" ? value.bind(current) : value;
|
|
5697
|
+
}
|
|
5698
|
+
}
|
|
5699
|
+
return void 0;
|
|
5141
5700
|
},
|
|
5142
|
-
set(
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
ctx.markDirty(receiver);
|
|
5701
|
+
set(target, prop, value, receiver) {
|
|
5702
|
+
if (typeof prop === "symbol") {
|
|
5703
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5146
5704
|
}
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
};
|
|
5150
|
-
const proxy = new Proxy(target, handler);
|
|
5151
|
-
populateHydrationCache(proxy, row, meta);
|
|
5152
|
-
return proxy;
|
|
5153
|
-
};
|
|
5154
|
-
var createEntityFromRow = (ctx, table, row, lazyRelations = []) => {
|
|
5155
|
-
const pkName = findPrimaryKey(table);
|
|
5156
|
-
const pkValue = row[pkName];
|
|
5157
|
-
if (pkValue !== void 0 && pkValue !== null) {
|
|
5158
|
-
const tracked = ctx.getEntity(table, pkValue);
|
|
5159
|
-
if (tracked) return tracked;
|
|
5160
|
-
}
|
|
5161
|
-
const entity = createEntityProxy(ctx, table, row, lazyRelations);
|
|
5162
|
-
if (pkValue !== void 0 && pkValue !== null) {
|
|
5163
|
-
ctx.trackManaged(table, pkValue, entity);
|
|
5164
|
-
} else {
|
|
5165
|
-
ctx.trackNew(table, entity);
|
|
5166
|
-
}
|
|
5167
|
-
return entity;
|
|
5168
|
-
};
|
|
5169
|
-
var toKey7 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
5170
|
-
var populateHydrationCache = (entity, row, meta) => {
|
|
5171
|
-
for (const relationName of Object.keys(meta.table.relations)) {
|
|
5172
|
-
const relation = meta.table.relations[relationName];
|
|
5173
|
-
const data = row[relationName];
|
|
5174
|
-
if (relation.type === RelationKinds.HasOne) {
|
|
5175
|
-
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
5176
|
-
const rootValue = entity[localKey];
|
|
5177
|
-
if (rootValue === void 0 || rootValue === null) continue;
|
|
5178
|
-
if (!data || typeof data !== "object") continue;
|
|
5179
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5180
|
-
cache.set(toKey7(rootValue), data);
|
|
5181
|
-
meta.relationHydration.set(relationName, cache);
|
|
5182
|
-
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5183
|
-
continue;
|
|
5184
|
-
}
|
|
5185
|
-
if (!Array.isArray(data)) continue;
|
|
5186
|
-
if (relation.type === RelationKinds.HasMany || relation.type === RelationKinds.BelongsToMany) {
|
|
5187
|
-
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
5188
|
-
const rootValue = entity[localKey];
|
|
5189
|
-
if (rootValue === void 0 || rootValue === null) continue;
|
|
5190
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5191
|
-
cache.set(toKey7(rootValue), data);
|
|
5192
|
-
meta.relationHydration.set(relationName, cache);
|
|
5193
|
-
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5194
|
-
continue;
|
|
5195
|
-
}
|
|
5196
|
-
if (relation.type === RelationKinds.BelongsTo) {
|
|
5197
|
-
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
5198
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5199
|
-
for (const item of data) {
|
|
5200
|
-
const pkValue = item[targetKey];
|
|
5201
|
-
if (pkValue === void 0 || pkValue === null) continue;
|
|
5202
|
-
cache.set(toKey7(pkValue), item);
|
|
5705
|
+
if (prop in target) {
|
|
5706
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5203
5707
|
}
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5708
|
+
const getRef = target.get;
|
|
5709
|
+
if (typeof getRef === "function") {
|
|
5710
|
+
const current = getRef.call(target);
|
|
5711
|
+
if (current && typeof current === "object") {
|
|
5712
|
+
return Reflect.set(current, prop, value);
|
|
5713
|
+
}
|
|
5714
|
+
}
|
|
5715
|
+
const getItems = target.getItems;
|
|
5716
|
+
if (typeof getItems === "function") {
|
|
5717
|
+
const items = getItems.call(target);
|
|
5718
|
+
return Reflect.set(items, prop, value);
|
|
5207
5719
|
}
|
|
5720
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5208
5721
|
}
|
|
5209
|
-
}
|
|
5722
|
+
});
|
|
5210
5723
|
};
|
|
5211
|
-
var getRelationWrapper = (meta, relationName, owner) => {
|
|
5212
|
-
|
|
5213
|
-
|
|
5724
|
+
var getRelationWrapper = (meta, relationName, owner, createEntity) => {
|
|
5725
|
+
const relationKey = relationName;
|
|
5726
|
+
if (meta.relationWrappers.has(relationKey)) {
|
|
5727
|
+
return meta.relationWrappers.get(relationKey);
|
|
5214
5728
|
}
|
|
5215
|
-
const relation = meta.table.relations[
|
|
5729
|
+
const relation = meta.table.relations[relationKey];
|
|
5216
5730
|
if (!relation) return void 0;
|
|
5217
|
-
const wrapper = instantiateWrapper(meta,
|
|
5218
|
-
if (wrapper)
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
return
|
|
5222
|
-
};
|
|
5223
|
-
var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
5731
|
+
const wrapper = instantiateWrapper(meta, relationKey, relation, owner, createEntity);
|
|
5732
|
+
if (!wrapper) return void 0;
|
|
5733
|
+
const proxied = proxifyRelationWrapper(wrapper);
|
|
5734
|
+
meta.relationWrappers.set(relationKey, proxied);
|
|
5735
|
+
return proxied;
|
|
5736
|
+
};
|
|
5737
|
+
var instantiateWrapper = (meta, relationName, relation, owner, createEntity) => {
|
|
5738
|
+
const metaBase = meta;
|
|
5739
|
+
const lazyOptions = meta.lazyRelationOptions.get(relationName);
|
|
5740
|
+
const loadCached = (factory) => relationLoaderCache(metaBase, relationName, factory);
|
|
5224
5741
|
switch (relation.type) {
|
|
5225
5742
|
case RelationKinds.HasOne: {
|
|
5226
5743
|
const hasOne2 = relation;
|
|
5227
5744
|
const localKey = hasOne2.localKey || findPrimaryKey(meta.table);
|
|
5228
|
-
const loader = () =>
|
|
5229
|
-
meta,
|
|
5230
|
-
relationName,
|
|
5231
|
-
() => loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne2)
|
|
5745
|
+
const loader = () => loadCached(
|
|
5746
|
+
() => loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne2, lazyOptions)
|
|
5232
5747
|
);
|
|
5233
5748
|
return new DefaultHasOneReference(
|
|
5234
5749
|
meta.ctx,
|
|
5235
|
-
|
|
5750
|
+
metaBase,
|
|
5236
5751
|
owner,
|
|
5237
5752
|
relationName,
|
|
5238
5753
|
hasOne2,
|
|
5239
5754
|
meta.table,
|
|
5240
5755
|
loader,
|
|
5241
|
-
(row) =>
|
|
5756
|
+
(row) => createEntity(hasOne2.target, row),
|
|
5242
5757
|
localKey
|
|
5243
5758
|
);
|
|
5244
5759
|
}
|
|
5245
5760
|
case RelationKinds.HasMany: {
|
|
5246
5761
|
const hasMany2 = relation;
|
|
5247
5762
|
const localKey = hasMany2.localKey || findPrimaryKey(meta.table);
|
|
5248
|
-
const loader = () =>
|
|
5249
|
-
meta,
|
|
5250
|
-
relationName,
|
|
5251
|
-
() => loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany2)
|
|
5763
|
+
const loader = () => loadCached(
|
|
5764
|
+
() => loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany2, lazyOptions)
|
|
5252
5765
|
);
|
|
5253
5766
|
return new DefaultHasManyCollection(
|
|
5254
5767
|
meta.ctx,
|
|
5255
|
-
|
|
5768
|
+
metaBase,
|
|
5256
5769
|
owner,
|
|
5257
5770
|
relationName,
|
|
5258
5771
|
hasMany2,
|
|
5259
5772
|
meta.table,
|
|
5260
5773
|
loader,
|
|
5261
|
-
(row) =>
|
|
5774
|
+
(row) => createEntity(relation.target, row),
|
|
5262
5775
|
localKey
|
|
5263
5776
|
);
|
|
5264
5777
|
}
|
|
5265
5778
|
case RelationKinds.BelongsTo: {
|
|
5266
5779
|
const belongsTo2 = relation;
|
|
5267
5780
|
const targetKey = belongsTo2.localKey || findPrimaryKey(belongsTo2.target);
|
|
5268
|
-
const loader = () =>
|
|
5269
|
-
meta,
|
|
5270
|
-
relationName,
|
|
5271
|
-
() => loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo2)
|
|
5781
|
+
const loader = () => loadCached(
|
|
5782
|
+
() => loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo2, lazyOptions)
|
|
5272
5783
|
);
|
|
5273
5784
|
return new DefaultBelongsToReference(
|
|
5274
5785
|
meta.ctx,
|
|
5275
|
-
|
|
5786
|
+
metaBase,
|
|
5276
5787
|
owner,
|
|
5277
5788
|
relationName,
|
|
5278
5789
|
belongsTo2,
|
|
5279
5790
|
meta.table,
|
|
5280
5791
|
loader,
|
|
5281
|
-
(row) =>
|
|
5792
|
+
(row) => createEntity(relation.target, row),
|
|
5282
5793
|
targetKey
|
|
5283
5794
|
);
|
|
5284
5795
|
}
|
|
5285
5796
|
case RelationKinds.BelongsToMany: {
|
|
5286
5797
|
const many = relation;
|
|
5287
5798
|
const localKey = many.localKey || findPrimaryKey(meta.table);
|
|
5288
|
-
const loader = () =>
|
|
5289
|
-
meta,
|
|
5290
|
-
relationName,
|
|
5291
|
-
() => loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many)
|
|
5799
|
+
const loader = () => loadCached(
|
|
5800
|
+
() => loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many, lazyOptions)
|
|
5292
5801
|
);
|
|
5293
5802
|
return new DefaultManyToManyCollection(
|
|
5294
5803
|
meta.ctx,
|
|
5295
|
-
|
|
5804
|
+
metaBase,
|
|
5296
5805
|
owner,
|
|
5297
5806
|
relationName,
|
|
5298
5807
|
many,
|
|
5299
5808
|
meta.table,
|
|
5300
5809
|
loader,
|
|
5301
|
-
(row) =>
|
|
5810
|
+
(row) => createEntity(relation.target, row),
|
|
5302
5811
|
localKey
|
|
5303
5812
|
);
|
|
5304
5813
|
}
|
|
@@ -5307,51 +5816,570 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
5307
5816
|
}
|
|
5308
5817
|
};
|
|
5309
5818
|
|
|
5310
|
-
// src/orm/
|
|
5311
|
-
var
|
|
5312
|
-
const
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5819
|
+
// src/orm/entity.ts
|
|
5820
|
+
var createEntityProxy = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
5821
|
+
const target = { ...row };
|
|
5822
|
+
const meta = {
|
|
5823
|
+
ctx,
|
|
5824
|
+
table,
|
|
5825
|
+
lazyRelations: [...lazyRelations],
|
|
5826
|
+
lazyRelationOptions: new Map(lazyRelationOptions),
|
|
5827
|
+
relationCache: /* @__PURE__ */ new Map(),
|
|
5828
|
+
relationHydration: /* @__PURE__ */ new Map(),
|
|
5829
|
+
relationWrappers: /* @__PURE__ */ new Map()
|
|
5830
|
+
};
|
|
5831
|
+
const createRelationEntity = (relationTable, relationRow) => createEntityFromRow(meta.ctx, relationTable, relationRow);
|
|
5832
|
+
Object.defineProperty(target, ENTITY_META, {
|
|
5833
|
+
value: meta,
|
|
5834
|
+
enumerable: false,
|
|
5835
|
+
writable: false
|
|
5836
|
+
});
|
|
5837
|
+
const handler = {
|
|
5838
|
+
get(targetObj, prop, receiver) {
|
|
5839
|
+
if (prop === ENTITY_META) {
|
|
5840
|
+
return meta;
|
|
5841
|
+
}
|
|
5842
|
+
if (prop === "$load") {
|
|
5843
|
+
return async (relationName) => {
|
|
5844
|
+
const wrapper = getRelationWrapper(meta, relationName, receiver, createRelationEntity);
|
|
5845
|
+
if (wrapper && typeof wrapper.load === "function") {
|
|
5846
|
+
return wrapper.load();
|
|
5847
|
+
}
|
|
5848
|
+
return void 0;
|
|
5849
|
+
};
|
|
5850
|
+
}
|
|
5851
|
+
if (typeof prop === "string" && table.relations[prop]) {
|
|
5852
|
+
return getRelationWrapper(meta, prop, receiver, createRelationEntity);
|
|
5853
|
+
}
|
|
5854
|
+
return Reflect.get(targetObj, prop, receiver);
|
|
5855
|
+
},
|
|
5856
|
+
set(targetObj, prop, value, receiver) {
|
|
5857
|
+
const result = Reflect.set(targetObj, prop, value, receiver);
|
|
5858
|
+
if (typeof prop === "string" && table.columns[prop]) {
|
|
5859
|
+
ctx.markDirty(receiver);
|
|
5860
|
+
}
|
|
5861
|
+
return result;
|
|
5862
|
+
}
|
|
5863
|
+
};
|
|
5864
|
+
const proxy = new Proxy(target, handler);
|
|
5865
|
+
populateHydrationCache(proxy, row, meta);
|
|
5866
|
+
return proxy;
|
|
5867
|
+
};
|
|
5868
|
+
var createEntityFromRow = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
5869
|
+
const pkName = findPrimaryKey(table);
|
|
5870
|
+
const pkValue = row[pkName];
|
|
5871
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
5872
|
+
const tracked = ctx.getEntity(table, pkValue);
|
|
5873
|
+
if (tracked) return tracked;
|
|
5874
|
+
}
|
|
5875
|
+
const entity = createEntityProxy(ctx, table, row, lazyRelations, lazyRelationOptions);
|
|
5876
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
5877
|
+
ctx.trackManaged(table, pkValue, entity);
|
|
5878
|
+
} else {
|
|
5879
|
+
ctx.trackNew(table, entity);
|
|
5880
|
+
}
|
|
5881
|
+
return entity;
|
|
5882
|
+
};
|
|
5883
|
+
|
|
5884
|
+
// src/orm/execute.ts
|
|
5885
|
+
var flattenResults = (results) => {
|
|
5886
|
+
const rows = [];
|
|
5887
|
+
for (const result of results) {
|
|
5888
|
+
const { columns, values } = result;
|
|
5889
|
+
for (const valueRow of values) {
|
|
5890
|
+
const row = {};
|
|
5891
|
+
columns.forEach((column, idx) => {
|
|
5892
|
+
row[column] = valueRow[idx];
|
|
5893
|
+
});
|
|
5894
|
+
rows.push(row);
|
|
5895
|
+
}
|
|
5896
|
+
}
|
|
5897
|
+
return rows;
|
|
5898
|
+
};
|
|
5899
|
+
var executeWithContexts = async (execCtx, entityCtx, qb) => {
|
|
5900
|
+
const ast = qb.getAST();
|
|
5901
|
+
const compiled = execCtx.dialect.compileSelect(ast);
|
|
5902
|
+
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
5903
|
+
const rows = flattenResults(executed);
|
|
5904
|
+
const lazyRelations = qb.getLazyRelations();
|
|
5905
|
+
const lazyRelationOptions = qb.getLazyRelationOptions();
|
|
5906
|
+
if (ast.setOps && ast.setOps.length > 0) {
|
|
5907
|
+
const proxies = rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
5908
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5909
|
+
return proxies;
|
|
5910
|
+
}
|
|
5911
|
+
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
5912
|
+
const entities = hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
5913
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
5914
|
+
return entities;
|
|
5915
|
+
};
|
|
5916
|
+
async function executeHydrated(session, qb) {
|
|
5917
|
+
return executeWithContexts(session.getExecutionContext(), session, qb);
|
|
5918
|
+
}
|
|
5919
|
+
async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
|
|
5920
|
+
const entityCtx = hydCtx.entityContext;
|
|
5921
|
+
if (!entityCtx) {
|
|
5922
|
+
throw new Error("Hydration context is missing an EntityContext");
|
|
5923
|
+
}
|
|
5924
|
+
return executeWithContexts(execCtx, entityCtx, qb);
|
|
5925
|
+
}
|
|
5926
|
+
var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOptions) => {
|
|
5927
|
+
if (!lazyRelations.length) return;
|
|
5928
|
+
const tracked = ctx.getEntitiesForTable(table);
|
|
5929
|
+
if (!tracked.length) return;
|
|
5930
|
+
const meta = getEntityMeta(tracked[0].entity);
|
|
5931
|
+
if (!meta) return;
|
|
5932
|
+
for (const relationName of lazyRelations) {
|
|
5933
|
+
const relation = table.relations[relationName];
|
|
5934
|
+
if (!relation) continue;
|
|
5935
|
+
const key = relationName;
|
|
5936
|
+
const options = lazyRelationOptions.get(key);
|
|
5937
|
+
if (!options) {
|
|
5938
|
+
continue;
|
|
5939
|
+
}
|
|
5940
|
+
switch (relation.type) {
|
|
5941
|
+
case RelationKinds.HasOne:
|
|
5942
|
+
await relationLoaderCache(
|
|
5943
|
+
meta,
|
|
5944
|
+
key,
|
|
5945
|
+
() => loadHasOneRelation(ctx, table, key, relation, options)
|
|
5946
|
+
);
|
|
5947
|
+
break;
|
|
5948
|
+
case RelationKinds.HasMany:
|
|
5949
|
+
await relationLoaderCache(
|
|
5950
|
+
meta,
|
|
5951
|
+
key,
|
|
5952
|
+
() => loadHasManyRelation(ctx, table, key, relation, options)
|
|
5953
|
+
);
|
|
5954
|
+
break;
|
|
5955
|
+
case RelationKinds.BelongsTo:
|
|
5956
|
+
await relationLoaderCache(
|
|
5957
|
+
meta,
|
|
5958
|
+
key,
|
|
5959
|
+
() => loadBelongsToRelation(ctx, table, key, relation, options)
|
|
5960
|
+
);
|
|
5961
|
+
break;
|
|
5962
|
+
case RelationKinds.BelongsToMany:
|
|
5963
|
+
await relationLoaderCache(
|
|
5964
|
+
meta,
|
|
5965
|
+
key,
|
|
5966
|
+
() => loadBelongsToManyRelation(ctx, table, key, relation, options)
|
|
5967
|
+
);
|
|
5968
|
+
break;
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
};
|
|
5972
|
+
|
|
5973
|
+
// src/query-builder/query-resolution.ts
|
|
5974
|
+
function resolveSelectQuery(query) {
|
|
5975
|
+
const candidate = query;
|
|
5976
|
+
return typeof candidate.getAST === "function" && candidate.getAST ? candidate.getAST() : query;
|
|
5977
|
+
}
|
|
5978
|
+
|
|
5979
|
+
// src/query-builder/select/select-operations.ts
|
|
5980
|
+
function applyOrderBy(context, predicateFacet, term, directionOrOptions) {
|
|
5981
|
+
const options = typeof directionOrOptions === "string" ? { direction: directionOrOptions } : directionOrOptions;
|
|
5982
|
+
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
5983
|
+
return predicateFacet.orderBy(context, term, dir, options.nulls, options.collation);
|
|
5984
|
+
}
|
|
5985
|
+
async function executeCount(context, env, session) {
|
|
5986
|
+
const unpagedAst = {
|
|
5987
|
+
...context.state.ast,
|
|
5988
|
+
orderBy: void 0,
|
|
5989
|
+
limit: void 0,
|
|
5990
|
+
offset: void 0
|
|
5991
|
+
};
|
|
5992
|
+
const nextState = new SelectQueryState(env.table, unpagedAst);
|
|
5993
|
+
const nextContext = {
|
|
5994
|
+
...context,
|
|
5995
|
+
state: nextState
|
|
5996
|
+
};
|
|
5997
|
+
const subAst = nextContext.hydration.applyToAst(nextState.ast);
|
|
5998
|
+
const countQuery = {
|
|
5999
|
+
type: "SelectQuery",
|
|
6000
|
+
from: derivedTable(subAst, "__metal_count"),
|
|
6001
|
+
columns: [{ type: "Function", name: "COUNT", args: [], alias: "total" }],
|
|
6002
|
+
joins: []
|
|
6003
|
+
};
|
|
6004
|
+
const execCtx = session.getExecutionContext();
|
|
6005
|
+
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
6006
|
+
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
6007
|
+
const value = results[0]?.values?.[0]?.[0];
|
|
6008
|
+
if (typeof value === "number") return value;
|
|
6009
|
+
if (typeof value === "bigint") return Number(value);
|
|
6010
|
+
if (typeof value === "string") return Number(value);
|
|
6011
|
+
return value === null || value === void 0 ? 0 : Number(value);
|
|
6012
|
+
}
|
|
6013
|
+
async function executePagedQuery(builder, session, options, countCallback) {
|
|
6014
|
+
const { page, pageSize } = options;
|
|
6015
|
+
if (!Number.isInteger(page) || page < 1) {
|
|
6016
|
+
throw new Error("executePaged: page must be an integer >= 1");
|
|
6017
|
+
}
|
|
6018
|
+
if (!Number.isInteger(pageSize) || pageSize < 1) {
|
|
6019
|
+
throw new Error("executePaged: pageSize must be an integer >= 1");
|
|
6020
|
+
}
|
|
6021
|
+
const offset = (page - 1) * pageSize;
|
|
6022
|
+
const [items, totalItems] = await Promise.all([
|
|
6023
|
+
builder.limit(pageSize).offset(offset).execute(session),
|
|
6024
|
+
countCallback(session)
|
|
6025
|
+
]);
|
|
6026
|
+
return { items, totalItems };
|
|
6027
|
+
}
|
|
6028
|
+
function buildWhereHasPredicate(env, context, relationFacet, createChildBuilder, relationName, callbackOrOptions, maybeOptions, negate = false) {
|
|
6029
|
+
const relation = env.table.relations[relationName];
|
|
6030
|
+
if (!relation) {
|
|
6031
|
+
throw new Error(`Relation '${relationName}' not found on table '${env.table.name}'`);
|
|
6032
|
+
}
|
|
6033
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
6034
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
6035
|
+
let subQb = createChildBuilder(relation.target);
|
|
6036
|
+
if (callback) {
|
|
6037
|
+
subQb = callback(subQb);
|
|
6038
|
+
}
|
|
6039
|
+
const subAst = subQb.getAST();
|
|
6040
|
+
const finalSubAst = relationFacet.applyRelationCorrelation(
|
|
6041
|
+
context,
|
|
6042
|
+
relationName,
|
|
6043
|
+
subAst,
|
|
6044
|
+
options?.correlate
|
|
6045
|
+
);
|
|
6046
|
+
return negate ? notExists(finalSubAst) : exists(finalSubAst);
|
|
6047
|
+
}
|
|
6048
|
+
|
|
6049
|
+
// src/query-builder/select/from-facet.ts
|
|
6050
|
+
var SelectFromFacet = class {
|
|
6051
|
+
/**
|
|
6052
|
+
* Creates a new SelectFromFacet instance
|
|
6053
|
+
* @param env - Query builder environment
|
|
6054
|
+
* @param createAstService - Function to create AST service
|
|
6055
|
+
*/
|
|
6056
|
+
constructor(env, createAstService) {
|
|
6057
|
+
this.env = env;
|
|
6058
|
+
this.createAstService = createAstService;
|
|
6059
|
+
}
|
|
6060
|
+
/**
|
|
6061
|
+
* Applies an alias to the FROM table
|
|
6062
|
+
* @param context - Current query context
|
|
6063
|
+
* @param alias - Alias to apply
|
|
6064
|
+
* @returns Updated query context with aliased FROM
|
|
6065
|
+
*/
|
|
6066
|
+
as(context, alias) {
|
|
6067
|
+
const from = context.state.ast.from;
|
|
6068
|
+
if (from.type !== "Table") {
|
|
6069
|
+
throw new Error("Cannot alias non-table FROM sources");
|
|
6070
|
+
}
|
|
6071
|
+
const nextFrom = { ...from, alias };
|
|
6072
|
+
const astService = this.createAstService(context.state);
|
|
6073
|
+
const nextState = astService.withFrom(nextFrom);
|
|
6074
|
+
return { state: nextState, hydration: context.hydration };
|
|
6075
|
+
}
|
|
6076
|
+
/**
|
|
6077
|
+
* Sets the FROM clause to a subquery
|
|
6078
|
+
* @param context - Current query context
|
|
6079
|
+
* @param subAst - Subquery AST
|
|
6080
|
+
* @param alias - Alias for the subquery
|
|
6081
|
+
* @param columnAliases - Optional column aliases
|
|
6082
|
+
* @returns Updated query context with subquery FROM
|
|
6083
|
+
*/
|
|
6084
|
+
fromSubquery(context, subAst, alias, columnAliases) {
|
|
6085
|
+
const fromNode = derivedTable(subAst, alias, columnAliases);
|
|
6086
|
+
const astService = this.createAstService(context.state);
|
|
6087
|
+
const nextState = astService.withFrom(fromNode);
|
|
6088
|
+
return { state: nextState, hydration: context.hydration };
|
|
6089
|
+
}
|
|
6090
|
+
/**
|
|
6091
|
+
* Sets the FROM clause to a function table
|
|
6092
|
+
* @param context - Current query context
|
|
6093
|
+
* @param name - Function name
|
|
6094
|
+
* @param args - Function arguments
|
|
6095
|
+
* @param alias - Optional alias for the function table
|
|
6096
|
+
* @param options - Optional function table options
|
|
6097
|
+
* @returns Updated query context with function table FROM
|
|
6098
|
+
*/
|
|
6099
|
+
fromFunctionTable(context, name, args, alias, options) {
|
|
6100
|
+
const functionTable = fnTable(name, args, alias, options);
|
|
6101
|
+
const astService = this.createAstService(context.state);
|
|
6102
|
+
const nextState = astService.withFrom(functionTable);
|
|
6103
|
+
return { state: nextState, hydration: context.hydration };
|
|
6104
|
+
}
|
|
6105
|
+
};
|
|
6106
|
+
|
|
6107
|
+
// src/query-builder/select/join-facet.ts
|
|
6108
|
+
var SelectJoinFacet = class {
|
|
6109
|
+
constructor(env, createAstService) {
|
|
6110
|
+
this.env = env;
|
|
6111
|
+
this.createAstService = createAstService;
|
|
6112
|
+
}
|
|
6113
|
+
applyJoin(context, table, condition, kind) {
|
|
6114
|
+
const joinNode = createJoinNode(kind, { type: "Table", name: table.name, schema: table.schema }, condition);
|
|
6115
|
+
const astService = this.createAstService(context.state);
|
|
6116
|
+
const nextState = astService.withJoin(joinNode);
|
|
6117
|
+
return { state: nextState, hydration: context.hydration };
|
|
6118
|
+
}
|
|
6119
|
+
joinSubquery(context, subAst, alias, condition, joinKind, columnAliases) {
|
|
6120
|
+
const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
|
|
6121
|
+
const astService = this.createAstService(context.state);
|
|
6122
|
+
const nextState = astService.withJoin(joinNode);
|
|
6123
|
+
return { state: nextState, hydration: context.hydration };
|
|
6124
|
+
}
|
|
6125
|
+
joinFunctionTable(context, name, args, alias, condition, joinKind, options) {
|
|
6126
|
+
const functionTable = fnTable(name, args, alias, options);
|
|
6127
|
+
const joinNode = createJoinNode(joinKind, functionTable, condition);
|
|
6128
|
+
const astService = this.createAstService(context.state);
|
|
6129
|
+
const nextState = astService.withJoin(joinNode);
|
|
6130
|
+
return { state: nextState, hydration: context.hydration };
|
|
6131
|
+
}
|
|
6132
|
+
};
|
|
6133
|
+
|
|
6134
|
+
// src/query-builder/select/projection-facet.ts
|
|
6135
|
+
var SelectProjectionFacet = class {
|
|
6136
|
+
/**
|
|
6137
|
+
* Creates a new SelectProjectionFacet instance
|
|
6138
|
+
* @param columnSelector - Column selector dependency
|
|
6139
|
+
*/
|
|
6140
|
+
constructor(columnSelector) {
|
|
6141
|
+
this.columnSelector = columnSelector;
|
|
6142
|
+
}
|
|
6143
|
+
/**
|
|
6144
|
+
* Selects columns for the query
|
|
6145
|
+
* @param context - Current query context
|
|
6146
|
+
* @param columns - Columns to select
|
|
6147
|
+
* @returns Updated query context with selected columns
|
|
6148
|
+
*/
|
|
6149
|
+
select(context, columns) {
|
|
6150
|
+
return this.columnSelector.select(context, columns);
|
|
6151
|
+
}
|
|
6152
|
+
/**
|
|
6153
|
+
* Selects raw column expressions
|
|
6154
|
+
* @param context - Current query context
|
|
6155
|
+
* @param cols - Raw column expressions
|
|
6156
|
+
* @returns Updated query context with raw column selections
|
|
6157
|
+
*/
|
|
6158
|
+
selectRaw(context, cols) {
|
|
6159
|
+
return this.columnSelector.selectRaw(context, cols);
|
|
6160
|
+
}
|
|
6161
|
+
/**
|
|
6162
|
+
* Selects a subquery as a column
|
|
6163
|
+
* @param context - Current query context
|
|
6164
|
+
* @param alias - Alias for the subquery
|
|
6165
|
+
* @param query - Subquery to select
|
|
6166
|
+
* @returns Updated query context with subquery selection
|
|
6167
|
+
*/
|
|
6168
|
+
selectSubquery(context, alias, query) {
|
|
6169
|
+
return this.columnSelector.selectSubquery(context, alias, query);
|
|
6170
|
+
}
|
|
6171
|
+
/**
|
|
6172
|
+
* Adds DISTINCT clause to the query
|
|
6173
|
+
* @param context - Current query context
|
|
6174
|
+
* @param cols - Columns to make distinct
|
|
6175
|
+
* @returns Updated query context with DISTINCT clause
|
|
6176
|
+
*/
|
|
6177
|
+
distinct(context, cols) {
|
|
6178
|
+
return this.columnSelector.distinct(context, cols);
|
|
6179
|
+
}
|
|
6180
|
+
};
|
|
6181
|
+
|
|
6182
|
+
// src/query-builder/select/predicate-facet.ts
|
|
6183
|
+
var SelectPredicateFacet = class {
|
|
6184
|
+
/**
|
|
6185
|
+
* Creates a new SelectPredicateFacet instance
|
|
6186
|
+
* @param env - Query builder environment
|
|
6187
|
+
* @param createAstService - Function to create AST service
|
|
6188
|
+
*/
|
|
6189
|
+
constructor(env, createAstService) {
|
|
6190
|
+
this.env = env;
|
|
6191
|
+
this.createAstService = createAstService;
|
|
6192
|
+
}
|
|
6193
|
+
/**
|
|
6194
|
+
* Adds a WHERE condition to the query
|
|
6195
|
+
* @param context - Current query context
|
|
6196
|
+
* @param expr - WHERE expression
|
|
6197
|
+
* @returns Updated query context with WHERE condition
|
|
6198
|
+
*/
|
|
6199
|
+
where(context, expr) {
|
|
6200
|
+
const astService = this.createAstService(context.state);
|
|
6201
|
+
const nextState = astService.withWhere(expr);
|
|
6202
|
+
return { state: nextState, hydration: context.hydration };
|
|
6203
|
+
}
|
|
6204
|
+
/**
|
|
6205
|
+
* Adds a GROUP BY clause to the query
|
|
6206
|
+
* @param context - Current query context
|
|
6207
|
+
* @param term - Column or ordering term to group by
|
|
6208
|
+
* @returns Updated query context with GROUP BY clause
|
|
6209
|
+
*/
|
|
6210
|
+
groupBy(context, term) {
|
|
6211
|
+
const astService = this.createAstService(context.state);
|
|
6212
|
+
const nextState = astService.withGroupBy(term);
|
|
6213
|
+
return { state: nextState, hydration: context.hydration };
|
|
6214
|
+
}
|
|
6215
|
+
/**
|
|
6216
|
+
* Adds a HAVING condition to the query
|
|
6217
|
+
* @param context - Current query context
|
|
6218
|
+
* @param expr - HAVING expression
|
|
6219
|
+
* @returns Updated query context with HAVING condition
|
|
6220
|
+
*/
|
|
6221
|
+
having(context, expr) {
|
|
6222
|
+
const astService = this.createAstService(context.state);
|
|
6223
|
+
const nextState = astService.withHaving(expr);
|
|
6224
|
+
return { state: nextState, hydration: context.hydration };
|
|
6225
|
+
}
|
|
6226
|
+
/**
|
|
6227
|
+
* Adds an ORDER BY clause to the query
|
|
6228
|
+
* @param context - Current query context
|
|
6229
|
+
* @param term - Column or ordering term to order by
|
|
6230
|
+
* @param direction - Order direction
|
|
6231
|
+
* @param nulls - Nulls ordering
|
|
6232
|
+
* @param collation - Collation
|
|
6233
|
+
* @returns Updated query context with ORDER BY clause
|
|
6234
|
+
*/
|
|
6235
|
+
orderBy(context, term, direction, nulls, collation) {
|
|
6236
|
+
const astService = this.createAstService(context.state);
|
|
6237
|
+
const nextState = astService.withOrderBy(term, direction, nulls, collation);
|
|
6238
|
+
return { state: nextState, hydration: context.hydration };
|
|
6239
|
+
}
|
|
6240
|
+
/**
|
|
6241
|
+
* Adds a LIMIT clause to the query
|
|
6242
|
+
* @param context - Current query context
|
|
6243
|
+
* @param n - Maximum number of rows
|
|
6244
|
+
* @returns Updated query context with LIMIT clause
|
|
6245
|
+
*/
|
|
6246
|
+
limit(context, n) {
|
|
6247
|
+
const astService = this.createAstService(context.state);
|
|
6248
|
+
const nextState = astService.withLimit(n);
|
|
6249
|
+
return { state: nextState, hydration: context.hydration };
|
|
6250
|
+
}
|
|
6251
|
+
/**
|
|
6252
|
+
* Adds an OFFSET clause to the query
|
|
6253
|
+
* @param context - Current query context
|
|
6254
|
+
* @param n - Number of rows to skip
|
|
6255
|
+
* @returns Updated query context with OFFSET clause
|
|
6256
|
+
*/
|
|
6257
|
+
offset(context, n) {
|
|
6258
|
+
const astService = this.createAstService(context.state);
|
|
6259
|
+
const nextState = astService.withOffset(n);
|
|
6260
|
+
return { state: nextState, hydration: context.hydration };
|
|
6261
|
+
}
|
|
6262
|
+
};
|
|
6263
|
+
|
|
6264
|
+
// src/query-builder/select/cte-facet.ts
|
|
6265
|
+
var SelectCTEFacet = class {
|
|
6266
|
+
/**
|
|
6267
|
+
* Creates a new SelectCTEFacet instance
|
|
6268
|
+
* @param env - Query builder environment
|
|
6269
|
+
* @param createAstService - Function to create AST service
|
|
6270
|
+
*/
|
|
6271
|
+
constructor(env, createAstService) {
|
|
6272
|
+
this.env = env;
|
|
6273
|
+
this.createAstService = createAstService;
|
|
5322
6274
|
}
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
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 };
|
|
5332
6288
|
}
|
|
5333
|
-
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
5334
|
-
return hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
5335
6289
|
};
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
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;
|
|
5343
6301
|
}
|
|
5344
|
-
|
|
5345
|
-
|
|
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
|
+
};
|
|
5346
6315
|
|
|
5347
|
-
// src/query-builder/
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
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
|
+
};
|
|
5352
6368
|
|
|
5353
6369
|
// src/query-builder/select.ts
|
|
5354
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;
|
|
5355
6383
|
/**
|
|
5356
6384
|
* Creates a new SelectQueryBuilder instance
|
|
5357
6385
|
* @param table - Table definition to query
|
|
@@ -5359,9 +6387,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5359
6387
|
* @param hydration - Optional hydration manager
|
|
5360
6388
|
* @param dependencies - Optional query builder dependencies
|
|
5361
6389
|
*/
|
|
5362
|
-
constructor(table, state, hydration, dependencies, lazyRelations) {
|
|
6390
|
+
constructor(table, state, hydration, dependencies, lazyRelations, lazyRelationOptions) {
|
|
5363
6391
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
5364
6392
|
this.env = { table, deps };
|
|
6393
|
+
const createAstService = (nextState) => deps.createQueryAstService(table, nextState);
|
|
5365
6394
|
const initialState = state ?? deps.createState(table);
|
|
5366
6395
|
const initialHydration = hydration ?? deps.createHydration(table);
|
|
5367
6396
|
this.context = {
|
|
@@ -5369,8 +6398,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5369
6398
|
hydration: initialHydration
|
|
5370
6399
|
};
|
|
5371
6400
|
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
6401
|
+
this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
|
|
5372
6402
|
this.columnSelector = deps.createColumnSelector(this.env);
|
|
5373
|
-
|
|
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);
|
|
5374
6411
|
}
|
|
5375
6412
|
/**
|
|
5376
6413
|
* Creates a new SelectQueryBuilder instance with updated context and lazy relations
|
|
@@ -5378,20 +6415,22 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5378
6415
|
* @param lazyRelations - Updated lazy relations set
|
|
5379
6416
|
* @returns New SelectQueryBuilder instance
|
|
5380
6417
|
*/
|
|
5381
|
-
clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
|
|
5382
|
-
return new _SelectQueryBuilder(
|
|
6418
|
+
clone(context = this.context, lazyRelations = new Set(this.lazyRelations), lazyRelationOptions = new Map(this.lazyRelationOptions)) {
|
|
6419
|
+
return new _SelectQueryBuilder(
|
|
6420
|
+
this.env.table,
|
|
6421
|
+
context.state,
|
|
6422
|
+
context.hydration,
|
|
6423
|
+
this.env.deps,
|
|
6424
|
+
lazyRelations,
|
|
6425
|
+
lazyRelationOptions
|
|
6426
|
+
);
|
|
5383
6427
|
}
|
|
5384
6428
|
/**
|
|
5385
6429
|
* Applies an alias to the root FROM table.
|
|
5386
6430
|
* @param alias - Alias to apply
|
|
5387
6431
|
*/
|
|
5388
6432
|
as(alias) {
|
|
5389
|
-
const
|
|
5390
|
-
if (from.type !== "Table") {
|
|
5391
|
-
throw new Error("Cannot alias non-table FROM sources");
|
|
5392
|
-
}
|
|
5393
|
-
const nextFrom = { ...from, alias };
|
|
5394
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
|
|
6433
|
+
const nextContext = this.fromFacet.as(this.context, alias);
|
|
5395
6434
|
return this.clone(nextContext);
|
|
5396
6435
|
}
|
|
5397
6436
|
/**
|
|
@@ -5416,29 +6455,6 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5416
6455
|
createChildBuilder(table) {
|
|
5417
6456
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
5418
6457
|
}
|
|
5419
|
-
/**
|
|
5420
|
-
* Applies an AST mutation using the query AST service
|
|
5421
|
-
* @param context - Current query context
|
|
5422
|
-
* @param mutator - Function that mutates the AST
|
|
5423
|
-
* @returns Updated query context
|
|
5424
|
-
*/
|
|
5425
|
-
applyAst(context, mutator) {
|
|
5426
|
-
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
5427
|
-
const nextState = mutator(astService);
|
|
5428
|
-
return { state: nextState, hydration: context.hydration };
|
|
5429
|
-
}
|
|
5430
|
-
/**
|
|
5431
|
-
* Applies a join to the query context
|
|
5432
|
-
* @param context - Current query context
|
|
5433
|
-
* @param table - Table to join
|
|
5434
|
-
* @param condition - Join condition
|
|
5435
|
-
* @param kind - Join kind
|
|
5436
|
-
* @returns Updated query context with join applied
|
|
5437
|
-
*/
|
|
5438
|
-
applyJoin(context, table, condition, kind) {
|
|
5439
|
-
const joinNode = createJoinNode(kind, { type: "Table", name: table.name, schema: table.schema }, condition);
|
|
5440
|
-
return this.applyAst(context, (service) => service.withJoin(joinNode));
|
|
5441
|
-
}
|
|
5442
6458
|
/**
|
|
5443
6459
|
* Applies a set operation to the query
|
|
5444
6460
|
* @param operator - Set operation kind
|
|
@@ -5447,12 +6463,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5447
6463
|
*/
|
|
5448
6464
|
applySetOperation(operator, query) {
|
|
5449
6465
|
const subAst = resolveSelectQuery(query);
|
|
5450
|
-
return this.
|
|
6466
|
+
return this.setOpFacet.applySetOperation(this.context, operator, subAst);
|
|
5451
6467
|
}
|
|
5452
6468
|
select(...args) {
|
|
5453
6469
|
if (args.length === 1 && typeof args[0] === "object" && args[0] !== null && typeof args[0] !== "string") {
|
|
5454
6470
|
const columns = args[0];
|
|
5455
|
-
return this.clone(this.
|
|
6471
|
+
return this.clone(this.projectionFacet.select(this.context, columns));
|
|
5456
6472
|
}
|
|
5457
6473
|
const cols = args;
|
|
5458
6474
|
const selection = {};
|
|
@@ -5463,7 +6479,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5463
6479
|
}
|
|
5464
6480
|
selection[key] = col2;
|
|
5465
6481
|
}
|
|
5466
|
-
return this.clone(this.
|
|
6482
|
+
return this.clone(this.projectionFacet.select(this.context, selection));
|
|
5467
6483
|
}
|
|
5468
6484
|
/**
|
|
5469
6485
|
* Selects raw column expressions
|
|
@@ -5471,7 +6487,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5471
6487
|
* @returns New query builder instance with raw column selections
|
|
5472
6488
|
*/
|
|
5473
6489
|
selectRaw(...cols) {
|
|
5474
|
-
return this.clone(this.
|
|
6490
|
+
return this.clone(this.projectionFacet.selectRaw(this.context, cols));
|
|
5475
6491
|
}
|
|
5476
6492
|
/**
|
|
5477
6493
|
* Adds a Common Table Expression (CTE) to the query
|
|
@@ -5482,7 +6498,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5482
6498
|
*/
|
|
5483
6499
|
with(name, query, columns) {
|
|
5484
6500
|
const subAst = resolveSelectQuery(query);
|
|
5485
|
-
const nextContext = this.
|
|
6501
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, false);
|
|
5486
6502
|
return this.clone(nextContext);
|
|
5487
6503
|
}
|
|
5488
6504
|
/**
|
|
@@ -5494,7 +6510,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5494
6510
|
*/
|
|
5495
6511
|
withRecursive(name, query, columns) {
|
|
5496
6512
|
const subAst = resolveSelectQuery(query);
|
|
5497
|
-
const nextContext = this.
|
|
6513
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, true);
|
|
5498
6514
|
return this.clone(nextContext);
|
|
5499
6515
|
}
|
|
5500
6516
|
/**
|
|
@@ -5506,8 +6522,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5506
6522
|
*/
|
|
5507
6523
|
fromSubquery(subquery, alias, columnAliases) {
|
|
5508
6524
|
const subAst = resolveSelectQuery(subquery);
|
|
5509
|
-
const
|
|
5510
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
|
|
6525
|
+
const nextContext = this.fromFacet.fromSubquery(this.context, subAst, alias, columnAliases);
|
|
5511
6526
|
return this.clone(nextContext);
|
|
5512
6527
|
}
|
|
5513
6528
|
/**
|
|
@@ -5518,8 +6533,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5518
6533
|
* @param options - Optional function-table metadata (lateral, ordinality, column aliases, schema)
|
|
5519
6534
|
*/
|
|
5520
6535
|
fromFunctionTable(name, args = [], alias, options) {
|
|
5521
|
-
const
|
|
5522
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(functionTable));
|
|
6536
|
+
const nextContext = this.fromFacet.fromFunctionTable(this.context, name, args, alias, options);
|
|
5523
6537
|
return this.clone(nextContext);
|
|
5524
6538
|
}
|
|
5525
6539
|
/**
|
|
@@ -5530,7 +6544,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5530
6544
|
*/
|
|
5531
6545
|
selectSubquery(alias, sub2) {
|
|
5532
6546
|
const query = resolveSelectQuery(sub2);
|
|
5533
|
-
return this.clone(this.
|
|
6547
|
+
return this.clone(this.projectionFacet.selectSubquery(this.context, alias, query));
|
|
5534
6548
|
}
|
|
5535
6549
|
/**
|
|
5536
6550
|
* Adds a JOIN against a derived table (subquery with alias)
|
|
@@ -5543,8 +6557,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5543
6557
|
*/
|
|
5544
6558
|
joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
|
|
5545
6559
|
const subAst = resolveSelectQuery(subquery);
|
|
5546
|
-
const
|
|
5547
|
-
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
6560
|
+
const nextContext = this.joinFacet.joinSubquery(this.context, subAst, alias, condition, joinKind, columnAliases);
|
|
5548
6561
|
return this.clone(nextContext);
|
|
5549
6562
|
}
|
|
5550
6563
|
/**
|
|
@@ -5557,9 +6570,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5557
6570
|
* @param options - Optional metadata (lateral, ordinality, column aliases, schema)
|
|
5558
6571
|
*/
|
|
5559
6572
|
joinFunctionTable(name, args = [], alias, condition, joinKind = JOIN_KINDS.INNER, options) {
|
|
5560
|
-
const
|
|
5561
|
-
const joinNode = createJoinNode(joinKind, functionTable, condition);
|
|
5562
|
-
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
6573
|
+
const nextContext = this.joinFacet.joinFunctionTable(this.context, name, args, alias, condition, joinKind, options);
|
|
5563
6574
|
return this.clone(nextContext);
|
|
5564
6575
|
}
|
|
5565
6576
|
/**
|
|
@@ -5569,7 +6580,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5569
6580
|
* @returns New query builder instance with the INNER JOIN
|
|
5570
6581
|
*/
|
|
5571
6582
|
innerJoin(table, condition) {
|
|
5572
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
6583
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
5573
6584
|
return this.clone(nextContext);
|
|
5574
6585
|
}
|
|
5575
6586
|
/**
|
|
@@ -5579,7 +6590,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5579
6590
|
* @returns New query builder instance with the LEFT JOIN
|
|
5580
6591
|
*/
|
|
5581
6592
|
leftJoin(table, condition) {
|
|
5582
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
6593
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
5583
6594
|
return this.clone(nextContext);
|
|
5584
6595
|
}
|
|
5585
6596
|
/**
|
|
@@ -5589,7 +6600,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5589
6600
|
* @returns New query builder instance with the RIGHT JOIN
|
|
5590
6601
|
*/
|
|
5591
6602
|
rightJoin(table, condition) {
|
|
5592
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
6603
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
5593
6604
|
return this.clone(nextContext);
|
|
5594
6605
|
}
|
|
5595
6606
|
/**
|
|
@@ -5599,7 +6610,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5599
6610
|
* @returns New query builder instance with the relationship match
|
|
5600
6611
|
*/
|
|
5601
6612
|
match(relationName, predicate) {
|
|
5602
|
-
const nextContext = this.
|
|
6613
|
+
const nextContext = this.relationFacet.match(this.context, relationName, predicate);
|
|
5603
6614
|
return this.clone(nextContext);
|
|
5604
6615
|
}
|
|
5605
6616
|
/**
|
|
@@ -5610,7 +6621,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5610
6621
|
* @returns New query builder instance with the relationship join
|
|
5611
6622
|
*/
|
|
5612
6623
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
5613
|
-
const nextContext = this.
|
|
6624
|
+
const nextContext = this.relationFacet.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
5614
6625
|
return this.clone(nextContext);
|
|
5615
6626
|
}
|
|
5616
6627
|
/**
|
|
@@ -5620,42 +6631,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5620
6631
|
* @returns New query builder instance with the relationship inclusion
|
|
5621
6632
|
*/
|
|
5622
6633
|
include(relationName, options) {
|
|
5623
|
-
const nextContext = this.
|
|
6634
|
+
const nextContext = this.relationFacet.include(this.context, relationName, options);
|
|
5624
6635
|
return this.clone(nextContext);
|
|
5625
6636
|
}
|
|
5626
6637
|
/**
|
|
5627
6638
|
* Includes a relation lazily in the query results
|
|
5628
6639
|
* @param relationName - Name of the relation to include lazily
|
|
6640
|
+
* @param options - Optional include options for lazy loading
|
|
5629
6641
|
* @returns New query builder instance with lazy relation inclusion
|
|
5630
6642
|
*/
|
|
5631
|
-
includeLazy(relationName) {
|
|
5632
|
-
|
|
5633
|
-
nextLazy.add(relationName);
|
|
5634
|
-
return this.clone(this.context, nextLazy);
|
|
5635
|
-
}
|
|
5636
|
-
/**
|
|
5637
|
-
* Selects columns for a related table in a single hop.
|
|
5638
|
-
*/
|
|
5639
|
-
selectRelationColumns(relationName, ...cols) {
|
|
6643
|
+
includeLazy(relationName, options) {
|
|
6644
|
+
let nextContext = this.context;
|
|
5640
6645
|
const relation = this.env.table.relations[relationName];
|
|
5641
|
-
if (
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
)
|
|
6646
|
+
if (relation?.type === RelationKinds.BelongsTo) {
|
|
6647
|
+
const foreignKey = relation.foreignKey;
|
|
6648
|
+
const fkColumn = this.env.table.columns[foreignKey];
|
|
6649
|
+
if (fkColumn) {
|
|
6650
|
+
const hasAlias2 = nextContext.state.ast.columns.some((col2) => {
|
|
6651
|
+
const node = col2;
|
|
6652
|
+
return (node.alias ?? node.name) === foreignKey;
|
|
6653
|
+
});
|
|
6654
|
+
if (!hasAlias2) {
|
|
6655
|
+
nextContext = this.columnSelector.select(nextContext, { [foreignKey]: fkColumn });
|
|
6656
|
+
}
|
|
5650
6657
|
}
|
|
5651
6658
|
}
|
|
5652
|
-
|
|
6659
|
+
const nextLazy = new Set(this.lazyRelations);
|
|
6660
|
+
nextLazy.add(relationName);
|
|
6661
|
+
const nextOptions = new Map(this.lazyRelationOptions);
|
|
6662
|
+
if (options) {
|
|
6663
|
+
nextOptions.set(relationName, options);
|
|
6664
|
+
} else {
|
|
6665
|
+
nextOptions.delete(relationName);
|
|
6666
|
+
}
|
|
6667
|
+
return this.clone(nextContext, nextLazy, nextOptions);
|
|
5653
6668
|
}
|
|
5654
6669
|
/**
|
|
5655
|
-
* Convenience alias for
|
|
6670
|
+
* Convenience alias for including only specific columns from a relation.
|
|
5656
6671
|
*/
|
|
5657
6672
|
includePick(relationName, cols) {
|
|
5658
|
-
|
|
6673
|
+
const options = { columns: cols };
|
|
6674
|
+
return this.include(relationName, options);
|
|
5659
6675
|
}
|
|
5660
6676
|
/**
|
|
5661
6677
|
* Selects columns for the root table and relations from an array of entries
|
|
@@ -5668,7 +6684,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5668
6684
|
if (entry.type === "root") {
|
|
5669
6685
|
currBuilder = currBuilder.select(...entry.columns);
|
|
5670
6686
|
} else {
|
|
5671
|
-
|
|
6687
|
+
const options = { columns: entry.columns };
|
|
6688
|
+
currBuilder = currBuilder.include(entry.relationName, options);
|
|
5672
6689
|
}
|
|
5673
6690
|
}
|
|
5674
6691
|
return currBuilder;
|
|
@@ -5680,6 +6697,13 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5680
6697
|
getLazyRelations() {
|
|
5681
6698
|
return Array.from(this.lazyRelations);
|
|
5682
6699
|
}
|
|
6700
|
+
/**
|
|
6701
|
+
* Gets lazy relation include options
|
|
6702
|
+
* @returns Map of relation names to include options
|
|
6703
|
+
*/
|
|
6704
|
+
getLazyRelationOptions() {
|
|
6705
|
+
return new Map(this.lazyRelationOptions);
|
|
6706
|
+
}
|
|
5683
6707
|
/**
|
|
5684
6708
|
* Gets the table definition for this query builder
|
|
5685
6709
|
* @returns Table definition
|
|
@@ -5695,51 +6719,23 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5695
6719
|
async execute(ctx) {
|
|
5696
6720
|
return executeHydrated(ctx, this);
|
|
5697
6721
|
}
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
return this.clone(nextContext);
|
|
5705
|
-
}
|
|
6722
|
+
/**
|
|
6723
|
+
* Executes a count query for the current builder without LIMIT/OFFSET clauses.
|
|
6724
|
+
*
|
|
6725
|
+
* @example
|
|
6726
|
+
* const total = await qb.count(session);
|
|
6727
|
+
*/
|
|
5706
6728
|
async count(session) {
|
|
5707
|
-
|
|
5708
|
-
...this.context.state.ast,
|
|
5709
|
-
orderBy: void 0,
|
|
5710
|
-
limit: void 0,
|
|
5711
|
-
offset: void 0
|
|
5712
|
-
};
|
|
5713
|
-
const subAst = this.withAst(unpagedAst).getAST();
|
|
5714
|
-
const countQuery = {
|
|
5715
|
-
type: "SelectQuery",
|
|
5716
|
-
from: derivedTable(subAst, "__metal_count"),
|
|
5717
|
-
columns: [{ type: "Function", name: "COUNT", args: [], alias: "total" }],
|
|
5718
|
-
joins: []
|
|
5719
|
-
};
|
|
5720
|
-
const execCtx = session.getExecutionContext();
|
|
5721
|
-
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
5722
|
-
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
5723
|
-
const value = results[0]?.values?.[0]?.[0];
|
|
5724
|
-
if (typeof value === "number") return value;
|
|
5725
|
-
if (typeof value === "bigint") return Number(value);
|
|
5726
|
-
if (typeof value === "string") return Number(value);
|
|
5727
|
-
return value === null || value === void 0 ? 0 : Number(value);
|
|
6729
|
+
return executeCount(this.context, this.env, session);
|
|
5728
6730
|
}
|
|
6731
|
+
/**
|
|
6732
|
+
* Executes the query and returns both the paged items and the total.
|
|
6733
|
+
*
|
|
6734
|
+
* @example
|
|
6735
|
+
* const { items, totalItems } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
6736
|
+
*/
|
|
5729
6737
|
async executePaged(session, options) {
|
|
5730
|
-
|
|
5731
|
-
if (!Number.isInteger(page) || page < 1) {
|
|
5732
|
-
throw new Error("executePaged: page must be an integer >= 1");
|
|
5733
|
-
}
|
|
5734
|
-
if (!Number.isInteger(pageSize) || pageSize < 1) {
|
|
5735
|
-
throw new Error("executePaged: pageSize must be an integer >= 1");
|
|
5736
|
-
}
|
|
5737
|
-
const offset = (page - 1) * pageSize;
|
|
5738
|
-
const [items, totalItems] = await Promise.all([
|
|
5739
|
-
this.limit(pageSize).offset(offset).execute(session),
|
|
5740
|
-
this.count(session)
|
|
5741
|
-
]);
|
|
5742
|
-
return { items, totalItems };
|
|
6738
|
+
return executePagedQuery(this, session, options, (sess) => this.count(sess));
|
|
5743
6739
|
}
|
|
5744
6740
|
/**
|
|
5745
6741
|
* Executes the query with provided execution and hydration contexts
|
|
@@ -5756,7 +6752,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5756
6752
|
* @returns New query builder instance with the WHERE condition
|
|
5757
6753
|
*/
|
|
5758
6754
|
where(expr) {
|
|
5759
|
-
const nextContext = this.
|
|
6755
|
+
const nextContext = this.predicateFacet.where(this.context, expr);
|
|
5760
6756
|
return this.clone(nextContext);
|
|
5761
6757
|
}
|
|
5762
6758
|
/**
|
|
@@ -5765,7 +6761,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5765
6761
|
* @returns New query builder instance with the GROUP BY clause
|
|
5766
6762
|
*/
|
|
5767
6763
|
groupBy(term) {
|
|
5768
|
-
const nextContext = this.
|
|
6764
|
+
const nextContext = this.predicateFacet.groupBy(this.context, term);
|
|
5769
6765
|
return this.clone(nextContext);
|
|
5770
6766
|
}
|
|
5771
6767
|
/**
|
|
@@ -5774,7 +6770,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5774
6770
|
* @returns New query builder instance with the HAVING condition
|
|
5775
6771
|
*/
|
|
5776
6772
|
having(expr) {
|
|
5777
|
-
const nextContext = this.
|
|
6773
|
+
const nextContext = this.predicateFacet.having(this.context, expr);
|
|
5778
6774
|
return this.clone(nextContext);
|
|
5779
6775
|
}
|
|
5780
6776
|
/**
|
|
@@ -5782,14 +6778,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5782
6778
|
* @param term - Column definition or ordering term to order by
|
|
5783
6779
|
* @param directionOrOptions - Order direction or options (defaults to ASC)
|
|
5784
6780
|
* @returns New query builder instance with the ORDER BY clause
|
|
6781
|
+
*
|
|
6782
|
+
* @example
|
|
6783
|
+
* qb.orderBy(userTable.columns.createdAt, 'DESC');
|
|
5785
6784
|
*/
|
|
5786
6785
|
orderBy(term, directionOrOptions = ORDER_DIRECTIONS.ASC) {
|
|
5787
|
-
const
|
|
5788
|
-
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
5789
|
-
const nextContext = this.applyAst(
|
|
5790
|
-
this.context,
|
|
5791
|
-
(service) => service.withOrderBy(term, dir, options.nulls, options.collation)
|
|
5792
|
-
);
|
|
6786
|
+
const nextContext = applyOrderBy(this.context, this.predicateFacet, term, directionOrOptions);
|
|
5793
6787
|
return this.clone(nextContext);
|
|
5794
6788
|
}
|
|
5795
6789
|
/**
|
|
@@ -5798,7 +6792,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5798
6792
|
* @returns New query builder instance with the DISTINCT clause
|
|
5799
6793
|
*/
|
|
5800
6794
|
distinct(...cols) {
|
|
5801
|
-
return this.clone(this.
|
|
6795
|
+
return this.clone(this.projectionFacet.distinct(this.context, cols));
|
|
5802
6796
|
}
|
|
5803
6797
|
/**
|
|
5804
6798
|
* Adds a LIMIT clause to the query
|
|
@@ -5806,7 +6800,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5806
6800
|
* @returns New query builder instance with the LIMIT clause
|
|
5807
6801
|
*/
|
|
5808
6802
|
limit(n) {
|
|
5809
|
-
const nextContext = this.
|
|
6803
|
+
const nextContext = this.predicateFacet.limit(this.context, n);
|
|
5810
6804
|
return this.clone(nextContext);
|
|
5811
6805
|
}
|
|
5812
6806
|
/**
|
|
@@ -5815,7 +6809,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5815
6809
|
* @returns New query builder instance with the OFFSET clause
|
|
5816
6810
|
*/
|
|
5817
6811
|
offset(n) {
|
|
5818
|
-
const nextContext = this.
|
|
6812
|
+
const nextContext = this.predicateFacet.offset(this.context, n);
|
|
5819
6813
|
return this.clone(nextContext);
|
|
5820
6814
|
}
|
|
5821
6815
|
/**
|
|
@@ -5875,42 +6869,44 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5875
6869
|
* @param relationName - Name of the relationship to check
|
|
5876
6870
|
* @param callback - Optional callback to modify the relationship query
|
|
5877
6871
|
* @returns New query builder instance with the relationship existence check
|
|
6872
|
+
*
|
|
6873
|
+
* @example
|
|
6874
|
+
* qb.whereHas('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
5878
6875
|
*/
|
|
5879
6876
|
whereHas(relationName, callbackOrOptions, maybeOptions) {
|
|
5880
|
-
const
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
5892
|
-
return this.where(exists(finalSubAst));
|
|
6877
|
+
const predicate = buildWhereHasPredicate(
|
|
6878
|
+
this.env,
|
|
6879
|
+
this.context,
|
|
6880
|
+
this.relationFacet,
|
|
6881
|
+
(table) => this.createChildBuilder(table),
|
|
6882
|
+
relationName,
|
|
6883
|
+
callbackOrOptions,
|
|
6884
|
+
maybeOptions,
|
|
6885
|
+
false
|
|
6886
|
+
);
|
|
6887
|
+
return this.where(predicate);
|
|
5893
6888
|
}
|
|
5894
6889
|
/**
|
|
5895
6890
|
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
5896
6891
|
* @param relationName - Name of the relationship to check
|
|
5897
6892
|
* @param callback - Optional callback to modify the relationship query
|
|
5898
6893
|
* @returns New query builder instance with the relationship non-existence check
|
|
6894
|
+
*
|
|
6895
|
+
* @example
|
|
6896
|
+
* qb.whereHasNot('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
5899
6897
|
*/
|
|
5900
6898
|
whereHasNot(relationName, callbackOrOptions, maybeOptions) {
|
|
5901
|
-
const
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
5913
|
-
return this.where(notExists(finalSubAst));
|
|
6899
|
+
const predicate = buildWhereHasPredicate(
|
|
6900
|
+
this.env,
|
|
6901
|
+
this.context,
|
|
6902
|
+
this.relationFacet,
|
|
6903
|
+
(table) => this.createChildBuilder(table),
|
|
6904
|
+
relationName,
|
|
6905
|
+
callbackOrOptions,
|
|
6906
|
+
maybeOptions,
|
|
6907
|
+
true
|
|
6908
|
+
);
|
|
6909
|
+
return this.where(predicate);
|
|
5914
6910
|
}
|
|
5915
6911
|
/**
|
|
5916
6912
|
* Compiles the query to SQL for a specific dialect
|
|
@@ -6042,23 +7038,44 @@ var resolveTableTarget = (target, tableMap) => {
|
|
|
6042
7038
|
}
|
|
6043
7039
|
return table;
|
|
6044
7040
|
};
|
|
7041
|
+
var toSnakeCase = (value) => {
|
|
7042
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
7043
|
+
};
|
|
7044
|
+
var normalizeEntityName = (value) => {
|
|
7045
|
+
const stripped = value.replace(/Entity$/i, "");
|
|
7046
|
+
const normalized = toSnakeCase(stripped || value);
|
|
7047
|
+
return normalized || "unknown";
|
|
7048
|
+
};
|
|
7049
|
+
var getPivotKeyBaseFromTarget = (target) => {
|
|
7050
|
+
const resolved = unwrapTarget(target);
|
|
7051
|
+
if (isTableDef(resolved)) {
|
|
7052
|
+
return toSnakeCase(resolved.name || "unknown");
|
|
7053
|
+
}
|
|
7054
|
+
const ctor = resolved;
|
|
7055
|
+
return normalizeEntityName(ctor.name || "unknown");
|
|
7056
|
+
};
|
|
7057
|
+
var getPivotKeyBaseFromRoot = (meta) => {
|
|
7058
|
+
return normalizeEntityName(meta.target.name || meta.tableName || "unknown");
|
|
7059
|
+
};
|
|
6045
7060
|
var buildRelationDefinitions = (meta, tableMap) => {
|
|
6046
7061
|
const relations = {};
|
|
6047
7062
|
for (const [name, relation] of Object.entries(meta.relations)) {
|
|
6048
7063
|
switch (relation.kind) {
|
|
6049
7064
|
case RelationKinds.HasOne: {
|
|
7065
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6050
7066
|
relations[name] = hasOne(
|
|
6051
7067
|
resolveTableTarget(relation.target, tableMap),
|
|
6052
|
-
|
|
7068
|
+
foreignKey,
|
|
6053
7069
|
relation.localKey,
|
|
6054
7070
|
relation.cascade
|
|
6055
7071
|
);
|
|
6056
7072
|
break;
|
|
6057
7073
|
}
|
|
6058
7074
|
case RelationKinds.HasMany: {
|
|
7075
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6059
7076
|
relations[name] = hasMany(
|
|
6060
7077
|
resolveTableTarget(relation.target, tableMap),
|
|
6061
|
-
|
|
7078
|
+
foreignKey,
|
|
6062
7079
|
relation.localKey,
|
|
6063
7080
|
relation.cascade
|
|
6064
7081
|
);
|
|
@@ -6074,12 +7091,14 @@ var buildRelationDefinitions = (meta, tableMap) => {
|
|
|
6074
7091
|
break;
|
|
6075
7092
|
}
|
|
6076
7093
|
case RelationKinds.BelongsToMany: {
|
|
7094
|
+
const pivotForeignKeyToRoot = relation.pivotForeignKeyToRoot ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
7095
|
+
const pivotForeignKeyToTarget = relation.pivotForeignKeyToTarget ?? `${getPivotKeyBaseFromTarget(relation.target)}_id`;
|
|
6077
7096
|
relations[name] = belongsToMany(
|
|
6078
7097
|
resolveTableTarget(relation.target, tableMap),
|
|
6079
7098
|
resolveTableTarget(relation.pivotTable, tableMap),
|
|
6080
7099
|
{
|
|
6081
|
-
pivotForeignKeyToRoot
|
|
6082
|
-
pivotForeignKeyToTarget
|
|
7100
|
+
pivotForeignKeyToRoot,
|
|
7101
|
+
pivotForeignKeyToTarget,
|
|
6083
7102
|
localKey: relation.localKey,
|
|
6084
7103
|
targetKey: relation.targetKey,
|
|
6085
7104
|
pivotPrimaryKey: relation.pivotPrimaryKey,
|
|
@@ -6160,6 +7179,8 @@ function esel(entity, ...props) {
|
|
|
6160
7179
|
|
|
6161
7180
|
// src/query-builder/insert-query-state.ts
|
|
6162
7181
|
var InsertQueryState = class _InsertQueryState {
|
|
7182
|
+
table;
|
|
7183
|
+
ast;
|
|
6163
7184
|
/**
|
|
6164
7185
|
* Creates a new InsertQueryState instance
|
|
6165
7186
|
* @param table - The table definition for the INSERT query
|
|
@@ -6280,6 +7301,8 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
6280
7301
|
|
|
6281
7302
|
// src/query-builder/insert.ts
|
|
6282
7303
|
var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
7304
|
+
table;
|
|
7305
|
+
state;
|
|
6283
7306
|
/**
|
|
6284
7307
|
* Creates a new InsertQueryBuilder instance
|
|
6285
7308
|
* @param table - The table definition for the INSERT query
|
|
@@ -6379,6 +7402,8 @@ var isUpdateValue = (value) => {
|
|
|
6379
7402
|
}
|
|
6380
7403
|
};
|
|
6381
7404
|
var UpdateQueryState = class _UpdateQueryState {
|
|
7405
|
+
table;
|
|
7406
|
+
ast;
|
|
6382
7407
|
/**
|
|
6383
7408
|
* Creates a new UpdateQueryState instance
|
|
6384
7409
|
* @param table - Table definition for the update
|
|
@@ -6489,6 +7514,8 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
6489
7514
|
|
|
6490
7515
|
// src/query-builder/update.ts
|
|
6491
7516
|
var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
7517
|
+
table;
|
|
7518
|
+
state;
|
|
6492
7519
|
/**
|
|
6493
7520
|
* Creates a new UpdateQueryBuilder instance
|
|
6494
7521
|
* @param table - The table definition for the UPDATE query
|
|
@@ -6606,6 +7633,8 @@ var isTableSourceNode = (source) => typeof source.type === "string";
|
|
|
6606
7633
|
|
|
6607
7634
|
// src/query-builder/delete-query-state.ts
|
|
6608
7635
|
var DeleteQueryState = class _DeleteQueryState {
|
|
7636
|
+
table;
|
|
7637
|
+
ast;
|
|
6609
7638
|
/**
|
|
6610
7639
|
* Creates a new DeleteQueryState instance
|
|
6611
7640
|
* @param table - The table definition for the DELETE query
|
|
@@ -6684,6 +7713,8 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
6684
7713
|
|
|
6685
7714
|
// src/query-builder/delete.ts
|
|
6686
7715
|
var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
7716
|
+
table;
|
|
7717
|
+
state;
|
|
6687
7718
|
/**
|
|
6688
7719
|
* Creates a new DeleteQueryBuilder instance
|
|
6689
7720
|
* @param table - The table definition for the DELETE query
|
|
@@ -6811,7 +7842,8 @@ var renderColumnDefinition = (table, col2, dialect, options = {}) => {
|
|
|
6811
7842
|
if (col2.default !== void 0) {
|
|
6812
7843
|
parts.push(`DEFAULT ${dialect.renderDefault(col2.default, col2)}`);
|
|
6813
7844
|
}
|
|
6814
|
-
|
|
7845
|
+
const autoIncIncludesPrimary = typeof autoInc === "string" && /\bPRIMARY\s+KEY\b/i.test(autoInc);
|
|
7846
|
+
if (options.includePrimary && col2.primary && !autoIncIncludesPrimary) {
|
|
6815
7847
|
parts.push("PRIMARY KEY");
|
|
6816
7848
|
}
|
|
6817
7849
|
if (col2.check) {
|
|
@@ -6869,6 +7901,16 @@ var generateSchemaSql = (tables, dialect) => {
|
|
|
6869
7901
|
});
|
|
6870
7902
|
return statements;
|
|
6871
7903
|
};
|
|
7904
|
+
var generateSchemaSqlFor = (dialect, ...tables) => generateSchemaSql(tables, dialect);
|
|
7905
|
+
var executeSchemaSql = async (executor, tables, dialect) => {
|
|
7906
|
+
const statements = generateSchemaSql(tables, dialect);
|
|
7907
|
+
for (const sql of statements) {
|
|
7908
|
+
await executor.executeSql(sql);
|
|
7909
|
+
}
|
|
7910
|
+
};
|
|
7911
|
+
var executeSchemaSqlFor = async (executor, dialect, ...tables) => {
|
|
7912
|
+
await executeSchemaSql(executor, tables, dialect);
|
|
7913
|
+
};
|
|
6872
7914
|
var orderTablesByDependencies = (tables) => {
|
|
6873
7915
|
const map = /* @__PURE__ */ new Map();
|
|
6874
7916
|
tables.forEach((t) => map.set(t.name, t));
|
|
@@ -8775,6 +9817,7 @@ var arrayAppend = (array, value) => fn7("ARRAY_APPEND", [array, value]);
|
|
|
8775
9817
|
|
|
8776
9818
|
// src/orm/als.ts
|
|
8777
9819
|
var AsyncLocalStorage = class {
|
|
9820
|
+
store;
|
|
8778
9821
|
/**
|
|
8779
9822
|
* Executes a callback function within a context containing the specified store value.
|
|
8780
9823
|
* The store value is only available during the callback's execution and is automatically
|
|
@@ -9271,9 +10314,7 @@ var TypeScriptGenerator = class {
|
|
|
9271
10314
|
|
|
9272
10315
|
// src/orm/identity-map.ts
|
|
9273
10316
|
var IdentityMap = class {
|
|
9274
|
-
|
|
9275
|
-
this.buckets = /* @__PURE__ */ new Map();
|
|
9276
|
-
}
|
|
10317
|
+
buckets = /* @__PURE__ */ new Map();
|
|
9277
10318
|
get bucketsMap() {
|
|
9278
10319
|
return this.buckets;
|
|
9279
10320
|
}
|
|
@@ -9343,8 +10384,8 @@ var UnitOfWork = class {
|
|
|
9343
10384
|
this.executor = executor;
|
|
9344
10385
|
this.identityMap = identityMap;
|
|
9345
10386
|
this.hookContext = hookContext;
|
|
9346
|
-
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
9347
10387
|
}
|
|
10388
|
+
trackedEntities = /* @__PURE__ */ new Map();
|
|
9348
10389
|
/**
|
|
9349
10390
|
* Gets the identity buckets map.
|
|
9350
10391
|
*/
|
|
@@ -9674,12 +10715,12 @@ var UnitOfWork = class {
|
|
|
9674
10715
|
|
|
9675
10716
|
// src/orm/domain-event-bus.ts
|
|
9676
10717
|
var DomainEventBus = class {
|
|
10718
|
+
handlers = /* @__PURE__ */ new Map();
|
|
9677
10719
|
/**
|
|
9678
10720
|
* Creates a new DomainEventBus instance.
|
|
9679
10721
|
* @param initialHandlers - Optional initial event handlers
|
|
9680
10722
|
*/
|
|
9681
10723
|
constructor(initialHandlers) {
|
|
9682
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
9683
10724
|
if (initialHandlers) {
|
|
9684
10725
|
for (const key in initialHandlers) {
|
|
9685
10726
|
const type = key;
|
|
@@ -9748,8 +10789,8 @@ var RelationChangeProcessor = class {
|
|
|
9748
10789
|
this.unitOfWork = unitOfWork;
|
|
9749
10790
|
this.dialect = dialect;
|
|
9750
10791
|
this.executor = executor;
|
|
9751
|
-
this.relationChanges = [];
|
|
9752
10792
|
}
|
|
10793
|
+
relationChanges = [];
|
|
9753
10794
|
/**
|
|
9754
10795
|
* Registers a relation change for processing.
|
|
9755
10796
|
* @param entry - The relation change entry
|
|
@@ -10183,25 +11224,24 @@ var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
|
|
|
10183
11224
|
|
|
10184
11225
|
// src/orm/orm-session.ts
|
|
10185
11226
|
var OrmSession = class {
|
|
11227
|
+
/** The ORM instance */
|
|
11228
|
+
orm;
|
|
11229
|
+
/** The database executor */
|
|
11230
|
+
executor;
|
|
11231
|
+
/** The identity map for tracking entity instances */
|
|
11232
|
+
identityMap;
|
|
11233
|
+
/** The unit of work for tracking entity changes */
|
|
11234
|
+
unitOfWork;
|
|
11235
|
+
/** The domain event bus */
|
|
11236
|
+
domainEvents;
|
|
11237
|
+
/** The relation change processor */
|
|
11238
|
+
relationChanges;
|
|
11239
|
+
interceptors;
|
|
10186
11240
|
/**
|
|
10187
11241
|
* Creates a new OrmSession instance.
|
|
10188
11242
|
* @param opts - Session options
|
|
10189
11243
|
*/
|
|
10190
11244
|
constructor(opts) {
|
|
10191
|
-
/**
|
|
10192
|
-
* Registers a relation change.
|
|
10193
|
-
* @param root - The root entity
|
|
10194
|
-
* @param relationKey - The relation key
|
|
10195
|
-
* @param rootTable - The root table definition
|
|
10196
|
-
* @param relationName - The relation name
|
|
10197
|
-
* @param relation - The relation definition
|
|
10198
|
-
* @param change - The relation change
|
|
10199
|
-
*/
|
|
10200
|
-
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
10201
|
-
this.relationChanges.registerChange(
|
|
10202
|
-
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
10203
|
-
);
|
|
10204
|
-
};
|
|
10205
11245
|
this.orm = opts.orm;
|
|
10206
11246
|
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
10207
11247
|
this.interceptors = [...opts.interceptors ?? []];
|
|
@@ -10290,6 +11330,20 @@ var OrmSession = class {
|
|
|
10290
11330
|
markRemoved(entity) {
|
|
10291
11331
|
this.unitOfWork.markRemoved(entity);
|
|
10292
11332
|
}
|
|
11333
|
+
/**
|
|
11334
|
+
* Registers a relation change.
|
|
11335
|
+
* @param root - The root entity
|
|
11336
|
+
* @param relationKey - The relation key
|
|
11337
|
+
* @param rootTable - The root table definition
|
|
11338
|
+
* @param relationName - The relation name
|
|
11339
|
+
* @param relation - The relation definition
|
|
11340
|
+
* @param change - The relation change
|
|
11341
|
+
*/
|
|
11342
|
+
registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
11343
|
+
this.relationChanges.registerChange(
|
|
11344
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
11345
|
+
);
|
|
11346
|
+
};
|
|
10293
11347
|
/**
|
|
10294
11348
|
* Gets all tracked entities for a specific table.
|
|
10295
11349
|
* @param table - The table definition
|
|
@@ -10495,9 +11549,7 @@ var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, rela
|
|
|
10495
11549
|
|
|
10496
11550
|
// src/orm/interceptor-pipeline.ts
|
|
10497
11551
|
var InterceptorPipeline = class {
|
|
10498
|
-
|
|
10499
|
-
this.interceptors = [];
|
|
10500
|
-
}
|
|
11552
|
+
interceptors = [];
|
|
10501
11553
|
use(interceptor) {
|
|
10502
11554
|
this.interceptors.push(interceptor);
|
|
10503
11555
|
}
|
|
@@ -10516,6 +11568,13 @@ var InterceptorPipeline = class {
|
|
|
10516
11568
|
|
|
10517
11569
|
// src/orm/orm.ts
|
|
10518
11570
|
var Orm = class {
|
|
11571
|
+
/** The database dialect */
|
|
11572
|
+
dialect;
|
|
11573
|
+
/** The interceptors pipeline */
|
|
11574
|
+
interceptors;
|
|
11575
|
+
/** The naming strategy */
|
|
11576
|
+
namingStrategy;
|
|
11577
|
+
executorFactory;
|
|
10519
11578
|
/**
|
|
10520
11579
|
* Creates a new ORM instance.
|
|
10521
11580
|
* @param opts - ORM options
|
|
@@ -10572,17 +11631,13 @@ var jsonify = (value) => {
|
|
|
10572
11631
|
|
|
10573
11632
|
// src/decorators/decorator-metadata.ts
|
|
10574
11633
|
var METADATA_KEY = "metal-orm:decorators";
|
|
10575
|
-
var isStandardDecoratorContext = (value) => {
|
|
10576
|
-
return typeof value === "object" && value !== null && "kind" in value;
|
|
10577
|
-
};
|
|
10578
11634
|
var getOrCreateMetadataBag = (context) => {
|
|
10579
11635
|
const metadata = context.metadata || (context.metadata = {});
|
|
10580
|
-
|
|
10581
|
-
if (
|
|
10582
|
-
|
|
11636
|
+
let bag = metadata[METADATA_KEY];
|
|
11637
|
+
if (!bag) {
|
|
11638
|
+
bag = { columns: [], relations: [] };
|
|
11639
|
+
metadata[METADATA_KEY] = bag;
|
|
10583
11640
|
}
|
|
10584
|
-
const bag = { columns: [], relations: [] };
|
|
10585
|
-
metadata[METADATA_KEY] = bag;
|
|
10586
11641
|
return bag;
|
|
10587
11642
|
};
|
|
10588
11643
|
var readMetadataBag = (context) => {
|
|
@@ -10597,57 +11652,50 @@ var readMetadataBagFromConstructor = (ctor) => {
|
|
|
10597
11652
|
var getDecoratorMetadata = (ctor) => readMetadataBagFromConstructor(ctor);
|
|
10598
11653
|
|
|
10599
11654
|
// src/decorators/entity.ts
|
|
10600
|
-
var
|
|
11655
|
+
var toSnakeCase2 = (value) => {
|
|
10601
11656
|
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
10602
11657
|
};
|
|
10603
11658
|
var deriveTableNameFromConstructor = (ctor) => {
|
|
10604
11659
|
const fallback = "unknown";
|
|
10605
11660
|
const rawName = ctor.name || fallback;
|
|
10606
11661
|
const strippedName = rawName.replace(/Entity$/i, "");
|
|
10607
|
-
const normalized =
|
|
11662
|
+
const normalized = toSnakeCase2(strippedName || rawName);
|
|
10608
11663
|
if (!normalized) {
|
|
10609
11664
|
return fallback;
|
|
10610
11665
|
}
|
|
10611
11666
|
return normalized.endsWith("s") ? normalized : `${normalized}s`;
|
|
10612
11667
|
};
|
|
10613
11668
|
function Entity(options = {}) {
|
|
10614
|
-
|
|
10615
|
-
const tableName = options.tableName ?? deriveTableNameFromConstructor(value);
|
|
10616
|
-
setEntityTableName(value, tableName, options.hooks);
|
|
10617
|
-
return value;
|
|
10618
|
-
};
|
|
10619
|
-
const decoratorWithContext = (value, context) => {
|
|
11669
|
+
return function(value, context) {
|
|
10620
11670
|
const ctor = value;
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
}
|
|
10632
|
-
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11671
|
+
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
11672
|
+
setEntityTableName(ctor, tableName, options.hooks);
|
|
11673
|
+
const bag = readMetadataBag(context);
|
|
11674
|
+
if (bag) {
|
|
11675
|
+
const meta = ensureEntityMetadata(ctor);
|
|
11676
|
+
for (const entry of bag.columns) {
|
|
11677
|
+
if (meta.columns[entry.propertyName]) {
|
|
11678
|
+
throw new Error(
|
|
11679
|
+
`Column '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11680
|
+
);
|
|
10633
11681
|
}
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
...entry.relation,
|
|
10642
|
-
defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
|
|
10643
|
-
} : { ...entry.relation };
|
|
10644
|
-
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
11682
|
+
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11683
|
+
}
|
|
11684
|
+
for (const entry of bag.relations) {
|
|
11685
|
+
if (meta.relations[entry.propertyName]) {
|
|
11686
|
+
throw new Error(
|
|
11687
|
+
`Relation '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11688
|
+
);
|
|
10645
11689
|
}
|
|
11690
|
+
const relationCopy = entry.relation.kind === RelationKinds.BelongsToMany ? {
|
|
11691
|
+
...entry.relation,
|
|
11692
|
+
defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
|
|
11693
|
+
} : { ...entry.relation };
|
|
11694
|
+
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
10646
11695
|
}
|
|
10647
11696
|
}
|
|
10648
11697
|
return ctor;
|
|
10649
11698
|
};
|
|
10650
|
-
return decoratorWithContext;
|
|
10651
11699
|
}
|
|
10652
11700
|
|
|
10653
11701
|
// src/decorators/column-decorator.ts
|
|
@@ -10680,26 +11728,13 @@ var normalizePropertyName = (name) => {
|
|
|
10680
11728
|
}
|
|
10681
11729
|
return name;
|
|
10682
11730
|
};
|
|
10683
|
-
var resolveConstructor = (target) => {
|
|
10684
|
-
if (typeof target === "function") {
|
|
10685
|
-
return target;
|
|
10686
|
-
}
|
|
10687
|
-
if (target && typeof target.constructor === "function") {
|
|
10688
|
-
return target.constructor;
|
|
10689
|
-
}
|
|
10690
|
-
return void 0;
|
|
10691
|
-
};
|
|
10692
|
-
var registerColumn = (ctor, propertyName, column) => {
|
|
10693
|
-
const meta = ensureEntityMetadata(ctor);
|
|
10694
|
-
if (meta.columns[propertyName]) {
|
|
10695
|
-
return;
|
|
10696
|
-
}
|
|
10697
|
-
addColumnMetadata(ctor, propertyName, column);
|
|
10698
|
-
};
|
|
10699
11731
|
var registerColumnFromContext = (context, column) => {
|
|
10700
11732
|
if (!context.name) {
|
|
10701
11733
|
throw new Error("Column decorator requires a property name");
|
|
10702
11734
|
}
|
|
11735
|
+
if (context.private) {
|
|
11736
|
+
throw new Error("Column decorator does not support private fields");
|
|
11737
|
+
}
|
|
10703
11738
|
const propertyName = normalizePropertyName(context.name);
|
|
10704
11739
|
const bag = getOrCreateMetadataBag(context);
|
|
10705
11740
|
if (!bag.columns.some((entry) => entry.propertyName === propertyName)) {
|
|
@@ -10708,19 +11743,9 @@ var registerColumnFromContext = (context, column) => {
|
|
|
10708
11743
|
};
|
|
10709
11744
|
function Column(definition) {
|
|
10710
11745
|
const normalized = normalizeColumnInput(definition);
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
registerColumnFromContext(propertyKeyOrContext, normalized);
|
|
10714
|
-
return;
|
|
10715
|
-
}
|
|
10716
|
-
const propertyName = normalizePropertyName(propertyKeyOrContext);
|
|
10717
|
-
const ctor = resolveConstructor(targetOrValue);
|
|
10718
|
-
if (!ctor) {
|
|
10719
|
-
throw new Error("Unable to resolve constructor when registering column metadata");
|
|
10720
|
-
}
|
|
10721
|
-
registerColumn(ctor, propertyName, { ...normalized });
|
|
11746
|
+
return function(_value, context) {
|
|
11747
|
+
registerColumnFromContext(context, normalized);
|
|
10722
11748
|
};
|
|
10723
|
-
return decorator;
|
|
10724
11749
|
}
|
|
10725
11750
|
function PrimaryKey(definition) {
|
|
10726
11751
|
const normalized = normalizeColumnInput(definition);
|
|
@@ -10735,41 +11760,21 @@ var normalizePropertyName2 = (name) => {
|
|
|
10735
11760
|
}
|
|
10736
11761
|
return name;
|
|
10737
11762
|
};
|
|
10738
|
-
var resolveConstructor2 = (instanceOrCtor) => {
|
|
10739
|
-
if (typeof instanceOrCtor === "function") {
|
|
10740
|
-
return instanceOrCtor;
|
|
10741
|
-
}
|
|
10742
|
-
if (instanceOrCtor && typeof instanceOrCtor.constructor === "function") {
|
|
10743
|
-
return instanceOrCtor.constructor;
|
|
10744
|
-
}
|
|
10745
|
-
return void 0;
|
|
10746
|
-
};
|
|
10747
|
-
var registerRelation = (ctor, propertyName, metadata) => {
|
|
10748
|
-
addRelationMetadata(ctor, propertyName, metadata);
|
|
10749
|
-
};
|
|
10750
11763
|
var createFieldDecorator = (metadataFactory) => {
|
|
10751
|
-
|
|
10752
|
-
if (
|
|
10753
|
-
|
|
10754
|
-
if (!ctx.name) {
|
|
10755
|
-
throw new Error("Relation decorator requires a property name");
|
|
10756
|
-
}
|
|
10757
|
-
const propertyName2 = normalizePropertyName2(ctx.name);
|
|
10758
|
-
const bag = getOrCreateMetadataBag(ctx);
|
|
10759
|
-
const relationMetadata = metadataFactory(propertyName2);
|
|
10760
|
-
if (!bag.relations.some((entry) => entry.propertyName === propertyName2)) {
|
|
10761
|
-
bag.relations.push({ propertyName: propertyName2, relation: relationMetadata });
|
|
10762
|
-
}
|
|
10763
|
-
return;
|
|
11764
|
+
return function(_value, context) {
|
|
11765
|
+
if (!context.name) {
|
|
11766
|
+
throw new Error("Relation decorator requires a property name");
|
|
10764
11767
|
}
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
11768
|
+
if (context.private) {
|
|
11769
|
+
throw new Error("Relation decorator does not support private fields");
|
|
11770
|
+
}
|
|
11771
|
+
const propertyName = normalizePropertyName2(context.name);
|
|
11772
|
+
const bag = getOrCreateMetadataBag(context);
|
|
11773
|
+
const relationMetadata = metadataFactory(propertyName);
|
|
11774
|
+
if (!bag.relations.some((entry) => entry.propertyName === propertyName)) {
|
|
11775
|
+
bag.relations.push({ propertyName, relation: relationMetadata });
|
|
10769
11776
|
}
|
|
10770
|
-
registerRelation(ctor, propertyName, metadataFactory(propertyName));
|
|
10771
11777
|
};
|
|
10772
|
-
return decorator;
|
|
10773
11778
|
};
|
|
10774
11779
|
function HasMany(options) {
|
|
10775
11780
|
return createFieldDecorator((propertyName) => ({
|
|
@@ -10796,7 +11801,7 @@ function BelongsTo(options) {
|
|
|
10796
11801
|
kind: RelationKinds.BelongsTo,
|
|
10797
11802
|
propertyKey: propertyName,
|
|
10798
11803
|
target: options.target,
|
|
10799
|
-
foreignKey: options.foreignKey
|
|
11804
|
+
foreignKey: options.foreignKey ?? `${propertyName}_id`,
|
|
10800
11805
|
localKey: options.localKey,
|
|
10801
11806
|
cascade: options.cascade
|
|
10802
11807
|
}));
|
|
@@ -10872,13 +11877,15 @@ var deferred = () => {
|
|
|
10872
11877
|
return { promise, resolve, reject };
|
|
10873
11878
|
};
|
|
10874
11879
|
var Pool = class {
|
|
11880
|
+
adapter;
|
|
11881
|
+
options;
|
|
11882
|
+
destroyed = false;
|
|
11883
|
+
creating = 0;
|
|
11884
|
+
leased = 0;
|
|
11885
|
+
idle = [];
|
|
11886
|
+
waiters = [];
|
|
11887
|
+
reapTimer = null;
|
|
10875
11888
|
constructor(adapter, options) {
|
|
10876
|
-
this.destroyed = false;
|
|
10877
|
-
this.creating = 0;
|
|
10878
|
-
this.leased = 0;
|
|
10879
|
-
this.idle = [];
|
|
10880
|
-
this.waiters = [];
|
|
10881
|
-
this.reapTimer = null;
|
|
10882
11889
|
if (!Number.isFinite(options.max) || options.max <= 0) {
|
|
10883
11890
|
throw new Error("Pool options.max must be a positive number");
|
|
10884
11891
|
}
|
|
@@ -11440,6 +12447,8 @@ export {
|
|
|
11440
12447
|
esel,
|
|
11441
12448
|
executeHydrated,
|
|
11442
12449
|
executeHydratedWithContexts,
|
|
12450
|
+
executeSchemaSql,
|
|
12451
|
+
executeSchemaSqlFor,
|
|
11443
12452
|
exists,
|
|
11444
12453
|
exp,
|
|
11445
12454
|
extract,
|
|
@@ -11448,6 +12457,7 @@ export {
|
|
|
11448
12457
|
fromUnixTime,
|
|
11449
12458
|
generateCreateTableSql,
|
|
11450
12459
|
generateSchemaSql,
|
|
12460
|
+
generateSchemaSqlFor,
|
|
11451
12461
|
getColumn,
|
|
11452
12462
|
getDecoratorMetadata,
|
|
11453
12463
|
getSchemaIntrospector,
|
|
@@ -11538,6 +12548,7 @@ export {
|
|
|
11538
12548
|
registerExpressionDispatcher,
|
|
11539
12549
|
registerOperandDispatcher,
|
|
11540
12550
|
registerSchemaIntrospector,
|
|
12551
|
+
relationLoaderCache,
|
|
11541
12552
|
renderColumnDefinition,
|
|
11542
12553
|
renderTypeWithArgs,
|
|
11543
12554
|
repeat,
|
|
@@ -11552,6 +12563,7 @@ export {
|
|
|
11552
12563
|
second,
|
|
11553
12564
|
sel,
|
|
11554
12565
|
selectFromEntity,
|
|
12566
|
+
setRelations,
|
|
11555
12567
|
sha1,
|
|
11556
12568
|
sha2,
|
|
11557
12569
|
shiftLeft,
|