@spinajs/orm 2.0.480 → 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.
Files changed (228) hide show
  1. package/README.md +72 -3
  2. package/lib/cjs/bootstrap.js +10 -0
  3. package/lib/cjs/bootstrap.js.map +1 -1
  4. package/lib/cjs/builders.d.ts +115 -11
  5. package/lib/cjs/builders.d.ts.map +1 -1
  6. package/lib/cjs/builders.js +342 -283
  7. package/lib/cjs/builders.js.map +1 -1
  8. package/lib/cjs/converters.d.ts +9 -2
  9. package/lib/cjs/converters.d.ts.map +1 -1
  10. package/lib/cjs/converters.js +48 -8
  11. package/lib/cjs/converters.js.map +1 -1
  12. package/lib/cjs/decorators.d.ts +26 -3
  13. package/lib/cjs/decorators.d.ts.map +1 -1
  14. package/lib/cjs/decorators.js +95 -42
  15. package/lib/cjs/decorators.js.map +1 -1
  16. package/lib/cjs/dehydrators.js +1 -1
  17. package/lib/cjs/dehydrators.js.map +1 -1
  18. package/lib/cjs/descriptor.d.ts +1 -0
  19. package/lib/cjs/descriptor.d.ts.map +1 -1
  20. package/lib/cjs/descriptor.js +16 -40
  21. package/lib/cjs/descriptor.js.map +1 -1
  22. package/lib/cjs/driver.d.ts +136 -7
  23. package/lib/cjs/driver.d.ts.map +1 -1
  24. package/lib/cjs/driver.js +279 -0
  25. package/lib/cjs/driver.js.map +1 -1
  26. package/lib/cjs/existsRelationHandlers.d.ts +29 -0
  27. package/lib/cjs/existsRelationHandlers.d.ts.map +1 -0
  28. package/lib/cjs/existsRelationHandlers.js +104 -0
  29. package/lib/cjs/existsRelationHandlers.js.map +1 -0
  30. package/lib/cjs/fp.d.ts.map +1 -1
  31. package/lib/cjs/fp.js +10 -15
  32. package/lib/cjs/fp.js.map +1 -1
  33. package/lib/cjs/hydrators.d.ts.map +1 -1
  34. package/lib/cjs/hydrators.js +29 -2
  35. package/lib/cjs/hydrators.js.map +1 -1
  36. package/lib/cjs/identity-map.d.ts +60 -0
  37. package/lib/cjs/identity-map.d.ts.map +1 -0
  38. package/lib/cjs/identity-map.js +135 -0
  39. package/lib/cjs/identity-map.js.map +1 -0
  40. package/lib/cjs/index.d.ts +12 -0
  41. package/lib/cjs/index.d.ts.map +1 -1
  42. package/lib/cjs/index.js +12 -0
  43. package/lib/cjs/index.js.map +1 -1
  44. package/lib/cjs/interfaces.d.ts +295 -9
  45. package/lib/cjs/interfaces.d.ts.map +1 -1
  46. package/lib/cjs/interfaces.js +54 -1
  47. package/lib/cjs/interfaces.js.map +1 -1
  48. package/lib/cjs/metadata.d.ts.map +1 -1
  49. package/lib/cjs/metadata.js +4 -1
  50. package/lib/cjs/metadata.js.map +1 -1
  51. package/lib/cjs/metrics.d.ts +53 -0
  52. package/lib/cjs/metrics.d.ts.map +1 -0
  53. package/lib/cjs/metrics.js +82 -0
  54. package/lib/cjs/metrics.js.map +1 -0
  55. package/lib/cjs/middlewares.d.ts +13 -1
  56. package/lib/cjs/middlewares.d.ts.map +1 -1
  57. package/lib/cjs/middlewares.js +55 -15
  58. package/lib/cjs/middlewares.js.map +1 -1
  59. package/lib/cjs/model.d.ts +129 -13
  60. package/lib/cjs/model.d.ts.map +1 -1
  61. package/lib/cjs/model.js +449 -93
  62. package/lib/cjs/model.js.map +1 -1
  63. package/lib/cjs/orm.d.ts.map +1 -1
  64. package/lib/cjs/orm.js +12 -3
  65. package/lib/cjs/orm.js.map +1 -1
  66. package/lib/cjs/orphan.d.ts +27 -0
  67. package/lib/cjs/orphan.d.ts.map +1 -0
  68. package/lib/cjs/orphan.js +55 -0
  69. package/lib/cjs/orphan.js.map +1 -0
  70. package/lib/cjs/primary-keys.d.ts +60 -0
  71. package/lib/cjs/primary-keys.d.ts.map +1 -0
  72. package/lib/cjs/primary-keys.js +243 -0
  73. package/lib/cjs/primary-keys.js.map +1 -0
  74. package/lib/cjs/relation-objects.d.ts +101 -9
  75. package/lib/cjs/relation-objects.d.ts.map +1 -1
  76. package/lib/cjs/relation-objects.js +194 -43
  77. package/lib/cjs/relation-objects.js.map +1 -1
  78. package/lib/cjs/relations.d.ts +7 -1
  79. package/lib/cjs/relations.d.ts.map +1 -1
  80. package/lib/cjs/relations.js +16 -1
  81. package/lib/cjs/relations.js.map +1 -1
  82. package/lib/cjs/resilience.d.ts +50 -0
  83. package/lib/cjs/resilience.d.ts.map +1 -0
  84. package/lib/cjs/resilience.js +70 -0
  85. package/lib/cjs/resilience.js.map +1 -0
  86. package/lib/cjs/snapshot.d.ts +58 -0
  87. package/lib/cjs/snapshot.d.ts.map +1 -0
  88. package/lib/cjs/snapshot.js +125 -0
  89. package/lib/cjs/snapshot.js.map +1 -0
  90. package/lib/cjs/statements.d.ts +11 -1
  91. package/lib/cjs/statements.d.ts.map +1 -1
  92. package/lib/cjs/statements.js +13 -2
  93. package/lib/cjs/statements.js.map +1 -1
  94. package/lib/cjs/subject-builder.d.ts +79 -0
  95. package/lib/cjs/subject-builder.d.ts.map +1 -0
  96. package/lib/cjs/subject-builder.js +296 -0
  97. package/lib/cjs/subject-builder.js.map +1 -0
  98. package/lib/cjs/subject-executor.d.ts +122 -0
  99. package/lib/cjs/subject-executor.d.ts.map +1 -0
  100. package/lib/cjs/subject-executor.js +319 -0
  101. package/lib/cjs/subject-executor.js.map +1 -0
  102. package/lib/cjs/subject-sorter.d.ts +70 -0
  103. package/lib/cjs/subject-sorter.d.ts.map +1 -0
  104. package/lib/cjs/subject-sorter.js +173 -0
  105. package/lib/cjs/subject-sorter.js.map +1 -0
  106. package/lib/cjs/subject.d.ts +100 -0
  107. package/lib/cjs/subject.d.ts.map +1 -0
  108. package/lib/cjs/subject.js +89 -0
  109. package/lib/cjs/subject.js.map +1 -0
  110. package/lib/cjs/unit-of-work.d.ts +52 -0
  111. package/lib/cjs/unit-of-work.d.ts.map +1 -0
  112. package/lib/cjs/unit-of-work.js +170 -0
  113. package/lib/cjs/unit-of-work.js.map +1 -0
  114. package/lib/mjs/bootstrap.js +10 -0
  115. package/lib/mjs/bootstrap.js.map +1 -1
  116. package/lib/mjs/builders.d.ts +115 -11
  117. package/lib/mjs/builders.d.ts.map +1 -1
  118. package/lib/mjs/builders.js +344 -285
  119. package/lib/mjs/builders.js.map +1 -1
  120. package/lib/mjs/converters.d.ts +9 -2
  121. package/lib/mjs/converters.d.ts.map +1 -1
  122. package/lib/mjs/converters.js +48 -8
  123. package/lib/mjs/converters.js.map +1 -1
  124. package/lib/mjs/decorators.d.ts +26 -3
  125. package/lib/mjs/decorators.d.ts.map +1 -1
  126. package/lib/mjs/decorators.js +96 -44
  127. package/lib/mjs/decorators.js.map +1 -1
  128. package/lib/mjs/dehydrators.js +1 -1
  129. package/lib/mjs/dehydrators.js.map +1 -1
  130. package/lib/mjs/descriptor.d.ts +1 -0
  131. package/lib/mjs/descriptor.d.ts.map +1 -1
  132. package/lib/mjs/descriptor.js +17 -39
  133. package/lib/mjs/descriptor.js.map +1 -1
  134. package/lib/mjs/driver.d.ts +136 -7
  135. package/lib/mjs/driver.d.ts.map +1 -1
  136. package/lib/mjs/driver.js +279 -0
  137. package/lib/mjs/driver.js.map +1 -1
  138. package/lib/mjs/existsRelationHandlers.d.ts +29 -0
  139. package/lib/mjs/existsRelationHandlers.d.ts.map +1 -0
  140. package/lib/mjs/existsRelationHandlers.js +100 -0
  141. package/lib/mjs/existsRelationHandlers.js.map +1 -0
  142. package/lib/mjs/fp.d.ts.map +1 -1
  143. package/lib/mjs/fp.js +10 -15
  144. package/lib/mjs/fp.js.map +1 -1
  145. package/lib/mjs/hydrators.d.ts.map +1 -1
  146. package/lib/mjs/hydrators.js +29 -2
  147. package/lib/mjs/hydrators.js.map +1 -1
  148. package/lib/mjs/identity-map.d.ts +60 -0
  149. package/lib/mjs/identity-map.d.ts.map +1 -0
  150. package/lib/mjs/identity-map.js +130 -0
  151. package/lib/mjs/identity-map.js.map +1 -0
  152. package/lib/mjs/index.d.ts +12 -0
  153. package/lib/mjs/index.d.ts.map +1 -1
  154. package/lib/mjs/index.js +12 -0
  155. package/lib/mjs/index.js.map +1 -1
  156. package/lib/mjs/interfaces.d.ts +295 -9
  157. package/lib/mjs/interfaces.d.ts.map +1 -1
  158. package/lib/mjs/interfaces.js +53 -0
  159. package/lib/mjs/interfaces.js.map +1 -1
  160. package/lib/mjs/metadata.d.ts.map +1 -1
  161. package/lib/mjs/metadata.js +4 -1
  162. package/lib/mjs/metadata.js.map +1 -1
  163. package/lib/mjs/metrics.d.ts +53 -0
  164. package/lib/mjs/metrics.d.ts.map +1 -0
  165. package/lib/mjs/metrics.js +76 -0
  166. package/lib/mjs/metrics.js.map +1 -0
  167. package/lib/mjs/middlewares.d.ts +13 -1
  168. package/lib/mjs/middlewares.d.ts.map +1 -1
  169. package/lib/mjs/middlewares.js +55 -15
  170. package/lib/mjs/middlewares.js.map +1 -1
  171. package/lib/mjs/model.d.ts +129 -13
  172. package/lib/mjs/model.d.ts.map +1 -1
  173. package/lib/mjs/model.js +451 -95
  174. package/lib/mjs/model.js.map +1 -1
  175. package/lib/mjs/orm.d.ts.map +1 -1
  176. package/lib/mjs/orm.js +12 -3
  177. package/lib/mjs/orm.js.map +1 -1
  178. package/lib/mjs/orphan.d.ts +27 -0
  179. package/lib/mjs/orphan.d.ts.map +1 -0
  180. package/lib/mjs/orphan.js +52 -0
  181. package/lib/mjs/orphan.js.map +1 -0
  182. package/lib/mjs/primary-keys.d.ts +60 -0
  183. package/lib/mjs/primary-keys.d.ts.map +1 -0
  184. package/lib/mjs/primary-keys.js +223 -0
  185. package/lib/mjs/primary-keys.js.map +1 -0
  186. package/lib/mjs/relation-objects.d.ts +101 -9
  187. package/lib/mjs/relation-objects.d.ts.map +1 -1
  188. package/lib/mjs/relation-objects.js +194 -43
  189. package/lib/mjs/relation-objects.js.map +1 -1
  190. package/lib/mjs/relations.d.ts +7 -1
  191. package/lib/mjs/relations.d.ts.map +1 -1
  192. package/lib/mjs/relations.js +16 -1
  193. package/lib/mjs/relations.js.map +1 -1
  194. package/lib/mjs/resilience.d.ts +50 -0
  195. package/lib/mjs/resilience.d.ts.map +1 -0
  196. package/lib/mjs/resilience.js +64 -0
  197. package/lib/mjs/resilience.js.map +1 -0
  198. package/lib/mjs/snapshot.d.ts +58 -0
  199. package/lib/mjs/snapshot.d.ts.map +1 -0
  200. package/lib/mjs/snapshot.js +115 -0
  201. package/lib/mjs/snapshot.js.map +1 -0
  202. package/lib/mjs/statements.d.ts +11 -1
  203. package/lib/mjs/statements.d.ts.map +1 -1
  204. package/lib/mjs/statements.js +14 -3
  205. package/lib/mjs/statements.js.map +1 -1
  206. package/lib/mjs/subject-builder.d.ts +79 -0
  207. package/lib/mjs/subject-builder.d.ts.map +1 -0
  208. package/lib/mjs/subject-builder.js +292 -0
  209. package/lib/mjs/subject-builder.js.map +1 -0
  210. package/lib/mjs/subject-executor.d.ts +122 -0
  211. package/lib/mjs/subject-executor.d.ts.map +1 -0
  212. package/lib/mjs/subject-executor.js +312 -0
  213. package/lib/mjs/subject-executor.js.map +1 -0
  214. package/lib/mjs/subject-sorter.d.ts +70 -0
  215. package/lib/mjs/subject-sorter.d.ts.map +1 -0
  216. package/lib/mjs/subject-sorter.js +168 -0
  217. package/lib/mjs/subject-sorter.js.map +1 -0
  218. package/lib/mjs/subject.d.ts +100 -0
  219. package/lib/mjs/subject.d.ts.map +1 -0
  220. package/lib/mjs/subject.js +84 -0
  221. package/lib/mjs/subject.js.map +1 -0
  222. package/lib/mjs/unit-of-work.d.ts +52 -0
  223. package/lib/mjs/unit-of-work.d.ts.map +1 -0
  224. package/lib/mjs/unit-of-work.js +166 -0
  225. package/lib/mjs/unit-of-work.js.map +1 -0
  226. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  227. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  228. package/package.json +9 -7
@@ -0,0 +1,292 @@
1
+ /* eslint-disable prettier/prettier */
2
+ import { extractModelDescriptor } from './descriptor.js';
3
+ import { identityKey } from './identity-map.js';
4
+ import { OrphanPolicy, RelationType } from './interfaces.js';
5
+ import { resolveOrphanPolicy } from './orphan.js';
6
+ import { SingleRelation } from './relation-objects.js';
7
+ import { OrmException } from './exceptions.js';
8
+ import { Subject, SubjectOperation, SubjectSet } from './subject.js';
9
+ /**
10
+ * Turns a mutated object graph into a `SubjectSet` — the complete, unordered description of
11
+ * what one `save()` must do.
12
+ *
13
+ * Traversal rules:
14
+ *
15
+ * - a `belongsTo` is followed whenever its `Value` is set, populated or not, because
16
+ * attaching a model to it is an explicit act;
17
+ * - a `hasMany` or `manyToMany` is followed **only when `Populated` is true**, so a relation
18
+ * the caller never loaded is invisible and `Items: OrderItem[] = []` on a freshly
19
+ * constructed model deletes nothing;
20
+ * - `Query` and `Virtual` relations are read-only projections and are never followed.
21
+ */
22
+ export class SubjectBuilder {
23
+ constructor(identityMap) {
24
+ this.identityMap = identityMap;
25
+ this._visited = new Set();
26
+ }
27
+ build(root) {
28
+ return this.buildFrom(this.collect(root));
29
+ }
30
+ /**
31
+ * Walks the graph breadth-first from `root`, canonicalizing every model through the
32
+ * identity map so a row reached by two paths yields one instance.
33
+ *
34
+ * @param root - the model `save()` was called on
35
+ */
36
+ collect(root) {
37
+ this._visited = new Set();
38
+ const ordered = [];
39
+ const queue = [this.identityMap.add(root)];
40
+ while (queue.length > 0) {
41
+ const model = queue.shift();
42
+ if (this._visited.has(model)) {
43
+ continue;
44
+ }
45
+ this._visited.add(model);
46
+ ordered.push(model);
47
+ for (const related of this.relatedOf(model)) {
48
+ const canonical = this.identityMap.add(related);
49
+ if (!this._visited.has(canonical)) {
50
+ queue.push(canonical);
51
+ }
52
+ }
53
+ }
54
+ return ordered;
55
+ }
56
+ /**
57
+ * Models directly reachable from `model` under the traversal rules.
58
+ */
59
+ relatedOf(model) {
60
+ const descriptor = extractModelDescriptor(model.constructor);
61
+ if (!descriptor) {
62
+ return [];
63
+ }
64
+ const out = [];
65
+ for (const [name, relation] of descriptor.Relations) {
66
+ // eslint-disable-next-line security/detect-object-injection
67
+ const value = model[name];
68
+ if (value === null || value === undefined) {
69
+ continue;
70
+ }
71
+ switch (relation.Type) {
72
+ case RelationType.One:
73
+ if (value instanceof SingleRelation && value.Value) {
74
+ out.push(value.Value);
75
+ }
76
+ break;
77
+ case RelationType.Many:
78
+ case RelationType.ManyToMany:
79
+ if (value.Populated === true) {
80
+ out.push(...[...value]);
81
+ }
82
+ break;
83
+ case RelationType.Query:
84
+ case RelationType.Virtual:
85
+ default:
86
+ break;
87
+ }
88
+ }
89
+ return out;
90
+ }
91
+ /**
92
+ * Diffs each collected model against its snapshot and records its `belongsTo` foreign keys.
93
+ * hasMany, manyToMany and orphan handling are layered on by later passes.
94
+ *
95
+ * @param models - output of `collect()`
96
+ */
97
+ buildFrom(models) {
98
+ const set = new SubjectSet();
99
+ for (const model of models) {
100
+ const descriptor = extractModelDescriptor(model.constructor);
101
+ if (!descriptor) {
102
+ continue;
103
+ }
104
+ const subject = new Subject(model, descriptor, classify(model));
105
+ // Only an UPDATE needs a column list: an INSERT writes every column, and a no-op
106
+ // writes none. Reading the diff again here is cheap and keeps `classify` pure.
107
+ if (subject.Operation === SubjectOperation.Update) {
108
+ subject.ChangedColumns = model.changedColumns();
109
+ }
110
+ set.add(subject);
111
+ }
112
+ for (const subject of set.Subjects) {
113
+ this.buildBelongsTo(subject);
114
+ this.buildHasMany(subject, set);
115
+ this.buildManyToMany(subject, set);
116
+ }
117
+ this.buildOrphans(set);
118
+ return set;
119
+ }
120
+ /**
121
+ * Records, for every `belongsTo` with a `Value`, that this subject's foreign-key column
122
+ * takes the target's primary key. The value is *not* read here — the target may not have
123
+ * been inserted yet; the executor resolves it immediately before the statement.
124
+ */
125
+ buildBelongsTo(subject) {
126
+ for (const [name, relation] of subject.Descriptor.Relations) {
127
+ if (relation.Type !== RelationType.One) {
128
+ continue;
129
+ }
130
+ // eslint-disable-next-line security/detect-object-injection
131
+ const rel = subject.Model[name];
132
+ if (!(rel instanceof SingleRelation) || !rel.Value) {
133
+ continue;
134
+ }
135
+ subject.PendingForeignKeys.push({ Column: relation.ForeignKey, Target: rel.Value });
136
+ }
137
+ }
138
+ /**
139
+ * Diffs each populated `hasMany` on `subject` against the owner's relation snapshot and
140
+ * records the owner's foreign key as pending on every member that stays.
141
+ *
142
+ * A relation with `Populated === false` is skipped entirely — that is the anti-footgun
143
+ * guarantee, and it is why a freshly constructed model with `Items: OrderItem[] = []`
144
+ * deletes nothing.
145
+ *
146
+ * Both new *and* kept members get the pending foreign key. That is what makes re-parenting
147
+ * work: a clean child moved to another owner has its key rewritten and is promoted from a
148
+ * no-op to an UPDATE, instead of keeping its old owner id in the database ( B20 ).
149
+ */
150
+ buildHasMany(subject, set) {
151
+ for (const [name, relation] of subject.Descriptor.Relations) {
152
+ if (relation.Type !== RelationType.Many) {
153
+ continue;
154
+ }
155
+ // eslint-disable-next-line security/detect-object-injection
156
+ const rel = subject.Model[name];
157
+ if (!rel || rel.Populated !== true) {
158
+ continue;
159
+ }
160
+ const members = [...rel];
161
+ const snapshotKeys = subject.Model.Snapshot?.Relations.get(name) ?? [];
162
+ const presentKeys = new Set(members.map((m) => identityKey(m.PrimaryKeyValue)).filter((k) => k !== null));
163
+ const delta = {
164
+ Descriptor: relation,
165
+ Added: members.filter((m) => m.Snapshot === null),
166
+ Kept: members.filter((m) => m.Snapshot !== null),
167
+ RemovedKeys: snapshotKeys.filter((k) => !presentKeys.has(identityKey(k))),
168
+ };
169
+ subject.RelationDeltas.push(delta);
170
+ for (const member of members) {
171
+ const memberSubject = set.find(member);
172
+ if (memberSubject) {
173
+ memberSubject.PendingForeignKeys.push({ Column: relation.ForeignKey, Target: subject.Model });
174
+ }
175
+ }
176
+ }
177
+ }
178
+ /**
179
+ * Diffs each populated `manyToMany` against the owner's relation snapshot into junction
180
+ * rows to create and destroy.
181
+ *
182
+ * Only the *junction* row is created or destroyed. A target that is new gets its own insert
183
+ * subject from `collect()` so its key exists before the junction row references it; a target
184
+ * that is merely unlinked is left completely alone — removing a tag from an order must
185
+ * never delete the tag.
186
+ */
187
+ buildManyToMany(subject, set) {
188
+ for (const [name, relation] of subject.Descriptor.Relations) {
189
+ if (relation.Type !== RelationType.ManyToMany) {
190
+ continue;
191
+ }
192
+ // eslint-disable-next-line security/detect-object-injection
193
+ const rel = subject.Model[name];
194
+ if (!rel || rel.Populated !== true) {
195
+ continue;
196
+ }
197
+ if (!relation.JunctionModel) {
198
+ throw new OrmException(`manyToMany relation ${relation.Name} on ${subject.Descriptor.Name} has no junction model`);
199
+ }
200
+ const junctionDescriptor = extractModelDescriptor(relation.JunctionModel);
201
+ if (!junctionDescriptor) {
202
+ throw new OrmException(`junction model ${relation.JunctionModel.name} for relation ${relation.Name} has no model descriptor`);
203
+ }
204
+ const members = [...rel];
205
+ const snapshotKeys = subject.Model.Snapshot?.Relations.get(name) ?? [];
206
+ const snapshotSet = new Set(snapshotKeys.map((k) => identityKey(k)).filter((k) => k !== null));
207
+ const presentKeys = new Set(members.map((m) => identityKey(m.PrimaryKeyValue)).filter((k) => k !== null));
208
+ const delta = {
209
+ Descriptor: relation,
210
+ JunctionDescriptor: junctionDescriptor,
211
+ Owner: subject.Model,
212
+ // A member with no key yet cannot have been linked before, so it is always an add.
213
+ Added: members.filter((m) => {
214
+ const key = identityKey(m.PrimaryKeyValue);
215
+ return key === null || !snapshotSet.has(key);
216
+ }),
217
+ RemovedKeys: snapshotKeys.filter((k) => !presentKeys.has(identityKey(k))),
218
+ };
219
+ set.Junctions.push(delta);
220
+ }
221
+ }
222
+ /**
223
+ * Turns every `hasMany` removal recorded during the diff into an orphan action.
224
+ *
225
+ * Runs once over the whole set rather than per relation, because the decision needs global
226
+ * information: a child removed from one owner and pushed onto another is a re-parent, not
227
+ * an orphan, and only a set-wide view can tell the two apart. Every key that has a live
228
+ * subject of the same target model in this graph is therefore subtracted.
229
+ */
230
+ buildOrphans(set) {
231
+ // Primary keys, per target model, that are alive somewhere in this graph. Keyed on
232
+ // TableName rather than on the constructor: a discrimination map can produce several
233
+ // constructors for one table, and a subclass instance is still the same row.
234
+ const alive = new Map();
235
+ for (const subject of set.Subjects) {
236
+ const key = identityKey(subject.Model.PrimaryKeyValue);
237
+ if (key === null) {
238
+ continue;
239
+ }
240
+ const table = subject.Descriptor.TableName;
241
+ if (!alive.has(table)) {
242
+ alive.set(table, new Set());
243
+ }
244
+ alive.get(table).add(key);
245
+ }
246
+ for (const subject of set.Subjects) {
247
+ for (const delta of subject.RelationDeltas) {
248
+ if (delta.RemovedKeys.length === 0) {
249
+ continue;
250
+ }
251
+ const targetDescriptor = extractModelDescriptor(delta.Descriptor.TargetModel);
252
+ if (!targetDescriptor) {
253
+ throw new OrmException(`relation ${delta.Descriptor.Name} on ${subject.Descriptor.Name} has an unresolved target model`);
254
+ }
255
+ const policy = resolveOrphanPolicy(delta.Descriptor, targetDescriptor);
256
+ if (policy === OrphanPolicy.Disable) {
257
+ continue;
258
+ }
259
+ const survivors = alive.get(targetDescriptor.TableName) ?? new Set();
260
+ const keys = delta.RemovedKeys.filter((k) => {
261
+ const key = identityKey(k);
262
+ return key !== null && !survivors.has(key);
263
+ });
264
+ // Drop an empty list rather than emitting a statement with `IN ()`.
265
+ if (keys.length === 0) {
266
+ continue;
267
+ }
268
+ const orphan = {
269
+ Descriptor: delta.Descriptor,
270
+ TargetDescriptor: targetDescriptor,
271
+ Policy: policy,
272
+ PrimaryKeys: keys,
273
+ };
274
+ set.Orphans.push(orphan);
275
+ }
276
+ }
277
+ }
278
+ }
279
+ /**
280
+ * `Insert` when the model has never been hydrated from the database, `Update` when its
281
+ * snapshot diff is non-empty, `None` otherwise.
282
+ *
283
+ * Deliberately not keyed on the primary key: `setDefaults()` pre-fills @Uuid keys on
284
+ * construction, so a brand-new UUID-keyed model already has one.
285
+ */
286
+ function classify(model) {
287
+ if (model.Snapshot === null) {
288
+ return SubjectOperation.Insert;
289
+ }
290
+ return model.changedColumns().length > 0 ? SubjectOperation.Update : SubjectOperation.None;
291
+ }
292
+ //# sourceMappingURL=subject-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subject-builder.js","sourceRoot":"","sources":["../../src/subject-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ import { ISaveOptions, ISaveResult, OrphanPolicy } from './interfaces.js';
2
+ import { ISortedPlan } from './subject-sorter.js';
3
+ import { IJunctionDelta, IOrphanDelta, Subject } from './subject.js';
4
+ /** Rows per batched statement when the caller does not say. */
5
+ export declare const DEFAULT_SAVE_CHUNK = 100;
6
+ /**
7
+ * Runs a sorted plan.
8
+ *
9
+ * Every statement is built through `createQuery`, so table naming, schema qualification and
10
+ * identifier escaping are the same as on the ActiveRecord paths. No connection is threaded by
11
+ * hand: `OrmDriver.transaction()` carries it in `AsyncLocalStorage` and the builders resolved
12
+ * from that driver pick it up automatically.
13
+ *
14
+ * The executor does **not** open the transaction — `UnitOfWork` does — so that a caller can
15
+ * drive it directly in a test and so that nested saves inside one transaction fold into
16
+ * savepoints rather than each opening their own.
17
+ */
18
+ export declare class SubjectExecutor {
19
+ protected options: ISaveOptions;
20
+ constructor(options: ISaveOptions);
21
+ execute(plan: ISortedPlan): Promise<ISaveResult>;
22
+ /**
23
+ * Inserts every insert subject in the order the sorter produced, reading each generated key
24
+ * back before moving on so the next subject's foreign keys can be resolved.
25
+ *
26
+ * One statement per row, deliberately, and NOT subject to `options.chunk`: a batched
27
+ * multi-row INSERT can only return keys where the dialect supports RETURNING or where
28
+ * `insertIdIsFirstOfBatch` holds, and a subject's key is needed by the very next subject in
29
+ * the order. Batching here is a real feature — it has to carry the per-dialect key-backfill
30
+ * rules with it — not something to fold into the chunking used for junction and orphan rows.
31
+ */
32
+ protected runInserts(plan: ISortedPlan, result: ISaveResult): Promise<void>;
33
+ /**
34
+ * One INSERT, with the key read back.
35
+ *
36
+ * Mirrors `ModelBase.insert()`'s key handling rather than inventing a second one: client-side
37
+ * keys are generated first, `assigned` keys are asserted before anything touches the database,
38
+ * and RETURNING is requested when an `auto` key needs to come back and the dialect supports it.
39
+ */
40
+ protected insertOne(subject: Subject): Promise<void>;
41
+ /**
42
+ * Runs every update, including the follow-up updates that carry deferred self-referencing
43
+ * foreign keys.
44
+ *
45
+ * A subject whose payload comes out empty emits nothing. This is the single place that
46
+ * decides whether a row actually changed: pending foreign keys are written onto the model
47
+ * first and `changedColumns()` is read afterwards, so a re-parented child that was clean
48
+ * when the subjects were built is caught here and nowhere else.
49
+ */
50
+ protected runUpdates(plan: ISortedPlan, result: ISaveResult): Promise<void>;
51
+ /**
52
+ * The column payload for one UPDATE, or `null` when there is nothing to write.
53
+ *
54
+ * The primary key columns are excluded: writing them is a no-op at best and, for a model
55
+ * whose key column differs from its snapshot for any other reason, a silent identity change.
56
+ *
57
+ * @param subject - an update subject, or an insert subject with deferred foreign keys
58
+ */
59
+ protected updatePayload(subject: Subject): Record<string, unknown> | null;
60
+ /**
61
+ * The column payload for one INSERT.
62
+ *
63
+ * Starts from the model's own serialization, drops every column whose foreign key is
64
+ * deferred to a follow-up UPDATE, then writes every pending foreign key from its target's
65
+ * now-known primary key. The overwrite matters: `StandardModelToSqlConverter` already wrote
66
+ * that column from the relation object, and for a target inserted moments ago that value was
67
+ * `undefined` when the model was serialized.
68
+ */
69
+ protected insertPayload(subject: Subject): Record<string, unknown>;
70
+ /**
71
+ * Writes a generated key onto the model.
72
+ *
73
+ * Uses `setPkValue` — the primary-keys helper that assigns the key columns and nothing else —
74
+ * rather than the `PrimaryKeyValue` setter, whose `RelationType.One` branch also writes the
75
+ * new key onto the owner's `SingleRelation` wrapper, which persists nothing. The executor
76
+ * resolves foreign keys itself and does not want that side effect.
77
+ *
78
+ * A key the caller already supplied ( uuid / assigned strategies ) is never overwritten.
79
+ */
80
+ protected backfillKey(subject: Subject, returning: any[], lastInsertId: number, needsKeyBack: boolean): void;
81
+ /**
82
+ * Creates and destroys junction rows.
83
+ *
84
+ * Rows are written column-first rather than through the junction model, so a junction model
85
+ * is not required to declare `@BelongsTo` on both sides — `ManyToManyRelationList.update()`
86
+ * does require that, and none of the existing junction fixtures satisfy it.
87
+ *
88
+ * Inserts run before deletes so that re-linking the same pair inside one save cannot
89
+ * momentarily violate a unique constraint on the junction table in the other order.
90
+ */
91
+ protected runJunctions(plan: ISortedPlan, result: ISaveResult): Promise<void>;
92
+ protected insertJunctionRows(delta: IJunctionDelta, result: ISaveResult): Promise<void>;
93
+ protected deleteJunctionRows(delta: IJunctionDelta, result: ISaveResult): Promise<void>;
94
+ /**
95
+ * Applies the orphan policy to every detached row.
96
+ *
97
+ * `nullify` and `soft-delete` run first as UPDATEs, then `delete` runs as DELETEs, and the
98
+ * deltas arrive from the sorter already ordered children-before-parents so a delete cannot
99
+ * strand a foreign key.
100
+ *
101
+ * `createQuery` only adds the default `DeletedAt IS NULL` filter to a SelectQueryBuilder, so
102
+ * these builders are unfiltered — which is what stamping an already-soft-deleted row needs.
103
+ */
104
+ protected runOrphans(plan: ISortedPlan, result: ISaveResult): Promise<void>;
105
+ /**
106
+ * The policy actually applied to `delta`.
107
+ *
108
+ * `delete` on a model that declares `@SoftDelete` degrades to `soft-delete`, so orphaning a
109
+ * row and calling `destroy()` on it mean the same thing. `ModelBase.destroy()` has always
110
+ * stamped `DeletedAt` rather than issuing a DELETE for such a model; an orphan taking the
111
+ * other branch made "delete this row" depend on which code path reached it, and hard-erased
112
+ * rows the model had declared should never be hard-erased.
113
+ */
114
+ protected effectivePolicy(delta: IOrphanDelta): OrphanPolicy;
115
+ protected updateOrphans(delta: IOrphanDelta, result: ISaveResult): Promise<void>;
116
+ protected deleteOrphans(delta: IOrphanDelta, result: ISaveResult): Promise<void>;
117
+ /** Rows per batched statement. */
118
+ protected get chunkSize(): number;
119
+ /** Splits `items` into runs of at most `chunkSize`. */
120
+ protected chunked<T>(items: T[]): T[][];
121
+ }
122
+ //# sourceMappingURL=subject-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subject-executor.d.ts","sourceRoot":"","sources":["../../src/subject-executor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiB,YAAY,EAAE,WAAW,EAAE,YAAY,EAAwB,MAAM,iBAAiB,CAAC;AAE/G,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAErE,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,qBAAa,eAAe;IACd,SAAS,CAAC,OAAO,EAAE,YAAY;gBAArB,OAAO,EAAE,YAAY;IAE9B,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAkB7D;;;;;;;;;OASG;cACa,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjF;;;;;;OAMG;cACa,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB1D;;;;;;;;OAQG;cACa,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBjF;;;;;;;OAOG;IACH,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAyBzE;;;;;;;;OAQG;IACH,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAkBlE;;;;;;;;;OASG;IACH,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,IAAI;IA+B5G;;;;;;;;;OASG;cACa,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;cAOnE,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;cA2B7E,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB7F;;;;;;;;;OASG;cACa,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAajF;;;;;;;;OAQG;IACH,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY;cAQ5C,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;cAkBtE,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtF,kCAAkC;IAClC,SAAS,KAAK,SAAS,IAAI,MAAM,CAGhC;IAED,uDAAuD;IACvD,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE;CAOxC"}