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.14",
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.30",
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
- return fRecordDone();
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
- return fFetchPage();
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
- this._incrementProgress(pSyncedCount || 0);
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 : JSON.stringify(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.operation.createProgressTracker(tmpSyncState.Server.RecordCount, `FullSync-${this.EntitySchema.TableName}`);
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
- this._incrementProgress(pSyncedCount || 0);
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
- this._incrementProgress(pSyncedCount || 0);
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(); });