@memberjunction/core 6.1.0-edge.0 → 6.1.0-edge.1
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/dist/generic/baseEngineRegistry.d.ts +14 -0
- package/dist/generic/baseEngineRegistry.d.ts.map +1 -1
- package/dist/generic/baseEngineRegistry.js +32 -0
- package/dist/generic/baseEngineRegistry.js.map +1 -1
- package/dist/generic/baseEntity.d.ts +329 -26
- package/dist/generic/baseEntity.d.ts.map +1 -1
- package/dist/generic/baseEntity.js +788 -79
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/databaseProviderBase.d.ts +44 -17
- package/dist/generic/databaseProviderBase.d.ts.map +1 -1
- package/dist/generic/databaseProviderBase.js +96 -52
- package/dist/generic/databaseProviderBase.js.map +1 -1
- package/dist/generic/entityCompanion.d.ts +218 -0
- package/dist/generic/entityCompanion.d.ts.map +1 -0
- package/dist/generic/entityCompanion.js +170 -0
- package/dist/generic/entityCompanion.js.map +1 -0
- package/dist/generic/entityInfo.d.ts +21 -0
- package/dist/generic/entityInfo.d.ts.map +1 -1
- package/dist/generic/entityInfo.js +21 -0
- package/dist/generic/entityInfo.js.map +1 -1
- package/dist/generic/entitySavePlan.d.ts +199 -0
- package/dist/generic/entitySavePlan.d.ts.map +1 -0
- package/dist/generic/entitySavePlan.js +213 -0
- package/dist/generic/entitySavePlan.js.map +1 -0
- package/dist/generic/entityTransactionScope.d.ts +125 -0
- package/dist/generic/entityTransactionScope.d.ts.map +1 -0
- package/dist/generic/entityTransactionScope.js +115 -0
- package/dist/generic/entityTransactionScope.js.map +1 -0
- package/dist/generic/interfaces.d.ts +93 -35
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js +27 -0
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/providerBase.d.ts +13 -0
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +63 -4
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/relatedRecordBatchLoader.d.ts +39 -0
- package/dist/generic/relatedRecordBatchLoader.d.ts.map +1 -0
- package/dist/generic/relatedRecordBatchLoader.js +154 -0
- package/dist/generic/relatedRecordBatchLoader.js.map +1 -0
- package/dist/generic/relatedRecordCollection.d.ts +578 -0
- package/dist/generic/relatedRecordCollection.d.ts.map +1 -0
- package/dist/generic/relatedRecordCollection.js +1004 -0
- package/dist/generic/relatedRecordCollection.js.map +1 -0
- package/dist/generic/saveEntityGraphOperation.d.ts +148 -0
- package/dist/generic/saveEntityGraphOperation.d.ts.map +1 -0
- package/dist/generic/saveEntityGraphOperation.js +157 -0
- package/dist/generic/saveEntityGraphOperation.js.map +1 -0
- package/dist/generic/telemetryManager.d.ts +21 -1
- package/dist/generic/telemetryManager.d.ts.map +1 -1
- package/dist/generic/telemetryManager.js +21 -6
- package/dist/generic/telemetryManager.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/views/runView.d.ts +31 -0
- package/dist/views/runView.d.ts.map +1 -1
- package/dist/views/runView.js.map +1 -1
- package/package.json +3 -3
- package/readme.md +151 -1
- package/dist/generic/runReport.d.ts +0 -25
- package/dist/generic/runReport.d.ts.map +0 -1
- package/dist/generic/runReport.js +0 -38
- package/dist/generic/runReport.js.map +0 -1
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `RelatedRecordCollection<T>` — a typed, transportable collection of child records that
|
|
3
|
+
* loads, validates and persists as one unit with its parent.
|
|
4
|
+
*
|
|
5
|
+
* ## The problem it replaces
|
|
6
|
+
*
|
|
7
|
+
* Three MemberJunction applications independently hand-rolled this same pattern, and each got a
|
|
8
|
+
* different subset of it right:
|
|
9
|
+
*
|
|
10
|
+
* | | Order | PaymentHeader | JournalEntry |
|
|
11
|
+
* |---|---|---|---|
|
|
12
|
+
* | Typed | ✓ | ✗ (`BaseEntity[]`) | ✓ |
|
|
13
|
+
* | Loads children | ✗ | ✗ | ✓ |
|
|
14
|
+
* | Tracks removals | ✗ | ✗ | ✓ |
|
|
15
|
+
* | Add/remove API | raw setter | raw setter | ✓ |
|
|
16
|
+
* | Re-sequences | ✗ | ✗ | ✓ |
|
|
17
|
+
*
|
|
18
|
+
* All three were server-only classes, because each cast the provider to `DatabaseProviderBase` to
|
|
19
|
+
* reach `BeginTransaction()`. `RelatedRecordCollection` is tier-neutral: it never touches a provider
|
|
20
|
+
* transaction itself, it only contributes nodes to an {@link EntitySavePlan}, and `BaseEntity`
|
|
21
|
+
* decides where that plan runs.
|
|
22
|
+
*
|
|
23
|
+
* @module @memberjunction/core
|
|
24
|
+
*/
|
|
25
|
+
import type { BaseEntity } from './baseEntity.js';
|
|
26
|
+
import { EntityCompanion, EntityCompanionDeserializeMode } from './entityCompanion.js';
|
|
27
|
+
import type { EntitySavePlan } from './entitySavePlan.js';
|
|
28
|
+
import { ValidationResult } from './entityInfo.js';
|
|
29
|
+
import type { EntitySaveOptions } from './interfaces.js';
|
|
30
|
+
/**
|
|
31
|
+
* When a child collection populates itself from the database.
|
|
32
|
+
*
|
|
33
|
+
* - `'explicit'` — **the default.** Nothing loads until the caller awaits `Load()`. Chosen as the
|
|
34
|
+
* default because the alternative is a performance trap: an eager collection on a widely-listed
|
|
35
|
+
* entity turns every grid into an N+1 storm.
|
|
36
|
+
* - `'immediate'` — populated automatically by `BaseEntity.Load()`. **Never** by `LoadFromData()`,
|
|
37
|
+
* which is the per-row materialization path for `RunView(ResultType:'entity_object')`. That
|
|
38
|
+
* exclusion is deliberate and is the structural fix for a live N+1 in production accounting code,
|
|
39
|
+
* where a `LoadFromData` override issued one child query per row of every view.
|
|
40
|
+
* - `'lazy'` — populated on first read of {@link RelatedRecordCollection.Items}. Requires
|
|
41
|
+
* {@link RelatedRecordSource} `'cache'`: a property getter cannot await, so a lazy *database*
|
|
42
|
+
* load could only ever silently fail to fill, and CodeGen refuses that combination. A cache
|
|
43
|
+
* lookup is synchronous, so lazy works there — reproducing exactly the hand-written memoized
|
|
44
|
+
* getters this mechanism replaces.
|
|
45
|
+
* - `'never'` — the collection is a write-only staging buffer; `Load()` is a no-op. Matches how
|
|
46
|
+
* order lines are actually used: built up in memory and pushed down, never read back through the
|
|
47
|
+
* collection.
|
|
48
|
+
*/
|
|
49
|
+
export type RelatedRecordLoadMode = 'explicit' | 'immediate' | 'lazy' | 'never';
|
|
50
|
+
/**
|
|
51
|
+
* Where a collection's records come from.
|
|
52
|
+
*
|
|
53
|
+
* - `'database'` — a `RunView` filtered by the join field. Always fresh, costs a query. Correct for
|
|
54
|
+
* transactional data where staleness is unacceptable.
|
|
55
|
+
* - `'cache'` — taken from whichever loaded `BaseEngine` already holds the entity, discovered
|
|
56
|
+
* generically via `BaseEngineRegistry.FindCachedEntity()`. Costs **zero queries**, and falls back
|
|
57
|
+
* to `'database'` when no loaded engine offers it, so a miss degrades rather than fails.
|
|
58
|
+
*
|
|
59
|
+
* Deliberately not `'query'`: in MemberJunction a *Query* is a stored, named artifact
|
|
60
|
+
* (`MJ: Queries`, `RunQuery`), so that word already means something else.
|
|
61
|
+
*/
|
|
62
|
+
export type RelatedRecordSource = 'database' | 'cache';
|
|
63
|
+
/**
|
|
64
|
+
* What happens to a child that is removed from the collection.
|
|
65
|
+
*
|
|
66
|
+
* - `'delete'` — the row is deleted when the parent saves. Correct for true composition, where a
|
|
67
|
+
* child has no meaning without its parent (order lines, journal entry lines).
|
|
68
|
+
* - `'orphan'` — the row is left in place, foreign key untouched. Correct for aggregation, where
|
|
69
|
+
* the child outlives the relationship.
|
|
70
|
+
* - `'refuse'` — removal throws. For collections where detaching a child is always a bug.
|
|
71
|
+
*/
|
|
72
|
+
export type RelatedRecordRemovalMode = 'delete' | 'orphan' | 'refuse';
|
|
73
|
+
/**
|
|
74
|
+
* Automatic sequence numbering for a child collection.
|
|
75
|
+
*/
|
|
76
|
+
export type RelatedRecordSequence = {
|
|
77
|
+
/** The child field holding the sequence number (e.g. `'LineNumber'`). */
|
|
78
|
+
Field: string;
|
|
79
|
+
/** The value assigned to the first child. Defaults to 1. */
|
|
80
|
+
From?: number;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Declaration for a {@link RelatedRecordCollection}, supplied to `BaseEntity.DeclareRelatedRecords()`.
|
|
84
|
+
*
|
|
85
|
+
* @remarks
|
|
86
|
+
* **This shape deliberately mirrors `EntityRelationship` metadata**, so a declaration can be
|
|
87
|
+
* hand-written today and code-generated tomorrow from exactly the same information:
|
|
88
|
+
*
|
|
89
|
+
* | Option | Metadata source |
|
|
90
|
+
* |---|---|
|
|
91
|
+
* | {@link RelatedEntity} | `EntityRelationship.RelatedEntity` (column) |
|
|
92
|
+
* | {@link RelatedEntityJoinField} | `EntityRelationship.RelatedEntityJoinField` (column) |
|
|
93
|
+
* | everything else | `EntityRelationship.RelatedRecordCollection` (JSONType, `IRelatedRecordCollectionConfig`) |
|
|
94
|
+
*
|
|
95
|
+
* The two column-backed options are **not** repeated inside the JSON blob — one source of truth
|
|
96
|
+
* each. Keep this type and `metadata/entities/JSONType-interfaces/IRelatedRecordCollectionConfig.ts`
|
|
97
|
+
* in step when adding an option.
|
|
98
|
+
*/
|
|
99
|
+
export type RelatedRecordCollectionOptions = {
|
|
100
|
+
/**
|
|
101
|
+
* The companion's stable name, and the property name callers will use. Also the wire key —
|
|
102
|
+
* see {@link EntityCompanion.Name}.
|
|
103
|
+
*/
|
|
104
|
+
Name: string;
|
|
105
|
+
/**
|
|
106
|
+
* The related entity's name in MJ metadata, e.g. `'MJ_BizApps_Orders: Order Lines'`.
|
|
107
|
+
* Mirrors `EntityRelationship.RelatedEntity`.
|
|
108
|
+
*/
|
|
109
|
+
RelatedEntity: string;
|
|
110
|
+
/**
|
|
111
|
+
* The related entity's field holding the foreign key back to this record, e.g.
|
|
112
|
+
* `'OrderHeaderID'`. Mirrors `EntityRelationship.RelatedEntityJoinField`.
|
|
113
|
+
*/
|
|
114
|
+
RelatedEntityJoinField: string;
|
|
115
|
+
/** `OrderBy` clause used when loading. Strongly recommended for sequenced collections. */
|
|
116
|
+
OrderBy?: string;
|
|
117
|
+
/** When the collection populates itself. Defaults to `'explicit'`. */
|
|
118
|
+
Load?: RelatedRecordLoadMode;
|
|
119
|
+
/** Where records come from. Defaults to `'database'`. */
|
|
120
|
+
Source?: RelatedRecordSource;
|
|
121
|
+
/**
|
|
122
|
+
* Whether the collection refuses mutation. Defaults to `false` — but to `true` when
|
|
123
|
+
* {@link Source} is `'cache'`, because a cache-sourced collection hands out the engine's own
|
|
124
|
+
* entity instances.
|
|
125
|
+
*/
|
|
126
|
+
ReadOnly?: boolean;
|
|
127
|
+
/** What removal means. Defaults to `'delete'`. */
|
|
128
|
+
OnRemove?: RelatedRecordRemovalMode;
|
|
129
|
+
/** Automatic sequence numbering, if the child has a sequence field. */
|
|
130
|
+
Sequence?: RelatedRecordSequence;
|
|
131
|
+
/**
|
|
132
|
+
* Whether the collection clears itself after a successful save.
|
|
133
|
+
*
|
|
134
|
+
* `true` matches the order-line staging pattern, where the collection is a buffer for pending
|
|
135
|
+
* inserts rather than a live view of persisted rows. Defaults to `false`, which keeps the
|
|
136
|
+
* saved children in memory with fresh primary keys — the behavior most callers expect.
|
|
137
|
+
*/
|
|
138
|
+
ClearAfterSave?: boolean;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* One retained child on the wire.
|
|
142
|
+
*/
|
|
143
|
+
export type RelatedRecordCollectionWireItem = {
|
|
144
|
+
/** The child's field values, as produced by `GetAll()`. */
|
|
145
|
+
Fields: Record<string, unknown>;
|
|
146
|
+
/**
|
|
147
|
+
* Whether this child is a pending insert rather than an edit of an existing row.
|
|
148
|
+
*
|
|
149
|
+
* Carried **explicitly** rather than inferred from primary-key presence, because `NewRecord()`
|
|
150
|
+
* generates a UUID for `uniqueidentifier` keys — so a brand-new child already has a populated
|
|
151
|
+
* primary key and is indistinguishable from an existing one by inspection. Inferring would make
|
|
152
|
+
* the server try to load a row that does not exist for every client-created child.
|
|
153
|
+
*/
|
|
154
|
+
IsNew: boolean;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* The wire shape of a serialized child collection.
|
|
158
|
+
*/
|
|
159
|
+
export type RelatedRecordCollectionWire = {
|
|
160
|
+
/** Each retained child. */
|
|
161
|
+
Items: RelatedRecordCollectionWireItem[];
|
|
162
|
+
/** Primary-key field maps for children removed since load, when removal means deletion. */
|
|
163
|
+
Removed: Record<string, unknown>[];
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* A typed collection of child records that travels, validates and persists with its parent.
|
|
167
|
+
*
|
|
168
|
+
* Obtain one via `BaseEntity.DeclareRelatedRecords()` in a subclass constructor or field initialiser —
|
|
169
|
+
* do not construct it directly, or it will not be registered as a companion and will be silently
|
|
170
|
+
* ignored by load, validation and save.
|
|
171
|
+
*
|
|
172
|
+
* @typeParam T - The child entity type.
|
|
173
|
+
*
|
|
174
|
+
* @example Declaring a collection on a shared (client + server) entity subclass
|
|
175
|
+
* ```typescript
|
|
176
|
+
* @RegisterClass(BaseEntity, 'MJ_BizApps_Accounting: Journal Entries')
|
|
177
|
+
* export class JournalEntryEntity extends mjBizAppsAccountingJournalEntryEntity {
|
|
178
|
+
* public readonly Lines = this.DeclareRelatedRecords<JournalEntryLineEntity>({
|
|
179
|
+
* Name: 'Lines',
|
|
180
|
+
* RelatedEntity: 'MJ_BizApps_Accounting: Journal Entry Lines',
|
|
181
|
+
* RelatedEntityJoinField: 'JournalEntryID',
|
|
182
|
+
* OrderBy: 'LineNumber ASC',
|
|
183
|
+
* Load: 'explicit',
|
|
184
|
+
* OnRemove: 'delete',
|
|
185
|
+
* Sequence: { Field: 'LineNumber', From: 1 },
|
|
186
|
+
* });
|
|
187
|
+
*
|
|
188
|
+
* public override Validate(): ValidationResult {
|
|
189
|
+
* const result = super.Validate(); // fans out to companions
|
|
190
|
+
* assertBalanced(this.Lines.Items, result); // runs on BOTH tiers
|
|
191
|
+
* return result;
|
|
192
|
+
* }
|
|
193
|
+
* }
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export declare class RelatedRecordCollection<T extends BaseEntity = BaseEntity> extends EntityCompanion<RelatedRecordCollectionWire> {
|
|
197
|
+
private items;
|
|
198
|
+
private removed;
|
|
199
|
+
private loaded;
|
|
200
|
+
private readonly options;
|
|
201
|
+
/**
|
|
202
|
+
* @param owner - The parent entity.
|
|
203
|
+
* @param options - The collection declaration.
|
|
204
|
+
*/
|
|
205
|
+
constructor(owner: BaseEntity, options: RelatedRecordCollectionOptions);
|
|
206
|
+
/**
|
|
207
|
+
* Rejects declarations whose combination of options cannot work, at declaration time.
|
|
208
|
+
*
|
|
209
|
+
* CodeGen already refuses these combinations for metadata-declared collections; enforcing them
|
|
210
|
+
* here as well means a hand-written declaration fails immediately with an accurate message,
|
|
211
|
+
* instead of at first read with a misleading one (`populateFromCache` bails on `!IsReadOnly`
|
|
212
|
+
* before ever consulting the donor, so a writable lazy collection used to throw "engine is not
|
|
213
|
+
* loaded yet" even when the engine was fully loaded).
|
|
214
|
+
*/
|
|
215
|
+
private assertDeclarationInvariants;
|
|
216
|
+
/** @inheritdoc */
|
|
217
|
+
get Name(): string;
|
|
218
|
+
/** The child entity's name in MJ metadata. */
|
|
219
|
+
get RelatedEntityName(): string;
|
|
220
|
+
/** The child field holding the foreign key back to the parent. */
|
|
221
|
+
get RelatedEntityJoinField(): string;
|
|
222
|
+
/** The `OrderBy` clause applied when loading, if declared. */
|
|
223
|
+
get OrderByClause(): string | undefined;
|
|
224
|
+
/** When this collection populates itself. */
|
|
225
|
+
get LoadMode(): RelatedRecordLoadMode;
|
|
226
|
+
/** What removal means for this collection. */
|
|
227
|
+
get RemovalMode(): RelatedRecordRemovalMode;
|
|
228
|
+
/** Where this collection's records come from. Defaults to `'database'`. */
|
|
229
|
+
get Source(): RelatedRecordSource;
|
|
230
|
+
/**
|
|
231
|
+
* Whether this collection refuses mutation.
|
|
232
|
+
*
|
|
233
|
+
* Defaults to `false`, **except for a cache-sourced collection**, which defaults to `true`
|
|
234
|
+
* because its records are the engine's own shared instances. An explicit `ReadOnly: false`
|
|
235
|
+
* still wins — and switches the cache path to copying, so the engine's objects stay untouched.
|
|
236
|
+
*/
|
|
237
|
+
get IsReadOnly(): boolean;
|
|
238
|
+
/**
|
|
239
|
+
* The retained children, in order.
|
|
240
|
+
*
|
|
241
|
+
* Read-only by design — mutate through {@link Add}, {@link Create} and {@link Remove} so that
|
|
242
|
+
* removals are tracked, sequence numbers stay correct, and the parent's `Dirty` flag reflects
|
|
243
|
+
* reality. Handing out a mutable array would make all three impossible to guarantee.
|
|
244
|
+
*/
|
|
245
|
+
get Items(): readonly T[];
|
|
246
|
+
/**
|
|
247
|
+
* Iterates the retained records, so the collection works directly with `for…of`, spread and
|
|
248
|
+
* array destructuring:
|
|
249
|
+
*
|
|
250
|
+
* ```typescript
|
|
251
|
+
* for (const param of action.Params) { … }
|
|
252
|
+
* const all = [...action.Params];
|
|
253
|
+
* const [first, ...rest] = action.Params;
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* This is the standard ES2015 iterable protocol — the same one `Map`, `Set` and `NodeList`
|
|
257
|
+
* implement — deliberately chosen over extending `Array`. Subclassing `Array` would inherit
|
|
258
|
+
* `push`, `splice`, `sort` and index assignment, every one of which bypasses the removal
|
|
259
|
+
* tracking, foreign-key stamping and sequence renumbering this class exists to guarantee; and
|
|
260
|
+
* `Symbol.species` would hand `map`/`filter` this constructor, which takes an owner and options
|
|
261
|
+
* rather than a length. Iterability adds the ergonomics without any of that.
|
|
262
|
+
*
|
|
263
|
+
* Use {@link Items} when you want the array itself — `map`, `filter`, `find` and indexing.
|
|
264
|
+
* It is `readonly`, which is what keeps a caller from mutating around the collection's back.
|
|
265
|
+
*
|
|
266
|
+
* @returns An iterator over the retained records, in collection order.
|
|
267
|
+
*/
|
|
268
|
+
[Symbol.iterator](): Iterator<T>;
|
|
269
|
+
/**
|
|
270
|
+
* Alias for {@link Count}, so the collection reads like a collection in the places people expect
|
|
271
|
+
* `length`. Both go through {@link Items}, so both trigger a lazy fill and see a live cache view.
|
|
272
|
+
*/
|
|
273
|
+
get length(): number;
|
|
274
|
+
/**
|
|
275
|
+
* Children removed since the last load or save, awaiting deletion on the next save.
|
|
276
|
+
*
|
|
277
|
+
* Always empty when {@link RemovalMode} is `'orphan'`.
|
|
278
|
+
*/
|
|
279
|
+
get Removed(): readonly T[];
|
|
280
|
+
/**
|
|
281
|
+
* Number of retained related records.
|
|
282
|
+
*
|
|
283
|
+
* Deliberately delegates to {@link Items} rather than reading the backing array: for a `'lazy'`
|
|
284
|
+
* collection `Items` is what triggers population, so reading the raw array here would report 0
|
|
285
|
+
* for a collection that has simply not been touched yet — and `Count === 0` while
|
|
286
|
+
* `Items.length === 2` is the kind of inconsistency nobody debugs quickly. Same reason it picks
|
|
287
|
+
* up a live cache view's refresh.
|
|
288
|
+
*/
|
|
289
|
+
get Count(): number;
|
|
290
|
+
/** Whether this collection has been populated from the database. */
|
|
291
|
+
get IsLoaded(): boolean;
|
|
292
|
+
/**
|
|
293
|
+
* True when saving would produce work: any retained child is dirty or unsaved, or any removal
|
|
294
|
+
* is pending.
|
|
295
|
+
*/
|
|
296
|
+
get Dirty(): boolean;
|
|
297
|
+
/**
|
|
298
|
+
* Appends an existing child entity to the collection.
|
|
299
|
+
*
|
|
300
|
+
* The foreign key is *not* set here — it is stamped at save time, because when the parent is
|
|
301
|
+
* itself new its primary key does not exist yet. See {@link ContributeSaveWork}.
|
|
302
|
+
*
|
|
303
|
+
* @param item - The child to append.
|
|
304
|
+
* @returns The same child, for chaining.
|
|
305
|
+
*/
|
|
306
|
+
Add(item: T): T;
|
|
307
|
+
/**
|
|
308
|
+
* Creates a new, empty child entity, appends it, and returns it.
|
|
309
|
+
*
|
|
310
|
+
* Uses the owner's provider so the child resolves to the right registered subclass on whichever
|
|
311
|
+
* tier this runs — the server subclass on the server, the shared subclass in the browser.
|
|
312
|
+
*
|
|
313
|
+
* @returns The newly created child.
|
|
314
|
+
*/
|
|
315
|
+
Create(): Promise<T>;
|
|
316
|
+
/**
|
|
317
|
+
* Removes a child by instance or index.
|
|
318
|
+
*
|
|
319
|
+
* A child that was already persisted is queued for deletion when {@link RemovalMode} is
|
|
320
|
+
* `'delete'`; an unsaved child is simply dropped, since there is nothing to delete.
|
|
321
|
+
*
|
|
322
|
+
* @param itemOrIndex - The child instance, or its index in {@link Items}.
|
|
323
|
+
* @throws When {@link RemovalMode} is `'refuse'`.
|
|
324
|
+
*/
|
|
325
|
+
Remove(itemOrIndex: T | number): void;
|
|
326
|
+
/** Removes every child. */
|
|
327
|
+
Clear(): void;
|
|
328
|
+
/**
|
|
329
|
+
* Populates the collection from the database.
|
|
330
|
+
*
|
|
331
|
+
* A no-op when the parent is unsaved (there is nothing to be a child of) or when
|
|
332
|
+
* {@link LoadMode} is `'never'`.
|
|
333
|
+
*
|
|
334
|
+
* @remarks
|
|
335
|
+
* A failed load **throws** rather than yielding an empty collection. Silently returning no
|
|
336
|
+
* children makes a populated parent look empty, and anything derived from that — a reversal, a
|
|
337
|
+
* total, a validation decision — is then wrong in a way nothing downstream can detect. Only
|
|
338
|
+
* saves use the boolean-return convention.
|
|
339
|
+
*
|
|
340
|
+
* @param force - Reload even if already loaded.
|
|
341
|
+
*/
|
|
342
|
+
Load(force?: boolean): Promise<void>;
|
|
343
|
+
/** @inheritdoc */
|
|
344
|
+
LoadEager(): Promise<void>;
|
|
345
|
+
/**
|
|
346
|
+
* Replaces the collection's contents with rows already fetched elsewhere.
|
|
347
|
+
*
|
|
348
|
+
* Used by `RunView`'s batched child loading, which issues one `WHERE fk IN (...)` for an entire
|
|
349
|
+
* result set and distributes the rows — turning what would be N+1 queries into 1 + K.
|
|
350
|
+
*
|
|
351
|
+
* @param items - The children belonging to this parent.
|
|
352
|
+
*/
|
|
353
|
+
SetLoadedItems(items: T[]): void;
|
|
354
|
+
/**
|
|
355
|
+
* Throws when the collection is read-only. Called by every mutating entry point.
|
|
356
|
+
*
|
|
357
|
+
* @param operation - The attempted operation, named in the error.
|
|
358
|
+
*/
|
|
359
|
+
private assertMutable;
|
|
360
|
+
/**
|
|
361
|
+
* Attempts to populate this collection from a `BaseEngine` cache without touching the database.
|
|
362
|
+
*
|
|
363
|
+
* Used by `BaseEntity.LoadRelatedRecords()` to resolve the free collections before batching
|
|
364
|
+
* whatever is left into a database round trip.
|
|
365
|
+
*
|
|
366
|
+
* @returns True when the collection was populated from a cache; false when the caller must load
|
|
367
|
+
* it from the database.
|
|
368
|
+
*/
|
|
369
|
+
TryLoadFromCache(): Promise<boolean>;
|
|
370
|
+
/**
|
|
371
|
+
* Fills the collection from whichever loaded engine already caches the related entity.
|
|
372
|
+
*
|
|
373
|
+
* Synchronous by nature — a registry walk plus a `filter` — which is what makes `'lazy'`
|
|
374
|
+
* possible at all. Returns `false` when no loaded engine offers the entity, leaving the
|
|
375
|
+
* collection unloaded so `Load()` can fall back to a query.
|
|
376
|
+
*
|
|
377
|
+
* @returns True when the collection was populated from a cache.
|
|
378
|
+
*/
|
|
379
|
+
/**
|
|
380
|
+
* Re-reads a live cache view when the donor engine has moved on.
|
|
381
|
+
*
|
|
382
|
+
* Only applies to a read-only cache-sourced collection — the case where the records belong to
|
|
383
|
+
* the engine rather than to this collection. A writable cache collection holds COPIES the caller
|
|
384
|
+
* owns, so silently replacing them would discard their edits; and a database-sourced collection
|
|
385
|
+
* is a point-in-time load by definition, which is what callers expect of one.
|
|
386
|
+
*
|
|
387
|
+
* The check is two reference comparisons in the common case, so this stays cheap enough to run
|
|
388
|
+
* on every read.
|
|
389
|
+
*/
|
|
390
|
+
private refreshCacheViewIfStale;
|
|
391
|
+
/**
|
|
392
|
+
* Populates a `'lazy'` collection from cache, or throws explaining why it could not.
|
|
393
|
+
*
|
|
394
|
+
* **A lazy declaration is an assertion.** Writing `Load: 'lazy'` says "an engine caches this
|
|
395
|
+
* entity"; there is no async fallback available from a getter, so if the assertion is wrong the
|
|
396
|
+
* only alternatives are a hard error or a silently empty array. Silence is how
|
|
397
|
+
* `MJAIAgentEntityExtended.Actions` returned `[]` to three call sites indefinitely without
|
|
398
|
+
* anyone noticing — exactly the failure this mechanism exists to end.
|
|
399
|
+
*
|
|
400
|
+
* A donor holding **zero rows** is a perfectly good answer and does not throw; the collection is
|
|
401
|
+
* simply empty. Only the absence of a donor is an error, and the message distinguishes the two
|
|
402
|
+
* ways that happens, because they need opposite fixes.
|
|
403
|
+
*/
|
|
404
|
+
private populateLazyOrThrow;
|
|
405
|
+
/**
|
|
406
|
+
* Whether reading {@link Items} right now will succeed — the guard for display-tier code.
|
|
407
|
+
*
|
|
408
|
+
* A lazy collection's {@link Items} getter **throws** when its donor engine is not available,
|
|
409
|
+
* deliberately: a silently empty array is how the bug this feature replaced went unnoticed for
|
|
410
|
+
* years. That is the right default for business logic, but a template or widget rendering
|
|
411
|
+
* during bootstrap (before anything has awaited the engine's `Config()`) wants "not yet",
|
|
412
|
+
* not an aborted render — and the null-check templates reach for (`@if (entity.Params && …)`)
|
|
413
|
+
* cannot help, because the collection property itself is never null; it is the *read* that
|
|
414
|
+
* throws.
|
|
415
|
+
*
|
|
416
|
+
* ```html
|
|
417
|
+
* @if (action.Params.IsAvailable) {
|
|
418
|
+
* @for (p of action.Params.Items; track p.ID) { … }
|
|
419
|
+
* }
|
|
420
|
+
* ```
|
|
421
|
+
*
|
|
422
|
+
* **This is a predicate, not a second way to read.** There is exactly one accessor — `Items` —
|
|
423
|
+
* so there is no `null`-versus-`[]` ambiguity for a caller to get wrong, and no quiet path that
|
|
424
|
+
* can drift into business logic and re-create the silent-empty bug. `true` here means the very
|
|
425
|
+
* next `Items` read is safe *and already populated*, because deciding the answer requires
|
|
426
|
+
* consulting the donor, and consulting it is what fills the collection.
|
|
427
|
+
*
|
|
428
|
+
* Never triggers a database load, and never throws.
|
|
429
|
+
*/
|
|
430
|
+
get IsAvailable(): boolean;
|
|
431
|
+
/**
|
|
432
|
+
* The engine and property this collection last read from, plus enough about that array to tell
|
|
433
|
+
* cheaply whether it has moved on.
|
|
434
|
+
*
|
|
435
|
+
* A cache-sourced read-only collection is a **live view**, not a snapshot. `.claude/rules/data-access.md`
|
|
436
|
+
* spells out why: an engine responds to entity events either by mutating its array in place or —
|
|
437
|
+
* for ordered configs — by REASSIGNING the property wholesale, so a captured reference silently
|
|
438
|
+
* goes stale. The documented remedy is to resolve per-access from the engine plus the config's
|
|
439
|
+
* property name, which is what this records.
|
|
440
|
+
*
|
|
441
|
+
* Revalidation is deliberately cheap: identity catches a reassignment, length catches an
|
|
442
|
+
* in-place push or splice, and field-level edits need no detection at all because a read-only
|
|
443
|
+
* collection hands out the engine's own instances — the caller is already looking at them.
|
|
444
|
+
*/
|
|
445
|
+
private cacheDonor;
|
|
446
|
+
private populateFromCache;
|
|
447
|
+
/**
|
|
448
|
+
* Finds this record's related rows in whichever loaded engine already caches the related entity.
|
|
449
|
+
*
|
|
450
|
+
* @returns The matching records in declared order, or `null` when no loaded engine offers the
|
|
451
|
+
* entity — in which case the caller falls back to a database load.
|
|
452
|
+
*/
|
|
453
|
+
private findCachedRecords;
|
|
454
|
+
/**
|
|
455
|
+
* Applies the declared `OrderBy` to cache-sourced records.
|
|
456
|
+
*
|
|
457
|
+
* Only single-field `FIELD [ASC|DESC]` clauses are honored — the common case, and all that can
|
|
458
|
+
* be done in memory without reimplementing SQL. Anything more complex is left in donor order
|
|
459
|
+
* rather than half-applied, because a silently mis-ordered sequenced collection would renumber
|
|
460
|
+
* itself into that wrong order on the next mutation.
|
|
461
|
+
*
|
|
462
|
+
* @param records - The filtered records.
|
|
463
|
+
* @returns A new, ordered array.
|
|
464
|
+
*/
|
|
465
|
+
private sortLikeOrderBy;
|
|
466
|
+
/**
|
|
467
|
+
* Parses the declared `OrderBy` into comparable terms.
|
|
468
|
+
*
|
|
469
|
+
* Handles `FIELD [ASC|DESC]` lists — `'Priority ASC, Name DESC'`. Anything beyond that (an
|
|
470
|
+
* expression, a function call, a CASE) is refused wholesale rather than partially applied,
|
|
471
|
+
* because a *silently* mis-ordered sequenced collection renumbers itself into that wrong order
|
|
472
|
+
* on the next mutation. This is in-memory ordering for cache-sourced collections only; a
|
|
473
|
+
* database-sourced load passes the clause to SQL untouched.
|
|
474
|
+
*
|
|
475
|
+
* @returns One term per field, or an empty array when the clause cannot be honored in memory.
|
|
476
|
+
*/
|
|
477
|
+
private parseOrderBy;
|
|
478
|
+
/**
|
|
479
|
+
* Copies cached records into fresh entity instances, so a writable collection never hands out —
|
|
480
|
+
* or mutates — the engine's own objects. Saving a copy fires the ordinary `BaseEntity` save
|
|
481
|
+
* event that the engines already subscribe to, so their caches refresh themselves.
|
|
482
|
+
*
|
|
483
|
+
* @param records - The engine's cached records.
|
|
484
|
+
* @returns Detached copies carrying the same field values.
|
|
485
|
+
*/
|
|
486
|
+
private copyRecords;
|
|
487
|
+
/** @inheritdoc */
|
|
488
|
+
Validate(result: ValidationResult): void;
|
|
489
|
+
/** @inheritdoc */
|
|
490
|
+
ValidateAsync(result: ValidationResult): Promise<void>;
|
|
491
|
+
/**
|
|
492
|
+
* Prefixes child validation errors with the collection and index they came from.
|
|
493
|
+
*
|
|
494
|
+
* Without this a failing order line reports "Quantity is required" with no indication of *which*
|
|
495
|
+
* line, which is close to useless on a twenty-line order.
|
|
496
|
+
*
|
|
497
|
+
* @param errors - The child's raw validation errors.
|
|
498
|
+
* @param index - The child's position in the collection.
|
|
499
|
+
* @returns Re-labeled errors.
|
|
500
|
+
*/
|
|
501
|
+
private prefixErrors;
|
|
502
|
+
/** @inheritdoc */
|
|
503
|
+
ContributeSaveWork(plan: EntitySavePlan, options?: EntitySaveOptions): void;
|
|
504
|
+
/**
|
|
505
|
+
* Leaves the exact breadcrumb a developer debugging "my edit vanished" needs.
|
|
506
|
+
*
|
|
507
|
+
* Mutating a record obtained from a read-only collection and then saving the PARENT succeeds
|
|
508
|
+
* while persisting nothing — the collection contributes no save work by design, and `Dirty`
|
|
509
|
+
* deliberately excludes it. That is correct, documented behavior, but it emits no runtime
|
|
510
|
+
* signal at all; this verbose-mode log is the one witness. Save the record directly
|
|
511
|
+
* (`record.Save()`), or declare the collection writable, to persist such edits.
|
|
512
|
+
*/
|
|
513
|
+
private warnIfReadOnlyHoldsDirtyItems;
|
|
514
|
+
/** @inheritdoc */
|
|
515
|
+
ContributeDeleteWork(plan: EntitySavePlan): void;
|
|
516
|
+
/** @inheritdoc */
|
|
517
|
+
AcceptChanges(): void;
|
|
518
|
+
/** @inheritdoc */
|
|
519
|
+
Serialize(): Promise<RelatedRecordCollectionWire | null>;
|
|
520
|
+
/** @inheritdoc */
|
|
521
|
+
Deserialize(data: RelatedRecordCollectionWire, mode?: EntityCompanionDeserializeMode): Promise<void>;
|
|
522
|
+
/**
|
|
523
|
+
* Rebuilds retained child entity objects from the wire.
|
|
524
|
+
*
|
|
525
|
+
* Each child is created through the provider, so it resolves to whatever subclass is registered
|
|
526
|
+
* on **this** tier. That is what makes a graph assembled in the browser execute server-side
|
|
527
|
+
* business logic: the server rebuilds the same records as their server subclasses.
|
|
528
|
+
*
|
|
529
|
+
* @param provider - The provider to create entity objects from.
|
|
530
|
+
* @param rows - Wire items.
|
|
531
|
+
* @returns Rehydrated child entities.
|
|
532
|
+
*/
|
|
533
|
+
private rehydrateItems;
|
|
534
|
+
/**
|
|
535
|
+
* Rebuilds the children queued for deletion. Only identity is carried, so these are loaded from
|
|
536
|
+
* their primary keys — a delete needs the real row, not the sender's view of its fields.
|
|
537
|
+
*
|
|
538
|
+
* A removal whose row has already vanished is skipped rather than failing the graph: the intent
|
|
539
|
+
* ("this should not exist") is already satisfied.
|
|
540
|
+
*
|
|
541
|
+
* @param provider - The provider to create entity objects from.
|
|
542
|
+
* @param rows - Primary-key maps.
|
|
543
|
+
* @returns Loaded child entities to delete.
|
|
544
|
+
*/
|
|
545
|
+
private rehydrateRemovals;
|
|
546
|
+
/**
|
|
547
|
+
* Extracts just the primary-key fields of a child, for the `Removed` payload.
|
|
548
|
+
*
|
|
549
|
+
* Removals only need identity — shipping the whole row would waste bandwidth and invite the
|
|
550
|
+
* server to act on stale field values for a record it is about to delete.
|
|
551
|
+
*
|
|
552
|
+
* @param child - The removed child.
|
|
553
|
+
* @returns A map of primary-key field names to values.
|
|
554
|
+
*/
|
|
555
|
+
private primaryKeyOf;
|
|
556
|
+
/**
|
|
557
|
+
* Copies the parent's primary key into every retained record's foreign-key field.
|
|
558
|
+
*
|
|
559
|
+
* Called at add time, at validation time and again immediately before each record is written.
|
|
560
|
+
* Doing it early keeps the in-memory graph coherent — `line.OrderHeaderID` is populated as soon
|
|
561
|
+
* as the line is added, which is what a caller inspecting the object expects, and what lets a
|
|
562
|
+
* `NOT NULL` foreign key pass validation on a create. Doing it again at execution time covers
|
|
563
|
+
* identity/auto-increment parents, whose key genuinely does not exist until their row is
|
|
564
|
+
* inserted.
|
|
565
|
+
*
|
|
566
|
+
* A parent with no key yet is skipped rather than stamping `undefined` over a value that may
|
|
567
|
+
* already be correct.
|
|
568
|
+
*/
|
|
569
|
+
private stampParentKey;
|
|
570
|
+
/**
|
|
571
|
+
* Renumbers retained children when the collection declares a sequence field.
|
|
572
|
+
*
|
|
573
|
+
* Runs on every add and remove so the sequence is always contiguous and gap-free, which is what
|
|
574
|
+
* callers assume when they display or reference "line 3".
|
|
575
|
+
*/
|
|
576
|
+
private applySequence;
|
|
577
|
+
}
|
|
578
|
+
//# sourceMappingURL=relatedRecordCollection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relatedRecordCollection.d.ts","sourceRoot":"","sources":["../../src/generic/relatedRecordCollection.ts"],"names":[],"mappings":"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"}
|