@spinajs/orm 2.0.481 → 2.0.482
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 +72 -3
- package/lib/cjs/bootstrap.js +10 -0
- package/lib/cjs/bootstrap.js.map +1 -1
- package/lib/cjs/builders.d.ts +115 -11
- package/lib/cjs/builders.d.ts.map +1 -1
- package/lib/cjs/builders.js +342 -283
- package/lib/cjs/builders.js.map +1 -1
- package/lib/cjs/converters.d.ts +9 -2
- package/lib/cjs/converters.d.ts.map +1 -1
- package/lib/cjs/converters.js +48 -8
- package/lib/cjs/converters.js.map +1 -1
- package/lib/cjs/decorators.d.ts +26 -3
- package/lib/cjs/decorators.d.ts.map +1 -1
- package/lib/cjs/decorators.js +95 -42
- package/lib/cjs/decorators.js.map +1 -1
- package/lib/cjs/dehydrators.js +1 -1
- package/lib/cjs/dehydrators.js.map +1 -1
- package/lib/cjs/descriptor.d.ts +1 -0
- package/lib/cjs/descriptor.d.ts.map +1 -1
- package/lib/cjs/descriptor.js +16 -40
- package/lib/cjs/descriptor.js.map +1 -1
- package/lib/cjs/driver.d.ts +136 -7
- package/lib/cjs/driver.d.ts.map +1 -1
- package/lib/cjs/driver.js +279 -0
- package/lib/cjs/driver.js.map +1 -1
- package/lib/cjs/existsRelationHandlers.d.ts +29 -0
- package/lib/cjs/existsRelationHandlers.d.ts.map +1 -0
- package/lib/cjs/existsRelationHandlers.js +104 -0
- package/lib/cjs/existsRelationHandlers.js.map +1 -0
- package/lib/cjs/fp.d.ts.map +1 -1
- package/lib/cjs/fp.js +10 -15
- package/lib/cjs/fp.js.map +1 -1
- package/lib/cjs/hydrators.d.ts.map +1 -1
- package/lib/cjs/hydrators.js +29 -2
- package/lib/cjs/hydrators.js.map +1 -1
- package/lib/cjs/identity-map.d.ts +60 -0
- package/lib/cjs/identity-map.d.ts.map +1 -0
- package/lib/cjs/identity-map.js +135 -0
- package/lib/cjs/identity-map.js.map +1 -0
- package/lib/cjs/index.d.ts +12 -0
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +12 -0
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/interfaces.d.ts +295 -9
- package/lib/cjs/interfaces.d.ts.map +1 -1
- package/lib/cjs/interfaces.js +54 -1
- package/lib/cjs/interfaces.js.map +1 -1
- package/lib/cjs/metadata.d.ts.map +1 -1
- package/lib/cjs/metadata.js +4 -1
- package/lib/cjs/metadata.js.map +1 -1
- package/lib/cjs/metrics.d.ts +53 -0
- package/lib/cjs/metrics.d.ts.map +1 -0
- package/lib/cjs/metrics.js +82 -0
- package/lib/cjs/metrics.js.map +1 -0
- package/lib/cjs/middlewares.d.ts +13 -1
- package/lib/cjs/middlewares.d.ts.map +1 -1
- package/lib/cjs/middlewares.js +55 -15
- package/lib/cjs/middlewares.js.map +1 -1
- package/lib/cjs/model.d.ts +129 -13
- package/lib/cjs/model.d.ts.map +1 -1
- package/lib/cjs/model.js +449 -93
- package/lib/cjs/model.js.map +1 -1
- package/lib/cjs/orm.d.ts.map +1 -1
- package/lib/cjs/orm.js +12 -3
- package/lib/cjs/orm.js.map +1 -1
- package/lib/cjs/orphan.d.ts +27 -0
- package/lib/cjs/orphan.d.ts.map +1 -0
- package/lib/cjs/orphan.js +55 -0
- package/lib/cjs/orphan.js.map +1 -0
- package/lib/cjs/primary-keys.d.ts +60 -0
- package/lib/cjs/primary-keys.d.ts.map +1 -0
- package/lib/cjs/primary-keys.js +243 -0
- package/lib/cjs/primary-keys.js.map +1 -0
- package/lib/cjs/relation-objects.d.ts +101 -9
- package/lib/cjs/relation-objects.d.ts.map +1 -1
- package/lib/cjs/relation-objects.js +194 -43
- package/lib/cjs/relation-objects.js.map +1 -1
- package/lib/cjs/relations.d.ts +7 -1
- package/lib/cjs/relations.d.ts.map +1 -1
- package/lib/cjs/relations.js +16 -1
- package/lib/cjs/relations.js.map +1 -1
- package/lib/cjs/resilience.d.ts +50 -0
- package/lib/cjs/resilience.d.ts.map +1 -0
- package/lib/cjs/resilience.js +70 -0
- package/lib/cjs/resilience.js.map +1 -0
- package/lib/cjs/snapshot.d.ts +58 -0
- package/lib/cjs/snapshot.d.ts.map +1 -0
- package/lib/cjs/snapshot.js +125 -0
- package/lib/cjs/snapshot.js.map +1 -0
- package/lib/cjs/statements.d.ts +11 -1
- package/lib/cjs/statements.d.ts.map +1 -1
- package/lib/cjs/statements.js +13 -2
- package/lib/cjs/statements.js.map +1 -1
- package/lib/cjs/subject-builder.d.ts +79 -0
- package/lib/cjs/subject-builder.d.ts.map +1 -0
- package/lib/cjs/subject-builder.js +296 -0
- package/lib/cjs/subject-builder.js.map +1 -0
- package/lib/cjs/subject-executor.d.ts +122 -0
- package/lib/cjs/subject-executor.d.ts.map +1 -0
- package/lib/cjs/subject-executor.js +319 -0
- package/lib/cjs/subject-executor.js.map +1 -0
- package/lib/cjs/subject-sorter.d.ts +70 -0
- package/lib/cjs/subject-sorter.d.ts.map +1 -0
- package/lib/cjs/subject-sorter.js +173 -0
- package/lib/cjs/subject-sorter.js.map +1 -0
- package/lib/cjs/subject.d.ts +100 -0
- package/lib/cjs/subject.d.ts.map +1 -0
- package/lib/cjs/subject.js +89 -0
- package/lib/cjs/subject.js.map +1 -0
- package/lib/cjs/unit-of-work.d.ts +52 -0
- package/lib/cjs/unit-of-work.d.ts.map +1 -0
- package/lib/cjs/unit-of-work.js +170 -0
- package/lib/cjs/unit-of-work.js.map +1 -0
- package/lib/mjs/bootstrap.js +10 -0
- package/lib/mjs/bootstrap.js.map +1 -1
- package/lib/mjs/builders.d.ts +115 -11
- package/lib/mjs/builders.d.ts.map +1 -1
- package/lib/mjs/builders.js +344 -285
- package/lib/mjs/builders.js.map +1 -1
- package/lib/mjs/converters.d.ts +9 -2
- package/lib/mjs/converters.d.ts.map +1 -1
- package/lib/mjs/converters.js +48 -8
- package/lib/mjs/converters.js.map +1 -1
- package/lib/mjs/decorators.d.ts +26 -3
- package/lib/mjs/decorators.d.ts.map +1 -1
- package/lib/mjs/decorators.js +96 -44
- package/lib/mjs/decorators.js.map +1 -1
- package/lib/mjs/dehydrators.js +1 -1
- package/lib/mjs/dehydrators.js.map +1 -1
- package/lib/mjs/descriptor.d.ts +1 -0
- package/lib/mjs/descriptor.d.ts.map +1 -1
- package/lib/mjs/descriptor.js +17 -39
- package/lib/mjs/descriptor.js.map +1 -1
- package/lib/mjs/driver.d.ts +136 -7
- package/lib/mjs/driver.d.ts.map +1 -1
- package/lib/mjs/driver.js +279 -0
- package/lib/mjs/driver.js.map +1 -1
- package/lib/mjs/existsRelationHandlers.d.ts +29 -0
- package/lib/mjs/existsRelationHandlers.d.ts.map +1 -0
- package/lib/mjs/existsRelationHandlers.js +100 -0
- package/lib/mjs/existsRelationHandlers.js.map +1 -0
- package/lib/mjs/fp.d.ts.map +1 -1
- package/lib/mjs/fp.js +10 -15
- package/lib/mjs/fp.js.map +1 -1
- package/lib/mjs/hydrators.d.ts.map +1 -1
- package/lib/mjs/hydrators.js +29 -2
- package/lib/mjs/hydrators.js.map +1 -1
- package/lib/mjs/identity-map.d.ts +60 -0
- package/lib/mjs/identity-map.d.ts.map +1 -0
- package/lib/mjs/identity-map.js +130 -0
- package/lib/mjs/identity-map.js.map +1 -0
- package/lib/mjs/index.d.ts +12 -0
- package/lib/mjs/index.d.ts.map +1 -1
- package/lib/mjs/index.js +12 -0
- package/lib/mjs/index.js.map +1 -1
- package/lib/mjs/interfaces.d.ts +295 -9
- package/lib/mjs/interfaces.d.ts.map +1 -1
- package/lib/mjs/interfaces.js +53 -0
- package/lib/mjs/interfaces.js.map +1 -1
- package/lib/mjs/metadata.d.ts.map +1 -1
- package/lib/mjs/metadata.js +4 -1
- package/lib/mjs/metadata.js.map +1 -1
- package/lib/mjs/metrics.d.ts +53 -0
- package/lib/mjs/metrics.d.ts.map +1 -0
- package/lib/mjs/metrics.js +76 -0
- package/lib/mjs/metrics.js.map +1 -0
- package/lib/mjs/middlewares.d.ts +13 -1
- package/lib/mjs/middlewares.d.ts.map +1 -1
- package/lib/mjs/middlewares.js +55 -15
- package/lib/mjs/middlewares.js.map +1 -1
- package/lib/mjs/model.d.ts +129 -13
- package/lib/mjs/model.d.ts.map +1 -1
- package/lib/mjs/model.js +451 -95
- package/lib/mjs/model.js.map +1 -1
- package/lib/mjs/orm.d.ts.map +1 -1
- package/lib/mjs/orm.js +12 -3
- package/lib/mjs/orm.js.map +1 -1
- package/lib/mjs/orphan.d.ts +27 -0
- package/lib/mjs/orphan.d.ts.map +1 -0
- package/lib/mjs/orphan.js +52 -0
- package/lib/mjs/orphan.js.map +1 -0
- package/lib/mjs/primary-keys.d.ts +60 -0
- package/lib/mjs/primary-keys.d.ts.map +1 -0
- package/lib/mjs/primary-keys.js +223 -0
- package/lib/mjs/primary-keys.js.map +1 -0
- package/lib/mjs/relation-objects.d.ts +101 -9
- package/lib/mjs/relation-objects.d.ts.map +1 -1
- package/lib/mjs/relation-objects.js +194 -43
- package/lib/mjs/relation-objects.js.map +1 -1
- package/lib/mjs/relations.d.ts +7 -1
- package/lib/mjs/relations.d.ts.map +1 -1
- package/lib/mjs/relations.js +16 -1
- package/lib/mjs/relations.js.map +1 -1
- package/lib/mjs/resilience.d.ts +50 -0
- package/lib/mjs/resilience.d.ts.map +1 -0
- package/lib/mjs/resilience.js +64 -0
- package/lib/mjs/resilience.js.map +1 -0
- package/lib/mjs/snapshot.d.ts +58 -0
- package/lib/mjs/snapshot.d.ts.map +1 -0
- package/lib/mjs/snapshot.js +115 -0
- package/lib/mjs/snapshot.js.map +1 -0
- package/lib/mjs/statements.d.ts +11 -1
- package/lib/mjs/statements.d.ts.map +1 -1
- package/lib/mjs/statements.js +14 -3
- package/lib/mjs/statements.js.map +1 -1
- package/lib/mjs/subject-builder.d.ts +79 -0
- package/lib/mjs/subject-builder.d.ts.map +1 -0
- package/lib/mjs/subject-builder.js +292 -0
- package/lib/mjs/subject-builder.js.map +1 -0
- package/lib/mjs/subject-executor.d.ts +122 -0
- package/lib/mjs/subject-executor.d.ts.map +1 -0
- package/lib/mjs/subject-executor.js +312 -0
- package/lib/mjs/subject-executor.js.map +1 -0
- package/lib/mjs/subject-sorter.d.ts +70 -0
- package/lib/mjs/subject-sorter.d.ts.map +1 -0
- package/lib/mjs/subject-sorter.js +168 -0
- package/lib/mjs/subject-sorter.js.map +1 -0
- package/lib/mjs/subject.d.ts +100 -0
- package/lib/mjs/subject.d.ts.map +1 -0
- package/lib/mjs/subject.js +84 -0
- package/lib/mjs/subject.js.map +1 -0
- package/lib/mjs/unit-of-work.d.ts +52 -0
- package/lib/mjs/unit-of-work.d.ts.map +1 -0
- package/lib/mjs/unit-of-work.js +166 -0
- package/lib/mjs/unit-of-work.js.map +1 -0
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +9 -7
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/* eslint-disable prettier/prettier */
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import { createQuery, DeleteQueryBuilder, InsertQueryBuilder, UpdateQueryBuilder } from './builders.js';
|
|
5
|
+
import { OrmException } from './exceptions.js';
|
|
6
|
+
import { OrphanPolicy, ServerResponseMapper } from './interfaces.js';
|
|
7
|
+
import { assertAssignedKeys, generateClientSideKeys, pkColumns, pkGeneration, pkValueOf, setPkValue, whereAnyPk, wherePk } from './primary-keys.js';
|
|
8
|
+
/** Rows per batched statement when the caller does not say. */
|
|
9
|
+
export const DEFAULT_SAVE_CHUNK = 100;
|
|
10
|
+
/**
|
|
11
|
+
* Runs a sorted plan.
|
|
12
|
+
*
|
|
13
|
+
* Every statement is built through `createQuery`, so table naming, schema qualification and
|
|
14
|
+
* identifier escaping are the same as on the ActiveRecord paths. No connection is threaded by
|
|
15
|
+
* hand: `OrmDriver.transaction()` carries it in `AsyncLocalStorage` and the builders resolved
|
|
16
|
+
* from that driver pick it up automatically.
|
|
17
|
+
*
|
|
18
|
+
* The executor does **not** open the transaction — `UnitOfWork` does — so that a caller can
|
|
19
|
+
* drive it directly in a test and so that nested saves inside one transaction fold into
|
|
20
|
+
* savepoints rather than each opening their own.
|
|
21
|
+
*/
|
|
22
|
+
export class SubjectExecutor {
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
async execute(plan) {
|
|
27
|
+
const result = {
|
|
28
|
+
Inserted: 0,
|
|
29
|
+
Updated: 0,
|
|
30
|
+
Deleted: 0,
|
|
31
|
+
SoftDeleted: 0,
|
|
32
|
+
JunctionInserted: 0,
|
|
33
|
+
JunctionDeleted: 0,
|
|
34
|
+
};
|
|
35
|
+
await this.runInserts(plan, result);
|
|
36
|
+
await this.runUpdates(plan, result);
|
|
37
|
+
await this.runJunctions(plan, result);
|
|
38
|
+
await this.runOrphans(plan, result);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Inserts every insert subject in the order the sorter produced, reading each generated key
|
|
43
|
+
* back before moving on so the next subject's foreign keys can be resolved.
|
|
44
|
+
*
|
|
45
|
+
* One statement per row, deliberately, and NOT subject to `options.chunk`: a batched
|
|
46
|
+
* multi-row INSERT can only return keys where the dialect supports RETURNING or where
|
|
47
|
+
* `insertIdIsFirstOfBatch` holds, and a subject's key is needed by the very next subject in
|
|
48
|
+
* the order. Batching here is a real feature — it has to carry the per-dialect key-backfill
|
|
49
|
+
* rules with it — not something to fold into the chunking used for junction and orphan rows.
|
|
50
|
+
*/
|
|
51
|
+
async runInserts(plan, result) {
|
|
52
|
+
for (const subject of plan.Inserts) {
|
|
53
|
+
await this.insertOne(subject);
|
|
54
|
+
result.Inserted += 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* One INSERT, with the key read back.
|
|
59
|
+
*
|
|
60
|
+
* Mirrors `ModelBase.insert()`'s key handling rather than inventing a second one: client-side
|
|
61
|
+
* keys are generated first, `assigned` keys are asserted before anything touches the database,
|
|
62
|
+
* and RETURNING is requested when an `auto` key needs to come back and the dialect supports it.
|
|
63
|
+
*/
|
|
64
|
+
async insertOne(subject) {
|
|
65
|
+
const descriptor = subject.Descriptor;
|
|
66
|
+
const model = subject.Model;
|
|
67
|
+
// Both run BEFORE the query is built, so an `assigned` key that was never supplied fails
|
|
68
|
+
// without touching the database.
|
|
69
|
+
generateClientSideKeys(model, descriptor);
|
|
70
|
+
assertAssignedKeys(model, descriptor);
|
|
71
|
+
const { query, container } = createQuery(model.constructor, InsertQueryBuilder);
|
|
72
|
+
const mapper = container.resolve(ServerResponseMapper);
|
|
73
|
+
const needsKeyBack = pkColumns(descriptor).some((c) => pkGeneration(descriptor, c) === 'auto');
|
|
74
|
+
if (needsKeyBack && query.Driver.supportedFeatures().insertReturning) {
|
|
75
|
+
query.returning(pkColumns(descriptor));
|
|
76
|
+
}
|
|
77
|
+
const response = mapper.read((await query.values(this.insertPayload(subject))), pkColumns(descriptor));
|
|
78
|
+
this.backfillKey(subject, response.Returning, response.LastInsertId, needsKeyBack);
|
|
79
|
+
model.IsDirty = false;
|
|
80
|
+
subject.Model.takeSnapshot();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Runs every update, including the follow-up updates that carry deferred self-referencing
|
|
84
|
+
* foreign keys.
|
|
85
|
+
*
|
|
86
|
+
* A subject whose payload comes out empty emits nothing. This is the single place that
|
|
87
|
+
* decides whether a row actually changed: pending foreign keys are written onto the model
|
|
88
|
+
* first and `changedColumns()` is read afterwards, so a re-parented child that was clean
|
|
89
|
+
* when the subjects were built is caught here and nowhere else.
|
|
90
|
+
*/
|
|
91
|
+
async runUpdates(plan, result) {
|
|
92
|
+
for (const subject of plan.Updates) {
|
|
93
|
+
const payload = this.updatePayload(subject);
|
|
94
|
+
if (payload === null) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const { query } = createQuery(subject.Model.constructor, UpdateQueryBuilder);
|
|
98
|
+
const update = query.update(payload);
|
|
99
|
+
wherePk(update, subject.Descriptor, subject.Model.PrimaryKeyValue);
|
|
100
|
+
await update;
|
|
101
|
+
subject.Model.IsDirty = false;
|
|
102
|
+
subject.Model.takeSnapshot();
|
|
103
|
+
result.Updated += 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The column payload for one UPDATE, or `null` when there is nothing to write.
|
|
108
|
+
*
|
|
109
|
+
* The primary key columns are excluded: writing them is a no-op at best and, for a model
|
|
110
|
+
* whose key column differs from its snapshot for any other reason, a silent identity change.
|
|
111
|
+
*
|
|
112
|
+
* @param subject - an update subject, or an insert subject with deferred foreign keys
|
|
113
|
+
*/
|
|
114
|
+
updatePayload(subject) {
|
|
115
|
+
// Resolve every foreign key onto the model first, so the diff below sees them.
|
|
116
|
+
for (const fk of subject.PendingForeignKeys.concat(subject.DeferredForeignKeys)) {
|
|
117
|
+
subject.Model[fk.Column] = fk.Target.PrimaryKeyValue;
|
|
118
|
+
}
|
|
119
|
+
const keyColumns = pkColumns(subject.Descriptor);
|
|
120
|
+
const changed = subject.Model.changedColumns().filter((c) => !keyColumns.includes(c));
|
|
121
|
+
if (changed.length === 0) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const updatedAt = subject.Descriptor.Timestamps?.UpdatedAt;
|
|
125
|
+
if (updatedAt) {
|
|
126
|
+
subject.Model[updatedAt] = DateTime.now();
|
|
127
|
+
if (!changed.includes(updatedAt)) {
|
|
128
|
+
changed.push(updatedAt);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
subject.ChangedColumns = changed;
|
|
132
|
+
return _.pick(subject.Model.toSql(), changed);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The column payload for one INSERT.
|
|
136
|
+
*
|
|
137
|
+
* Starts from the model's own serialization, drops every column whose foreign key is
|
|
138
|
+
* deferred to a follow-up UPDATE, then writes every pending foreign key from its target's
|
|
139
|
+
* now-known primary key. The overwrite matters: `StandardModelToSqlConverter` already wrote
|
|
140
|
+
* that column from the relation object, and for a target inserted moments ago that value was
|
|
141
|
+
* `undefined` when the model was serialized.
|
|
142
|
+
*/
|
|
143
|
+
insertPayload(subject) {
|
|
144
|
+
const payload = subject.Model.toSql();
|
|
145
|
+
for (const fk of subject.DeferredForeignKeys) {
|
|
146
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
147
|
+
delete payload[fk.Column];
|
|
148
|
+
}
|
|
149
|
+
for (const fk of subject.PendingForeignKeys) {
|
|
150
|
+
const value = fk.Target.PrimaryKeyValue;
|
|
151
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
152
|
+
payload[fk.Column] = value;
|
|
153
|
+
subject.Model[fk.Column] = value;
|
|
154
|
+
}
|
|
155
|
+
return payload;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Writes a generated key onto the model.
|
|
159
|
+
*
|
|
160
|
+
* Uses `setPkValue` — the primary-keys helper that assigns the key columns and nothing else —
|
|
161
|
+
* rather than the `PrimaryKeyValue` setter, whose `RelationType.One` branch also writes the
|
|
162
|
+
* new key onto the owner's `SingleRelation` wrapper, which persists nothing. The executor
|
|
163
|
+
* resolves foreign keys itself and does not want that side effect.
|
|
164
|
+
*
|
|
165
|
+
* A key the caller already supplied ( uuid / assigned strategies ) is never overwritten.
|
|
166
|
+
*/
|
|
167
|
+
backfillKey(subject, returning, lastInsertId, needsKeyBack) {
|
|
168
|
+
const descriptor = subject.Descriptor;
|
|
169
|
+
if (pkColumns(descriptor).length === 0) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if ((returning ?? []).length !== 0) {
|
|
173
|
+
setPkValue(subject.Model, descriptor, pkValueOf(returning[0], descriptor));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (!needsKeyBack) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// A composite key is a tuple, and a tuple is ALWAYS truthy — check every part.
|
|
180
|
+
const current = subject.Model.PrimaryKeyValue;
|
|
181
|
+
const missing = Array.isArray(current) ? current.some((v) => v === null || v === undefined) : current === null || current === undefined;
|
|
182
|
+
if (!missing) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (lastInsertId === null || lastInsertId === undefined) {
|
|
186
|
+
throw new OrmException(`insert of ${subject.Identity} returned no generated key and the model set none itself`);
|
|
187
|
+
}
|
|
188
|
+
setPkValue(subject.Model, descriptor, lastInsertId);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Creates and destroys junction rows.
|
|
192
|
+
*
|
|
193
|
+
* Rows are written column-first rather than through the junction model, so a junction model
|
|
194
|
+
* is not required to declare `@BelongsTo` on both sides — `ManyToManyRelationList.update()`
|
|
195
|
+
* does require that, and none of the existing junction fixtures satisfy it.
|
|
196
|
+
*
|
|
197
|
+
* Inserts run before deletes so that re-linking the same pair inside one save cannot
|
|
198
|
+
* momentarily violate a unique constraint on the junction table in the other order.
|
|
199
|
+
*/
|
|
200
|
+
async runJunctions(plan, result) {
|
|
201
|
+
for (const delta of plan.Junctions) {
|
|
202
|
+
await this.insertJunctionRows(delta, result);
|
|
203
|
+
await this.deleteJunctionRows(delta, result);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async insertJunctionRows(delta, result) {
|
|
207
|
+
if (delta.Added.length === 0) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const sourceColumn = delta.Descriptor.JunctionModelSourceModelFKey_Name;
|
|
211
|
+
const targetColumn = delta.Descriptor.JunctionModelTargetModelFKey_Name;
|
|
212
|
+
if (!sourceColumn || !targetColumn) {
|
|
213
|
+
throw new OrmException(`manyToMany relation ${delta.Descriptor.Name} has no junction foreign-key column names`);
|
|
214
|
+
}
|
|
215
|
+
const ownerKey = delta.Owner.PrimaryKeyValue;
|
|
216
|
+
for (const batch of this.chunked(delta.Added)) {
|
|
217
|
+
const values = batch.map((target) => ({
|
|
218
|
+
[sourceColumn]: ownerKey,
|
|
219
|
+
[targetColumn]: target.PrimaryKeyValue,
|
|
220
|
+
}));
|
|
221
|
+
const { query } = createQuery(delta.Descriptor.JunctionModel, InsertQueryBuilder);
|
|
222
|
+
await query.values(values);
|
|
223
|
+
result.JunctionInserted += values.length;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async deleteJunctionRows(delta, result) {
|
|
227
|
+
if (delta.RemovedKeys.length === 0) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const sourceColumn = delta.Descriptor.JunctionModelSourceModelFKey_Name;
|
|
231
|
+
const targetColumn = delta.Descriptor.JunctionModelTargetModelFKey_Name;
|
|
232
|
+
const ownerKey = delta.Owner.PrimaryKeyValue;
|
|
233
|
+
for (const batch of this.chunked(delta.RemovedKeys)) {
|
|
234
|
+
const { query } = createQuery(delta.Descriptor.JunctionModel, DeleteQueryBuilder);
|
|
235
|
+
await query.where(sourceColumn, ownerKey).whereIn(targetColumn, batch);
|
|
236
|
+
result.JunctionDeleted += batch.length;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Applies the orphan policy to every detached row.
|
|
241
|
+
*
|
|
242
|
+
* `nullify` and `soft-delete` run first as UPDATEs, then `delete` runs as DELETEs, and the
|
|
243
|
+
* deltas arrive from the sorter already ordered children-before-parents so a delete cannot
|
|
244
|
+
* strand a foreign key.
|
|
245
|
+
*
|
|
246
|
+
* `createQuery` only adds the default `DeletedAt IS NULL` filter to a SelectQueryBuilder, so
|
|
247
|
+
* these builders are unfiltered — which is what stamping an already-soft-deleted row needs.
|
|
248
|
+
*/
|
|
249
|
+
async runOrphans(plan, result) {
|
|
250
|
+
const updates = plan.Orphans.filter((o) => this.effectivePolicy(o) !== OrphanPolicy.Delete);
|
|
251
|
+
const deletes = plan.Orphans.filter((o) => this.effectivePolicy(o) === OrphanPolicy.Delete);
|
|
252
|
+
for (const delta of updates) {
|
|
253
|
+
await this.updateOrphans(delta, result);
|
|
254
|
+
}
|
|
255
|
+
for (const delta of deletes) {
|
|
256
|
+
await this.deleteOrphans(delta, result);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The policy actually applied to `delta`.
|
|
261
|
+
*
|
|
262
|
+
* `delete` on a model that declares `@SoftDelete` degrades to `soft-delete`, so orphaning a
|
|
263
|
+
* row and calling `destroy()` on it mean the same thing. `ModelBase.destroy()` has always
|
|
264
|
+
* stamped `DeletedAt` rather than issuing a DELETE for such a model; an orphan taking the
|
|
265
|
+
* other branch made "delete this row" depend on which code path reached it, and hard-erased
|
|
266
|
+
* rows the model had declared should never be hard-erased.
|
|
267
|
+
*/
|
|
268
|
+
effectivePolicy(delta) {
|
|
269
|
+
if (delta.Policy === OrphanPolicy.Delete && delta.TargetDescriptor.SoftDelete?.DeletedAt) {
|
|
270
|
+
return OrphanPolicy.SoftDelete;
|
|
271
|
+
}
|
|
272
|
+
return delta.Policy;
|
|
273
|
+
}
|
|
274
|
+
async updateOrphans(delta, result) {
|
|
275
|
+
const policy = this.effectivePolicy(delta);
|
|
276
|
+
const payload = policy === OrphanPolicy.Nullify ? { [delta.Descriptor.ForeignKey]: null } : { [delta.TargetDescriptor.SoftDelete.DeletedAt]: DateTime.now() };
|
|
277
|
+
for (const batch of this.chunked(delta.PrimaryKeys)) {
|
|
278
|
+
const { query } = createQuery(delta.Descriptor.TargetModel, UpdateQueryBuilder);
|
|
279
|
+
const update = query.update(payload);
|
|
280
|
+
whereAnyPk(update, delta.TargetDescriptor, batch);
|
|
281
|
+
await update;
|
|
282
|
+
if (policy === OrphanPolicy.Nullify) {
|
|
283
|
+
result.Updated += batch.length;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
result.SoftDeleted += batch.length;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async deleteOrphans(delta, result) {
|
|
291
|
+
for (const batch of this.chunked(delta.PrimaryKeys)) {
|
|
292
|
+
const { query } = createQuery(delta.Descriptor.TargetModel, DeleteQueryBuilder);
|
|
293
|
+
whereAnyPk(query, delta.TargetDescriptor, batch);
|
|
294
|
+
await query;
|
|
295
|
+
result.Deleted += batch.length;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/** Rows per batched statement. */
|
|
299
|
+
get chunkSize() {
|
|
300
|
+
const chunk = this.options.chunk ?? DEFAULT_SAVE_CHUNK;
|
|
301
|
+
return chunk > 0 ? chunk : DEFAULT_SAVE_CHUNK;
|
|
302
|
+
}
|
|
303
|
+
/** Splits `items` into runs of at most `chunkSize`. */
|
|
304
|
+
chunked(items) {
|
|
305
|
+
const out = [];
|
|
306
|
+
for (let i = 0; i < items.length; i += this.chunkSize) {
|
|
307
|
+
out.push(items.slice(i, i + this.chunkSize));
|
|
308
|
+
}
|
|
309
|
+
return out;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=subject-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject-executor.js","sourceRoot":"","sources":["../../src/subject-executor.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,CAAC,MAAM,QAAQ,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxG,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAA4C,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC/G,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAIpJ,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,eAAe;IAC1B,YAAsB,OAAqB;QAArB,YAAO,GAAP,OAAO,CAAc;IAAG,CAAC;IAExC,KAAK,CAAC,OAAO,CAAC,IAAiB;QACpC,MAAM,MAAM,GAAgB;YAC1B,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,CAAC;YACd,gBAAgB,EAAE,CAAC;YACnB,eAAe,EAAE,CAAC;SACnB,CAAC;QAEF,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACpC,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACpC,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAEpC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;OASG;IACO,KAAK,CAAC,UAAU,CAAC,IAAiB,EAAE,MAAmB;QAC/D,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAC9B,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACO,KAAK,CAAC,SAAS,CAAC,OAAgB;QACxC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACtC,MAAM,KAAK,GAAQ,OAAO,CAAC,KAAK,CAAC;QAEjC,yFAAyF;QACzF,iCAAiC;QACjC,sBAAsB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAC1C,kBAAkB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAEtC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAEvD,MAAM,YAAY,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;QAC/F,IAAI,YAAY,IAAI,KAAK,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,eAAe,EAAE,CAAC;YACrE,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAkB,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;QAExH,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAEnF,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;IAC/B,CAAC;IAED;;;;;;;;OAQG;IACO,KAAK,CAAC,UAAU,CAAC,IAAiB,EAAE,MAAmB;QAC/D,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC5C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,SAAS;YACX,CAAC;YAED,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;YAC7E,MAAM,MAAM,GAAI,KAAqC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACtE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YACnE,MAAM,MAAM,CAAC;YAEb,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YAE7B,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACO,aAAa,CAAC,OAAgB;QACtC,+EAA+E;QAC/E,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC/E,OAAO,CAAC,KAAa,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC;QAChE,CAAC;QAED,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACtF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC;QAC3D,IAAI,SAAS,EAAE,CAAC;YACb,OAAO,CAAC,KAAa,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC;YACnD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,CAAC,cAAc,GAAG,OAAO,CAAC;QAEjC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAA6B,EAAE,OAAO,CAAC,CAAC;IAC3E,CAAC;IAED;;;;;;;;OAQG;IACO,aAAa,CAAC,OAAgB;QACtC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAA6B,CAAC;QAEjE,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;YAC7C,4DAA4D;YAC5D,OAAO,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAED,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC;YACxC,4DAA4D;YAC5D,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;YAC1B,OAAO,CAAC,KAAa,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;QAC5C,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;;;OASG;IACO,WAAW,CAAC,OAAgB,EAAE,SAAgB,EAAE,YAAoB,EAAE,YAAqB;QACnG,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAEtC,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QAED,+EAA+E;QAC/E,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;QAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,CAAC;QAExI,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,YAAY,KAAK,IAAI,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YACxD,MAAM,IAAI,YAAY,CAAC,aAAa,OAAO,CAAC,QAAQ,0DAA0D,CAAC,CAAC;QAClH,CAAC;QAED,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IACtD,CAAC;IAED;;;;;;;;;OASG;IACO,KAAK,CAAC,YAAY,CAAC,IAAiB,EAAE,MAAmB;QACjE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC7C,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAES,KAAK,CAAC,kBAAkB,CAAC,KAAqB,EAAE,MAAmB;QAC3E,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,iCAAiC,CAAC;QACxE,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,iCAAiC,CAAC;QAExE,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,MAAM,IAAI,YAAY,CAAC,uBAAuB,KAAK,CAAC,UAAU,CAAC,IAAI,2CAA2C,CAAC,CAAC;QAClH,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC;QAE7C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBACpC,CAAC,YAAY,CAAC,EAAE,QAAQ;gBACxB,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,eAAe;aACvC,CAAC,CAAC,CAAC;YAEJ,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,aAAc,EAAE,kBAAkB,CAAC,CAAC;YACnF,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAE3B,MAAM,CAAC,gBAAgB,IAAI,MAAM,CAAC,MAAM,CAAC;QAC3C,CAAC;IACH,CAAC;IAES,KAAK,CAAC,kBAAkB,CAAC,KAAqB,EAAE,MAAmB;QAC3E,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,iCAAkC,CAAC;QACzE,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,iCAAkC,CAAC;QACzE,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC;QAE7C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,aAAc,EAAE,kBAAkB,CAAC,CAAC;YACnF,MAAO,KAAqC,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YAExG,MAAM,CAAC,eAAe,IAAI,KAAK,CAAC,MAAM,CAAC;QACzC,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACO,KAAK,CAAC,UAAU,CAAC,IAAiB,EAAE,MAAmB;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC;QAC5F,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC;QAE5F,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACO,eAAe,CAAC,KAAmB;QAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;YACzF,OAAO,YAAY,CAAC,UAAU,CAAC;QACjC,CAAC;QAED,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IAES,KAAK,CAAC,aAAa,CAAC,KAAmB,EAAE,MAAmB;QACpE,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAW,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;QAE/J,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;YAChF,MAAM,MAAM,GAAI,KAAqC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACtE,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YAClD,MAAM,MAAM,CAAC;YAEb,IAAI,MAAM,KAAK,YAAY,CAAC,OAAO,EAAE,CAAC;gBACpC,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAES,KAAK,CAAC,aAAa,CAAC,KAAmB,EAAE,MAAmB;QACpE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;YAChF,UAAU,CAAC,KAAoC,EAAE,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YAChF,MAAM,KAAK,CAAC;YAEZ,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC;QACjC,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,IAAc,SAAS;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAAC;QACvD,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAChD,CAAC;IAED,uDAAuD;IAC7C,OAAO,CAAI,KAAU;QAC7B,MAAM,GAAG,GAAU,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OrmException } from './exceptions.js';
|
|
2
|
+
import type { ModelBase } from './model.js';
|
|
3
|
+
import { IJunctionDelta, IOrphanDelta, Subject, SubjectSet } from './subject.js';
|
|
4
|
+
/**
|
|
5
|
+
* Raised when the insert order cannot be satisfied because two or more rows reference each
|
|
6
|
+
* other through non-deferrable foreign keys.
|
|
7
|
+
*/
|
|
8
|
+
export declare class OrmCycleException extends OrmException {
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A `SubjectSet` in execution order.
|
|
12
|
+
*/
|
|
13
|
+
export interface ISortedPlan {
|
|
14
|
+
/** Insert subjects, every parent before every child that references it. */
|
|
15
|
+
Inserts: Subject[];
|
|
16
|
+
/** Update subjects, followed by insert subjects carrying deferred foreign keys. */
|
|
17
|
+
Updates: Subject[];
|
|
18
|
+
Junctions: IJunctionDelta[];
|
|
19
|
+
/** Orphan actions, children before parents. */
|
|
20
|
+
Orphans: IOrphanDelta[];
|
|
21
|
+
}
|
|
22
|
+
export declare class SubjectSorter {
|
|
23
|
+
/**
|
|
24
|
+
* Orders a subject set for execution.
|
|
25
|
+
*
|
|
26
|
+
* @param set - output of `SubjectBuilder.build()`
|
|
27
|
+
* @throws OrmCycleException when a non-self-referencing foreign-key cycle makes the order
|
|
28
|
+
* unsatisfiable
|
|
29
|
+
*/
|
|
30
|
+
sort(set: SubjectSet): ISortedPlan;
|
|
31
|
+
/**
|
|
32
|
+
* Kahn's algorithm over the insert subjects, in O(V + E).
|
|
33
|
+
*
|
|
34
|
+
* Each subject carries a count of how many not-yet-emitted subjects it must follow, plus the
|
|
35
|
+
* list of subjects waiting on IT. Emitting a subject decrements its dependents' counters and
|
|
36
|
+
* moves any that reach zero onto the ready queue, so no pass ever rescans the whole graph.
|
|
37
|
+
* The previous shape rebuilt the entire dependency map and re-filtered every insert on every
|
|
38
|
+
* pass — O(V² · E) on a deep chain, which is exactly the shape `deferSelfReferences` exists
|
|
39
|
+
* to serve ( a self-referencing tree inserted parent-by-parent ).
|
|
40
|
+
*
|
|
41
|
+
* Stable: the queue is seeded and refilled in the subjects' own order, so a dependency-free
|
|
42
|
+
* graph comes out exactly as it went in.
|
|
43
|
+
*/
|
|
44
|
+
protected order(inserts: Subject[]): Subject[];
|
|
45
|
+
/**
|
|
46
|
+
* In-degree per remaining subject, and the reverse edges needed to decrement them.
|
|
47
|
+
*
|
|
48
|
+
* `pending` counts DISTINCT targets: two foreign keys on one subject pointing at the same
|
|
49
|
+
* target are one dependency, and counting them twice would leave a counter that never
|
|
50
|
+
* reaches zero and a spurious cycle report.
|
|
51
|
+
*/
|
|
52
|
+
protected buildDegrees(inserts: Subject[], byModel: Map<ModelBase, Subject>, remaining: Set<Subject>): {
|
|
53
|
+
pending: Map<Subject, number>;
|
|
54
|
+
dependents: Map<Subject, Subject[]>;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Breaks a cycle by deferring the foreign keys that point at the *same model* — a
|
|
58
|
+
* self-referencing hierarchy, which is a cycle between models but not between rows.
|
|
59
|
+
* The row is inserted without the column and a follow-up UPDATE sets it.
|
|
60
|
+
*
|
|
61
|
+
* @returns true when at least one foreign key was deferred, i.e. progress is possible
|
|
62
|
+
*/
|
|
63
|
+
protected deferSelfReferences(remaining: Set<Subject>, byModel: Map<ModelBase, Subject>): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Children before parents, so a DELETE never strands a foreign key. A model that does not
|
|
66
|
+
* appear in the insert order at all keeps its relative position at the front.
|
|
67
|
+
*/
|
|
68
|
+
protected orderOrphans(orphans: IOrphanDelta[], inserts: Subject[]): IOrphanDelta[];
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=subject-sorter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject-sorter.d.ts","sourceRoot":"","sources":["../../src/subject-sorter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAsB,OAAO,EAAoB,UAAU,EAAE,MAAM,cAAc,CAAC;AAEvH;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;CAAG;AAEtD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,mFAAmF;IACnF,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,+CAA+C;IAC/C,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,qBAAa,aAAa;IACxB;;;;;;OAMG;IACI,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,WAAW;IAuBzC;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE;IAqD9C;;;;;;OAMG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC;;;;IAqCpG;;;;;;OAMG;IACH,SAAS,CAAC,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,OAAO;IA0BjG;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,EAAE;CAUpF"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/* eslint-disable prettier/prettier */
|
|
2
|
+
import { OrmException } from './exceptions.js';
|
|
3
|
+
import { SubjectOperation } from './subject.js';
|
|
4
|
+
/**
|
|
5
|
+
* Raised when the insert order cannot be satisfied because two or more rows reference each
|
|
6
|
+
* other through non-deferrable foreign keys.
|
|
7
|
+
*/
|
|
8
|
+
export class OrmCycleException extends OrmException {
|
|
9
|
+
}
|
|
10
|
+
export class SubjectSorter {
|
|
11
|
+
/**
|
|
12
|
+
* Orders a subject set for execution.
|
|
13
|
+
*
|
|
14
|
+
* @param set - output of `SubjectBuilder.build()`
|
|
15
|
+
* @throws OrmCycleException when a non-self-referencing foreign-key cycle makes the order
|
|
16
|
+
* unsatisfiable
|
|
17
|
+
*/
|
|
18
|
+
sort(set) {
|
|
19
|
+
const inserts = set.Subjects.filter((s) => s.Operation === SubjectOperation.Insert);
|
|
20
|
+
const ordered = this.order(inserts);
|
|
21
|
+
const deferred = ordered.filter((s) => s.DeferredForeignKeys.length > 0);
|
|
22
|
+
// `None` subjects that carry a pending foreign key are candidates for promotion: a clean
|
|
23
|
+
// child re-parented to another owner in this graph classifies as `None` ( its columns match
|
|
24
|
+
// its snapshot ) and only becomes an UPDATE once the executor writes the new owner key onto
|
|
25
|
+
// it and re-reads the diff. Excluding them here would lose the move entirely.
|
|
26
|
+
//
|
|
27
|
+
// Including them is safe and cheap: `SubjectExecutor.updatePayload` returns null — and the
|
|
28
|
+
// executor emits nothing — for any subject whose diff is still empty afterwards.
|
|
29
|
+
const updates = set.Subjects.filter((s) => s.Operation === SubjectOperation.Update || (s.Operation === SubjectOperation.None && s.PendingForeignKeys.length > 0)).concat(deferred);
|
|
30
|
+
return {
|
|
31
|
+
Inserts: ordered,
|
|
32
|
+
Updates: updates,
|
|
33
|
+
Junctions: set.Junctions,
|
|
34
|
+
Orphans: this.orderOrphans(set.Orphans, ordered),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Kahn's algorithm over the insert subjects, in O(V + E).
|
|
39
|
+
*
|
|
40
|
+
* Each subject carries a count of how many not-yet-emitted subjects it must follow, plus the
|
|
41
|
+
* list of subjects waiting on IT. Emitting a subject decrements its dependents' counters and
|
|
42
|
+
* moves any that reach zero onto the ready queue, so no pass ever rescans the whole graph.
|
|
43
|
+
* The previous shape rebuilt the entire dependency map and re-filtered every insert on every
|
|
44
|
+
* pass — O(V² · E) on a deep chain, which is exactly the shape `deferSelfReferences` exists
|
|
45
|
+
* to serve ( a self-referencing tree inserted parent-by-parent ).
|
|
46
|
+
*
|
|
47
|
+
* Stable: the queue is seeded and refilled in the subjects' own order, so a dependency-free
|
|
48
|
+
* graph comes out exactly as it went in.
|
|
49
|
+
*/
|
|
50
|
+
order(inserts) {
|
|
51
|
+
const byModel = new Map();
|
|
52
|
+
for (const s of inserts) {
|
|
53
|
+
byModel.set(s.Model, s);
|
|
54
|
+
}
|
|
55
|
+
const remaining = new Set(inserts);
|
|
56
|
+
const output = [];
|
|
57
|
+
let { pending, dependents } = this.buildDegrees(inserts, byModel, remaining);
|
|
58
|
+
let ready = inserts.filter((s) => pending.get(s) === 0);
|
|
59
|
+
while (output.length < inserts.length) {
|
|
60
|
+
if (ready.length === 0) {
|
|
61
|
+
// Nothing can proceed. Either a genuine cycle, or a self-referencing one that can be
|
|
62
|
+
// broken by deferring the offending column to a follow-up UPDATE. Deferring mutates
|
|
63
|
+
// PendingForeignKeys, so the degrees are recomputed once — at most once per cycle
|
|
64
|
+
// broken, not once per emitted subject.
|
|
65
|
+
if (!this.deferSelfReferences(remaining, byModel)) {
|
|
66
|
+
const names = [...remaining].map((s) => s.Descriptor.Name);
|
|
67
|
+
throw new OrmCycleException(`cannot order INSERTs: foreign-key cycle between models ${[...new Set(names)].join(' -> ')}. Break the cycle by saving one side first, or make one of the foreign keys deferrable by pointing it at the same model.`);
|
|
68
|
+
}
|
|
69
|
+
({ pending, dependents } = this.buildDegrees(inserts, byModel, remaining));
|
|
70
|
+
ready = inserts.filter((s) => remaining.has(s) && pending.get(s) === 0);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const next = ready;
|
|
74
|
+
ready = [];
|
|
75
|
+
for (const s of next) {
|
|
76
|
+
output.push(s);
|
|
77
|
+
remaining.delete(s);
|
|
78
|
+
for (const dependent of dependents.get(s) ?? []) {
|
|
79
|
+
if (!remaining.has(dependent)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const left = pending.get(dependent) - 1;
|
|
83
|
+
pending.set(dependent, left);
|
|
84
|
+
if (left === 0) {
|
|
85
|
+
ready.push(dependent);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return output;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* In-degree per remaining subject, and the reverse edges needed to decrement them.
|
|
94
|
+
*
|
|
95
|
+
* `pending` counts DISTINCT targets: two foreign keys on one subject pointing at the same
|
|
96
|
+
* target are one dependency, and counting them twice would leave a counter that never
|
|
97
|
+
* reaches zero and a spurious cycle report.
|
|
98
|
+
*/
|
|
99
|
+
buildDegrees(inserts, byModel, remaining) {
|
|
100
|
+
const pending = new Map();
|
|
101
|
+
const dependents = new Map();
|
|
102
|
+
for (const s of inserts) {
|
|
103
|
+
pending.set(s, 0);
|
|
104
|
+
}
|
|
105
|
+
for (const s of inserts) {
|
|
106
|
+
if (!remaining.has(s)) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
for (const fk of s.PendingForeignKeys) {
|
|
111
|
+
const target = byModel.get(fk.Target);
|
|
112
|
+
if (!target || target === s || !remaining.has(target) || seen.has(target)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
seen.add(target);
|
|
116
|
+
pending.set(s, pending.get(s) + 1);
|
|
117
|
+
const list = dependents.get(target);
|
|
118
|
+
if (list) {
|
|
119
|
+
list.push(s);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
dependents.set(target, [s]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { pending, dependents };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Breaks a cycle by deferring the foreign keys that point at the *same model* — a
|
|
130
|
+
* self-referencing hierarchy, which is a cycle between models but not between rows.
|
|
131
|
+
* The row is inserted without the column and a follow-up UPDATE sets it.
|
|
132
|
+
*
|
|
133
|
+
* @returns true when at least one foreign key was deferred, i.e. progress is possible
|
|
134
|
+
*/
|
|
135
|
+
deferSelfReferences(remaining, byModel) {
|
|
136
|
+
let progress = false;
|
|
137
|
+
for (const s of remaining) {
|
|
138
|
+
const keep = [];
|
|
139
|
+
for (const fk of s.PendingForeignKeys) {
|
|
140
|
+
const target = byModel.get(fk.Target);
|
|
141
|
+
const cyclic = target !== undefined && remaining.has(target);
|
|
142
|
+
const selfReferencing = target !== undefined && target.Descriptor.TableName === s.Descriptor.TableName;
|
|
143
|
+
if (cyclic && selfReferencing) {
|
|
144
|
+
s.DeferredForeignKeys.push(fk);
|
|
145
|
+
progress = true;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
keep.push(fk);
|
|
149
|
+
}
|
|
150
|
+
s.PendingForeignKeys = keep;
|
|
151
|
+
}
|
|
152
|
+
return progress;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Children before parents, so a DELETE never strands a foreign key. A model that does not
|
|
156
|
+
* appear in the insert order at all keeps its relative position at the front.
|
|
157
|
+
*/
|
|
158
|
+
orderOrphans(orphans, inserts) {
|
|
159
|
+
const rank = new Map();
|
|
160
|
+
inserts.forEach((s, i) => {
|
|
161
|
+
if (!rank.has(s.Descriptor.TableName)) {
|
|
162
|
+
rank.set(s.Descriptor.TableName, i);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return [...orphans].sort((a, b) => (rank.get(b.TargetDescriptor.TableName) ?? -1) - (rank.get(a.TargetDescriptor.TableName) ?? -1));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=subject-sorter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject-sorter.js","sourceRoot":"","sources":["../../src/subject-sorter.ts"],"names":[],"mappings":"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"}
|