meadow-integration 1.0.13 → 1.0.14
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/package.json
CHANGED
|
@@ -46,6 +46,15 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
46
46
|
// pull all records in the range from the server instead of subdividing further.
|
|
47
47
|
this.BisectMinRangeSize = this.options.BisectMinRangeSize || 1000;
|
|
48
48
|
|
|
49
|
+
// Tolerance window in milliseconds for cross-database timestamp precision differences.
|
|
50
|
+
// MySQL DATETIME stores whole seconds, MSSQL DATETIME rounds to ~3.33ms increments,
|
|
51
|
+
// PostgreSQL TIMESTAMP stores microseconds, and SQLite stores as TEXT. When comparing
|
|
52
|
+
// timestamps across systems, the maximum rounding error is 1000ms (MySQL second-level
|
|
53
|
+
// truncation). Default 1000ms covers all supported provider combinations.
|
|
54
|
+
this.DateTimePrecisionMS = (typeof(this.options.DateTimePrecisionMS) === 'number')
|
|
55
|
+
? this.options.DateTimePrecisionMS
|
|
56
|
+
: 1000;
|
|
57
|
+
|
|
49
58
|
this.Meadow = false;
|
|
50
59
|
|
|
51
60
|
this.operation = new libMeadowOperation(this.fable);
|
|
@@ -150,10 +159,31 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
150
159
|
|
|
151
160
|
// ---- REST / Local query helpers ----
|
|
152
161
|
|
|
162
|
+
// Normalize a date value to a UTC dayJS instance.
|
|
163
|
+
//
|
|
164
|
+
// Local dates stored in SQLite are in UTC but formatted without a timezone
|
|
165
|
+
// indicator (e.g. "2022-05-10 22:50:26.000"). When the driver or ORM wraps
|
|
166
|
+
// them in a JavaScript Date object, JS interprets them as local time, shifting
|
|
167
|
+
// the value by the machine's UTC offset. To recover the original naive UTC
|
|
168
|
+
// time, we format through local time (which undoes the offset) then re-parse
|
|
169
|
+
// as UTC. Server dates already carry a "Z" suffix and are parsed correctly.
|
|
170
|
+
_normalizeDateUTC(pDate)
|
|
171
|
+
{
|
|
172
|
+
if (typeof(pDate) === 'string')
|
|
173
|
+
{
|
|
174
|
+
// String dates — strip any trailing Z or timezone so dayJS.utc() treats as UTC
|
|
175
|
+
return this.fable.Dates.dayJS.utc(pDate);
|
|
176
|
+
}
|
|
177
|
+
// Date objects (from SQLite via ORM) — format as local time string to recover
|
|
178
|
+
// the naive stored value, then re-parse as UTC
|
|
179
|
+
let tmpNaiveStr = this.fable.Dates.dayJS(pDate).format('YYYY-MM-DD HH:mm:ss.SSS');
|
|
180
|
+
return this.fable.Dates.dayJS.utc(tmpNaiveStr);
|
|
181
|
+
}
|
|
182
|
+
|
|
153
183
|
// Format a date value for use in Meadow REST filter expressions (FBV).
|
|
154
184
|
_formatDateForFilter(pDate)
|
|
155
185
|
{
|
|
156
|
-
return this.
|
|
186
|
+
return this._normalizeDateUTC(pDate).format('YYYY-MM-DDTHH:mm:ss.SSS');
|
|
157
187
|
}
|
|
158
188
|
|
|
159
189
|
// Get a count from the remote server, optionally filtered.
|
|
@@ -433,6 +463,16 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
433
463
|
fFetchPage();
|
|
434
464
|
}
|
|
435
465
|
|
|
466
|
+
// Increment the FullSync progress tracker by pCount records checked/synced.
|
|
467
|
+
_incrementProgress(pCount)
|
|
468
|
+
{
|
|
469
|
+
let tmpTracker = this.operation.progressTrackers[`FullSync-${this.EntitySchema.TableName}`];
|
|
470
|
+
if (tmpTracker && pCount > 0)
|
|
471
|
+
{
|
|
472
|
+
tmpTracker.CurrentCount = Math.min(tmpTracker.CurrentCount + pCount, tmpTracker.TotalCount);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
436
476
|
// ---- Bisection logic ----
|
|
437
477
|
|
|
438
478
|
// Compare a local ID range against the server. If counts or date boundaries
|
|
@@ -470,6 +510,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
470
510
|
if (!this._hasUpdateDate)
|
|
471
511
|
{
|
|
472
512
|
// No UpdateDate column -- counts match, assume in sync
|
|
513
|
+
this._incrementProgress(pServerCount);
|
|
473
514
|
return fCallback();
|
|
474
515
|
}
|
|
475
516
|
|
|
@@ -493,11 +534,12 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
493
534
|
}
|
|
494
535
|
|
|
495
536
|
const tmpServerMaxDate = pServerMaxRecords[0].UpdateDate;
|
|
496
|
-
const tmpMaxDateDiff = Math.abs(this.
|
|
537
|
+
const tmpMaxDateDiff = Math.abs(this._normalizeDateUTC(pLocalMaxDate).diff(this._normalizeDateUTC(tmpServerMaxDate)));
|
|
497
538
|
|
|
498
|
-
if (tmpMaxDateDiff
|
|
539
|
+
if (tmpMaxDateDiff <= this.DateTimePrecisionMS)
|
|
499
540
|
{
|
|
500
541
|
// Max dates match and counts match -- this range is in sync
|
|
542
|
+
this._incrementProgress(pServerCount);
|
|
501
543
|
return fCallback();
|
|
502
544
|
}
|
|
503
545
|
|
|
@@ -562,6 +604,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
562
604
|
{
|
|
563
605
|
this.fable.log.info(`${this.EntitySchema.TableName}: synced ${pSyncedCount} records in range ${pMinID}-${pMaxID}`);
|
|
564
606
|
}
|
|
607
|
+
this._incrementProgress(pSyncedCount || 0);
|
|
565
608
|
return fCallback();
|
|
566
609
|
});
|
|
567
610
|
}
|
|
@@ -890,6 +933,13 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
890
933
|
});
|
|
891
934
|
},
|
|
892
935
|
|
|
936
|
+
// Create a progress tracker so callers (e.g. data-cloner UI) can see Total/Synced
|
|
937
|
+
(fStageComplete) =>
|
|
938
|
+
{
|
|
939
|
+
this.operation.createProgressTracker(tmpSyncState.Server.RecordCount, `FullSync-${this.EntitySchema.TableName}`);
|
|
940
|
+
return fStageComplete();
|
|
941
|
+
},
|
|
942
|
+
|
|
893
943
|
// ---- Stage 3: UpdateDate-based fast sync ----
|
|
894
944
|
// If we have UpdateDate, compare server record count up to our local
|
|
895
945
|
// max UpdateDate. If it matches local count, existing records are in
|
|
@@ -926,6 +976,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
926
976
|
// Record counts match up to our max UpdateDate -- existing records are in sync.
|
|
927
977
|
this.fable.log.info(`${this.EntitySchema.TableName}: counts match up to local max UpdateDate; existing records appear in sync.`);
|
|
928
978
|
tmpSyncState.ExistingRecordsInSync = true;
|
|
979
|
+
this._incrementProgress(pServerCountBefore);
|
|
929
980
|
}
|
|
930
981
|
else
|
|
931
982
|
{
|
|
@@ -951,6 +1002,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
951
1002
|
if (pServerCountAfter < 1)
|
|
952
1003
|
{
|
|
953
1004
|
tmpSyncState.UpdateDateSyncDone = true;
|
|
1005
|
+
// No new records -- nothing additional to count
|
|
954
1006
|
return fStageComplete();
|
|
955
1007
|
}
|
|
956
1008
|
|
|
@@ -965,6 +1017,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
965
1017
|
{
|
|
966
1018
|
this.fable.log.info(`${this.EntitySchema.TableName}: pulled ${pSyncedCount} new/modified records via UpdateDate.`);
|
|
967
1019
|
}
|
|
1020
|
+
this._incrementProgress(pSyncedCount || 0);
|
|
968
1021
|
tmpSyncState.UpdateDateSyncDone = true;
|
|
969
1022
|
return fStageComplete();
|
|
970
1023
|
});
|
|
@@ -1047,6 +1100,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
1047
1100
|
{
|
|
1048
1101
|
this.fable.log.info(`${this.EntitySchema.TableName}: pulled ${pSyncedCount} new records by ID.`);
|
|
1049
1102
|
}
|
|
1103
|
+
this._incrementProgress(pSyncedCount || 0);
|
|
1050
1104
|
return fStageComplete();
|
|
1051
1105
|
});
|
|
1052
1106
|
},
|
|
@@ -1058,6 +1112,13 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
1058
1112
|
this.fable.log.error(`Error performing ongoing sync ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
|
|
1059
1113
|
}
|
|
1060
1114
|
|
|
1115
|
+
// Mark progress tracker as complete so the UI shows the correct totals
|
|
1116
|
+
let tmpTracker = this.operation.progressTrackers[`FullSync-${this.EntitySchema.TableName}`];
|
|
1117
|
+
if (tmpTracker)
|
|
1118
|
+
{
|
|
1119
|
+
tmpTracker.CurrentCount = tmpTracker.TotalCount;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1061
1122
|
this.fable.log.info(`${this.EntitySchema.TableName}: ongoing sync complete.`);
|
|
1062
1123
|
|
|
1063
1124
|
if (this.SyncDeletedRecords)
|
|
@@ -65,6 +65,18 @@ class MeadowSync extends libFableServiceProviderBase
|
|
|
65
65
|
this.MaxRecordsPerEntity = parseInt(this.options.MaxRecordsPerEntity, 10) || 0;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
// Tolerance window in milliseconds for cross-database timestamp precision differences.
|
|
69
|
+
// Passed through to Ongoing sync entities for bisection date comparison.
|
|
70
|
+
this.DateTimePrecisionMS = 1000;
|
|
71
|
+
if (this.fable.ProgramConfiguration.hasOwnProperty('DateTimePrecisionMS'))
|
|
72
|
+
{
|
|
73
|
+
this.DateTimePrecisionMS = parseInt(this.fable.ProgramConfiguration.DateTimePrecisionMS, 10) || 1000;
|
|
74
|
+
}
|
|
75
|
+
else if (this.options.hasOwnProperty('DateTimePrecisionMS'))
|
|
76
|
+
{
|
|
77
|
+
this.DateTimePrecisionMS = parseInt(this.options.DateTimePrecisionMS, 10) || 1000;
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
this.MeadowSchema = false;
|
|
69
81
|
this.MeadowSchemaTableList = false;
|
|
70
82
|
|
|
@@ -101,6 +113,7 @@ class MeadowSync extends libFableServiceProviderBase
|
|
|
101
113
|
PageSize: this.options.PageSize || 100,
|
|
102
114
|
SyncDeletedRecords: this.SyncDeletedRecords,
|
|
103
115
|
MaxRecordsPerEntity: this.MaxRecordsPerEntity,
|
|
116
|
+
DateTimePrecisionMS: this.DateTimePrecisionMS,
|
|
104
117
|
};
|
|
105
118
|
|
|
106
119
|
let tmpSyncEntity;
|