metal-orm 1.1.8 → 1.1.10
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 +769 -764
- package/dist/index.cjs +2352 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +605 -40
- package/dist/index.d.ts +605 -40
- package/dist/index.js +2324 -226
- package/dist/index.js.map +1 -1
- package/package.json +22 -17
- package/src/bulk/bulk-context.ts +83 -0
- package/src/bulk/bulk-delete-executor.ts +89 -0
- package/src/bulk/bulk-executor.base.ts +73 -0
- package/src/bulk/bulk-insert-executor.ts +74 -0
- package/src/bulk/bulk-types.ts +70 -0
- package/src/bulk/bulk-update-executor.ts +192 -0
- package/src/bulk/bulk-upsert-executor.ts +95 -0
- package/src/bulk/bulk-utils.ts +91 -0
- package/src/bulk/index.ts +18 -0
- package/src/codegen/typescript.ts +30 -21
- package/src/core/ast/expression-builders.ts +107 -10
- package/src/core/ast/expression-nodes.ts +52 -22
- package/src/core/ast/expression-visitor.ts +23 -13
- package/src/core/dialect/abstract.ts +30 -17
- package/src/core/dialect/mysql/index.ts +20 -5
- package/src/core/execution/db-executor.ts +96 -64
- package/src/core/execution/executors/better-sqlite3-executor.ts +94 -0
- package/src/core/execution/executors/mssql-executor.ts +66 -34
- package/src/core/execution/executors/mysql-executor.ts +98 -66
- package/src/core/execution/executors/postgres-executor.ts +33 -11
- package/src/core/execution/executors/sqlite-executor.ts +86 -30
- package/src/decorators/bootstrap.ts +482 -398
- package/src/decorators/column-decorator.ts +87 -96
- package/src/decorators/decorator-metadata.ts +100 -24
- package/src/decorators/entity.ts +27 -24
- package/src/decorators/relations.ts +231 -149
- package/src/decorators/transformers/transformer-decorators.ts +26 -29
- package/src/decorators/validators/country-validators-decorators.ts +9 -15
- package/src/dto/apply-filter.ts +568 -551
- package/src/index.ts +16 -9
- package/src/orm/entity-hydration.ts +116 -72
- package/src/orm/entity-metadata.ts +347 -301
- package/src/orm/entity-relations.ts +264 -207
- package/src/orm/entity.ts +199 -199
- package/src/orm/execute.ts +13 -13
- package/src/orm/lazy-batch/morph-many.ts +70 -0
- package/src/orm/lazy-batch/morph-one.ts +69 -0
- package/src/orm/lazy-batch/morph-to.ts +59 -0
- package/src/orm/lazy-batch.ts +4 -1
- package/src/orm/orm-session.ts +170 -104
- package/src/orm/pooled-executor-factory.ts +99 -58
- package/src/orm/query-logger.ts +49 -40
- package/src/orm/relation-change-processor.ts +198 -96
- package/src/orm/relations/belongs-to.ts +143 -143
- package/src/orm/relations/has-many.ts +204 -204
- package/src/orm/relations/has-one.ts +174 -174
- package/src/orm/relations/many-to-many.ts +288 -288
- package/src/orm/relations/morph-many.ts +156 -0
- package/src/orm/relations/morph-one.ts +151 -0
- package/src/orm/relations/morph-to.ts +162 -0
- package/src/orm/save-graph.ts +116 -1
- package/src/query-builder/expression-table-mapper.ts +5 -0
- package/src/query-builder/hydration-manager.ts +345 -345
- package/src/query-builder/hydration-planner.ts +178 -148
- package/src/query-builder/relation-conditions.ts +171 -151
- package/src/query-builder/relation-cte-builder.ts +5 -1
- package/src/query-builder/relation-filter-utils.ts +9 -6
- package/src/query-builder/relation-include-strategies.ts +44 -2
- package/src/query-builder/relation-join-strategies.ts +8 -1
- package/src/query-builder/relation-service.ts +250 -241
- package/src/query-builder/select/cursor-pagination.ts +323 -0
- package/src/query-builder/select/select-operations.ts +110 -105
- package/src/query-builder/select.ts +42 -1
- package/src/query-builder/update-include.ts +4 -0
- package/src/schema/relation.ts +296 -188
- package/src/schema/types.ts +138 -123
- package/src/tree/tree-decorator.ts +127 -137
package/dist/index.cjs
CHANGED
|
@@ -50,6 +50,10 @@ __export(index_exports, {
|
|
|
50
50
|
BigIntTypeStrategy: () => BigIntTypeStrategy,
|
|
51
51
|
BinaryTypeStrategy: () => BinaryTypeStrategy,
|
|
52
52
|
BooleanTypeStrategy: () => BooleanTypeStrategy,
|
|
53
|
+
BulkDeleteExecutor: () => BulkDeleteExecutor,
|
|
54
|
+
BulkInsertExecutor: () => BulkInsertExecutor,
|
|
55
|
+
BulkUpdateExecutor: () => BulkUpdateExecutor,
|
|
56
|
+
BulkUpsertExecutor: () => BulkUpsertExecutor,
|
|
53
57
|
CEP: () => CEP,
|
|
54
58
|
CNPJ: () => CNPJ,
|
|
55
59
|
CPF: () => CPF,
|
|
@@ -65,6 +69,9 @@ __export(index_exports, {
|
|
|
65
69
|
DefaultEntityMaterializer: () => DefaultEntityMaterializer,
|
|
66
70
|
DefaultHasManyCollection: () => DefaultHasManyCollection,
|
|
67
71
|
DefaultManyToManyCollection: () => DefaultManyToManyCollection,
|
|
72
|
+
DefaultMorphManyCollection: () => DefaultMorphManyCollection,
|
|
73
|
+
DefaultMorphOneReference: () => DefaultMorphOneReference,
|
|
74
|
+
DefaultMorphToReference: () => DefaultMorphToReference,
|
|
68
75
|
DefaultTypeStrategy: () => DefaultTypeStrategy,
|
|
69
76
|
DeleteQueryBuilder: () => DeleteQueryBuilder,
|
|
70
77
|
DomainEventBus: () => DomainEventBus,
|
|
@@ -80,6 +87,9 @@ __export(index_exports, {
|
|
|
80
87
|
Length: () => Length,
|
|
81
88
|
Lower: () => Lower,
|
|
82
89
|
MemoryCacheAdapter: () => MemoryCacheAdapter,
|
|
90
|
+
MorphMany: () => MorphMany,
|
|
91
|
+
MorphOne: () => MorphOne,
|
|
92
|
+
MorphTo: () => MorphTo,
|
|
83
93
|
MySqlDialect: () => MySqlDialect,
|
|
84
94
|
NestedSetStrategy: () => NestedSetStrategy,
|
|
85
95
|
Orm: () => Orm,
|
|
@@ -138,6 +148,12 @@ __export(index_exports, {
|
|
|
138
148
|
bootstrapEntities: () => bootstrapEntities,
|
|
139
149
|
buildFilterExpression: () => buildFilterExpression,
|
|
140
150
|
buildScopeConditions: () => buildScopeConditions,
|
|
151
|
+
bulkDelete: () => bulkDelete,
|
|
152
|
+
bulkDeleteWhere: () => bulkDeleteWhere,
|
|
153
|
+
bulkInsert: () => bulkInsert,
|
|
154
|
+
bulkUpdate: () => bulkUpdate,
|
|
155
|
+
bulkUpdateWhere: () => bulkUpdateWhere,
|
|
156
|
+
bulkUpsert: () => bulkUpsert,
|
|
141
157
|
calculateRowDepths: () => calculateRowDepths,
|
|
142
158
|
calculateTotalPages: () => calculateTotalPages,
|
|
143
159
|
callProcedure: () => callProcedure,
|
|
@@ -170,6 +186,7 @@ __export(index_exports, {
|
|
|
170
186
|
count: () => count,
|
|
171
187
|
countAll: () => countAll,
|
|
172
188
|
createApiComponentsSection: () => createApiComponentsSection,
|
|
189
|
+
createBetterSqlite3Executor: () => createBetterSqlite3Executor,
|
|
173
190
|
createDeterministicNamingState: () => createDeterministicNamingState,
|
|
174
191
|
createDtoToOpenApiSchema: () => createDtoToOpenApiSchema,
|
|
175
192
|
createEntityFromRow: () => createEntityFromRow,
|
|
@@ -271,12 +288,16 @@ __export(index_exports, {
|
|
|
271
288
|
isCastExpressionNode: () => isCastExpressionNode,
|
|
272
289
|
isCollateExpressionNode: () => isCollateExpressionNode,
|
|
273
290
|
isComponentReference: () => isComponentReference,
|
|
291
|
+
isDistinctFrom: () => isDistinctFrom,
|
|
274
292
|
isExpressionSelectionNode: () => isExpressionSelectionNode,
|
|
275
293
|
isFunctionNode: () => isFunctionNode,
|
|
294
|
+
isMorphRelation: () => isMorphRelation,
|
|
295
|
+
isNotDistinctFrom: () => isNotDistinctFrom,
|
|
276
296
|
isNotNull: () => isNotNull,
|
|
277
297
|
isNull: () => isNull,
|
|
278
298
|
isNullableColumn: () => isNullableColumn,
|
|
279
299
|
isOperandNode: () => isOperandNode,
|
|
300
|
+
isSingleTargetRelation: () => isSingleTargetRelation,
|
|
280
301
|
isTableDef: () => isTableDef2,
|
|
281
302
|
isTreeConfig: () => isTreeConfig,
|
|
282
303
|
isValidDuration: () => isValidDuration,
|
|
@@ -300,6 +321,9 @@ __export(index_exports, {
|
|
|
300
321
|
loadBelongsToRelation: () => loadBelongsToRelation,
|
|
301
322
|
loadHasManyRelation: () => loadHasManyRelation,
|
|
302
323
|
loadHasOneRelation: () => loadHasOneRelation,
|
|
324
|
+
loadMorphManyRelation: () => loadMorphManyRelation,
|
|
325
|
+
loadMorphOneRelation: () => loadMorphOneRelation,
|
|
326
|
+
loadMorphToRelation: () => loadMorphToRelation,
|
|
303
327
|
localTime: () => localTime,
|
|
304
328
|
localTimestamp: () => localTimestamp,
|
|
305
329
|
locate: () => locate,
|
|
@@ -321,11 +345,15 @@ __export(index_exports, {
|
|
|
321
345
|
minute: () => minute,
|
|
322
346
|
mod: () => mod,
|
|
323
347
|
month: () => month,
|
|
348
|
+
morphMany: () => morphMany,
|
|
349
|
+
morphOne: () => morphOne,
|
|
350
|
+
morphTo: () => morphTo,
|
|
324
351
|
mul: () => mul,
|
|
325
352
|
neq: () => neq,
|
|
326
353
|
nestedDtoToOpenApiSchema: () => nestedDtoToOpenApiSchema,
|
|
327
354
|
nestedWhereInputToOpenApiSchema: () => nestedWhereInputToOpenApiSchema,
|
|
328
355
|
normalizeColumnType: () => normalizeColumnType,
|
|
356
|
+
not: () => not,
|
|
329
357
|
notBetween: () => notBetween,
|
|
330
358
|
notExists: () => notExists,
|
|
331
359
|
notInList: () => notInList,
|
|
@@ -732,7 +760,13 @@ var RelationKinds = {
|
|
|
732
760
|
/** Many-to-one relationship */
|
|
733
761
|
BelongsTo: "BELONGS_TO",
|
|
734
762
|
/** Many-to-many relationship with pivot metadata */
|
|
735
|
-
BelongsToMany: "BELONGS_TO_MANY"
|
|
763
|
+
BelongsToMany: "BELONGS_TO_MANY",
|
|
764
|
+
/** Polymorphic inverse (child side) */
|
|
765
|
+
MorphTo: "MORPH_TO",
|
|
766
|
+
/** Polymorphic one-to-one (parent side) */
|
|
767
|
+
MorphOne: "MORPH_ONE",
|
|
768
|
+
/** Polymorphic one-to-many (parent side) */
|
|
769
|
+
MorphMany: "MORPH_MANY"
|
|
736
770
|
};
|
|
737
771
|
var hasMany = (target, foreignKey, localKey, cascade) => ({
|
|
738
772
|
type: RelationKinds.HasMany,
|
|
@@ -767,6 +801,32 @@ var belongsToMany = (target, pivotTable, options) => ({
|
|
|
767
801
|
defaultPivotColumns: options.defaultPivotColumns,
|
|
768
802
|
cascade: options.cascade
|
|
769
803
|
});
|
|
804
|
+
var isSingleTargetRelation = (rel) => rel.type !== RelationKinds.MorphTo;
|
|
805
|
+
var isMorphRelation = (rel) => rel.type === RelationKinds.MorphTo || rel.type === RelationKinds.MorphOne || rel.type === RelationKinds.MorphMany;
|
|
806
|
+
var morphTo = (opts) => ({
|
|
807
|
+
type: RelationKinds.MorphTo,
|
|
808
|
+
...opts
|
|
809
|
+
});
|
|
810
|
+
var morphOne = (target, opts) => ({
|
|
811
|
+
type: RelationKinds.MorphOne,
|
|
812
|
+
target,
|
|
813
|
+
morphName: opts.as,
|
|
814
|
+
typeField: opts.typeField ?? `${opts.as}Type`,
|
|
815
|
+
idField: opts.idField ?? `${opts.as}Id`,
|
|
816
|
+
typeValue: opts.typeValue,
|
|
817
|
+
localKey: opts.localKey,
|
|
818
|
+
cascade: opts.cascade
|
|
819
|
+
});
|
|
820
|
+
var morphMany = (target, opts) => ({
|
|
821
|
+
type: RelationKinds.MorphMany,
|
|
822
|
+
target,
|
|
823
|
+
morphName: opts.as,
|
|
824
|
+
typeField: opts.typeField ?? `${opts.as}Type`,
|
|
825
|
+
idField: opts.idField ?? `${opts.as}Id`,
|
|
826
|
+
typeValue: opts.typeValue,
|
|
827
|
+
localKey: opts.localKey,
|
|
828
|
+
cascade: opts.cascade
|
|
829
|
+
});
|
|
770
830
|
|
|
771
831
|
// src/core/ast/expression-nodes.ts
|
|
772
832
|
var operandTypes = /* @__PURE__ */ new Set([
|
|
@@ -894,6 +954,10 @@ var or = (...operands) => ({
|
|
|
894
954
|
operator: "OR",
|
|
895
955
|
operands
|
|
896
956
|
});
|
|
957
|
+
var not = (operand) => ({
|
|
958
|
+
type: "NotExpression",
|
|
959
|
+
operand
|
|
960
|
+
});
|
|
897
961
|
var isNull = (left2) => ({
|
|
898
962
|
type: "NullExpression",
|
|
899
963
|
left: toOperandNode(left2),
|
|
@@ -977,6 +1041,18 @@ var collate = (expression, collation) => ({
|
|
|
977
1041
|
expression: toOperand(expression),
|
|
978
1042
|
collation
|
|
979
1043
|
});
|
|
1044
|
+
var isDistinctFrom = (left2, right2) => ({
|
|
1045
|
+
type: "IsDistinctExpression",
|
|
1046
|
+
left: toOperandNode(left2),
|
|
1047
|
+
operator: "IS DISTINCT FROM",
|
|
1048
|
+
right: toOperand(right2)
|
|
1049
|
+
});
|
|
1050
|
+
var isNotDistinctFrom = (left2, right2) => ({
|
|
1051
|
+
type: "IsDistinctExpression",
|
|
1052
|
+
left: toOperandNode(left2),
|
|
1053
|
+
operator: "IS NOT DISTINCT FROM",
|
|
1054
|
+
right: toOperand(right2)
|
|
1055
|
+
});
|
|
980
1056
|
|
|
981
1057
|
// src/core/ast/window-functions.ts
|
|
982
1058
|
var buildWindowFunction = (name, args = [], partitionBy, orderBy) => {
|
|
@@ -1183,6 +1259,9 @@ var visitExpression = (node, visitor) => {
|
|
|
1183
1259
|
case "LogicalExpression":
|
|
1184
1260
|
if (visitor.visitLogicalExpression) return visitor.visitLogicalExpression(node);
|
|
1185
1261
|
break;
|
|
1262
|
+
case "NotExpression":
|
|
1263
|
+
if (visitor.visitNotExpression) return visitor.visitNotExpression(node);
|
|
1264
|
+
break;
|
|
1186
1265
|
case "NullExpression":
|
|
1187
1266
|
if (visitor.visitNullExpression) return visitor.visitNullExpression(node);
|
|
1188
1267
|
break;
|
|
@@ -1201,6 +1280,9 @@ var visitExpression = (node, visitor) => {
|
|
|
1201
1280
|
case "BitwiseExpression":
|
|
1202
1281
|
if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node);
|
|
1203
1282
|
break;
|
|
1283
|
+
case "IsDistinctExpression":
|
|
1284
|
+
if (visitor.visitIsDistinctExpression) return visitor.visitIsDistinctExpression(node);
|
|
1285
|
+
break;
|
|
1204
1286
|
default:
|
|
1205
1287
|
break;
|
|
1206
1288
|
}
|
|
@@ -1924,6 +2006,10 @@ var Dialect = class _Dialect {
|
|
|
1924
2006
|
});
|
|
1925
2007
|
return parts.join(` ${logical.operator} `);
|
|
1926
2008
|
});
|
|
2009
|
+
this.registerExpressionCompiler("NotExpression", (notExpr, ctx) => {
|
|
2010
|
+
const operand = this.compileExpression(notExpr.operand, ctx);
|
|
2011
|
+
return `NOT (${operand})`;
|
|
2012
|
+
});
|
|
1927
2013
|
this.registerExpressionCompiler("NullExpression", (nullExpr, ctx) => {
|
|
1928
2014
|
const left2 = this.compileOperand(nullExpr.left, ctx);
|
|
1929
2015
|
return `${left2} ${nullExpr.operator}`;
|
|
@@ -1957,6 +2043,11 @@ var Dialect = class _Dialect {
|
|
|
1957
2043
|
const right2 = this.compileOperand(bitwise.right, ctx);
|
|
1958
2044
|
return `${left2} ${bitwise.operator} ${right2}`;
|
|
1959
2045
|
});
|
|
2046
|
+
this.registerExpressionCompiler("IsDistinctExpression", (node, ctx) => {
|
|
2047
|
+
const left2 = this.compileOperand(node.left, ctx);
|
|
2048
|
+
const right2 = this.compileOperand(node.right, ctx);
|
|
2049
|
+
return `${left2} ${node.operator} ${right2}`;
|
|
2050
|
+
});
|
|
1960
2051
|
}
|
|
1961
2052
|
registerDefaultOperandCompilers() {
|
|
1962
2053
|
this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
|
|
@@ -2878,6 +2969,18 @@ var MySqlDialect = class extends SqlDialectBase {
|
|
|
2878
2969
|
*/
|
|
2879
2970
|
constructor() {
|
|
2880
2971
|
super(new MysqlFunctionStrategy());
|
|
2972
|
+
this.registerExpressionCompiler(
|
|
2973
|
+
"IsDistinctExpression",
|
|
2974
|
+
(node, ctx) => {
|
|
2975
|
+
const left2 = this.compileOperand(node.left, ctx);
|
|
2976
|
+
const right2 = this.compileOperand(node.right, ctx);
|
|
2977
|
+
const spaceship = `${left2} <=> ${right2}`;
|
|
2978
|
+
if (node.operator === "IS NOT DISTINCT FROM") {
|
|
2979
|
+
return spaceship;
|
|
2980
|
+
}
|
|
2981
|
+
return `NOT (${spaceship})`;
|
|
2982
|
+
}
|
|
2983
|
+
);
|
|
2881
2984
|
}
|
|
2882
2985
|
/**
|
|
2883
2986
|
* Quotes an identifier using MySQL backtick syntax
|
|
@@ -3977,7 +4080,7 @@ var HydrationManager = class _HydrationManager {
|
|
|
3977
4080
|
*/
|
|
3978
4081
|
hasMultiplyingRelations(plan) {
|
|
3979
4082
|
return plan.relations.some(
|
|
3980
|
-
(rel) => rel.type === RelationKinds.HasMany || rel.type === RelationKinds.BelongsToMany
|
|
4083
|
+
(rel) => rel.type === RelationKinds.HasMany || rel.type === RelationKinds.BelongsToMany || rel.type === RelationKinds.MorphMany
|
|
3981
4084
|
);
|
|
3982
4085
|
}
|
|
3983
4086
|
/**
|
|
@@ -4311,6 +4414,36 @@ var HydrationPlanner = class _HydrationPlanner {
|
|
|
4311
4414
|
}
|
|
4312
4415
|
};
|
|
4313
4416
|
}
|
|
4417
|
+
case RelationKinds.MorphOne: {
|
|
4418
|
+
const morphRel = rel;
|
|
4419
|
+
const localKey = morphRel.localKey || findPrimaryKey(this.table);
|
|
4420
|
+
return {
|
|
4421
|
+
name: relationName,
|
|
4422
|
+
aliasPrefix,
|
|
4423
|
+
type: rel.type,
|
|
4424
|
+
targetTable: morphRel.target.name,
|
|
4425
|
+
targetPrimaryKey: findPrimaryKey(morphRel.target),
|
|
4426
|
+
foreignKey: morphRel.idField,
|
|
4427
|
+
localKey,
|
|
4428
|
+
columns
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4431
|
+
case RelationKinds.MorphMany: {
|
|
4432
|
+
const morphRel = rel;
|
|
4433
|
+
const localKey = morphRel.localKey || findPrimaryKey(this.table);
|
|
4434
|
+
return {
|
|
4435
|
+
name: relationName,
|
|
4436
|
+
aliasPrefix,
|
|
4437
|
+
type: rel.type,
|
|
4438
|
+
targetTable: morphRel.target.name,
|
|
4439
|
+
targetPrimaryKey: findPrimaryKey(morphRel.target),
|
|
4440
|
+
foreignKey: morphRel.idField,
|
|
4441
|
+
localKey,
|
|
4442
|
+
columns
|
|
4443
|
+
};
|
|
4444
|
+
}
|
|
4445
|
+
case RelationKinds.MorphTo:
|
|
4446
|
+
throw new Error("MorphTo relations do not support hydration planning via JOIN.");
|
|
4314
4447
|
}
|
|
4315
4448
|
}
|
|
4316
4449
|
};
|
|
@@ -4615,23 +4748,44 @@ var assertNever = (value) => {
|
|
|
4615
4748
|
};
|
|
4616
4749
|
var baseRelationCondition = (root, relation, rootAlias, targetTableName) => {
|
|
4617
4750
|
const rootTable = rootAlias || root.name;
|
|
4751
|
+
if (relation.type === RelationKinds.MorphTo) {
|
|
4752
|
+
throw new Error("MorphTo relations do not support the standard join condition builder");
|
|
4753
|
+
}
|
|
4618
4754
|
const targetTable = targetTableName ?? relation.target.name;
|
|
4619
|
-
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
4620
|
-
const localKey = relation.localKey || defaultLocalKey;
|
|
4621
4755
|
switch (relation.type) {
|
|
4622
4756
|
case RelationKinds.HasMany:
|
|
4623
|
-
case RelationKinds.HasOne:
|
|
4757
|
+
case RelationKinds.HasOne: {
|
|
4758
|
+
const defaultLocalKey = findPrimaryKey(root);
|
|
4759
|
+
const localKey = relation.localKey || defaultLocalKey;
|
|
4624
4760
|
return eq(
|
|
4625
4761
|
{ type: "Column", table: targetTable, name: relation.foreignKey },
|
|
4626
4762
|
{ type: "Column", table: rootTable, name: localKey }
|
|
4627
4763
|
);
|
|
4628
|
-
|
|
4764
|
+
}
|
|
4765
|
+
case RelationKinds.BelongsTo: {
|
|
4766
|
+
const defaultLocalKey = findPrimaryKey(relation.target);
|
|
4767
|
+
const localKey = relation.localKey || defaultLocalKey;
|
|
4629
4768
|
return eq(
|
|
4630
4769
|
{ type: "Column", table: targetTable, name: localKey },
|
|
4631
4770
|
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
4632
4771
|
);
|
|
4772
|
+
}
|
|
4633
4773
|
case RelationKinds.BelongsToMany:
|
|
4634
4774
|
throw new Error("BelongsToMany relations do not support the standard join condition builder");
|
|
4775
|
+
case RelationKinds.MorphOne:
|
|
4776
|
+
case RelationKinds.MorphMany: {
|
|
4777
|
+
const morphRel = relation;
|
|
4778
|
+
const morphLocalKey = morphRel.localKey || findPrimaryKey(root);
|
|
4779
|
+
const baseCondition = eq(
|
|
4780
|
+
{ type: "Column", table: targetTable, name: morphRel.idField },
|
|
4781
|
+
{ type: "Column", table: rootTable, name: morphLocalKey }
|
|
4782
|
+
);
|
|
4783
|
+
const discriminatorCondition = eq(
|
|
4784
|
+
{ type: "Column", table: targetTable, name: morphRel.typeField },
|
|
4785
|
+
{ type: "Literal", value: morphRel.typeValue }
|
|
4786
|
+
);
|
|
4787
|
+
return and(baseCondition, discriminatorCondition);
|
|
4788
|
+
}
|
|
4635
4789
|
default:
|
|
4636
4790
|
return assertNever(relation);
|
|
4637
4791
|
}
|
|
@@ -4727,6 +4881,9 @@ var collectFromExpression = (expr, collector) => {
|
|
|
4727
4881
|
case "LogicalExpression":
|
|
4728
4882
|
expr.operands.forEach((operand) => collectFromExpression(operand, collector));
|
|
4729
4883
|
break;
|
|
4884
|
+
case "NotExpression":
|
|
4885
|
+
collectFromExpression(expr.operand, collector);
|
|
4886
|
+
break;
|
|
4730
4887
|
case "NullExpression":
|
|
4731
4888
|
collectFromOperand(expr.left, collector);
|
|
4732
4889
|
break;
|
|
@@ -4833,6 +4990,11 @@ var mapExpression = (expr, fromTable, toTable) => {
|
|
|
4833
4990
|
if (nextOperands.every((op, i) => op === expr.operands[i])) return expr;
|
|
4834
4991
|
return { ...expr, operands: nextOperands };
|
|
4835
4992
|
}
|
|
4993
|
+
case "NotExpression": {
|
|
4994
|
+
const operand = mapExpression(expr.operand, fromTable, toTable);
|
|
4995
|
+
if (operand === expr.operand) return expr;
|
|
4996
|
+
return { ...expr, operand };
|
|
4997
|
+
}
|
|
4836
4998
|
case "NullExpression": {
|
|
4837
4999
|
const left2 = mapOperand(expr.left, fromTable, toTable);
|
|
4838
5000
|
if (left2 === expr.left) return expr;
|
|
@@ -5133,6 +5295,9 @@ var addRelationJoin = (params) => {
|
|
|
5133
5295
|
);
|
|
5134
5296
|
return joins.reduce((curr, join) => curr.withJoin(join), state);
|
|
5135
5297
|
}
|
|
5298
|
+
if (!isSingleTargetRelation(relation)) {
|
|
5299
|
+
throw new Error("Polymorphic MorphTo relations do not support join-based strategies");
|
|
5300
|
+
}
|
|
5136
5301
|
let targetSource = tableSource ?? {
|
|
5137
5302
|
type: "Table",
|
|
5138
5303
|
name: relation.target.name,
|
|
@@ -5148,6 +5313,9 @@ var addRelationJoin = (params) => {
|
|
|
5148
5313
|
var updateRelationJoin = (params) => {
|
|
5149
5314
|
const { joins, joinIndex, relation, currentTable, currentAlias, options } = params;
|
|
5150
5315
|
const join = joins[joinIndex];
|
|
5316
|
+
if (!isSingleTargetRelation(relation)) {
|
|
5317
|
+
throw new Error("Polymorphic MorphTo relations do not support join updates");
|
|
5318
|
+
}
|
|
5151
5319
|
const targetName = resolveTargetTableName(join.table, relation.target.name);
|
|
5152
5320
|
const extra = remapExpressionTable(options.filter, relation.target.name, targetName);
|
|
5153
5321
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
@@ -5207,6 +5375,9 @@ var RelationCteBuilder = class {
|
|
|
5207
5375
|
if (!predicate) {
|
|
5208
5376
|
throw new Error("Unable to build filter CTE without predicates.");
|
|
5209
5377
|
}
|
|
5378
|
+
if (!isSingleTargetRelation(relation)) {
|
|
5379
|
+
throw new Error("Polymorphic MorphTo relations do not support filter CTEs");
|
|
5380
|
+
}
|
|
5210
5381
|
const columns = Object.keys(relation.target.columns).map((name) => ({
|
|
5211
5382
|
type: "Column",
|
|
5212
5383
|
table: relation.target.name,
|
|
@@ -5254,6 +5425,9 @@ var buildTypedSelection = (columns, prefix, keys, missingMsg, tableOverride) =>
|
|
|
5254
5425
|
}, {});
|
|
5255
5426
|
};
|
|
5256
5427
|
var resolveTargetColumns = (relation, options) => {
|
|
5428
|
+
if (!isSingleTargetRelation(relation)) {
|
|
5429
|
+
return [];
|
|
5430
|
+
}
|
|
5257
5431
|
const requestedColumns = options?.columns?.length ? [...options.columns] : Object.keys(relation.target.columns);
|
|
5258
5432
|
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
5259
5433
|
if (!requestedColumns.includes(targetPrimaryKey)) {
|
|
@@ -5345,11 +5519,41 @@ var belongsToManyStrategy = (context) => {
|
|
|
5345
5519
|
);
|
|
5346
5520
|
return { state, hydration };
|
|
5347
5521
|
};
|
|
5522
|
+
var morphIncludeStrategy = (context) => {
|
|
5523
|
+
let { state, hydration } = context;
|
|
5524
|
+
const relation = context.relation;
|
|
5525
|
+
const targetColumns = resolveTargetColumns(relation, context.options);
|
|
5526
|
+
const tableOverride = getJoinCorrelationName(state, context.relationName, relation.target.name);
|
|
5527
|
+
const targetSelection = buildTypedSelection(
|
|
5528
|
+
relation.target.columns,
|
|
5529
|
+
context.aliasPrefix,
|
|
5530
|
+
targetColumns,
|
|
5531
|
+
(key) => `Column '${key}' not found on relation '${context.relationName}'`,
|
|
5532
|
+
tableOverride
|
|
5533
|
+
);
|
|
5534
|
+
const relationSelectionResult = context.selectColumns(state, hydration, targetSelection);
|
|
5535
|
+
state = relationSelectionResult.state;
|
|
5536
|
+
hydration = relationSelectionResult.hydration;
|
|
5537
|
+
hydration = hydration.onRelationIncluded(
|
|
5538
|
+
state,
|
|
5539
|
+
relation,
|
|
5540
|
+
context.relationName,
|
|
5541
|
+
context.aliasPrefix,
|
|
5542
|
+
targetColumns
|
|
5543
|
+
);
|
|
5544
|
+
return { state, hydration };
|
|
5545
|
+
};
|
|
5546
|
+
var morphToIncludeStrategy = () => {
|
|
5547
|
+
throw new Error("MorphTo relations do not support JOIN-based include. Use lazy loading instead.");
|
|
5548
|
+
};
|
|
5348
5549
|
var relationIncludeStrategies = {
|
|
5349
5550
|
[RelationKinds.HasMany]: standardIncludeStrategy,
|
|
5350
5551
|
[RelationKinds.HasOne]: standardIncludeStrategy,
|
|
5351
5552
|
[RelationKinds.BelongsTo]: standardIncludeStrategy,
|
|
5352
|
-
[RelationKinds.BelongsToMany]: belongsToManyStrategy
|
|
5553
|
+
[RelationKinds.BelongsToMany]: belongsToManyStrategy,
|
|
5554
|
+
[RelationKinds.MorphOne]: morphIncludeStrategy,
|
|
5555
|
+
[RelationKinds.MorphMany]: morphIncludeStrategy,
|
|
5556
|
+
[RelationKinds.MorphTo]: morphToIncludeStrategy
|
|
5353
5557
|
};
|
|
5354
5558
|
|
|
5355
5559
|
// src/query-builder/relation-service.ts
|
|
@@ -5418,6 +5622,12 @@ var RelationService = class {
|
|
|
5418
5622
|
let state = this.state;
|
|
5419
5623
|
let hydration = this.hydration;
|
|
5420
5624
|
const relation = this.getRelation(relationName);
|
|
5625
|
+
if (relation.type === RelationKinds.MorphTo) {
|
|
5626
|
+
throw new Error(`MorphTo relation '${relationName}' does not support include() via JOIN. Use lazy loading ($load) instead.`);
|
|
5627
|
+
}
|
|
5628
|
+
if (!isSingleTargetRelation(relation)) {
|
|
5629
|
+
return { state, hydration };
|
|
5630
|
+
}
|
|
5421
5631
|
const aliasPrefix = options?.aliasPrefix ?? relationName;
|
|
5422
5632
|
const alreadyJoined = hasJoinForRelationKey(state.ast.joins, relationName);
|
|
5423
5633
|
const { selfFilters, crossFilters } = splitFilterExpressions(
|
|
@@ -5476,6 +5686,9 @@ var RelationService = class {
|
|
|
5476
5686
|
*/
|
|
5477
5687
|
applyRelationCorrelation(relationName, ast, additionalCorrelation) {
|
|
5478
5688
|
const relation = this.getRelation(relationName);
|
|
5689
|
+
if (relation.type === RelationKinds.MorphTo) {
|
|
5690
|
+
throw new Error(`MorphTo relation '${relationName}' does not support correlation-based operations.`);
|
|
5691
|
+
}
|
|
5479
5692
|
const rootAlias = this.state.ast.from.type === "Table" ? this.state.ast.from.alias : void 0;
|
|
5480
5693
|
let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
|
|
5481
5694
|
if (additionalCorrelation) {
|
|
@@ -5935,6 +6148,45 @@ var populateHydrationCache = (entity, row, meta) => {
|
|
|
5935
6148
|
}
|
|
5936
6149
|
}
|
|
5937
6150
|
}
|
|
6151
|
+
for (const relationName of Object.keys(meta.table.relations)) {
|
|
6152
|
+
const relation = meta.table.relations[relationName];
|
|
6153
|
+
const data = row[relationName];
|
|
6154
|
+
if (relation.type === RelationKinds.MorphOne) {
|
|
6155
|
+
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
6156
|
+
const rootValue = entity[localKey];
|
|
6157
|
+
if (rootValue === void 0 || rootValue === null) continue;
|
|
6158
|
+
if (!data || typeof data !== "object") continue;
|
|
6159
|
+
const cache = /* @__PURE__ */ new Map();
|
|
6160
|
+
cache.set(toKey2(rootValue), data);
|
|
6161
|
+
meta.relationHydration.set(relationName, cache);
|
|
6162
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
6163
|
+
continue;
|
|
6164
|
+
}
|
|
6165
|
+
if (relation.type === RelationKinds.MorphMany) {
|
|
6166
|
+
if (!Array.isArray(data)) continue;
|
|
6167
|
+
const localKey = relation.localKey || findPrimaryKey(meta.table);
|
|
6168
|
+
const rootValue = entity[localKey];
|
|
6169
|
+
if (rootValue === void 0 || rootValue === null) continue;
|
|
6170
|
+
const cache = /* @__PURE__ */ new Map();
|
|
6171
|
+
cache.set(toKey2(rootValue), data);
|
|
6172
|
+
meta.relationHydration.set(relationName, cache);
|
|
6173
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
6174
|
+
continue;
|
|
6175
|
+
}
|
|
6176
|
+
if (relation.type === RelationKinds.MorphTo) {
|
|
6177
|
+
if (!data || typeof data !== "object") continue;
|
|
6178
|
+
const morphTo2 = relation;
|
|
6179
|
+
const typeValue = entity[morphTo2.typeField];
|
|
6180
|
+
const idValue = entity[morphTo2.idField];
|
|
6181
|
+
if (!typeValue || idValue === void 0 || idValue === null) continue;
|
|
6182
|
+
const compositeKey = `${toKey2(typeValue)}:${toKey2(idValue)}`;
|
|
6183
|
+
const cache = /* @__PURE__ */ new Map();
|
|
6184
|
+
cache.set(compositeKey, data);
|
|
6185
|
+
meta.relationHydration.set(relationName, cache);
|
|
6186
|
+
meta.relationCache.set(relationName, Promise.resolve(cache));
|
|
6187
|
+
continue;
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
5938
6190
|
};
|
|
5939
6191
|
|
|
5940
6192
|
// src/orm/relations/has-many.ts
|
|
@@ -6607,113 +6859,519 @@ var DefaultManyToManyCollection = class {
|
|
|
6607
6859
|
}
|
|
6608
6860
|
};
|
|
6609
6861
|
|
|
6610
|
-
// src/orm/
|
|
6611
|
-
var hasColumns = (columns) => Boolean(columns && columns.length > 0);
|
|
6612
|
-
var buildColumnSelection = (table, columns, missingMsg) => {
|
|
6613
|
-
return columns.reduce((acc, column) => {
|
|
6614
|
-
const def = table.columns[column];
|
|
6615
|
-
if (!def) {
|
|
6616
|
-
throw new Error(missingMsg(column));
|
|
6617
|
-
}
|
|
6618
|
-
acc[column] = def;
|
|
6619
|
-
return acc;
|
|
6620
|
-
}, {});
|
|
6621
|
-
};
|
|
6622
|
-
var filterRow = (row, columns) => {
|
|
6623
|
-
const filtered = {};
|
|
6624
|
-
for (const column of columns) {
|
|
6625
|
-
if (column in row) {
|
|
6626
|
-
filtered[column] = row[column];
|
|
6627
|
-
}
|
|
6628
|
-
}
|
|
6629
|
-
return filtered;
|
|
6630
|
-
};
|
|
6631
|
-
var filterRows = (rows, columns) => rows.map((row) => filterRow(row, columns));
|
|
6632
|
-
var rowsFromResults = (results) => {
|
|
6633
|
-
const rows = [];
|
|
6634
|
-
for (const result of results) {
|
|
6635
|
-
const { columns, values } = result;
|
|
6636
|
-
for (const valueRow of values) {
|
|
6637
|
-
const row = {};
|
|
6638
|
-
columns.forEach((column, idx) => {
|
|
6639
|
-
row[column] = valueRow[idx];
|
|
6640
|
-
});
|
|
6641
|
-
rows.push(row);
|
|
6642
|
-
}
|
|
6643
|
-
}
|
|
6644
|
-
return rows;
|
|
6645
|
-
};
|
|
6646
|
-
var executeQuery = async (ctx, qb) => {
|
|
6647
|
-
const compiled = ctx.dialect.compileSelect(qb.getAST());
|
|
6648
|
-
const results = await ctx.executor.executeSql(compiled.sql, compiled.params);
|
|
6649
|
-
return rowsFromResults(results);
|
|
6650
|
-
};
|
|
6862
|
+
// src/orm/relations/morph-one.ts
|
|
6651
6863
|
var toKey7 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
6652
|
-
var
|
|
6653
|
-
const
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6864
|
+
var hideInternal5 = (obj, keys) => {
|
|
6865
|
+
for (const key of keys) {
|
|
6866
|
+
Object.defineProperty(obj, key, {
|
|
6867
|
+
value: obj[key],
|
|
6868
|
+
writable: false,
|
|
6869
|
+
configurable: false,
|
|
6870
|
+
enumerable: false
|
|
6871
|
+
});
|
|
6659
6872
|
}
|
|
6660
|
-
return collected;
|
|
6661
6873
|
};
|
|
6662
|
-
var
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6874
|
+
var hideWritable5 = (obj, keys) => {
|
|
6875
|
+
for (const key of keys) {
|
|
6876
|
+
const value = obj[key];
|
|
6877
|
+
Object.defineProperty(obj, key, {
|
|
6878
|
+
value,
|
|
6879
|
+
writable: true,
|
|
6880
|
+
configurable: true,
|
|
6881
|
+
enumerable: false
|
|
6882
|
+
});
|
|
6668
6883
|
}
|
|
6669
|
-
return executeQuery(ctx, qb);
|
|
6670
6884
|
};
|
|
6671
|
-
var
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6885
|
+
var DefaultMorphOneReference = class {
|
|
6886
|
+
constructor(ctx, meta, root, relationName, relation, rootTable, loader, createEntity, localKey) {
|
|
6887
|
+
this.ctx = ctx;
|
|
6888
|
+
this.meta = meta;
|
|
6889
|
+
this.root = root;
|
|
6890
|
+
this.relationName = relationName;
|
|
6891
|
+
this.relation = relation;
|
|
6892
|
+
this.rootTable = rootTable;
|
|
6893
|
+
this.loader = loader;
|
|
6894
|
+
this.createEntity = createEntity;
|
|
6895
|
+
this.localKey = localKey;
|
|
6896
|
+
hideInternal5(this, [
|
|
6897
|
+
"ctx",
|
|
6898
|
+
"meta",
|
|
6899
|
+
"root",
|
|
6900
|
+
"relationName",
|
|
6901
|
+
"relation",
|
|
6902
|
+
"rootTable",
|
|
6903
|
+
"loader",
|
|
6904
|
+
"createEntity",
|
|
6905
|
+
"localKey"
|
|
6906
|
+
]);
|
|
6907
|
+
hideWritable5(this, ["loaded", "current"]);
|
|
6908
|
+
this.populateFromHydrationCache();
|
|
6680
6909
|
}
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
const
|
|
6687
|
-
if (
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
lookup.set(key, row);
|
|
6910
|
+
loaded = false;
|
|
6911
|
+
current = null;
|
|
6912
|
+
async load() {
|
|
6913
|
+
if (this.loaded) return this.current;
|
|
6914
|
+
const map = await this.loader();
|
|
6915
|
+
const keyValue = this.root[this.localKey];
|
|
6916
|
+
if (keyValue === void 0 || keyValue === null) {
|
|
6917
|
+
this.loaded = true;
|
|
6918
|
+
return this.current;
|
|
6691
6919
|
}
|
|
6920
|
+
const row = map.get(toKey7(keyValue));
|
|
6921
|
+
this.current = row ? this.createEntity(row) : null;
|
|
6922
|
+
this.loaded = true;
|
|
6923
|
+
return this.current;
|
|
6692
6924
|
}
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
// src/orm/lazy-batch/has-many.ts
|
|
6697
|
-
var loadHasManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
6698
|
-
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
6699
|
-
const roots = ctx.getEntitiesForTable(rootTable);
|
|
6700
|
-
const keys = collectKeysFromRoots(roots, localKey);
|
|
6701
|
-
if (!keys.size) {
|
|
6702
|
-
return /* @__PURE__ */ new Map();
|
|
6703
|
-
}
|
|
6704
|
-
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
6705
|
-
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
6706
|
-
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
6707
|
-
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
6708
|
-
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
6709
|
-
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
6710
|
-
selectedColumns.push(targetPrimaryKey);
|
|
6925
|
+
get() {
|
|
6926
|
+
return this.current;
|
|
6711
6927
|
}
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6928
|
+
set(data) {
|
|
6929
|
+
if (data === null) {
|
|
6930
|
+
return this.detachCurrent();
|
|
6931
|
+
}
|
|
6932
|
+
const entity = hasEntityMeta(data) ? data : this.createEntity(data);
|
|
6933
|
+
if (this.current && this.current !== entity) {
|
|
6934
|
+
this.ctx.registerRelationChange(
|
|
6935
|
+
this.root,
|
|
6936
|
+
this.relationKey,
|
|
6937
|
+
this.rootTable,
|
|
6938
|
+
this.relationName,
|
|
6939
|
+
this.relation,
|
|
6940
|
+
{ kind: "remove", entity: this.current }
|
|
6941
|
+
);
|
|
6942
|
+
}
|
|
6943
|
+
this.assignMorphKeys(entity);
|
|
6944
|
+
this.current = entity;
|
|
6945
|
+
this.loaded = true;
|
|
6946
|
+
this.ctx.registerRelationChange(
|
|
6947
|
+
this.root,
|
|
6948
|
+
this.relationKey,
|
|
6949
|
+
this.rootTable,
|
|
6950
|
+
this.relationName,
|
|
6951
|
+
this.relation,
|
|
6952
|
+
{ kind: "attach", entity }
|
|
6953
|
+
);
|
|
6954
|
+
return entity;
|
|
6955
|
+
}
|
|
6956
|
+
toJSON() {
|
|
6957
|
+
if (!this.current) return null;
|
|
6958
|
+
const entityWithToJSON = this.current;
|
|
6959
|
+
return typeof entityWithToJSON.toJSON === "function" ? entityWithToJSON.toJSON() : this.current;
|
|
6960
|
+
}
|
|
6961
|
+
detachCurrent() {
|
|
6962
|
+
const previous = this.current;
|
|
6963
|
+
if (!previous) return null;
|
|
6964
|
+
this.current = null;
|
|
6965
|
+
this.loaded = true;
|
|
6966
|
+
this.ctx.registerRelationChange(
|
|
6967
|
+
this.root,
|
|
6968
|
+
this.relationKey,
|
|
6969
|
+
this.rootTable,
|
|
6970
|
+
this.relationName,
|
|
6971
|
+
this.relation,
|
|
6972
|
+
{ kind: "remove", entity: previous }
|
|
6973
|
+
);
|
|
6974
|
+
return null;
|
|
6975
|
+
}
|
|
6976
|
+
assignMorphKeys(entity) {
|
|
6977
|
+
const keyValue = this.root[this.localKey];
|
|
6978
|
+
entity[this.relation.idField] = keyValue;
|
|
6979
|
+
entity[this.relation.typeField] = this.relation.typeValue;
|
|
6980
|
+
}
|
|
6981
|
+
get relationKey() {
|
|
6982
|
+
return `${this.rootTable.name}.${this.relationName}`;
|
|
6983
|
+
}
|
|
6984
|
+
populateFromHydrationCache() {
|
|
6985
|
+
const keyValue = this.root[this.localKey];
|
|
6986
|
+
if (keyValue === void 0 || keyValue === null) return;
|
|
6987
|
+
const row = getHydrationRecord(this.meta, this.relationName, keyValue);
|
|
6988
|
+
if (!row) return;
|
|
6989
|
+
this.current = this.createEntity(row);
|
|
6990
|
+
this.loaded = true;
|
|
6991
|
+
}
|
|
6992
|
+
};
|
|
6993
|
+
|
|
6994
|
+
// src/orm/relations/morph-many.ts
|
|
6995
|
+
var toKey8 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
6996
|
+
var hideInternal6 = (obj, keys) => {
|
|
6997
|
+
for (const key of keys) {
|
|
6998
|
+
Object.defineProperty(obj, key, {
|
|
6999
|
+
value: obj[key],
|
|
7000
|
+
writable: false,
|
|
7001
|
+
configurable: false,
|
|
7002
|
+
enumerable: false
|
|
7003
|
+
});
|
|
7004
|
+
}
|
|
7005
|
+
};
|
|
7006
|
+
var hideWritable6 = (obj, keys) => {
|
|
7007
|
+
for (const key of keys) {
|
|
7008
|
+
const value = obj[key];
|
|
7009
|
+
Object.defineProperty(obj, key, {
|
|
7010
|
+
value,
|
|
7011
|
+
writable: true,
|
|
7012
|
+
configurable: true,
|
|
7013
|
+
enumerable: false
|
|
7014
|
+
});
|
|
7015
|
+
}
|
|
7016
|
+
};
|
|
7017
|
+
var DefaultMorphManyCollection = class {
|
|
7018
|
+
constructor(ctx, meta, root, relationName, relation, rootTable, loader, createEntity, localKey) {
|
|
7019
|
+
this.ctx = ctx;
|
|
7020
|
+
this.meta = meta;
|
|
7021
|
+
this.root = root;
|
|
7022
|
+
this.relationName = relationName;
|
|
7023
|
+
this.relation = relation;
|
|
7024
|
+
this.rootTable = rootTable;
|
|
7025
|
+
this.loader = loader;
|
|
7026
|
+
this.createEntity = createEntity;
|
|
7027
|
+
this.localKey = localKey;
|
|
7028
|
+
hideInternal6(this, ["ctx", "meta", "root", "relationName", "relation", "rootTable", "loader", "createEntity", "localKey"]);
|
|
7029
|
+
hideWritable6(this, ["loaded", "items", "added", "removed"]);
|
|
7030
|
+
this.hydrateFromCache();
|
|
7031
|
+
}
|
|
7032
|
+
loaded = false;
|
|
7033
|
+
items = [];
|
|
7034
|
+
added = /* @__PURE__ */ new Set();
|
|
7035
|
+
removed = /* @__PURE__ */ new Set();
|
|
7036
|
+
async load() {
|
|
7037
|
+
if (this.loaded) return this.items;
|
|
7038
|
+
const map = await this.loader();
|
|
7039
|
+
const key = toKey8(this.root[this.localKey]);
|
|
7040
|
+
const rows = map.get(key) ?? [];
|
|
7041
|
+
this.items = rows.map((row) => this.createEntity(row));
|
|
7042
|
+
this.loaded = true;
|
|
7043
|
+
return this.items;
|
|
7044
|
+
}
|
|
7045
|
+
getItems() {
|
|
7046
|
+
return this.items;
|
|
7047
|
+
}
|
|
7048
|
+
get length() {
|
|
7049
|
+
return this.items.length;
|
|
7050
|
+
}
|
|
7051
|
+
[Symbol.iterator]() {
|
|
7052
|
+
return this.items[Symbol.iterator]();
|
|
7053
|
+
}
|
|
7054
|
+
add(data) {
|
|
7055
|
+
const keyValue = this.root[this.localKey];
|
|
7056
|
+
const childRow = {
|
|
7057
|
+
...data,
|
|
7058
|
+
[this.relation.idField]: keyValue,
|
|
7059
|
+
[this.relation.typeField]: this.relation.typeValue
|
|
7060
|
+
};
|
|
7061
|
+
const entity = this.createEntity(childRow);
|
|
7062
|
+
this.added.add(entity);
|
|
7063
|
+
this.items.push(entity);
|
|
7064
|
+
this.ctx.registerRelationChange(
|
|
7065
|
+
this.root,
|
|
7066
|
+
this.relationKey,
|
|
7067
|
+
this.rootTable,
|
|
7068
|
+
this.relationName,
|
|
7069
|
+
this.relation,
|
|
7070
|
+
{ kind: "add", entity }
|
|
7071
|
+
);
|
|
7072
|
+
return entity;
|
|
7073
|
+
}
|
|
7074
|
+
attach(entity) {
|
|
7075
|
+
const keyValue = this.root[this.localKey];
|
|
7076
|
+
entity[this.relation.idField] = keyValue;
|
|
7077
|
+
entity[this.relation.typeField] = this.relation.typeValue;
|
|
7078
|
+
this.ctx.markDirty(entity);
|
|
7079
|
+
this.items.push(entity);
|
|
7080
|
+
this.ctx.registerRelationChange(
|
|
7081
|
+
this.root,
|
|
7082
|
+
this.relationKey,
|
|
7083
|
+
this.rootTable,
|
|
7084
|
+
this.relationName,
|
|
7085
|
+
this.relation,
|
|
7086
|
+
{ kind: "attach", entity }
|
|
7087
|
+
);
|
|
7088
|
+
}
|
|
7089
|
+
remove(entity) {
|
|
7090
|
+
this.items = this.items.filter((item) => item !== entity);
|
|
7091
|
+
this.removed.add(entity);
|
|
7092
|
+
this.ctx.registerRelationChange(
|
|
7093
|
+
this.root,
|
|
7094
|
+
this.relationKey,
|
|
7095
|
+
this.rootTable,
|
|
7096
|
+
this.relationName,
|
|
7097
|
+
this.relation,
|
|
7098
|
+
{ kind: "remove", entity }
|
|
7099
|
+
);
|
|
7100
|
+
}
|
|
7101
|
+
clear() {
|
|
7102
|
+
for (const entity of [...this.items]) {
|
|
7103
|
+
this.remove(entity);
|
|
7104
|
+
}
|
|
7105
|
+
}
|
|
7106
|
+
get relationKey() {
|
|
7107
|
+
return `${this.rootTable.name}.${this.relationName}`;
|
|
7108
|
+
}
|
|
7109
|
+
hydrateFromCache() {
|
|
7110
|
+
const keyValue = this.root[this.localKey];
|
|
7111
|
+
if (keyValue === void 0 || keyValue === null) return;
|
|
7112
|
+
const rows = getHydrationRows(this.meta, this.relationName, keyValue);
|
|
7113
|
+
if (!rows?.length) return;
|
|
7114
|
+
this.items = rows.map((row) => this.createEntity(row));
|
|
7115
|
+
this.loaded = true;
|
|
7116
|
+
}
|
|
7117
|
+
toJSON() {
|
|
7118
|
+
return this.items.map((item) => {
|
|
7119
|
+
const entityWithToJSON = item;
|
|
7120
|
+
return typeof entityWithToJSON.toJSON === "function" ? entityWithToJSON.toJSON() : item;
|
|
7121
|
+
});
|
|
7122
|
+
}
|
|
7123
|
+
};
|
|
7124
|
+
|
|
7125
|
+
// src/orm/relations/morph-to.ts
|
|
7126
|
+
var toKey9 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
7127
|
+
var hideInternal7 = (obj, keys) => {
|
|
7128
|
+
for (const key of keys) {
|
|
7129
|
+
Object.defineProperty(obj, key, {
|
|
7130
|
+
value: obj[key],
|
|
7131
|
+
writable: false,
|
|
7132
|
+
configurable: false,
|
|
7133
|
+
enumerable: false
|
|
7134
|
+
});
|
|
7135
|
+
}
|
|
7136
|
+
};
|
|
7137
|
+
var hideWritable7 = (obj, keys) => {
|
|
7138
|
+
for (const key of keys) {
|
|
7139
|
+
const value = obj[key];
|
|
7140
|
+
Object.defineProperty(obj, key, {
|
|
7141
|
+
value,
|
|
7142
|
+
writable: true,
|
|
7143
|
+
configurable: true,
|
|
7144
|
+
enumerable: false
|
|
7145
|
+
});
|
|
7146
|
+
}
|
|
7147
|
+
};
|
|
7148
|
+
var DefaultMorphToReference = class {
|
|
7149
|
+
constructor(ctx, meta, root, relationName, relation, rootTable, loader, createEntity, resolveTargetTable) {
|
|
7150
|
+
this.ctx = ctx;
|
|
7151
|
+
this.meta = meta;
|
|
7152
|
+
this.root = root;
|
|
7153
|
+
this.relationName = relationName;
|
|
7154
|
+
this.relation = relation;
|
|
7155
|
+
this.rootTable = rootTable;
|
|
7156
|
+
this.loader = loader;
|
|
7157
|
+
this.createEntity = createEntity;
|
|
7158
|
+
this.resolveTargetTable = resolveTargetTable;
|
|
7159
|
+
hideInternal7(this, [
|
|
7160
|
+
"ctx",
|
|
7161
|
+
"meta",
|
|
7162
|
+
"root",
|
|
7163
|
+
"relationName",
|
|
7164
|
+
"relation",
|
|
7165
|
+
"rootTable",
|
|
7166
|
+
"loader",
|
|
7167
|
+
"createEntity",
|
|
7168
|
+
"resolveTargetTable"
|
|
7169
|
+
]);
|
|
7170
|
+
hideWritable7(this, ["loaded", "current"]);
|
|
7171
|
+
this.populateFromHydrationCache();
|
|
7172
|
+
}
|
|
7173
|
+
loaded = false;
|
|
7174
|
+
current = null;
|
|
7175
|
+
async load() {
|
|
7176
|
+
if (this.loaded) return this.current;
|
|
7177
|
+
const rootObj = this.root;
|
|
7178
|
+
const typeValue = rootObj[this.relation.typeField];
|
|
7179
|
+
const idValue = rootObj[this.relation.idField];
|
|
7180
|
+
if (!typeValue || idValue === void 0 || idValue === null) {
|
|
7181
|
+
this.loaded = true;
|
|
7182
|
+
return this.current;
|
|
7183
|
+
}
|
|
7184
|
+
const map = await this.loader();
|
|
7185
|
+
const compositeKey = `${toKey9(typeValue)}:${toKey9(idValue)}`;
|
|
7186
|
+
const row = map.get(compositeKey);
|
|
7187
|
+
if (row) {
|
|
7188
|
+
const targetTable = this.resolveTargetTable(toKey9(typeValue));
|
|
7189
|
+
if (targetTable) {
|
|
7190
|
+
this.current = this.createEntity(targetTable, row);
|
|
7191
|
+
}
|
|
7192
|
+
}
|
|
7193
|
+
this.loaded = true;
|
|
7194
|
+
return this.current;
|
|
7195
|
+
}
|
|
7196
|
+
get() {
|
|
7197
|
+
return this.current;
|
|
7198
|
+
}
|
|
7199
|
+
set(data) {
|
|
7200
|
+
if (data === null) {
|
|
7201
|
+
return this.detachCurrent();
|
|
7202
|
+
}
|
|
7203
|
+
const entity = hasEntityMeta(data) ? data : data;
|
|
7204
|
+
if (this.current && this.current !== entity) {
|
|
7205
|
+
this.ctx.registerRelationChange(
|
|
7206
|
+
this.root,
|
|
7207
|
+
this.relationKey,
|
|
7208
|
+
this.rootTable,
|
|
7209
|
+
this.relationName,
|
|
7210
|
+
this.relation,
|
|
7211
|
+
{ kind: "remove", entity: this.current }
|
|
7212
|
+
);
|
|
7213
|
+
}
|
|
7214
|
+
this.current = entity;
|
|
7215
|
+
this.loaded = true;
|
|
7216
|
+
this.ctx.registerRelationChange(
|
|
7217
|
+
this.root,
|
|
7218
|
+
this.relationKey,
|
|
7219
|
+
this.rootTable,
|
|
7220
|
+
this.relationName,
|
|
7221
|
+
this.relation,
|
|
7222
|
+
{ kind: "attach", entity }
|
|
7223
|
+
);
|
|
7224
|
+
return entity;
|
|
7225
|
+
}
|
|
7226
|
+
toJSON() {
|
|
7227
|
+
if (!this.current) return null;
|
|
7228
|
+
const entityWithToJSON = this.current;
|
|
7229
|
+
return typeof entityWithToJSON.toJSON === "function" ? entityWithToJSON.toJSON() : this.current;
|
|
7230
|
+
}
|
|
7231
|
+
detachCurrent() {
|
|
7232
|
+
const previous = this.current;
|
|
7233
|
+
if (!previous) return null;
|
|
7234
|
+
this.current = null;
|
|
7235
|
+
this.loaded = true;
|
|
7236
|
+
const rootObj = this.root;
|
|
7237
|
+
rootObj[this.relation.typeField] = null;
|
|
7238
|
+
rootObj[this.relation.idField] = null;
|
|
7239
|
+
this.ctx.registerRelationChange(
|
|
7240
|
+
this.root,
|
|
7241
|
+
this.relationKey,
|
|
7242
|
+
this.rootTable,
|
|
7243
|
+
this.relationName,
|
|
7244
|
+
this.relation,
|
|
7245
|
+
{ kind: "remove", entity: previous }
|
|
7246
|
+
);
|
|
7247
|
+
return null;
|
|
7248
|
+
}
|
|
7249
|
+
get relationKey() {
|
|
7250
|
+
return `${this.rootTable.name}.${this.relationName}`;
|
|
7251
|
+
}
|
|
7252
|
+
populateFromHydrationCache() {
|
|
7253
|
+
const rootObj = this.root;
|
|
7254
|
+
const typeValue = rootObj[this.relation.typeField];
|
|
7255
|
+
const idValue = rootObj[this.relation.idField];
|
|
7256
|
+
if (!typeValue || idValue === void 0 || idValue === null) return;
|
|
7257
|
+
const compositeKey = `${toKey9(typeValue)}:${toKey9(idValue)}`;
|
|
7258
|
+
const row = getHydrationRecord(this.meta, this.relationName, compositeKey);
|
|
7259
|
+
if (!row) return;
|
|
7260
|
+
const targetTable = this.resolveTargetTable(toKey9(typeValue));
|
|
7261
|
+
if (targetTable) {
|
|
7262
|
+
this.current = this.createEntity(targetTable, row);
|
|
7263
|
+
this.loaded = true;
|
|
7264
|
+
}
|
|
7265
|
+
}
|
|
7266
|
+
};
|
|
7267
|
+
|
|
7268
|
+
// src/orm/lazy-batch/shared.ts
|
|
7269
|
+
var hasColumns = (columns) => Boolean(columns && columns.length > 0);
|
|
7270
|
+
var buildColumnSelection = (table, columns, missingMsg) => {
|
|
7271
|
+
return columns.reduce((acc, column) => {
|
|
7272
|
+
const def = table.columns[column];
|
|
7273
|
+
if (!def) {
|
|
7274
|
+
throw new Error(missingMsg(column));
|
|
7275
|
+
}
|
|
7276
|
+
acc[column] = def;
|
|
7277
|
+
return acc;
|
|
7278
|
+
}, {});
|
|
7279
|
+
};
|
|
7280
|
+
var filterRow = (row, columns) => {
|
|
7281
|
+
const filtered = {};
|
|
7282
|
+
for (const column of columns) {
|
|
7283
|
+
if (column in row) {
|
|
7284
|
+
filtered[column] = row[column];
|
|
7285
|
+
}
|
|
7286
|
+
}
|
|
7287
|
+
return filtered;
|
|
7288
|
+
};
|
|
7289
|
+
var filterRows = (rows, columns) => rows.map((row) => filterRow(row, columns));
|
|
7290
|
+
var rowsFromResults = (results) => {
|
|
7291
|
+
const rows = [];
|
|
7292
|
+
for (const result of results) {
|
|
7293
|
+
const { columns, values } = result;
|
|
7294
|
+
for (const valueRow of values) {
|
|
7295
|
+
const row = {};
|
|
7296
|
+
columns.forEach((column, idx) => {
|
|
7297
|
+
row[column] = valueRow[idx];
|
|
7298
|
+
});
|
|
7299
|
+
rows.push(row);
|
|
7300
|
+
}
|
|
7301
|
+
}
|
|
7302
|
+
return rows;
|
|
7303
|
+
};
|
|
7304
|
+
var executeQuery = async (ctx, qb) => {
|
|
7305
|
+
const compiled = ctx.dialect.compileSelect(qb.getAST());
|
|
7306
|
+
const results = await ctx.executor.executeSql(compiled.sql, compiled.params);
|
|
7307
|
+
return rowsFromResults(results);
|
|
7308
|
+
};
|
|
7309
|
+
var toKey10 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
7310
|
+
var collectKeysFromRoots = (roots, key) => {
|
|
7311
|
+
const collected = /* @__PURE__ */ new Set();
|
|
7312
|
+
for (const tracked of roots) {
|
|
7313
|
+
const value = tracked.entity[key];
|
|
7314
|
+
if (value !== null && value !== void 0) {
|
|
7315
|
+
collected.add(value);
|
|
7316
|
+
}
|
|
7317
|
+
}
|
|
7318
|
+
return collected;
|
|
7319
|
+
};
|
|
7320
|
+
var buildInListValues = (keys) => Array.from(keys);
|
|
7321
|
+
var fetchRowsForKeys = async (ctx, table, column, keys, selection, filter) => {
|
|
7322
|
+
let qb = new SelectQueryBuilder(table).select(selection);
|
|
7323
|
+
qb = qb.where(inList(column, buildInListValues(keys)));
|
|
7324
|
+
if (filter) {
|
|
7325
|
+
qb = qb.where(filter);
|
|
7326
|
+
}
|
|
7327
|
+
return executeQuery(ctx, qb);
|
|
7328
|
+
};
|
|
7329
|
+
var groupRowsByMany = (rows, keyColumn) => {
|
|
7330
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
7331
|
+
for (const row of rows) {
|
|
7332
|
+
const value = row[keyColumn];
|
|
7333
|
+
if (value === null || value === void 0) continue;
|
|
7334
|
+
const key = toKey10(value);
|
|
7335
|
+
const bucket = grouped.get(key) ?? [];
|
|
7336
|
+
bucket.push(row);
|
|
7337
|
+
grouped.set(key, bucket);
|
|
7338
|
+
}
|
|
7339
|
+
return grouped;
|
|
7340
|
+
};
|
|
7341
|
+
var groupRowsByUnique = (rows, keyColumn) => {
|
|
7342
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
7343
|
+
for (const row of rows) {
|
|
7344
|
+
const value = row[keyColumn];
|
|
7345
|
+
if (value === null || value === void 0) continue;
|
|
7346
|
+
const key = toKey10(value);
|
|
7347
|
+
if (!lookup.has(key)) {
|
|
7348
|
+
lookup.set(key, row);
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
7351
|
+
return lookup;
|
|
7352
|
+
};
|
|
7353
|
+
|
|
7354
|
+
// src/orm/lazy-batch/has-many.ts
|
|
7355
|
+
var loadHasManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
7356
|
+
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
7357
|
+
const roots = ctx.getEntitiesForTable(rootTable);
|
|
7358
|
+
const keys = collectKeysFromRoots(roots, localKey);
|
|
7359
|
+
if (!keys.size) {
|
|
7360
|
+
return /* @__PURE__ */ new Map();
|
|
7361
|
+
}
|
|
7362
|
+
const fkColumn = relation.target.columns[relation.foreignKey];
|
|
7363
|
+
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
7364
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
7365
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
7366
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
7367
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
7368
|
+
selectedColumns.push(targetPrimaryKey);
|
|
7369
|
+
}
|
|
7370
|
+
const queryColumns = new Set(selectedColumns);
|
|
7371
|
+
queryColumns.add(relation.foreignKey);
|
|
7372
|
+
const selection = buildColumnSelection(
|
|
7373
|
+
relation.target,
|
|
7374
|
+
Array.from(queryColumns),
|
|
6717
7375
|
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
6718
7376
|
);
|
|
6719
7377
|
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, options?.filter);
|
|
@@ -6870,12 +7528,12 @@ var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, o
|
|
|
6870
7528
|
if (rootValue === null || rootValue === void 0 || targetValue === null || targetValue === void 0) {
|
|
6871
7529
|
continue;
|
|
6872
7530
|
}
|
|
6873
|
-
const bucket = rootLookup.get(
|
|
7531
|
+
const bucket = rootLookup.get(toKey10(rootValue)) ?? [];
|
|
6874
7532
|
bucket.push({
|
|
6875
7533
|
targetId: targetValue,
|
|
6876
7534
|
pivot: pivotVisibleColumns.size ? filterRow(pivot, pivotVisibleColumns) : {}
|
|
6877
7535
|
});
|
|
6878
|
-
rootLookup.set(
|
|
7536
|
+
rootLookup.set(toKey10(rootValue), bucket);
|
|
6879
7537
|
targetIds.add(targetValue);
|
|
6880
7538
|
}
|
|
6881
7539
|
if (!targetIds.size) {
|
|
@@ -6908,7 +7566,7 @@ var loadBelongsToManyRelation = async (ctx, rootTable, relationName, relation, o
|
|
|
6908
7566
|
for (const [rootId, entries] of rootLookup.entries()) {
|
|
6909
7567
|
const bucket = [];
|
|
6910
7568
|
for (const entry of entries) {
|
|
6911
|
-
const targetRow = targetMap.get(
|
|
7569
|
+
const targetRow = targetMap.get(toKey10(entry.targetId));
|
|
6912
7570
|
if (!targetRow) continue;
|
|
6913
7571
|
const row = targetRequestedColumns ? filterRow(targetRow, targetVisibleColumns) : { ...targetRow };
|
|
6914
7572
|
if (options?.pivot?.merge) {
|
|
@@ -6927,6 +7585,123 @@ var mergePivotIntoRow = (row, pivot) => {
|
|
|
6927
7585
|
}
|
|
6928
7586
|
};
|
|
6929
7587
|
|
|
7588
|
+
// src/orm/lazy-batch/morph-one.ts
|
|
7589
|
+
var loadMorphOneRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
7590
|
+
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
7591
|
+
const roots = ctx.getEntitiesForTable(rootTable);
|
|
7592
|
+
const keys = collectKeysFromRoots(roots, localKey);
|
|
7593
|
+
if (!keys.size) {
|
|
7594
|
+
return /* @__PURE__ */ new Map();
|
|
7595
|
+
}
|
|
7596
|
+
const fkColumn = relation.target.columns[relation.idField];
|
|
7597
|
+
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
7598
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
7599
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
7600
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
7601
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
7602
|
+
selectedColumns.push(targetPrimaryKey);
|
|
7603
|
+
}
|
|
7604
|
+
const queryColumns = new Set(selectedColumns);
|
|
7605
|
+
queryColumns.add(relation.idField);
|
|
7606
|
+
const selection = buildColumnSelection(
|
|
7607
|
+
relation.target,
|
|
7608
|
+
Array.from(queryColumns),
|
|
7609
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
7610
|
+
);
|
|
7611
|
+
const typeColumn = relation.target.columns[relation.typeField];
|
|
7612
|
+
const discriminatorFilter = eq(
|
|
7613
|
+
typeColumn ?? { type: "Column", table: relation.target.name, name: relation.typeField },
|
|
7614
|
+
{ type: "Literal", value: relation.typeValue }
|
|
7615
|
+
);
|
|
7616
|
+
const combinedFilter = options?.filter ? and(options.filter, discriminatorFilter) : discriminatorFilter;
|
|
7617
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, combinedFilter);
|
|
7618
|
+
const grouped = groupRowsByUnique(rows, relation.idField);
|
|
7619
|
+
if (!requestedColumns) return grouped;
|
|
7620
|
+
const visibleColumns = new Set(selectedColumns);
|
|
7621
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
7622
|
+
for (const [key, row] of grouped.entries()) {
|
|
7623
|
+
filtered.set(key, filterRow(row, visibleColumns));
|
|
7624
|
+
}
|
|
7625
|
+
return filtered;
|
|
7626
|
+
};
|
|
7627
|
+
|
|
7628
|
+
// src/orm/lazy-batch/morph-many.ts
|
|
7629
|
+
var loadMorphManyRelation = async (ctx, rootTable, relationName, relation, options) => {
|
|
7630
|
+
const localKey = relation.localKey || findPrimaryKey(rootTable);
|
|
7631
|
+
const roots = ctx.getEntitiesForTable(rootTable);
|
|
7632
|
+
const keys = collectKeysFromRoots(roots, localKey);
|
|
7633
|
+
if (!keys.size) {
|
|
7634
|
+
return /* @__PURE__ */ new Map();
|
|
7635
|
+
}
|
|
7636
|
+
const fkColumn = relation.target.columns[relation.idField];
|
|
7637
|
+
if (!fkColumn) return /* @__PURE__ */ new Map();
|
|
7638
|
+
const requestedColumns = hasColumns(options?.columns) ? [...options.columns] : void 0;
|
|
7639
|
+
const targetPrimaryKey = findPrimaryKey(relation.target);
|
|
7640
|
+
const selectedColumns = requestedColumns ? [...requestedColumns] : Object.keys(relation.target.columns);
|
|
7641
|
+
if (!selectedColumns.includes(targetPrimaryKey)) {
|
|
7642
|
+
selectedColumns.push(targetPrimaryKey);
|
|
7643
|
+
}
|
|
7644
|
+
const queryColumns = new Set(selectedColumns);
|
|
7645
|
+
queryColumns.add(relation.idField);
|
|
7646
|
+
const selection = buildColumnSelection(
|
|
7647
|
+
relation.target,
|
|
7648
|
+
Array.from(queryColumns),
|
|
7649
|
+
(column) => `Column '${column}' not found on relation '${relationName}'`
|
|
7650
|
+
);
|
|
7651
|
+
const typeColumn = relation.target.columns[relation.typeField];
|
|
7652
|
+
const discriminatorFilter = eq(
|
|
7653
|
+
typeColumn ?? { type: "Column", table: relation.target.name, name: relation.typeField },
|
|
7654
|
+
{ type: "Literal", value: relation.typeValue }
|
|
7655
|
+
);
|
|
7656
|
+
const combinedFilter = options?.filter ? and(options.filter, discriminatorFilter) : discriminatorFilter;
|
|
7657
|
+
const rows = await fetchRowsForKeys(ctx, relation.target, fkColumn, keys, selection, combinedFilter);
|
|
7658
|
+
const grouped = groupRowsByMany(rows, relation.idField);
|
|
7659
|
+
if (!requestedColumns) return grouped;
|
|
7660
|
+
const visibleColumns = new Set(selectedColumns);
|
|
7661
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
7662
|
+
for (const [key, bucket] of grouped.entries()) {
|
|
7663
|
+
filtered.set(key, filterRows(bucket, visibleColumns));
|
|
7664
|
+
}
|
|
7665
|
+
return filtered;
|
|
7666
|
+
};
|
|
7667
|
+
|
|
7668
|
+
// src/orm/lazy-batch/morph-to.ts
|
|
7669
|
+
var loadMorphToRelation = async (ctx, rootTable, _relationName, relation) => {
|
|
7670
|
+
const roots = ctx.getEntitiesForTable(rootTable);
|
|
7671
|
+
const result = /* @__PURE__ */ new Map();
|
|
7672
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
7673
|
+
for (const tracked of roots) {
|
|
7674
|
+
const entity = tracked.entity;
|
|
7675
|
+
const typeValue = entity[relation.typeField];
|
|
7676
|
+
const idValue = entity[relation.idField];
|
|
7677
|
+
if (!typeValue || idValue === void 0 || idValue === null) continue;
|
|
7678
|
+
const typeKey = toKey10(typeValue);
|
|
7679
|
+
const ids = grouped.get(typeKey) ?? /* @__PURE__ */ new Set();
|
|
7680
|
+
ids.add(idValue);
|
|
7681
|
+
grouped.set(typeKey, ids);
|
|
7682
|
+
}
|
|
7683
|
+
for (const [typeKey, ids] of grouped.entries()) {
|
|
7684
|
+
const targetTable = relation.targets[typeKey];
|
|
7685
|
+
if (!targetTable) continue;
|
|
7686
|
+
const targetPk = relation.targetKey || findPrimaryKey(targetTable);
|
|
7687
|
+
const pkColumn = targetTable.columns[targetPk];
|
|
7688
|
+
if (!pkColumn) continue;
|
|
7689
|
+
const selection = buildColumnSelection(
|
|
7690
|
+
targetTable,
|
|
7691
|
+
Object.keys(targetTable.columns),
|
|
7692
|
+
(column) => `Column '${column}' not found on target '${targetTable.name}'`
|
|
7693
|
+
);
|
|
7694
|
+
const rows = await fetchRowsForKeys(ctx, targetTable, pkColumn, ids, selection);
|
|
7695
|
+
for (const row of rows) {
|
|
7696
|
+
const pkValue = row[targetPk];
|
|
7697
|
+
if (pkValue === void 0 || pkValue === null) continue;
|
|
7698
|
+
const compositeKey = `${typeKey}:${toKey10(pkValue)}`;
|
|
7699
|
+
result.set(compositeKey, row);
|
|
7700
|
+
}
|
|
7701
|
+
}
|
|
7702
|
+
return result;
|
|
7703
|
+
};
|
|
7704
|
+
|
|
6930
7705
|
// src/orm/entity-relation-cache.ts
|
|
6931
7706
|
var relationLoaderCache = (meta, relationName, factory) => {
|
|
6932
7707
|
if (meta.relationCache.has(relationName)) {
|
|
@@ -7088,8 +7863,62 @@ var instantiateWrapper = (meta, relationName, relation, owner, createEntity) =>
|
|
|
7088
7863
|
many,
|
|
7089
7864
|
meta.table,
|
|
7090
7865
|
loader,
|
|
7091
|
-
(row) => createEntity(relation.target, row),
|
|
7092
|
-
localKey
|
|
7866
|
+
(row) => createEntity(relation.target, row),
|
|
7867
|
+
localKey
|
|
7868
|
+
);
|
|
7869
|
+
}
|
|
7870
|
+
case RelationKinds.MorphOne: {
|
|
7871
|
+
const morphOne2 = relation;
|
|
7872
|
+
const localKey = morphOne2.localKey || findPrimaryKey(meta.table);
|
|
7873
|
+
const loader = () => loadCached(
|
|
7874
|
+
() => loadMorphOneRelation(meta.ctx, meta.table, relationName, morphOne2, resolveOptions())
|
|
7875
|
+
);
|
|
7876
|
+
return new DefaultMorphOneReference(
|
|
7877
|
+
meta.ctx,
|
|
7878
|
+
metaBase,
|
|
7879
|
+
owner,
|
|
7880
|
+
relationName,
|
|
7881
|
+
morphOne2,
|
|
7882
|
+
meta.table,
|
|
7883
|
+
loader,
|
|
7884
|
+
(row) => createEntity(morphOne2.target, row),
|
|
7885
|
+
localKey
|
|
7886
|
+
);
|
|
7887
|
+
}
|
|
7888
|
+
case RelationKinds.MorphMany: {
|
|
7889
|
+
const morphMany2 = relation;
|
|
7890
|
+
const localKey = morphMany2.localKey || findPrimaryKey(meta.table);
|
|
7891
|
+
const loader = () => loadCached(
|
|
7892
|
+
() => loadMorphManyRelation(meta.ctx, meta.table, relationName, morphMany2, resolveOptions())
|
|
7893
|
+
);
|
|
7894
|
+
return new DefaultMorphManyCollection(
|
|
7895
|
+
meta.ctx,
|
|
7896
|
+
metaBase,
|
|
7897
|
+
owner,
|
|
7898
|
+
relationName,
|
|
7899
|
+
morphMany2,
|
|
7900
|
+
meta.table,
|
|
7901
|
+
loader,
|
|
7902
|
+
(row) => createEntity(morphMany2.target, row),
|
|
7903
|
+
localKey
|
|
7904
|
+
);
|
|
7905
|
+
}
|
|
7906
|
+
case RelationKinds.MorphTo: {
|
|
7907
|
+
const morphTo2 = relation;
|
|
7908
|
+
const loader = () => loadCached(
|
|
7909
|
+
() => loadMorphToRelation(meta.ctx, meta.table, relationName, morphTo2)
|
|
7910
|
+
);
|
|
7911
|
+
const resolveTargetTable = (typeValue) => morphTo2.targets[typeValue];
|
|
7912
|
+
return new DefaultMorphToReference(
|
|
7913
|
+
meta.ctx,
|
|
7914
|
+
metaBase,
|
|
7915
|
+
owner,
|
|
7916
|
+
relationName,
|
|
7917
|
+
morphTo2,
|
|
7918
|
+
meta.table,
|
|
7919
|
+
loader,
|
|
7920
|
+
(table, row) => createEntity(table, row),
|
|
7921
|
+
resolveTargetTable
|
|
7093
7922
|
);
|
|
7094
7923
|
}
|
|
7095
7924
|
default:
|
|
@@ -7117,7 +7946,7 @@ var createEntityProxy = (ctx, table, row, lazyRelations = [], lazyRelationOption
|
|
|
7117
7946
|
const isCollectionRelation = (relationName) => {
|
|
7118
7947
|
const rel = table.relations[relationName];
|
|
7119
7948
|
if (!rel) return false;
|
|
7120
|
-
return rel.type === RelationKinds.HasMany || rel.type === RelationKinds.BelongsToMany;
|
|
7949
|
+
return rel.type === RelationKinds.HasMany || rel.type === RelationKinds.BelongsToMany || rel.type === RelationKinds.MorphMany;
|
|
7121
7950
|
};
|
|
7122
7951
|
const buildJson = (self, options) => {
|
|
7123
7952
|
const json = {};
|
|
@@ -7299,9 +8128,11 @@ function rowsToQueryResult(rows) {
|
|
|
7299
8128
|
}
|
|
7300
8129
|
function createExecutorFromQueryRunner(runner) {
|
|
7301
8130
|
const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
|
|
8131
|
+
const supportsSavepoints = supportsTransactions && typeof runner.savepoint === "function" && typeof runner.releaseSavepoint === "function" && typeof runner.rollbackToSavepoint === "function";
|
|
7302
8132
|
return {
|
|
7303
8133
|
capabilities: {
|
|
7304
|
-
transactions: supportsTransactions
|
|
8134
|
+
transactions: supportsTransactions,
|
|
8135
|
+
...supportsSavepoints ? { savepoints: true } : {}
|
|
7305
8136
|
},
|
|
7306
8137
|
async executeSql(sql, params) {
|
|
7307
8138
|
const rows = await runner.query(sql, params);
|
|
@@ -7326,6 +8157,24 @@ function createExecutorFromQueryRunner(runner) {
|
|
|
7326
8157
|
}
|
|
7327
8158
|
await runner.rollbackTransaction.call(runner);
|
|
7328
8159
|
},
|
|
8160
|
+
async savepoint(name) {
|
|
8161
|
+
if (!supportsSavepoints) {
|
|
8162
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
8163
|
+
}
|
|
8164
|
+
await runner.savepoint.call(runner, name);
|
|
8165
|
+
},
|
|
8166
|
+
async releaseSavepoint(name) {
|
|
8167
|
+
if (!supportsSavepoints) {
|
|
8168
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
8169
|
+
}
|
|
8170
|
+
await runner.releaseSavepoint.call(runner, name);
|
|
8171
|
+
},
|
|
8172
|
+
async rollbackToSavepoint(name) {
|
|
8173
|
+
if (!supportsSavepoints) {
|
|
8174
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
8175
|
+
}
|
|
8176
|
+
await runner.rollbackToSavepoint.call(runner, name);
|
|
8177
|
+
},
|
|
7329
8178
|
async dispose() {
|
|
7330
8179
|
await runner.dispose?.call(runner);
|
|
7331
8180
|
}
|
|
@@ -7700,6 +8549,9 @@ function buildWhereHasPredicate(env, context, relationFacet, createChildBuilder,
|
|
|
7700
8549
|
}
|
|
7701
8550
|
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
7702
8551
|
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
8552
|
+
if (!isSingleTargetRelation(relation)) {
|
|
8553
|
+
throw new Error(`Polymorphic relation '${relationName}' does not support whereHas/whereHasNot`);
|
|
8554
|
+
}
|
|
7703
8555
|
let subQb = createChildBuilder(relation.target);
|
|
7704
8556
|
if (callback) {
|
|
7705
8557
|
subQb = callback(subQb);
|
|
@@ -7714,6 +8566,193 @@ function buildWhereHasPredicate(env, context, relationFacet, createChildBuilder,
|
|
|
7714
8566
|
return negate ? notExists(finalSubAst) : exists(finalSubAst);
|
|
7715
8567
|
}
|
|
7716
8568
|
|
|
8569
|
+
// src/query-builder/select/cursor-pagination.ts
|
|
8570
|
+
function encodeCursor(payload) {
|
|
8571
|
+
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
8572
|
+
}
|
|
8573
|
+
function decodeCursor(cursor) {
|
|
8574
|
+
let parsed;
|
|
8575
|
+
try {
|
|
8576
|
+
parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
8577
|
+
} catch {
|
|
8578
|
+
throw new Error("executeCursor: invalid cursor format");
|
|
8579
|
+
}
|
|
8580
|
+
if (typeof parsed !== "object" || parsed === null || parsed.v !== 2 || !Array.isArray(parsed.values) || typeof parsed.orderSig !== "string") {
|
|
8581
|
+
throw new Error("executeCursor: invalid cursor payload");
|
|
8582
|
+
}
|
|
8583
|
+
return parsed;
|
|
8584
|
+
}
|
|
8585
|
+
function buildOrderSignature(specs) {
|
|
8586
|
+
return specs.map((s) => `${s.table}.${s.column}:${s.direction}`).join(",");
|
|
8587
|
+
}
|
|
8588
|
+
function extractOrderSpecs(ast) {
|
|
8589
|
+
if (!ast.orderBy || ast.orderBy.length === 0) {
|
|
8590
|
+
throw new Error("executeCursor: ORDER BY is required for cursor pagination");
|
|
8591
|
+
}
|
|
8592
|
+
return ast.orderBy.map((ob) => {
|
|
8593
|
+
if (ob.nulls) {
|
|
8594
|
+
throw new Error("executeCursor: NULLS FIRST/LAST is not supported for cursor pagination");
|
|
8595
|
+
}
|
|
8596
|
+
const term = ob.term;
|
|
8597
|
+
if (!term || term.type !== "Column") {
|
|
8598
|
+
throw new Error(
|
|
8599
|
+
"executeCursor: only column references are supported in ORDER BY for cursor pagination"
|
|
8600
|
+
);
|
|
8601
|
+
}
|
|
8602
|
+
const col2 = term;
|
|
8603
|
+
return {
|
|
8604
|
+
table: col2.table,
|
|
8605
|
+
column: col2.name,
|
|
8606
|
+
valueKey: resolveOrderValueKey(ast, col2),
|
|
8607
|
+
direction: ob.direction
|
|
8608
|
+
};
|
|
8609
|
+
});
|
|
8610
|
+
}
|
|
8611
|
+
function resolveOrderValueKey(ast, col2) {
|
|
8612
|
+
const projectedColumn = ast.columns.find(
|
|
8613
|
+
(candidate) => candidate.type === "Column" && candidate.table === col2.table && candidate.name === col2.name
|
|
8614
|
+
);
|
|
8615
|
+
return projectedColumn?.alias ?? projectedColumn?.name ?? col2.alias ?? col2.name;
|
|
8616
|
+
}
|
|
8617
|
+
function buildKeysetPredicate(specs, values, mode) {
|
|
8618
|
+
if (values.length !== specs.length) {
|
|
8619
|
+
throw new Error("executeCursor: invalid cursor payload");
|
|
8620
|
+
}
|
|
8621
|
+
const branches = [];
|
|
8622
|
+
for (let i = 0; i < specs.length; i++) {
|
|
8623
|
+
const spec = specs[i];
|
|
8624
|
+
const colNode = { type: "Column", table: spec.table, name: spec.column };
|
|
8625
|
+
const value = values[i];
|
|
8626
|
+
if (value === null || value === void 0) {
|
|
8627
|
+
throw new Error("executeCursor: invalid cursor payload");
|
|
8628
|
+
}
|
|
8629
|
+
const literal = { type: "Literal", value };
|
|
8630
|
+
let operator;
|
|
8631
|
+
if (mode === "after") {
|
|
8632
|
+
operator = spec.direction === "ASC" ? ">" : "<";
|
|
8633
|
+
} else {
|
|
8634
|
+
operator = spec.direction === "ASC" ? "<" : ">";
|
|
8635
|
+
}
|
|
8636
|
+
const eqParts = [];
|
|
8637
|
+
for (let j = 0; j < i; j++) {
|
|
8638
|
+
const prevSpec = specs[j];
|
|
8639
|
+
const prevCol = { type: "Column", table: prevSpec.table, name: prevSpec.column };
|
|
8640
|
+
const prevValue = values[j];
|
|
8641
|
+
if (prevValue === null || prevValue === void 0) {
|
|
8642
|
+
throw new Error("executeCursor: invalid cursor payload");
|
|
8643
|
+
}
|
|
8644
|
+
const prevVal = { type: "Literal", value: prevValue };
|
|
8645
|
+
eqParts.push({
|
|
8646
|
+
type: "BinaryExpression",
|
|
8647
|
+
left: prevCol,
|
|
8648
|
+
operator: "=",
|
|
8649
|
+
right: prevVal
|
|
8650
|
+
});
|
|
8651
|
+
}
|
|
8652
|
+
const breakExpr = {
|
|
8653
|
+
type: "BinaryExpression",
|
|
8654
|
+
left: colNode,
|
|
8655
|
+
operator,
|
|
8656
|
+
right: literal
|
|
8657
|
+
};
|
|
8658
|
+
if (eqParts.length === 0) {
|
|
8659
|
+
branches.push(breakExpr);
|
|
8660
|
+
} else {
|
|
8661
|
+
branches.push(and(...eqParts, breakExpr));
|
|
8662
|
+
}
|
|
8663
|
+
}
|
|
8664
|
+
return branches.length === 1 ? branches[0] : or(...branches);
|
|
8665
|
+
}
|
|
8666
|
+
function buildCursorFromRow(row, specs) {
|
|
8667
|
+
const values = specs.map((spec) => {
|
|
8668
|
+
const value = row[spec.valueKey];
|
|
8669
|
+
if (value === null || value === void 0) {
|
|
8670
|
+
throw new Error("executeCursor: cursor pagination requires non-null ORDER BY values");
|
|
8671
|
+
}
|
|
8672
|
+
return value;
|
|
8673
|
+
});
|
|
8674
|
+
return encodeCursor({ v: 2, values, orderSig: buildOrderSignature(specs) });
|
|
8675
|
+
}
|
|
8676
|
+
function reverseDirection(direction) {
|
|
8677
|
+
return direction === "ASC" ? "DESC" : "ASC";
|
|
8678
|
+
}
|
|
8679
|
+
function createExecutionBuilder(builder, options) {
|
|
8680
|
+
const internals = builder.getInternals();
|
|
8681
|
+
const baseAst = internals.context.state.ast;
|
|
8682
|
+
const orderBy = options.reverseOrder && baseAst.orderBy ? baseAst.orderBy.map((order) => ({
|
|
8683
|
+
...order,
|
|
8684
|
+
direction: reverseDirection(order.direction)
|
|
8685
|
+
})) : baseAst.orderBy;
|
|
8686
|
+
const nextAst = {
|
|
8687
|
+
...baseAst,
|
|
8688
|
+
where: options.predicate ? baseAst.where ? and(baseAst.where, options.predicate) : options.predicate : baseAst.where,
|
|
8689
|
+
orderBy,
|
|
8690
|
+
limit: options.limit
|
|
8691
|
+
};
|
|
8692
|
+
const nextContext = {
|
|
8693
|
+
...internals.context,
|
|
8694
|
+
state: new SelectQueryState(builder.getTable(), nextAst)
|
|
8695
|
+
};
|
|
8696
|
+
return internals.clone(nextContext, internals.includeTree);
|
|
8697
|
+
}
|
|
8698
|
+
async function executeCursorQuery(builder, session, options) {
|
|
8699
|
+
const { first, after, last, before } = options;
|
|
8700
|
+
if (first != null && last != null) {
|
|
8701
|
+
throw new Error('executeCursor: "first" and "last" cannot be used together');
|
|
8702
|
+
}
|
|
8703
|
+
if (after != null && before != null) {
|
|
8704
|
+
throw new Error('executeCursor: "after" and "before" cannot be used together');
|
|
8705
|
+
}
|
|
8706
|
+
if (first == null && last == null) {
|
|
8707
|
+
throw new Error('executeCursor: either "first" or "last" must be provided');
|
|
8708
|
+
}
|
|
8709
|
+
const limit = first ?? last;
|
|
8710
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
8711
|
+
throw new Error(`executeCursor: "${first != null ? "first" : "last"}" must be an integer >= 1`);
|
|
8712
|
+
}
|
|
8713
|
+
const isBackward = last != null;
|
|
8714
|
+
const cursor = after ?? before;
|
|
8715
|
+
const ast = builder.getInternals().context.state.ast;
|
|
8716
|
+
const specs = extractOrderSpecs(ast);
|
|
8717
|
+
let predicate;
|
|
8718
|
+
if (cursor) {
|
|
8719
|
+
const decoded = decodeCursor(cursor);
|
|
8720
|
+
const expectedSig = buildOrderSignature(specs);
|
|
8721
|
+
if (decoded.orderSig !== expectedSig) {
|
|
8722
|
+
throw new Error(
|
|
8723
|
+
"executeCursor: cursor ORDER BY signature does not match the current query. The ORDER BY clause must remain the same between paginated requests."
|
|
8724
|
+
);
|
|
8725
|
+
}
|
|
8726
|
+
predicate = buildKeysetPredicate(specs, decoded.values, isBackward ? "before" : "after");
|
|
8727
|
+
}
|
|
8728
|
+
const executionBuilder = createExecutionBuilder(builder, {
|
|
8729
|
+
predicate,
|
|
8730
|
+
limit: limit + 1,
|
|
8731
|
+
reverseOrder: isBackward
|
|
8732
|
+
});
|
|
8733
|
+
const rows = await executionBuilder.execute(session);
|
|
8734
|
+
const hasExtraItem = rows.length > limit;
|
|
8735
|
+
if (hasExtraItem) {
|
|
8736
|
+
rows.pop();
|
|
8737
|
+
}
|
|
8738
|
+
const orderedRows = isBackward ? rows.reverse() : rows;
|
|
8739
|
+
const items = orderedRows;
|
|
8740
|
+
const hasItems = items.length > 0;
|
|
8741
|
+
const hasNextPage2 = hasItems ? isBackward ? before != null : hasExtraItem : false;
|
|
8742
|
+
const hasPreviousPage = hasItems ? isBackward ? hasExtraItem : after != null : false;
|
|
8743
|
+
const startCursor = hasItems ? buildCursorFromRow(items[0], specs) : null;
|
|
8744
|
+
const endCursor = hasItems ? buildCursorFromRow(items[items.length - 1], specs) : null;
|
|
8745
|
+
return {
|
|
8746
|
+
items,
|
|
8747
|
+
pageInfo: {
|
|
8748
|
+
hasNextPage: hasNextPage2,
|
|
8749
|
+
hasPreviousPage,
|
|
8750
|
+
startCursor,
|
|
8751
|
+
endCursor
|
|
8752
|
+
}
|
|
8753
|
+
};
|
|
8754
|
+
}
|
|
8755
|
+
|
|
7717
8756
|
// src/query-builder/select/from-facet.ts
|
|
7718
8757
|
var SelectFromFacet = class {
|
|
7719
8758
|
/**
|
|
@@ -8740,7 +9779,38 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
8740
9779
|
return executePagedQuery(builder, session, options, (sess) => builder.count(sess));
|
|
8741
9780
|
}
|
|
8742
9781
|
/**
|
|
8743
|
-
* Executes the query
|
|
9782
|
+
* Executes the query using cursor-based (keyset) pagination.
|
|
9783
|
+
* Requires a stable ORDER BY on selected, non-null columns.
|
|
9784
|
+
* Cursor pagination currently supports simple column references only and
|
|
9785
|
+
* the cursor token is opaque: it must be reused with the same ORDER BY signature.
|
|
9786
|
+
*
|
|
9787
|
+
* @param session - ORM session context
|
|
9788
|
+
* @param options - Cursor pagination options (`first`/`after` or `last`/`before`)
|
|
9789
|
+
* @returns Promise of cursor-paginated result with items and pageInfo
|
|
9790
|
+
* @example
|
|
9791
|
+
* const page1 = await selectFrom(users)
|
|
9792
|
+
* .orderBy(users.columns.createdAt, 'DESC')
|
|
9793
|
+
* .orderBy(users.columns.id, 'DESC')
|
|
9794
|
+
* .executeCursor(session, { first: 20 });
|
|
9795
|
+
*
|
|
9796
|
+
* // Next page
|
|
9797
|
+
* const page2 = await selectFrom(users)
|
|
9798
|
+
* .orderBy(users.columns.createdAt, 'DESC')
|
|
9799
|
+
* .orderBy(users.columns.id, 'DESC')
|
|
9800
|
+
* .executeCursor(session, { first: 20, after: page1.pageInfo.endCursor });
|
|
9801
|
+
*
|
|
9802
|
+
* // Previous page from a known cursor
|
|
9803
|
+
* const prevPage = await selectFrom(users)
|
|
9804
|
+
* .orderBy(users.columns.createdAt, 'DESC')
|
|
9805
|
+
* .orderBy(users.columns.id, 'DESC')
|
|
9806
|
+
* .executeCursor(session, { last: 20, before: page2.pageInfo.startCursor });
|
|
9807
|
+
*/
|
|
9808
|
+
async executeCursor(session, options) {
|
|
9809
|
+
const builder = this.ensureDefaultSelection();
|
|
9810
|
+
return executeCursorQuery(builder, session, options);
|
|
9811
|
+
}
|
|
9812
|
+
/**
|
|
9813
|
+
* Executes the query and returns an array of values for a single column.
|
|
8744
9814
|
* This is a convenience method to avoid manual `.map(r => r.column)`.
|
|
8745
9815
|
*
|
|
8746
9816
|
* @param column - The column name to extract
|
|
@@ -9068,6 +10138,7 @@ var isTableDef = (value) => {
|
|
|
9068
10138
|
|
|
9069
10139
|
// src/decorators/decorator-metadata.ts
|
|
9070
10140
|
var METADATA_KEY = "metal-orm:decorators";
|
|
10141
|
+
var LEGACY_METADATA_KEY = /* @__PURE__ */ Symbol.for("metal-orm:decorators:legacy");
|
|
9071
10142
|
var getOrCreateMetadataBag = (context) => {
|
|
9072
10143
|
const metadata = context.metadata || (context.metadata = {});
|
|
9073
10144
|
let bag = metadata[METADATA_KEY];
|
|
@@ -9077,16 +10148,65 @@ var getOrCreateMetadataBag = (context) => {
|
|
|
9077
10148
|
}
|
|
9078
10149
|
return bag;
|
|
9079
10150
|
};
|
|
10151
|
+
var getOrCreateMetadataBagOnConstructor = (ctor) => {
|
|
10152
|
+
const carrier = ctor;
|
|
10153
|
+
let bag = carrier[LEGACY_METADATA_KEY];
|
|
10154
|
+
if (!bag) {
|
|
10155
|
+
bag = { columns: [], relations: [], transformers: [] };
|
|
10156
|
+
carrier[LEGACY_METADATA_KEY] = bag;
|
|
10157
|
+
}
|
|
10158
|
+
return bag;
|
|
10159
|
+
};
|
|
9080
10160
|
var readMetadataBag = (context) => {
|
|
9081
10161
|
return context.metadata?.[METADATA_KEY];
|
|
9082
10162
|
};
|
|
9083
10163
|
var readMetadataBagFromConstructor = (ctor) => {
|
|
9084
10164
|
const metadataSymbol = Symbol.metadata;
|
|
9085
|
-
if (
|
|
9086
|
-
|
|
9087
|
-
|
|
10165
|
+
if (metadataSymbol) {
|
|
10166
|
+
const metadata = Reflect.get(ctor, metadataSymbol);
|
|
10167
|
+
const stage3Bag = metadata?.[METADATA_KEY];
|
|
10168
|
+
if (stage3Bag) {
|
|
10169
|
+
return stage3Bag;
|
|
10170
|
+
}
|
|
10171
|
+
}
|
|
10172
|
+
return ctor[LEGACY_METADATA_KEY];
|
|
9088
10173
|
};
|
|
9089
10174
|
var getDecoratorMetadata = (ctor) => readMetadataBagFromConstructor(ctor);
|
|
10175
|
+
var normalizePropertyName = (name) => {
|
|
10176
|
+
if (typeof name === "symbol") {
|
|
10177
|
+
return name.description ?? name.toString();
|
|
10178
|
+
}
|
|
10179
|
+
return name;
|
|
10180
|
+
};
|
|
10181
|
+
var isStage3FieldContext = (value) => {
|
|
10182
|
+
return typeof value === "object" && value !== null && "name" in value && "private" in value && "metadata" in value;
|
|
10183
|
+
};
|
|
10184
|
+
var resolveFieldDecoratorInfo = (targetOrValue, contextOrProperty, decoratorName) => {
|
|
10185
|
+
if (isStage3FieldContext(contextOrProperty)) {
|
|
10186
|
+
if (!contextOrProperty.name) {
|
|
10187
|
+
throw new Error(`${decoratorName} decorator requires a property name`);
|
|
10188
|
+
}
|
|
10189
|
+
if (contextOrProperty.private) {
|
|
10190
|
+
throw new Error(`${decoratorName} decorator does not support private fields`);
|
|
10191
|
+
}
|
|
10192
|
+
return {
|
|
10193
|
+
propertyName: normalizePropertyName(contextOrProperty.name),
|
|
10194
|
+
bag: getOrCreateMetadataBag(contextOrProperty)
|
|
10195
|
+
};
|
|
10196
|
+
}
|
|
10197
|
+
if (typeof contextOrProperty === "string" || typeof contextOrProperty === "symbol") {
|
|
10198
|
+
const legacyTarget = targetOrValue;
|
|
10199
|
+
const ctor = typeof legacyTarget === "function" ? legacyTarget : legacyTarget?.constructor;
|
|
10200
|
+
if (!ctor || typeof ctor !== "function" && typeof ctor !== "object") {
|
|
10201
|
+
throw new Error(`${decoratorName} decorator requires a class field target`);
|
|
10202
|
+
}
|
|
10203
|
+
return {
|
|
10204
|
+
propertyName: normalizePropertyName(contextOrProperty),
|
|
10205
|
+
bag: getOrCreateMetadataBagOnConstructor(ctor)
|
|
10206
|
+
};
|
|
10207
|
+
}
|
|
10208
|
+
throw new Error(`${decoratorName} decorator received an unsupported decorator context`);
|
|
10209
|
+
};
|
|
9090
10210
|
|
|
9091
10211
|
// src/decorators/bootstrap.ts
|
|
9092
10212
|
var unwrapTarget = (target) => {
|
|
@@ -9176,6 +10296,48 @@ var buildRelationDefinitions = (meta, tableMap) => {
|
|
|
9176
10296
|
);
|
|
9177
10297
|
break;
|
|
9178
10298
|
}
|
|
10299
|
+
case RelationKinds.MorphOne: {
|
|
10300
|
+
relations[name] = morphOne(
|
|
10301
|
+
resolveTableTarget(relation.target, tableMap),
|
|
10302
|
+
{
|
|
10303
|
+
as: relation.morphName,
|
|
10304
|
+
typeValue: relation.typeValue,
|
|
10305
|
+
typeField: relation.typeField,
|
|
10306
|
+
idField: relation.idField,
|
|
10307
|
+
localKey: relation.localKey,
|
|
10308
|
+
cascade: relation.cascade
|
|
10309
|
+
}
|
|
10310
|
+
);
|
|
10311
|
+
break;
|
|
10312
|
+
}
|
|
10313
|
+
case RelationKinds.MorphMany: {
|
|
10314
|
+
relations[name] = morphMany(
|
|
10315
|
+
resolveTableTarget(relation.target, tableMap),
|
|
10316
|
+
{
|
|
10317
|
+
as: relation.morphName,
|
|
10318
|
+
typeValue: relation.typeValue,
|
|
10319
|
+
typeField: relation.typeField,
|
|
10320
|
+
idField: relation.idField,
|
|
10321
|
+
localKey: relation.localKey,
|
|
10322
|
+
cascade: relation.cascade
|
|
10323
|
+
}
|
|
10324
|
+
);
|
|
10325
|
+
break;
|
|
10326
|
+
}
|
|
10327
|
+
case RelationKinds.MorphTo: {
|
|
10328
|
+
const resolvedTargets = {};
|
|
10329
|
+
for (const [typeValue, targetResolver] of Object.entries(relation.targets)) {
|
|
10330
|
+
resolvedTargets[typeValue] = resolveTableTarget(targetResolver, tableMap);
|
|
10331
|
+
}
|
|
10332
|
+
relations[name] = morphTo({
|
|
10333
|
+
typeField: relation.typeField,
|
|
10334
|
+
idField: relation.idField,
|
|
10335
|
+
targets: resolvedTargets,
|
|
10336
|
+
targetKey: relation.targetKey,
|
|
10337
|
+
cascade: relation.cascade
|
|
10338
|
+
});
|
|
10339
|
+
break;
|
|
10340
|
+
}
|
|
9179
10341
|
}
|
|
9180
10342
|
}
|
|
9181
10343
|
return relations;
|
|
@@ -9249,6 +10411,45 @@ var resolveSingleRelation = (relationName, relation, rootMeta) => {
|
|
|
9249
10411
|
}
|
|
9250
10412
|
);
|
|
9251
10413
|
}
|
|
10414
|
+
case RelationKinds.MorphOne: {
|
|
10415
|
+
return morphOne(
|
|
10416
|
+
resolveTableTarget(relation.target, tableMap),
|
|
10417
|
+
{
|
|
10418
|
+
as: relation.morphName,
|
|
10419
|
+
typeValue: relation.typeValue,
|
|
10420
|
+
typeField: relation.typeField,
|
|
10421
|
+
idField: relation.idField,
|
|
10422
|
+
localKey: relation.localKey,
|
|
10423
|
+
cascade: relation.cascade
|
|
10424
|
+
}
|
|
10425
|
+
);
|
|
10426
|
+
}
|
|
10427
|
+
case RelationKinds.MorphMany: {
|
|
10428
|
+
return morphMany(
|
|
10429
|
+
resolveTableTarget(relation.target, tableMap),
|
|
10430
|
+
{
|
|
10431
|
+
as: relation.morphName,
|
|
10432
|
+
typeValue: relation.typeValue,
|
|
10433
|
+
typeField: relation.typeField,
|
|
10434
|
+
idField: relation.idField,
|
|
10435
|
+
localKey: relation.localKey,
|
|
10436
|
+
cascade: relation.cascade
|
|
10437
|
+
}
|
|
10438
|
+
);
|
|
10439
|
+
}
|
|
10440
|
+
case RelationKinds.MorphTo: {
|
|
10441
|
+
const resolvedTargets = {};
|
|
10442
|
+
for (const [typeValue, targetResolver] of Object.entries(relation.targets)) {
|
|
10443
|
+
resolvedTargets[typeValue] = resolveTableTarget(targetResolver, tableMap);
|
|
10444
|
+
}
|
|
10445
|
+
return morphTo({
|
|
10446
|
+
typeField: relation.typeField,
|
|
10447
|
+
idField: relation.idField,
|
|
10448
|
+
targets: resolvedTargets,
|
|
10449
|
+
targetKey: relation.targetKey,
|
|
10450
|
+
cascade: relation.cascade
|
|
10451
|
+
});
|
|
10452
|
+
}
|
|
9252
10453
|
default:
|
|
9253
10454
|
throw new Error(`Unknown relation kind for relation '${relationName}'`);
|
|
9254
10455
|
}
|
|
@@ -12838,6 +14039,9 @@ var TypeScriptGenerator = class {
|
|
|
12838
14039
|
visitLogicalExpression(logical) {
|
|
12839
14040
|
return this.printLogicalExpression(logical);
|
|
12840
14041
|
}
|
|
14042
|
+
visitNotExpression(notExpr) {
|
|
14043
|
+
return this.printNotExpression(notExpr);
|
|
14044
|
+
}
|
|
12841
14045
|
visitNullExpression(nullExpr) {
|
|
12842
14046
|
return this.printNullExpression(nullExpr);
|
|
12843
14047
|
}
|
|
@@ -12913,6 +14117,9 @@ var TypeScriptGenerator = class {
|
|
|
12913
14117
|
${parts.join(",\n ")}
|
|
12914
14118
|
)`;
|
|
12915
14119
|
}
|
|
14120
|
+
printNotExpression(notExpr) {
|
|
14121
|
+
return `not(${this.printExpression(notExpr.operand)})`;
|
|
14122
|
+
}
|
|
12916
14123
|
printArithmeticExpression(expr) {
|
|
12917
14124
|
const left2 = this.printOperand(expr.left);
|
|
12918
14125
|
const right2 = this.printOperand(expr.right);
|
|
@@ -13606,6 +14813,15 @@ var RelationChangeProcessor = class {
|
|
|
13606
14813
|
case RelationKinds.BelongsTo:
|
|
13607
14814
|
await this.handleBelongsToChange(entry);
|
|
13608
14815
|
break;
|
|
14816
|
+
case RelationKinds.MorphOne:
|
|
14817
|
+
await this.handleMorphOneChange(entry);
|
|
14818
|
+
break;
|
|
14819
|
+
case RelationKinds.MorphMany:
|
|
14820
|
+
await this.handleMorphManyChange(entry);
|
|
14821
|
+
break;
|
|
14822
|
+
case RelationKinds.MorphTo:
|
|
14823
|
+
await this.handleMorphToChange(entry);
|
|
14824
|
+
break;
|
|
13609
14825
|
}
|
|
13610
14826
|
}
|
|
13611
14827
|
}
|
|
@@ -13808,6 +15024,86 @@ var RelationChangeProcessor = class {
|
|
|
13808
15024
|
}
|
|
13809
15025
|
return Object.keys(payload).length ? payload : void 0;
|
|
13810
15026
|
}
|
|
15027
|
+
async handleMorphOneChange(entry) {
|
|
15028
|
+
const relation = entry.relation;
|
|
15029
|
+
const target = entry.change.entity;
|
|
15030
|
+
if (!target) return;
|
|
15031
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
15032
|
+
if (!tracked) return;
|
|
15033
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
15034
|
+
const rootValue = entry.root[localKey];
|
|
15035
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
15036
|
+
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
15037
|
+
const child = tracked.entity;
|
|
15038
|
+
child[relation.idField] = rootValue;
|
|
15039
|
+
child[relation.typeField] = relation.typeValue;
|
|
15040
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
15041
|
+
return;
|
|
15042
|
+
}
|
|
15043
|
+
if (entry.change.kind === "remove") {
|
|
15044
|
+
const child = tracked.entity;
|
|
15045
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
15046
|
+
this.unitOfWork.markRemoved(child);
|
|
15047
|
+
return;
|
|
15048
|
+
}
|
|
15049
|
+
child[relation.idField] = null;
|
|
15050
|
+
child[relation.typeField] = null;
|
|
15051
|
+
this.unitOfWork.markDirty(child);
|
|
15052
|
+
}
|
|
15053
|
+
}
|
|
15054
|
+
async handleMorphManyChange(entry) {
|
|
15055
|
+
const relation = entry.relation;
|
|
15056
|
+
const target = entry.change.entity;
|
|
15057
|
+
if (!target) return;
|
|
15058
|
+
const tracked = this.unitOfWork.findTracked(target);
|
|
15059
|
+
if (!tracked) return;
|
|
15060
|
+
const localKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
15061
|
+
const rootValue = entry.root[localKey];
|
|
15062
|
+
if (rootValue === void 0 || rootValue === null) return;
|
|
15063
|
+
if (entry.change.kind === "add" || entry.change.kind === "attach") {
|
|
15064
|
+
const child = tracked.entity;
|
|
15065
|
+
child[relation.idField] = rootValue;
|
|
15066
|
+
child[relation.typeField] = relation.typeValue;
|
|
15067
|
+
this.unitOfWork.markDirty(tracked.entity);
|
|
15068
|
+
return;
|
|
15069
|
+
}
|
|
15070
|
+
if (entry.change.kind === "remove") {
|
|
15071
|
+
const child = tracked.entity;
|
|
15072
|
+
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
15073
|
+
this.unitOfWork.markRemoved(child);
|
|
15074
|
+
return;
|
|
15075
|
+
}
|
|
15076
|
+
child[relation.idField] = null;
|
|
15077
|
+
child[relation.typeField] = null;
|
|
15078
|
+
this.unitOfWork.markDirty(child);
|
|
15079
|
+
}
|
|
15080
|
+
}
|
|
15081
|
+
async handleMorphToChange(entry) {
|
|
15082
|
+
const relation = entry.relation;
|
|
15083
|
+
const target = entry.change.entity;
|
|
15084
|
+
if (!target) return;
|
|
15085
|
+
if (entry.change.kind === "attach" || entry.change.kind === "add") {
|
|
15086
|
+
const targetEntity = target;
|
|
15087
|
+
for (const [typeValue, targetTable] of Object.entries(relation.targets)) {
|
|
15088
|
+
const targetPk = relation.targetKey || findPrimaryKey(targetTable);
|
|
15089
|
+
const pkValue = targetEntity[targetPk];
|
|
15090
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
15091
|
+
const rootEntity = entry.root;
|
|
15092
|
+
rootEntity[relation.typeField] = typeValue;
|
|
15093
|
+
rootEntity[relation.idField] = pkValue;
|
|
15094
|
+
this.unitOfWork.markDirty(entry.root);
|
|
15095
|
+
break;
|
|
15096
|
+
}
|
|
15097
|
+
}
|
|
15098
|
+
return;
|
|
15099
|
+
}
|
|
15100
|
+
if (entry.change.kind === "remove") {
|
|
15101
|
+
const rootEntity = entry.root;
|
|
15102
|
+
rootEntity[relation.typeField] = null;
|
|
15103
|
+
rootEntity[relation.idField] = null;
|
|
15104
|
+
this.unitOfWork.markDirty(entry.root);
|
|
15105
|
+
}
|
|
15106
|
+
}
|
|
13811
15107
|
};
|
|
13812
15108
|
|
|
13813
15109
|
// src/orm/query-logger.ts
|
|
@@ -13824,6 +15120,9 @@ var createQueryLoggingExecutor = (executor, logger) => {
|
|
|
13824
15120
|
beginTransaction: () => executor.beginTransaction(),
|
|
13825
15121
|
commitTransaction: () => executor.commitTransaction(),
|
|
13826
15122
|
rollbackTransaction: () => executor.rollbackTransaction(),
|
|
15123
|
+
savepoint: executor.savepoint ? (name) => executor.savepoint(name) : void 0,
|
|
15124
|
+
releaseSavepoint: executor.releaseSavepoint ? (name) => executor.releaseSavepoint(name) : void 0,
|
|
15125
|
+
rollbackToSavepoint: executor.rollbackToSavepoint ? (name) => executor.rollbackToSavepoint(name) : void 0,
|
|
13827
15126
|
dispose: () => executor.dispose()
|
|
13828
15127
|
};
|
|
13829
15128
|
return wrapped;
|
|
@@ -13846,7 +15145,7 @@ var runInTransaction = async (executor, action) => {
|
|
|
13846
15145
|
};
|
|
13847
15146
|
|
|
13848
15147
|
// src/orm/save-graph.ts
|
|
13849
|
-
var
|
|
15148
|
+
var toKey11 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
13850
15149
|
var coerceColumnValue = (table, columnName, value, options) => {
|
|
13851
15150
|
if (value === null || value === void 0) return value;
|
|
13852
15151
|
const column = table.columns[columnName];
|
|
@@ -13908,11 +15207,11 @@ var isEntityInCollection = (items, pkName, entity) => {
|
|
|
13908
15207
|
if (items.includes(entity)) return true;
|
|
13909
15208
|
const entityPk = entity[pkName];
|
|
13910
15209
|
if (entityPk === void 0 || entityPk === null) return false;
|
|
13911
|
-
return items.some((item) =>
|
|
15210
|
+
return items.some((item) => toKey11(item[pkName]) === toKey11(entityPk));
|
|
13912
15211
|
};
|
|
13913
15212
|
var findInCollectionByPk = (items, pkName, pkValue) => {
|
|
13914
15213
|
if (pkValue === void 0 || pkValue === null) return void 0;
|
|
13915
|
-
return items.find((item) =>
|
|
15214
|
+
return items.find((item) => toKey11(item[pkName]) === toKey11(pkValue));
|
|
13916
15215
|
};
|
|
13917
15216
|
var extractPivotPayload = (payload) => {
|
|
13918
15217
|
const pivot = payload._pivot ?? payload.pivot;
|
|
@@ -13941,13 +15240,13 @@ var handleHasMany = async (session, root, relationName, relation, payload, optio
|
|
|
13941
15240
|
collection.attach(entity);
|
|
13942
15241
|
}
|
|
13943
15242
|
if (pkValue !== void 0 && pkValue !== null) {
|
|
13944
|
-
seen.add(
|
|
15243
|
+
seen.add(toKey11(pkValue));
|
|
13945
15244
|
}
|
|
13946
15245
|
}
|
|
13947
15246
|
if (options.pruneMissing) {
|
|
13948
15247
|
for (const item of [...collection.getItems()]) {
|
|
13949
15248
|
const pkValue = item[targetPk];
|
|
13950
|
-
if (pkValue !== void 0 && pkValue !== null && !seen.has(
|
|
15249
|
+
if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey11(pkValue))) {
|
|
13951
15250
|
collection.remove(item);
|
|
13952
15251
|
}
|
|
13953
15252
|
}
|
|
@@ -14005,7 +15304,7 @@ var handleBelongsToMany = async (session, root, relationName, relation, payload,
|
|
|
14005
15304
|
if (typeof item === "number" || typeof item === "string") {
|
|
14006
15305
|
const id = item;
|
|
14007
15306
|
collection.attach(id);
|
|
14008
|
-
seen.add(
|
|
15307
|
+
seen.add(toKey11(id));
|
|
14009
15308
|
continue;
|
|
14010
15309
|
}
|
|
14011
15310
|
const asObj = item;
|
|
@@ -14023,18 +15322,89 @@ var handleBelongsToMany = async (session, root, relationName, relation, payload,
|
|
|
14023
15322
|
collection.attach(entity, pivotPayload);
|
|
14024
15323
|
}
|
|
14025
15324
|
if (pkValue !== void 0 && pkValue !== null) {
|
|
14026
|
-
seen.add(
|
|
15325
|
+
seen.add(toKey11(pkValue));
|
|
14027
15326
|
}
|
|
14028
15327
|
}
|
|
14029
15328
|
if (options.pruneMissing) {
|
|
14030
15329
|
for (const item of [...collection.getItems()]) {
|
|
14031
15330
|
const pkValue = item[targetPk];
|
|
14032
|
-
if (pkValue !== void 0 && pkValue !== null && !seen.has(
|
|
15331
|
+
if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey11(pkValue))) {
|
|
14033
15332
|
collection.detach(item);
|
|
14034
15333
|
}
|
|
14035
15334
|
}
|
|
14036
15335
|
}
|
|
14037
15336
|
};
|
|
15337
|
+
var handleMorphOne = async (session, root, relationName, relation, payload, options) => {
|
|
15338
|
+
const ref = root[relationName];
|
|
15339
|
+
if (payload === void 0) return;
|
|
15340
|
+
if (payload === null) {
|
|
15341
|
+
ref.set(null);
|
|
15342
|
+
return;
|
|
15343
|
+
}
|
|
15344
|
+
const pk = findPrimaryKey(relation.target);
|
|
15345
|
+
if (typeof payload === "number" || typeof payload === "string") {
|
|
15346
|
+
const entity = ref.set({ [pk]: payload });
|
|
15347
|
+
if (entity) {
|
|
15348
|
+
await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
|
|
15349
|
+
}
|
|
15350
|
+
return;
|
|
15351
|
+
}
|
|
15352
|
+
const attached = ref.set(payload);
|
|
15353
|
+
if (attached) {
|
|
15354
|
+
await applyGraphToEntity(session, relation.target, attached, payload, options);
|
|
15355
|
+
}
|
|
15356
|
+
};
|
|
15357
|
+
var handleMorphMany = async (session, root, relationName, relation, payload, options) => {
|
|
15358
|
+
if (!Array.isArray(payload)) return;
|
|
15359
|
+
const collection = root[relationName];
|
|
15360
|
+
await collection.load();
|
|
15361
|
+
const targetTable = relation.target;
|
|
15362
|
+
const targetPk = findPrimaryKey(targetTable);
|
|
15363
|
+
const existing = collection.getItems();
|
|
15364
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15365
|
+
for (const item of payload) {
|
|
15366
|
+
if (item === null || item === void 0) continue;
|
|
15367
|
+
const asObj = typeof item === "object" ? item : { [targetPk]: item };
|
|
15368
|
+
const pkValue = asObj[targetPk];
|
|
15369
|
+
const current = findInCollectionByPk(existing, targetPk, pkValue) ?? (pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) : void 0);
|
|
15370
|
+
const entity = current ?? ensureEntity(session, targetTable, asObj, options);
|
|
15371
|
+
assignColumns(targetTable, entity, asObj, options);
|
|
15372
|
+
await applyGraphToEntity(session, targetTable, entity, asObj, options);
|
|
15373
|
+
if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
|
|
15374
|
+
collection.attach(entity);
|
|
15375
|
+
}
|
|
15376
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
15377
|
+
seen.add(toKey11(pkValue));
|
|
15378
|
+
}
|
|
15379
|
+
}
|
|
15380
|
+
if (options.pruneMissing) {
|
|
15381
|
+
for (const item of [...collection.getItems()]) {
|
|
15382
|
+
const pkValue = item[targetPk];
|
|
15383
|
+
if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey11(pkValue))) {
|
|
15384
|
+
collection.remove(item);
|
|
15385
|
+
}
|
|
15386
|
+
}
|
|
15387
|
+
}
|
|
15388
|
+
};
|
|
15389
|
+
var handleMorphTo = async (session, root, relationName, relation, payload, options) => {
|
|
15390
|
+
const ref = root[relationName];
|
|
15391
|
+
if (payload === void 0) return;
|
|
15392
|
+
if (payload === null) {
|
|
15393
|
+
ref.set(null);
|
|
15394
|
+
return;
|
|
15395
|
+
}
|
|
15396
|
+
const attached = ref.set(payload);
|
|
15397
|
+
if (attached) {
|
|
15398
|
+
for (const [, targetTable] of Object.entries(relation.targets)) {
|
|
15399
|
+
const pk = relation.targetKey || findPrimaryKey(targetTable);
|
|
15400
|
+
const pkValue = attached[pk];
|
|
15401
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
15402
|
+
await applyGraphToEntity(session, targetTable, attached, payload, options);
|
|
15403
|
+
break;
|
|
15404
|
+
}
|
|
15405
|
+
}
|
|
15406
|
+
}
|
|
15407
|
+
};
|
|
14038
15408
|
var applyRelation = async (session, table, entity, relationName, relation, payload, options) => {
|
|
14039
15409
|
switch (relation.type) {
|
|
14040
15410
|
case RelationKinds.HasMany:
|
|
@@ -14045,6 +15415,12 @@ var applyRelation = async (session, table, entity, relationName, relation, paylo
|
|
|
14045
15415
|
return handleBelongsTo(session, entity, relationName, relation, payload, options);
|
|
14046
15416
|
case RelationKinds.BelongsToMany:
|
|
14047
15417
|
return handleBelongsToMany(session, entity, relationName, relation, payload, options);
|
|
15418
|
+
case RelationKinds.MorphOne:
|
|
15419
|
+
return handleMorphOne(session, entity, relationName, relation, payload, options);
|
|
15420
|
+
case RelationKinds.MorphMany:
|
|
15421
|
+
return handleMorphMany(session, entity, relationName, relation, payload, options);
|
|
15422
|
+
case RelationKinds.MorphTo:
|
|
15423
|
+
return handleMorphTo(session, entity, relationName, relation, payload, options);
|
|
14048
15424
|
}
|
|
14049
15425
|
};
|
|
14050
15426
|
var applyGraphToEntity = async (session, table, entity, payload, options) => {
|
|
@@ -14073,6 +15449,8 @@ var patchGraphInternal = async (session, entityClass, existing, payload, options
|
|
|
14073
15449
|
};
|
|
14074
15450
|
|
|
14075
15451
|
// src/orm/orm-session.ts
|
|
15452
|
+
var NESTED_TRANSACTIONS_REQUIRE_SAVEPOINTS = "Nested session.transaction calls require savepoint support in this executor";
|
|
15453
|
+
var ROLLBACK_ONLY_TRANSACTION = "Cannot commit transaction because an inner transaction failed";
|
|
14076
15454
|
var OrmSession = class {
|
|
14077
15455
|
/** The ORM instance */
|
|
14078
15456
|
orm;
|
|
@@ -14092,6 +15470,9 @@ var OrmSession = class {
|
|
|
14092
15470
|
tenantId;
|
|
14093
15471
|
interceptors;
|
|
14094
15472
|
saveGraphDefaults;
|
|
15473
|
+
transactionDepth = 0;
|
|
15474
|
+
savepointCounter = 0;
|
|
15475
|
+
rollbackOnly = false;
|
|
14095
15476
|
/**
|
|
14096
15477
|
* Creates a new OrmSession instance.
|
|
14097
15478
|
* @param opts - Session options
|
|
@@ -14434,16 +15815,43 @@ var OrmSession = class {
|
|
|
14434
15815
|
await this.commit();
|
|
14435
15816
|
return result;
|
|
14436
15817
|
}
|
|
14437
|
-
|
|
15818
|
+
const isOutermost = this.transactionDepth === 0;
|
|
15819
|
+
let savepointName = null;
|
|
15820
|
+
if (isOutermost) {
|
|
15821
|
+
this.rollbackOnly = false;
|
|
15822
|
+
await this.executor.beginTransaction();
|
|
15823
|
+
} else {
|
|
15824
|
+
this.assertSavepointSupport();
|
|
15825
|
+
savepointName = this.nextSavepointName();
|
|
15826
|
+
await this.executor.savepoint(savepointName);
|
|
15827
|
+
}
|
|
15828
|
+
this.transactionDepth += 1;
|
|
14438
15829
|
try {
|
|
14439
15830
|
const result = await fn8(this);
|
|
15831
|
+
this.throwIfRollbackOnly();
|
|
14440
15832
|
await this.flushWithHooks();
|
|
14441
|
-
|
|
14442
|
-
|
|
15833
|
+
this.throwIfRollbackOnly();
|
|
15834
|
+
if (isOutermost) {
|
|
15835
|
+
await this.executor.commitTransaction();
|
|
15836
|
+
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
15837
|
+
} else {
|
|
15838
|
+
await this.executor.releaseSavepoint(savepointName);
|
|
15839
|
+
}
|
|
14443
15840
|
return result;
|
|
14444
15841
|
} catch (err) {
|
|
14445
|
-
|
|
15842
|
+
if (isOutermost) {
|
|
15843
|
+
await this.rollback();
|
|
15844
|
+
} else {
|
|
15845
|
+
this.rollbackOnly = true;
|
|
15846
|
+
await this.executor.rollbackToSavepoint(savepointName);
|
|
15847
|
+
}
|
|
14446
15848
|
throw err;
|
|
15849
|
+
} finally {
|
|
15850
|
+
this.transactionDepth = Math.max(0, this.transactionDepth - 1);
|
|
15851
|
+
if (this.transactionDepth === 0) {
|
|
15852
|
+
this.rollbackOnly = false;
|
|
15853
|
+
this.savepointCounter = 0;
|
|
15854
|
+
}
|
|
14447
15855
|
}
|
|
14448
15856
|
}
|
|
14449
15857
|
/**
|
|
@@ -14453,6 +15861,9 @@ var OrmSession = class {
|
|
|
14453
15861
|
if (this.executor.capabilities.transactions) {
|
|
14454
15862
|
await this.executor.rollbackTransaction();
|
|
14455
15863
|
}
|
|
15864
|
+
this.transactionDepth = 0;
|
|
15865
|
+
this.savepointCounter = 0;
|
|
15866
|
+
this.rollbackOnly = false;
|
|
14456
15867
|
this.unitOfWork.reset();
|
|
14457
15868
|
this.relationChanges.reset();
|
|
14458
15869
|
}
|
|
@@ -14527,6 +15938,23 @@ var OrmSession = class {
|
|
|
14527
15938
|
resolveSaveGraphOptions(options) {
|
|
14528
15939
|
return { ...this.saveGraphDefaults ?? {}, ...options ?? {} };
|
|
14529
15940
|
}
|
|
15941
|
+
assertSavepointSupport() {
|
|
15942
|
+
if (!this.executor.capabilities.savepoints) {
|
|
15943
|
+
throw new Error(NESTED_TRANSACTIONS_REQUIRE_SAVEPOINTS);
|
|
15944
|
+
}
|
|
15945
|
+
if (typeof this.executor.savepoint !== "function" || typeof this.executor.releaseSavepoint !== "function" || typeof this.executor.rollbackToSavepoint !== "function") {
|
|
15946
|
+
throw new Error(NESTED_TRANSACTIONS_REQUIRE_SAVEPOINTS);
|
|
15947
|
+
}
|
|
15948
|
+
}
|
|
15949
|
+
nextSavepointName() {
|
|
15950
|
+
this.savepointCounter += 1;
|
|
15951
|
+
return `metalorm_sp_${this.savepointCounter}`;
|
|
15952
|
+
}
|
|
15953
|
+
throwIfRollbackOnly() {
|
|
15954
|
+
if (this.rollbackOnly) {
|
|
15955
|
+
throw new Error(ROLLBACK_ONLY_TRANSACTION);
|
|
15956
|
+
}
|
|
15957
|
+
}
|
|
14530
15958
|
};
|
|
14531
15959
|
var buildRelationChangeEntry = (root, relationKey, rootTable, relationName, relation, change) => ({
|
|
14532
15960
|
root,
|
|
@@ -15051,7 +16479,7 @@ var TREE_METADATA_KEY = /* @__PURE__ */ Symbol("metal-orm:tree");
|
|
|
15051
16479
|
function Tree(options = {}) {
|
|
15052
16480
|
return function(target, context) {
|
|
15053
16481
|
const config = resolveTreeConfig(options);
|
|
15054
|
-
const metadataBag = readMetadataBag(context) ?? readMetadataBagFromConstructor(target);
|
|
16482
|
+
const metadataBag = context ? readMetadataBag(context) ?? readMetadataBagFromConstructor(target) : readMetadataBagFromConstructor(target);
|
|
15055
16483
|
const metadata = {
|
|
15056
16484
|
config,
|
|
15057
16485
|
parentProperty: metadataBag?.tree?.parentProperty,
|
|
@@ -15063,28 +16491,22 @@ function Tree(options = {}) {
|
|
|
15063
16491
|
};
|
|
15064
16492
|
}
|
|
15065
16493
|
function TreeParent() {
|
|
15066
|
-
return function(
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
-
|
|
15070
|
-
|
|
15071
|
-
|
|
15072
|
-
}
|
|
15073
|
-
const propertyName = String(context.name);
|
|
15074
|
-
const bag = getOrCreateMetadataBag(context);
|
|
16494
|
+
return function(targetOrValue, contextOrProperty) {
|
|
16495
|
+
const { propertyName, bag } = resolveFieldDecoratorInfo(
|
|
16496
|
+
targetOrValue,
|
|
16497
|
+
contextOrProperty,
|
|
16498
|
+
"TreeParent"
|
|
16499
|
+
);
|
|
15075
16500
|
bag.tree = { ...bag.tree, parentProperty: propertyName };
|
|
15076
16501
|
};
|
|
15077
16502
|
}
|
|
15078
16503
|
function TreeChildren() {
|
|
15079
|
-
return function(
|
|
15080
|
-
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
|
|
15084
|
-
|
|
15085
|
-
}
|
|
15086
|
-
const propertyName = String(context.name);
|
|
15087
|
-
const bag = getOrCreateMetadataBag(context);
|
|
16504
|
+
return function(targetOrValue, contextOrProperty) {
|
|
16505
|
+
const { propertyName, bag } = resolveFieldDecoratorInfo(
|
|
16506
|
+
targetOrValue,
|
|
16507
|
+
contextOrProperty,
|
|
16508
|
+
"TreeChildren"
|
|
16509
|
+
);
|
|
15088
16510
|
bag.tree = { ...bag.tree, childrenProperty: propertyName };
|
|
15089
16511
|
};
|
|
15090
16512
|
}
|
|
@@ -15248,7 +16670,7 @@ function Entity(options = {}) {
|
|
|
15248
16670
|
const ctor = value;
|
|
15249
16671
|
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
15250
16672
|
setEntityTableName(ctor, tableName, options.hooks, options.type);
|
|
15251
|
-
const bag = readMetadataBag(context);
|
|
16673
|
+
const bag = context ? readMetadataBag(context) : readMetadataBagFromConstructor(ctor);
|
|
15252
16674
|
if (bag) {
|
|
15253
16675
|
const meta = ensureEntityMetadata(ctor);
|
|
15254
16676
|
for (const entry of bag.columns) {
|
|
@@ -15302,29 +16724,20 @@ var normalizeColumnInput = (input) => {
|
|
|
15302
16724
|
}
|
|
15303
16725
|
return column;
|
|
15304
16726
|
};
|
|
15305
|
-
var
|
|
15306
|
-
|
|
15307
|
-
|
|
15308
|
-
|
|
15309
|
-
|
|
15310
|
-
|
|
15311
|
-
var registerColumnFromContext = (context, column) => {
|
|
15312
|
-
if (!context.name) {
|
|
15313
|
-
throw new Error("Column decorator requires a property name");
|
|
15314
|
-
}
|
|
15315
|
-
if (context.private) {
|
|
15316
|
-
throw new Error("Column decorator does not support private fields");
|
|
15317
|
-
}
|
|
15318
|
-
const propertyName = normalizePropertyName(context.name);
|
|
15319
|
-
const bag = getOrCreateMetadataBag(context);
|
|
16727
|
+
var registerColumnFromContext = (targetOrValue, contextOrProperty, column) => {
|
|
16728
|
+
const { propertyName, bag } = resolveFieldDecoratorInfo(
|
|
16729
|
+
targetOrValue,
|
|
16730
|
+
contextOrProperty,
|
|
16731
|
+
"Column"
|
|
16732
|
+
);
|
|
15320
16733
|
if (!bag.columns.some((entry) => entry.propertyName === propertyName)) {
|
|
15321
16734
|
bag.columns.push({ propertyName, column: { ...column } });
|
|
15322
16735
|
}
|
|
15323
16736
|
};
|
|
15324
16737
|
function Column(definition) {
|
|
15325
16738
|
const normalized = normalizeColumnInput(definition);
|
|
15326
|
-
return function(
|
|
15327
|
-
registerColumnFromContext(
|
|
16739
|
+
return function(targetOrValue, contextOrProperty) {
|
|
16740
|
+
registerColumnFromContext(targetOrValue, contextOrProperty, normalized);
|
|
15328
16741
|
};
|
|
15329
16742
|
}
|
|
15330
16743
|
function PrimaryKey(definition) {
|
|
@@ -15334,22 +16747,13 @@ function PrimaryKey(definition) {
|
|
|
15334
16747
|
}
|
|
15335
16748
|
|
|
15336
16749
|
// src/decorators/relations.ts
|
|
15337
|
-
var normalizePropertyName2 = (name) => {
|
|
15338
|
-
if (typeof name === "symbol") {
|
|
15339
|
-
return name.description ?? name.toString();
|
|
15340
|
-
}
|
|
15341
|
-
return name;
|
|
15342
|
-
};
|
|
15343
16750
|
var createFieldDecorator = (metadataFactory) => {
|
|
15344
|
-
return function(
|
|
15345
|
-
|
|
15346
|
-
|
|
15347
|
-
|
|
15348
|
-
|
|
15349
|
-
|
|
15350
|
-
}
|
|
15351
|
-
const propertyName = normalizePropertyName2(context.name);
|
|
15352
|
-
const bag = getOrCreateMetadataBag(context);
|
|
16751
|
+
return function(targetOrValue, contextOrProperty) {
|
|
16752
|
+
const { propertyName, bag } = resolveFieldDecoratorInfo(
|
|
16753
|
+
targetOrValue,
|
|
16754
|
+
contextOrProperty,
|
|
16755
|
+
"Relation"
|
|
16756
|
+
);
|
|
15353
16757
|
const relationMetadata = metadataFactory(propertyName);
|
|
15354
16758
|
if (!bag.relations.some((entry) => entry.propertyName === propertyName)) {
|
|
15355
16759
|
bag.relations.push({ propertyName, relation: relationMetadata });
|
|
@@ -15401,6 +16805,43 @@ function BelongsToMany(options) {
|
|
|
15401
16805
|
cascade: options.cascade
|
|
15402
16806
|
}));
|
|
15403
16807
|
}
|
|
16808
|
+
function MorphTo(options) {
|
|
16809
|
+
return createFieldDecorator((propertyName) => ({
|
|
16810
|
+
kind: RelationKinds.MorphTo,
|
|
16811
|
+
propertyKey: propertyName,
|
|
16812
|
+
typeField: options.typeField,
|
|
16813
|
+
idField: options.idField,
|
|
16814
|
+
targets: options.targets,
|
|
16815
|
+
targetKey: options.targetKey,
|
|
16816
|
+
cascade: options.cascade
|
|
16817
|
+
}));
|
|
16818
|
+
}
|
|
16819
|
+
function MorphOne(options) {
|
|
16820
|
+
return createFieldDecorator((propertyName) => ({
|
|
16821
|
+
kind: RelationKinds.MorphOne,
|
|
16822
|
+
propertyKey: propertyName,
|
|
16823
|
+
target: options.target,
|
|
16824
|
+
morphName: options.morphName,
|
|
16825
|
+
typeValue: options.typeValue,
|
|
16826
|
+
typeField: options.typeField,
|
|
16827
|
+
idField: options.idField,
|
|
16828
|
+
localKey: options.localKey,
|
|
16829
|
+
cascade: options.cascade
|
|
16830
|
+
}));
|
|
16831
|
+
}
|
|
16832
|
+
function MorphMany(options) {
|
|
16833
|
+
return createFieldDecorator((propertyName) => ({
|
|
16834
|
+
kind: RelationKinds.MorphMany,
|
|
16835
|
+
propertyKey: propertyName,
|
|
16836
|
+
target: options.target,
|
|
16837
|
+
morphName: options.morphName,
|
|
16838
|
+
typeValue: options.typeValue,
|
|
16839
|
+
typeField: options.typeField,
|
|
16840
|
+
idField: options.idField,
|
|
16841
|
+
localKey: options.localKey,
|
|
16842
|
+
cascade: options.cascade
|
|
16843
|
+
}));
|
|
16844
|
+
}
|
|
15404
16845
|
|
|
15405
16846
|
// src/decorators/transformers/built-in/string-transformers.ts
|
|
15406
16847
|
var TrimTransformer = class {
|
|
@@ -15586,15 +17027,12 @@ var PatternValidator = class {
|
|
|
15586
17027
|
};
|
|
15587
17028
|
|
|
15588
17029
|
// src/decorators/transformers/transformer-decorators.ts
|
|
15589
|
-
var
|
|
15590
|
-
|
|
15591
|
-
|
|
15592
|
-
|
|
15593
|
-
|
|
15594
|
-
|
|
15595
|
-
var registerTransformerMetadata = (context, metadata) => {
|
|
15596
|
-
const propertyName = normalizePropertyName3(context.name);
|
|
15597
|
-
const bag = getOrCreateMetadataBag(context);
|
|
17030
|
+
var registerTransformerMetadata = (targetOrValue, contextOrProperty, metadata) => {
|
|
17031
|
+
const { propertyName, bag } = resolveFieldDecoratorInfo(
|
|
17032
|
+
targetOrValue,
|
|
17033
|
+
contextOrProperty,
|
|
17034
|
+
"Transformer"
|
|
17035
|
+
);
|
|
15598
17036
|
let existing = bag.transformers.find((t) => t.propertyName === propertyName);
|
|
15599
17037
|
if (!existing) {
|
|
15600
17038
|
existing = {
|
|
@@ -15623,64 +17061,64 @@ var registerTransformerMetadata = (context, metadata) => {
|
|
|
15623
17061
|
}
|
|
15624
17062
|
};
|
|
15625
17063
|
function Trim(options) {
|
|
15626
|
-
return function(
|
|
15627
|
-
registerTransformerMetadata(
|
|
17064
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17065
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15628
17066
|
sanitizers: [new TrimTransformer(options)]
|
|
15629
17067
|
});
|
|
15630
17068
|
};
|
|
15631
17069
|
}
|
|
15632
17070
|
function Lower() {
|
|
15633
|
-
return function(
|
|
15634
|
-
registerTransformerMetadata(
|
|
17071
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17072
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15635
17073
|
sanitizers: [new CaseTransformer("lower")]
|
|
15636
17074
|
});
|
|
15637
17075
|
};
|
|
15638
17076
|
}
|
|
15639
17077
|
function Upper() {
|
|
15640
|
-
return function(
|
|
15641
|
-
registerTransformerMetadata(
|
|
17078
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17079
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15642
17080
|
sanitizers: [new CaseTransformer("upper")]
|
|
15643
17081
|
});
|
|
15644
17082
|
};
|
|
15645
17083
|
}
|
|
15646
17084
|
function Capitalize() {
|
|
15647
|
-
return function(
|
|
15648
|
-
registerTransformerMetadata(
|
|
17085
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17086
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15649
17087
|
sanitizers: [new CaseTransformer("capitalize")]
|
|
15650
17088
|
});
|
|
15651
17089
|
};
|
|
15652
17090
|
}
|
|
15653
17091
|
function Title() {
|
|
15654
|
-
return function(
|
|
15655
|
-
registerTransformerMetadata(
|
|
17092
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17093
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15656
17094
|
sanitizers: [new CaseTransformer("title")]
|
|
15657
17095
|
});
|
|
15658
17096
|
};
|
|
15659
17097
|
}
|
|
15660
17098
|
function Alphanumeric(options) {
|
|
15661
|
-
return function(
|
|
15662
|
-
registerTransformerMetadata(
|
|
17099
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17100
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15663
17101
|
validators: [new AlphanumericValidator(options)]
|
|
15664
17102
|
});
|
|
15665
17103
|
};
|
|
15666
17104
|
}
|
|
15667
17105
|
function Email(options) {
|
|
15668
|
-
return function(
|
|
15669
|
-
registerTransformerMetadata(
|
|
17106
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17107
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15670
17108
|
validators: [new EmailValidator(options)]
|
|
15671
17109
|
});
|
|
15672
17110
|
};
|
|
15673
17111
|
}
|
|
15674
17112
|
function Length(options) {
|
|
15675
|
-
return function(
|
|
15676
|
-
registerTransformerMetadata(
|
|
17113
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17114
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15677
17115
|
validators: [new LengthValidator(options)]
|
|
15678
17116
|
});
|
|
15679
17117
|
};
|
|
15680
17118
|
}
|
|
15681
17119
|
function Pattern(options) {
|
|
15682
|
-
return function(
|
|
15683
|
-
registerTransformerMetadata(
|
|
17120
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17121
|
+
registerTransformerMetadata(targetOrValue, contextOrProperty, {
|
|
15684
17122
|
validators: [new PatternValidator(options)]
|
|
15685
17123
|
});
|
|
15686
17124
|
};
|
|
@@ -15907,16 +17345,12 @@ var CEPValidator = class {
|
|
|
15907
17345
|
registerValidator("BR", "cpf", () => new CPFValidator());
|
|
15908
17346
|
registerValidator("BR", "cnpj", () => new CNPJValidator());
|
|
15909
17347
|
registerValidator("BR", "cep", () => new CEPValidator());
|
|
15910
|
-
var
|
|
15911
|
-
|
|
15912
|
-
return name.description ?? name.toString();
|
|
15913
|
-
}
|
|
15914
|
-
return name;
|
|
17348
|
+
var resolveCountryDecoratorInfo = (targetOrValue, contextOrProperty) => {
|
|
17349
|
+
return resolveFieldDecoratorInfo(targetOrValue, contextOrProperty, "Country validator");
|
|
15915
17350
|
};
|
|
15916
17351
|
function CPF(options) {
|
|
15917
|
-
return function(
|
|
15918
|
-
const propertyName =
|
|
15919
|
-
const bag = getOrCreateMetadataBag(context);
|
|
17352
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17353
|
+
const { propertyName, bag } = resolveCountryDecoratorInfo(targetOrValue, contextOrProperty);
|
|
15920
17354
|
let existing = bag.transformers.find((t) => t.propertyName === propertyName);
|
|
15921
17355
|
if (!existing) {
|
|
15922
17356
|
existing = {
|
|
@@ -15964,9 +17398,8 @@ function CPF(options) {
|
|
|
15964
17398
|
};
|
|
15965
17399
|
}
|
|
15966
17400
|
function CNPJ(options) {
|
|
15967
|
-
return function(
|
|
15968
|
-
const propertyName =
|
|
15969
|
-
const bag = getOrCreateMetadataBag(context);
|
|
17401
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17402
|
+
const { propertyName, bag } = resolveCountryDecoratorInfo(targetOrValue, contextOrProperty);
|
|
15970
17403
|
let existing = bag.transformers.find((t) => t.propertyName === propertyName);
|
|
15971
17404
|
if (!existing) {
|
|
15972
17405
|
existing = {
|
|
@@ -16014,9 +17447,8 @@ function CNPJ(options) {
|
|
|
16014
17447
|
};
|
|
16015
17448
|
}
|
|
16016
17449
|
function CEP(options) {
|
|
16017
|
-
return function(
|
|
16018
|
-
const propertyName =
|
|
16019
|
-
const bag = getOrCreateMetadataBag(context);
|
|
17450
|
+
return function(targetOrValue, contextOrProperty) {
|
|
17451
|
+
const { propertyName, bag } = resolveCountryDecoratorInfo(targetOrValue, contextOrProperty);
|
|
16020
17452
|
let existing = bag.transformers.find((t) => t.propertyName === propertyName);
|
|
16021
17453
|
if (!existing) {
|
|
16022
17454
|
existing = {
|
|
@@ -16272,6 +17704,14 @@ var Pool = class {
|
|
|
16272
17704
|
};
|
|
16273
17705
|
|
|
16274
17706
|
// src/core/execution/executors/postgres-executor.ts
|
|
17707
|
+
var SAVEPOINT_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17708
|
+
var sanitizeSavepointName = (name) => {
|
|
17709
|
+
const trimmed = name.trim();
|
|
17710
|
+
if (!SAVEPOINT_NAME_PATTERN.test(trimmed)) {
|
|
17711
|
+
throw new Error(`Invalid savepoint name: "${name}"`);
|
|
17712
|
+
}
|
|
17713
|
+
return trimmed;
|
|
17714
|
+
};
|
|
16275
17715
|
function createPostgresExecutor(client) {
|
|
16276
17716
|
return createExecutorFromQueryRunner({
|
|
16277
17717
|
async query(sql, params) {
|
|
@@ -16286,11 +17726,24 @@ function createPostgresExecutor(client) {
|
|
|
16286
17726
|
},
|
|
16287
17727
|
async rollbackTransaction() {
|
|
16288
17728
|
await client.query("ROLLBACK");
|
|
17729
|
+
},
|
|
17730
|
+
async savepoint(name) {
|
|
17731
|
+
const savepoint = sanitizeSavepointName(name);
|
|
17732
|
+
await client.query(`SAVEPOINT ${savepoint}`);
|
|
17733
|
+
},
|
|
17734
|
+
async releaseSavepoint(name) {
|
|
17735
|
+
const savepoint = sanitizeSavepointName(name);
|
|
17736
|
+
await client.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
17737
|
+
},
|
|
17738
|
+
async rollbackToSavepoint(name) {
|
|
17739
|
+
const savepoint = sanitizeSavepointName(name);
|
|
17740
|
+
await client.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
16289
17741
|
}
|
|
16290
17742
|
});
|
|
16291
17743
|
}
|
|
16292
17744
|
|
|
16293
17745
|
// src/core/execution/executors/mysql-executor.ts
|
|
17746
|
+
var SAVEPOINT_NAME_PATTERN2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
16294
17747
|
var isRowObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16295
17748
|
var isRowObjectArray = (value) => Array.isArray(value) && value.every(isRowObject);
|
|
16296
17749
|
var isMysqlResultHeader = (value) => isRowObject(value) && ("affectedRows" in value || "insertId" in value || "warningStatus" in value || "serverStatus" in value);
|
|
@@ -16302,6 +17755,13 @@ var headerToQueryResult = (header) => ({
|
|
|
16302
17755
|
rowsAffected: header.affectedRows
|
|
16303
17756
|
}
|
|
16304
17757
|
});
|
|
17758
|
+
var sanitizeSavepointName2 = (name) => {
|
|
17759
|
+
const trimmed = name.trim();
|
|
17760
|
+
if (!SAVEPOINT_NAME_PATTERN2.test(trimmed)) {
|
|
17761
|
+
throw new Error(`Invalid savepoint name: "${name}"`);
|
|
17762
|
+
}
|
|
17763
|
+
return trimmed;
|
|
17764
|
+
};
|
|
16305
17765
|
var normalizeMysqlResults = (rows) => {
|
|
16306
17766
|
if (!Array.isArray(rows)) {
|
|
16307
17767
|
return isMysqlResultHeader(rows) ? [headerToQueryResult(rows)] : [rowsToQueryResult([])];
|
|
@@ -16323,9 +17783,11 @@ var normalizeMysqlResults = (rows) => {
|
|
|
16323
17783
|
};
|
|
16324
17784
|
function createMysqlExecutor(client) {
|
|
16325
17785
|
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
17786
|
+
const supportsSavepoints = supportsTransactions;
|
|
16326
17787
|
return {
|
|
16327
17788
|
capabilities: {
|
|
16328
|
-
transactions: supportsTransactions
|
|
17789
|
+
transactions: supportsTransactions,
|
|
17790
|
+
...supportsSavepoints ? { savepoints: true } : {}
|
|
16329
17791
|
},
|
|
16330
17792
|
async executeSql(sql, params) {
|
|
16331
17793
|
const [rows] = await client.query(sql, params);
|
|
@@ -16349,17 +17811,55 @@ function createMysqlExecutor(client) {
|
|
|
16349
17811
|
}
|
|
16350
17812
|
await client.rollback();
|
|
16351
17813
|
},
|
|
17814
|
+
async savepoint(name) {
|
|
17815
|
+
if (!supportsSavepoints) {
|
|
17816
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
17817
|
+
}
|
|
17818
|
+
const savepoint = sanitizeSavepointName2(name);
|
|
17819
|
+
await client.query(`SAVEPOINT ${savepoint}`);
|
|
17820
|
+
},
|
|
17821
|
+
async releaseSavepoint(name) {
|
|
17822
|
+
if (!supportsSavepoints) {
|
|
17823
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
17824
|
+
}
|
|
17825
|
+
const savepoint = sanitizeSavepointName2(name);
|
|
17826
|
+
await client.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
17827
|
+
},
|
|
17828
|
+
async rollbackToSavepoint(name) {
|
|
17829
|
+
if (!supportsSavepoints) {
|
|
17830
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
17831
|
+
}
|
|
17832
|
+
const savepoint = sanitizeSavepointName2(name);
|
|
17833
|
+
await client.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
17834
|
+
},
|
|
16352
17835
|
async dispose() {
|
|
16353
17836
|
}
|
|
16354
17837
|
};
|
|
16355
17838
|
}
|
|
16356
17839
|
|
|
16357
17840
|
// src/core/execution/executors/sqlite-executor.ts
|
|
17841
|
+
var SAVEPOINT_NAME_PATTERN3 = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17842
|
+
var sanitizeSavepointName3 = (name) => {
|
|
17843
|
+
const trimmed = name.trim();
|
|
17844
|
+
if (!SAVEPOINT_NAME_PATTERN3.test(trimmed)) {
|
|
17845
|
+
throw new Error(`Invalid savepoint name: "${name}"`);
|
|
17846
|
+
}
|
|
17847
|
+
return trimmed;
|
|
17848
|
+
};
|
|
16358
17849
|
function createSqliteExecutor(client) {
|
|
16359
17850
|
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commitTransaction === "function" && typeof client.rollbackTransaction === "function";
|
|
17851
|
+
const supportsSavepoints = supportsTransactions;
|
|
17852
|
+
const executeControlStatement = async (sql) => {
|
|
17853
|
+
if (typeof client.run === "function") {
|
|
17854
|
+
await client.run(sql);
|
|
17855
|
+
return;
|
|
17856
|
+
}
|
|
17857
|
+
await client.all(sql);
|
|
17858
|
+
};
|
|
16360
17859
|
return {
|
|
16361
17860
|
capabilities: {
|
|
16362
|
-
transactions: supportsTransactions
|
|
17861
|
+
transactions: supportsTransactions,
|
|
17862
|
+
...supportsSavepoints ? { savepoints: true } : {}
|
|
16363
17863
|
},
|
|
16364
17864
|
async executeSql(sql, params) {
|
|
16365
17865
|
const rows = await client.all(sql, params);
|
|
@@ -16384,17 +17884,120 @@ function createSqliteExecutor(client) {
|
|
|
16384
17884
|
}
|
|
16385
17885
|
await client.rollbackTransaction();
|
|
16386
17886
|
},
|
|
17887
|
+
async savepoint(name) {
|
|
17888
|
+
if (!supportsSavepoints) {
|
|
17889
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
17890
|
+
}
|
|
17891
|
+
const savepoint = sanitizeSavepointName3(name);
|
|
17892
|
+
if (typeof client.savepoint === "function") {
|
|
17893
|
+
await client.savepoint(savepoint);
|
|
17894
|
+
return;
|
|
17895
|
+
}
|
|
17896
|
+
await executeControlStatement(`SAVEPOINT ${savepoint}`);
|
|
17897
|
+
},
|
|
17898
|
+
async releaseSavepoint(name) {
|
|
17899
|
+
if (!supportsSavepoints) {
|
|
17900
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
17901
|
+
}
|
|
17902
|
+
const savepoint = sanitizeSavepointName3(name);
|
|
17903
|
+
if (typeof client.releaseSavepoint === "function") {
|
|
17904
|
+
await client.releaseSavepoint(savepoint);
|
|
17905
|
+
return;
|
|
17906
|
+
}
|
|
17907
|
+
await executeControlStatement(`RELEASE SAVEPOINT ${savepoint}`);
|
|
17908
|
+
},
|
|
17909
|
+
async rollbackToSavepoint(name) {
|
|
17910
|
+
if (!supportsSavepoints) {
|
|
17911
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
17912
|
+
}
|
|
17913
|
+
const savepoint = sanitizeSavepointName3(name);
|
|
17914
|
+
if (typeof client.rollbackToSavepoint === "function") {
|
|
17915
|
+
await client.rollbackToSavepoint(savepoint);
|
|
17916
|
+
return;
|
|
17917
|
+
}
|
|
17918
|
+
await executeControlStatement(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
17919
|
+
},
|
|
17920
|
+
async dispose() {
|
|
17921
|
+
}
|
|
17922
|
+
};
|
|
17923
|
+
}
|
|
17924
|
+
|
|
17925
|
+
// src/core/execution/executors/better-sqlite3-executor.ts
|
|
17926
|
+
var SAVEPOINT_NAME_PATTERN4 = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17927
|
+
var sanitizeSavepointName4 = (name) => {
|
|
17928
|
+
const trimmed = name.trim();
|
|
17929
|
+
if (!SAVEPOINT_NAME_PATTERN4.test(trimmed)) {
|
|
17930
|
+
throw new Error(`Invalid savepoint name: "${name}"`);
|
|
17931
|
+
}
|
|
17932
|
+
return trimmed;
|
|
17933
|
+
};
|
|
17934
|
+
function createBetterSqlite3Executor(client) {
|
|
17935
|
+
return {
|
|
17936
|
+
capabilities: {
|
|
17937
|
+
transactions: true,
|
|
17938
|
+
savepoints: true
|
|
17939
|
+
},
|
|
17940
|
+
async executeSql(sql, params) {
|
|
17941
|
+
const stmt = client.prepare(sql);
|
|
17942
|
+
let result;
|
|
17943
|
+
if (stmt.reader) {
|
|
17944
|
+
const rows = stmt.all(...params ?? []);
|
|
17945
|
+
result = rowsToQueryResult(rows);
|
|
17946
|
+
} else {
|
|
17947
|
+
const info = stmt.run(...params ?? []);
|
|
17948
|
+
result = {
|
|
17949
|
+
columns: [],
|
|
17950
|
+
values: [],
|
|
17951
|
+
meta: {
|
|
17952
|
+
rowsAffected: info.changes,
|
|
17953
|
+
insertId: typeof info.lastInsertRowid === "bigint" ? info.lastInsertRowid.toString() : info.lastInsertRowid
|
|
17954
|
+
}
|
|
17955
|
+
};
|
|
17956
|
+
}
|
|
17957
|
+
return toExecutionPayload([result]);
|
|
17958
|
+
},
|
|
17959
|
+
async beginTransaction() {
|
|
17960
|
+
client.prepare("BEGIN").run();
|
|
17961
|
+
},
|
|
17962
|
+
async commitTransaction() {
|
|
17963
|
+
client.prepare("COMMIT").run();
|
|
17964
|
+
},
|
|
17965
|
+
async rollbackTransaction() {
|
|
17966
|
+
client.prepare("ROLLBACK").run();
|
|
17967
|
+
},
|
|
17968
|
+
async savepoint(name) {
|
|
17969
|
+
const savepoint = sanitizeSavepointName4(name);
|
|
17970
|
+
client.prepare(`SAVEPOINT ${savepoint}`).run();
|
|
17971
|
+
},
|
|
17972
|
+
async releaseSavepoint(name) {
|
|
17973
|
+
const savepoint = sanitizeSavepointName4(name);
|
|
17974
|
+
client.prepare(`RELEASE SAVEPOINT ${savepoint}`).run();
|
|
17975
|
+
},
|
|
17976
|
+
async rollbackToSavepoint(name) {
|
|
17977
|
+
const savepoint = sanitizeSavepointName4(name);
|
|
17978
|
+
client.prepare(`ROLLBACK TO SAVEPOINT ${savepoint}`).run();
|
|
17979
|
+
},
|
|
16387
17980
|
async dispose() {
|
|
16388
17981
|
}
|
|
16389
17982
|
};
|
|
16390
17983
|
}
|
|
16391
17984
|
|
|
16392
17985
|
// src/core/execution/executors/mssql-executor.ts
|
|
17986
|
+
var SAVEPOINT_NAME_PATTERN5 = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
17987
|
+
var sanitizeSavepointName5 = (name) => {
|
|
17988
|
+
const trimmed = name.trim();
|
|
17989
|
+
if (!SAVEPOINT_NAME_PATTERN5.test(trimmed)) {
|
|
17990
|
+
throw new Error(`Invalid savepoint name: "${name}"`);
|
|
17991
|
+
}
|
|
17992
|
+
return trimmed;
|
|
17993
|
+
};
|
|
16393
17994
|
function createMssqlExecutor(client) {
|
|
16394
17995
|
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
17996
|
+
const supportsSavepoints = supportsTransactions;
|
|
16395
17997
|
return {
|
|
16396
17998
|
capabilities: {
|
|
16397
|
-
transactions: supportsTransactions
|
|
17999
|
+
transactions: supportsTransactions,
|
|
18000
|
+
...supportsSavepoints ? { savepoints: true } : {}
|
|
16398
18001
|
},
|
|
16399
18002
|
async executeSql(sql, params) {
|
|
16400
18003
|
const { recordset, recordsets } = await client.query(sql, params);
|
|
@@ -16419,6 +18022,25 @@ function createMssqlExecutor(client) {
|
|
|
16419
18022
|
}
|
|
16420
18023
|
await client.rollback();
|
|
16421
18024
|
},
|
|
18025
|
+
async savepoint(name) {
|
|
18026
|
+
if (!supportsSavepoints) {
|
|
18027
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
18028
|
+
}
|
|
18029
|
+
const savepoint = sanitizeSavepointName5(name);
|
|
18030
|
+
await client.query(`SAVE TRANSACTION ${savepoint}`);
|
|
18031
|
+
},
|
|
18032
|
+
async releaseSavepoint(_name) {
|
|
18033
|
+
if (!supportsSavepoints) {
|
|
18034
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
18035
|
+
}
|
|
18036
|
+
},
|
|
18037
|
+
async rollbackToSavepoint(name) {
|
|
18038
|
+
if (!supportsSavepoints) {
|
|
18039
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
18040
|
+
}
|
|
18041
|
+
const savepoint = sanitizeSavepointName5(name);
|
|
18042
|
+
await client.query(`ROLLBACK TRANSACTION ${savepoint}`);
|
|
18043
|
+
},
|
|
16422
18044
|
async dispose() {
|
|
16423
18045
|
}
|
|
16424
18046
|
};
|
|
@@ -16494,6 +18116,7 @@ var isQueryResult = (value) => typeof value === "object" && value !== null && Ar
|
|
|
16494
18116
|
var isRowArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "object" && item !== null && !Array.isArray(item));
|
|
16495
18117
|
function createPooledExecutorFactory(opts) {
|
|
16496
18118
|
const { pool, adapter } = opts;
|
|
18119
|
+
const supportsSavepoints = typeof adapter.savepoint === "function" && typeof adapter.releaseSavepoint === "function" && typeof adapter.rollbackToSavepoint === "function";
|
|
16497
18120
|
const makeExecutor = (mode) => {
|
|
16498
18121
|
let lease = null;
|
|
16499
18122
|
const getLease = async () => {
|
|
@@ -16511,8 +18134,17 @@ function createPooledExecutorFactory(opts) {
|
|
|
16511
18134
|
}
|
|
16512
18135
|
return toExecutionPayload([rowsToQueryResult(rows)]);
|
|
16513
18136
|
};
|
|
18137
|
+
const requireActiveTransactionLease = () => {
|
|
18138
|
+
if (!lease) {
|
|
18139
|
+
throw new Error("savepoint operation called without an active transaction");
|
|
18140
|
+
}
|
|
18141
|
+
return lease;
|
|
18142
|
+
};
|
|
16514
18143
|
return {
|
|
16515
|
-
capabilities: {
|
|
18144
|
+
capabilities: {
|
|
18145
|
+
transactions: true,
|
|
18146
|
+
...supportsSavepoints ? { savepoints: true } : {}
|
|
18147
|
+
},
|
|
16516
18148
|
async executeSql(sql, params) {
|
|
16517
18149
|
if (mode === "sticky") {
|
|
16518
18150
|
const l2 = await getLease();
|
|
@@ -16556,6 +18188,27 @@ function createPooledExecutorFactory(opts) {
|
|
|
16556
18188
|
await l.release();
|
|
16557
18189
|
}
|
|
16558
18190
|
},
|
|
18191
|
+
async savepoint(name) {
|
|
18192
|
+
if (!supportsSavepoints) {
|
|
18193
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
18194
|
+
}
|
|
18195
|
+
const l = requireActiveTransactionLease();
|
|
18196
|
+
await adapter.savepoint(l.resource, name);
|
|
18197
|
+
},
|
|
18198
|
+
async releaseSavepoint(name) {
|
|
18199
|
+
if (!supportsSavepoints) {
|
|
18200
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
18201
|
+
}
|
|
18202
|
+
const l = requireActiveTransactionLease();
|
|
18203
|
+
await adapter.releaseSavepoint(l.resource, name);
|
|
18204
|
+
},
|
|
18205
|
+
async rollbackToSavepoint(name) {
|
|
18206
|
+
if (!supportsSavepoints) {
|
|
18207
|
+
throw new Error("Savepoints are not supported by this executor");
|
|
18208
|
+
}
|
|
18209
|
+
const l = requireActiveTransactionLease();
|
|
18210
|
+
await adapter.rollbackToSavepoint(l.resource, name);
|
|
18211
|
+
},
|
|
16559
18212
|
async dispose() {
|
|
16560
18213
|
if (!lease) return;
|
|
16561
18214
|
const l = lease;
|
|
@@ -16650,6 +18303,9 @@ var updateInclude = (qb, relationPath, updater) => {
|
|
|
16650
18303
|
filter: segmentOptions?.filter
|
|
16651
18304
|
});
|
|
16652
18305
|
}
|
|
18306
|
+
if (!isSingleTargetRelation(relation)) {
|
|
18307
|
+
continue;
|
|
18308
|
+
}
|
|
16653
18309
|
const joinForSegment = findJoinByRelationKey(state.ast.joins, relationKey);
|
|
16654
18310
|
currentAlias = joinForSegment ? getExposedName(joinForSegment.table) ?? relation.target.name : relation.target.name;
|
|
16655
18311
|
currentTable = relation.target;
|
|
@@ -16778,6 +18434,9 @@ function applyRelationFilter(qb, table, relationName, filter) {
|
|
|
16778
18434
|
`Relation filter "${relationName}" must include at least one of "some", "none", "every", "isEmpty", or "isNotEmpty".`
|
|
16779
18435
|
);
|
|
16780
18436
|
}
|
|
18437
|
+
if (!isSingleTargetRelation(relation)) {
|
|
18438
|
+
return qb;
|
|
18439
|
+
}
|
|
16781
18440
|
if (filter.some) {
|
|
16782
18441
|
const predicate = buildFilterExpression(relation.target, filter.some);
|
|
16783
18442
|
if (predicate) {
|
|
@@ -16823,6 +18482,9 @@ function applyRelationFilter(qb, table, relationName, filter) {
|
|
|
16823
18482
|
return qb;
|
|
16824
18483
|
}
|
|
16825
18484
|
var buildRelationSubqueryBase = (table, relation) => {
|
|
18485
|
+
if (!isSingleTargetRelation(relation)) {
|
|
18486
|
+
throw new Error("MorphTo relations do not support subquery-based filtering");
|
|
18487
|
+
}
|
|
16826
18488
|
const target = relation.target;
|
|
16827
18489
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
16828
18490
|
const many = relation;
|
|
@@ -16868,7 +18530,14 @@ var buildRelationSubqueryBase = (table, relation) => {
|
|
|
16868
18530
|
schema: target.schema
|
|
16869
18531
|
};
|
|
16870
18532
|
const correlation = buildRelationCorrelation(table, relation);
|
|
16871
|
-
|
|
18533
|
+
let groupByColumnName;
|
|
18534
|
+
if (relation.type === RelationKinds.BelongsTo) {
|
|
18535
|
+
groupByColumnName = relation.localKey || findPrimaryKey(target);
|
|
18536
|
+
} else if (relation.type === RelationKinds.MorphOne || relation.type === RelationKinds.MorphMany) {
|
|
18537
|
+
groupByColumnName = relation.idField;
|
|
18538
|
+
} else {
|
|
18539
|
+
groupByColumnName = relation.foreignKey;
|
|
18540
|
+
}
|
|
16872
18541
|
return {
|
|
16873
18542
|
from,
|
|
16874
18543
|
joins: [],
|
|
@@ -16900,6 +18569,9 @@ function buildRelationFilterExpression(table, relationName, filter) {
|
|
|
16900
18569
|
where
|
|
16901
18570
|
};
|
|
16902
18571
|
};
|
|
18572
|
+
if (!isSingleTargetRelation(relation)) {
|
|
18573
|
+
return null;
|
|
18574
|
+
}
|
|
16903
18575
|
if (filter.some) {
|
|
16904
18576
|
const predicate = buildFilterExpression(relation.target, filter.some);
|
|
16905
18577
|
if (predicate) {
|
|
@@ -19869,6 +21541,432 @@ var TagIndex = class {
|
|
|
19869
21541
|
};
|
|
19870
21542
|
}
|
|
19871
21543
|
};
|
|
21544
|
+
|
|
21545
|
+
// src/bulk/bulk-context.ts
|
|
21546
|
+
function createBulkExecutionContext(session) {
|
|
21547
|
+
const executionContext = session.getExecutionContext();
|
|
21548
|
+
return {
|
|
21549
|
+
session,
|
|
21550
|
+
executionContext,
|
|
21551
|
+
dialect: executionContext.dialect,
|
|
21552
|
+
supportsReturning: executionContext.dialect.supportsDmlReturningClause()
|
|
21553
|
+
};
|
|
21554
|
+
}
|
|
21555
|
+
async function executeCompiled(ctx, compiled) {
|
|
21556
|
+
const payload = await ctx.executionContext.interceptors.run(
|
|
21557
|
+
{ sql: compiled.sql, params: compiled.params },
|
|
21558
|
+
ctx.executionContext.executor
|
|
21559
|
+
);
|
|
21560
|
+
return extractResultSets(payload);
|
|
21561
|
+
}
|
|
21562
|
+
function extractResultSets(payload) {
|
|
21563
|
+
const result = payload;
|
|
21564
|
+
if (result.resultSets) {
|
|
21565
|
+
return result.resultSets;
|
|
21566
|
+
}
|
|
21567
|
+
return [];
|
|
21568
|
+
}
|
|
21569
|
+
function flattenQueryResults(resultSets) {
|
|
21570
|
+
const rows = [];
|
|
21571
|
+
for (const rs of resultSets) {
|
|
21572
|
+
for (const valueRow of rs.values) {
|
|
21573
|
+
const obj = {};
|
|
21574
|
+
rs.columns.forEach((col2, idx) => {
|
|
21575
|
+
const bare = col2.split(".").pop().replace(/^["`[\]]+|["`[\]]+$/g, "");
|
|
21576
|
+
obj[bare] = valueRow[idx];
|
|
21577
|
+
});
|
|
21578
|
+
rows.push(obj);
|
|
21579
|
+
}
|
|
21580
|
+
}
|
|
21581
|
+
return rows;
|
|
21582
|
+
}
|
|
21583
|
+
function resolveReturningColumns(ctx, table, returning) {
|
|
21584
|
+
if (!returning) return void 0;
|
|
21585
|
+
if (!ctx.supportsReturning) return void 0;
|
|
21586
|
+
if (returning === true) {
|
|
21587
|
+
return Object.values(table.columns).map((col2) => ({
|
|
21588
|
+
type: "Column",
|
|
21589
|
+
table: table.name,
|
|
21590
|
+
name: col2.name,
|
|
21591
|
+
alias: col2.name
|
|
21592
|
+
}));
|
|
21593
|
+
}
|
|
21594
|
+
return returning.map((col2) => ({
|
|
21595
|
+
type: "Column",
|
|
21596
|
+
table: table.name,
|
|
21597
|
+
name: col2.name,
|
|
21598
|
+
alias: col2.name
|
|
21599
|
+
}));
|
|
21600
|
+
}
|
|
21601
|
+
|
|
21602
|
+
// src/bulk/bulk-utils.ts
|
|
21603
|
+
function splitIntoChunks(items, size) {
|
|
21604
|
+
if (size < 1) throw new RangeError(`chunkSize must be >= 1, got ${size}`);
|
|
21605
|
+
const chunks = [];
|
|
21606
|
+
for (let i = 0; i < items.length; i += size) {
|
|
21607
|
+
chunks.push(items.slice(i, i + size));
|
|
21608
|
+
}
|
|
21609
|
+
return chunks;
|
|
21610
|
+
}
|
|
21611
|
+
async function runWithConcurrency(tasks, concurrency) {
|
|
21612
|
+
const limit = concurrency === "sequential" ? 1 : Math.max(1, concurrency);
|
|
21613
|
+
if (limit === 1) {
|
|
21614
|
+
const results2 = [];
|
|
21615
|
+
for (const task of tasks) {
|
|
21616
|
+
results2.push(await task());
|
|
21617
|
+
}
|
|
21618
|
+
return results2;
|
|
21619
|
+
}
|
|
21620
|
+
const results = new Array(tasks.length);
|
|
21621
|
+
let nextIndex = 0;
|
|
21622
|
+
const worker = async () => {
|
|
21623
|
+
while (nextIndex < tasks.length) {
|
|
21624
|
+
const i = nextIndex++;
|
|
21625
|
+
results[i] = await tasks[i]();
|
|
21626
|
+
}
|
|
21627
|
+
};
|
|
21628
|
+
const workers = Array.from({ length: Math.min(limit, tasks.length) }, worker);
|
|
21629
|
+
await Promise.all(workers);
|
|
21630
|
+
return results;
|
|
21631
|
+
}
|
|
21632
|
+
async function runChunk(task, chunkIndex, totalChunks, rowsInChunk, timing, onChunkComplete) {
|
|
21633
|
+
const start = timing || onChunkComplete ? Date.now() : 0;
|
|
21634
|
+
const result = await task();
|
|
21635
|
+
const elapsedMs = start ? Date.now() - start : 0;
|
|
21636
|
+
if (onChunkComplete) {
|
|
21637
|
+
await onChunkComplete({ chunkIndex, totalChunks, rowsInChunk, elapsedMs });
|
|
21638
|
+
}
|
|
21639
|
+
return result;
|
|
21640
|
+
}
|
|
21641
|
+
async function maybeTransaction(session, transactional, fn8) {
|
|
21642
|
+
if (!transactional) return fn8();
|
|
21643
|
+
const ormSession = session;
|
|
21644
|
+
return ormSession.transaction(fn8);
|
|
21645
|
+
}
|
|
21646
|
+
function aggregateOutcomes(outcomes) {
|
|
21647
|
+
const result = {
|
|
21648
|
+
processedRows: 0,
|
|
21649
|
+
chunksExecuted: outcomes.length,
|
|
21650
|
+
returning: []
|
|
21651
|
+
};
|
|
21652
|
+
for (const o of outcomes) {
|
|
21653
|
+
result.processedRows += o.processedRows;
|
|
21654
|
+
result.returning.push(...o.returning);
|
|
21655
|
+
}
|
|
21656
|
+
return result;
|
|
21657
|
+
}
|
|
21658
|
+
function aggregateOutcomesWithTimings(outcomes) {
|
|
21659
|
+
const result = aggregateOutcomes(outcomes);
|
|
21660
|
+
result.chunkTimings = outcomes.map((o) => o.elapsedMs);
|
|
21661
|
+
return result;
|
|
21662
|
+
}
|
|
21663
|
+
|
|
21664
|
+
// src/bulk/bulk-executor.base.ts
|
|
21665
|
+
var DEFAULT_CHUNK_SIZE = 500;
|
|
21666
|
+
var BulkBaseExecutor = class {
|
|
21667
|
+
session;
|
|
21668
|
+
table;
|
|
21669
|
+
ctx;
|
|
21670
|
+
options;
|
|
21671
|
+
chunks;
|
|
21672
|
+
totalChunks;
|
|
21673
|
+
constructor(session, table, rows, options = {}) {
|
|
21674
|
+
this.session = session;
|
|
21675
|
+
this.table = table;
|
|
21676
|
+
this.ctx = createBulkExecutionContext(session);
|
|
21677
|
+
this.options = {
|
|
21678
|
+
chunkSize: DEFAULT_CHUNK_SIZE,
|
|
21679
|
+
concurrency: "sequential",
|
|
21680
|
+
transactional: true,
|
|
21681
|
+
timing: false,
|
|
21682
|
+
...options
|
|
21683
|
+
};
|
|
21684
|
+
this.chunks = splitIntoChunks(rows, this.options.chunkSize);
|
|
21685
|
+
this.totalChunks = this.chunks.length;
|
|
21686
|
+
}
|
|
21687
|
+
async execute() {
|
|
21688
|
+
const buildTask = (chunk, chunkIndex) => async () => {
|
|
21689
|
+
return runChunk(
|
|
21690
|
+
() => this.executeChunk(chunk, chunkIndex),
|
|
21691
|
+
chunkIndex,
|
|
21692
|
+
this.totalChunks,
|
|
21693
|
+
chunk.length,
|
|
21694
|
+
this.options.timing,
|
|
21695
|
+
this.options.onChunkComplete
|
|
21696
|
+
);
|
|
21697
|
+
};
|
|
21698
|
+
const tasks = this.chunks.map((chunk, i) => buildTask(chunk, i));
|
|
21699
|
+
const outcomes = await maybeTransaction(
|
|
21700
|
+
this.session,
|
|
21701
|
+
this.options.transactional,
|
|
21702
|
+
() => runWithConcurrency(tasks, this.options.concurrency)
|
|
21703
|
+
);
|
|
21704
|
+
return this.options.timing ? aggregateOutcomesWithTimings(outcomes) : aggregateOutcomes(outcomes);
|
|
21705
|
+
}
|
|
21706
|
+
};
|
|
21707
|
+
|
|
21708
|
+
// src/bulk/bulk-insert-executor.ts
|
|
21709
|
+
var BulkInsertExecutor = class extends BulkBaseExecutor {
|
|
21710
|
+
constructor(session, table, rows, options = {}) {
|
|
21711
|
+
super(session, table, rows, options);
|
|
21712
|
+
}
|
|
21713
|
+
async executeChunk(chunk, chunkIndex) {
|
|
21714
|
+
const returningColumns = resolveReturningColumns(this.ctx, this.table, this.options.returning);
|
|
21715
|
+
let builder = new InsertQueryBuilder(this.table).values(chunk);
|
|
21716
|
+
if (this.options.onConflict) {
|
|
21717
|
+
const conflictColumns = this.options.onConflict.target?.columns ?? [];
|
|
21718
|
+
builder = builder.onConflict(conflictColumns);
|
|
21719
|
+
if (this.options.onConflict.action.type === "DoNothing") {
|
|
21720
|
+
builder = builder.doNothing();
|
|
21721
|
+
} else if (this.options.onConflict.action.type === "DoUpdate" && this.options.onConflict.action.set) {
|
|
21722
|
+
const setMap = {};
|
|
21723
|
+
for (const assignment of this.options.onConflict.action.set) {
|
|
21724
|
+
const colName = typeof assignment.column === "object" ? assignment.column.name : assignment.column;
|
|
21725
|
+
setMap[colName] = assignment.value;
|
|
21726
|
+
}
|
|
21727
|
+
builder = builder.doUpdate(setMap);
|
|
21728
|
+
}
|
|
21729
|
+
}
|
|
21730
|
+
const finalBuilder = builder;
|
|
21731
|
+
if (returningColumns?.length) {
|
|
21732
|
+
finalBuilder.returning(...returningColumns);
|
|
21733
|
+
}
|
|
21734
|
+
const compiled = finalBuilder.compile(this.ctx.dialect);
|
|
21735
|
+
const resultSets = await executeCompiled(this.ctx, compiled);
|
|
21736
|
+
return {
|
|
21737
|
+
processedRows: chunk.length,
|
|
21738
|
+
returning: returningColumns ? flattenQueryResults(resultSets) : [],
|
|
21739
|
+
elapsedMs: 0
|
|
21740
|
+
};
|
|
21741
|
+
}
|
|
21742
|
+
};
|
|
21743
|
+
async function bulkInsert(session, table, rows, options = {}) {
|
|
21744
|
+
if (!rows.length) {
|
|
21745
|
+
return { processedRows: 0, chunksExecuted: 0, returning: [] };
|
|
21746
|
+
}
|
|
21747
|
+
const executor = new BulkInsertExecutor(session, table, rows, options);
|
|
21748
|
+
return executor.execute();
|
|
21749
|
+
}
|
|
21750
|
+
|
|
21751
|
+
// src/bulk/bulk-update-executor.ts
|
|
21752
|
+
function resolveByColumns(table, by) {
|
|
21753
|
+
if (!by) return [findPrimaryKey(table)];
|
|
21754
|
+
return Array.isArray(by) ? by : [by];
|
|
21755
|
+
}
|
|
21756
|
+
var BulkUpdateExecutor = class extends BulkBaseExecutor {
|
|
21757
|
+
byColumns;
|
|
21758
|
+
constructor(session, table, rows, options = {}) {
|
|
21759
|
+
super(session, table, rows, options);
|
|
21760
|
+
this.byColumns = resolveByColumns(table, options.by);
|
|
21761
|
+
}
|
|
21762
|
+
async executeChunk(chunk, chunkIndex) {
|
|
21763
|
+
const allReturning = [];
|
|
21764
|
+
const returningColumns = resolveReturningColumns(this.ctx, this.table, this.options.returning);
|
|
21765
|
+
const extraWhere = this.options.where;
|
|
21766
|
+
for (const row of chunk) {
|
|
21767
|
+
const predicates = this.byColumns.map((colName) => {
|
|
21768
|
+
const col2 = this.table.columns[colName];
|
|
21769
|
+
if (!col2) {
|
|
21770
|
+
throw new Error(
|
|
21771
|
+
`bulkUpdate: column "${colName}" not found in table "${this.table.name}"`
|
|
21772
|
+
);
|
|
21773
|
+
}
|
|
21774
|
+
const val = row[colName];
|
|
21775
|
+
if (val === void 0) {
|
|
21776
|
+
throw new Error(
|
|
21777
|
+
`bulkUpdate: row is missing the identity column "${colName}" required by the "by" option`
|
|
21778
|
+
);
|
|
21779
|
+
}
|
|
21780
|
+
return eq(col2, val);
|
|
21781
|
+
});
|
|
21782
|
+
const whereExpr = predicates.length === 1 ? predicates[0] : predicates.reduce((acc, p) => and(acc, p), predicates[0]);
|
|
21783
|
+
const finalWhere = extraWhere ? and(whereExpr, extraWhere) : whereExpr;
|
|
21784
|
+
const bySet = new Set(this.byColumns);
|
|
21785
|
+
const setPayload = {};
|
|
21786
|
+
for (const [key, val] of Object.entries(row)) {
|
|
21787
|
+
if (!bySet.has(key) && key in this.table.columns) {
|
|
21788
|
+
setPayload[key] = val;
|
|
21789
|
+
}
|
|
21790
|
+
}
|
|
21791
|
+
if (!Object.keys(setPayload).length) continue;
|
|
21792
|
+
let builder = new UpdateQueryBuilder(this.table).set(setPayload).where(finalWhere);
|
|
21793
|
+
if (returningColumns?.length) {
|
|
21794
|
+
builder = builder.returning(...returningColumns);
|
|
21795
|
+
}
|
|
21796
|
+
const compiled = builder.compile(this.ctx.dialect);
|
|
21797
|
+
const resultSets = await executeCompiled(this.ctx, compiled);
|
|
21798
|
+
if (returningColumns) {
|
|
21799
|
+
allReturning.push(...flattenQueryResults(resultSets));
|
|
21800
|
+
}
|
|
21801
|
+
}
|
|
21802
|
+
return {
|
|
21803
|
+
processedRows: chunk.length,
|
|
21804
|
+
returning: allReturning,
|
|
21805
|
+
elapsedMs: 0
|
|
21806
|
+
};
|
|
21807
|
+
}
|
|
21808
|
+
};
|
|
21809
|
+
async function bulkUpdate(session, table, rows, options = {}) {
|
|
21810
|
+
if (!rows.length) {
|
|
21811
|
+
return { processedRows: 0, chunksExecuted: 0, returning: [] };
|
|
21812
|
+
}
|
|
21813
|
+
const executor = new BulkUpdateExecutor(session, table, rows, options);
|
|
21814
|
+
return executor.execute();
|
|
21815
|
+
}
|
|
21816
|
+
var DEFAULT_BULK_UPDATE_WHERE_CHUNK_SIZE = 500;
|
|
21817
|
+
async function bulkUpdateWhere(session, table, ids, set, options = {}) {
|
|
21818
|
+
if (!ids.length) {
|
|
21819
|
+
return { processedRows: 0, chunksExecuted: 0, returning: [] };
|
|
21820
|
+
}
|
|
21821
|
+
const {
|
|
21822
|
+
chunkSize = DEFAULT_BULK_UPDATE_WHERE_CHUNK_SIZE,
|
|
21823
|
+
concurrency = "sequential",
|
|
21824
|
+
transactional = true,
|
|
21825
|
+
timing = false,
|
|
21826
|
+
onChunkComplete,
|
|
21827
|
+
by,
|
|
21828
|
+
where: extraWhere,
|
|
21829
|
+
returning
|
|
21830
|
+
} = options;
|
|
21831
|
+
const ctx = createBulkExecutionContext(session);
|
|
21832
|
+
const byColumnName = by ?? findPrimaryKey(table);
|
|
21833
|
+
const byColumn = table.columns[byColumnName];
|
|
21834
|
+
if (!byColumn) {
|
|
21835
|
+
throw new Error(
|
|
21836
|
+
`bulkUpdateWhere: column "${byColumnName}" not found in table "${table.name}"`
|
|
21837
|
+
);
|
|
21838
|
+
}
|
|
21839
|
+
const returningColumns = resolveReturningColumns(ctx, table, returning);
|
|
21840
|
+
const chunks = splitIntoChunks(ids, chunkSize);
|
|
21841
|
+
const totalChunks = chunks.length;
|
|
21842
|
+
const buildTask = (chunk, chunkIndex) => async () => {
|
|
21843
|
+
return runChunk(
|
|
21844
|
+
async () => {
|
|
21845
|
+
const inExpr = inList(byColumn, chunk);
|
|
21846
|
+
const finalWhere = extraWhere ? and(inExpr, extraWhere) : inExpr;
|
|
21847
|
+
let builder = new UpdateQueryBuilder(table).set(set).where(finalWhere);
|
|
21848
|
+
if (returningColumns?.length) {
|
|
21849
|
+
builder = builder.returning(...returningColumns);
|
|
21850
|
+
}
|
|
21851
|
+
const compiled = builder.compile(ctx.dialect);
|
|
21852
|
+
const resultSets = await executeCompiled(ctx, compiled);
|
|
21853
|
+
return {
|
|
21854
|
+
processedRows: chunk.length,
|
|
21855
|
+
returning: returningColumns ? flattenQueryResults(resultSets) : [],
|
|
21856
|
+
elapsedMs: 0
|
|
21857
|
+
};
|
|
21858
|
+
},
|
|
21859
|
+
chunkIndex,
|
|
21860
|
+
totalChunks,
|
|
21861
|
+
chunk.length,
|
|
21862
|
+
timing,
|
|
21863
|
+
onChunkComplete
|
|
21864
|
+
);
|
|
21865
|
+
};
|
|
21866
|
+
const tasks = chunks.map((chunk, i) => buildTask(chunk, i));
|
|
21867
|
+
const outcomes = await maybeTransaction(
|
|
21868
|
+
session,
|
|
21869
|
+
transactional,
|
|
21870
|
+
() => runWithConcurrency(tasks, concurrency)
|
|
21871
|
+
);
|
|
21872
|
+
return timing ? aggregateOutcomesWithTimings(outcomes) : aggregateOutcomes(outcomes);
|
|
21873
|
+
}
|
|
21874
|
+
|
|
21875
|
+
// src/bulk/bulk-delete-executor.ts
|
|
21876
|
+
var BulkDeleteExecutor = class extends BulkBaseExecutor {
|
|
21877
|
+
byColumnName;
|
|
21878
|
+
constructor(session, table, ids, options = {}) {
|
|
21879
|
+
super(session, table, ids, options);
|
|
21880
|
+
this.byColumnName = options.by ?? findPrimaryKey(table);
|
|
21881
|
+
}
|
|
21882
|
+
async executeChunk(chunk, chunkIndex) {
|
|
21883
|
+
const byColumn = this.table.columns[this.byColumnName];
|
|
21884
|
+
if (!byColumn) {
|
|
21885
|
+
throw new Error(
|
|
21886
|
+
`bulkDelete: column "${this.byColumnName}" not found in table "${this.table.name}"`
|
|
21887
|
+
);
|
|
21888
|
+
}
|
|
21889
|
+
const extraWhere = this.options.where;
|
|
21890
|
+
const inExpr = inList(byColumn, chunk);
|
|
21891
|
+
const finalWhere = extraWhere ? and(inExpr, extraWhere) : inExpr;
|
|
21892
|
+
const builder = new DeleteQueryBuilder(this.table).where(finalWhere);
|
|
21893
|
+
const compiled = builder.compile(this.ctx.dialect);
|
|
21894
|
+
await executeCompiled(this.ctx, compiled);
|
|
21895
|
+
return {
|
|
21896
|
+
processedRows: chunk.length,
|
|
21897
|
+
returning: [],
|
|
21898
|
+
elapsedMs: 0
|
|
21899
|
+
};
|
|
21900
|
+
}
|
|
21901
|
+
};
|
|
21902
|
+
async function bulkDelete(session, table, ids, options = {}) {
|
|
21903
|
+
if (!ids.length) {
|
|
21904
|
+
return { processedRows: 0, chunksExecuted: 0, returning: [] };
|
|
21905
|
+
}
|
|
21906
|
+
const executor = new BulkDeleteExecutor(session, table, ids, options);
|
|
21907
|
+
return executor.execute();
|
|
21908
|
+
}
|
|
21909
|
+
async function bulkDeleteWhere(session, table, where, options = {}) {
|
|
21910
|
+
const { transactional = false } = options;
|
|
21911
|
+
const ctx = createBulkExecutionContext(session);
|
|
21912
|
+
const builder = new DeleteQueryBuilder(table).where(where);
|
|
21913
|
+
const compiled = builder.compile(ctx.dialect);
|
|
21914
|
+
const execute = async () => {
|
|
21915
|
+
await executeCompiled(ctx, compiled);
|
|
21916
|
+
return { processedRows: 0, chunksExecuted: 1, returning: [] };
|
|
21917
|
+
};
|
|
21918
|
+
return maybeTransaction(session, transactional, execute);
|
|
21919
|
+
}
|
|
21920
|
+
|
|
21921
|
+
// src/bulk/bulk-upsert-executor.ts
|
|
21922
|
+
var DEFAULT_CHUNK_SIZE2 = 500;
|
|
21923
|
+
var BulkUpsertExecutor = class extends BulkBaseExecutor {
|
|
21924
|
+
conflictTargetNodes;
|
|
21925
|
+
updateColumns;
|
|
21926
|
+
constructor(session, table, rows, options = {}) {
|
|
21927
|
+
super(session, table, rows, { ...options, chunkSize: options.chunkSize ?? DEFAULT_CHUNK_SIZE2 });
|
|
21928
|
+
const pkName = findPrimaryKey(table);
|
|
21929
|
+
const conflictTargetNames = options.conflictColumns ?? [pkName];
|
|
21930
|
+
this.conflictTargetNodes = conflictTargetNames.map((name) => ({
|
|
21931
|
+
type: "Column",
|
|
21932
|
+
table: table.name,
|
|
21933
|
+
name
|
|
21934
|
+
}));
|
|
21935
|
+
const conflictSet = new Set(conflictTargetNames);
|
|
21936
|
+
this.updateColumns = options.updateColumns ?? Object.keys(rows[0] ?? {}).filter((col2) => !conflictSet.has(col2) && col2 in table.columns);
|
|
21937
|
+
}
|
|
21938
|
+
async executeChunk(chunk, chunkIndex) {
|
|
21939
|
+
const returningColumns = resolveReturningColumns(this.ctx, this.table, this.options.returning);
|
|
21940
|
+
const set = {};
|
|
21941
|
+
for (const col2 of this.updateColumns) {
|
|
21942
|
+
set[col2] = { type: "ExcludedColumn", name: col2 };
|
|
21943
|
+
}
|
|
21944
|
+
let builder;
|
|
21945
|
+
if (this.updateColumns.length === 0) {
|
|
21946
|
+
builder = new InsertQueryBuilder(this.table).values(chunk).onConflict(this.conflictTargetNodes).doNothing();
|
|
21947
|
+
} else {
|
|
21948
|
+
builder = new InsertQueryBuilder(this.table).values(chunk).onConflict(this.conflictTargetNodes).doUpdate(set);
|
|
21949
|
+
}
|
|
21950
|
+
const finalBuilder = builder;
|
|
21951
|
+
if (returningColumns?.length) {
|
|
21952
|
+
finalBuilder.returning(...returningColumns);
|
|
21953
|
+
}
|
|
21954
|
+
const compiled = finalBuilder.compile(this.ctx.dialect);
|
|
21955
|
+
const resultSets = await executeCompiled(this.ctx, compiled);
|
|
21956
|
+
return {
|
|
21957
|
+
processedRows: chunk.length,
|
|
21958
|
+
returning: returningColumns ? flattenQueryResults(resultSets) : [],
|
|
21959
|
+
elapsedMs: 0
|
|
21960
|
+
};
|
|
21961
|
+
}
|
|
21962
|
+
};
|
|
21963
|
+
async function bulkUpsert(session, table, rows, options = {}) {
|
|
21964
|
+
if (!rows.length) {
|
|
21965
|
+
return { processedRows: 0, chunksExecuted: 0, returning: [] };
|
|
21966
|
+
}
|
|
21967
|
+
const executor = new BulkUpsertExecutor(session, table, rows, options);
|
|
21968
|
+
return executor.execute();
|
|
21969
|
+
}
|
|
19872
21970
|
// Annotate the CommonJS export names for ESM import in node:
|
|
19873
21971
|
0 && (module.exports = {
|
|
19874
21972
|
Alphanumeric,
|
|
@@ -19878,6 +21976,10 @@ var TagIndex = class {
|
|
|
19878
21976
|
BigIntTypeStrategy,
|
|
19879
21977
|
BinaryTypeStrategy,
|
|
19880
21978
|
BooleanTypeStrategy,
|
|
21979
|
+
BulkDeleteExecutor,
|
|
21980
|
+
BulkInsertExecutor,
|
|
21981
|
+
BulkUpdateExecutor,
|
|
21982
|
+
BulkUpsertExecutor,
|
|
19881
21983
|
CEP,
|
|
19882
21984
|
CNPJ,
|
|
19883
21985
|
CPF,
|
|
@@ -19893,6 +21995,9 @@ var TagIndex = class {
|
|
|
19893
21995
|
DefaultEntityMaterializer,
|
|
19894
21996
|
DefaultHasManyCollection,
|
|
19895
21997
|
DefaultManyToManyCollection,
|
|
21998
|
+
DefaultMorphManyCollection,
|
|
21999
|
+
DefaultMorphOneReference,
|
|
22000
|
+
DefaultMorphToReference,
|
|
19896
22001
|
DefaultTypeStrategy,
|
|
19897
22002
|
DeleteQueryBuilder,
|
|
19898
22003
|
DomainEventBus,
|
|
@@ -19908,6 +22013,9 @@ var TagIndex = class {
|
|
|
19908
22013
|
Length,
|
|
19909
22014
|
Lower,
|
|
19910
22015
|
MemoryCacheAdapter,
|
|
22016
|
+
MorphMany,
|
|
22017
|
+
MorphOne,
|
|
22018
|
+
MorphTo,
|
|
19911
22019
|
MySqlDialect,
|
|
19912
22020
|
NestedSetStrategy,
|
|
19913
22021
|
Orm,
|
|
@@ -19966,6 +22074,12 @@ var TagIndex = class {
|
|
|
19966
22074
|
bootstrapEntities,
|
|
19967
22075
|
buildFilterExpression,
|
|
19968
22076
|
buildScopeConditions,
|
|
22077
|
+
bulkDelete,
|
|
22078
|
+
bulkDeleteWhere,
|
|
22079
|
+
bulkInsert,
|
|
22080
|
+
bulkUpdate,
|
|
22081
|
+
bulkUpdateWhere,
|
|
22082
|
+
bulkUpsert,
|
|
19969
22083
|
calculateRowDepths,
|
|
19970
22084
|
calculateTotalPages,
|
|
19971
22085
|
callProcedure,
|
|
@@ -19998,6 +22112,7 @@ var TagIndex = class {
|
|
|
19998
22112
|
count,
|
|
19999
22113
|
countAll,
|
|
20000
22114
|
createApiComponentsSection,
|
|
22115
|
+
createBetterSqlite3Executor,
|
|
20001
22116
|
createDeterministicNamingState,
|
|
20002
22117
|
createDtoToOpenApiSchema,
|
|
20003
22118
|
createEntityFromRow,
|
|
@@ -20099,12 +22214,16 @@ var TagIndex = class {
|
|
|
20099
22214
|
isCastExpressionNode,
|
|
20100
22215
|
isCollateExpressionNode,
|
|
20101
22216
|
isComponentReference,
|
|
22217
|
+
isDistinctFrom,
|
|
20102
22218
|
isExpressionSelectionNode,
|
|
20103
22219
|
isFunctionNode,
|
|
22220
|
+
isMorphRelation,
|
|
22221
|
+
isNotDistinctFrom,
|
|
20104
22222
|
isNotNull,
|
|
20105
22223
|
isNull,
|
|
20106
22224
|
isNullableColumn,
|
|
20107
22225
|
isOperandNode,
|
|
22226
|
+
isSingleTargetRelation,
|
|
20108
22227
|
isTableDef,
|
|
20109
22228
|
isTreeConfig,
|
|
20110
22229
|
isValidDuration,
|
|
@@ -20128,6 +22247,9 @@ var TagIndex = class {
|
|
|
20128
22247
|
loadBelongsToRelation,
|
|
20129
22248
|
loadHasManyRelation,
|
|
20130
22249
|
loadHasOneRelation,
|
|
22250
|
+
loadMorphManyRelation,
|
|
22251
|
+
loadMorphOneRelation,
|
|
22252
|
+
loadMorphToRelation,
|
|
20131
22253
|
localTime,
|
|
20132
22254
|
localTimestamp,
|
|
20133
22255
|
locate,
|
|
@@ -20149,11 +22271,15 @@ var TagIndex = class {
|
|
|
20149
22271
|
minute,
|
|
20150
22272
|
mod,
|
|
20151
22273
|
month,
|
|
22274
|
+
morphMany,
|
|
22275
|
+
morphOne,
|
|
22276
|
+
morphTo,
|
|
20152
22277
|
mul,
|
|
20153
22278
|
neq,
|
|
20154
22279
|
nestedDtoToOpenApiSchema,
|
|
20155
22280
|
nestedWhereInputToOpenApiSchema,
|
|
20156
22281
|
normalizeColumnType,
|
|
22282
|
+
not,
|
|
20157
22283
|
notBetween,
|
|
20158
22284
|
notExists,
|
|
20159
22285
|
notInList,
|