meadow-integration 1.0.10 → 1.0.11

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.10",
3
+ "version": "1.0.11",
4
4
  "description": "Meadow Data Integration",
5
5
  "bin": {
6
6
  "mdwint": "source/cli/Meadow-Integration-CLI-Run.js"
@@ -45,6 +45,8 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
45
45
  this.Meadow = false;
46
46
 
47
47
  this.operation = new libMeadowOperation(this.fable);
48
+
49
+ this.skipSync = false;
48
50
  }
49
51
 
50
52
  initialize(fCallback)
@@ -72,6 +74,33 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
72
74
 
73
75
  return tmpProvider.createTable(this.EntitySchema, (pCreateError) =>
74
76
  {
77
+ let fValidateAndCallback = (pPriorError) =>
78
+ {
79
+ // Validate local table schema with a lightweight read
80
+ const tmpValidationQuery = this.Meadow.query;
81
+ tmpValidationQuery.setCap(1);
82
+ tmpValidationQuery.setDisableDeleteTracking(true);
83
+ this.Meadow.doRead(tmpValidationQuery,
84
+ (pReadError) =>
85
+ {
86
+ if (pReadError)
87
+ {
88
+ let tmpErrorStr = (typeof(pReadError) === 'string') ? pReadError : JSON.stringify(pReadError);
89
+ // Only skip sync for schema-specific errors (invalid column/object name)
90
+ // Generic provider errors (e.g. prepared statement failures) should not block sync
91
+ if (tmpErrorStr.indexOf('Invalid column') > -1 || tmpErrorStr.indexOf('Invalid object') > -1 || tmpErrorStr.indexOf('no such column') > -1 || tmpErrorStr.indexOf('no such table') > -1)
92
+ {
93
+ this.log.warn(`${this.EntitySchema.TableName}: local table schema validation failed (${pReadError}); this entity will be skipped during sync.`);
94
+ this.skipSync = true;
95
+ }
96
+ else
97
+ {
98
+ this.log.warn(`${this.EntitySchema.TableName}: validation read returned error (${pReadError}); sync will proceed.`);
99
+ }
100
+ }
101
+ return fCallback(pPriorError);
102
+ });
103
+ };
75
104
  if (pCreateError)
76
105
  {
77
106
  this.log.warn(`${this.EntitySchema.TableName}: createTable returned error: ${pCreateError}`);
@@ -83,13 +112,13 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
83
112
  if (!tmpGUIDColumn && !tmpDeletedColumn)
84
113
  {
85
114
  this.log.info(`No GUID or Deleted columns for ${this.EntitySchema.TableName}; skipping index creation`);
86
- return fCallback(pCreateError);
115
+ return fValidateAndCallback(pCreateError);
87
116
  }
88
117
 
89
118
  if (!this.fable.MeadowConnectionManager || !this.fable.MeadowConnectionManager.ConnectionPool)
90
119
  {
91
120
  this.log.info(`No connection manager available; skipping index creation for ${this.EntitySchema.TableName}`);
92
- return fCallback(pCreateError);
121
+ return fValidateAndCallback(pCreateError);
93
122
  }
94
123
 
95
124
  let tmpAnticipate = this.fable.newAnticipate();
@@ -115,7 +144,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
115
144
  {
116
145
  this.log.warn(`${this.EntitySchema.TableName}: Index creation error: ${pIndexError}`);
117
146
  }
118
- return fCallback(pIndexError || pCreateError);
147
+ return fValidateAndCallback(pIndexError || pCreateError);
119
148
  });
120
149
  });
121
150
  }
@@ -301,6 +330,12 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
301
330
 
302
331
  sync(fCallback)
303
332
  {
333
+ if (this.skipSync)
334
+ {
335
+ this.log.warn(`Skipping sync for ${this.EntitySchema.TableName} -- local table schema does not match expected schema.`);
336
+ return fCallback();
337
+ }
338
+
304
339
  this.operation.createTimeStamp('EntityInitialSync');
305
340
 
306
341
  this.log.info(`Syncing ${this.EntitySchema.TableName} (PageSize: ${this.PageSize}, SyncDeletedRecords: ${this.SyncDeletedRecords})`);
@@ -377,7 +412,8 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
377
412
  {
378
413
  if (pError)
379
414
  {
380
- return fStageComplete(`Error getting server max entity ID ${this.EntitySchema.TableName}: ${pError}`);
415
+ this.fable.log.warn(`Could not get server max entity ID for ${this.EntitySchema.TableName} (${pError}); continuing sync.`);
416
+ return fStageComplete();
381
417
  }
382
418
  if (pBody && pBody.hasOwnProperty(this.DefaultIdentifier))
383
419
  {
@@ -394,7 +430,9 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
394
430
  {
395
431
  if (pError)
396
432
  {
397
- return fStageComplete(`Error getting server count for ${this.EntitySchema.TableName}: ${pError}`);
433
+ this.fable.log.warn(`Could not get server count for ${this.EntitySchema.TableName} (${pError}); estimating from max ID.`);
434
+ tmpSyncState.Server.RecordCount = tmpSyncState.Server.MaxIDEntity > 0 ? tmpSyncState.Server.MaxIDEntity : 0;
435
+ return fStageComplete();
398
436
  }
399
437
  if (pBody && pBody.hasOwnProperty('Count'))
400
438
  {
@@ -451,7 +489,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
451
489
  this.fable.log.error(`${this.EntitySchema.TableName}: page ${tmpPageIndex} download error: ${pDownloadError}`);
452
490
  return fDownloadComplete();
453
491
  }
454
- if (pBody && pBody.length > 0)
492
+ if (pBody && Array.isArray(pBody) && pBody.length > 0)
455
493
  {
456
494
  this.fable.Utility.eachLimit(pBody, 5,
457
495
  (pEntityRecord, fEntitySyncComplete) =>
@@ -45,6 +45,8 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
45
45
  this.Meadow = false;
46
46
 
47
47
  this.operation = new libMeadowOperation(this.fable);
48
+
49
+ this.skipSync = false;
48
50
  }
49
51
 
50
52
  initialize(fCallback)
@@ -60,19 +62,46 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
60
62
  {
61
63
  return this.Meadow.provider.getProvider().createTable(this.EntitySchema, (pCreateError) =>
62
64
  {
65
+ let fValidateAndCallback = (pPriorError) =>
66
+ {
67
+ // Validate local table schema with a lightweight read
68
+ const tmpValidationQuery = this.Meadow.query;
69
+ tmpValidationQuery.setCap(1);
70
+ tmpValidationQuery.setDisableDeleteTracking(true);
71
+ this.Meadow.doRead(tmpValidationQuery,
72
+ (pReadError) =>
73
+ {
74
+ if (pReadError)
75
+ {
76
+ let tmpErrorStr = (typeof(pReadError) === 'string') ? pReadError : JSON.stringify(pReadError);
77
+ // Only skip sync for schema-specific errors (invalid column/object name)
78
+ // Generic provider errors (e.g. prepared statement failures) should not block sync
79
+ if (tmpErrorStr.indexOf('Invalid column') > -1 || tmpErrorStr.indexOf('Invalid object') > -1 || tmpErrorStr.indexOf('no such column') > -1 || tmpErrorStr.indexOf('no such table') > -1)
80
+ {
81
+ this.log.warn(`${this.EntitySchema.TableName}: local table schema validation failed (${pReadError}); this entity will be skipped during sync.`);
82
+ this.skipSync = true;
83
+ }
84
+ else
85
+ {
86
+ this.log.warn(`${this.EntitySchema.TableName}: validation read returned error (${pReadError}); sync will proceed.`);
87
+ }
88
+ }
89
+ return fCallback(pPriorError);
90
+ });
91
+ };
63
92
  const tmpGUIDColumn = this.EntitySchema.Columns.find((c) => c.DataType == 'GUID');
64
93
  const tmpDeletedColumn = this.EntitySchema.Columns.find((c) => c.Column == 'Deleted');
65
94
 
66
95
  if (!tmpGUIDColumn && !tmpDeletedColumn)
67
96
  {
68
97
  this.log.info(`No GUID or Deleted columns for ${this.EntitySchema.TableName}; skipping index creation`);
69
- return fCallback(pCreateError);
98
+ return fValidateAndCallback(pCreateError);
70
99
  }
71
100
 
72
101
  if (!this.fable.MeadowConnectionManager || !this.fable.MeadowConnectionManager.ConnectionPool)
73
102
  {
74
103
  this.log.info(`No connection manager available; skipping index creation for ${this.EntitySchema.TableName}`);
75
- return fCallback(pCreateError);
104
+ return fValidateAndCallback(pCreateError);
76
105
  }
77
106
 
78
107
  let tmpAnticipate = this.fable.newAnticipate();
@@ -92,7 +121,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
92
121
  return this.fable.MeadowConnectionManager.createIndex(this.EntitySchema, tmpDeletedColumn, false, fNext);
93
122
  });
94
123
  }
95
- tmpAnticipate.wait(fCallback);
124
+ tmpAnticipate.wait((pIndexError) => { return fValidateAndCallback(pCreateError); });
96
125
  });
97
126
  }
98
127
  return fCallback();
@@ -288,7 +317,7 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
288
317
  this.fable.log.error(`Error getting URL Partial [${tmpURLPartial}]: ${pDownloadError}`, { Error: pDownloadError });
289
318
  return fNext();
290
319
  }
291
- if (pBody && pBody.length > 0)
320
+ if (pBody && Array.isArray(pBody) && pBody.length > 0)
292
321
  {
293
322
  for (let i = 0; i < pBody.length; i++)
294
323
  {
@@ -420,6 +449,12 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
420
449
 
421
450
  sync(fCallback)
422
451
  {
452
+ if (this.skipSync)
453
+ {
454
+ this.log.warn(`Skipping sync for ${this.EntitySchema.TableName} -- local table schema does not match expected schema.`);
455
+ return fCallback();
456
+ }
457
+
423
458
  this.operation.createTimeStamp('EntityOngoingSync');
424
459
 
425
460
  let tmpAnticipate = this.fable.newAnticipate();
@@ -551,8 +586,8 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
551
586
  {
552
587
  if (pError)
553
588
  {
554
- this.fable.log.error(`Error getting server max entity ID ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
555
- return fStageComplete(`Error getting server max entity ID ${this.EntitySchema.TableName}: ${pError}`);
589
+ this.fable.log.warn(`Could not get server max entity ID for ${this.EntitySchema.TableName} (${pError}); continuing sync.`);
590
+ return fStageComplete();
556
591
  }
557
592
  if (pBody && pBody.hasOwnProperty(this.DefaultIdentifier))
558
593
  {
@@ -574,8 +609,8 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
574
609
  {
575
610
  if (pError)
576
611
  {
577
- this.fable.log.error(`Error getting server max UpdateDate ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
578
- return fStageComplete(`Error getting server max UpdateDate ${this.EntitySchema.TableName}: ${pError}`);
612
+ this.fable.log.warn(`Could not get server max UpdateDate for ${this.EntitySchema.TableName} (${pError}); will sync by ID only.`);
613
+ return fStageComplete();
579
614
  }
580
615
  if (pBody && pBody.hasOwnProperty(this.DefaultIdentifier))
581
616
  {
@@ -597,8 +632,9 @@ class MeadowSyncEntityOngoing extends libFableServiceProviderBase
597
632
  {
598
633
  if (pError)
599
634
  {
600
- this.fable.log.error(`Error getting server count for ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
601
- return fStageComplete(`Error getting server count for ${this.EntitySchema.TableName}: ${pError}`);
635
+ this.fable.log.warn(`Could not get server count for ${this.EntitySchema.TableName} (${pError}); estimating from max ID.`);
636
+ tmpSyncState.Server.RecordCount = tmpSyncState.Server.MaxIDEntity > 0 ? tmpSyncState.Server.MaxIDEntity : 0;
637
+ return fStageComplete();
602
638
  }
603
639
  if (pBody && pBody.hasOwnProperty('Count'))
604
640
  {