@memberjunction/external-change-detection 1.7.1 → 1.8.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/ChangeDetector.d.ts +82 -2
- package/dist/ChangeDetector.d.ts.map +1 -1
- package/dist/ChangeDetector.js +509 -37
- package/dist/ChangeDetector.js.map +1 -1
- package/package.json +5 -5
package/dist/ChangeDetector.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { BaseEngine, CompositeKey, EntityInfo, UserInfo } from "@memberjunction/core";
|
|
1
|
+
import { BaseEngine, BaseEntity, CompositeKey, EntityField, EntityInfo, Metadata, UserInfo } from "@memberjunction/core";
|
|
2
|
+
import { RecordChangeEntity, RecordChangeReplayRunEntity } from "@memberjunction/core-entities";
|
|
2
3
|
/**
|
|
3
4
|
* Represents a change to a single field in a record
|
|
4
5
|
*/
|
|
@@ -16,6 +17,12 @@ export declare class ChangeDetectionItem {
|
|
|
16
17
|
Type: 'Create' | 'Update' | 'Delete';
|
|
17
18
|
ChangedAt: Date;
|
|
18
19
|
Changes: FieldChange[];
|
|
20
|
+
/**
|
|
21
|
+
* Populated for Create and Update types only. This is the latest version of the record from the organic database table
|
|
22
|
+
*/
|
|
23
|
+
LatestRecord?: BaseEntity;
|
|
24
|
+
LegacyKey?: boolean;
|
|
25
|
+
LegacyKeyValue?: string;
|
|
19
26
|
}
|
|
20
27
|
/**
|
|
21
28
|
* Result type for a change detection operation
|
|
@@ -32,9 +39,27 @@ export declare class ChangeDetectionResult {
|
|
|
32
39
|
export declare class ExternalChangeDetectorEngine extends BaseEngine<ExternalChangeDetectorEngine> {
|
|
33
40
|
Config(forceRefresh?: boolean, contextUser?: UserInfo): Promise<void>;
|
|
34
41
|
static get Instance(): ExternalChangeDetectorEngine;
|
|
42
|
+
private _IneligibleEntities;
|
|
43
|
+
/**
|
|
44
|
+
* A list of entities that will automatically be excluded from all calls to this class. This array is used as a "safety"
|
|
45
|
+
* mechanism to prevent the system from trying to replay changes to these entities which wouldn't negatively affect system integrity
|
|
46
|
+
* but could cause performance issues. If you want to add/remove entities to this list, you can do so by manipulating this array.
|
|
47
|
+
*
|
|
48
|
+
* If you want to run Change Detection and/or replay changes for entities in this array, you will need to remove them
|
|
49
|
+
* in your code before calling the methods in this class. While executing methods on this class with these default
|
|
50
|
+
* ineligible entities will not cause any issues, they may take a long time to run and utilize a significant amount
|
|
51
|
+
* of resources.
|
|
52
|
+
*/
|
|
53
|
+
get IneligibleEntities(): string[];
|
|
35
54
|
private _EligibleEntities;
|
|
36
55
|
/**
|
|
37
|
-
* A list of the entities that are eligible for external change detection
|
|
56
|
+
* A list of the entities that are eligible for external change detection. This is determined by using the underlying
|
|
57
|
+
* database view vwEntitiesWithExternalChangeTracking which is a view that is maintained by the MJ system and is used to
|
|
58
|
+
* find a list of entities that have the required characteristics that support external change detection. These characteristics
|
|
59
|
+
* include:
|
|
60
|
+
* * The entity has the TrackRecordChanges property set to 1
|
|
61
|
+
* * The entity has the special UpdatedAt/CreatedAt fields (which are called __mj_UpdatedAt and __mj_CreatedAt in the database). These fields are AUTOMATICALLY added to an entity that has TrackRecordChanges set to 1 by the MJ CodeGen tool.
|
|
62
|
+
* * The entity is not in the IneligibleEntities list. See info on the IneligibleEntities property for more information on excluded entities.
|
|
38
63
|
*/
|
|
39
64
|
get EligibleEntities(): EntityInfo[];
|
|
40
65
|
/**
|
|
@@ -42,6 +67,30 @@ export declare class ExternalChangeDetectorEngine extends BaseEngine<ExternalCha
|
|
|
42
67
|
* @param entity
|
|
43
68
|
*/
|
|
44
69
|
DetectChangesForEntity(entity: EntityInfo): Promise<ChangeDetectionResult>;
|
|
70
|
+
/**
|
|
71
|
+
* This method compares a version of the record in question from the database with the last version we had in RecordChange table
|
|
72
|
+
* @param change
|
|
73
|
+
*/
|
|
74
|
+
DetermineRecordChanges(md: Metadata, change: ChangeDetectionItem): Promise<{
|
|
75
|
+
changes: FieldChange[];
|
|
76
|
+
latestRecord: BaseEntity;
|
|
77
|
+
}>;
|
|
78
|
+
protected DoValuesDiffer(field: EntityField, value1: any, value2: any): {
|
|
79
|
+
differ: boolean;
|
|
80
|
+
castValue1: any;
|
|
81
|
+
castValue2: any;
|
|
82
|
+
};
|
|
83
|
+
protected GetLatestRecordChangesDataForEntityRecord(change: ChangeDetectionItem): Promise<any>;
|
|
84
|
+
protected GetLatestDatabaseRecord(md: Metadata, change: ChangeDetectionItem): Promise<BaseEntity>;
|
|
85
|
+
/**
|
|
86
|
+
* Get all of the latest database records together in grouped queries for each entity that has records we need instead
|
|
87
|
+
* of one at a time like GetLatestDatabaseRecord does. This method will return true/false and will place the LatestRecord
|
|
88
|
+
* into each item in the changes array for you.
|
|
89
|
+
* @param md
|
|
90
|
+
* @param changes
|
|
91
|
+
* @returns
|
|
92
|
+
*/
|
|
93
|
+
protected GetLatestDatabaseRecords(md: Metadata, changes: ChangeDetectionItem[]): Promise<boolean>;
|
|
45
94
|
protected getPrimaryKeyString(entity: EntityInfo, tablePrefix: string): string;
|
|
46
95
|
protected generateDetectUpdatesQuery(entity: EntityInfo): string;
|
|
47
96
|
protected generateDetectCreationsQuery(entity: EntityInfo): string;
|
|
@@ -51,6 +100,37 @@ export declare class ExternalChangeDetectorEngine extends BaseEngine<ExternalCha
|
|
|
51
100
|
* @returns
|
|
52
101
|
*/
|
|
53
102
|
DetectChangesForEntities(entities: EntityInfo[]): Promise<ChangeDetectionResult>;
|
|
103
|
+
/**
|
|
104
|
+
* This method will detect changes for all eligible entities as defined by the EligibleEntities property
|
|
105
|
+
*/
|
|
54
106
|
DetectChangesForAllEligibleEntities(): Promise<ChangeDetectionResult>;
|
|
107
|
+
/**
|
|
108
|
+
* This method will replay all of the items in the changes array
|
|
109
|
+
* @param changes Array of changes to replay.
|
|
110
|
+
* @param batchSize Optional, defines the # of concurrent changes to replay at once. If you want to replay changes serially, set this to 1
|
|
111
|
+
* @returns {Promise<boolean>} - Returns true if all changes are successfully replayed, otherwise false.
|
|
112
|
+
*/
|
|
113
|
+
ReplayChanges(changes: ChangeDetectionItem[], batchSize?: number): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Method creates a new Record Change Replay Run and returns the object for the run
|
|
116
|
+
*/
|
|
117
|
+
protected StartRun(): Promise<RecordChangeReplayRunEntity>;
|
|
118
|
+
/**
|
|
119
|
+
* Replays a single change item within a given run. This method will:
|
|
120
|
+
* 1) Create a new Record Change record for the replay item
|
|
121
|
+
* 2) Load a BaseEntity derived class for the entity in question and call either Save() or Delete() and pass in the Replay Only option
|
|
122
|
+
* 3) Record the result in the Record Change record, updating status and if appropriate, the error message
|
|
123
|
+
* @param change
|
|
124
|
+
*/
|
|
125
|
+
protected ReplaySingleChange(md: Metadata, run: RecordChangeReplayRunEntity, change: ChangeDetectionItem): Promise<boolean>;
|
|
126
|
+
/**
|
|
127
|
+
* This method will attempt to update the RecordChange record and return true if succesful, false otherwise.
|
|
128
|
+
*/
|
|
129
|
+
protected FinishRecordChangeRecord(rc: RecordChangeEntity, code: 'error' | 'success', errorMessage: string): Promise<boolean>;
|
|
130
|
+
/**
|
|
131
|
+
* Creates a new record change record for the start of the replay process.
|
|
132
|
+
* @param change
|
|
133
|
+
*/
|
|
134
|
+
protected CreateRecordChangeRecord(md: Metadata, run: RecordChangeReplayRunEntity, change: ChangeDetectionItem): Promise<RecordChangeEntity>;
|
|
55
135
|
}
|
|
56
136
|
//# sourceMappingURL=ChangeDetector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangeDetector.d.ts","sourceRoot":"","sources":["../src/ChangeDetector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA4B,
|
|
1
|
+
{"version":3,"file":"ChangeDetector.d.ts","sourceRoot":"","sources":["../src/ChangeDetector.ts"],"names":[],"mappings":"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"}
|
package/dist/ChangeDetector.js
CHANGED
|
@@ -12,6 +12,9 @@ exports.FieldChange = FieldChange;
|
|
|
12
12
|
* Represents a change to a single record in an entity
|
|
13
13
|
*/
|
|
14
14
|
class ChangeDetectionItem {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.LegacyKey = false; // if true, this means that the key was a single value and not a concatenated key
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
19
|
exports.ChangeDetectionItem = ChangeDetectionItem;
|
|
17
20
|
/**
|
|
@@ -25,6 +28,10 @@ exports.ChangeDetectionResult = ChangeDetectionResult;
|
|
|
25
28
|
* such as BaseEntity sub-classes as well as any custom logic that are tied to the system via Actions/AI Actions/etc...
|
|
26
29
|
*/
|
|
27
30
|
class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
31
|
+
constructor() {
|
|
32
|
+
super(...arguments);
|
|
33
|
+
this._IneligibleEntities = []; // ['Entities', 'Entity Fields', 'Entity Field Values', 'Entity Relationships', 'Record Changes']; // default ineligible entities --- turned off for now
|
|
34
|
+
}
|
|
28
35
|
async Config(forceRefresh, contextUser) {
|
|
29
36
|
const provider = core_1.Metadata.Provider;
|
|
30
37
|
const c = [
|
|
@@ -40,10 +47,30 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
40
47
|
return super.getInstance();
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
43
|
-
* A list of
|
|
50
|
+
* A list of entities that will automatically be excluded from all calls to this class. This array is used as a "safety"
|
|
51
|
+
* mechanism to prevent the system from trying to replay changes to these entities which wouldn't negatively affect system integrity
|
|
52
|
+
* but could cause performance issues. If you want to add/remove entities to this list, you can do so by manipulating this array.
|
|
53
|
+
*
|
|
54
|
+
* If you want to run Change Detection and/or replay changes for entities in this array, you will need to remove them
|
|
55
|
+
* in your code before calling the methods in this class. While executing methods on this class with these default
|
|
56
|
+
* ineligible entities will not cause any issues, they may take a long time to run and utilize a significant amount
|
|
57
|
+
* of resources.
|
|
58
|
+
*/
|
|
59
|
+
get IneligibleEntities() {
|
|
60
|
+
return this._IneligibleEntities;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A list of the entities that are eligible for external change detection. This is determined by using the underlying
|
|
64
|
+
* database view vwEntitiesWithExternalChangeTracking which is a view that is maintained by the MJ system and is used to
|
|
65
|
+
* find a list of entities that have the required characteristics that support external change detection. These characteristics
|
|
66
|
+
* include:
|
|
67
|
+
* * The entity has the TrackRecordChanges property set to 1
|
|
68
|
+
* * The entity has the special UpdatedAt/CreatedAt fields (which are called __mj_UpdatedAt and __mj_CreatedAt in the database). These fields are AUTOMATICALLY added to an entity that has TrackRecordChanges set to 1 by the MJ CodeGen tool.
|
|
69
|
+
* * The entity is not in the IneligibleEntities list. See info on the IneligibleEntities property for more information on excluded entities.
|
|
44
70
|
*/
|
|
45
71
|
get EligibleEntities() {
|
|
46
|
-
|
|
72
|
+
const netEligible = this._EligibleEntities.filter(e => !this.IneligibleEntities.map(i => i.toLowerCase().trim()).includes(e.Name.toLowerCase().trim()));
|
|
73
|
+
return netEligible;
|
|
47
74
|
}
|
|
48
75
|
/**
|
|
49
76
|
* Detects external changes for a single entity
|
|
@@ -51,6 +78,14 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
51
78
|
*/
|
|
52
79
|
async DetectChangesForEntity(entity) {
|
|
53
80
|
try {
|
|
81
|
+
// check to make sure that the entity is in the eligible list
|
|
82
|
+
if (!entity) {
|
|
83
|
+
throw new Error("entity parameter is required");
|
|
84
|
+
}
|
|
85
|
+
else if (!this.EligibleEntities.find(e => e.ID === entity.ID)) {
|
|
86
|
+
throw new Error(`Entity ${entity.Name} is not eligible for external change detection. Refer to the documentation on the EligibleEntities and IneligibleEntities properties for more information.`);
|
|
87
|
+
}
|
|
88
|
+
const md = new core_1.Metadata();
|
|
54
89
|
const sqlCreates = this.generateDetectCreationsQuery(entity);
|
|
55
90
|
const sqlUpdates = this.generateDetectUpdatesQuery(entity);
|
|
56
91
|
const sqlDeletes = this.generateDetectDeletionsQuery(entity);
|
|
@@ -61,7 +96,7 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
61
96
|
// we have the results for all of the queries, now we need to convert them into ChangeDetectionItems
|
|
62
97
|
const changes = [];
|
|
63
98
|
if (createResult && createResult.length > 0) {
|
|
64
|
-
|
|
99
|
+
for (const row of createResult) {
|
|
65
100
|
const item = new ChangeDetectionItem();
|
|
66
101
|
item.Entity = entity;
|
|
67
102
|
item.PrimaryKey = new core_1.CompositeKey(entity.PrimaryKeys.map(pk => {
|
|
@@ -71,13 +106,13 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
71
106
|
};
|
|
72
107
|
}));
|
|
73
108
|
item.Type = 'Create';
|
|
74
|
-
item.ChangedAt = row.CreatedAt;
|
|
75
|
-
item.Changes = [];
|
|
109
|
+
item.ChangedAt = row.CreatedAt >= row.UpdatedAt ? row.CreatedAt : row.UpdatedAt;
|
|
110
|
+
item.Changes = []; // not relevant because the row is new
|
|
76
111
|
changes.push(item);
|
|
77
|
-
}
|
|
112
|
+
}
|
|
78
113
|
}
|
|
79
114
|
if (updateResult && updateResult.length > 0) {
|
|
80
|
-
|
|
115
|
+
for (const row of updateResult) {
|
|
81
116
|
const item = new ChangeDetectionItem();
|
|
82
117
|
item.Entity = entity;
|
|
83
118
|
item.PrimaryKey = new core_1.CompositeKey(entity.PrimaryKeys.map(pk => {
|
|
@@ -88,30 +123,45 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
88
123
|
}));
|
|
89
124
|
item.Type = 'Update';
|
|
90
125
|
item.ChangedAt = row.UpdatedAt;
|
|
91
|
-
item.Changes = [];
|
|
92
126
|
// push the item but first make sure it is NOT already in the changes from the
|
|
93
127
|
// create detection, if it is, we do not push it into changes
|
|
94
128
|
if (!changes.find(c => c.PrimaryKey.Equals(item.PrimaryKey))) {
|
|
95
129
|
changes.push(item);
|
|
96
130
|
}
|
|
97
|
-
}
|
|
131
|
+
}
|
|
98
132
|
}
|
|
99
133
|
if (deleteResult && deleteResult.length > 0) {
|
|
100
134
|
deleteResult.forEach(row => {
|
|
101
135
|
const item = new ChangeDetectionItem();
|
|
102
136
|
item.Entity = entity;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
137
|
+
const ck = new core_1.CompositeKey();
|
|
138
|
+
// row.RecordID should have a format of Field1|Value1||Field2|Value2, however in some cases there is legacy
|
|
139
|
+
// data in the RecordChange table that just has a single value in it and in that case assuming that the entity
|
|
140
|
+
// in question has a single-valued primary key, we can just use that value as the key, so we need to test for that
|
|
141
|
+
// first and if we find that the RecordID is just a single value, we can use that as the key
|
|
142
|
+
if (row.RecordID.indexOf(core_1.CompositeKey.DefaultValueDelimiter) === -1) {
|
|
143
|
+
// there is no field delimiter, so we can assume this is a single value
|
|
144
|
+
ck.LoadFromSingleKeyValuePair(entity.PrimaryKeys[0].Name, row.RecordID); // this is a string like 'Field1Value' (no quotes
|
|
145
|
+
item.LegacyKey = true;
|
|
146
|
+
item.LegacyKeyValue = row.RecordID;
|
|
147
|
+
}
|
|
148
|
+
else
|
|
149
|
+
ck.LoadFromConcatenatedString(row.RecordID); // this is a string like 'Field1Value|Field2Value' (no quotes)
|
|
150
|
+
item.PrimaryKey = ck;
|
|
109
151
|
item.Type = 'Delete';
|
|
110
|
-
item.ChangedAt = row.
|
|
111
|
-
item.Changes = [];
|
|
152
|
+
item.ChangedAt = row.ChangedAt;
|
|
153
|
+
item.Changes = []; // not relevant because the row is now deleted
|
|
112
154
|
changes.push(item);
|
|
113
155
|
});
|
|
114
156
|
}
|
|
157
|
+
await this.GetLatestDatabaseRecords(md, changes); // load everything from the database in one step
|
|
158
|
+
// now we have latest records, go back through and update the Changes field for the UPDATE types
|
|
159
|
+
for (const c of changes) {
|
|
160
|
+
if (c.Type === 'Update') {
|
|
161
|
+
const changesResult = await this.DetermineRecordChanges(md, c);
|
|
162
|
+
c.Changes = changesResult.changes;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
115
165
|
return {
|
|
116
166
|
Success: true,
|
|
117
167
|
Changes: changes
|
|
@@ -126,41 +176,207 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
126
176
|
};
|
|
127
177
|
}
|
|
128
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* This method compares a version of the record in question from the database with the last version we had in RecordChange table
|
|
181
|
+
* @param change
|
|
182
|
+
*/
|
|
183
|
+
async DetermineRecordChanges(md, change) {
|
|
184
|
+
try {
|
|
185
|
+
// Step 1 - load the current record if needed, sometimes already loaded by here
|
|
186
|
+
const record = change.LatestRecord ? change.LatestRecord : await this.GetLatestDatabaseRecord(md, change);
|
|
187
|
+
if (record) {
|
|
188
|
+
// now we have the version from the database that has been updated from an external source
|
|
189
|
+
// then we need to get the latest version from the vwRecordChanges table that matches this entity and RecordID
|
|
190
|
+
const result = await this.GetLatestRecordChangesDataForEntityRecord(change);
|
|
191
|
+
if (result && result.FullRecordJSON && result.FullRecordJSON.length > 0) {
|
|
192
|
+
// we have our row, so get the JSON, parse it and we'll have the differences
|
|
193
|
+
const json = JSON.parse(result.FullRecordJSON);
|
|
194
|
+
// now go through each field in the record object and compare it with the json
|
|
195
|
+
const changes = [];
|
|
196
|
+
for (const field of record.Fields) {
|
|
197
|
+
if (!field.IsPrimaryKey) {
|
|
198
|
+
const differResult = this.DoValuesDiffer(field, field.Value, json[field.Name]);
|
|
199
|
+
if (differResult.differ) {
|
|
200
|
+
changes.push({
|
|
201
|
+
FieldName: field.Name,
|
|
202
|
+
NewValue: differResult.castValue1, // use the typecast values so they're the right types
|
|
203
|
+
OldValue: differResult.castValue2 // use the typecast values so they're the right types
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return { changes, latestRecord: record };
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
(0, core_1.LogStatus)(` WARNING: No record found, or no FullRecordJSON found, in vwRecordChanges for ${change.Entity.Name}: ${change.PrimaryKey.ToConcatenatedString()}`);
|
|
212
|
+
return { changes: [], latestRecord: record };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else
|
|
216
|
+
throw new Error(`Failed to load record: ${change.Entity.Name}: ${change.PrimaryKey}`);
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
(0, core_1.LogError)(e);
|
|
220
|
+
return { changes: [], latestRecord: null };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
DoValuesDiffer(field, value1, value2) {
|
|
224
|
+
// type specific comparisons
|
|
225
|
+
// for each scenario, make sure both value1 and value 2 are of the type we care about, if they're not, create new variables
|
|
226
|
+
// of those types and then do type specific comparisons for equality
|
|
227
|
+
switch (field.EntityFieldInfo.TSType) {
|
|
228
|
+
case core_1.EntityFieldTSType.Boolean:
|
|
229
|
+
// check to see if value1 and value2 are both boolean, if not, convert them to boolean
|
|
230
|
+
const v1 = typeof value1 === 'boolean' ? value1 : value1 === 'true' ? true : false;
|
|
231
|
+
const v2 = typeof value2 === 'boolean' ? value2 : value2 === 'true' ? true : false;
|
|
232
|
+
return { differ: v1 !== v2, castValue1: v1, castValue2: v2 };
|
|
233
|
+
case core_1.EntityFieldTSType.Date:
|
|
234
|
+
// check to see if value1 and value2 are both dates, if not, convert them to dates
|
|
235
|
+
const d1 = value1 instanceof Date ? value1 : new Date(value1);
|
|
236
|
+
const d2 = value2 instanceof Date ? value2 : new Date(value2);
|
|
237
|
+
return { differ: d1.getTime() !== d2.getTime(), castValue1: d1, castValue2: d2 };
|
|
238
|
+
case core_1.EntityFieldTSType.Number:
|
|
239
|
+
// check to see if value1 and value2 are both numbers, if not, convert them to numbers
|
|
240
|
+
const n1 = value1 ? typeof value1 === 'number' ? value1 : parseFloat(value1) : value1;
|
|
241
|
+
const n2 = value2 ? typeof value2 === 'number' ? value2 : parseFloat(value2) : value2;
|
|
242
|
+
return { differ: n1 !== n2, castValue1: n1, castValue2: n2 };
|
|
243
|
+
case core_1.EntityFieldTSType.String:
|
|
244
|
+
// check to see if value1 and value2 are both strings, if not, convert them to strings
|
|
245
|
+
const s1 = typeof value1 === 'string' || !value1 ? value1 : value1.toString();
|
|
246
|
+
const s2 = typeof value2 === 'string' || !value2 ? value2 : value2.toString();
|
|
247
|
+
return { differ: s1 !== s2, castValue1: s1, castValue2: s2 };
|
|
248
|
+
default:
|
|
249
|
+
// don't know the type, shouldn't get here, just do a basic TypeScript equality check
|
|
250
|
+
// with a single != instead of !== because we don't want to check type just value
|
|
251
|
+
return { differ: value1 != value2, castValue1: value1, castValue2: value2 };
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async GetLatestRecordChangesDataForEntityRecord(change) {
|
|
255
|
+
const Provider = core_1.Metadata.Provider;
|
|
256
|
+
const sql = `SELECT
|
|
257
|
+
TOP 1 FullRecordJSON
|
|
258
|
+
FROM
|
|
259
|
+
${Provider.MJCoreSchemaName}.vwRecordChanges
|
|
260
|
+
WHERE
|
|
261
|
+
RecordID = '${change.PrimaryKey.ToConcatenatedString()}'
|
|
262
|
+
AND EntityID = ${change.Entity.ID}
|
|
263
|
+
AND Status <> 'Pending'
|
|
264
|
+
ORDER BY
|
|
265
|
+
ChangedAt DESC`;
|
|
266
|
+
const result = await Provider.ExecuteSQL(sql);
|
|
267
|
+
if (result && result.length > 0)
|
|
268
|
+
return result[0];
|
|
269
|
+
else
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
async GetLatestDatabaseRecord(md, change) {
|
|
273
|
+
const record = await md.GetEntityObject(change.Entity.Name, this.ContextUser);
|
|
274
|
+
if (await record.InnerLoad(change.PrimaryKey)) {
|
|
275
|
+
return record;
|
|
276
|
+
}
|
|
277
|
+
else
|
|
278
|
+
throw new Error(`Failed to load record: ${change.Entity.Name}: ${change.PrimaryKey}`);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Get all of the latest database records together in grouped queries for each entity that has records we need instead
|
|
282
|
+
* of one at a time like GetLatestDatabaseRecord does. This method will return true/false and will place the LatestRecord
|
|
283
|
+
* into each item in the changes array for you.
|
|
284
|
+
* @param md
|
|
285
|
+
* @param changes
|
|
286
|
+
* @returns
|
|
287
|
+
*/
|
|
288
|
+
async GetLatestDatabaseRecords(md, changes) {
|
|
289
|
+
try {
|
|
290
|
+
// Step 1 - group by entity and get a complete list of entities from the changes
|
|
291
|
+
const entities = [];
|
|
292
|
+
const provider = core_1.Metadata.Provider;
|
|
293
|
+
for (const c of changes) {
|
|
294
|
+
let e = entities.find(e => e.entity.ID === c.Entity.ID);
|
|
295
|
+
if (!e) {
|
|
296
|
+
e = {
|
|
297
|
+
entity: c.Entity,
|
|
298
|
+
keys: [c.PrimaryKey]
|
|
299
|
+
};
|
|
300
|
+
entities.push(e);
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
e.keys.push(c.PrimaryKey);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// now we have a distinct list of entities and all of the pkeys for each one, so we can run a single
|
|
307
|
+
// select statement for each entity
|
|
308
|
+
for (const e of entities) {
|
|
309
|
+
const sql = `SELECT * FROM [${e.entity.SchemaName}].[${e.entity.BaseView}]
|
|
310
|
+
WHERE ${e.keys.map(k => `(${k.KeyValuePairs.map(kvp => {
|
|
311
|
+
const f = e.entity.Fields.find(f => kvp.FieldName.trim().toLowerCase() === f.Name);
|
|
312
|
+
const quotes = f?.NeedsQuotes ? "'" : "";
|
|
313
|
+
return `[${kvp.FieldName}]=${quotes}${kvp.Value}${quotes}`;
|
|
314
|
+
}).join(' AND ')})`).join(' OR ')} `;
|
|
315
|
+
const result = await provider.ExecuteSQL(sql);
|
|
316
|
+
if (result) {
|
|
317
|
+
// we have the rows from the result, now go back through each of the changes we have in the changes array
|
|
318
|
+
// and associate the data with each one
|
|
319
|
+
for (const r of result) {
|
|
320
|
+
const kvp = e.entity.PrimaryKeys.map(pk => {
|
|
321
|
+
return {
|
|
322
|
+
FieldName: pk.Name,
|
|
323
|
+
Value: r[pk.Name]
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
const changeItem = changes.find(ci => ci.Entity === e.entity && ci.PrimaryKey.EqualsKey(kvp));
|
|
327
|
+
if (changeItem) {
|
|
328
|
+
// found the match, update latest Record
|
|
329
|
+
const record = await md.GetEntityObject(changeItem.Entity.Name, this.ContextUser);
|
|
330
|
+
record.LoadFromData(r);
|
|
331
|
+
changeItem.LatestRecord = record;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
catch (e) {
|
|
339
|
+
(0, core_1.LogError)(e);
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
129
343
|
getPrimaryKeyString(entity, tablePrefix) {
|
|
130
|
-
return entity.PrimaryKeys.
|
|
131
|
-
`${tablePrefix}.${entity.PrimaryKeys[0].Name}` :
|
|
132
|
-
entity.PrimaryKeys.map(pk => `'${pk.Name}|' + CAST(${tablePrefix}.[${pk.Name}] AS NVARCHAR(MAX))`).join(` + '||' + `);
|
|
344
|
+
return entity.PrimaryKeys.map(pk => `'${pk.Name}${core_1.CompositeKey.DefaultValueDelimiter}' + CAST(${tablePrefix}.[${pk.Name}] AS NVARCHAR(MAX))`).join(` + '${core_1.CompositeKey.DefaultFieldDelimiter}' + `);
|
|
133
345
|
}
|
|
134
346
|
generateDetectUpdatesQuery(entity) {
|
|
135
347
|
const primaryKeyString = this.getPrimaryKeyString(entity, 'ot');
|
|
136
348
|
return `
|
|
137
349
|
SELECT
|
|
138
|
-
${entity.PrimaryKeys.map(pk => `ot.[${pk.Name}]`).join(', ')}, ot.UpdatedAt
|
|
350
|
+
${entity.PrimaryKeys.map(pk => `ot.[${pk.Name}]`).join(', ')}, ot.${core_1.EntityInfo.UpdatedAtFieldName} AS UpdatedAt, rc.last_change_time LatestRecordChangeAt
|
|
139
351
|
FROM
|
|
140
352
|
[${entity.SchemaName}].[${entity.BaseView}] ot
|
|
141
|
-
|
|
353
|
+
INNER JOIN (
|
|
142
354
|
SELECT
|
|
143
355
|
RecordID, MAX(ChangedAt) AS last_change_time
|
|
144
356
|
FROM
|
|
145
357
|
__mj.vwRecordChanges
|
|
146
358
|
WHERE
|
|
147
|
-
Type IN ('Update', 'Create')
|
|
359
|
+
Type IN ('Update', 'Create') AND EntityID = ${entity.ID}
|
|
148
360
|
GROUP BY
|
|
149
361
|
RecordID
|
|
150
362
|
) rc ON ${primaryKeyString} = rc.RecordID
|
|
151
363
|
WHERE
|
|
152
|
-
ot.
|
|
153
|
-
|
|
364
|
+
FORMAT(ot.${core_1.EntityInfo.UpdatedAtFieldName}, 'yyyy-MM-dd HH:mm:ss.fff') > COALESCE(FORMAT(rc.last_change_time, 'yyyy-MM-dd HH:mm:ss.fff'), '1900-01-01 00:00:00.000');`;
|
|
365
|
+
// use up to 3 digits of precision because when we get the values back into JavaScript objects, Date objects only have 3 digits of precision
|
|
154
366
|
}
|
|
155
367
|
generateDetectCreationsQuery(entity) {
|
|
156
368
|
const primaryKeyString = this.getPrimaryKeyString(entity, 'ot');
|
|
157
369
|
return `
|
|
158
370
|
SELECT
|
|
159
|
-
${entity.PrimaryKeys.map(pk => `ot.[${pk.Name}]`).join(', ')}, ot.CreatedAt
|
|
371
|
+
${entity.PrimaryKeys.map(pk => `ot.[${pk.Name}]`).join(', ')}, ot.${core_1.EntityInfo.CreatedAtFieldName} AS CreatedAt, ot.${core_1.EntityInfo.UpdatedAtFieldName} AS UpdatedAt
|
|
160
372
|
FROM
|
|
161
373
|
[${entity.SchemaName}].[${entity.BaseView}] ot
|
|
162
374
|
LEFT JOIN
|
|
163
|
-
__mj.vwRecordChanges rc
|
|
375
|
+
__mj.vwRecordChanges rc
|
|
376
|
+
ON
|
|
377
|
+
(${primaryKeyString} = rc.RecordID) AND
|
|
378
|
+
rc.Type = 'Create' AND
|
|
379
|
+
rc.EntityID = ${entity.ID}
|
|
164
380
|
WHERE
|
|
165
381
|
rc.RecordID IS NULL;
|
|
166
382
|
`;
|
|
@@ -169,16 +385,26 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
169
385
|
const primaryKeyString = this.getPrimaryKeyString(entity, 'ot');
|
|
170
386
|
return `
|
|
171
387
|
SELECT
|
|
172
|
-
rc.RecordID, rc.ChangedAt
|
|
388
|
+
rc.RecordID, MAX(rc.ChangedAt) ChangedAt
|
|
173
389
|
FROM
|
|
174
390
|
__mj.vwRecordChanges rc
|
|
175
391
|
LEFT JOIN
|
|
176
|
-
[${entity.SchemaName}].[${entity.BaseView}] ot
|
|
392
|
+
[${entity.SchemaName}].[${entity.BaseView}] ot
|
|
393
|
+
ON
|
|
394
|
+
rc.RecordID = ${primaryKeyString}
|
|
177
395
|
WHERE
|
|
178
396
|
${entity.PrimaryKeys.map(pk => `ot.[${pk.Name}] IS NULL`).join(' AND ')}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
397
|
+
AND
|
|
398
|
+
rc.EntityID = ${entity.ID}
|
|
399
|
+
AND
|
|
400
|
+
NOT EXISTS
|
|
401
|
+
(
|
|
402
|
+
SELECT rc2.ID FROM __mj.vwRecordChanges rc2 WHERE
|
|
403
|
+
rc2.RecordID = rc.RecordID AND rc2.EntityID=rc.EntityID AND rc2.Type='Delete'
|
|
404
|
+
)
|
|
405
|
+
GROUP BY
|
|
406
|
+
rc.RecordID
|
|
407
|
+
`; // last part of above query makes sure we don't include records already deleted in Record Changes
|
|
182
408
|
}
|
|
183
409
|
/**
|
|
184
410
|
* Detects changes across all of the entities specified
|
|
@@ -186,14 +412,30 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
186
412
|
*/
|
|
187
413
|
async DetectChangesForEntities(entities) {
|
|
188
414
|
try {
|
|
415
|
+
if (!entities)
|
|
416
|
+
throw new Error("entities parameter is required");
|
|
417
|
+
else if (entities.length === 0)
|
|
418
|
+
throw new Error("entities parameter must have at least one entity in it");
|
|
189
419
|
const result = new ChangeDetectionResult();
|
|
190
420
|
result.Success = true;
|
|
191
421
|
result.Changes = [];
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
422
|
+
const promises = [];
|
|
423
|
+
// fire them all off in parallel
|
|
424
|
+
(0, core_1.LogStatus)(`Detecting changes for ${entities.length} entities`);
|
|
425
|
+
let numFinished = 0;
|
|
426
|
+
entities.forEach((e) => {
|
|
427
|
+
(0, core_1.UpdateCurrentConsoleLine)(` Starting change detection changes for ${e.Name}`, core_1.ConsoleColor.gray);
|
|
428
|
+
const p = this.DetectChangesForEntity(e); // no await
|
|
429
|
+
promises.push(p);
|
|
430
|
+
p.then(entityResult => {
|
|
431
|
+
(0, core_1.UpdateCurrentConsoleProgress)(` Finished change detection changes for ${e.Name}`, ++numFinished, entities.length, entityResult.Success ? core_1.ConsoleColor.cyan : core_1.ConsoleColor.crimson);
|
|
432
|
+
result.Changes = result.Changes.concat(entityResult.Changes);
|
|
433
|
+
result.Success = result.Success && entityResult.Success;
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
// now wait for all of the promises to finish
|
|
437
|
+
await Promise.all(promises);
|
|
438
|
+
(0, core_1.UpdateCurrentConsoleProgress)(` Finished detecting changes for ${entities.length} entities`, entities.length, entities.length, result.Success ? core_1.ConsoleColor.green : core_1.ConsoleColor.red);
|
|
197
439
|
return result;
|
|
198
440
|
}
|
|
199
441
|
catch (e) {
|
|
@@ -205,9 +447,239 @@ class ExternalChangeDetectorEngine extends core_1.BaseEngine {
|
|
|
205
447
|
};
|
|
206
448
|
}
|
|
207
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* This method will detect changes for all eligible entities as defined by the EligibleEntities property
|
|
452
|
+
*/
|
|
208
453
|
async DetectChangesForAllEligibleEntities() {
|
|
209
454
|
return await this.DetectChangesForEntities(this.EligibleEntities);
|
|
210
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* This method will replay all of the items in the changes array
|
|
458
|
+
* @param changes Array of changes to replay.
|
|
459
|
+
* @param batchSize Optional, defines the # of concurrent changes to replay at once. If you want to replay changes serially, set this to 1
|
|
460
|
+
* @returns {Promise<boolean>} - Returns true if all changes are successfully replayed, otherwise false.
|
|
461
|
+
*/
|
|
462
|
+
async ReplayChanges(changes, batchSize = 20) {
|
|
463
|
+
let run; // delcare outside of try block so we have access to it in the catch block
|
|
464
|
+
try {
|
|
465
|
+
if (changes && changes.length > 0) {
|
|
466
|
+
const md = new core_1.Metadata();
|
|
467
|
+
const results = [];
|
|
468
|
+
run = await this.StartRun();
|
|
469
|
+
(0, core_1.LogStatus)(`Replaying ${changes.length} changes`);
|
|
470
|
+
let numProcessed = 0;
|
|
471
|
+
for (let i = 0; i < changes.length; i += batchSize) {
|
|
472
|
+
const batch = changes.slice(i, i + batchSize);
|
|
473
|
+
// Process the current batch
|
|
474
|
+
const batchPromises = batch.map(async (change) => {
|
|
475
|
+
(0, core_1.UpdateCurrentConsoleProgress)(` Replaying ${change.Entity.Name} ${change.Type} ${change.PrimaryKey.ToConcatenatedString()}`, ++numProcessed, changes.length, core_1.ConsoleColor.gray);
|
|
476
|
+
const result = await this.ReplaySingleChange(md, run, change);
|
|
477
|
+
return { Success: result, change: change };
|
|
478
|
+
});
|
|
479
|
+
// Wait for all promises in the current batch to complete
|
|
480
|
+
const batchResults = await Promise.all(batchPromises);
|
|
481
|
+
results.push(...batchResults);
|
|
482
|
+
}
|
|
483
|
+
// for (const change of changes) {
|
|
484
|
+
// UpdateCurrentConsoleProgress(` Replaying ${change.Entity.Name} ${change.Type} ${change.PrimaryKey.ToConcatenatedString()}`, changes.indexOf(change), changes.length, ConsoleColor.gray);
|
|
485
|
+
// const result = await this.ReplaySingleChange(md, run, change);
|
|
486
|
+
// results.push({Success: result, change: change});
|
|
487
|
+
// }
|
|
488
|
+
run.EndedAt = new Date();
|
|
489
|
+
run.Status = results.every(r => r.Success) ? 'Complete' : 'Error';
|
|
490
|
+
if (await run.Save()) {
|
|
491
|
+
return results.every(r => r.Success);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
throw new Error("Failed to save run");
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
else
|
|
498
|
+
return true; // no changes to process
|
|
499
|
+
}
|
|
500
|
+
catch (e) {
|
|
501
|
+
(0, core_1.LogError)(e);
|
|
502
|
+
if (run) {
|
|
503
|
+
// attempt to mark the run as error
|
|
504
|
+
try {
|
|
505
|
+
run.Status = 'Error';
|
|
506
|
+
run.EndedAt = new Date();
|
|
507
|
+
await run.Save(); // dont' care about return value here, we've already tried to save it and the return value will be false anyway and message is the original root cause of the first exception
|
|
508
|
+
}
|
|
509
|
+
catch (innerError) {
|
|
510
|
+
(0, core_1.LogError)('Attempted to mark run as error failed, make sure you update the database for future runs to be allowed.');
|
|
511
|
+
(0, core_1.LogError)(innerError);
|
|
512
|
+
return false; // couldn't get it done
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Method creates a new Record Change Replay Run and returns the object for the run
|
|
520
|
+
*/
|
|
521
|
+
async StartRun() {
|
|
522
|
+
// first make sure an existing run isn't in progress
|
|
523
|
+
const rv = new core_1.RunView();
|
|
524
|
+
const existingRun = await rv.RunView({
|
|
525
|
+
EntityName: "Record Change Replay Runs",
|
|
526
|
+
ExtraFilter: "Status NOT IN('Complete', 'Error')"
|
|
527
|
+
}, this.ContextUser);
|
|
528
|
+
if (existingRun && existingRun.Success) {
|
|
529
|
+
if (existingRun.Results.length > 0)
|
|
530
|
+
throw new Error(`Existing Record Change Replay Run ${existingRun.Results[0].ID} is not complete or marked as error, cannot start a new run.`);
|
|
531
|
+
else {
|
|
532
|
+
const md = new core_1.Metadata();
|
|
533
|
+
const run = await md.GetEntityObject("Record Change Replay Runs", this.ContextUser);
|
|
534
|
+
run.StartedAt = new Date();
|
|
535
|
+
run.UserID = this.ContextUser.ID;
|
|
536
|
+
run.Status = 'In Progress';
|
|
537
|
+
if (await run.Save()) {
|
|
538
|
+
return run;
|
|
539
|
+
}
|
|
540
|
+
else
|
|
541
|
+
throw new Error("Failed to start run");
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
// failed to run the view
|
|
546
|
+
throw new Error("Failed to check for existing run: " + existingRun.ErrorMessage);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Replays a single change item within a given run. This method will:
|
|
551
|
+
* 1) Create a new Record Change record for the replay item
|
|
552
|
+
* 2) Load a BaseEntity derived class for the entity in question and call either Save() or Delete() and pass in the Replay Only option
|
|
553
|
+
* 3) Record the result in the Record Change record, updating status and if appropriate, the error message
|
|
554
|
+
* @param change
|
|
555
|
+
*/
|
|
556
|
+
async ReplaySingleChange(md, run, change) {
|
|
557
|
+
try {
|
|
558
|
+
const rc = await this.CreateRecordChangeRecord(md, run, change);
|
|
559
|
+
if (rc) {
|
|
560
|
+
// step 2 - get the base entity for the change
|
|
561
|
+
let entityObject = change.LatestRecord; // for updates and creates we already have this
|
|
562
|
+
if (!entityObject) {
|
|
563
|
+
// for deletes we don't have this yet - it is not the normal load from DB since it wont be in the database at all
|
|
564
|
+
entityObject = await md.GetEntityObject(change.Entity.Name, this.ContextUser);
|
|
565
|
+
const latestRCData = await this.GetLatestRecordChangesDataForEntityRecord(change);
|
|
566
|
+
if (latestRCData && latestRCData.FullRecordJSON?.length > 0) {
|
|
567
|
+
const obj = JSON.parse(latestRCData.FullRecordJSON);
|
|
568
|
+
entityObject.LoadFromData(obj); // loaded up from the latest data in the Record Change table
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
// we have an issue becuase we don't have data in the RecordChange table so we can't replay the DELETE, so mark that in the error for the RecordChange
|
|
572
|
+
return this.FinishRecordChangeRecord(rc, 'error', 'No prior record data is available in the Record Changes entity, so it is not possible to replay the Delete');
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
// if we get here, entityObject is now all set to go for replay!
|
|
576
|
+
if (change.Type === 'Delete') {
|
|
577
|
+
const result = await entityObject.Delete({
|
|
578
|
+
ReplayOnly: true
|
|
579
|
+
});
|
|
580
|
+
return this.FinishRecordChangeRecord(rc, result ? 'success' : 'error', entityObject.LatestResult?.Error);
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
// for updates and creates we just call Save() with the ReplayOnly option
|
|
584
|
+
const result = await entityObject.Save({
|
|
585
|
+
ReplayOnly: true,
|
|
586
|
+
IgnoreDirtyState: false //not relevant for replay
|
|
587
|
+
});
|
|
588
|
+
return this.FinishRecordChangeRecord(rc, result ? 'success' : 'error', entityObject.LatestResult?.Error);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
throw new Error("Failed to create Record Change record");
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
catch (e) {
|
|
596
|
+
(0, core_1.LogError)(e);
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* This method will attempt to update the RecordChange record and return true if succesful, false otherwise.
|
|
602
|
+
*/
|
|
603
|
+
async FinishRecordChangeRecord(rc, code, errorMessage) {
|
|
604
|
+
try {
|
|
605
|
+
rc.Status = code === 'error' ? 'Error' : 'Complete';
|
|
606
|
+
rc.ErrorLog = errorMessage;
|
|
607
|
+
if (await rc.Save())
|
|
608
|
+
return true;
|
|
609
|
+
else
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
catch (e) {
|
|
613
|
+
(0, core_1.LogError)(e);
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Creates a new record change record for the start of the replay process.
|
|
619
|
+
* @param change
|
|
620
|
+
*/
|
|
621
|
+
async CreateRecordChangeRecord(md, run, change) {
|
|
622
|
+
try {
|
|
623
|
+
const rc = await md.GetEntityObject("Record Changes", this.ContextUser);
|
|
624
|
+
rc.EntityID = change.Entity.ID;
|
|
625
|
+
if (change.LegacyKey)
|
|
626
|
+
rc.RecordID = change.LegacyKeyValue; // need to match legacy key otherwise the other RC records will keep coming back up in detect changes runs in the future
|
|
627
|
+
else
|
|
628
|
+
rc.RecordID = change.PrimaryKey.ToConcatenatedString();
|
|
629
|
+
rc.Source = 'External';
|
|
630
|
+
rc.Type = change.Type;
|
|
631
|
+
rc.Status = 'Pending';
|
|
632
|
+
if (change.ChangedAt)
|
|
633
|
+
rc.ChangedAt = change.ChangedAt;
|
|
634
|
+
else {
|
|
635
|
+
// we don't have a ChangedAt from the database, so we need to use the current date
|
|
636
|
+
// however, we want UTC date/time for now as that is what we use in the DB for all of
|
|
637
|
+
// these fields.
|
|
638
|
+
const d = new Date();
|
|
639
|
+
rc.ChangedAt = new Date(d.toISOString());
|
|
640
|
+
}
|
|
641
|
+
const changesObject = {};
|
|
642
|
+
for (const field of change.Changes) {
|
|
643
|
+
changesObject[field.FieldName] = {
|
|
644
|
+
field: field.FieldName,
|
|
645
|
+
oldValue: field.OldValue,
|
|
646
|
+
newValue: field.NewValue
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
if (change.Type === 'Update')
|
|
650
|
+
rc.ChangesJSON = JSON.stringify(changesObject);
|
|
651
|
+
else
|
|
652
|
+
rc.ChangesJSON = ''; // not null
|
|
653
|
+
if (change.Type !== 'Delete') {
|
|
654
|
+
const obj = change.LatestRecord?.GetAll();
|
|
655
|
+
if (obj)
|
|
656
|
+
rc.FullRecordJSON = JSON.stringify(obj);
|
|
657
|
+
else
|
|
658
|
+
rc.FullRecordJSON = ''; // null not allowed
|
|
659
|
+
}
|
|
660
|
+
else
|
|
661
|
+
rc.FullRecordJSON = ''; // null not allowed
|
|
662
|
+
const provider = core_1.Metadata.Provider;
|
|
663
|
+
if (change.Type === 'Update')
|
|
664
|
+
rc.ChangesDescription = provider.CreateUserDescriptionOfChanges(changesObject);
|
|
665
|
+
else if (change.Type === 'Create')
|
|
666
|
+
rc.ChangesDescription = 'New Record';
|
|
667
|
+
else
|
|
668
|
+
rc.ChangesDescription = 'Record Deleted';
|
|
669
|
+
rc.ReplayRunID = run.ID;
|
|
670
|
+
rc.UserID = this.ContextUser.ID;
|
|
671
|
+
if (await rc.Save()) {
|
|
672
|
+
return rc;
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
throw new Error("Failed to save Record Change record: " + rc.LatestResult?.Message);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
catch (e) {
|
|
679
|
+
(0, core_1.LogError)(e);
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
211
683
|
}
|
|
212
684
|
exports.ExternalChangeDetectorEngine = ExternalChangeDetectorEngine;
|
|
213
685
|
//# sourceMappingURL=ChangeDetector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangeDetector.js","sourceRoot":"","sources":["../src/ChangeDetector.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChangeDetector.js","sourceRoot":"","sources":["../src/ChangeDetector.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/external-change-detection",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Library used by server side applications to determine if changes have been made to entities by external systems/integrations",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"typescript": "^5.4.5"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@memberjunction/core": "1.
|
|
23
|
-
"@memberjunction/core-entities": "1.
|
|
24
|
-
"@memberjunction/global": "1.
|
|
25
|
-
"@memberjunction/sqlserver-dataprovider": "1.
|
|
22
|
+
"@memberjunction/core": "1.8.1",
|
|
23
|
+
"@memberjunction/core-entities": "1.8.1",
|
|
24
|
+
"@memberjunction/global": "1.8.1",
|
|
25
|
+
"@memberjunction/sqlserver-dataprovider": "1.8.1"
|
|
26
26
|
}
|
|
27
27
|
}
|