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.cjs
CHANGED
|
@@ -143,6 +143,8 @@ __export(index_exports, {
|
|
|
143
143
|
esel: () => esel,
|
|
144
144
|
executeHydrated: () => executeHydrated,
|
|
145
145
|
executeHydratedWithContexts: () => executeHydratedWithContexts,
|
|
146
|
+
executeSchemaSql: () => executeSchemaSql,
|
|
147
|
+
executeSchemaSqlFor: () => executeSchemaSqlFor,
|
|
146
148
|
exists: () => exists,
|
|
147
149
|
exp: () => exp,
|
|
148
150
|
extract: () => extract,
|
|
@@ -151,6 +153,7 @@ __export(index_exports, {
|
|
|
151
153
|
fromUnixTime: () => fromUnixTime,
|
|
152
154
|
generateCreateTableSql: () => generateCreateTableSql,
|
|
153
155
|
generateSchemaSql: () => generateSchemaSql,
|
|
156
|
+
generateSchemaSqlFor: () => generateSchemaSqlFor,
|
|
154
157
|
getColumn: () => getColumn,
|
|
155
158
|
getDecoratorMetadata: () => getDecoratorMetadata,
|
|
156
159
|
getSchemaIntrospector: () => getSchemaIntrospector,
|
|
@@ -241,6 +244,7 @@ __export(index_exports, {
|
|
|
241
244
|
registerExpressionDispatcher: () => registerExpressionDispatcher,
|
|
242
245
|
registerOperandDispatcher: () => registerOperandDispatcher,
|
|
243
246
|
registerSchemaIntrospector: () => registerSchemaIntrospector,
|
|
247
|
+
relationLoaderCache: () => relationLoaderCache,
|
|
244
248
|
renderColumnDefinition: () => renderColumnDefinition,
|
|
245
249
|
renderTypeWithArgs: () => renderTypeWithArgs,
|
|
246
250
|
repeat: () => repeat,
|
|
@@ -255,6 +259,7 @@ __export(index_exports, {
|
|
|
255
259
|
second: () => second,
|
|
256
260
|
sel: () => sel,
|
|
257
261
|
selectFromEntity: () => selectFromEntity,
|
|
262
|
+
setRelations: () => setRelations,
|
|
258
263
|
sha1: () => sha1,
|
|
259
264
|
sha2: () => sha2,
|
|
260
265
|
shiftLeft: () => shiftLeft,
|
|
@@ -310,6 +315,9 @@ var defineTable = (name, columns, relations = {}, hooks, options = {}) => {
|
|
|
310
315
|
collation: options.collation
|
|
311
316
|
};
|
|
312
317
|
};
|
|
318
|
+
function setRelations(table, relations) {
|
|
319
|
+
table.relations = relations;
|
|
320
|
+
}
|
|
313
321
|
var TABLE_REF_CACHE = /* @__PURE__ */ new WeakMap();
|
|
314
322
|
var withColumnProps = (table) => {
|
|
315
323
|
const cached = TABLE_REF_CACHE.get(table);
|
|
@@ -953,6 +961,7 @@ var variance = buildAggregate("VARIANCE");
|
|
|
953
961
|
|
|
954
962
|
// src/core/ast/expression-visitor.ts
|
|
955
963
|
var DispatcherRegistry = class _DispatcherRegistry {
|
|
964
|
+
dispatchers;
|
|
956
965
|
constructor(dispatchers = /* @__PURE__ */ new Map()) {
|
|
957
966
|
this.dispatchers = dispatchers;
|
|
958
967
|
}
|
|
@@ -1086,61 +1095,9 @@ var toTableRef = (table) => ({
|
|
|
1086
1095
|
alias: hasAlias(table) ? table.alias : void 0
|
|
1087
1096
|
});
|
|
1088
1097
|
|
|
1089
|
-
// src/core/ast/builders.ts
|
|
1090
|
-
var isColumnNode = (col2) => "type" in col2 && col2.type === "Column";
|
|
1091
|
-
var resolveTableName = (def, table) => {
|
|
1092
|
-
if (!def.table) {
|
|
1093
|
-
return table.alias || table.name;
|
|
1094
|
-
}
|
|
1095
|
-
if (table.alias && def.table === table.name) {
|
|
1096
|
-
return table.alias;
|
|
1097
|
-
}
|
|
1098
|
-
return def.table;
|
|
1099
|
-
};
|
|
1100
|
-
var buildColumnNode = (table, column) => {
|
|
1101
|
-
if (isColumnNode(column)) {
|
|
1102
|
-
return column;
|
|
1103
|
-
}
|
|
1104
|
-
const def = column;
|
|
1105
|
-
const baseTable = resolveTableName(def, table);
|
|
1106
|
-
return {
|
|
1107
|
-
type: "Column",
|
|
1108
|
-
table: baseTable,
|
|
1109
|
-
name: def.name
|
|
1110
|
-
};
|
|
1111
|
-
};
|
|
1112
|
-
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
1113
|
-
type: "Column",
|
|
1114
|
-
table: table.alias || table.name,
|
|
1115
|
-
name
|
|
1116
|
-
}));
|
|
1117
|
-
var createTableNode = (table) => ({
|
|
1118
|
-
type: "Table",
|
|
1119
|
-
name: table.name,
|
|
1120
|
-
schema: table.schema
|
|
1121
|
-
});
|
|
1122
|
-
var fnTable = (name, args = [], alias, opts) => ({
|
|
1123
|
-
type: "FunctionTable",
|
|
1124
|
-
name,
|
|
1125
|
-
args,
|
|
1126
|
-
alias,
|
|
1127
|
-
lateral: opts?.lateral,
|
|
1128
|
-
withOrdinality: opts?.withOrdinality,
|
|
1129
|
-
columnAliases: opts?.columnAliases,
|
|
1130
|
-
schema: opts?.schema
|
|
1131
|
-
});
|
|
1132
|
-
var derivedTable = (query, alias, columnAliases) => ({
|
|
1133
|
-
type: "DerivedTable",
|
|
1134
|
-
query,
|
|
1135
|
-
alias,
|
|
1136
|
-
columnAliases
|
|
1137
|
-
});
|
|
1138
|
-
|
|
1139
1098
|
// src/core/functions/function-registry.ts
|
|
1140
1099
|
var FunctionRegistry = class {
|
|
1141
|
-
|
|
1142
|
-
this.renderers = /* @__PURE__ */ new Map();
|
|
1143
|
-
}
|
|
1100
|
+
renderers = /* @__PURE__ */ new Map();
|
|
1144
1101
|
/**
|
|
1145
1102
|
* Registers or overrides a renderer for the given function name.
|
|
1146
1103
|
*/
|
|
@@ -1435,6 +1392,7 @@ function renderStandardGroupConcat(ctx) {
|
|
|
1435
1392
|
|
|
1436
1393
|
// src/core/functions/standard-strategy.ts
|
|
1437
1394
|
var StandardFunctionStrategy = class {
|
|
1395
|
+
registry;
|
|
1438
1396
|
/**
|
|
1439
1397
|
* Creates a new StandardFunctionStrategy and registers standard functions.
|
|
1440
1398
|
*/
|
|
@@ -1500,17 +1458,13 @@ var StandardFunctionStrategy = class {
|
|
|
1500
1458
|
getGroupConcatSeparatorOperand(ctx) {
|
|
1501
1459
|
return getGroupConcatSeparatorOperand(ctx);
|
|
1502
1460
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
this.DEFAULT_GROUP_CONCAT_SEPARATOR = DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
1506
|
-
}
|
|
1461
|
+
/** Default separator for GROUP_CONCAT, a comma. */
|
|
1462
|
+
static DEFAULT_GROUP_CONCAT_SEPARATOR = DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
1507
1463
|
};
|
|
1508
1464
|
|
|
1509
1465
|
// src/core/functions/standard-table-strategy.ts
|
|
1510
1466
|
var StandardTableFunctionStrategy = class {
|
|
1511
|
-
|
|
1512
|
-
this.renderers = /* @__PURE__ */ new Map();
|
|
1513
|
-
}
|
|
1467
|
+
renderers = /* @__PURE__ */ new Map();
|
|
1514
1468
|
add(key, renderer) {
|
|
1515
1469
|
this.renderers.set(key, renderer);
|
|
1516
1470
|
}
|
|
@@ -1689,6 +1643,10 @@ var Dialect = class _Dialect {
|
|
|
1689
1643
|
const combinedCtes = [...normalized.ctes ?? [], ...hoistedCtes];
|
|
1690
1644
|
return combinedCtes.length ? { ...normalized, ctes: combinedCtes } : normalized;
|
|
1691
1645
|
}
|
|
1646
|
+
expressionCompilers;
|
|
1647
|
+
operandCompilers;
|
|
1648
|
+
functionStrategy;
|
|
1649
|
+
tableFunctionStrategy;
|
|
1692
1650
|
constructor(functionStrategy, tableFunctionStrategy) {
|
|
1693
1651
|
this.expressionCompilers = /* @__PURE__ */ new Map();
|
|
1694
1652
|
this.operandCompilers = /* @__PURE__ */ new Map();
|
|
@@ -1704,10 +1662,7 @@ var Dialect = class _Dialect {
|
|
|
1704
1662
|
*/
|
|
1705
1663
|
static create(functionStrategy, tableFunctionStrategy) {
|
|
1706
1664
|
class TestDialect extends _Dialect {
|
|
1707
|
-
|
|
1708
|
-
super(...arguments);
|
|
1709
|
-
this.dialect = "sqlite";
|
|
1710
|
-
}
|
|
1665
|
+
dialect = "sqlite";
|
|
1711
1666
|
quoteIdentifier(id) {
|
|
1712
1667
|
return `"${id}"`;
|
|
1713
1668
|
}
|
|
@@ -2147,11 +2102,8 @@ var OrderByCompiler = class {
|
|
|
2147
2102
|
|
|
2148
2103
|
// src/core/dialect/base/sql-dialect.ts
|
|
2149
2104
|
var SqlDialectBase = class extends Dialect {
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
this.paginationStrategy = new StandardLimitOffsetPagination();
|
|
2153
|
-
this.returningStrategy = new NoReturningStrategy();
|
|
2154
|
-
}
|
|
2105
|
+
paginationStrategy = new StandardLimitOffsetPagination();
|
|
2106
|
+
returningStrategy = new NoReturningStrategy();
|
|
2155
2107
|
compileSelectAst(ast, ctx) {
|
|
2156
2108
|
const hasSetOps = !!(ast.setOps && ast.setOps.length);
|
|
2157
2109
|
const ctes = CteCompiler.compileCtes(
|
|
@@ -2539,12 +2491,12 @@ var PostgresTableFunctionStrategy = class extends StandardTableFunctionStrategy
|
|
|
2539
2491
|
|
|
2540
2492
|
// src/core/dialect/postgres/index.ts
|
|
2541
2493
|
var PostgresDialect = class extends SqlDialectBase {
|
|
2494
|
+
dialect = "postgres";
|
|
2542
2495
|
/**
|
|
2543
2496
|
* Creates a new PostgresDialect instance
|
|
2544
2497
|
*/
|
|
2545
2498
|
constructor() {
|
|
2546
2499
|
super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
|
|
2547
|
-
this.dialect = "postgres";
|
|
2548
2500
|
this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
|
|
2549
2501
|
const left2 = this.compileOperand(node.left, ctx);
|
|
2550
2502
|
const right2 = this.compileOperand(node.right, ctx);
|
|
@@ -2678,12 +2630,12 @@ var MysqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2678
2630
|
|
|
2679
2631
|
// src/core/dialect/mysql/index.ts
|
|
2680
2632
|
var MySqlDialect = class extends SqlDialectBase {
|
|
2633
|
+
dialect = "mysql";
|
|
2681
2634
|
/**
|
|
2682
2635
|
* Creates a new MySqlDialect instance
|
|
2683
2636
|
*/
|
|
2684
2637
|
constructor() {
|
|
2685
2638
|
super(new MysqlFunctionStrategy());
|
|
2686
|
-
this.dialect = "mysql";
|
|
2687
2639
|
}
|
|
2688
2640
|
/**
|
|
2689
2641
|
* Quotes an identifier using MySQL backtick syntax
|
|
@@ -2834,12 +2786,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2834
2786
|
|
|
2835
2787
|
// src/core/dialect/sqlite/index.ts
|
|
2836
2788
|
var SqliteDialect = class extends SqlDialectBase {
|
|
2789
|
+
dialect = "sqlite";
|
|
2837
2790
|
/**
|
|
2838
2791
|
* Creates a new SqliteDialect instance
|
|
2839
2792
|
*/
|
|
2840
2793
|
constructor() {
|
|
2841
2794
|
super(new SqliteFunctionStrategy());
|
|
2842
|
-
this.dialect = "sqlite";
|
|
2843
2795
|
this.registerExpressionCompiler("BitwiseExpression", (node, ctx) => {
|
|
2844
2796
|
const left2 = this.compileOperand(node.left, ctx);
|
|
2845
2797
|
const right2 = this.compileOperand(node.right, ctx);
|
|
@@ -3012,12 +2964,12 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
3012
2964
|
|
|
3013
2965
|
// src/core/dialect/mssql/index.ts
|
|
3014
2966
|
var SqlServerDialect = class extends SqlDialectBase {
|
|
2967
|
+
dialect = "mssql";
|
|
3015
2968
|
/**
|
|
3016
2969
|
* Creates a new SqlServerDialect instance
|
|
3017
2970
|
*/
|
|
3018
2971
|
constructor() {
|
|
3019
2972
|
super(new MssqlFunctionStrategy());
|
|
3020
|
-
this.dialect = "mssql";
|
|
3021
2973
|
}
|
|
3022
2974
|
/**
|
|
3023
2975
|
* Quotes an identifier using SQL Server bracket syntax
|
|
@@ -3144,12 +3096,8 @@ var SqlServerDialect = class extends SqlDialectBase {
|
|
|
3144
3096
|
|
|
3145
3097
|
// src/core/dialect/dialect-factory.ts
|
|
3146
3098
|
var DialectFactory = class {
|
|
3147
|
-
static
|
|
3148
|
-
|
|
3149
|
-
}
|
|
3150
|
-
static {
|
|
3151
|
-
this.defaultsInitialized = false;
|
|
3152
|
-
}
|
|
3099
|
+
static registry = /* @__PURE__ */ new Map();
|
|
3100
|
+
static defaultsInitialized = false;
|
|
3153
3101
|
static ensureDefaults() {
|
|
3154
3102
|
if (this.defaultsInitialized) return;
|
|
3155
3103
|
this.defaultsInitialized = true;
|
|
@@ -3208,8 +3156,66 @@ var resolveDialectInput = (dialect) => {
|
|
|
3208
3156
|
return dialect;
|
|
3209
3157
|
};
|
|
3210
3158
|
|
|
3159
|
+
// src/core/ast/builders.ts
|
|
3160
|
+
var isColumnNode = (col2) => "type" in col2 && col2.type === "Column";
|
|
3161
|
+
var resolveTableName = (def, table) => {
|
|
3162
|
+
if (!def.table) {
|
|
3163
|
+
return table.alias || table.name;
|
|
3164
|
+
}
|
|
3165
|
+
if (table.alias && def.table === table.name) {
|
|
3166
|
+
return table.alias;
|
|
3167
|
+
}
|
|
3168
|
+
return def.table;
|
|
3169
|
+
};
|
|
3170
|
+
var buildColumnNode = (table, column) => {
|
|
3171
|
+
if (isColumnNode(column)) {
|
|
3172
|
+
return column;
|
|
3173
|
+
}
|
|
3174
|
+
const def = column;
|
|
3175
|
+
const baseTable = resolveTableName(def, table);
|
|
3176
|
+
return {
|
|
3177
|
+
type: "Column",
|
|
3178
|
+
table: baseTable,
|
|
3179
|
+
name: def.name
|
|
3180
|
+
};
|
|
3181
|
+
};
|
|
3182
|
+
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
3183
|
+
type: "Column",
|
|
3184
|
+
table: table.alias || table.name,
|
|
3185
|
+
name
|
|
3186
|
+
}));
|
|
3187
|
+
var createTableNode = (table) => ({
|
|
3188
|
+
type: "Table",
|
|
3189
|
+
name: table.name,
|
|
3190
|
+
schema: table.schema
|
|
3191
|
+
});
|
|
3192
|
+
var fnTable = (name, args = [], alias, opts) => ({
|
|
3193
|
+
type: "FunctionTable",
|
|
3194
|
+
name,
|
|
3195
|
+
args,
|
|
3196
|
+
alias,
|
|
3197
|
+
lateral: opts?.lateral,
|
|
3198
|
+
withOrdinality: opts?.withOrdinality,
|
|
3199
|
+
columnAliases: opts?.columnAliases,
|
|
3200
|
+
schema: opts?.schema
|
|
3201
|
+
});
|
|
3202
|
+
var derivedTable = (query, alias, columnAliases) => ({
|
|
3203
|
+
type: "DerivedTable",
|
|
3204
|
+
query,
|
|
3205
|
+
alias,
|
|
3206
|
+
columnAliases
|
|
3207
|
+
});
|
|
3208
|
+
|
|
3211
3209
|
// src/query-builder/select-query-state.ts
|
|
3212
3210
|
var SelectQueryState = class _SelectQueryState {
|
|
3211
|
+
/**
|
|
3212
|
+
* Table definition for the query
|
|
3213
|
+
*/
|
|
3214
|
+
table;
|
|
3215
|
+
/**
|
|
3216
|
+
* Abstract Syntax Tree (AST) representation of the query
|
|
3217
|
+
*/
|
|
3218
|
+
ast;
|
|
3213
3219
|
/**
|
|
3214
3220
|
* Creates a new SelectQueryState instance
|
|
3215
3221
|
* @param table - Table definition
|
|
@@ -4111,20 +4117,21 @@ var RelationProjectionHelper = class {
|
|
|
4111
4117
|
var assertNever = (value) => {
|
|
4112
4118
|
throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
|
|
4113
4119
|
};
|
|
4114
|
-
var baseRelationCondition = (root, relation, rootAlias) => {
|
|
4120
|
+
var baseRelationCondition = (root, relation, rootAlias, targetTableName) => {
|
|
4115
4121
|
const rootTable = rootAlias || root.name;
|
|
4122
|
+
const targetTable = targetTableName ?? relation.target.name;
|
|
4116
4123
|
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
4117
4124
|
const localKey = relation.localKey || defaultLocalKey;
|
|
4118
4125
|
switch (relation.type) {
|
|
4119
4126
|
case RelationKinds.HasMany:
|
|
4120
4127
|
case RelationKinds.HasOne:
|
|
4121
4128
|
return eq(
|
|
4122
|
-
{ type: "Column", table:
|
|
4129
|
+
{ type: "Column", table: targetTable, name: relation.foreignKey },
|
|
4123
4130
|
{ type: "Column", table: rootTable, name: localKey }
|
|
4124
4131
|
);
|
|
4125
4132
|
case RelationKinds.BelongsTo:
|
|
4126
4133
|
return eq(
|
|
4127
|
-
{ type: "Column", table:
|
|
4134
|
+
{ type: "Column", table: targetTable, name: localKey },
|
|
4128
4135
|
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
4129
4136
|
);
|
|
4130
4137
|
case RelationKinds.BelongsToMany:
|
|
@@ -4133,7 +4140,7 @@ var baseRelationCondition = (root, relation, rootAlias) => {
|
|
|
4133
4140
|
return assertNever(relation);
|
|
4134
4141
|
}
|
|
4135
4142
|
};
|
|
4136
|
-
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
|
|
4143
|
+
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias, targetTable, targetTableName) => {
|
|
4137
4144
|
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
4138
4145
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
4139
4146
|
const rootTable = rootAlias || root.name;
|
|
@@ -4146,8 +4153,14 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, ro
|
|
|
4146
4153
|
{ type: "Table", name: relation.pivotTable.name, schema: relation.pivotTable.schema },
|
|
4147
4154
|
pivotCondition
|
|
4148
4155
|
);
|
|
4156
|
+
const targetSource = targetTable ?? {
|
|
4157
|
+
type: "Table",
|
|
4158
|
+
name: relation.target.name,
|
|
4159
|
+
schema: relation.target.schema
|
|
4160
|
+
};
|
|
4161
|
+
const effectiveTargetName = targetTableName ?? relation.target.name;
|
|
4149
4162
|
let targetCondition = eq(
|
|
4150
|
-
{ type: "Column", table:
|
|
4163
|
+
{ type: "Column", table: effectiveTargetName, name: targetKey },
|
|
4151
4164
|
{ type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToTarget }
|
|
4152
4165
|
);
|
|
4153
4166
|
if (extra) {
|
|
@@ -4155,141 +4168,487 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, ro
|
|
|
4155
4168
|
}
|
|
4156
4169
|
const targetJoin = createJoinNode(
|
|
4157
4170
|
joinKind,
|
|
4158
|
-
|
|
4171
|
+
targetSource,
|
|
4159
4172
|
targetCondition,
|
|
4160
4173
|
relationName
|
|
4161
4174
|
);
|
|
4162
4175
|
return [pivotJoin, targetJoin];
|
|
4163
4176
|
};
|
|
4164
|
-
var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
|
|
4165
|
-
const base = baseRelationCondition(root, relation, rootAlias);
|
|
4177
|
+
var buildRelationJoinCondition = (root, relation, extra, rootAlias, targetTableName) => {
|
|
4178
|
+
const base = baseRelationCondition(root, relation, rootAlias, targetTableName);
|
|
4166
4179
|
return extra ? and(base, extra) : base;
|
|
4167
4180
|
};
|
|
4168
|
-
var buildRelationCorrelation = (root, relation, rootAlias) => {
|
|
4169
|
-
return baseRelationCondition(root, relation, rootAlias);
|
|
4181
|
+
var buildRelationCorrelation = (root, relation, rootAlias, targetTableName) => {
|
|
4182
|
+
return baseRelationCondition(root, relation, rootAlias, targetTableName);
|
|
4170
4183
|
};
|
|
4171
4184
|
|
|
4172
4185
|
// src/core/ast/join-metadata.ts
|
|
4173
4186
|
var getJoinRelationName = (join) => join.meta?.relationName;
|
|
4174
4187
|
|
|
4175
|
-
// src/query-builder/relation-
|
|
4176
|
-
var
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
this.hydration = hydration;
|
|
4187
|
-
this.createQueryAstService = createQueryAstService;
|
|
4188
|
-
this.projectionHelper = new RelationProjectionHelper(
|
|
4189
|
-
table,
|
|
4190
|
-
(state2, hydration2, columns) => this.selectColumns(state2, hydration2, columns)
|
|
4191
|
-
);
|
|
4188
|
+
// src/query-builder/relation-filter-utils.ts
|
|
4189
|
+
var splitFilterExpressions = (filter, allowedTables) => {
|
|
4190
|
+
const terms = flattenAnd(filter);
|
|
4191
|
+
const selfFilters = [];
|
|
4192
|
+
const crossFilters = [];
|
|
4193
|
+
for (const term of terms) {
|
|
4194
|
+
if (isExpressionSelfContained(term, allowedTables)) {
|
|
4195
|
+
selfFilters.push(term);
|
|
4196
|
+
} else {
|
|
4197
|
+
crossFilters.push(term);
|
|
4198
|
+
}
|
|
4192
4199
|
}
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
*/
|
|
4200
|
-
joinRelation(relationName, joinKind, extraCondition) {
|
|
4201
|
-
const nextState = this.withJoin(this.state, relationName, joinKind, extraCondition);
|
|
4202
|
-
return { state: nextState, hydration: this.hydration };
|
|
4200
|
+
return { selfFilters, crossFilters };
|
|
4201
|
+
};
|
|
4202
|
+
var flattenAnd = (node) => {
|
|
4203
|
+
if (!node) return [];
|
|
4204
|
+
if (node.type === "LogicalExpression" && node.operator === "AND") {
|
|
4205
|
+
return node.operands.flatMap((operand) => flattenAnd(operand));
|
|
4203
4206
|
}
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
4215
|
-
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
4216
|
-
return { state: nextState, hydration: joined.hydration };
|
|
4207
|
+
return [node];
|
|
4208
|
+
};
|
|
4209
|
+
var isExpressionSelfContained = (expr, allowedTables) => {
|
|
4210
|
+
const collector = collectReferencedTables(expr);
|
|
4211
|
+
if (collector.hasSubquery) return false;
|
|
4212
|
+
if (collector.tables.size === 0) return true;
|
|
4213
|
+
for (const table of collector.tables) {
|
|
4214
|
+
if (!allowedTables.has(table)) {
|
|
4215
|
+
return false;
|
|
4216
|
+
}
|
|
4217
4217
|
}
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4218
|
+
return true;
|
|
4219
|
+
};
|
|
4220
|
+
var collectReferencedTables = (expr) => {
|
|
4221
|
+
const collector = {
|
|
4222
|
+
tables: /* @__PURE__ */ new Set(),
|
|
4223
|
+
hasSubquery: false
|
|
4224
|
+
};
|
|
4225
|
+
collectFromExpression(expr, collector);
|
|
4226
|
+
return collector;
|
|
4227
|
+
};
|
|
4228
|
+
var collectFromExpression = (expr, collector) => {
|
|
4229
|
+
switch (expr.type) {
|
|
4230
|
+
case "BinaryExpression":
|
|
4231
|
+
collectFromOperand(expr.left, collector);
|
|
4232
|
+
collectFromOperand(expr.right, collector);
|
|
4233
|
+
break;
|
|
4234
|
+
case "LogicalExpression":
|
|
4235
|
+
expr.operands.forEach((operand) => collectFromExpression(operand, collector));
|
|
4236
|
+
break;
|
|
4237
|
+
case "NullExpression":
|
|
4238
|
+
collectFromOperand(expr.left, collector);
|
|
4239
|
+
break;
|
|
4240
|
+
case "InExpression":
|
|
4241
|
+
collectFromOperand(expr.left, collector);
|
|
4242
|
+
if (Array.isArray(expr.right)) {
|
|
4243
|
+
expr.right.forEach((value) => collectFromOperand(value, collector));
|
|
4244
|
+
} else {
|
|
4245
|
+
collector.hasSubquery = true;
|
|
4246
|
+
}
|
|
4247
|
+
break;
|
|
4248
|
+
case "ExistsExpression":
|
|
4249
|
+
collector.hasSubquery = true;
|
|
4250
|
+
break;
|
|
4251
|
+
case "BetweenExpression":
|
|
4252
|
+
collectFromOperand(expr.left, collector);
|
|
4253
|
+
collectFromOperand(expr.lower, collector);
|
|
4254
|
+
collectFromOperand(expr.upper, collector);
|
|
4255
|
+
break;
|
|
4256
|
+
case "ArithmeticExpression":
|
|
4257
|
+
case "BitwiseExpression":
|
|
4258
|
+
collectFromOperand(expr.left, collector);
|
|
4259
|
+
collectFromOperand(expr.right, collector);
|
|
4260
|
+
break;
|
|
4261
|
+
default:
|
|
4262
|
+
break;
|
|
4263
|
+
}
|
|
4264
|
+
};
|
|
4265
|
+
var collectFromOperand = (node, collector) => {
|
|
4266
|
+
switch (node.type) {
|
|
4267
|
+
case "Column":
|
|
4268
|
+
collector.tables.add(node.table);
|
|
4269
|
+
break;
|
|
4270
|
+
case "Function":
|
|
4271
|
+
node.args.forEach((arg) => collectFromOperand(arg, collector));
|
|
4272
|
+
if (node.separator) {
|
|
4273
|
+
collectFromOperand(node.separator, collector);
|
|
4274
|
+
}
|
|
4275
|
+
if (node.orderBy) {
|
|
4276
|
+
node.orderBy.forEach((order) => collectFromOrderingTerm(order.term, collector));
|
|
4277
|
+
}
|
|
4278
|
+
break;
|
|
4279
|
+
case "JsonPath":
|
|
4280
|
+
collectFromOperand(node.column, collector);
|
|
4281
|
+
break;
|
|
4282
|
+
case "ScalarSubquery":
|
|
4283
|
+
collector.hasSubquery = true;
|
|
4284
|
+
break;
|
|
4285
|
+
case "CaseExpression":
|
|
4286
|
+
node.conditions.forEach(({ when, then }) => {
|
|
4287
|
+
collectFromExpression(when, collector);
|
|
4288
|
+
collectFromOperand(then, collector);
|
|
4289
|
+
});
|
|
4290
|
+
if (node.else) {
|
|
4291
|
+
collectFromOperand(node.else, collector);
|
|
4292
|
+
}
|
|
4293
|
+
break;
|
|
4294
|
+
case "Cast":
|
|
4295
|
+
collectFromOperand(node.expression, collector);
|
|
4296
|
+
break;
|
|
4297
|
+
case "WindowFunction":
|
|
4298
|
+
node.args.forEach((arg) => collectFromOperand(arg, collector));
|
|
4299
|
+
node.partitionBy?.forEach((part) => collectFromOperand(part, collector));
|
|
4300
|
+
node.orderBy?.forEach((order) => collectFromOrderingTerm(order.term, collector));
|
|
4301
|
+
break;
|
|
4302
|
+
case "Collate":
|
|
4303
|
+
collectFromOperand(node.expression, collector);
|
|
4304
|
+
break;
|
|
4305
|
+
case "ArithmeticExpression":
|
|
4306
|
+
case "BitwiseExpression":
|
|
4307
|
+
collectFromOperand(node.left, collector);
|
|
4308
|
+
collectFromOperand(node.right, collector);
|
|
4309
|
+
break;
|
|
4310
|
+
case "Literal":
|
|
4311
|
+
case "AliasRef":
|
|
4312
|
+
break;
|
|
4313
|
+
default:
|
|
4314
|
+
break;
|
|
4315
|
+
}
|
|
4316
|
+
};
|
|
4317
|
+
var collectFromOrderingTerm = (term, collector) => {
|
|
4318
|
+
if (isOperandNode(term)) {
|
|
4319
|
+
collectFromOperand(term, collector);
|
|
4320
|
+
return;
|
|
4321
|
+
}
|
|
4322
|
+
collectFromExpression(term, collector);
|
|
4323
|
+
};
|
|
4324
|
+
|
|
4325
|
+
// src/query-builder/relation-join-planner.ts
|
|
4326
|
+
var RelationJoinPlanner = class {
|
|
4327
|
+
constructor(table, createQueryAstService) {
|
|
4328
|
+
this.table = table;
|
|
4329
|
+
this.createQueryAstService = createQueryAstService;
|
|
4330
|
+
}
|
|
4331
|
+
withJoin(state, relationName, relation, joinKind, extraCondition, tableSource) {
|
|
4332
|
+
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
4333
|
+
if (relation.type === RelationKinds.BelongsToMany) {
|
|
4334
|
+
const targetTableSource = tableSource ?? {
|
|
4335
|
+
type: "Table",
|
|
4336
|
+
name: relation.target.name,
|
|
4337
|
+
schema: relation.target.schema
|
|
4338
|
+
};
|
|
4339
|
+
const targetName2 = this.resolveTargetTableName(targetTableSource, relation);
|
|
4340
|
+
const joins = buildBelongsToManyJoins(
|
|
4341
|
+
this.table,
|
|
4342
|
+
relationName,
|
|
4343
|
+
relation,
|
|
4344
|
+
joinKind,
|
|
4345
|
+
extraCondition,
|
|
4346
|
+
rootAlias,
|
|
4347
|
+
targetTableSource,
|
|
4348
|
+
targetName2
|
|
4349
|
+
);
|
|
4350
|
+
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
4233
4351
|
}
|
|
4234
|
-
const
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
const buildTypedSelection = (columns, prefix, keys, missingMsg) => {
|
|
4239
|
-
return keys.reduce((acc, key) => {
|
|
4240
|
-
const def = columns[key];
|
|
4241
|
-
if (!def) {
|
|
4242
|
-
throw new Error(missingMsg(key));
|
|
4243
|
-
}
|
|
4244
|
-
acc[makeRelationAlias(prefix, key)] = def;
|
|
4245
|
-
return acc;
|
|
4246
|
-
}, {});
|
|
4352
|
+
const targetTable = tableSource ?? {
|
|
4353
|
+
type: "Table",
|
|
4354
|
+
name: relation.target.name,
|
|
4355
|
+
schema: relation.target.schema
|
|
4247
4356
|
};
|
|
4248
|
-
const
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4357
|
+
const targetName = this.resolveTargetTableName(targetTable, relation);
|
|
4358
|
+
const condition = buildRelationJoinCondition(
|
|
4359
|
+
this.table,
|
|
4360
|
+
relation,
|
|
4361
|
+
extraCondition,
|
|
4362
|
+
rootAlias,
|
|
4363
|
+
targetName
|
|
4253
4364
|
);
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4365
|
+
const joinNode = createJoinNode(joinKind, targetTable, condition, relationName);
|
|
4366
|
+
return this.astService(state).withJoin(joinNode);
|
|
4367
|
+
}
|
|
4368
|
+
astService(state) {
|
|
4369
|
+
return this.createQueryAstService(this.table, state);
|
|
4370
|
+
}
|
|
4371
|
+
resolveTargetTableName(target, relation) {
|
|
4372
|
+
if (target.type === "Table") {
|
|
4373
|
+
return target.alias ?? target.name;
|
|
4374
|
+
}
|
|
4375
|
+
if (target.type === "DerivedTable") {
|
|
4376
|
+
return target.alias;
|
|
4377
|
+
}
|
|
4378
|
+
if (target.type === "FunctionTable") {
|
|
4379
|
+
return target.alias ?? relation.target.name;
|
|
4380
|
+
}
|
|
4381
|
+
return relation.target.name;
|
|
4382
|
+
}
|
|
4383
|
+
};
|
|
4384
|
+
|
|
4385
|
+
// src/query-builder/relation-cte-builder.ts
|
|
4386
|
+
var RelationCteBuilder = class {
|
|
4387
|
+
constructor(table, createQueryAstService) {
|
|
4388
|
+
this.table = table;
|
|
4389
|
+
this.createQueryAstService = createQueryAstService;
|
|
4390
|
+
}
|
|
4391
|
+
createFilteredRelationCte(state, relationName, relation, predicate) {
|
|
4392
|
+
const cteName = this.generateUniqueCteName(state, relationName);
|
|
4393
|
+
if (!predicate) {
|
|
4394
|
+
throw new Error("Unable to build filter CTE without predicates.");
|
|
4395
|
+
}
|
|
4396
|
+
const columns = Object.keys(relation.target.columns).map((name) => ({
|
|
4397
|
+
type: "Column",
|
|
4398
|
+
table: relation.target.name,
|
|
4399
|
+
name
|
|
4400
|
+
}));
|
|
4401
|
+
const cteQuery = {
|
|
4402
|
+
type: "SelectQuery",
|
|
4403
|
+
from: { type: "Table", name: relation.target.name, schema: relation.target.schema },
|
|
4404
|
+
columns,
|
|
4405
|
+
joins: [],
|
|
4406
|
+
where: predicate
|
|
4407
|
+
};
|
|
4408
|
+
const nextState = this.astService(state).withCte(cteName, cteQuery);
|
|
4409
|
+
const tableNode3 = {
|
|
4410
|
+
type: "Table",
|
|
4411
|
+
name: cteName,
|
|
4412
|
+
alias: relation.target.name
|
|
4413
|
+
};
|
|
4414
|
+
return { state: nextState, table: tableNode3 };
|
|
4415
|
+
}
|
|
4416
|
+
generateUniqueCteName(state, relationName) {
|
|
4417
|
+
const existing = new Set((state.ast.ctes ?? []).map((cte) => cte.name));
|
|
4418
|
+
let candidate = `${relationName}__filtered`;
|
|
4419
|
+
let suffix = 1;
|
|
4420
|
+
while (existing.has(candidate)) {
|
|
4421
|
+
candidate = `${relationName}__filtered_${suffix}`;
|
|
4422
|
+
suffix += 1;
|
|
4423
|
+
}
|
|
4424
|
+
return candidate;
|
|
4425
|
+
}
|
|
4426
|
+
astService(state) {
|
|
4427
|
+
return this.createQueryAstService(this.table, state);
|
|
4428
|
+
}
|
|
4429
|
+
};
|
|
4430
|
+
|
|
4431
|
+
// src/query-builder/relation-include-strategies.ts
|
|
4432
|
+
var buildTypedSelection = (columns, prefix, keys, missingMsg) => {
|
|
4433
|
+
return keys.reduce((acc, key) => {
|
|
4434
|
+
const def = columns[key];
|
|
4435
|
+
if (!def) {
|
|
4436
|
+
throw new Error(missingMsg(key));
|
|
4437
|
+
}
|
|
4438
|
+
acc[makeRelationAlias(prefix, key)] = def;
|
|
4439
|
+
return acc;
|
|
4440
|
+
}, {});
|
|
4441
|
+
};
|
|
4442
|
+
var resolveTargetColumns = (relation, options) => {
|
|
4443
|
+
const requestedColumns = options?.columns?.length ? [...options.columns] : Object.keys(relation.target.columns);
|
|
4444
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
4445
|
+
if (!requestedColumns.includes(targetPrimaryKey)) {
|
|
4446
|
+
requestedColumns.push(targetPrimaryKey);
|
|
4447
|
+
}
|
|
4448
|
+
return requestedColumns;
|
|
4449
|
+
};
|
|
4450
|
+
var ensureRootForeignKeySelected = (context, relation) => {
|
|
4451
|
+
const fkColumn = context.rootTable.columns[relation.foreignKey];
|
|
4452
|
+
if (!fkColumn) {
|
|
4453
|
+
return { state: context.state, hydration: context.hydration };
|
|
4454
|
+
}
|
|
4455
|
+
const hasForeignKeySelected = context.state.ast.columns.some((col2) => {
|
|
4456
|
+
if (col2.type !== "Column") return false;
|
|
4457
|
+
const node = col2;
|
|
4458
|
+
const alias = node.alias ?? node.name;
|
|
4459
|
+
return alias === relation.foreignKey;
|
|
4460
|
+
});
|
|
4461
|
+
if (hasForeignKeySelected) {
|
|
4462
|
+
return { state: context.state, hydration: context.hydration };
|
|
4463
|
+
}
|
|
4464
|
+
return context.selectColumns(context.state, context.hydration, {
|
|
4465
|
+
[relation.foreignKey]: fkColumn
|
|
4466
|
+
});
|
|
4467
|
+
};
|
|
4468
|
+
var standardIncludeStrategy = (context) => {
|
|
4469
|
+
const relation = context.relation;
|
|
4470
|
+
let { state, hydration } = context;
|
|
4471
|
+
const fkSelectionResult = ensureRootForeignKeySelected(context, relation);
|
|
4472
|
+
state = fkSelectionResult.state;
|
|
4473
|
+
hydration = fkSelectionResult.hydration;
|
|
4474
|
+
const targetColumns = resolveTargetColumns(relation, context.options);
|
|
4475
|
+
const targetSelection = buildTypedSelection(
|
|
4476
|
+
relation.target.columns,
|
|
4477
|
+
context.aliasPrefix,
|
|
4478
|
+
targetColumns,
|
|
4479
|
+
(key) => `Column '${key}' not found on relation '${context.relationName}'`
|
|
4480
|
+
);
|
|
4481
|
+
const relationSelectionResult = context.selectColumns(state, hydration, targetSelection);
|
|
4482
|
+
state = relationSelectionResult.state;
|
|
4483
|
+
hydration = relationSelectionResult.hydration;
|
|
4484
|
+
hydration = hydration.onRelationIncluded(
|
|
4485
|
+
state,
|
|
4486
|
+
relation,
|
|
4487
|
+
context.relationName,
|
|
4488
|
+
context.aliasPrefix,
|
|
4489
|
+
targetColumns
|
|
4490
|
+
);
|
|
4491
|
+
return { state, hydration };
|
|
4492
|
+
};
|
|
4493
|
+
var belongsToManyStrategy = (context) => {
|
|
4494
|
+
const relation = context.relation;
|
|
4495
|
+
let { state, hydration } = context;
|
|
4496
|
+
const targetColumns = resolveTargetColumns(relation, context.options);
|
|
4497
|
+
const targetSelection = buildTypedSelection(
|
|
4498
|
+
relation.target.columns,
|
|
4499
|
+
context.aliasPrefix,
|
|
4500
|
+
targetColumns,
|
|
4501
|
+
(key) => `Column '${key}' not found on relation '${context.relationName}'`
|
|
4502
|
+
);
|
|
4503
|
+
const pivotAliasPrefix = context.options?.pivot?.aliasPrefix ?? `${context.aliasPrefix}_pivot`;
|
|
4504
|
+
const pivotPk = relation.pivotPrimaryKey || findPrimaryKey(relation.pivotTable);
|
|
4505
|
+
const defaultPivotColumns = relation.defaultPivotColumns ?? buildDefaultPivotColumns(relation, pivotPk);
|
|
4506
|
+
const pivotColumns = context.options?.pivot?.columns ? [...context.options.pivot.columns] : [...defaultPivotColumns];
|
|
4507
|
+
const pivotSelection = buildTypedSelection(
|
|
4508
|
+
relation.pivotTable.columns,
|
|
4509
|
+
pivotAliasPrefix,
|
|
4510
|
+
pivotColumns,
|
|
4511
|
+
(key) => `Column '${key}' not found on pivot table '${relation.pivotTable.name}'`
|
|
4512
|
+
);
|
|
4513
|
+
const combinedSelection = {
|
|
4514
|
+
...targetSelection,
|
|
4515
|
+
...pivotSelection
|
|
4516
|
+
};
|
|
4517
|
+
const relationSelectionResult = context.selectColumns(state, hydration, combinedSelection);
|
|
4518
|
+
state = relationSelectionResult.state;
|
|
4519
|
+
hydration = relationSelectionResult.hydration;
|
|
4520
|
+
hydration = hydration.onRelationIncluded(
|
|
4521
|
+
state,
|
|
4522
|
+
relation,
|
|
4523
|
+
context.relationName,
|
|
4524
|
+
context.aliasPrefix,
|
|
4525
|
+
targetColumns,
|
|
4526
|
+
{ aliasPrefix: pivotAliasPrefix, columns: pivotColumns }
|
|
4527
|
+
);
|
|
4528
|
+
return { state, hydration };
|
|
4529
|
+
};
|
|
4530
|
+
var relationIncludeStrategies = {
|
|
4531
|
+
[RelationKinds.HasMany]: standardIncludeStrategy,
|
|
4532
|
+
[RelationKinds.HasOne]: standardIncludeStrategy,
|
|
4533
|
+
[RelationKinds.BelongsTo]: standardIncludeStrategy,
|
|
4534
|
+
[RelationKinds.BelongsToMany]: belongsToManyStrategy
|
|
4535
|
+
};
|
|
4536
|
+
|
|
4537
|
+
// src/query-builder/relation-service.ts
|
|
4538
|
+
var RelationService = class {
|
|
4539
|
+
/**
|
|
4540
|
+
* Creates a new RelationService instance
|
|
4541
|
+
* @param table - Table definition
|
|
4542
|
+
* @param state - Current query state
|
|
4543
|
+
* @param hydration - Hydration manager
|
|
4544
|
+
*/
|
|
4545
|
+
constructor(table, state, hydration, createQueryAstService) {
|
|
4546
|
+
this.table = table;
|
|
4547
|
+
this.state = state;
|
|
4548
|
+
this.hydration = hydration;
|
|
4549
|
+
this.createQueryAstService = createQueryAstService;
|
|
4550
|
+
this.projectionHelper = new RelationProjectionHelper(
|
|
4551
|
+
table,
|
|
4552
|
+
(state2, hydration2, columns) => this.selectColumns(state2, hydration2, columns)
|
|
4553
|
+
);
|
|
4554
|
+
this.joinPlanner = new RelationJoinPlanner(table, createQueryAstService);
|
|
4555
|
+
this.cteBuilder = new RelationCteBuilder(table, createQueryAstService);
|
|
4556
|
+
}
|
|
4557
|
+
projectionHelper;
|
|
4558
|
+
joinPlanner;
|
|
4559
|
+
cteBuilder;
|
|
4560
|
+
/**
|
|
4561
|
+
* Joins a relation to the query
|
|
4562
|
+
* @param relationName - Name of the relation to join
|
|
4563
|
+
* @param joinKind - Type of join to use
|
|
4564
|
+
* @param extraCondition - Additional join condition
|
|
4565
|
+
* @returns Relation result with updated state and hydration
|
|
4566
|
+
*/
|
|
4567
|
+
joinRelation(relationName, joinKind, extraCondition, tableSource) {
|
|
4568
|
+
const relation = this.getRelation(relationName);
|
|
4569
|
+
const nextState = this.joinPlanner.withJoin(
|
|
4570
|
+
this.state,
|
|
4571
|
+
relationName,
|
|
4572
|
+
relation,
|
|
4573
|
+
joinKind,
|
|
4574
|
+
extraCondition,
|
|
4575
|
+
tableSource
|
|
4576
|
+
);
|
|
4577
|
+
return { state: nextState, hydration: this.hydration };
|
|
4578
|
+
}
|
|
4579
|
+
/**
|
|
4580
|
+
* Matches records based on a relation with an optional predicate
|
|
4581
|
+
* @param relationName - Name of the relation to match
|
|
4582
|
+
* @param predicate - Optional predicate expression
|
|
4583
|
+
* @returns Relation result with updated state and hydration
|
|
4584
|
+
*/
|
|
4585
|
+
match(relationName, predicate) {
|
|
4586
|
+
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
4587
|
+
const pk = findPrimaryKey(this.table);
|
|
4588
|
+
const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
|
|
4589
|
+
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
4590
|
+
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
4591
|
+
return { state: nextState, hydration: joined.hydration };
|
|
4592
|
+
}
|
|
4593
|
+
/**
|
|
4594
|
+
* Includes a relation in the query result
|
|
4595
|
+
* @param relationName - Name of the relation to include
|
|
4596
|
+
* @param options - Options for relation inclusion
|
|
4597
|
+
* @returns Relation result with updated state and hydration
|
|
4598
|
+
*/
|
|
4599
|
+
include(relationName, options) {
|
|
4600
|
+
let state = this.state;
|
|
4601
|
+
let hydration = this.hydration;
|
|
4602
|
+
const relation = this.getRelation(relationName);
|
|
4603
|
+
const aliasPrefix = options?.aliasPrefix ?? relationName;
|
|
4604
|
+
const alreadyJoined = state.ast.joins.some((j) => getJoinRelationName(j) === relationName);
|
|
4605
|
+
const { selfFilters, crossFilters } = splitFilterExpressions(
|
|
4606
|
+
options?.filter,
|
|
4607
|
+
/* @__PURE__ */ new Set([relation.target.name])
|
|
4608
|
+
);
|
|
4609
|
+
const canUseCte = !alreadyJoined && selfFilters.length > 0;
|
|
4610
|
+
const joinFilters = [...crossFilters];
|
|
4611
|
+
if (!canUseCte) {
|
|
4612
|
+
joinFilters.push(...selfFilters);
|
|
4613
|
+
}
|
|
4614
|
+
const joinCondition = this.combineWithAnd(joinFilters);
|
|
4615
|
+
let tableSourceOverride;
|
|
4616
|
+
if (canUseCte) {
|
|
4617
|
+
const predicate = this.combineWithAnd(selfFilters);
|
|
4618
|
+
const cteInfo = this.cteBuilder.createFilteredRelationCte(
|
|
4619
|
+
state,
|
|
4620
|
+
relationName,
|
|
4260
4621
|
relation,
|
|
4622
|
+
predicate
|
|
4623
|
+
);
|
|
4624
|
+
state = cteInfo.state;
|
|
4625
|
+
tableSourceOverride = cteInfo.table;
|
|
4626
|
+
}
|
|
4627
|
+
if (!alreadyJoined) {
|
|
4628
|
+
state = this.joinPlanner.withJoin(
|
|
4629
|
+
state,
|
|
4261
4630
|
relationName,
|
|
4262
|
-
|
|
4263
|
-
|
|
4631
|
+
relation,
|
|
4632
|
+
options?.joinKind ?? JOIN_KINDS.LEFT,
|
|
4633
|
+
joinCondition,
|
|
4634
|
+
tableSourceOverride
|
|
4264
4635
|
);
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
const
|
|
4270
|
-
const
|
|
4271
|
-
|
|
4272
|
-
many.pivotTable.columns,
|
|
4273
|
-
pivotAliasPrefix,
|
|
4274
|
-
pivotColumns,
|
|
4275
|
-
(key) => `Column '${key}' not found on pivot table '${many.pivotTable.name}'`
|
|
4276
|
-
);
|
|
4277
|
-
const combinedSelection = {
|
|
4278
|
-
...targetSelection,
|
|
4279
|
-
...pivotSelection
|
|
4280
|
-
};
|
|
4281
|
-
const relationSelectionResult = this.selectColumns(state, hydration, combinedSelection);
|
|
4282
|
-
state = relationSelectionResult.state;
|
|
4283
|
-
hydration = relationSelectionResult.hydration;
|
|
4284
|
-
hydration = hydration.onRelationIncluded(
|
|
4636
|
+
}
|
|
4637
|
+
const projectionResult = this.projectionHelper.ensureBaseProjection(state, hydration);
|
|
4638
|
+
state = projectionResult.state;
|
|
4639
|
+
hydration = projectionResult.hydration;
|
|
4640
|
+
const strategy = relationIncludeStrategies[relation.type];
|
|
4641
|
+
const result = strategy({
|
|
4642
|
+
rootTable: this.table,
|
|
4285
4643
|
state,
|
|
4644
|
+
hydration,
|
|
4286
4645
|
relation,
|
|
4287
4646
|
relationName,
|
|
4288
4647
|
aliasPrefix,
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
);
|
|
4292
|
-
return { state, hydration };
|
|
4648
|
+
options,
|
|
4649
|
+
selectColumns: (nextState, nextHydration, columns) => this.selectColumns(nextState, nextHydration, columns)
|
|
4650
|
+
});
|
|
4651
|
+
return { state: result.state, hydration: result.hydration };
|
|
4293
4652
|
}
|
|
4294
4653
|
/**
|
|
4295
4654
|
* Applies relation correlation to a query AST
|
|
@@ -4310,37 +4669,6 @@ var RelationService = class {
|
|
|
4310
4669
|
where: whereInSubquery
|
|
4311
4670
|
};
|
|
4312
4671
|
}
|
|
4313
|
-
/**
|
|
4314
|
-
* Creates a join node for a relation
|
|
4315
|
-
* @param state - Current query state
|
|
4316
|
-
* @param relationName - Name of the relation
|
|
4317
|
-
* @param joinKind - Type of join to use
|
|
4318
|
-
* @param extraCondition - Additional join condition
|
|
4319
|
-
* @returns Updated query state with join
|
|
4320
|
-
*/
|
|
4321
|
-
withJoin(state, relationName, joinKind, extraCondition) {
|
|
4322
|
-
const relation = this.getRelation(relationName);
|
|
4323
|
-
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
4324
|
-
if (relation.type === RelationKinds.BelongsToMany) {
|
|
4325
|
-
const joins = buildBelongsToManyJoins(
|
|
4326
|
-
this.table,
|
|
4327
|
-
relationName,
|
|
4328
|
-
relation,
|
|
4329
|
-
joinKind,
|
|
4330
|
-
extraCondition,
|
|
4331
|
-
rootAlias
|
|
4332
|
-
);
|
|
4333
|
-
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
4334
|
-
}
|
|
4335
|
-
const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
|
|
4336
|
-
const joinNode = createJoinNode(
|
|
4337
|
-
joinKind,
|
|
4338
|
-
{ type: "Table", name: relation.target.name, schema: relation.target.schema },
|
|
4339
|
-
condition,
|
|
4340
|
-
relationName
|
|
4341
|
-
);
|
|
4342
|
-
return this.astService(state).withJoin(joinNode);
|
|
4343
|
-
}
|
|
4344
4672
|
/**
|
|
4345
4673
|
* Selects columns for a relation
|
|
4346
4674
|
* @param state - Current query state
|
|
@@ -4355,6 +4683,15 @@ var RelationService = class {
|
|
|
4355
4683
|
hydration: hydration.onColumnsSelected(nextState, addedColumns)
|
|
4356
4684
|
};
|
|
4357
4685
|
}
|
|
4686
|
+
combineWithAnd(expressions) {
|
|
4687
|
+
if (expressions.length === 0) return void 0;
|
|
4688
|
+
if (expressions.length === 1) return expressions[0];
|
|
4689
|
+
return {
|
|
4690
|
+
type: "LogicalExpression",
|
|
4691
|
+
operator: "AND",
|
|
4692
|
+
operands: expressions
|
|
4693
|
+
};
|
|
4694
|
+
}
|
|
4358
4695
|
/**
|
|
4359
4696
|
* Gets a relation definition by name
|
|
4360
4697
|
* @param relationName - Name of the relation
|
|
@@ -4643,8 +4980,52 @@ var hasEntityMeta = (entity) => {
|
|
|
4643
4980
|
return Boolean(getEntityMeta(entity));
|
|
4644
4981
|
};
|
|
4645
4982
|
|
|
4646
|
-
// src/orm/
|
|
4983
|
+
// src/orm/entity-hydration.ts
|
|
4647
4984
|
var toKey2 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4985
|
+
var populateHydrationCache = (entity, row, meta) => {
|
|
4986
|
+
for (const relationName of Object.keys(meta.table.relations)) {
|
|
4987
|
+
const relation = meta.table.relations[relationName];
|
|
4988
|
+
const data = row[relationName];
|
|
4989
|
+
if (relation.type === RelationKinds.HasOne) {
|
|
4990
|
+
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
4991
|
+
const rootValue = entity[localKey];
|
|
4992
|
+
if (rootValue === void 0 || rootValue === null) continue;
|
|
4993
|
+
if (!data || typeof data !== "object") continue;
|
|
4994
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4995
|
+
cache.set(toKey2(rootValue), data);
|
|
4996
|
+
meta.relationHydration.set(relationName, cache);
|
|
4997
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
4998
|
+
continue;
|
|
4999
|
+
}
|
|
5000
|
+
if (!Array.isArray(data)) continue;
|
|
5001
|
+
if (relation.type === RelationKinds.HasMany || relation.type === RelationKinds.BelongsToMany) {
|
|
5002
|
+
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
5003
|
+
const rootValue = entity[localKey];
|
|
5004
|
+
if (rootValue === void 0 || rootValue === null) continue;
|
|
5005
|
+
const cache = /* @__PURE__ */ new Map();
|
|
5006
|
+
cache.set(toKey2(rootValue), data);
|
|
5007
|
+
meta.relationHydration.set(relationName, cache);
|
|
5008
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5009
|
+
continue;
|
|
5010
|
+
}
|
|
5011
|
+
if (relation.type === RelationKinds.BelongsTo) {
|
|
5012
|
+
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
5013
|
+
const cache = /* @__PURE__ */ new Map();
|
|
5014
|
+
for (const item of data) {
|
|
5015
|
+
const pkValue = item[targetKey];
|
|
5016
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
5017
|
+
cache.set(toKey2(pkValue), item);
|
|
5018
|
+
}
|
|
5019
|
+
if (cache.size) {
|
|
5020
|
+
meta.relationHydration.set(relationName, cache);
|
|
5021
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5022
|
+
}
|
|
5023
|
+
}
|
|
5024
|
+
}
|
|
5025
|
+
};
|
|
5026
|
+
|
|
5027
|
+
// src/orm/relations/has-many.ts
|
|
5028
|
+
var toKey3 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4648
5029
|
var hideInternal = (obj, keys) => {
|
|
4649
5030
|
for (const key of keys) {
|
|
4650
5031
|
Object.defineProperty(obj, key, {
|
|
@@ -4678,13 +5059,13 @@ var DefaultHasManyCollection = class {
|
|
|
4678
5059
|
this.loader = loader;
|
|
4679
5060
|
this.createEntity = createEntity;
|
|
4680
5061
|
this.localKey = localKey;
|
|
4681
|
-
this.loaded = false;
|
|
4682
|
-
this.items = [];
|
|
4683
|
-
this.added = /* @__PURE__ */ new Set();
|
|
4684
|
-
this.removed = /* @__PURE__ */ new Set();
|
|
4685
5062
|
hideInternal(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
4686
5063
|
this.hydrateFromCache();
|
|
4687
5064
|
}
|
|
5065
|
+
loaded = false;
|
|
5066
|
+
items = [];
|
|
5067
|
+
added = /* @__PURE__ */ new Set();
|
|
5068
|
+
removed = /* @__PURE__ */ new Set();
|
|
4688
5069
|
/**
|
|
4689
5070
|
* Loads the related entities if not already loaded.
|
|
4690
5071
|
* @returns Promise resolving to the array of child entities
|
|
@@ -4692,7 +5073,7 @@ var DefaultHasManyCollection = class {
|
|
|
4692
5073
|
async load() {
|
|
4693
5074
|
if (this.loaded) return this.items;
|
|
4694
5075
|
const map = await this.loader();
|
|
4695
|
-
const key =
|
|
5076
|
+
const key = toKey3(this.root[this.localKey]);
|
|
4696
5077
|
const rows = map.get(key) ?? [];
|
|
4697
5078
|
this.items = rows.map((row) => this.createEntity(row));
|
|
4698
5079
|
this.loaded = true;
|
|
@@ -4705,6 +5086,18 @@ var DefaultHasManyCollection = class {
|
|
|
4705
5086
|
getItems() {
|
|
4706
5087
|
return this.items;
|
|
4707
5088
|
}
|
|
5089
|
+
/**
|
|
5090
|
+
* Array-compatible length for testing frameworks.
|
|
5091
|
+
*/
|
|
5092
|
+
get length() {
|
|
5093
|
+
return this.items.length;
|
|
5094
|
+
}
|
|
5095
|
+
/**
|
|
5096
|
+
* Enables iteration over the collection like an array.
|
|
5097
|
+
*/
|
|
5098
|
+
[Symbol.iterator]() {
|
|
5099
|
+
return this.items[Symbol.iterator]();
|
|
5100
|
+
}
|
|
4708
5101
|
/**
|
|
4709
5102
|
* Adds a new child entity to the collection.
|
|
4710
5103
|
* @param data - Partial data for the new entity
|
|
@@ -4792,7 +5185,7 @@ var DefaultHasManyCollection = class {
|
|
|
4792
5185
|
};
|
|
4793
5186
|
|
|
4794
5187
|
// src/orm/relations/has-one.ts
|
|
4795
|
-
var
|
|
5188
|
+
var toKey4 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4796
5189
|
var hideInternal2 = (obj, keys) => {
|
|
4797
5190
|
for (const key of keys) {
|
|
4798
5191
|
Object.defineProperty(obj, key, {
|
|
@@ -4825,8 +5218,6 @@ var DefaultHasOneReference = class {
|
|
|
4825
5218
|
this.loader = loader;
|
|
4826
5219
|
this.createEntity = createEntity;
|
|
4827
5220
|
this.localKey = localKey;
|
|
4828
|
-
this.loaded = false;
|
|
4829
|
-
this.current = null;
|
|
4830
5221
|
hideInternal2(this, [
|
|
4831
5222
|
"ctx",
|
|
4832
5223
|
"meta",
|
|
@@ -4840,6 +5231,8 @@ var DefaultHasOneReference = class {
|
|
|
4840
5231
|
]);
|
|
4841
5232
|
this.populateFromHydrationCache();
|
|
4842
5233
|
}
|
|
5234
|
+
loaded = false;
|
|
5235
|
+
current = null;
|
|
4843
5236
|
async load() {
|
|
4844
5237
|
if (this.loaded) return this.current;
|
|
4845
5238
|
const map = await this.loader();
|
|
@@ -4848,7 +5241,7 @@ var DefaultHasOneReference = class {
|
|
|
4848
5241
|
this.loaded = true;
|
|
4849
5242
|
return this.current;
|
|
4850
5243
|
}
|
|
4851
|
-
const row = map.get(
|
|
5244
|
+
const row = map.get(toKey4(keyValue));
|
|
4852
5245
|
this.current = row ? this.createEntity(row) : null;
|
|
4853
5246
|
this.loaded = true;
|
|
4854
5247
|
return this.current;
|
|
@@ -4920,7 +5313,7 @@ var DefaultHasOneReference = class {
|
|
|
4920
5313
|
};
|
|
4921
5314
|
|
|
4922
5315
|
// src/orm/relations/belongs-to.ts
|
|
4923
|
-
var
|
|
5316
|
+
var toKey5 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
4924
5317
|
var hideInternal3 = (obj, keys) => {
|
|
4925
5318
|
for (const key of keys) {
|
|
4926
5319
|
Object.defineProperty(obj, key, {
|
|
@@ -4953,11 +5346,11 @@ var DefaultBelongsToReference = class {
|
|
|
4953
5346
|
this.loader = loader;
|
|
4954
5347
|
this.createEntity = createEntity;
|
|
4955
5348
|
this.targetKey = targetKey;
|
|
4956
|
-
this.loaded = false;
|
|
4957
|
-
this.current = null;
|
|
4958
5349
|
hideInternal3(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "targetKey"]);
|
|
4959
5350
|
this.populateFromHydrationCache();
|
|
4960
5351
|
}
|
|
5352
|
+
loaded = false;
|
|
5353
|
+
current = null;
|
|
4961
5354
|
async load() {
|
|
4962
5355
|
if (this.loaded) return this.current;
|
|
4963
5356
|
const map = await this.loader();
|
|
@@ -4965,7 +5358,7 @@ var DefaultBelongsToReference = class {
|
|
|
4965
5358
|
if (fkValue === null || fkValue === void 0) {
|
|
4966
5359
|
this.current = null;
|
|
4967
5360
|
} else {
|
|
4968
|
-
const row = map.get(
|
|
5361
|
+
const row = map.get(toKey5(fkValue));
|
|
4969
5362
|
this.current = row ? this.createEntity(row) : null;
|
|
4970
5363
|
}
|
|
4971
5364
|
this.loaded = true;
|
|
@@ -5022,7 +5415,7 @@ var DefaultBelongsToReference = class {
|
|
|
5022
5415
|
};
|
|
5023
5416
|
|
|
5024
5417
|
// src/orm/relations/many-to-many.ts
|
|
5025
|
-
var
|
|
5418
|
+
var toKey6 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
5026
5419
|
var hideInternal4 = (obj, keys) => {
|
|
5027
5420
|
for (const key of keys) {
|
|
5028
5421
|
Object.defineProperty(obj, key, {
|
|
@@ -5055,11 +5448,11 @@ var DefaultManyToManyCollection = class {
|
|
|
5055
5448
|
this.loader = loader;
|
|
5056
5449
|
this.createEntity = createEntity;
|
|
5057
5450
|
this.localKey = localKey;
|
|
5058
|
-
this.loaded = false;
|
|
5059
|
-
this.items = [];
|
|
5060
5451
|
hideInternal4(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
5061
5452
|
this.hydrateFromCache();
|
|
5062
5453
|
}
|
|
5454
|
+
loaded = false;
|
|
5455
|
+
items = [];
|
|
5063
5456
|
/**
|
|
5064
5457
|
* Loads the collection items if not already loaded.
|
|
5065
5458
|
* @returns A promise that resolves to the array of target entities.
|
|
@@ -5067,7 +5460,7 @@ var DefaultManyToManyCollection = class {
|
|
|
5067
5460
|
async load() {
|
|
5068
5461
|
if (this.loaded) return this.items;
|
|
5069
5462
|
const map = await this.loader();
|
|
5070
|
-
const key =
|
|
5463
|
+
const key = toKey6(this.root[this.localKey]);
|
|
5071
5464
|
const rows = map.get(key) ?? [];
|
|
5072
5465
|
this.items = rows.map((row) => {
|
|
5073
5466
|
const entity = this.createEntity(row);
|
|
@@ -5086,6 +5479,18 @@ var DefaultManyToManyCollection = class {
|
|
|
5086
5479
|
getItems() {
|
|
5087
5480
|
return this.items;
|
|
5088
5481
|
}
|
|
5482
|
+
/**
|
|
5483
|
+
* Array-compatible length for testing frameworks.
|
|
5484
|
+
*/
|
|
5485
|
+
get length() {
|
|
5486
|
+
return this.items.length;
|
|
5487
|
+
}
|
|
5488
|
+
/**
|
|
5489
|
+
* Enables iteration over the collection like an array.
|
|
5490
|
+
*/
|
|
5491
|
+
[Symbol.iterator]() {
|
|
5492
|
+
return this.items[Symbol.iterator]();
|
|
5493
|
+
}
|
|
5089
5494
|
/**
|
|
5090
5495
|
* Attaches an entity to the collection.
|
|
5091
5496
|
* Registers an 'attach' change in the entity context.
|
|
@@ -5137,15 +5542,15 @@ var DefaultManyToManyCollection = class {
|
|
|
5137
5542
|
*/
|
|
5138
5543
|
async syncByIds(ids) {
|
|
5139
5544
|
await this.load();
|
|
5140
|
-
const normalized = new Set(ids.map((id) =>
|
|
5141
|
-
const currentIds = new Set(this.items.map((item) =>
|
|
5545
|
+
const normalized = new Set(ids.map((id) => toKey6(id)));
|
|
5546
|
+
const currentIds = new Set(this.items.map((item) => toKey6(this.extractId(item))));
|
|
5142
5547
|
for (const id of normalized) {
|
|
5143
5548
|
if (!currentIds.has(id)) {
|
|
5144
5549
|
this.attach(id);
|
|
5145
5550
|
}
|
|
5146
5551
|
}
|
|
5147
5552
|
for (const item of [...this.items]) {
|
|
5148
|
-
const itemId =
|
|
5553
|
+
const itemId = toKey6(this.extractId(item));
|
|
5149
5554
|
if (!normalized.has(itemId)) {
|
|
5150
5555
|
this.detach(item);
|
|
5151
5556
|
}
|
|
@@ -5192,11 +5597,28 @@ var DefaultManyToManyCollection = class {
|
|
|
5192
5597
|
}
|
|
5193
5598
|
};
|
|
5194
5599
|
|
|
5195
|
-
// src/orm/lazy-batch.ts
|
|
5196
|
-
var
|
|
5197
|
-
|
|
5198
|
-
return acc
|
|
5199
|
-
|
|
5600
|
+
// src/orm/lazy-batch/shared.ts
|
|
5601
|
+
var hasColumns = (columns) => Boolean(columns && columns.length > 0);
|
|
5602
|
+
var buildColumnSelection = (table, columns, missingMsg) => {
|
|
5603
|
+
return columns.reduce((acc, column) => {
|
|
5604
|
+
const def = table.columns[column];
|
|
5605
|
+
if (!def) {
|
|
5606
|
+
throw new Error(missingMsg(column));
|
|
5607
|
+
}
|
|
5608
|
+
acc[column] = def;
|
|
5609
|
+
return acc;
|
|
5610
|
+
}, {});
|
|
5611
|
+
};
|
|
5612
|
+
var filterRow = (row, columns) => {
|
|
5613
|
+
const filtered = {};
|
|
5614
|
+
for (const column of columns) {
|
|
5615
|
+
if (column in row) {
|
|
5616
|
+
filtered[column] = row[column];
|
|
5617
|
+
}
|
|
5618
|
+
}
|
|
5619
|
+
return filtered;
|
|
5620
|
+
};
|
|
5621
|
+
var filterRows = (rows, columns) => rows.map((row) => filterRow(row, columns));
|
|
5200
5622
|
var rowsFromResults = (results) => {
|
|
5201
5623
|
const rows = [];
|
|
5202
5624
|
for (const result of results) {
|
|
@@ -5216,7 +5638,7 @@ var executeQuery = async (ctx, qb) => {
|
|
|
5216
5638
|
const results = await ctx.executor.executeSql(compiled.sql, compiled.params);
|
|
5217
5639
|
return rowsFromResults(results);
|
|
5218
5640
|
};
|
|
5219
|
-
var
|
|
5641
|
+
var toKey7 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
5220
5642
|
var collectKeysFromRoots = (roots, key) => {
|
|
5221
5643
|
const collected = /* @__PURE__ */ new Set();
|
|
5222
5644
|
for (const tracked of roots) {
|
|
@@ -5228,9 +5650,12 @@ var collectKeysFromRoots = (roots, key) => {
|
|
|
5228
5650
|
return collected;
|
|
5229
5651
|
};
|
|
5230
5652
|
var buildInListValues = (keys) => Array.from(keys);
|
|
5231
|
-
var fetchRowsForKeys = async (ctx, table, column, keys) => {
|
|
5232
|
-
|
|
5233
|
-
qb.where(inList(column, buildInListValues(keys)));
|
|
5653
|
+
var fetchRowsForKeys = async (ctx, table, column, keys, selection, filter) => {
|
|
5654
|
+
let qb = new SelectQueryBuilder(table).select(selection);
|
|
5655
|
+
qb = qb.where(inList(column, buildInListValues(keys)));
|
|
5656
|
+
if (filter) {
|
|
5657
|
+
qb = qb.where(filter);
|
|
5658
|
+
}
|
|
5234
5659
|
return executeQuery(ctx, qb);
|
|
5235
5660
|
};
|
|
5236
5661
|
var groupRowsByMany = (rows, keyColumn) => {
|
|
@@ -5238,7 +5663,7 @@ var groupRowsByMany = (rows, keyColumn) => {
|
|
|
5238
5663
|
for (const row of rows) {
|
|
5239
5664
|
const value = row[keyColumn];
|
|
5240
5665
|
if (value === null || value === void 0) continue;
|
|
5241
|
-
const key =
|
|
5666
|
+
const key = toKey7(value);
|
|
5242
5667
|
const bucket = grouped.get(key) ?? [];
|
|
5243
5668
|
bucket.push(row);
|
|
5244
5669
|
grouped.set(key, bucket);
|
|
@@ -5250,14 +5675,16 @@ var groupRowsByUnique = (rows, keyColumn) => {
|
|
|
5250
5675
|
for (const row of rows) {
|
|
5251
5676
|
const value = row[keyColumn];
|
|
5252
5677
|
if (value === null || value === void 0) continue;
|
|
5253
|
-
const key =
|
|
5678
|
+
const key = toKey7(value);
|
|
5254
5679
|
if (!lookup.has(key)) {
|
|
5255
5680
|
lookup.set(key, row);
|
|
5256
5681
|
}
|
|
5257
5682
|
}
|
|
5258
5683
|
return lookup;
|
|
5259
5684
|
};
|
|
5260
|
-
|
|
5685
|
+
|
|
5686
|
+
// src/orm/lazy-batch/has-many.ts
|
|
5687
|
+
var loadHasManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5261
5688
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5262
5689
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5263
5690
|
const keys = collectKeysFromRoots(roots, localKey);
|
|
@@ -5266,10 +5693,32 @@ var loadHasManyRelation = async (ctx, rootTable, _relationName, relation) => {
|
|
|
5266
5693
|
}
|
|
5267
5694
|
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
5268
5695
|
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
5269
|
-
const
|
|
5270
|
-
|
|
5696
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5697
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
5698
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5699
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
5700
|
+
selectedColumns.push(targetPrimaryKey);
|
|
5701
|
+
}
|
|
5702
|
+
const queryColumns = new Set(selectedColumns);
|
|
5703
|
+
queryColumns.add(relation.foreignKey);
|
|
5704
|
+
const selection = buildColumnSelection(
|
|
5705
|
+
relation.target,
|
|
5706
|
+
Array.from(queryColumns),
|
|
5707
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5708
|
+
);
|
|
5709
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
|
|
5710
|
+
const grouped = groupRowsByMany(rows, relation.foreignKey);
|
|
5711
|
+
if (!requestedColumns) return grouped;
|
|
5712
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5713
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5714
|
+
for (const [key, bucket] of grouped.entries()) {
|
|
5715
|
+
filtered.set(key, filterRows(bucket, visibleColumns));
|
|
5716
|
+
}
|
|
5717
|
+
return filtered;
|
|
5271
5718
|
};
|
|
5272
|
-
|
|
5719
|
+
|
|
5720
|
+
// src/orm/lazy-batch/has-one.ts
|
|
5721
|
+
var loadHasOneRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5273
5722
|
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5274
5723
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5275
5724
|
const keys = collectKeysFromRoots(roots, localKey);
|
|
@@ -5278,22 +5727,102 @@ var loadHasOneRelation = async (ctx, rootTable, _relationName, relation) => {
|
|
|
5278
5727
|
}
|
|
5279
5728
|
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
5280
5729
|
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
5281
|
-
const
|
|
5282
|
-
|
|
5730
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5731
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
5732
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5733
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
5734
|
+
selectedColumns.push(targetPrimaryKey);
|
|
5735
|
+
}
|
|
5736
|
+
const queryColumns = new Set(selectedColumns);
|
|
5737
|
+
queryColumns.add(relation.foreignKey);
|
|
5738
|
+
const selection = buildColumnSelection(
|
|
5739
|
+
relation.target,
|
|
5740
|
+
Array.from(queryColumns),
|
|
5741
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5742
|
+
);
|
|
5743
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
|
|
5744
|
+
const grouped = groupRowsByUnique(rows, relation.foreignKey);
|
|
5745
|
+
if (!requestedColumns) return grouped;
|
|
5746
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5747
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5748
|
+
for (const [key, row] of grouped.entries()) {
|
|
5749
|
+
filtered.set(key, filterRow(row, visibleColumns));
|
|
5750
|
+
}
|
|
5751
|
+
return filtered;
|
|
5283
5752
|
};
|
|
5284
|
-
|
|
5753
|
+
|
|
5754
|
+
// src/orm/lazy-batch/belongs-to.ts
|
|
5755
|
+
var loadBelongsToRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5285
5756
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5286
|
-
const
|
|
5757
|
+
const getForeignKeys = () => collectKeysFromRoots(roots, relation.foreignKey);
|
|
5758
|
+
let foreignKeys = getForeignKeys();
|
|
5759
|
+
if (!foreignKeys.size) {
|
|
5760
|
+
const pkName = findPrimaryKey(rootTable);
|
|
5761
|
+
const pkColumn2 = rootTable.columns[pkName];
|
|
5762
|
+
const fkColumn = rootTable.columns[relation.foreignKey];
|
|
5763
|
+
if (pkColumn2 && fkColumn) {
|
|
5764
|
+
const missingKeys = /* @__PURE__ */ new Set();
|
|
5765
|
+
const entityByPk = /* @__PURE__ */ new Map();
|
|
5766
|
+
for (const tracked of roots) {
|
|
5767
|
+
const entity = tracked.entity;
|
|
5768
|
+
const pkValue = entity[pkName];
|
|
5769
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
5770
|
+
const fkValue = entity[relation.foreignKey];
|
|
5771
|
+
if (fkValue === void 0 || fkValue === null) {
|
|
5772
|
+
missingKeys.add(pkValue);
|
|
5773
|
+
entityByPk.set(pkValue, entity);
|
|
5774
|
+
}
|
|
5775
|
+
}
|
|
5776
|
+
if (missingKeys.size) {
|
|
5777
|
+
const selection2 = buildColumnSelection(
|
|
5778
|
+
rootTable,
|
|
5779
|
+
[pkName, relation.foreignKey],
|
|
5780
|
+
(column) => `Column '${column}' not found on table '${rootTable.name}'`
|
|
5781
|
+
);
|
|
5782
|
+
const keyRows = await fetchRowsForKeys(ctx, rootTable, pkColumn2, missingKeys, selection2);
|
|
5783
|
+
for (const row of keyRows) {
|
|
5784
|
+
const pkValue = row[pkName];
|
|
5785
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
5786
|
+
const entity = entityByPk.get(pkValue);
|
|
5787
|
+
if (!entity) continue;
|
|
5788
|
+
const fkValue = row[relation.foreignKey];
|
|
5789
|
+
if (fkValue !== void 0 && fkValue !== null) {
|
|
5790
|
+
entity[relation.foreignKey] = fkValue;
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5793
|
+
foreignKeys = getForeignKeys();
|
|
5794
|
+
}
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5287
5797
|
if (!foreignKeys.size) {
|
|
5288
5798
|
return /* @__PURE__ */ new Map();
|
|
5289
5799
|
}
|
|
5290
5800
|
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
5291
5801
|
const pkColumn = relation.target.columns[targetKey];
|
|
5292
5802
|
if (!pkColumn) return /* @__PURE__ */ new Map();
|
|
5293
|
-
const
|
|
5294
|
-
|
|
5803
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5804
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
5805
|
+
if (!selectedColumns.includes(targetKey)) {
|
|
5806
|
+
selectedColumns.push(targetKey);
|
|
5807
|
+
}
|
|
5808
|
+
const selection = buildColumnSelection(
|
|
5809
|
+
relation.target,
|
|
5810
|
+
selectedColumns,
|
|
5811
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5812
|
+
);
|
|
5813
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, pkColumn, foreignKeys, selection, options?.filter);
|
|
5814
|
+
const grouped = groupRowsByUnique(rows, targetKey);
|
|
5815
|
+
if (!requestedColumns) return grouped;
|
|
5816
|
+
const visibleColumns = new Set(selectedColumns);
|
|
5817
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
5818
|
+
for (const [key, row] of grouped.entries()) {
|
|
5819
|
+
filtered.set(key, filterRow(row, visibleColumns));
|
|
5820
|
+
}
|
|
5821
|
+
return filtered;
|
|
5295
5822
|
};
|
|
5296
|
-
|
|
5823
|
+
|
|
5824
|
+
// src/orm/lazy-batch/belongs-to-many.ts
|
|
5825
|
+
var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
5297
5826
|
const rootKey = relation.localKey || findPrimaryKey(rootTable);
|
|
5298
5827
|
const roots = ctx.getEntitiesForTable(rootTable);
|
|
5299
5828
|
const rootIds = collectKeysFromRoots(roots, rootKey);
|
|
@@ -5302,21 +5831,41 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
5302
5831
|
}
|
|
5303
5832
|
const pivotColumn = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
5304
5833
|
if (!pivotColumn) return /* @__PURE__ */ new Map();
|
|
5305
|
-
const
|
|
5834
|
+
const pivotColumnsRequested = hasColumns(options?.pivot?.columns) ? [...options.pivot.columns] : void 0;
|
|
5835
|
+
const useIncludeDefaults = options !== void 0;
|
|
5836
|
+
let pivotSelectedColumns;
|
|
5837
|
+
if (pivotColumnsRequested) {
|
|
5838
|
+
pivotSelectedColumns = [...pivotColumnsRequested];
|
|
5839
|
+
} else if (useIncludeDefaults) {
|
|
5840
|
+
const pivotPk = relation.pivotPrimaryKey || findPrimaryKey(relation.pivotTable);
|
|
5841
|
+
pivotSelectedColumns = relation.defaultPivotColumns ?? buildDefaultPivotColumns(relation, pivotPk);
|
|
5842
|
+
} else {
|
|
5843
|
+
pivotSelectedColumns = Object.keys(relation.pivotTable.columns);
|
|
5844
|
+
}
|
|
5845
|
+
const pivotQueryColumns = new Set(pivotSelectedColumns);
|
|
5846
|
+
pivotQueryColumns.add(relation.pivotForeignKeyToRoot);
|
|
5847
|
+
pivotQueryColumns.add(relation.pivotForeignKeyToTarget);
|
|
5848
|
+
const pivotSelection = buildColumnSelection(
|
|
5849
|
+
relation.pivotTable,
|
|
5850
|
+
Array.from(pivotQueryColumns),
|
|
5851
|
+
(column) => `Column '${column}' not found on pivot table '${relation.pivotTable.name}'`
|
|
5852
|
+
);
|
|
5853
|
+
const pivotRows = await fetchRowsForKeys(ctx, relation.pivotTable, pivotColumn, rootIds, pivotSelection);
|
|
5306
5854
|
const rootLookup = /* @__PURE__ */ new Map();
|
|
5307
5855
|
const targetIds = /* @__PURE__ */ new Set();
|
|
5856
|
+
const pivotVisibleColumns = new Set(pivotSelectedColumns);
|
|
5308
5857
|
for (const pivot of pivotRows) {
|
|
5309
5858
|
const rootValue = pivot[relation.pivotForeignKeyToRoot];
|
|
5310
5859
|
const targetValue = pivot[relation.pivotForeignKeyToTarget];
|
|
5311
5860
|
if (rootValue === null || rootValue === void 0 || targetValue === null || targetValue === void 0) {
|
|
5312
5861
|
continue;
|
|
5313
5862
|
}
|
|
5314
|
-
const bucket = rootLookup.get(
|
|
5863
|
+
const bucket = rootLookup.get(toKey7(rootValue)) ?? [];
|
|
5315
5864
|
bucket.push({
|
|
5316
5865
|
targetId: targetValue,
|
|
5317
|
-
pivot:
|
|
5866
|
+
pivot: pivotVisibleColumns.size ? filterRow(pivot, pivotVisibleColumns) : {}
|
|
5318
5867
|
});
|
|
5319
|
-
rootLookup.set(
|
|
5868
|
+
rootLookup.set(toKey7(rootValue), bucket);
|
|
5320
5869
|
targetIds.add(targetValue);
|
|
5321
5870
|
}
|
|
5322
5871
|
if (!targetIds.size) {
|
|
@@ -5325,16 +5874,34 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
5325
5874
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
5326
5875
|
const targetPkColumn = relation.target.columns[targetKey];
|
|
5327
5876
|
if (!targetPkColumn) return /* @__PURE__ */ new Map();
|
|
5328
|
-
const
|
|
5877
|
+
const targetRequestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
5878
|
+
const targetSelectedColumns = targetRequestedColumns ? [...targetRequestedColumns] : Object.keys(relation.target.columns);
|
|
5879
|
+
if (!targetSelectedColumns.includes(targetKey)) {
|
|
5880
|
+
targetSelectedColumns.push(targetKey);
|
|
5881
|
+
}
|
|
5882
|
+
const targetSelection = buildColumnSelection(
|
|
5883
|
+
relation.target,
|
|
5884
|
+
targetSelectedColumns,
|
|
5885
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
5886
|
+
);
|
|
5887
|
+
const targetRows = await fetchRowsForKeys(
|
|
5888
|
+
ctx,
|
|
5889
|
+
relation.target,
|
|
5890
|
+
targetPkColumn,
|
|
5891
|
+
targetIds,
|
|
5892
|
+
targetSelection,
|
|
5893
|
+
options?.filter
|
|
5894
|
+
);
|
|
5329
5895
|
const targetMap = groupRowsByUnique(targetRows, targetKey);
|
|
5896
|
+
const targetVisibleColumns = new Set(targetSelectedColumns);
|
|
5330
5897
|
const result = /* @__PURE__ */ new Map();
|
|
5331
5898
|
for (const [rootId, entries] of rootLookup.entries()) {
|
|
5332
5899
|
const bucket = [];
|
|
5333
5900
|
for (const entry of entries) {
|
|
5334
|
-
const targetRow = targetMap.get(
|
|
5901
|
+
const targetRow = targetMap.get(toKey7(entry.targetId));
|
|
5335
5902
|
if (!targetRow) continue;
|
|
5336
5903
|
bucket.push({
|
|
5337
|
-
...targetRow,
|
|
5904
|
+
...targetRequestedColumns ? filterRow(targetRow, targetVisibleColumns) : targetRow,
|
|
5338
5905
|
_pivot: entry.pivot
|
|
5339
5906
|
});
|
|
5340
5907
|
}
|
|
@@ -5343,7 +5910,7 @@ var loadBelongsToManyRelation = async (ctx, rootTable, _relationName, relation)
|
|
|
5343
5910
|
return result;
|
|
5344
5911
|
};
|
|
5345
5912
|
|
|
5346
|
-
// src/orm/entity.ts
|
|
5913
|
+
// src/orm/entity-relation-cache.ts
|
|
5347
5914
|
var relationLoaderCache = (meta, relationName, factory) => {
|
|
5348
5915
|
if (meta.relationCache.has(relationName)) {
|
|
5349
5916
|
return meta.relationCache.get(relationName);
|
|
@@ -5364,200 +5931,147 @@ var relationLoaderCache = (meta, relationName, factory) => {
|
|
|
5364
5931
|
}
|
|
5365
5932
|
return promise;
|
|
5366
5933
|
};
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
relationHydration: /* @__PURE__ */ new Map(),
|
|
5375
|
-
relationWrappers: /* @__PURE__ */ new Map()
|
|
5376
|
-
};
|
|
5377
|
-
Object.defineProperty(target, ENTITY_META, {
|
|
5378
|
-
value: meta,
|
|
5379
|
-
enumerable: false,
|
|
5380
|
-
writable: false
|
|
5381
|
-
});
|
|
5382
|
-
const handler = {
|
|
5383
|
-
get(targetObj, prop, receiver) {
|
|
5384
|
-
if (prop === ENTITY_META) {
|
|
5385
|
-
return meta;
|
|
5934
|
+
|
|
5935
|
+
// src/orm/entity-relations.ts
|
|
5936
|
+
var proxifyRelationWrapper = (wrapper) => {
|
|
5937
|
+
return new Proxy(wrapper, {
|
|
5938
|
+
get(target, prop, receiver) {
|
|
5939
|
+
if (typeof prop === "symbol") {
|
|
5940
|
+
return Reflect.get(target, prop, receiver);
|
|
5386
5941
|
}
|
|
5387
|
-
if (prop
|
|
5388
|
-
return
|
|
5389
|
-
const wrapper = getRelationWrapper(meta, relationName, receiver);
|
|
5390
|
-
if (wrapper && typeof wrapper.load === "function") {
|
|
5391
|
-
return wrapper.load();
|
|
5392
|
-
}
|
|
5393
|
-
return void 0;
|
|
5394
|
-
};
|
|
5942
|
+
if (prop in target) {
|
|
5943
|
+
return Reflect.get(target, prop, receiver);
|
|
5395
5944
|
}
|
|
5396
|
-
|
|
5397
|
-
|
|
5945
|
+
const getItems = target.getItems;
|
|
5946
|
+
if (typeof getItems === "function") {
|
|
5947
|
+
const items = getItems.call(target);
|
|
5948
|
+
if (items && prop in items) {
|
|
5949
|
+
const propName = prop;
|
|
5950
|
+
const value = items[propName];
|
|
5951
|
+
return typeof value === "function" ? value.bind(items) : value;
|
|
5952
|
+
}
|
|
5398
5953
|
}
|
|
5399
|
-
|
|
5954
|
+
const getRef = target.get;
|
|
5955
|
+
if (typeof getRef === "function") {
|
|
5956
|
+
const current = getRef.call(target);
|
|
5957
|
+
if (current && prop in current) {
|
|
5958
|
+
const propName = prop;
|
|
5959
|
+
const value = current[propName];
|
|
5960
|
+
return typeof value === "function" ? value.bind(current) : value;
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
return void 0;
|
|
5400
5964
|
},
|
|
5401
|
-
set(
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
ctx.markDirty(receiver);
|
|
5965
|
+
set(target, prop, value, receiver) {
|
|
5966
|
+
if (typeof prop === "symbol") {
|
|
5967
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5405
5968
|
}
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
};
|
|
5409
|
-
const proxy = new Proxy(target, handler);
|
|
5410
|
-
populateHydrationCache(proxy, row, meta);
|
|
5411
|
-
return proxy;
|
|
5412
|
-
};
|
|
5413
|
-
var createEntityFromRow = (ctx, table, row, lazyRelations = []) => {
|
|
5414
|
-
const pkName = findPrimaryKey(table);
|
|
5415
|
-
const pkValue = row[pkName];
|
|
5416
|
-
if (pkValue !== void 0 && pkValue !== null) {
|
|
5417
|
-
const tracked = ctx.getEntity(table, pkValue);
|
|
5418
|
-
if (tracked) return tracked;
|
|
5419
|
-
}
|
|
5420
|
-
const entity = createEntityProxy(ctx, table, row, lazyRelations);
|
|
5421
|
-
if (pkValue !== void 0 && pkValue !== null) {
|
|
5422
|
-
ctx.trackManaged(table, pkValue, entity);
|
|
5423
|
-
} else {
|
|
5424
|
-
ctx.trackNew(table, entity);
|
|
5425
|
-
}
|
|
5426
|
-
return entity;
|
|
5427
|
-
};
|
|
5428
|
-
var toKey7 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
5429
|
-
var populateHydrationCache = (entity, row, meta) => {
|
|
5430
|
-
for (const relationName of Object.keys(meta.table.relations)) {
|
|
5431
|
-
const relation = meta.table.relations[relationName];
|
|
5432
|
-
const data = row[relationName];
|
|
5433
|
-
if (relation.type === RelationKinds.HasOne) {
|
|
5434
|
-
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
5435
|
-
const rootValue = entity[localKey];
|
|
5436
|
-
if (rootValue === void 0 || rootValue === null) continue;
|
|
5437
|
-
if (!data || typeof data !== "object") continue;
|
|
5438
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5439
|
-
cache.set(toKey7(rootValue), data);
|
|
5440
|
-
meta.relationHydration.set(relationName, cache);
|
|
5441
|
-
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5442
|
-
continue;
|
|
5443
|
-
}
|
|
5444
|
-
if (!Array.isArray(data)) continue;
|
|
5445
|
-
if (relation.type === RelationKinds.HasMany || relation.type === RelationKinds.BelongsToMany) {
|
|
5446
|
-
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
5447
|
-
const rootValue = entity[localKey];
|
|
5448
|
-
if (rootValue === void 0 || rootValue === null) continue;
|
|
5449
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5450
|
-
cache.set(toKey7(rootValue), data);
|
|
5451
|
-
meta.relationHydration.set(relationName, cache);
|
|
5452
|
-
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
5453
|
-
continue;
|
|
5454
|
-
}
|
|
5455
|
-
if (relation.type === RelationKinds.BelongsTo) {
|
|
5456
|
-
const targetKey = relation.localKey || findPrimaryKey(relation.target);
|
|
5457
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5458
|
-
for (const item of data) {
|
|
5459
|
-
const pkValue = item[targetKey];
|
|
5460
|
-
if (pkValue === void 0 || pkValue === null) continue;
|
|
5461
|
-
cache.set(toKey7(pkValue), item);
|
|
5969
|
+
if (prop in target) {
|
|
5970
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5462
5971
|
}
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5972
|
+
const getRef = target.get;
|
|
5973
|
+
if (typeof getRef === "function") {
|
|
5974
|
+
const current = getRef.call(target);
|
|
5975
|
+
if (current && typeof current === "object") {
|
|
5976
|
+
return Reflect.set(current, prop, value);
|
|
5977
|
+
}
|
|
5978
|
+
}
|
|
5979
|
+
const getItems = target.getItems;
|
|
5980
|
+
if (typeof getItems === "function") {
|
|
5981
|
+
const items = getItems.call(target);
|
|
5982
|
+
return Reflect.set(items, prop, value);
|
|
5466
5983
|
}
|
|
5984
|
+
return Reflect.set(target, prop, value, receiver);
|
|
5467
5985
|
}
|
|
5468
|
-
}
|
|
5986
|
+
});
|
|
5469
5987
|
};
|
|
5470
|
-
var getRelationWrapper = (meta, relationName, owner) => {
|
|
5471
|
-
|
|
5472
|
-
|
|
5988
|
+
var getRelationWrapper = (meta, relationName, owner, createEntity) => {
|
|
5989
|
+
const relationKey = relationName;
|
|
5990
|
+
if (meta.relationWrappers.has(relationKey)) {
|
|
5991
|
+
return meta.relationWrappers.get(relationKey);
|
|
5473
5992
|
}
|
|
5474
|
-
const relation = meta.table.relations[
|
|
5993
|
+
const relation = meta.table.relations[relationKey];
|
|
5475
5994
|
if (!relation) return void 0;
|
|
5476
|
-
const wrapper = instantiateWrapper(meta,
|
|
5477
|
-
if (wrapper)
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
return
|
|
5481
|
-
};
|
|
5482
|
-
var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
5995
|
+
const wrapper = instantiateWrapper(meta, relationKey, relation, owner, createEntity);
|
|
5996
|
+
if (!wrapper) return void 0;
|
|
5997
|
+
const proxied = proxifyRelationWrapper(wrapper);
|
|
5998
|
+
meta.relationWrappers.set(relationKey, proxied);
|
|
5999
|
+
return proxied;
|
|
6000
|
+
};
|
|
6001
|
+
var instantiateWrapper = (meta, relationName, relation, owner, createEntity) => {
|
|
6002
|
+
const metaBase = meta;
|
|
6003
|
+
const lazyOptions = meta.lazyRelationOptions.get(relationName);
|
|
6004
|
+
const loadCached = (factory) => relationLoaderCache(metaBase, relationName, factory);
|
|
5483
6005
|
switch (relation.type) {
|
|
5484
6006
|
case RelationKinds.HasOne: {
|
|
5485
6007
|
const hasOne2 = relation;
|
|
5486
6008
|
const localKey = hasOne2.localKey || findPrimaryKey(meta.table);
|
|
5487
|
-
const loader = () =>
|
|
5488
|
-
meta,
|
|
5489
|
-
relationName,
|
|
5490
|
-
() => loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne2)
|
|
6009
|
+
const loader = () => loadCached(
|
|
6010
|
+
() => loadHasOneRelation(meta.ctx, meta.table, relationName, hasOne2, lazyOptions)
|
|
5491
6011
|
);
|
|
5492
6012
|
return new DefaultHasOneReference(
|
|
5493
6013
|
meta.ctx,
|
|
5494
|
-
|
|
6014
|
+
metaBase,
|
|
5495
6015
|
owner,
|
|
5496
6016
|
relationName,
|
|
5497
6017
|
hasOne2,
|
|
5498
6018
|
meta.table,
|
|
5499
6019
|
loader,
|
|
5500
|
-
(row) =>
|
|
6020
|
+
(row) => createEntity(hasOne2.target, row),
|
|
5501
6021
|
localKey
|
|
5502
6022
|
);
|
|
5503
6023
|
}
|
|
5504
6024
|
case RelationKinds.HasMany: {
|
|
5505
6025
|
const hasMany2 = relation;
|
|
5506
6026
|
const localKey = hasMany2.localKey || findPrimaryKey(meta.table);
|
|
5507
|
-
const loader = () =>
|
|
5508
|
-
meta,
|
|
5509
|
-
relationName,
|
|
5510
|
-
() => loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany2)
|
|
6027
|
+
const loader = () => loadCached(
|
|
6028
|
+
() => loadHasManyRelation(meta.ctx, meta.table, relationName, hasMany2, lazyOptions)
|
|
5511
6029
|
);
|
|
5512
6030
|
return new DefaultHasManyCollection(
|
|
5513
6031
|
meta.ctx,
|
|
5514
|
-
|
|
6032
|
+
metaBase,
|
|
5515
6033
|
owner,
|
|
5516
6034
|
relationName,
|
|
5517
6035
|
hasMany2,
|
|
5518
6036
|
meta.table,
|
|
5519
6037
|
loader,
|
|
5520
|
-
(row) =>
|
|
6038
|
+
(row) => createEntity(relation.target, row),
|
|
5521
6039
|
localKey
|
|
5522
6040
|
);
|
|
5523
6041
|
}
|
|
5524
6042
|
case RelationKinds.BelongsTo: {
|
|
5525
6043
|
const belongsTo2 = relation;
|
|
5526
6044
|
const targetKey = belongsTo2.localKey || findPrimaryKey(belongsTo2.target);
|
|
5527
|
-
const loader = () =>
|
|
5528
|
-
meta,
|
|
5529
|
-
relationName,
|
|
5530
|
-
() => loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo2)
|
|
6045
|
+
const loader = () => loadCached(
|
|
6046
|
+
() => loadBelongsToRelation(meta.ctx, meta.table, relationName, belongsTo2, lazyOptions)
|
|
5531
6047
|
);
|
|
5532
6048
|
return new DefaultBelongsToReference(
|
|
5533
6049
|
meta.ctx,
|
|
5534
|
-
|
|
6050
|
+
metaBase,
|
|
5535
6051
|
owner,
|
|
5536
6052
|
relationName,
|
|
5537
6053
|
belongsTo2,
|
|
5538
6054
|
meta.table,
|
|
5539
6055
|
loader,
|
|
5540
|
-
(row) =>
|
|
6056
|
+
(row) => createEntity(relation.target, row),
|
|
5541
6057
|
targetKey
|
|
5542
6058
|
);
|
|
5543
6059
|
}
|
|
5544
6060
|
case RelationKinds.BelongsToMany: {
|
|
5545
6061
|
const many = relation;
|
|
5546
6062
|
const localKey = many.localKey || findPrimaryKey(meta.table);
|
|
5547
|
-
const loader = () =>
|
|
5548
|
-
meta,
|
|
5549
|
-
relationName,
|
|
5550
|
-
() => loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many)
|
|
6063
|
+
const loader = () => loadCached(
|
|
6064
|
+
() => loadBelongsToManyRelation(meta.ctx, meta.table, relationName, many, lazyOptions)
|
|
5551
6065
|
);
|
|
5552
6066
|
return new DefaultManyToManyCollection(
|
|
5553
6067
|
meta.ctx,
|
|
5554
|
-
|
|
6068
|
+
metaBase,
|
|
5555
6069
|
owner,
|
|
5556
6070
|
relationName,
|
|
5557
6071
|
many,
|
|
5558
6072
|
meta.table,
|
|
5559
6073
|
loader,
|
|
5560
|
-
(row) =>
|
|
6074
|
+
(row) => createEntity(relation.target, row),
|
|
5561
6075
|
localKey
|
|
5562
6076
|
);
|
|
5563
6077
|
}
|
|
@@ -5566,51 +6080,570 @@ var instantiateWrapper = (meta, relationName, relation, owner) => {
|
|
|
5566
6080
|
}
|
|
5567
6081
|
};
|
|
5568
6082
|
|
|
5569
|
-
// src/orm/
|
|
5570
|
-
var
|
|
5571
|
-
const
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
6083
|
+
// src/orm/entity.ts
|
|
6084
|
+
var createEntityProxy = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
6085
|
+
const target = { ...row };
|
|
6086
|
+
const meta = {
|
|
6087
|
+
ctx,
|
|
6088
|
+
table,
|
|
6089
|
+
lazyRelations: [...lazyRelations],
|
|
6090
|
+
lazyRelationOptions: new Map(lazyRelationOptions),
|
|
6091
|
+
relationCache: /* @__PURE__ */ new Map(),
|
|
6092
|
+
relationHydration: /* @__PURE__ */ new Map(),
|
|
6093
|
+
relationWrappers: /* @__PURE__ */ new Map()
|
|
6094
|
+
};
|
|
6095
|
+
const createRelationEntity = (relationTable, relationRow) => createEntityFromRow(meta.ctx, relationTable, relationRow);
|
|
6096
|
+
Object.defineProperty(target, ENTITY_META, {
|
|
6097
|
+
value: meta,
|
|
6098
|
+
enumerable: false,
|
|
6099
|
+
writable: false
|
|
6100
|
+
});
|
|
6101
|
+
const handler = {
|
|
6102
|
+
get(targetObj, prop, receiver) {
|
|
6103
|
+
if (prop === ENTITY_META) {
|
|
6104
|
+
return meta;
|
|
6105
|
+
}
|
|
6106
|
+
if (prop === "$load") {
|
|
6107
|
+
return async (relationName) => {
|
|
6108
|
+
const wrapper = getRelationWrapper(meta, relationName, receiver, createRelationEntity);
|
|
6109
|
+
if (wrapper && typeof wrapper.load === "function") {
|
|
6110
|
+
return wrapper.load();
|
|
6111
|
+
}
|
|
6112
|
+
return void 0;
|
|
6113
|
+
};
|
|
6114
|
+
}
|
|
6115
|
+
if (typeof prop === "string" && table.relations[prop]) {
|
|
6116
|
+
return getRelationWrapper(meta, prop, receiver, createRelationEntity);
|
|
6117
|
+
}
|
|
6118
|
+
return Reflect.get(targetObj, prop, receiver);
|
|
6119
|
+
},
|
|
6120
|
+
set(targetObj, prop, value, receiver) {
|
|
6121
|
+
const result = Reflect.set(targetObj, prop, value, receiver);
|
|
6122
|
+
if (typeof prop === "string" && table.columns[prop]) {
|
|
6123
|
+
ctx.markDirty(receiver);
|
|
6124
|
+
}
|
|
6125
|
+
return result;
|
|
6126
|
+
}
|
|
6127
|
+
};
|
|
6128
|
+
const proxy = new Proxy(target, handler);
|
|
6129
|
+
populateHydrationCache(proxy, row, meta);
|
|
6130
|
+
return proxy;
|
|
6131
|
+
};
|
|
6132
|
+
var createEntityFromRow = (ctx, table, row, lazyRelations = [], lazyRelationOptions = /* @__PURE__ */ new Map()) => {
|
|
6133
|
+
const pkName = findPrimaryKey(table);
|
|
6134
|
+
const pkValue = row[pkName];
|
|
6135
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
6136
|
+
const tracked = ctx.getEntity(table, pkValue);
|
|
6137
|
+
if (tracked) return tracked;
|
|
6138
|
+
}
|
|
6139
|
+
const entity = createEntityProxy(ctx, table, row, lazyRelations, lazyRelationOptions);
|
|
6140
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
6141
|
+
ctx.trackManaged(table, pkValue, entity);
|
|
6142
|
+
} else {
|
|
6143
|
+
ctx.trackNew(table, entity);
|
|
6144
|
+
}
|
|
6145
|
+
return entity;
|
|
6146
|
+
};
|
|
6147
|
+
|
|
6148
|
+
// src/orm/execute.ts
|
|
6149
|
+
var flattenResults = (results) => {
|
|
6150
|
+
const rows = [];
|
|
6151
|
+
for (const result of results) {
|
|
6152
|
+
const { columns, values } = result;
|
|
6153
|
+
for (const valueRow of values) {
|
|
6154
|
+
const row = {};
|
|
6155
|
+
columns.forEach((column, idx) => {
|
|
6156
|
+
row[column] = valueRow[idx];
|
|
6157
|
+
});
|
|
6158
|
+
rows.push(row);
|
|
6159
|
+
}
|
|
6160
|
+
}
|
|
6161
|
+
return rows;
|
|
6162
|
+
};
|
|
6163
|
+
var executeWithContexts = async (execCtx, entityCtx, qb) => {
|
|
6164
|
+
const ast = qb.getAST();
|
|
6165
|
+
const compiled = execCtx.dialect.compileSelect(ast);
|
|
6166
|
+
const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
6167
|
+
const rows = flattenResults(executed);
|
|
6168
|
+
const lazyRelations = qb.getLazyRelations();
|
|
6169
|
+
const lazyRelationOptions = qb.getLazyRelationOptions();
|
|
6170
|
+
if (ast.setOps && ast.setOps.length > 0) {
|
|
6171
|
+
const proxies = rows.map((row) => createEntityProxy(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
6172
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
6173
|
+
return proxies;
|
|
6174
|
+
}
|
|
6175
|
+
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
6176
|
+
const entities = hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, lazyRelations, lazyRelationOptions));
|
|
6177
|
+
await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
|
|
6178
|
+
return entities;
|
|
6179
|
+
};
|
|
6180
|
+
async function executeHydrated(session, qb) {
|
|
6181
|
+
return executeWithContexts(session.getExecutionContext(), session, qb);
|
|
6182
|
+
}
|
|
6183
|
+
async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
|
|
6184
|
+
const entityCtx = hydCtx.entityContext;
|
|
6185
|
+
if (!entityCtx) {
|
|
6186
|
+
throw new Error("Hydration context is missing an EntityContext");
|
|
6187
|
+
}
|
|
6188
|
+
return executeWithContexts(execCtx, entityCtx, qb);
|
|
6189
|
+
}
|
|
6190
|
+
var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOptions) => {
|
|
6191
|
+
if (!lazyRelations.length) return;
|
|
6192
|
+
const tracked = ctx.getEntitiesForTable(table);
|
|
6193
|
+
if (!tracked.length) return;
|
|
6194
|
+
const meta = getEntityMeta(tracked[0].entity);
|
|
6195
|
+
if (!meta) return;
|
|
6196
|
+
for (const relationName of lazyRelations) {
|
|
6197
|
+
const relation = table.relations[relationName];
|
|
6198
|
+
if (!relation) continue;
|
|
6199
|
+
const key = relationName;
|
|
6200
|
+
const options = lazyRelationOptions.get(key);
|
|
6201
|
+
if (!options) {
|
|
6202
|
+
continue;
|
|
6203
|
+
}
|
|
6204
|
+
switch (relation.type) {
|
|
6205
|
+
case RelationKinds.HasOne:
|
|
6206
|
+
await relationLoaderCache(
|
|
6207
|
+
meta,
|
|
6208
|
+
key,
|
|
6209
|
+
() => loadHasOneRelation(ctx, table, key, relation, options)
|
|
6210
|
+
);
|
|
6211
|
+
break;
|
|
6212
|
+
case RelationKinds.HasMany:
|
|
6213
|
+
await relationLoaderCache(
|
|
6214
|
+
meta,
|
|
6215
|
+
key,
|
|
6216
|
+
() => loadHasManyRelation(ctx, table, key, relation, options)
|
|
6217
|
+
);
|
|
6218
|
+
break;
|
|
6219
|
+
case RelationKinds.BelongsTo:
|
|
6220
|
+
await relationLoaderCache(
|
|
6221
|
+
meta,
|
|
6222
|
+
key,
|
|
6223
|
+
() => loadBelongsToRelation(ctx, table, key, relation, options)
|
|
6224
|
+
);
|
|
6225
|
+
break;
|
|
6226
|
+
case RelationKinds.BelongsToMany:
|
|
6227
|
+
await relationLoaderCache(
|
|
6228
|
+
meta,
|
|
6229
|
+
key,
|
|
6230
|
+
() => loadBelongsToManyRelation(ctx, table, key, relation, options)
|
|
6231
|
+
);
|
|
6232
|
+
break;
|
|
6233
|
+
}
|
|
6234
|
+
}
|
|
6235
|
+
};
|
|
6236
|
+
|
|
6237
|
+
// src/query-builder/query-resolution.ts
|
|
6238
|
+
function resolveSelectQuery(query) {
|
|
6239
|
+
const candidate = query;
|
|
6240
|
+
return typeof candidate.getAST === "function" && candidate.getAST ? candidate.getAST() : query;
|
|
6241
|
+
}
|
|
6242
|
+
|
|
6243
|
+
// src/query-builder/select/select-operations.ts
|
|
6244
|
+
function applyOrderBy(context, predicateFacet, term, directionOrOptions) {
|
|
6245
|
+
const options = typeof directionOrOptions === "string" ? { direction: directionOrOptions } : directionOrOptions;
|
|
6246
|
+
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
6247
|
+
return predicateFacet.orderBy(context, term, dir, options.nulls, options.collation);
|
|
6248
|
+
}
|
|
6249
|
+
async function executeCount(context, env, session) {
|
|
6250
|
+
const unpagedAst = {
|
|
6251
|
+
...context.state.ast,
|
|
6252
|
+
orderBy: void 0,
|
|
6253
|
+
limit: void 0,
|
|
6254
|
+
offset: void 0
|
|
6255
|
+
};
|
|
6256
|
+
const nextState = new SelectQueryState(env.table, unpagedAst);
|
|
6257
|
+
const nextContext = {
|
|
6258
|
+
...context,
|
|
6259
|
+
state: nextState
|
|
6260
|
+
};
|
|
6261
|
+
const subAst = nextContext.hydration.applyToAst(nextState.ast);
|
|
6262
|
+
const countQuery = {
|
|
6263
|
+
type: "SelectQuery",
|
|
6264
|
+
from: derivedTable(subAst, "__metal_count"),
|
|
6265
|
+
columns: [{ type: "Function", name: "COUNT", args: [], alias: "total" }],
|
|
6266
|
+
joins: []
|
|
6267
|
+
};
|
|
6268
|
+
const execCtx = session.getExecutionContext();
|
|
6269
|
+
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
6270
|
+
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
6271
|
+
const value = results[0]?.values?.[0]?.[0];
|
|
6272
|
+
if (typeof value === "number") return value;
|
|
6273
|
+
if (typeof value === "bigint") return Number(value);
|
|
6274
|
+
if (typeof value === "string") return Number(value);
|
|
6275
|
+
return value === null || value === void 0 ? 0 : Number(value);
|
|
6276
|
+
}
|
|
6277
|
+
async function executePagedQuery(builder, session, options, countCallback) {
|
|
6278
|
+
const { page, pageSize } = options;
|
|
6279
|
+
if (!Number.isInteger(page) || page < 1) {
|
|
6280
|
+
throw new Error("executePaged: page must be an integer >= 1");
|
|
6281
|
+
}
|
|
6282
|
+
if (!Number.isInteger(pageSize) || pageSize < 1) {
|
|
6283
|
+
throw new Error("executePaged: pageSize must be an integer >= 1");
|
|
6284
|
+
}
|
|
6285
|
+
const offset = (page - 1) * pageSize;
|
|
6286
|
+
const [items, totalItems] = await Promise.all([
|
|
6287
|
+
builder.limit(pageSize).offset(offset).execute(session),
|
|
6288
|
+
countCallback(session)
|
|
6289
|
+
]);
|
|
6290
|
+
return { items, totalItems };
|
|
6291
|
+
}
|
|
6292
|
+
function buildWhereHasPredicate(env, context, relationFacet, createChildBuilder, relationName, callbackOrOptions, maybeOptions, negate = false) {
|
|
6293
|
+
const relation = env.table.relations[relationName];
|
|
6294
|
+
if (!relation) {
|
|
6295
|
+
throw new Error(`Relation '${relationName}' not found on table '${env.table.name}'`);
|
|
6296
|
+
}
|
|
6297
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
6298
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
6299
|
+
let subQb = createChildBuilder(relation.target);
|
|
6300
|
+
if (callback) {
|
|
6301
|
+
subQb = callback(subQb);
|
|
6302
|
+
}
|
|
6303
|
+
const subAst = subQb.getAST();
|
|
6304
|
+
const finalSubAst = relationFacet.applyRelationCorrelation(
|
|
6305
|
+
context,
|
|
6306
|
+
relationName,
|
|
6307
|
+
subAst,
|
|
6308
|
+
options?.correlate
|
|
6309
|
+
);
|
|
6310
|
+
return negate ? notExists(finalSubAst) : exists(finalSubAst);
|
|
6311
|
+
}
|
|
6312
|
+
|
|
6313
|
+
// src/query-builder/select/from-facet.ts
|
|
6314
|
+
var SelectFromFacet = class {
|
|
6315
|
+
/**
|
|
6316
|
+
* Creates a new SelectFromFacet instance
|
|
6317
|
+
* @param env - Query builder environment
|
|
6318
|
+
* @param createAstService - Function to create AST service
|
|
6319
|
+
*/
|
|
6320
|
+
constructor(env, createAstService) {
|
|
6321
|
+
this.env = env;
|
|
6322
|
+
this.createAstService = createAstService;
|
|
6323
|
+
}
|
|
6324
|
+
/**
|
|
6325
|
+
* Applies an alias to the FROM table
|
|
6326
|
+
* @param context - Current query context
|
|
6327
|
+
* @param alias - Alias to apply
|
|
6328
|
+
* @returns Updated query context with aliased FROM
|
|
6329
|
+
*/
|
|
6330
|
+
as(context, alias) {
|
|
6331
|
+
const from = context.state.ast.from;
|
|
6332
|
+
if (from.type !== "Table") {
|
|
6333
|
+
throw new Error("Cannot alias non-table FROM sources");
|
|
6334
|
+
}
|
|
6335
|
+
const nextFrom = { ...from, alias };
|
|
6336
|
+
const astService = this.createAstService(context.state);
|
|
6337
|
+
const nextState = astService.withFrom(nextFrom);
|
|
6338
|
+
return { state: nextState, hydration: context.hydration };
|
|
6339
|
+
}
|
|
6340
|
+
/**
|
|
6341
|
+
* Sets the FROM clause to a subquery
|
|
6342
|
+
* @param context - Current query context
|
|
6343
|
+
* @param subAst - Subquery AST
|
|
6344
|
+
* @param alias - Alias for the subquery
|
|
6345
|
+
* @param columnAliases - Optional column aliases
|
|
6346
|
+
* @returns Updated query context with subquery FROM
|
|
6347
|
+
*/
|
|
6348
|
+
fromSubquery(context, subAst, alias, columnAliases) {
|
|
6349
|
+
const fromNode = derivedTable(subAst, alias, columnAliases);
|
|
6350
|
+
const astService = this.createAstService(context.state);
|
|
6351
|
+
const nextState = astService.withFrom(fromNode);
|
|
6352
|
+
return { state: nextState, hydration: context.hydration };
|
|
6353
|
+
}
|
|
6354
|
+
/**
|
|
6355
|
+
* Sets the FROM clause to a function table
|
|
6356
|
+
* @param context - Current query context
|
|
6357
|
+
* @param name - Function name
|
|
6358
|
+
* @param args - Function arguments
|
|
6359
|
+
* @param alias - Optional alias for the function table
|
|
6360
|
+
* @param options - Optional function table options
|
|
6361
|
+
* @returns Updated query context with function table FROM
|
|
6362
|
+
*/
|
|
6363
|
+
fromFunctionTable(context, name, args, alias, options) {
|
|
6364
|
+
const functionTable = fnTable(name, args, alias, options);
|
|
6365
|
+
const astService = this.createAstService(context.state);
|
|
6366
|
+
const nextState = astService.withFrom(functionTable);
|
|
6367
|
+
return { state: nextState, hydration: context.hydration };
|
|
6368
|
+
}
|
|
6369
|
+
};
|
|
6370
|
+
|
|
6371
|
+
// src/query-builder/select/join-facet.ts
|
|
6372
|
+
var SelectJoinFacet = class {
|
|
6373
|
+
constructor(env, createAstService) {
|
|
6374
|
+
this.env = env;
|
|
6375
|
+
this.createAstService = createAstService;
|
|
6376
|
+
}
|
|
6377
|
+
applyJoin(context, table, condition, kind) {
|
|
6378
|
+
const joinNode = createJoinNode(kind, { type: "Table", name: table.name, schema: table.schema }, condition);
|
|
6379
|
+
const astService = this.createAstService(context.state);
|
|
6380
|
+
const nextState = astService.withJoin(joinNode);
|
|
6381
|
+
return { state: nextState, hydration: context.hydration };
|
|
6382
|
+
}
|
|
6383
|
+
joinSubquery(context, subAst, alias, condition, joinKind, columnAliases) {
|
|
6384
|
+
const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
|
|
6385
|
+
const astService = this.createAstService(context.state);
|
|
6386
|
+
const nextState = astService.withJoin(joinNode);
|
|
6387
|
+
return { state: nextState, hydration: context.hydration };
|
|
6388
|
+
}
|
|
6389
|
+
joinFunctionTable(context, name, args, alias, condition, joinKind, options) {
|
|
6390
|
+
const functionTable = fnTable(name, args, alias, options);
|
|
6391
|
+
const joinNode = createJoinNode(joinKind, functionTable, condition);
|
|
6392
|
+
const astService = this.createAstService(context.state);
|
|
6393
|
+
const nextState = astService.withJoin(joinNode);
|
|
6394
|
+
return { state: nextState, hydration: context.hydration };
|
|
6395
|
+
}
|
|
6396
|
+
};
|
|
6397
|
+
|
|
6398
|
+
// src/query-builder/select/projection-facet.ts
|
|
6399
|
+
var SelectProjectionFacet = class {
|
|
6400
|
+
/**
|
|
6401
|
+
* Creates a new SelectProjectionFacet instance
|
|
6402
|
+
* @param columnSelector - Column selector dependency
|
|
6403
|
+
*/
|
|
6404
|
+
constructor(columnSelector) {
|
|
6405
|
+
this.columnSelector = columnSelector;
|
|
6406
|
+
}
|
|
6407
|
+
/**
|
|
6408
|
+
* Selects columns for the query
|
|
6409
|
+
* @param context - Current query context
|
|
6410
|
+
* @param columns - Columns to select
|
|
6411
|
+
* @returns Updated query context with selected columns
|
|
6412
|
+
*/
|
|
6413
|
+
select(context, columns) {
|
|
6414
|
+
return this.columnSelector.select(context, columns);
|
|
6415
|
+
}
|
|
6416
|
+
/**
|
|
6417
|
+
* Selects raw column expressions
|
|
6418
|
+
* @param context - Current query context
|
|
6419
|
+
* @param cols - Raw column expressions
|
|
6420
|
+
* @returns Updated query context with raw column selections
|
|
6421
|
+
*/
|
|
6422
|
+
selectRaw(context, cols) {
|
|
6423
|
+
return this.columnSelector.selectRaw(context, cols);
|
|
6424
|
+
}
|
|
6425
|
+
/**
|
|
6426
|
+
* Selects a subquery as a column
|
|
6427
|
+
* @param context - Current query context
|
|
6428
|
+
* @param alias - Alias for the subquery
|
|
6429
|
+
* @param query - Subquery to select
|
|
6430
|
+
* @returns Updated query context with subquery selection
|
|
6431
|
+
*/
|
|
6432
|
+
selectSubquery(context, alias, query) {
|
|
6433
|
+
return this.columnSelector.selectSubquery(context, alias, query);
|
|
6434
|
+
}
|
|
6435
|
+
/**
|
|
6436
|
+
* Adds DISTINCT clause to the query
|
|
6437
|
+
* @param context - Current query context
|
|
6438
|
+
* @param cols - Columns to make distinct
|
|
6439
|
+
* @returns Updated query context with DISTINCT clause
|
|
6440
|
+
*/
|
|
6441
|
+
distinct(context, cols) {
|
|
6442
|
+
return this.columnSelector.distinct(context, cols);
|
|
6443
|
+
}
|
|
6444
|
+
};
|
|
6445
|
+
|
|
6446
|
+
// src/query-builder/select/predicate-facet.ts
|
|
6447
|
+
var SelectPredicateFacet = class {
|
|
6448
|
+
/**
|
|
6449
|
+
* Creates a new SelectPredicateFacet instance
|
|
6450
|
+
* @param env - Query builder environment
|
|
6451
|
+
* @param createAstService - Function to create AST service
|
|
6452
|
+
*/
|
|
6453
|
+
constructor(env, createAstService) {
|
|
6454
|
+
this.env = env;
|
|
6455
|
+
this.createAstService = createAstService;
|
|
6456
|
+
}
|
|
6457
|
+
/**
|
|
6458
|
+
* Adds a WHERE condition to the query
|
|
6459
|
+
* @param context - Current query context
|
|
6460
|
+
* @param expr - WHERE expression
|
|
6461
|
+
* @returns Updated query context with WHERE condition
|
|
6462
|
+
*/
|
|
6463
|
+
where(context, expr) {
|
|
6464
|
+
const astService = this.createAstService(context.state);
|
|
6465
|
+
const nextState = astService.withWhere(expr);
|
|
6466
|
+
return { state: nextState, hydration: context.hydration };
|
|
6467
|
+
}
|
|
6468
|
+
/**
|
|
6469
|
+
* Adds a GROUP BY clause to the query
|
|
6470
|
+
* @param context - Current query context
|
|
6471
|
+
* @param term - Column or ordering term to group by
|
|
6472
|
+
* @returns Updated query context with GROUP BY clause
|
|
6473
|
+
*/
|
|
6474
|
+
groupBy(context, term) {
|
|
6475
|
+
const astService = this.createAstService(context.state);
|
|
6476
|
+
const nextState = astService.withGroupBy(term);
|
|
6477
|
+
return { state: nextState, hydration: context.hydration };
|
|
6478
|
+
}
|
|
6479
|
+
/**
|
|
6480
|
+
* Adds a HAVING condition to the query
|
|
6481
|
+
* @param context - Current query context
|
|
6482
|
+
* @param expr - HAVING expression
|
|
6483
|
+
* @returns Updated query context with HAVING condition
|
|
6484
|
+
*/
|
|
6485
|
+
having(context, expr) {
|
|
6486
|
+
const astService = this.createAstService(context.state);
|
|
6487
|
+
const nextState = astService.withHaving(expr);
|
|
6488
|
+
return { state: nextState, hydration: context.hydration };
|
|
6489
|
+
}
|
|
6490
|
+
/**
|
|
6491
|
+
* Adds an ORDER BY clause to the query
|
|
6492
|
+
* @param context - Current query context
|
|
6493
|
+
* @param term - Column or ordering term to order by
|
|
6494
|
+
* @param direction - Order direction
|
|
6495
|
+
* @param nulls - Nulls ordering
|
|
6496
|
+
* @param collation - Collation
|
|
6497
|
+
* @returns Updated query context with ORDER BY clause
|
|
6498
|
+
*/
|
|
6499
|
+
orderBy(context, term, direction, nulls, collation) {
|
|
6500
|
+
const astService = this.createAstService(context.state);
|
|
6501
|
+
const nextState = astService.withOrderBy(term, direction, nulls, collation);
|
|
6502
|
+
return { state: nextState, hydration: context.hydration };
|
|
6503
|
+
}
|
|
6504
|
+
/**
|
|
6505
|
+
* Adds a LIMIT clause to the query
|
|
6506
|
+
* @param context - Current query context
|
|
6507
|
+
* @param n - Maximum number of rows
|
|
6508
|
+
* @returns Updated query context with LIMIT clause
|
|
6509
|
+
*/
|
|
6510
|
+
limit(context, n) {
|
|
6511
|
+
const astService = this.createAstService(context.state);
|
|
6512
|
+
const nextState = astService.withLimit(n);
|
|
6513
|
+
return { state: nextState, hydration: context.hydration };
|
|
6514
|
+
}
|
|
6515
|
+
/**
|
|
6516
|
+
* Adds an OFFSET clause to the query
|
|
6517
|
+
* @param context - Current query context
|
|
6518
|
+
* @param n - Number of rows to skip
|
|
6519
|
+
* @returns Updated query context with OFFSET clause
|
|
6520
|
+
*/
|
|
6521
|
+
offset(context, n) {
|
|
6522
|
+
const astService = this.createAstService(context.state);
|
|
6523
|
+
const nextState = astService.withOffset(n);
|
|
6524
|
+
return { state: nextState, hydration: context.hydration };
|
|
6525
|
+
}
|
|
6526
|
+
};
|
|
6527
|
+
|
|
6528
|
+
// src/query-builder/select/cte-facet.ts
|
|
6529
|
+
var SelectCTEFacet = class {
|
|
6530
|
+
/**
|
|
6531
|
+
* Creates a new SelectCTEFacet instance
|
|
6532
|
+
* @param env - Query builder environment
|
|
6533
|
+
* @param createAstService - Function to create AST service
|
|
6534
|
+
*/
|
|
6535
|
+
constructor(env, createAstService) {
|
|
6536
|
+
this.env = env;
|
|
6537
|
+
this.createAstService = createAstService;
|
|
5581
6538
|
}
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
6539
|
+
/**
|
|
6540
|
+
* Adds a Common Table Expression to the query
|
|
6541
|
+
* @param context - Current query context
|
|
6542
|
+
* @param name - CTE name
|
|
6543
|
+
* @param subAst - CTE query AST
|
|
6544
|
+
* @param columns - Optional column names
|
|
6545
|
+
* @param recursive - Whether the CTE is recursive
|
|
6546
|
+
* @returns Updated query context with CTE
|
|
6547
|
+
*/
|
|
6548
|
+
withCTE(context, name, subAst, columns, recursive) {
|
|
6549
|
+
const astService = this.createAstService(context.state);
|
|
6550
|
+
const nextState = astService.withCte(name, subAst, columns, recursive);
|
|
6551
|
+
return { state: nextState, hydration: context.hydration };
|
|
5591
6552
|
}
|
|
5592
|
-
const hydrated = hydrateRows(rows, qb.getHydrationPlan());
|
|
5593
|
-
return hydrated.map((row) => createEntityFromRow(entityCtx, qb.getTable(), row, qb.getLazyRelations()));
|
|
5594
6553
|
};
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
6554
|
+
|
|
6555
|
+
// src/query-builder/select/setop-facet.ts
|
|
6556
|
+
var SelectSetOpFacet = class {
|
|
6557
|
+
/**
|
|
6558
|
+
* Creates a new SelectSetOpFacet instance
|
|
6559
|
+
* @param env - Query builder environment
|
|
6560
|
+
* @param createAstService - Function to create AST service
|
|
6561
|
+
*/
|
|
6562
|
+
constructor(env, createAstService) {
|
|
6563
|
+
this.env = env;
|
|
6564
|
+
this.createAstService = createAstService;
|
|
5602
6565
|
}
|
|
5603
|
-
|
|
5604
|
-
|
|
6566
|
+
/**
|
|
6567
|
+
* Applies a set operation to the query
|
|
6568
|
+
* @param context - Current query context
|
|
6569
|
+
* @param operator - Set operation kind
|
|
6570
|
+
* @param subAst - Subquery AST to combine
|
|
6571
|
+
* @returns Updated query context with set operation
|
|
6572
|
+
*/
|
|
6573
|
+
applySetOperation(context, operator, subAst) {
|
|
6574
|
+
const astService = this.createAstService(context.state);
|
|
6575
|
+
const nextState = astService.withSetOperation(operator, subAst);
|
|
6576
|
+
return { state: nextState, hydration: context.hydration };
|
|
6577
|
+
}
|
|
6578
|
+
};
|
|
5605
6579
|
|
|
5606
|
-
// src/query-builder/
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
6580
|
+
// src/query-builder/select/relation-facet.ts
|
|
6581
|
+
var SelectRelationFacet = class {
|
|
6582
|
+
/**
|
|
6583
|
+
* Creates a new SelectRelationFacet instance
|
|
6584
|
+
* @param relationManager - Relation manager dependency
|
|
6585
|
+
*/
|
|
6586
|
+
constructor(relationManager) {
|
|
6587
|
+
this.relationManager = relationManager;
|
|
6588
|
+
}
|
|
6589
|
+
/**
|
|
6590
|
+
* Matches records based on a relationship
|
|
6591
|
+
* @param context - Current query context
|
|
6592
|
+
* @param relationName - Name of the relationship
|
|
6593
|
+
* @param predicate - Optional predicate
|
|
6594
|
+
* @returns Updated query context with relation match
|
|
6595
|
+
*/
|
|
6596
|
+
match(context, relationName, predicate) {
|
|
6597
|
+
return this.relationManager.match(context, relationName, predicate);
|
|
6598
|
+
}
|
|
6599
|
+
/**
|
|
6600
|
+
* Joins a related table
|
|
6601
|
+
* @param context - Current query context
|
|
6602
|
+
* @param relationName - Name of the relationship
|
|
6603
|
+
* @param joinKind - Type of join
|
|
6604
|
+
* @param extraCondition - Optional additional condition
|
|
6605
|
+
* @returns Updated query context with relation join
|
|
6606
|
+
*/
|
|
6607
|
+
joinRelation(context, relationName, joinKind, extraCondition) {
|
|
6608
|
+
return this.relationManager.joinRelation(context, relationName, joinKind, extraCondition);
|
|
6609
|
+
}
|
|
6610
|
+
/**
|
|
6611
|
+
* Includes related data in the query results
|
|
6612
|
+
* @param context - Current query context
|
|
6613
|
+
* @param relationName - Name of the relationship to include
|
|
6614
|
+
* @param options - Optional include options
|
|
6615
|
+
* @returns Updated query context with relation inclusion
|
|
6616
|
+
*/
|
|
6617
|
+
include(context, relationName, options) {
|
|
6618
|
+
return this.relationManager.include(context, relationName, options);
|
|
6619
|
+
}
|
|
6620
|
+
/**
|
|
6621
|
+
* Applies correlation for relation-based subqueries
|
|
6622
|
+
* @param context - Current query context
|
|
6623
|
+
* @param relationName - Name of the relationship
|
|
6624
|
+
* @param subAst - Subquery AST
|
|
6625
|
+
* @param extraCorrelate - Optional additional correlation
|
|
6626
|
+
* @returns Modified subquery AST with correlation
|
|
6627
|
+
*/
|
|
6628
|
+
applyRelationCorrelation(context, relationName, subAst, extraCorrelate) {
|
|
6629
|
+
return this.relationManager.applyRelationCorrelation(context, relationName, subAst, extraCorrelate);
|
|
6630
|
+
}
|
|
6631
|
+
};
|
|
5611
6632
|
|
|
5612
6633
|
// src/query-builder/select.ts
|
|
5613
6634
|
var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
6635
|
+
env;
|
|
6636
|
+
context;
|
|
6637
|
+
columnSelector;
|
|
6638
|
+
fromFacet;
|
|
6639
|
+
joinFacet;
|
|
6640
|
+
projectionFacet;
|
|
6641
|
+
predicateFacet;
|
|
6642
|
+
cteFacet;
|
|
6643
|
+
setOpFacet;
|
|
6644
|
+
relationFacet;
|
|
6645
|
+
lazyRelations;
|
|
6646
|
+
lazyRelationOptions;
|
|
5614
6647
|
/**
|
|
5615
6648
|
* Creates a new SelectQueryBuilder instance
|
|
5616
6649
|
* @param table - Table definition to query
|
|
@@ -5618,9 +6651,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5618
6651
|
* @param hydration - Optional hydration manager
|
|
5619
6652
|
* @param dependencies - Optional query builder dependencies
|
|
5620
6653
|
*/
|
|
5621
|
-
constructor(table, state, hydration, dependencies, lazyRelations) {
|
|
6654
|
+
constructor(table, state, hydration, dependencies, lazyRelations, lazyRelationOptions) {
|
|
5622
6655
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
5623
6656
|
this.env = { table, deps };
|
|
6657
|
+
const createAstService = (nextState) => deps.createQueryAstService(table, nextState);
|
|
5624
6658
|
const initialState = state ?? deps.createState(table);
|
|
5625
6659
|
const initialHydration = hydration ?? deps.createHydration(table);
|
|
5626
6660
|
this.context = {
|
|
@@ -5628,8 +6662,16 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5628
6662
|
hydration: initialHydration
|
|
5629
6663
|
};
|
|
5630
6664
|
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
6665
|
+
this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
|
|
5631
6666
|
this.columnSelector = deps.createColumnSelector(this.env);
|
|
5632
|
-
|
|
6667
|
+
const relationManager = deps.createRelationManager(this.env);
|
|
6668
|
+
this.fromFacet = new SelectFromFacet(this.env, createAstService);
|
|
6669
|
+
this.joinFacet = new SelectJoinFacet(this.env, createAstService);
|
|
6670
|
+
this.projectionFacet = new SelectProjectionFacet(this.columnSelector);
|
|
6671
|
+
this.predicateFacet = new SelectPredicateFacet(this.env, createAstService);
|
|
6672
|
+
this.cteFacet = new SelectCTEFacet(this.env, createAstService);
|
|
6673
|
+
this.setOpFacet = new SelectSetOpFacet(this.env, createAstService);
|
|
6674
|
+
this.relationFacet = new SelectRelationFacet(relationManager);
|
|
5633
6675
|
}
|
|
5634
6676
|
/**
|
|
5635
6677
|
* Creates a new SelectQueryBuilder instance with updated context and lazy relations
|
|
@@ -5637,20 +6679,22 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5637
6679
|
* @param lazyRelations - Updated lazy relations set
|
|
5638
6680
|
* @returns New SelectQueryBuilder instance
|
|
5639
6681
|
*/
|
|
5640
|
-
clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
|
|
5641
|
-
return new _SelectQueryBuilder(
|
|
6682
|
+
clone(context = this.context, lazyRelations = new Set(this.lazyRelations), lazyRelationOptions = new Map(this.lazyRelationOptions)) {
|
|
6683
|
+
return new _SelectQueryBuilder(
|
|
6684
|
+
this.env.table,
|
|
6685
|
+
context.state,
|
|
6686
|
+
context.hydration,
|
|
6687
|
+
this.env.deps,
|
|
6688
|
+
lazyRelations,
|
|
6689
|
+
lazyRelationOptions
|
|
6690
|
+
);
|
|
5642
6691
|
}
|
|
5643
6692
|
/**
|
|
5644
6693
|
* Applies an alias to the root FROM table.
|
|
5645
6694
|
* @param alias - Alias to apply
|
|
5646
6695
|
*/
|
|
5647
6696
|
as(alias) {
|
|
5648
|
-
const
|
|
5649
|
-
if (from.type !== "Table") {
|
|
5650
|
-
throw new Error("Cannot alias non-table FROM sources");
|
|
5651
|
-
}
|
|
5652
|
-
const nextFrom = { ...from, alias };
|
|
5653
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
|
|
6697
|
+
const nextContext = this.fromFacet.as(this.context, alias);
|
|
5654
6698
|
return this.clone(nextContext);
|
|
5655
6699
|
}
|
|
5656
6700
|
/**
|
|
@@ -5675,29 +6719,6 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5675
6719
|
createChildBuilder(table) {
|
|
5676
6720
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
5677
6721
|
}
|
|
5678
|
-
/**
|
|
5679
|
-
* Applies an AST mutation using the query AST service
|
|
5680
|
-
* @param context - Current query context
|
|
5681
|
-
* @param mutator - Function that mutates the AST
|
|
5682
|
-
* @returns Updated query context
|
|
5683
|
-
*/
|
|
5684
|
-
applyAst(context, mutator) {
|
|
5685
|
-
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
5686
|
-
const nextState = mutator(astService);
|
|
5687
|
-
return { state: nextState, hydration: context.hydration };
|
|
5688
|
-
}
|
|
5689
|
-
/**
|
|
5690
|
-
* Applies a join to the query context
|
|
5691
|
-
* @param context - Current query context
|
|
5692
|
-
* @param table - Table to join
|
|
5693
|
-
* @param condition - Join condition
|
|
5694
|
-
* @param kind - Join kind
|
|
5695
|
-
* @returns Updated query context with join applied
|
|
5696
|
-
*/
|
|
5697
|
-
applyJoin(context, table, condition, kind) {
|
|
5698
|
-
const joinNode = createJoinNode(kind, { type: "Table", name: table.name, schema: table.schema }, condition);
|
|
5699
|
-
return this.applyAst(context, (service) => service.withJoin(joinNode));
|
|
5700
|
-
}
|
|
5701
6722
|
/**
|
|
5702
6723
|
* Applies a set operation to the query
|
|
5703
6724
|
* @param operator - Set operation kind
|
|
@@ -5706,12 +6727,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5706
6727
|
*/
|
|
5707
6728
|
applySetOperation(operator, query) {
|
|
5708
6729
|
const subAst = resolveSelectQuery(query);
|
|
5709
|
-
return this.
|
|
6730
|
+
return this.setOpFacet.applySetOperation(this.context, operator, subAst);
|
|
5710
6731
|
}
|
|
5711
6732
|
select(...args) {
|
|
5712
6733
|
if (args.length === 1 && typeof args[0] === "object" && args[0] !== null && typeof args[0] !== "string") {
|
|
5713
6734
|
const columns = args[0];
|
|
5714
|
-
return this.clone(this.
|
|
6735
|
+
return this.clone(this.projectionFacet.select(this.context, columns));
|
|
5715
6736
|
}
|
|
5716
6737
|
const cols = args;
|
|
5717
6738
|
const selection = {};
|
|
@@ -5722,7 +6743,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5722
6743
|
}
|
|
5723
6744
|
selection[key] = col2;
|
|
5724
6745
|
}
|
|
5725
|
-
return this.clone(this.
|
|
6746
|
+
return this.clone(this.projectionFacet.select(this.context, selection));
|
|
5726
6747
|
}
|
|
5727
6748
|
/**
|
|
5728
6749
|
* Selects raw column expressions
|
|
@@ -5730,7 +6751,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5730
6751
|
* @returns New query builder instance with raw column selections
|
|
5731
6752
|
*/
|
|
5732
6753
|
selectRaw(...cols) {
|
|
5733
|
-
return this.clone(this.
|
|
6754
|
+
return this.clone(this.projectionFacet.selectRaw(this.context, cols));
|
|
5734
6755
|
}
|
|
5735
6756
|
/**
|
|
5736
6757
|
* Adds a Common Table Expression (CTE) to the query
|
|
@@ -5741,7 +6762,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5741
6762
|
*/
|
|
5742
6763
|
with(name, query, columns) {
|
|
5743
6764
|
const subAst = resolveSelectQuery(query);
|
|
5744
|
-
const nextContext = this.
|
|
6765
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, false);
|
|
5745
6766
|
return this.clone(nextContext);
|
|
5746
6767
|
}
|
|
5747
6768
|
/**
|
|
@@ -5753,7 +6774,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5753
6774
|
*/
|
|
5754
6775
|
withRecursive(name, query, columns) {
|
|
5755
6776
|
const subAst = resolveSelectQuery(query);
|
|
5756
|
-
const nextContext = this.
|
|
6777
|
+
const nextContext = this.cteFacet.withCTE(this.context, name, subAst, columns, true);
|
|
5757
6778
|
return this.clone(nextContext);
|
|
5758
6779
|
}
|
|
5759
6780
|
/**
|
|
@@ -5765,8 +6786,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5765
6786
|
*/
|
|
5766
6787
|
fromSubquery(subquery, alias, columnAliases) {
|
|
5767
6788
|
const subAst = resolveSelectQuery(subquery);
|
|
5768
|
-
const
|
|
5769
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
|
|
6789
|
+
const nextContext = this.fromFacet.fromSubquery(this.context, subAst, alias, columnAliases);
|
|
5770
6790
|
return this.clone(nextContext);
|
|
5771
6791
|
}
|
|
5772
6792
|
/**
|
|
@@ -5777,8 +6797,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5777
6797
|
* @param options - Optional function-table metadata (lateral, ordinality, column aliases, schema)
|
|
5778
6798
|
*/
|
|
5779
6799
|
fromFunctionTable(name, args = [], alias, options) {
|
|
5780
|
-
const
|
|
5781
|
-
const nextContext = this.applyAst(this.context, (service) => service.withFrom(functionTable));
|
|
6800
|
+
const nextContext = this.fromFacet.fromFunctionTable(this.context, name, args, alias, options);
|
|
5782
6801
|
return this.clone(nextContext);
|
|
5783
6802
|
}
|
|
5784
6803
|
/**
|
|
@@ -5789,7 +6808,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5789
6808
|
*/
|
|
5790
6809
|
selectSubquery(alias, sub2) {
|
|
5791
6810
|
const query = resolveSelectQuery(sub2);
|
|
5792
|
-
return this.clone(this.
|
|
6811
|
+
return this.clone(this.projectionFacet.selectSubquery(this.context, alias, query));
|
|
5793
6812
|
}
|
|
5794
6813
|
/**
|
|
5795
6814
|
* Adds a JOIN against a derived table (subquery with alias)
|
|
@@ -5802,8 +6821,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5802
6821
|
*/
|
|
5803
6822
|
joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
|
|
5804
6823
|
const subAst = resolveSelectQuery(subquery);
|
|
5805
|
-
const
|
|
5806
|
-
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
6824
|
+
const nextContext = this.joinFacet.joinSubquery(this.context, subAst, alias, condition, joinKind, columnAliases);
|
|
5807
6825
|
return this.clone(nextContext);
|
|
5808
6826
|
}
|
|
5809
6827
|
/**
|
|
@@ -5816,9 +6834,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5816
6834
|
* @param options - Optional metadata (lateral, ordinality, column aliases, schema)
|
|
5817
6835
|
*/
|
|
5818
6836
|
joinFunctionTable(name, args = [], alias, condition, joinKind = JOIN_KINDS.INNER, options) {
|
|
5819
|
-
const
|
|
5820
|
-
const joinNode = createJoinNode(joinKind, functionTable, condition);
|
|
5821
|
-
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
6837
|
+
const nextContext = this.joinFacet.joinFunctionTable(this.context, name, args, alias, condition, joinKind, options);
|
|
5822
6838
|
return this.clone(nextContext);
|
|
5823
6839
|
}
|
|
5824
6840
|
/**
|
|
@@ -5828,7 +6844,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5828
6844
|
* @returns New query builder instance with the INNER JOIN
|
|
5829
6845
|
*/
|
|
5830
6846
|
innerJoin(table, condition) {
|
|
5831
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
6847
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
5832
6848
|
return this.clone(nextContext);
|
|
5833
6849
|
}
|
|
5834
6850
|
/**
|
|
@@ -5838,7 +6854,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5838
6854
|
* @returns New query builder instance with the LEFT JOIN
|
|
5839
6855
|
*/
|
|
5840
6856
|
leftJoin(table, condition) {
|
|
5841
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
6857
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
5842
6858
|
return this.clone(nextContext);
|
|
5843
6859
|
}
|
|
5844
6860
|
/**
|
|
@@ -5848,7 +6864,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5848
6864
|
* @returns New query builder instance with the RIGHT JOIN
|
|
5849
6865
|
*/
|
|
5850
6866
|
rightJoin(table, condition) {
|
|
5851
|
-
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
6867
|
+
const nextContext = this.joinFacet.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
5852
6868
|
return this.clone(nextContext);
|
|
5853
6869
|
}
|
|
5854
6870
|
/**
|
|
@@ -5858,7 +6874,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5858
6874
|
* @returns New query builder instance with the relationship match
|
|
5859
6875
|
*/
|
|
5860
6876
|
match(relationName, predicate) {
|
|
5861
|
-
const nextContext = this.
|
|
6877
|
+
const nextContext = this.relationFacet.match(this.context, relationName, predicate);
|
|
5862
6878
|
return this.clone(nextContext);
|
|
5863
6879
|
}
|
|
5864
6880
|
/**
|
|
@@ -5869,7 +6885,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5869
6885
|
* @returns New query builder instance with the relationship join
|
|
5870
6886
|
*/
|
|
5871
6887
|
joinRelation(relationName, joinKind = JOIN_KINDS.INNER, extraCondition) {
|
|
5872
|
-
const nextContext = this.
|
|
6888
|
+
const nextContext = this.relationFacet.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
5873
6889
|
return this.clone(nextContext);
|
|
5874
6890
|
}
|
|
5875
6891
|
/**
|
|
@@ -5879,42 +6895,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5879
6895
|
* @returns New query builder instance with the relationship inclusion
|
|
5880
6896
|
*/
|
|
5881
6897
|
include(relationName, options) {
|
|
5882
|
-
const nextContext = this.
|
|
6898
|
+
const nextContext = this.relationFacet.include(this.context, relationName, options);
|
|
5883
6899
|
return this.clone(nextContext);
|
|
5884
6900
|
}
|
|
5885
6901
|
/**
|
|
5886
6902
|
* Includes a relation lazily in the query results
|
|
5887
6903
|
* @param relationName - Name of the relation to include lazily
|
|
6904
|
+
* @param options - Optional include options for lazy loading
|
|
5888
6905
|
* @returns New query builder instance with lazy relation inclusion
|
|
5889
6906
|
*/
|
|
5890
|
-
includeLazy(relationName) {
|
|
5891
|
-
|
|
5892
|
-
nextLazy.add(relationName);
|
|
5893
|
-
return this.clone(this.context, nextLazy);
|
|
5894
|
-
}
|
|
5895
|
-
/**
|
|
5896
|
-
* Selects columns for a related table in a single hop.
|
|
5897
|
-
*/
|
|
5898
|
-
selectRelationColumns(relationName, ...cols) {
|
|
6907
|
+
includeLazy(relationName, options) {
|
|
6908
|
+
let nextContext = this.context;
|
|
5899
6909
|
const relation = this.env.table.relations[relationName];
|
|
5900
|
-
if (
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
)
|
|
6910
|
+
if (relation?.type === RelationKinds.BelongsTo) {
|
|
6911
|
+
const foreignKey = relation.foreignKey;
|
|
6912
|
+
const fkColumn = this.env.table.columns[foreignKey];
|
|
6913
|
+
if (fkColumn) {
|
|
6914
|
+
const hasAlias2 = nextContext.state.ast.columns.some((col2) => {
|
|
6915
|
+
const node = col2;
|
|
6916
|
+
return (node.alias ?? node.name) === foreignKey;
|
|
6917
|
+
});
|
|
6918
|
+
if (!hasAlias2) {
|
|
6919
|
+
nextContext = this.columnSelector.select(nextContext, { [foreignKey]: fkColumn });
|
|
6920
|
+
}
|
|
5909
6921
|
}
|
|
5910
6922
|
}
|
|
5911
|
-
|
|
6923
|
+
const nextLazy = new Set(this.lazyRelations);
|
|
6924
|
+
nextLazy.add(relationName);
|
|
6925
|
+
const nextOptions = new Map(this.lazyRelationOptions);
|
|
6926
|
+
if (options) {
|
|
6927
|
+
nextOptions.set(relationName, options);
|
|
6928
|
+
} else {
|
|
6929
|
+
nextOptions.delete(relationName);
|
|
6930
|
+
}
|
|
6931
|
+
return this.clone(nextContext, nextLazy, nextOptions);
|
|
5912
6932
|
}
|
|
5913
6933
|
/**
|
|
5914
|
-
* Convenience alias for
|
|
6934
|
+
* Convenience alias for including only specific columns from a relation.
|
|
5915
6935
|
*/
|
|
5916
6936
|
includePick(relationName, cols) {
|
|
5917
|
-
|
|
6937
|
+
const options = { columns: cols };
|
|
6938
|
+
return this.include(relationName, options);
|
|
5918
6939
|
}
|
|
5919
6940
|
/**
|
|
5920
6941
|
* Selects columns for the root table and relations from an array of entries
|
|
@@ -5927,7 +6948,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5927
6948
|
if (entry.type === "root") {
|
|
5928
6949
|
currBuilder = currBuilder.select(...entry.columns);
|
|
5929
6950
|
} else {
|
|
5930
|
-
|
|
6951
|
+
const options = { columns: entry.columns };
|
|
6952
|
+
currBuilder = currBuilder.include(entry.relationName, options);
|
|
5931
6953
|
}
|
|
5932
6954
|
}
|
|
5933
6955
|
return currBuilder;
|
|
@@ -5939,6 +6961,13 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5939
6961
|
getLazyRelations() {
|
|
5940
6962
|
return Array.from(this.lazyRelations);
|
|
5941
6963
|
}
|
|
6964
|
+
/**
|
|
6965
|
+
* Gets lazy relation include options
|
|
6966
|
+
* @returns Map of relation names to include options
|
|
6967
|
+
*/
|
|
6968
|
+
getLazyRelationOptions() {
|
|
6969
|
+
return new Map(this.lazyRelationOptions);
|
|
6970
|
+
}
|
|
5942
6971
|
/**
|
|
5943
6972
|
* Gets the table definition for this query builder
|
|
5944
6973
|
* @returns Table definition
|
|
@@ -5954,51 +6983,23 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
5954
6983
|
async execute(ctx) {
|
|
5955
6984
|
return executeHydrated(ctx, this);
|
|
5956
6985
|
}
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
return this.clone(nextContext);
|
|
5964
|
-
}
|
|
6986
|
+
/**
|
|
6987
|
+
* Executes a count query for the current builder without LIMIT/OFFSET clauses.
|
|
6988
|
+
*
|
|
6989
|
+
* @example
|
|
6990
|
+
* const total = await qb.count(session);
|
|
6991
|
+
*/
|
|
5965
6992
|
async count(session) {
|
|
5966
|
-
|
|
5967
|
-
...this.context.state.ast,
|
|
5968
|
-
orderBy: void 0,
|
|
5969
|
-
limit: void 0,
|
|
5970
|
-
offset: void 0
|
|
5971
|
-
};
|
|
5972
|
-
const subAst = this.withAst(unpagedAst).getAST();
|
|
5973
|
-
const countQuery = {
|
|
5974
|
-
type: "SelectQuery",
|
|
5975
|
-
from: derivedTable(subAst, "__metal_count"),
|
|
5976
|
-
columns: [{ type: "Function", name: "COUNT", args: [], alias: "total" }],
|
|
5977
|
-
joins: []
|
|
5978
|
-
};
|
|
5979
|
-
const execCtx = session.getExecutionContext();
|
|
5980
|
-
const compiled = execCtx.dialect.compileSelect(countQuery);
|
|
5981
|
-
const results = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
|
|
5982
|
-
const value = results[0]?.values?.[0]?.[0];
|
|
5983
|
-
if (typeof value === "number") return value;
|
|
5984
|
-
if (typeof value === "bigint") return Number(value);
|
|
5985
|
-
if (typeof value === "string") return Number(value);
|
|
5986
|
-
return value === null || value === void 0 ? 0 : Number(value);
|
|
6993
|
+
return executeCount(this.context, this.env, session);
|
|
5987
6994
|
}
|
|
6995
|
+
/**
|
|
6996
|
+
* Executes the query and returns both the paged items and the total.
|
|
6997
|
+
*
|
|
6998
|
+
* @example
|
|
6999
|
+
* const { items, totalItems } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
7000
|
+
*/
|
|
5988
7001
|
async executePaged(session, options) {
|
|
5989
|
-
|
|
5990
|
-
if (!Number.isInteger(page) || page < 1) {
|
|
5991
|
-
throw new Error("executePaged: page must be an integer >= 1");
|
|
5992
|
-
}
|
|
5993
|
-
if (!Number.isInteger(pageSize) || pageSize < 1) {
|
|
5994
|
-
throw new Error("executePaged: pageSize must be an integer >= 1");
|
|
5995
|
-
}
|
|
5996
|
-
const offset = (page - 1) * pageSize;
|
|
5997
|
-
const [items, totalItems] = await Promise.all([
|
|
5998
|
-
this.limit(pageSize).offset(offset).execute(session),
|
|
5999
|
-
this.count(session)
|
|
6000
|
-
]);
|
|
6001
|
-
return { items, totalItems };
|
|
7002
|
+
return executePagedQuery(this, session, options, (sess) => this.count(sess));
|
|
6002
7003
|
}
|
|
6003
7004
|
/**
|
|
6004
7005
|
* Executes the query with provided execution and hydration contexts
|
|
@@ -6015,7 +7016,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6015
7016
|
* @returns New query builder instance with the WHERE condition
|
|
6016
7017
|
*/
|
|
6017
7018
|
where(expr) {
|
|
6018
|
-
const nextContext = this.
|
|
7019
|
+
const nextContext = this.predicateFacet.where(this.context, expr);
|
|
6019
7020
|
return this.clone(nextContext);
|
|
6020
7021
|
}
|
|
6021
7022
|
/**
|
|
@@ -6024,7 +7025,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6024
7025
|
* @returns New query builder instance with the GROUP BY clause
|
|
6025
7026
|
*/
|
|
6026
7027
|
groupBy(term) {
|
|
6027
|
-
const nextContext = this.
|
|
7028
|
+
const nextContext = this.predicateFacet.groupBy(this.context, term);
|
|
6028
7029
|
return this.clone(nextContext);
|
|
6029
7030
|
}
|
|
6030
7031
|
/**
|
|
@@ -6033,7 +7034,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6033
7034
|
* @returns New query builder instance with the HAVING condition
|
|
6034
7035
|
*/
|
|
6035
7036
|
having(expr) {
|
|
6036
|
-
const nextContext = this.
|
|
7037
|
+
const nextContext = this.predicateFacet.having(this.context, expr);
|
|
6037
7038
|
return this.clone(nextContext);
|
|
6038
7039
|
}
|
|
6039
7040
|
/**
|
|
@@ -6041,14 +7042,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6041
7042
|
* @param term - Column definition or ordering term to order by
|
|
6042
7043
|
* @param directionOrOptions - Order direction or options (defaults to ASC)
|
|
6043
7044
|
* @returns New query builder instance with the ORDER BY clause
|
|
7045
|
+
*
|
|
7046
|
+
* @example
|
|
7047
|
+
* qb.orderBy(userTable.columns.createdAt, 'DESC');
|
|
6044
7048
|
*/
|
|
6045
7049
|
orderBy(term, directionOrOptions = ORDER_DIRECTIONS.ASC) {
|
|
6046
|
-
const
|
|
6047
|
-
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
6048
|
-
const nextContext = this.applyAst(
|
|
6049
|
-
this.context,
|
|
6050
|
-
(service) => service.withOrderBy(term, dir, options.nulls, options.collation)
|
|
6051
|
-
);
|
|
7050
|
+
const nextContext = applyOrderBy(this.context, this.predicateFacet, term, directionOrOptions);
|
|
6052
7051
|
return this.clone(nextContext);
|
|
6053
7052
|
}
|
|
6054
7053
|
/**
|
|
@@ -6057,7 +7056,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6057
7056
|
* @returns New query builder instance with the DISTINCT clause
|
|
6058
7057
|
*/
|
|
6059
7058
|
distinct(...cols) {
|
|
6060
|
-
return this.clone(this.
|
|
7059
|
+
return this.clone(this.projectionFacet.distinct(this.context, cols));
|
|
6061
7060
|
}
|
|
6062
7061
|
/**
|
|
6063
7062
|
* Adds a LIMIT clause to the query
|
|
@@ -6065,7 +7064,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6065
7064
|
* @returns New query builder instance with the LIMIT clause
|
|
6066
7065
|
*/
|
|
6067
7066
|
limit(n) {
|
|
6068
|
-
const nextContext = this.
|
|
7067
|
+
const nextContext = this.predicateFacet.limit(this.context, n);
|
|
6069
7068
|
return this.clone(nextContext);
|
|
6070
7069
|
}
|
|
6071
7070
|
/**
|
|
@@ -6074,7 +7073,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6074
7073
|
* @returns New query builder instance with the OFFSET clause
|
|
6075
7074
|
*/
|
|
6076
7075
|
offset(n) {
|
|
6077
|
-
const nextContext = this.
|
|
7076
|
+
const nextContext = this.predicateFacet.offset(this.context, n);
|
|
6078
7077
|
return this.clone(nextContext);
|
|
6079
7078
|
}
|
|
6080
7079
|
/**
|
|
@@ -6134,42 +7133,44 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
6134
7133
|
* @param relationName - Name of the relationship to check
|
|
6135
7134
|
* @param callback - Optional callback to modify the relationship query
|
|
6136
7135
|
* @returns New query builder instance with the relationship existence check
|
|
7136
|
+
*
|
|
7137
|
+
* @example
|
|
7138
|
+
* qb.whereHas('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
6137
7139
|
*/
|
|
6138
7140
|
whereHas(relationName, callbackOrOptions, maybeOptions) {
|
|
6139
|
-
const
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
6151
|
-
return this.where(exists(finalSubAst));
|
|
7141
|
+
const predicate = buildWhereHasPredicate(
|
|
7142
|
+
this.env,
|
|
7143
|
+
this.context,
|
|
7144
|
+
this.relationFacet,
|
|
7145
|
+
(table) => this.createChildBuilder(table),
|
|
7146
|
+
relationName,
|
|
7147
|
+
callbackOrOptions,
|
|
7148
|
+
maybeOptions,
|
|
7149
|
+
false
|
|
7150
|
+
);
|
|
7151
|
+
return this.where(predicate);
|
|
6152
7152
|
}
|
|
6153
7153
|
/**
|
|
6154
7154
|
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
6155
7155
|
* @param relationName - Name of the relationship to check
|
|
6156
7156
|
* @param callback - Optional callback to modify the relationship query
|
|
6157
7157
|
* @returns New query builder instance with the relationship non-existence check
|
|
7158
|
+
*
|
|
7159
|
+
* @example
|
|
7160
|
+
* qb.whereHasNot('posts', postQb => postQb.where(eq(postTable.columns.published, true)));
|
|
6158
7161
|
*/
|
|
6159
7162
|
whereHasNot(relationName, callbackOrOptions, maybeOptions) {
|
|
6160
|
-
const
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
6172
|
-
return this.where(notExists(finalSubAst));
|
|
7163
|
+
const predicate = buildWhereHasPredicate(
|
|
7164
|
+
this.env,
|
|
7165
|
+
this.context,
|
|
7166
|
+
this.relationFacet,
|
|
7167
|
+
(table) => this.createChildBuilder(table),
|
|
7168
|
+
relationName,
|
|
7169
|
+
callbackOrOptions,
|
|
7170
|
+
maybeOptions,
|
|
7171
|
+
true
|
|
7172
|
+
);
|
|
7173
|
+
return this.where(predicate);
|
|
6173
7174
|
}
|
|
6174
7175
|
/**
|
|
6175
7176
|
* Compiles the query to SQL for a specific dialect
|
|
@@ -6301,23 +7302,44 @@ var resolveTableTarget = (target, tableMap) => {
|
|
|
6301
7302
|
}
|
|
6302
7303
|
return table;
|
|
6303
7304
|
};
|
|
7305
|
+
var toSnakeCase = (value) => {
|
|
7306
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
7307
|
+
};
|
|
7308
|
+
var normalizeEntityName = (value) => {
|
|
7309
|
+
const stripped = value.replace(/Entity$/i, "");
|
|
7310
|
+
const normalized = toSnakeCase(stripped || value);
|
|
7311
|
+
return normalized || "unknown";
|
|
7312
|
+
};
|
|
7313
|
+
var getPivotKeyBaseFromTarget = (target) => {
|
|
7314
|
+
const resolved = unwrapTarget(target);
|
|
7315
|
+
if (isTableDef(resolved)) {
|
|
7316
|
+
return toSnakeCase(resolved.name || "unknown");
|
|
7317
|
+
}
|
|
7318
|
+
const ctor = resolved;
|
|
7319
|
+
return normalizeEntityName(ctor.name || "unknown");
|
|
7320
|
+
};
|
|
7321
|
+
var getPivotKeyBaseFromRoot = (meta) => {
|
|
7322
|
+
return normalizeEntityName(meta.target.name || meta.tableName || "unknown");
|
|
7323
|
+
};
|
|
6304
7324
|
var buildRelationDefinitions = (meta, tableMap) => {
|
|
6305
7325
|
const relations = {};
|
|
6306
7326
|
for (const [name, relation] of Object.entries(meta.relations)) {
|
|
6307
7327
|
switch (relation.kind) {
|
|
6308
7328
|
case RelationKinds.HasOne: {
|
|
7329
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6309
7330
|
relations[name] = hasOne(
|
|
6310
7331
|
resolveTableTarget(relation.target, tableMap),
|
|
6311
|
-
|
|
7332
|
+
foreignKey,
|
|
6312
7333
|
relation.localKey,
|
|
6313
7334
|
relation.cascade
|
|
6314
7335
|
);
|
|
6315
7336
|
break;
|
|
6316
7337
|
}
|
|
6317
7338
|
case RelationKinds.HasMany: {
|
|
7339
|
+
const foreignKey = relation.foreignKey ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
6318
7340
|
relations[name] = hasMany(
|
|
6319
7341
|
resolveTableTarget(relation.target, tableMap),
|
|
6320
|
-
|
|
7342
|
+
foreignKey,
|
|
6321
7343
|
relation.localKey,
|
|
6322
7344
|
relation.cascade
|
|
6323
7345
|
);
|
|
@@ -6333,12 +7355,14 @@ var buildRelationDefinitions = (meta, tableMap) => {
|
|
|
6333
7355
|
break;
|
|
6334
7356
|
}
|
|
6335
7357
|
case RelationKinds.BelongsToMany: {
|
|
7358
|
+
const pivotForeignKeyToRoot = relation.pivotForeignKeyToRoot ?? `${getPivotKeyBaseFromRoot(meta)}_id`;
|
|
7359
|
+
const pivotForeignKeyToTarget = relation.pivotForeignKeyToTarget ?? `${getPivotKeyBaseFromTarget(relation.target)}_id`;
|
|
6336
7360
|
relations[name] = belongsToMany(
|
|
6337
7361
|
resolveTableTarget(relation.target, tableMap),
|
|
6338
7362
|
resolveTableTarget(relation.pivotTable, tableMap),
|
|
6339
7363
|
{
|
|
6340
|
-
pivotForeignKeyToRoot
|
|
6341
|
-
pivotForeignKeyToTarget
|
|
7364
|
+
pivotForeignKeyToRoot,
|
|
7365
|
+
pivotForeignKeyToTarget,
|
|
6342
7366
|
localKey: relation.localKey,
|
|
6343
7367
|
targetKey: relation.targetKey,
|
|
6344
7368
|
pivotPrimaryKey: relation.pivotPrimaryKey,
|
|
@@ -6419,6 +7443,8 @@ function esel(entity, ...props) {
|
|
|
6419
7443
|
|
|
6420
7444
|
// src/query-builder/insert-query-state.ts
|
|
6421
7445
|
var InsertQueryState = class _InsertQueryState {
|
|
7446
|
+
table;
|
|
7447
|
+
ast;
|
|
6422
7448
|
/**
|
|
6423
7449
|
* Creates a new InsertQueryState instance
|
|
6424
7450
|
* @param table - The table definition for the INSERT query
|
|
@@ -6539,6 +7565,8 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
6539
7565
|
|
|
6540
7566
|
// src/query-builder/insert.ts
|
|
6541
7567
|
var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
7568
|
+
table;
|
|
7569
|
+
state;
|
|
6542
7570
|
/**
|
|
6543
7571
|
* Creates a new InsertQueryBuilder instance
|
|
6544
7572
|
* @param table - The table definition for the INSERT query
|
|
@@ -6638,6 +7666,8 @@ var isUpdateValue = (value) => {
|
|
|
6638
7666
|
}
|
|
6639
7667
|
};
|
|
6640
7668
|
var UpdateQueryState = class _UpdateQueryState {
|
|
7669
|
+
table;
|
|
7670
|
+
ast;
|
|
6641
7671
|
/**
|
|
6642
7672
|
* Creates a new UpdateQueryState instance
|
|
6643
7673
|
* @param table - Table definition for the update
|
|
@@ -6748,6 +7778,8 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
6748
7778
|
|
|
6749
7779
|
// src/query-builder/update.ts
|
|
6750
7780
|
var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
7781
|
+
table;
|
|
7782
|
+
state;
|
|
6751
7783
|
/**
|
|
6752
7784
|
* Creates a new UpdateQueryBuilder instance
|
|
6753
7785
|
* @param table - The table definition for the UPDATE query
|
|
@@ -6865,6 +7897,8 @@ var isTableSourceNode = (source) => typeof source.type === "string";
|
|
|
6865
7897
|
|
|
6866
7898
|
// src/query-builder/delete-query-state.ts
|
|
6867
7899
|
var DeleteQueryState = class _DeleteQueryState {
|
|
7900
|
+
table;
|
|
7901
|
+
ast;
|
|
6868
7902
|
/**
|
|
6869
7903
|
* Creates a new DeleteQueryState instance
|
|
6870
7904
|
* @param table - The table definition for the DELETE query
|
|
@@ -6943,6 +7977,8 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
6943
7977
|
|
|
6944
7978
|
// src/query-builder/delete.ts
|
|
6945
7979
|
var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
7980
|
+
table;
|
|
7981
|
+
state;
|
|
6946
7982
|
/**
|
|
6947
7983
|
* Creates a new DeleteQueryBuilder instance
|
|
6948
7984
|
* @param table - The table definition for the DELETE query
|
|
@@ -7070,7 +8106,8 @@ var renderColumnDefinition = (table, col2, dialect, options = {}) => {
|
|
|
7070
8106
|
if (col2.default !== void 0) {
|
|
7071
8107
|
parts.push(`DEFAULT ${dialect.renderDefault(col2.default, col2)}`);
|
|
7072
8108
|
}
|
|
7073
|
-
|
|
8109
|
+
const autoIncIncludesPrimary = typeof autoInc === "string" && /\bPRIMARY\s+KEY\b/i.test(autoInc);
|
|
8110
|
+
if (options.includePrimary && col2.primary && !autoIncIncludesPrimary) {
|
|
7074
8111
|
parts.push("PRIMARY KEY");
|
|
7075
8112
|
}
|
|
7076
8113
|
if (col2.check) {
|
|
@@ -7128,6 +8165,16 @@ var generateSchemaSql = (tables, dialect) => {
|
|
|
7128
8165
|
});
|
|
7129
8166
|
return statements;
|
|
7130
8167
|
};
|
|
8168
|
+
var generateSchemaSqlFor = (dialect, ...tables) => generateSchemaSql(tables, dialect);
|
|
8169
|
+
var executeSchemaSql = async (executor, tables, dialect) => {
|
|
8170
|
+
const statements = generateSchemaSql(tables, dialect);
|
|
8171
|
+
for (const sql of statements) {
|
|
8172
|
+
await executor.executeSql(sql);
|
|
8173
|
+
}
|
|
8174
|
+
};
|
|
8175
|
+
var executeSchemaSqlFor = async (executor, dialect, ...tables) => {
|
|
8176
|
+
await executeSchemaSql(executor, tables, dialect);
|
|
8177
|
+
};
|
|
7131
8178
|
var orderTablesByDependencies = (tables) => {
|
|
7132
8179
|
const map = /* @__PURE__ */ new Map();
|
|
7133
8180
|
tables.forEach((t) => map.set(t.name, t));
|
|
@@ -9034,6 +10081,7 @@ var arrayAppend = (array, value) => fn7("ARRAY_APPEND", [array, value]);
|
|
|
9034
10081
|
|
|
9035
10082
|
// src/orm/als.ts
|
|
9036
10083
|
var AsyncLocalStorage = class {
|
|
10084
|
+
store;
|
|
9037
10085
|
/**
|
|
9038
10086
|
* Executes a callback function within a context containing the specified store value.
|
|
9039
10087
|
* The store value is only available during the callback's execution and is automatically
|
|
@@ -9530,9 +10578,7 @@ var TypeScriptGenerator = class {
|
|
|
9530
10578
|
|
|
9531
10579
|
// src/orm/identity-map.ts
|
|
9532
10580
|
var IdentityMap = class {
|
|
9533
|
-
|
|
9534
|
-
this.buckets = /* @__PURE__ */ new Map();
|
|
9535
|
-
}
|
|
10581
|
+
buckets = /* @__PURE__ */ new Map();
|
|
9536
10582
|
get bucketsMap() {
|
|
9537
10583
|
return this.buckets;
|
|
9538
10584
|
}
|
|
@@ -9602,8 +10648,8 @@ var UnitOfWork = class {
|
|
|
9602
10648
|
this.executor = executor;
|
|
9603
10649
|
this.identityMap = identityMap;
|
|
9604
10650
|
this.hookContext = hookContext;
|
|
9605
|
-
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
9606
10651
|
}
|
|
10652
|
+
trackedEntities = /* @__PURE__ */ new Map();
|
|
9607
10653
|
/**
|
|
9608
10654
|
* Gets the identity buckets map.
|
|
9609
10655
|
*/
|
|
@@ -9933,12 +10979,12 @@ var UnitOfWork = class {
|
|
|
9933
10979
|
|
|
9934
10980
|
// src/orm/domain-event-bus.ts
|
|
9935
10981
|
var DomainEventBus = class {
|
|
10982
|
+
handlers = /* @__PURE__ */ new Map();
|
|
9936
10983
|
/**
|
|
9937
10984
|
* Creates a new DomainEventBus instance.
|
|
9938
10985
|
* @param initialHandlers - Optional initial event handlers
|
|
9939
10986
|
*/
|
|
9940
10987
|
constructor(initialHandlers) {
|
|
9941
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
9942
10988
|
if (initialHandlers) {
|
|
9943
10989
|
for (const key in initialHandlers) {
|
|
9944
10990
|
const type = key;
|
|
@@ -10007,8 +11053,8 @@ var RelationChangeProcessor = class {
|
|
|
10007
11053
|
this.unitOfWork = unitOfWork;
|
|
10008
11054
|
this.dialect = dialect;
|
|
10009
11055
|
this.executor = executor;
|
|
10010
|
-
this.relationChanges = [];
|
|
10011
11056
|
}
|
|
11057
|
+
relationChanges = [];
|
|
10012
11058
|
/**
|
|
10013
11059
|
* Registers a relation change for processing.
|
|
10014
11060
|
* @param entry - The relation change entry
|
|
@@ -10442,25 +11488,24 @@ var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
|
|
|
10442
11488
|
|
|
10443
11489
|
// src/orm/orm-session.ts
|
|
10444
11490
|
var OrmSession = class {
|
|
11491
|
+
/** The ORM instance */
|
|
11492
|
+
orm;
|
|
11493
|
+
/** The database executor */
|
|
11494
|
+
executor;
|
|
11495
|
+
/** The identity map for tracking entity instances */
|
|
11496
|
+
identityMap;
|
|
11497
|
+
/** The unit of work for tracking entity changes */
|
|
11498
|
+
unitOfWork;
|
|
11499
|
+
/** The domain event bus */
|
|
11500
|
+
domainEvents;
|
|
11501
|
+
/** The relation change processor */
|
|
11502
|
+
relationChanges;
|
|
11503
|
+
interceptors;
|
|
10445
11504
|
/**
|
|
10446
11505
|
* Creates a new OrmSession instance.
|
|
10447
11506
|
* @param opts - Session options
|
|
10448
11507
|
*/
|
|
10449
11508
|
constructor(opts) {
|
|
10450
|
-
/**
|
|
10451
|
-
* Registers a relation change.
|
|
10452
|
-
* @param root - The root entity
|
|
10453
|
-
* @param relationKey - The relation key
|
|
10454
|
-
* @param rootTable - The root table definition
|
|
10455
|
-
* @param relationName - The relation name
|
|
10456
|
-
* @param relation - The relation definition
|
|
10457
|
-
* @param change - The relation change
|
|
10458
|
-
*/
|
|
10459
|
-
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
10460
|
-
this.relationChanges.registerChange(
|
|
10461
|
-
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
10462
|
-
);
|
|
10463
|
-
};
|
|
10464
11509
|
this.orm = opts.orm;
|
|
10465
11510
|
this.executor = createQueryLoggingExecutor(opts.executor, opts.queryLogger);
|
|
10466
11511
|
this.interceptors = [...opts.interceptors ?? []];
|
|
@@ -10549,6 +11594,20 @@ var OrmSession = class {
|
|
|
10549
11594
|
markRemoved(entity) {
|
|
10550
11595
|
this.unitOfWork.markRemoved(entity);
|
|
10551
11596
|
}
|
|
11597
|
+
/**
|
|
11598
|
+
* Registers a relation change.
|
|
11599
|
+
* @param root - The root entity
|
|
11600
|
+
* @param relationKey - The relation key
|
|
11601
|
+
* @param rootTable - The root table definition
|
|
11602
|
+
* @param relationName - The relation name
|
|
11603
|
+
* @param relation - The relation definition
|
|
11604
|
+
* @param change - The relation change
|
|
11605
|
+
*/
|
|
11606
|
+
registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
11607
|
+
this.relationChanges.registerChange(
|
|
11608
|
+
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
11609
|
+
);
|
|
11610
|
+
};
|
|
10552
11611
|
/**
|
|
10553
11612
|
* Gets all tracked entities for a specific table.
|
|
10554
11613
|
* @param table - The table definition
|
|
@@ -10754,9 +11813,7 @@ var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, rela
|
|
|
10754
11813
|
|
|
10755
11814
|
// src/orm/interceptor-pipeline.ts
|
|
10756
11815
|
var InterceptorPipeline = class {
|
|
10757
|
-
|
|
10758
|
-
this.interceptors = [];
|
|
10759
|
-
}
|
|
11816
|
+
interceptors = [];
|
|
10760
11817
|
use(interceptor) {
|
|
10761
11818
|
this.interceptors.push(interceptor);
|
|
10762
11819
|
}
|
|
@@ -10775,6 +11832,13 @@ var InterceptorPipeline = class {
|
|
|
10775
11832
|
|
|
10776
11833
|
// src/orm/orm.ts
|
|
10777
11834
|
var Orm = class {
|
|
11835
|
+
/** The database dialect */
|
|
11836
|
+
dialect;
|
|
11837
|
+
/** The interceptors pipeline */
|
|
11838
|
+
interceptors;
|
|
11839
|
+
/** The naming strategy */
|
|
11840
|
+
namingStrategy;
|
|
11841
|
+
executorFactory;
|
|
10778
11842
|
/**
|
|
10779
11843
|
* Creates a new ORM instance.
|
|
10780
11844
|
* @param opts - ORM options
|
|
@@ -10831,17 +11895,13 @@ var jsonify = (value) => {
|
|
|
10831
11895
|
|
|
10832
11896
|
// src/decorators/decorator-metadata.ts
|
|
10833
11897
|
var METADATA_KEY = "metal-orm:decorators";
|
|
10834
|
-
var isStandardDecoratorContext = (value) => {
|
|
10835
|
-
return typeof value === "object" && value !== null && "kind" in value;
|
|
10836
|
-
};
|
|
10837
11898
|
var getOrCreateMetadataBag = (context) => {
|
|
10838
11899
|
const metadata = context.metadata || (context.metadata = {});
|
|
10839
|
-
|
|
10840
|
-
if (
|
|
10841
|
-
|
|
11900
|
+
let bag = metadata[METADATA_KEY];
|
|
11901
|
+
if (!bag) {
|
|
11902
|
+
bag = { columns: [], relations: [] };
|
|
11903
|
+
metadata[METADATA_KEY] = bag;
|
|
10842
11904
|
}
|
|
10843
|
-
const bag = { columns: [], relations: [] };
|
|
10844
|
-
metadata[METADATA_KEY] = bag;
|
|
10845
11905
|
return bag;
|
|
10846
11906
|
};
|
|
10847
11907
|
var readMetadataBag = (context) => {
|
|
@@ -10856,57 +11916,50 @@ var readMetadataBagFromConstructor = (ctor) => {
|
|
|
10856
11916
|
var getDecoratorMetadata = (ctor) => readMetadataBagFromConstructor(ctor);
|
|
10857
11917
|
|
|
10858
11918
|
// src/decorators/entity.ts
|
|
10859
|
-
var
|
|
11919
|
+
var toSnakeCase2 = (value) => {
|
|
10860
11920
|
return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_]+/gi, "_").replace(/__+/g, "_").replace(/^_|_$/g, "").toLowerCase();
|
|
10861
11921
|
};
|
|
10862
11922
|
var deriveTableNameFromConstructor = (ctor) => {
|
|
10863
11923
|
const fallback = "unknown";
|
|
10864
11924
|
const rawName = ctor.name || fallback;
|
|
10865
11925
|
const strippedName = rawName.replace(/Entity$/i, "");
|
|
10866
|
-
const normalized =
|
|
11926
|
+
const normalized = toSnakeCase2(strippedName || rawName);
|
|
10867
11927
|
if (!normalized) {
|
|
10868
11928
|
return fallback;
|
|
10869
11929
|
}
|
|
10870
11930
|
return normalized.endsWith("s") ? normalized : `${normalized}s`;
|
|
10871
11931
|
};
|
|
10872
11932
|
function Entity(options = {}) {
|
|
10873
|
-
|
|
10874
|
-
const tableName = options.tableName ?? deriveTableNameFromConstructor(value);
|
|
10875
|
-
setEntityTableName(value, tableName, options.hooks);
|
|
10876
|
-
return value;
|
|
10877
|
-
};
|
|
10878
|
-
const decoratorWithContext = (value, context) => {
|
|
11933
|
+
return function(value, context) {
|
|
10879
11934
|
const ctor = value;
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
}
|
|
10891
|
-
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11935
|
+
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
11936
|
+
setEntityTableName(ctor, tableName, options.hooks);
|
|
11937
|
+
const bag = readMetadataBag(context);
|
|
11938
|
+
if (bag) {
|
|
11939
|
+
const meta = ensureEntityMetadata(ctor);
|
|
11940
|
+
for (const entry of bag.columns) {
|
|
11941
|
+
if (meta.columns[entry.propertyName]) {
|
|
11942
|
+
throw new Error(
|
|
11943
|
+
`Column '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11944
|
+
);
|
|
10892
11945
|
}
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
...entry.relation,
|
|
10901
|
-
defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
|
|
10902
|
-
} : { ...entry.relation };
|
|
10903
|
-
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
11946
|
+
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
11947
|
+
}
|
|
11948
|
+
for (const entry of bag.relations) {
|
|
11949
|
+
if (meta.relations[entry.propertyName]) {
|
|
11950
|
+
throw new Error(
|
|
11951
|
+
`Relation '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
11952
|
+
);
|
|
10904
11953
|
}
|
|
11954
|
+
const relationCopy = entry.relation.kind === RelationKinds.BelongsToMany ? {
|
|
11955
|
+
...entry.relation,
|
|
11956
|
+
defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
|
|
11957
|
+
} : { ...entry.relation };
|
|
11958
|
+
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
10905
11959
|
}
|
|
10906
11960
|
}
|
|
10907
11961
|
return ctor;
|
|
10908
11962
|
};
|
|
10909
|
-
return decoratorWithContext;
|
|
10910
11963
|
}
|
|
10911
11964
|
|
|
10912
11965
|
// src/decorators/column-decorator.ts
|
|
@@ -10939,26 +11992,13 @@ var normalizePropertyName = (name) => {
|
|
|
10939
11992
|
}
|
|
10940
11993
|
return name;
|
|
10941
11994
|
};
|
|
10942
|
-
var resolveConstructor = (target) => {
|
|
10943
|
-
if (typeof target === "function") {
|
|
10944
|
-
return target;
|
|
10945
|
-
}
|
|
10946
|
-
if (target && typeof target.constructor === "function") {
|
|
10947
|
-
return target.constructor;
|
|
10948
|
-
}
|
|
10949
|
-
return void 0;
|
|
10950
|
-
};
|
|
10951
|
-
var registerColumn = (ctor, propertyName, column) => {
|
|
10952
|
-
const meta = ensureEntityMetadata(ctor);
|
|
10953
|
-
if (meta.columns[propertyName]) {
|
|
10954
|
-
return;
|
|
10955
|
-
}
|
|
10956
|
-
addColumnMetadata(ctor, propertyName, column);
|
|
10957
|
-
};
|
|
10958
11995
|
var registerColumnFromContext = (context, column) => {
|
|
10959
11996
|
if (!context.name) {
|
|
10960
11997
|
throw new Error("Column decorator requires a property name");
|
|
10961
11998
|
}
|
|
11999
|
+
if (context.private) {
|
|
12000
|
+
throw new Error("Column decorator does not support private fields");
|
|
12001
|
+
}
|
|
10962
12002
|
const propertyName = normalizePropertyName(context.name);
|
|
10963
12003
|
const bag = getOrCreateMetadataBag(context);
|
|
10964
12004
|
if (!bag.columns.some((entry) => entry.propertyName === propertyName)) {
|
|
@@ -10967,19 +12007,9 @@ var registerColumnFromContext = (context, column) => {
|
|
|
10967
12007
|
};
|
|
10968
12008
|
function Column(definition) {
|
|
10969
12009
|
const normalized = normalizeColumnInput(definition);
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
registerColumnFromContext(propertyKeyOrContext, normalized);
|
|
10973
|
-
return;
|
|
10974
|
-
}
|
|
10975
|
-
const propertyName = normalizePropertyName(propertyKeyOrContext);
|
|
10976
|
-
const ctor = resolveConstructor(targetOrValue);
|
|
10977
|
-
if (!ctor) {
|
|
10978
|
-
throw new Error("Unable to resolve constructor when registering column metadata");
|
|
10979
|
-
}
|
|
10980
|
-
registerColumn(ctor, propertyName, { ...normalized });
|
|
12010
|
+
return function(_value, context) {
|
|
12011
|
+
registerColumnFromContext(context, normalized);
|
|
10981
12012
|
};
|
|
10982
|
-
return decorator;
|
|
10983
12013
|
}
|
|
10984
12014
|
function PrimaryKey(definition) {
|
|
10985
12015
|
const normalized = normalizeColumnInput(definition);
|
|
@@ -10994,41 +12024,21 @@ var normalizePropertyName2 = (name) => {
|
|
|
10994
12024
|
}
|
|
10995
12025
|
return name;
|
|
10996
12026
|
};
|
|
10997
|
-
var resolveConstructor2 = (instanceOrCtor) => {
|
|
10998
|
-
if (typeof instanceOrCtor === "function") {
|
|
10999
|
-
return instanceOrCtor;
|
|
11000
|
-
}
|
|
11001
|
-
if (instanceOrCtor && typeof instanceOrCtor.constructor === "function") {
|
|
11002
|
-
return instanceOrCtor.constructor;
|
|
11003
|
-
}
|
|
11004
|
-
return void 0;
|
|
11005
|
-
};
|
|
11006
|
-
var registerRelation = (ctor, propertyName, metadata) => {
|
|
11007
|
-
addRelationMetadata(ctor, propertyName, metadata);
|
|
11008
|
-
};
|
|
11009
12027
|
var createFieldDecorator = (metadataFactory) => {
|
|
11010
|
-
|
|
11011
|
-
if (
|
|
11012
|
-
|
|
11013
|
-
if (!ctx.name) {
|
|
11014
|
-
throw new Error("Relation decorator requires a property name");
|
|
11015
|
-
}
|
|
11016
|
-
const propertyName2 = normalizePropertyName2(ctx.name);
|
|
11017
|
-
const bag = getOrCreateMetadataBag(ctx);
|
|
11018
|
-
const relationMetadata = metadataFactory(propertyName2);
|
|
11019
|
-
if (!bag.relations.some((entry) => entry.propertyName === propertyName2)) {
|
|
11020
|
-
bag.relations.push({ propertyName: propertyName2, relation: relationMetadata });
|
|
11021
|
-
}
|
|
11022
|
-
return;
|
|
12028
|
+
return function(_value, context) {
|
|
12029
|
+
if (!context.name) {
|
|
12030
|
+
throw new Error("Relation decorator requires a property name");
|
|
11023
12031
|
}
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
12032
|
+
if (context.private) {
|
|
12033
|
+
throw new Error("Relation decorator does not support private fields");
|
|
12034
|
+
}
|
|
12035
|
+
const propertyName = normalizePropertyName2(context.name);
|
|
12036
|
+
const bag = getOrCreateMetadataBag(context);
|
|
12037
|
+
const relationMetadata = metadataFactory(propertyName);
|
|
12038
|
+
if (!bag.relations.some((entry) => entry.propertyName === propertyName)) {
|
|
12039
|
+
bag.relations.push({ propertyName, relation: relationMetadata });
|
|
11028
12040
|
}
|
|
11029
|
-
registerRelation(ctor, propertyName, metadataFactory(propertyName));
|
|
11030
12041
|
};
|
|
11031
|
-
return decorator;
|
|
11032
12042
|
};
|
|
11033
12043
|
function HasMany(options) {
|
|
11034
12044
|
return createFieldDecorator((propertyName) => ({
|
|
@@ -11055,7 +12065,7 @@ function BelongsTo(options) {
|
|
|
11055
12065
|
kind: RelationKinds.BelongsTo,
|
|
11056
12066
|
propertyKey: propertyName,
|
|
11057
12067
|
target: options.target,
|
|
11058
|
-
foreignKey: options.foreignKey
|
|
12068
|
+
foreignKey: options.foreignKey ?? `${propertyName}_id`,
|
|
11059
12069
|
localKey: options.localKey,
|
|
11060
12070
|
cascade: options.cascade
|
|
11061
12071
|
}));
|
|
@@ -11131,13 +12141,15 @@ var deferred = () => {
|
|
|
11131
12141
|
return { promise, resolve, reject };
|
|
11132
12142
|
};
|
|
11133
12143
|
var Pool = class {
|
|
12144
|
+
adapter;
|
|
12145
|
+
options;
|
|
12146
|
+
destroyed = false;
|
|
12147
|
+
creating = 0;
|
|
12148
|
+
leased = 0;
|
|
12149
|
+
idle = [];
|
|
12150
|
+
waiters = [];
|
|
12151
|
+
reapTimer = null;
|
|
11134
12152
|
constructor(adapter, options) {
|
|
11135
|
-
this.destroyed = false;
|
|
11136
|
-
this.creating = 0;
|
|
11137
|
-
this.leased = 0;
|
|
11138
|
-
this.idle = [];
|
|
11139
|
-
this.waiters = [];
|
|
11140
|
-
this.reapTimer = null;
|
|
11141
12153
|
if (!Number.isFinite(options.max) || options.max <= 0) {
|
|
11142
12154
|
throw new Error("Pool options.max must be a positive number");
|
|
11143
12155
|
}
|
|
@@ -11700,6 +12712,8 @@ function createPooledExecutorFactory(opts) {
|
|
|
11700
12712
|
esel,
|
|
11701
12713
|
executeHydrated,
|
|
11702
12714
|
executeHydratedWithContexts,
|
|
12715
|
+
executeSchemaSql,
|
|
12716
|
+
executeSchemaSqlFor,
|
|
11703
12717
|
exists,
|
|
11704
12718
|
exp,
|
|
11705
12719
|
extract,
|
|
@@ -11708,6 +12722,7 @@ function createPooledExecutorFactory(opts) {
|
|
|
11708
12722
|
fromUnixTime,
|
|
11709
12723
|
generateCreateTableSql,
|
|
11710
12724
|
generateSchemaSql,
|
|
12725
|
+
generateSchemaSqlFor,
|
|
11711
12726
|
getColumn,
|
|
11712
12727
|
getDecoratorMetadata,
|
|
11713
12728
|
getSchemaIntrospector,
|
|
@@ -11798,6 +12813,7 @@ function createPooledExecutorFactory(opts) {
|
|
|
11798
12813
|
registerExpressionDispatcher,
|
|
11799
12814
|
registerOperandDispatcher,
|
|
11800
12815
|
registerSchemaIntrospector,
|
|
12816
|
+
relationLoaderCache,
|
|
11801
12817
|
renderColumnDefinition,
|
|
11802
12818
|
renderTypeWithArgs,
|
|
11803
12819
|
repeat,
|
|
@@ -11812,6 +12828,7 @@ function createPooledExecutorFactory(opts) {
|
|
|
11812
12828
|
second,
|
|
11813
12829
|
sel,
|
|
11814
12830
|
selectFromEntity,
|
|
12831
|
+
setRelations,
|
|
11815
12832
|
sha1,
|
|
11816
12833
|
sha2,
|
|
11817
12834
|
shiftLeft,
|