meadow-integration 1.0.14 → 1.0.16
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meadow-integration",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "Meadow Data Integration",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mdwint": "source/cli/Meadow-Integration-CLI-Run.js"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"fable": "^3.1.63",
|
|
41
41
|
"fable-serviceproviderbase": "^3.0.19",
|
|
42
|
-
"meadow": "^2.0.
|
|
42
|
+
"meadow": "^2.0.33",
|
|
43
43
|
"meadow-connection-mssql": "^1.0.16",
|
|
44
44
|
"meadow-connection-mysql": "^1.0.14",
|
|
45
45
|
"orator": "^6.0.4",
|
|
@@ -297,6 +297,10 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
297
297
|
(pDeleteSyncError) =>
|
|
298
298
|
{
|
|
299
299
|
this.fable.log.info(`Delete sync complete for ${this.EntitySchema.TableName} (${tmpDeletedCount} deleted records processed).`);
|
|
300
|
+
if (this.syncResults)
|
|
301
|
+
{
|
|
302
|
+
this.syncResults.Deleted = tmpDeletedCount;
|
|
303
|
+
}
|
|
300
304
|
return fCallback();
|
|
301
305
|
});
|
|
302
306
|
});
|
|
@@ -599,6 +603,21 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
599
603
|
{
|
|
600
604
|
this.fable.log.error(`Error returned URL Partial .. this may not be an error: ${pDownloadError}`);
|
|
601
605
|
}
|
|
606
|
+
|
|
607
|
+
// Store sync results on the entity so callers can inspect the breakdown
|
|
608
|
+
this.syncResults = (
|
|
609
|
+
{
|
|
610
|
+
Created: tmpRecordsCreated,
|
|
611
|
+
Skipped: tmpRecordsSkipped,
|
|
612
|
+
Errors: tmpRecordsErrored,
|
|
613
|
+
Deleted: 0,
|
|
614
|
+
ServerRecordCount: tmpSyncState.Server.RecordCount,
|
|
615
|
+
LocalRecordCount: tmpSyncState.Local.RecordCount,
|
|
616
|
+
ServerMaxID: tmpSyncState.Server.MaxIDEntity,
|
|
617
|
+
LocalMaxID: tmpSyncState.Local.MaxIDEntity,
|
|
618
|
+
EstimatedNew: tmpSyncState.EstimatedRecordCount
|
|
619
|
+
});
|
|
620
|
+
|
|
602
621
|
fStageComplete();
|
|
603
622
|
});
|
|
604
623
|
},
|
|
@@ -372,6 +372,10 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
372
372
|
{
|
|
373
373
|
this.log.error(`Fallback update also failed for ${this.EntitySchema.TableName} ID ${pServerRecord[this.DefaultIdentifier]}: ${pUpdateError}`);
|
|
374
374
|
}
|
|
375
|
+
else
|
|
376
|
+
{
|
|
377
|
+
this._recordsUpdated++;
|
|
378
|
+
}
|
|
375
379
|
return fCallback();
|
|
376
380
|
});
|
|
377
381
|
return;
|
|
@@ -379,6 +383,10 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
379
383
|
this.log.error(`Error creating record ${this.EntitySchema.TableName}: ${pCreateError}`, pCreateError);
|
|
380
384
|
return fCallback();
|
|
381
385
|
}
|
|
386
|
+
else
|
|
387
|
+
{
|
|
388
|
+
this._recordsCreated++;
|
|
389
|
+
}
|
|
382
390
|
return fCallback();
|
|
383
391
|
});
|
|
384
392
|
}
|
|
@@ -392,6 +400,10 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
392
400
|
{
|
|
393
401
|
this.log.error(`Error updating record ${this.EntitySchema.TableName}: ${pUpdateError}`, pUpdateError);
|
|
394
402
|
}
|
|
403
|
+
else
|
|
404
|
+
{
|
|
405
|
+
this._recordsUpdated++;
|
|
406
|
+
}
|
|
395
407
|
return fCallback();
|
|
396
408
|
});
|
|
397
409
|
}
|
|
@@ -407,12 +419,22 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
407
419
|
return fCallback(null, 0);
|
|
408
420
|
}
|
|
409
421
|
|
|
422
|
+
// Check the global cap before starting -- if we have already synced
|
|
423
|
+
// MaxRecordsPerEntity records across all stages, stop immediately.
|
|
424
|
+
if (this.MaxRecordsPerEntity > 0 && this._totalSyncedThisSync >= this.MaxRecordsPerEntity)
|
|
425
|
+
{
|
|
426
|
+
this.fable.log.info(`${this.EntitySchema.TableName}: global record cap reached (${this._totalSyncedThisSync}/${this.MaxRecordsPerEntity}); skipping pull.`);
|
|
427
|
+
return fCallback(null, 0);
|
|
428
|
+
}
|
|
429
|
+
|
|
410
430
|
let tmpSyncedCount = 0;
|
|
411
431
|
let tmpOffset = 0;
|
|
412
432
|
let tmpDone = false;
|
|
413
433
|
|
|
434
|
+
// Apply per-call cap based on estimated count, then further limit by
|
|
435
|
+
// how many records remain before hitting the global MaxRecordsPerEntity.
|
|
414
436
|
let tmpRecordCap = (this.MaxRecordsPerEntity > 0)
|
|
415
|
-
? Math.min(pEstimatedCount, this.MaxRecordsPerEntity)
|
|
437
|
+
? Math.min(pEstimatedCount, this.MaxRecordsPerEntity - this._totalSyncedThisSync)
|
|
416
438
|
: pEstimatedCount;
|
|
417
439
|
|
|
418
440
|
const fFetchPage = () =>
|
|
@@ -443,11 +465,16 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
443
465
|
() =>
|
|
444
466
|
{
|
|
445
467
|
tmpSyncedCount++;
|
|
446
|
-
|
|
468
|
+
this._totalSyncedThisSync++;
|
|
469
|
+
// Use setImmediate to yield the event loop and prevent
|
|
470
|
+
// stack overflow when SQLite callbacks complete synchronously
|
|
471
|
+
return setImmediate(fRecordDone);
|
|
447
472
|
});
|
|
448
473
|
},
|
|
449
474
|
(pUpsertError) =>
|
|
450
475
|
{
|
|
476
|
+
// Increment per-page progress so the UI reflects sync in real-time
|
|
477
|
+
this._incrementProgress(pRecords.length);
|
|
451
478
|
tmpOffset += this.PageSize;
|
|
452
479
|
if (pRecords.length < this.PageSize)
|
|
453
480
|
{
|
|
@@ -455,7 +482,8 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
455
482
|
return fCallback(null, tmpSyncedCount);
|
|
456
483
|
}
|
|
457
484
|
this.fable.log.info(`${this.EntitySchema.TableName}: pulled ${tmpSyncedCount} of ~${tmpRecordCap} records...`);
|
|
458
|
-
|
|
485
|
+
// Use setImmediate to break the recursive call chain across pages
|
|
486
|
+
return setImmediate(fFetchPage);
|
|
459
487
|
});
|
|
460
488
|
});
|
|
461
489
|
};
|
|
@@ -480,6 +508,12 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
480
508
|
// the range from the server to bring local in sync.
|
|
481
509
|
_bisectRange(pMinID, pMaxID, pDepth, fCallback)
|
|
482
510
|
{
|
|
511
|
+
// If the global record cap has been reached, stop bisecting
|
|
512
|
+
if (this.MaxRecordsPerEntity > 0 && this._totalSyncedThisSync >= this.MaxRecordsPerEntity)
|
|
513
|
+
{
|
|
514
|
+
return fCallback();
|
|
515
|
+
}
|
|
516
|
+
|
|
483
517
|
const tmpRangeSize = pMaxID - pMinID + 1;
|
|
484
518
|
const tmpIDCol = this.DefaultIdentifier;
|
|
485
519
|
const tmpRangeFilter = `FBV~${tmpIDCol}~GE~${pMinID}~FBV~${tmpIDCol}~LE~${pMaxID}`;
|
|
@@ -604,7 +638,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
604
638
|
{
|
|
605
639
|
this.fable.log.info(`${this.EntitySchema.TableName}: synced ${pSyncedCount} records in range ${pMinID}-${pMaxID}`);
|
|
606
640
|
}
|
|
607
|
-
|
|
641
|
+
// Per-page progress is now tracked inside _pullServerRecords()
|
|
608
642
|
return fCallback();
|
|
609
643
|
});
|
|
610
644
|
}
|
|
@@ -763,7 +797,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
763
797
|
{
|
|
764
798
|
if (pReadError)
|
|
765
799
|
{
|
|
766
|
-
let tmpErrorStr = (typeof(pReadError) === 'string') ? pReadError :
|
|
800
|
+
let tmpErrorStr = (typeof(pReadError) === 'string') ? pReadError : String(pReadError);
|
|
767
801
|
if (tmpErrorStr.indexOf('Invalid column') > -1 || tmpErrorStr.indexOf('Invalid object') > -1 || tmpErrorStr.indexOf('no such column') > -1 || tmpErrorStr.indexOf('no such table') > -1)
|
|
768
802
|
{
|
|
769
803
|
this.log.warn(`${this.EntitySchema.TableName}: local table schema mismatch (${pReadError}); skipping sync.`);
|
|
@@ -778,6 +812,13 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
778
812
|
{
|
|
779
813
|
this.operation.createTimeStamp('EntityOngoingSync');
|
|
780
814
|
|
|
815
|
+
// Track total records synced across all stages to enforce MaxRecordsPerEntity globally
|
|
816
|
+
this._totalSyncedThisSync = 0;
|
|
817
|
+
|
|
818
|
+
// Track per-record create vs update counts for the sync report
|
|
819
|
+
this._recordsCreated = 0;
|
|
820
|
+
this._recordsUpdated = 0;
|
|
821
|
+
|
|
781
822
|
const tmpSyncState = (
|
|
782
823
|
{
|
|
783
824
|
Local: { MaxIDEntity: -1, RecordCount: 0 },
|
|
@@ -936,7 +977,10 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
936
977
|
// Create a progress tracker so callers (e.g. data-cloner UI) can see Total/Synced
|
|
937
978
|
(fStageComplete) =>
|
|
938
979
|
{
|
|
939
|
-
this.
|
|
980
|
+
let tmpTrackerTotal = (this.MaxRecordsPerEntity > 0)
|
|
981
|
+
? Math.min(tmpSyncState.Server.RecordCount, this.MaxRecordsPerEntity)
|
|
982
|
+
: tmpSyncState.Server.RecordCount;
|
|
983
|
+
this.operation.createProgressTracker(tmpTrackerTotal, `FullSync-${this.EntitySchema.TableName}`);
|
|
940
984
|
return fStageComplete();
|
|
941
985
|
},
|
|
942
986
|
|
|
@@ -1017,7 +1061,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
1017
1061
|
{
|
|
1018
1062
|
this.fable.log.info(`${this.EntitySchema.TableName}: pulled ${pSyncedCount} new/modified records via UpdateDate.`);
|
|
1019
1063
|
}
|
|
1020
|
-
|
|
1064
|
+
// Per-page progress is now tracked inside _pullServerRecords()
|
|
1021
1065
|
tmpSyncState.UpdateDateSyncDone = true;
|
|
1022
1066
|
return fStageComplete();
|
|
1023
1067
|
});
|
|
@@ -1100,7 +1144,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
1100
1144
|
{
|
|
1101
1145
|
this.fable.log.info(`${this.EntitySchema.TableName}: pulled ${pSyncedCount} new records by ID.`);
|
|
1102
1146
|
}
|
|
1103
|
-
|
|
1147
|
+
// Per-page progress is now tracked inside _pullServerRecords()
|
|
1104
1148
|
return fStageComplete();
|
|
1105
1149
|
});
|
|
1106
1150
|
},
|
|
@@ -1121,6 +1165,15 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
|
|
|
1121
1165
|
|
|
1122
1166
|
this.fable.log.info(`${this.EntitySchema.TableName}: ongoing sync complete.`);
|
|
1123
1167
|
|
|
1168
|
+
// Store sync results so callers can inspect the breakdown
|
|
1169
|
+
this.syncResults = {
|
|
1170
|
+
Created: this._recordsCreated,
|
|
1171
|
+
Updated: this._recordsUpdated,
|
|
1172
|
+
Deleted: 0,
|
|
1173
|
+
ServerRecordCount: tmpSyncState.Server.RecordCount,
|
|
1174
|
+
LocalRecordCount: tmpSyncState.Local.RecordCount
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1124
1177
|
if (this.SyncDeletedRecords)
|
|
1125
1178
|
{
|
|
1126
1179
|
return this.syncDeletedRecords(() => { return fCallback(); });
|