@memberjunction/version-history 0.0.1 → 4.0.0

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.
@@ -0,0 +1,97 @@
1
+ import { UserInfo } from '@memberjunction/core';
2
+ import { RestoreOptions, RestoreResult } from './types.js';
3
+ /**
4
+ * Restores records to the state captured by a version label.
5
+ *
6
+ * Key behaviors:
7
+ * - Automatically creates a "Pre-Restore" safety label before making changes
8
+ * - Restores in topological order (parents before children) based on entity
9
+ * relationships to maintain referential integrity
10
+ * - Tracks progress and errors in a VersionLabelRestore audit record
11
+ * - Supports dry-run mode for previewing changes without applying them
12
+ */
13
+ export declare class RestoreEngine {
14
+ private LabelMgr;
15
+ private SnapshotBldr;
16
+ /**
17
+ * Restore records to the state captured by a version label.
18
+ */
19
+ RestoreToLabel(labelId: string, options: RestoreOptions, contextUser: UserInfo): Promise<RestoreResult>;
20
+ /**
21
+ * Process all restore items in order, tracking progress and updating the
22
+ * audit record in batches.
23
+ */
24
+ private processRestoreItems;
25
+ /**
26
+ * Load all VersionLabelItems for a label, optionally filtered.
27
+ */
28
+ private loadLabelItems;
29
+ /**
30
+ * Filter label items to only include those matching a set of selected records.
31
+ */
32
+ private filterBySelectedRecords;
33
+ /**
34
+ * Sort label items by entity dependency order so parents are restored
35
+ * before their children.
36
+ */
37
+ private sortByDependencyOrder;
38
+ /**
39
+ * Restore a single record to its labeled state.
40
+ */
41
+ private restoreSingleItem;
42
+ /**
43
+ * Resolve entity metadata by ID.
44
+ */
45
+ private resolveEntityInfo;
46
+ /**
47
+ * Apply the snapshot data to an existing or new entity and save it.
48
+ */
49
+ private applyRestore;
50
+ /**
51
+ * Build a failed RestoreItemResult.
52
+ */
53
+ private failedItemResult;
54
+ /**
55
+ * Load an existing entity record, or create a new one if it doesn't exist.
56
+ */
57
+ private loadOrCreateEntity;
58
+ /**
59
+ * Apply snapshot data to an entity, setting each field from the snapshot.
60
+ * Returns true if any field was changed.
61
+ */
62
+ private applySnapshotToEntity;
63
+ /**
64
+ * Check if two values are meaningfully different.
65
+ */
66
+ private valuesDiffer;
67
+ /**
68
+ * Create a "Pre-Restore" safety label capturing current state of all
69
+ * records that will be affected by the restore.
70
+ */
71
+ private createPreRestoreLabel;
72
+ /**
73
+ * Create a VersionLabelRestore audit record.
74
+ */
75
+ private createRestoreAuditRecord;
76
+ /**
77
+ * Update restore progress counters.
78
+ */
79
+ private updateRestoreProgress;
80
+ /**
81
+ * Finalize the restore audit record.
82
+ */
83
+ private finalizeRestoreAudit;
84
+ /**
85
+ * Determine the overall status based on counts.
86
+ */
87
+ private determineFinalStatus;
88
+ /**
89
+ * Apply defaults to restore options.
90
+ */
91
+ private resolveDefaults;
92
+ /**
93
+ * Create an empty result (used when there's nothing to restore).
94
+ */
95
+ private emptyResult;
96
+ }
97
+ //# sourceMappingURL=RestoreEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RestoreEngine.d.ts","sourceRoot":"","sources":["../src/RestoreEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAMH,QAAQ,EAGX,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EAEH,cAAc,EACd,aAAa,EAGhB,MAAM,SAAS,CAAC;AAiBjB;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,YAAY,CAAyB;IAE7C;;OAEG;IACU,cAAc,CACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,aAAa,CAAC;IAoEzB;;;OAGG;YACW,mBAAmB;IAsCjC;;OAEG;YACW,cAAc;IAyC5B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAe/B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA8C7B;;OAEG;YACW,iBAAiB;IA8B/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;OAEG;YACW,YAAY;IAwB1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;OAEG;YACW,kBAAkB;IAqBhC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA0B7B;;OAEG;IACH,OAAO,CAAC,YAAY;IAMpB;;;OAGG;YACW,qBAAqB;IAuCnC;;OAEG;YACW,wBAAwB;IA2BtC;;OAEG;YACW,qBAAqB;IAoBnC;;OAEG;YACW,oBAAoB;IA6BlC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,OAAO,CAAC,WAAW;CAWtB"}
@@ -0,0 +1,432 @@
1
+ import { CompositeKey, Metadata, RunView, LogError, LogStatus, } from '@memberjunction/core';
2
+ import { LabelManager } from './LabelManager.js';
3
+ import { SnapshotBuilder } from './SnapshotBuilder.js';
4
+ import { ENTITY_VERSION_LABEL_ITEMS, ENTITY_VERSION_LABEL_RESTORES, ENTITY_VERSION_LABELS, sqlEquals, sqlNotIn, loadRecordChangeSnapshot, loadEntityById, buildPrimaryKeyForLoad, } from './constants.js';
5
+ /** Batch size for progress update writes — only persist every N items. */
6
+ const PROGRESS_UPDATE_INTERVAL = 10;
7
+ /**
8
+ * Restores records to the state captured by a version label.
9
+ *
10
+ * Key behaviors:
11
+ * - Automatically creates a "Pre-Restore" safety label before making changes
12
+ * - Restores in topological order (parents before children) based on entity
13
+ * relationships to maintain referential integrity
14
+ * - Tracks progress and errors in a VersionLabelRestore audit record
15
+ * - Supports dry-run mode for previewing changes without applying them
16
+ */
17
+ export class RestoreEngine {
18
+ constructor() {
19
+ this.LabelMgr = new LabelManager();
20
+ this.SnapshotBldr = new SnapshotBuilder();
21
+ }
22
+ /**
23
+ * Restore records to the state captured by a version label.
24
+ */
25
+ async RestoreToLabel(labelId, options, contextUser) {
26
+ const resolvedOptions = this.resolveDefaults(options);
27
+ // Load the target label
28
+ const label = await loadEntityById(ENTITY_VERSION_LABELS, labelId, contextUser);
29
+ if (!label)
30
+ throw new Error(`Version label '${labelId}' not found`);
31
+ const labelName = label.Name;
32
+ const labelScope = label.Scope;
33
+ LogStatus(`VersionHistory: Starting restore to label '${labelName}' (${labelId})`);
34
+ // Load all label items to restore
35
+ const items = await this.loadLabelItems(labelId, resolvedOptions, contextUser);
36
+ if (items.length === 0) {
37
+ LogStatus('VersionHistory: No items to restore');
38
+ return this.emptyResult(resolvedOptions.DryRun);
39
+ }
40
+ // Create pre-restore safety label
41
+ let preRestoreLabelId = null;
42
+ if (resolvedOptions.CreatePreRestoreLabel && !resolvedOptions.DryRun) {
43
+ preRestoreLabelId = await this.createPreRestoreLabel(labelName, labelScope, items, contextUser);
44
+ }
45
+ // Create the restore audit record
46
+ let restoreAuditId = null;
47
+ if (!resolvedOptions.DryRun) {
48
+ restoreAuditId = await this.createRestoreAuditRecord(labelId, items.length, preRestoreLabelId, contextUser);
49
+ }
50
+ // Sort items by entity dependency order and process them
51
+ const sortedItems = this.sortByDependencyOrder(items);
52
+ const { details, restoredCount, failedCount, skippedCount } = await this.processRestoreItems(sortedItems, resolvedOptions.DryRun, restoreAuditId, contextUser);
53
+ // Finalize the audit record
54
+ const finalStatus = this.determineFinalStatus(restoredCount, failedCount, items.length);
55
+ if (restoreAuditId && !resolvedOptions.DryRun) {
56
+ await this.finalizeRestoreAudit(restoreAuditId, finalStatus, failedCount, details, contextUser);
57
+ }
58
+ // Mark the label as restored
59
+ if (!resolvedOptions.DryRun && finalStatus !== 'Error') {
60
+ await this.LabelMgr.MarkLabelRestored(labelId, contextUser);
61
+ }
62
+ LogStatus(`VersionHistory: Restore complete. ${restoredCount} restored, ${failedCount} failed, ${skippedCount} skipped.`);
63
+ return {
64
+ RestoreID: restoreAuditId ?? 'dry-run',
65
+ PreRestoreLabelID: preRestoreLabelId,
66
+ Status: finalStatus,
67
+ RestoredCount: restoredCount,
68
+ FailedCount: failedCount,
69
+ SkippedCount: skippedCount,
70
+ Details: details,
71
+ };
72
+ }
73
+ // -----------------------------------------------------------------------
74
+ // Private helpers
75
+ // -----------------------------------------------------------------------
76
+ /**
77
+ * Process all restore items in order, tracking progress and updating the
78
+ * audit record in batches.
79
+ */
80
+ async processRestoreItems(sortedItems, dryRun, restoreAuditId, contextUser) {
81
+ const details = [];
82
+ let restoredCount = 0;
83
+ let failedCount = 0;
84
+ let skippedCount = 0;
85
+ for (let i = 0; i < sortedItems.length; i++) {
86
+ const result = await this.restoreSingleItem(sortedItems[i], dryRun, contextUser);
87
+ details.push(result);
88
+ switch (result.Status) {
89
+ case 'Restored':
90
+ restoredCount++;
91
+ break;
92
+ case 'Failed':
93
+ failedCount++;
94
+ break;
95
+ case 'Skipped':
96
+ skippedCount++;
97
+ break;
98
+ }
99
+ // Batch progress updates — only write every N items or on the last item
100
+ const isLastItem = i === sortedItems.length - 1;
101
+ const isBatchBoundary = (i + 1) % PROGRESS_UPDATE_INTERVAL === 0;
102
+ if (restoreAuditId && !dryRun && (isBatchBoundary || isLastItem)) {
103
+ await this.updateRestoreProgress(restoreAuditId, restoredCount, failedCount, contextUser);
104
+ }
105
+ }
106
+ return { details, restoredCount, failedCount, skippedCount };
107
+ }
108
+ /**
109
+ * Load all VersionLabelItems for a label, optionally filtered.
110
+ */
111
+ async loadLabelItems(labelId, options, contextUser) {
112
+ const rv = new RunView();
113
+ let extraFilter = sqlEquals('VersionLabelID', labelId);
114
+ // Apply entity exclusion
115
+ if (options.SkipEntities && options.SkipEntities.length > 0) {
116
+ const md = new Metadata();
117
+ const excludeIds = options.SkipEntities
118
+ .map(name => md.EntityByName(name)?.ID)
119
+ .filter((id) => id != null);
120
+ if (excludeIds.length > 0) {
121
+ extraFilter += ` AND ${sqlNotIn('EntityID', excludeIds)}`;
122
+ }
123
+ }
124
+ const result = await rv.RunView({
125
+ EntityName: ENTITY_VERSION_LABEL_ITEMS,
126
+ ExtraFilter: extraFilter,
127
+ ResultType: 'simple',
128
+ }, contextUser);
129
+ if (!result.Success) {
130
+ LogError(`RestoreEngine: Failed to load label items: ${result.ErrorMessage}`);
131
+ return [];
132
+ }
133
+ let items = result.Results;
134
+ // Apply selected records filter
135
+ if (options.Scope === 'Selected' && options.SelectedRecords && options.SelectedRecords.length > 0) {
136
+ items = this.filterBySelectedRecords(items, options.SelectedRecords);
137
+ }
138
+ return items;
139
+ }
140
+ /**
141
+ * Filter label items to only include those matching a set of selected records.
142
+ */
143
+ filterBySelectedRecords(items, selectedRecords) {
144
+ const selectedSet = new Set(selectedRecords.map(s => `${s.EntityName}::${s.RecordID}`));
145
+ const md = new Metadata();
146
+ return items.filter(item => {
147
+ const entityInfo = md.Entities.find(e => e.ID === item.EntityID);
148
+ const entityName = entityInfo?.Name ?? '';
149
+ return selectedSet.has(`${entityName}::${item.RecordID}`);
150
+ });
151
+ }
152
+ /**
153
+ * Sort label items by entity dependency order so parents are restored
154
+ * before their children.
155
+ */
156
+ sortByDependencyOrder(items) {
157
+ const md = new Metadata();
158
+ // Build a map of entityId -> dependency level
159
+ const levelMap = new Map();
160
+ const visited = new Set();
161
+ const computeLevel = (entityId) => {
162
+ if (levelMap.has(entityId))
163
+ return levelMap.get(entityId);
164
+ if (visited.has(entityId))
165
+ return 0; // Cycle — break it
166
+ visited.add(entityId);
167
+ const entityInfo = md.Entities.find(e => e.ID === entityId);
168
+ if (!entityInfo) {
169
+ levelMap.set(entityId, 0);
170
+ return 0;
171
+ }
172
+ // Find all FK fields pointing to other entities
173
+ let maxParentLevel = -1;
174
+ for (const field of entityInfo.Fields) {
175
+ if (field.RelatedEntityID && field.RelatedEntityID !== entityId) {
176
+ const parentLevel = computeLevel(field.RelatedEntityID);
177
+ maxParentLevel = Math.max(maxParentLevel, parentLevel);
178
+ }
179
+ }
180
+ const level = maxParentLevel + 1;
181
+ levelMap.set(entityId, level);
182
+ return level;
183
+ };
184
+ // Compute levels for all entities in the item set
185
+ const entityIds = new Set(items.map(i => i.EntityID));
186
+ for (const entityId of entityIds) {
187
+ computeLevel(entityId);
188
+ }
189
+ // Sort: lower level (parents) first
190
+ return [...items].sort((a, b) => {
191
+ const levelA = levelMap.get(a.EntityID) ?? 0;
192
+ const levelB = levelMap.get(b.EntityID) ?? 0;
193
+ return levelA - levelB;
194
+ });
195
+ }
196
+ /**
197
+ * Restore a single record to its labeled state.
198
+ */
199
+ async restoreSingleItem(item, dryRun, contextUser) {
200
+ const entityInfo = this.resolveEntityInfo(item.EntityID);
201
+ if (!entityInfo) {
202
+ return this.failedItemResult(`Unknown(${item.EntityID})`, item.RecordID, `Entity with ID '${item.EntityID}' not found in metadata`);
203
+ }
204
+ try {
205
+ const snapshotData = await loadRecordChangeSnapshot(item.RecordChangeID, contextUser);
206
+ if (!snapshotData) {
207
+ return this.failedItemResult(entityInfo.Name, item.RecordID, 'Could not load snapshot from RecordChange');
208
+ }
209
+ if (dryRun) {
210
+ return { EntityName: entityInfo.Name, RecordID: item.RecordID, Status: 'Restored' };
211
+ }
212
+ return await this.applyRestore(entityInfo, item.RecordID, snapshotData, contextUser);
213
+ }
214
+ catch (e) {
215
+ const msg = e instanceof Error ? e.message : String(e);
216
+ LogError(`RestoreEngine: Error restoring ${entityInfo.Name}/${item.RecordID}: ${msg}`);
217
+ return this.failedItemResult(entityInfo.Name, item.RecordID, msg);
218
+ }
219
+ }
220
+ /**
221
+ * Resolve entity metadata by ID.
222
+ */
223
+ resolveEntityInfo(entityId) {
224
+ const md = new Metadata();
225
+ return md.Entities.find(e => e.ID === entityId) ?? null;
226
+ }
227
+ /**
228
+ * Apply the snapshot data to an existing or new entity and save it.
229
+ */
230
+ async applyRestore(entityInfo, recordId, snapshotData, contextUser) {
231
+ const entity = await this.loadOrCreateEntity(entityInfo, recordId, contextUser);
232
+ if (!entity) {
233
+ return this.failedItemResult(entityInfo.Name, recordId, 'Could not load entity for restore');
234
+ }
235
+ const changed = this.applySnapshotToEntity(entity, snapshotData, entityInfo);
236
+ if (!changed) {
237
+ return { EntityName: entityInfo.Name, RecordID: recordId, Status: 'Skipped' };
238
+ }
239
+ const saved = await entity.Save();
240
+ if (!saved) {
241
+ return this.failedItemResult(entityInfo.Name, recordId, 'Save failed');
242
+ }
243
+ return { EntityName: entityInfo.Name, RecordID: recordId, Status: 'Restored' };
244
+ }
245
+ /**
246
+ * Build a failed RestoreItemResult.
247
+ */
248
+ failedItemResult(entityName, recordId, errorMessage) {
249
+ return { EntityName: entityName, RecordID: recordId, Status: 'Failed', ErrorMessage: errorMessage };
250
+ }
251
+ /**
252
+ * Load an existing entity record, or create a new one if it doesn't exist.
253
+ */
254
+ async loadOrCreateEntity(entityInfo, recordId, contextUser) {
255
+ const md = new Metadata();
256
+ const entity = await md.GetEntityObject(entityInfo.Name, contextUser);
257
+ // Try to load existing record using the entity's actual primary key
258
+ try {
259
+ const key = buildPrimaryKeyForLoad(entityInfo, recordId);
260
+ const loaded = await entity.InnerLoad(key);
261
+ if (loaded)
262
+ return entity;
263
+ }
264
+ catch {
265
+ // Record doesn't exist — fall through to create
266
+ }
267
+ // Record doesn't exist; return fresh entity for insert
268
+ return await md.GetEntityObject(entityInfo.Name, contextUser);
269
+ }
270
+ /**
271
+ * Apply snapshot data to an entity, setting each field from the snapshot.
272
+ * Returns true if any field was changed.
273
+ */
274
+ applySnapshotToEntity(entity, snapshotData, entityInfo) {
275
+ let anyChanged = false;
276
+ for (const field of entityInfo.Fields) {
277
+ // Skip read-only, primary key, and system fields
278
+ if (field.ReadOnly)
279
+ continue;
280
+ if (field.IsPrimaryKey)
281
+ continue;
282
+ if (field.Name.startsWith('__mj_'))
283
+ continue;
284
+ const snapshotValue = snapshotData[field.Name];
285
+ if (snapshotValue === undefined)
286
+ continue;
287
+ const currentValue = entity.Get(field.Name);
288
+ if (!this.valuesDiffer(currentValue, snapshotValue))
289
+ continue;
290
+ entity.Set(field.Name, snapshotValue);
291
+ anyChanged = true;
292
+ }
293
+ return anyChanged;
294
+ }
295
+ /**
296
+ * Check if two values are meaningfully different.
297
+ */
298
+ valuesDiffer(a, b) {
299
+ if (a === b)
300
+ return false;
301
+ if (a == null && b == null)
302
+ return false;
303
+ return String(a) !== String(b);
304
+ }
305
+ /**
306
+ * Create a "Pre-Restore" safety label capturing current state of all
307
+ * records that will be affected by the restore.
308
+ */
309
+ async createPreRestoreLabel(targetLabelName, targetLabelScope, items, contextUser) {
310
+ const label = await this.LabelMgr.CreateLabel({
311
+ Name: `Pre-Restore: ${targetLabelName} (${new Date().toISOString()})`,
312
+ Description: `Automatic safety snapshot created before restoring to label '${targetLabelName}'`,
313
+ Scope: targetLabelScope,
314
+ }, contextUser);
315
+ const preRestoreLabelId = label.ID;
316
+ const md = new Metadata();
317
+ // Capture current state of each record that will be restored
318
+ for (const item of items) {
319
+ const entityInfo = md.Entities.find(e => e.ID === item.EntityID);
320
+ if (!entityInfo)
321
+ continue;
322
+ const key = new CompositeKey([{
323
+ FieldName: entityInfo.FirstPrimaryKey.Name,
324
+ Value: item.RecordID,
325
+ }]);
326
+ await this.SnapshotBldr.CaptureRecord(preRestoreLabelId, entityInfo.Name, key, false, // Don't walk dependencies — we already have the full item list
327
+ {}, contextUser);
328
+ }
329
+ LogStatus(`VersionHistory: Created pre-restore safety label (${preRestoreLabelId})`);
330
+ return preRestoreLabelId;
331
+ }
332
+ /**
333
+ * Create a VersionLabelRestore audit record.
334
+ */
335
+ async createRestoreAuditRecord(labelId, totalItems, preRestoreLabelId, contextUser) {
336
+ const md = new Metadata();
337
+ const restore = await md.GetEntityObject(ENTITY_VERSION_LABEL_RESTORES, contextUser);
338
+ restore.VersionLabelID = labelId;
339
+ restore.Status = 'In Progress';
340
+ restore.UserID = contextUser.ID;
341
+ restore.TotalItems = totalItems;
342
+ restore.CompletedItems = 0;
343
+ restore.FailedItems = 0;
344
+ if (preRestoreLabelId) {
345
+ restore.PreRestoreLabelID = preRestoreLabelId;
346
+ }
347
+ const saved = await restore.Save();
348
+ if (!saved) {
349
+ throw new Error('Failed to create restore audit record');
350
+ }
351
+ return restore.ID;
352
+ }
353
+ /**
354
+ * Update restore progress counters.
355
+ */
356
+ async updateRestoreProgress(restoreId, completedItems, failedItems, contextUser) {
357
+ try {
358
+ const restore = await loadEntityById(ENTITY_VERSION_LABEL_RESTORES, restoreId, contextUser);
359
+ if (!restore)
360
+ return;
361
+ restore.CompletedItems = completedItems;
362
+ restore.FailedItems = failedItems;
363
+ await restore.Save();
364
+ }
365
+ catch (e) {
366
+ // Non-critical — progress update failure shouldn't stop the restore
367
+ const msg = e instanceof Error ? e.message : String(e);
368
+ LogError(`RestoreEngine: Failed to update restore progress for ${restoreId}: ${msg}`);
369
+ }
370
+ }
371
+ /**
372
+ * Finalize the restore audit record.
373
+ */
374
+ async finalizeRestoreAudit(restoreId, status, failedCount, details, contextUser) {
375
+ try {
376
+ const restore = await loadEntityById(ENTITY_VERSION_LABEL_RESTORES, restoreId, contextUser);
377
+ if (!restore)
378
+ return;
379
+ restore.Status = status;
380
+ restore.EndedAt = new Date();
381
+ if (failedCount > 0) {
382
+ const errorItems = details
383
+ .filter(d => d.Status === 'Failed')
384
+ .map(d => `${d.EntityName}/${d.RecordID}: ${d.ErrorMessage ?? 'Unknown'}`)
385
+ .join('\n');
386
+ restore.ErrorLog = errorItems;
387
+ }
388
+ await restore.Save();
389
+ }
390
+ catch (e) {
391
+ const msg = e instanceof Error ? e.message : String(e);
392
+ LogError(`RestoreEngine: Error finalizing audit record: ${msg}`);
393
+ }
394
+ }
395
+ /**
396
+ * Determine the overall status based on counts.
397
+ */
398
+ determineFinalStatus(restored, failed, _total) {
399
+ if (failed === 0)
400
+ return 'Complete';
401
+ if (restored === 0)
402
+ return 'Error';
403
+ return 'Partial';
404
+ }
405
+ /**
406
+ * Apply defaults to restore options.
407
+ */
408
+ resolveDefaults(options) {
409
+ return {
410
+ DryRun: options.DryRun ?? false,
411
+ Scope: options.Scope ?? 'Full',
412
+ SelectedRecords: options.SelectedRecords ?? [],
413
+ SkipEntities: options.SkipEntities ?? [],
414
+ CreatePreRestoreLabel: options.CreatePreRestoreLabel ?? true,
415
+ };
416
+ }
417
+ /**
418
+ * Create an empty result (used when there's nothing to restore).
419
+ */
420
+ emptyResult(dryRun) {
421
+ return {
422
+ RestoreID: dryRun ? 'dry-run' : '',
423
+ PreRestoreLabelID: null,
424
+ Status: 'Complete',
425
+ RestoredCount: 0,
426
+ FailedCount: 0,
427
+ SkippedCount: 0,
428
+ Details: [],
429
+ };
430
+ }
431
+ }
432
+ //# sourceMappingURL=RestoreEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RestoreEngine.js","sourceRoot":"","sources":["../src/RestoreEngine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import { CompositeKey, UserInfo } from '@memberjunction/core';
2
+ import { CaptureResult, CreateLabelProgressCallback, WalkOptions } from './types.js';
3
+ /**
4
+ * Captures the current state of records into VersionLabelItem entries,
5
+ * linking each record to its most recent RecordChange snapshot.
6
+ *
7
+ * ## Batched approach
8
+ *
9
+ * When capturing a dependency graph, the builder:
10
+ * 1. Groups all nodes by EntityID
11
+ * 2. For each entity group, runs ONE batched query to find the latest
12
+ * RecordChange for all records in the group
13
+ * 3. Creates synthetic snapshots for records with no change history
14
+ * 4. Creates VersionLabelItem entries for all records
15
+ *
16
+ * This reduces hundreds/thousands of individual RunView calls down to
17
+ * a handful of batched queries (one per unique entity type).
18
+ */
19
+ export declare class SnapshotBuilder {
20
+ private Walker;
21
+ /**
22
+ * Capture a snapshot of a single record and optionally its full dependency graph.
23
+ */
24
+ CaptureRecord(labelId: string, entityName: string, recordKey: CompositeKey, includeDependencies: boolean, walkOptions: WalkOptions, contextUser: UserInfo, onProgress?: CreateLabelProgressCallback): Promise<CaptureResult>;
25
+ /**
26
+ * Capture all records of a given entity type.
27
+ */
28
+ CaptureEntity(labelId: string, entityName: string, contextUser: UserInfo): Promise<CaptureResult>;
29
+ /**
30
+ * Capture all tracked entities (System scope).
31
+ */
32
+ CaptureSystem(labelId: string, contextUser: UserInfo): Promise<CaptureResult>;
33
+ /**
34
+ * Walk the dependency graph and capture all nodes using batched queries.
35
+ *
36
+ * Steps:
37
+ * 1. Walk the dependency graph to get all nodes
38
+ * 2. Batch-lookup the latest RecordChange for all nodes (grouped by entity)
39
+ * 3. Create synthetic snapshots for nodes without a RecordChange
40
+ * 4. Create VersionLabelItem entries for all nodes
41
+ */
42
+ private captureWithDependencies;
43
+ /** Safely invoke the progress callback if provided. */
44
+ private emitProgress;
45
+ /**
46
+ * Batch-lookup the latest RecordChange for a list of dependency nodes.
47
+ *
48
+ * Groups nodes by EntityID, then runs ONE query per entity group with an
49
+ * IN clause for all RecordIDs. Returns a map keyed by "entityId::recordId"
50
+ * with the latest RecordChange ID and timestamp.
51
+ *
52
+ * This replaces N individual RunView calls with ~K calls (K = unique entity types).
53
+ */
54
+ private batchLookupLatestChanges;
55
+ /**
56
+ * Group dependency nodes by EntityID, collecting unique RecordIDs per entity.
57
+ * Returns a Map of entityId → Set of recordIds.
58
+ */
59
+ private groupNodesByEntity;
60
+ /**
61
+ * Query Record Changes for a single entity group.
62
+ * Uses an IN clause to find the latest change for each record in one query.
63
+ *
64
+ * Returns a Map of "entityId::recordId" → RecordChangeLookup.
65
+ */
66
+ private lookupChangesForEntityGroup;
67
+ /**
68
+ * Query Record Changes for a chunk of RecordIDs within a single entity.
69
+ * Loads all matching changes ordered by RecordID and ChangedAt DESC,
70
+ * then picks the latest change per record.
71
+ */
72
+ private lookupChangesChunk;
73
+ /**
74
+ * Capture a single dependency node using the pre-built change lookup.
75
+ * If no existing RecordChange is found, creates a synthetic snapshot.
76
+ */
77
+ private captureNodeWithLookup;
78
+ /**
79
+ * Capture a single record without batching. Used by CaptureEntity and
80
+ * the non-dependency CaptureRecord path.
81
+ */
82
+ private captureSingleRecord;
83
+ /**
84
+ * Wrapper for captureSingleRecord that returns a CaptureResult.
85
+ */
86
+ private captureSingleRecordAsResult;
87
+ /**
88
+ * Find the most recent RecordChange for a single entity + record.
89
+ * Used by the non-batched capture path.
90
+ */
91
+ private findLatestRecordChange;
92
+ /**
93
+ * Create a synthetic RecordChange entry of Type='Snapshot' for a record
94
+ * that has no prior change history.
95
+ */
96
+ private createSyntheticSnapshot;
97
+ /**
98
+ * Create a VersionLabelItem linking a record to its RecordChange.
99
+ */
100
+ private createLabelItem;
101
+ /**
102
+ * Load the current state of a single record.
103
+ */
104
+ private loadCurrentRecord;
105
+ /** Create a failure CaptureResult. */
106
+ private failResult;
107
+ }
108
+ //# sourceMappingURL=SnapshotBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SnapshotBuilder.d.ts","sourceRoot":"","sources":["../src/SnapshotBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EAIZ,QAAQ,EAGX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAgB,aAAa,EAAE,2BAA2B,EAAkB,WAAW,EAAE,MAAM,SAAS,CAAC;AA+BhH;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,MAAM,CAA+B;IAM7C;;OAEG;IACU,aAAa,CACtB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,YAAY,EACvB,mBAAmB,EAAE,OAAO,EAC5B,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,QAAQ,EACrB,UAAU,CAAC,EAAE,2BAA2B,GACzC,OAAO,CAAC,aAAa,CAAC;IAOzB;;OAEG;IACU,aAAa,CACtB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,aAAa,CAAC;IAgDzB;;OAEG;IACU,aAAa,CACtB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,aAAa,CAAC;IA6BzB;;;;;;;;OAQG;YACW,uBAAuB;IAwFrC,uDAAuD;IACvD,OAAO,CAAC,YAAY;IAiBpB;;;;;;;;OAQG;YACW,wBAAwB;IAwBtC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;;;;OAKG;YACW,2BAA2B;IAuBzC;;;;OAIG;YACW,kBAAkB;IAkDhC;;;OAGG;YACW,qBAAqB;IAuCnC;;;OAGG;YACW,mBAAmB;IA6CjC;;OAEG;YACW,2BAA2B;IA6BzC;;;OAGG;YACW,sBAAsB;IAsBpC;;;OAGG;YACW,uBAAuB;IAiCrC;;OAEG;YACW,eAAe;IAsB7B;;OAEG;YACW,iBAAiB;IAkB/B,sCAAsC;IACtC,OAAO,CAAC,UAAU;CASrB"}