meadow-integration 1.0.7 → 1.0.9
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.9",
|
|
4
4
|
"description": "Meadow Data Integration",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mdwint": "source/cli/Meadow-Integration-CLI-Run.js"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"author": "steven velozo <steven@velozo.com>",
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"quackage": "^1.0.
|
|
19
|
+
"quackage": "^1.0.63"
|
|
20
20
|
},
|
|
21
21
|
"mocha": {
|
|
22
22
|
"diff": true,
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"fable": "^3.1.63",
|
|
41
41
|
"fable-serviceproviderbase": "^3.0.19",
|
|
42
|
-
"meadow": "^2.0.
|
|
43
|
-
"meadow-connection-mysql": "^1.0.
|
|
44
|
-
"meadow-connection-mssql": "^1.0.
|
|
42
|
+
"meadow": "^2.0.30",
|
|
43
|
+
"meadow-connection-mysql": "^1.0.14",
|
|
44
|
+
"meadow-connection-mssql": "^1.0.16",
|
|
45
45
|
"orator": "^6.0.4",
|
|
46
46
|
"orator-serviceserver-restify": "^2.0.9",
|
|
47
47
|
"pict-service-commandlineutility": "^1.0.19"
|
|
@@ -6,6 +6,14 @@ const defaultRestClientOptions = (
|
|
|
6
6
|
{
|
|
7
7
|
DownloadBatchSize: 100,
|
|
8
8
|
|
|
9
|
+
// Request timeout in milliseconds for normal remote API calls.
|
|
10
|
+
// Default: 60 seconds.
|
|
11
|
+
RequestTimeout: 60000,
|
|
12
|
+
|
|
13
|
+
// Request timeout in milliseconds for MAX(column) queries,
|
|
14
|
+
// which can be very slow on large tables. Default: 5 minutes.
|
|
15
|
+
MaxRequestTimeout: 300000,
|
|
16
|
+
|
|
9
17
|
ServerURL: 'https://localhost:8080/1.0/',
|
|
10
18
|
UserID: false,
|
|
11
19
|
Password: false,
|
|
@@ -36,7 +44,12 @@ class MeadowCloneRestClient extends libFableServiceProviderBase
|
|
|
36
44
|
this.restClient = this.fable.serviceManager.instantiateServiceProvider('RestClient', {}, 'MeadowCloneRestClient-RestClient');
|
|
37
45
|
this.cache = {};
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
this.requestTimeout = this.options.RequestTimeout;
|
|
48
|
+
this.maxRequestTimeout = this.options.MaxRequestTimeout;
|
|
49
|
+
|
|
50
|
+
// Use the longer of the two timeouts for the agent's socket timeout
|
|
51
|
+
// so that MAX queries don't get killed at the socket level.
|
|
52
|
+
const agentOptions = { keepAlive: true, timeout: Math.max(this.requestTimeout, this.maxRequestTimeout) };
|
|
40
53
|
|
|
41
54
|
if (this.serverURL && this.serverURL.startsWith('http:'))
|
|
42
55
|
{
|
|
@@ -53,12 +53,29 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
53
53
|
this.Meadow = this.fable.Meadow.loadFromPackageObject(this.EntitySchema.MeadowSchema);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
this.log.info(`Sync for ${this.EntitySchema.TableName} creating table if it doesn't exist...`);
|
|
57
|
-
|
|
58
56
|
if (this.Meadow && this.Meadow.provider)
|
|
59
57
|
{
|
|
60
|
-
|
|
58
|
+
let tmpProvider = this.Meadow.provider.getProvider();
|
|
59
|
+
|
|
60
|
+
if (!tmpProvider)
|
|
61
|
+
{
|
|
62
|
+
this.log.error(`No provider returned by getProvider() for ${this.EntitySchema.TableName}`);
|
|
63
|
+
return fCallback(new Error(`No provider returned by getProvider() for ${this.EntitySchema.TableName}`));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!tmpProvider.createTable)
|
|
61
67
|
{
|
|
68
|
+
this.log.error(`Provider for ${this.EntitySchema.TableName} has no createTable method.`);
|
|
69
|
+
return fCallback(new Error(`Provider for ${this.EntitySchema.TableName} has no createTable method`));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return tmpProvider.createTable(this.EntitySchema, (pCreateError) =>
|
|
73
|
+
{
|
|
74
|
+
if (pCreateError)
|
|
75
|
+
{
|
|
76
|
+
this.log.warn(`${this.EntitySchema.TableName}: createTable returned error: ${pCreateError}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
62
79
|
const tmpGUIDColumn = this.EntitySchema.Columns.find((c) => c.DataType == 'GUID');
|
|
63
80
|
const tmpDeletedColumn = this.EntitySchema.Columns.find((c) => c.Column == 'Deleted');
|
|
64
81
|
|
|
@@ -91,9 +108,17 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
91
108
|
return this.fable.MeadowConnectionManager.createIndex(this.EntitySchema, tmpDeletedColumn, false, fNext);
|
|
92
109
|
});
|
|
93
110
|
}
|
|
94
|
-
tmpAnticipate.wait(
|
|
111
|
+
tmpAnticipate.wait((pIndexError) =>
|
|
112
|
+
{
|
|
113
|
+
if (pIndexError)
|
|
114
|
+
{
|
|
115
|
+
this.log.warn(`${this.EntitySchema.TableName}: Index creation error: ${pIndexError}`);
|
|
116
|
+
}
|
|
117
|
+
return fCallback(pIndexError || pCreateError);
|
|
118
|
+
});
|
|
95
119
|
});
|
|
96
120
|
}
|
|
121
|
+
|
|
97
122
|
return fCallback();
|
|
98
123
|
}
|
|
99
124
|
|
|
@@ -274,6 +299,8 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
274
299
|
{
|
|
275
300
|
this.operation.createTimeStamp('EntityInitialSync');
|
|
276
301
|
|
|
302
|
+
this.log.info(`Syncing ${this.EntitySchema.TableName} (PageSize: ${this.PageSize}, SyncDeletedRecords: ${this.SyncDeletedRecords})`);
|
|
303
|
+
|
|
277
304
|
const tmpSyncState = (
|
|
278
305
|
{
|
|
279
306
|
Local: { MaxIDEntity: -1, RecordCount: 0 },
|
|
@@ -293,16 +320,12 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
293
320
|
{
|
|
294
321
|
if (pReadError)
|
|
295
322
|
{
|
|
296
|
-
this.fable.log.error(`Error reading local max entity ID ${this.EntitySchema.TableName}: ${pReadError}`, { Error: pReadError });
|
|
297
323
|
return fStageComplete(`Error reading local max entity ID ${this.EntitySchema.TableName}: ${pReadError}`);
|
|
298
324
|
}
|
|
299
|
-
if (
|
|
325
|
+
if (pRecord)
|
|
300
326
|
{
|
|
301
|
-
|
|
302
|
-
return fStageComplete();
|
|
327
|
+
tmpSyncState.Local.MaxIDEntity = pRecord[this.DefaultIdentifier];
|
|
303
328
|
}
|
|
304
|
-
this.fable.log.info(`Found local max entity ID ${this.EntitySchema.TableName}: ${pRecord[this.DefaultIdentifier]}`);
|
|
305
|
-
tmpSyncState.Local.MaxIDEntity = pRecord[this.DefaultIdentifier];
|
|
306
329
|
return fStageComplete();
|
|
307
330
|
});
|
|
308
331
|
},
|
|
@@ -315,7 +338,6 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
315
338
|
{
|
|
316
339
|
if (pCountError)
|
|
317
340
|
{
|
|
318
|
-
this.fable.log.error(`Error getting local count of ${this.EntitySchema.TableName}: ${pCountError}`, { Error: pCountError });
|
|
319
341
|
return fStageComplete(`Error getting local count of ${this.EntitySchema.TableName}: ${pCountError}`);
|
|
320
342
|
}
|
|
321
343
|
tmpSyncState.Local.RecordCount = pCount;
|
|
@@ -330,18 +352,12 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
330
352
|
{
|
|
331
353
|
if (pError)
|
|
332
354
|
{
|
|
333
|
-
this.fable.log.error(`Error getting server max entity ID ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
|
|
334
355
|
return fStageComplete(`Error getting server max entity ID ${this.EntitySchema.TableName}: ${pError}`);
|
|
335
356
|
}
|
|
336
357
|
if (pBody && pBody.hasOwnProperty(this.DefaultIdentifier))
|
|
337
358
|
{
|
|
338
|
-
this.fable.log.info(`Found server max entity ID ${this.EntitySchema.TableName}: ${pBody[this.DefaultIdentifier]}`);
|
|
339
359
|
tmpSyncState.Server.MaxIDEntity = pBody[this.DefaultIdentifier];
|
|
340
360
|
}
|
|
341
|
-
else
|
|
342
|
-
{
|
|
343
|
-
this.fable.log.warn(`No records found in server for max entity ID of ${this.EntitySchema.TableName}.`);
|
|
344
|
-
}
|
|
345
361
|
return fStageComplete();
|
|
346
362
|
});
|
|
347
363
|
},
|
|
@@ -353,18 +369,12 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
353
369
|
{
|
|
354
370
|
if (pError)
|
|
355
371
|
{
|
|
356
|
-
this.fable.log.error(`Error getting server count for ${this.EntitySchema.TableName}: ${pError}`, { Error: pError });
|
|
357
372
|
return fStageComplete(`Error getting server count for ${this.EntitySchema.TableName}: ${pError}`);
|
|
358
373
|
}
|
|
359
374
|
if (pBody && pBody.hasOwnProperty('Count'))
|
|
360
375
|
{
|
|
361
|
-
this.fable.log.info(`Found server count for ${this.EntitySchema.TableName}: ${pBody.Count}`);
|
|
362
376
|
tmpSyncState.Server.RecordCount = pBody.Count;
|
|
363
377
|
}
|
|
364
|
-
else
|
|
365
|
-
{
|
|
366
|
-
this.fable.log.warn(`No records found in server based on count for ${this.EntitySchema.TableName}.`);
|
|
367
|
-
}
|
|
368
378
|
return fStageComplete();
|
|
369
379
|
});
|
|
370
380
|
},
|
|
@@ -382,21 +392,28 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
382
392
|
tmpSyncState.URLPartials.push(`${this.EntitySchema.TableName}s/FilteredTo/FBV~${this.DefaultIdentifier}~GT~${tmpSyncState.Local.MaxIDEntity}~FSF~${this.DefaultIdentifier}~ASC~ASC/${i}/${this.PageSize}`);
|
|
383
393
|
}
|
|
384
394
|
|
|
385
|
-
this.fable.log.info(
|
|
395
|
+
this.fable.log.info(`${this.EntitySchema.TableName}: downloading ${tmpSyncState.URLPartials.length} pages (local: ${tmpSyncState.Local.RecordCount}/${tmpSyncState.Local.MaxIDEntity}, server: ${tmpSyncState.Server.RecordCount}/${tmpSyncState.Server.MaxIDEntity}, estimated new: ${tmpSyncState.EstimatedRecordCount})`);
|
|
386
396
|
|
|
387
397
|
return fStageComplete();
|
|
388
398
|
},
|
|
389
399
|
(fStageComplete) =>
|
|
390
400
|
{
|
|
401
|
+
let tmpPageIndex = 0;
|
|
402
|
+
let tmpRecordsCreated = 0;
|
|
403
|
+
let tmpRecordsSkipped = 0;
|
|
404
|
+
let tmpRecordsErrored = 0;
|
|
405
|
+
|
|
391
406
|
this.fable.Utility.eachLimit(tmpSyncState.URLPartials, 1,
|
|
392
407
|
(pURLPartial, fDownloadComplete) =>
|
|
393
408
|
{
|
|
409
|
+
tmpPageIndex++;
|
|
410
|
+
|
|
394
411
|
this.fable.MeadowCloneRestClient.getJSON(pURLPartial,
|
|
395
412
|
(pDownloadError, pResponse, pBody) =>
|
|
396
413
|
{
|
|
397
414
|
if (pDownloadError)
|
|
398
415
|
{
|
|
399
|
-
this.fable.log.error(
|
|
416
|
+
this.fable.log.error(`${this.EntitySchema.TableName}: page ${tmpPageIndex} download error: ${pDownloadError}`);
|
|
400
417
|
return fDownloadComplete();
|
|
401
418
|
}
|
|
402
419
|
if (pBody && pBody.length > 0)
|
|
@@ -417,7 +434,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
417
434
|
{
|
|
418
435
|
if (pReadError)
|
|
419
436
|
{
|
|
420
|
-
|
|
437
|
+
tmpRecordsErrored++;
|
|
421
438
|
return fEntitySyncComplete();
|
|
422
439
|
}
|
|
423
440
|
if (!pRecord)
|
|
@@ -439,15 +456,18 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
439
456
|
{
|
|
440
457
|
if (pCreateError)
|
|
441
458
|
{
|
|
442
|
-
|
|
459
|
+
tmpRecordsErrored++;
|
|
460
|
+
this.log.error(`${this.EntitySchema.TableName}: doCreate error for ID ${tmpRecord[this.DefaultIdentifier]}: ${pCreateError}`);
|
|
443
461
|
return fEntitySyncComplete();
|
|
444
462
|
}
|
|
463
|
+
tmpRecordsCreated++;
|
|
445
464
|
this.operation.incrementProgressTrackerStatus(`FullSync-${this.EntitySchema.TableName}`, 1);
|
|
446
465
|
return fEntitySyncComplete();
|
|
447
466
|
});
|
|
448
467
|
}
|
|
449
468
|
else
|
|
450
469
|
{
|
|
470
|
+
tmpRecordsSkipped++;
|
|
451
471
|
return fEntitySyncComplete();
|
|
452
472
|
}
|
|
453
473
|
});
|
|
@@ -474,6 +494,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
474
494
|
},
|
|
475
495
|
(pDownloadError) =>
|
|
476
496
|
{
|
|
497
|
+
this.fable.log.info(`${this.EntitySchema.TableName}: sync complete — created: ${tmpRecordsCreated}, skipped: ${tmpRecordsSkipped}, errors: ${tmpRecordsErrored}`);
|
|
477
498
|
if (pDownloadError)
|
|
478
499
|
{
|
|
479
500
|
this.fable.log.error(`Error returned URL Partial .. this may not be an error: ${pDownloadError}`);
|
|
@@ -486,7 +507,7 @@ class MeadowSyncEntityInitial extends libFableServiceProviderBase
|
|
|
486
507
|
{
|
|
487
508
|
if (pError)
|
|
488
509
|
{
|
|
489
|
-
this.fable.log.error(
|
|
510
|
+
this.fable.log.error(`${this.EntitySchema.TableName}: sync error: ${pError}`);
|
|
490
511
|
}
|
|
491
512
|
|
|
492
513
|
if (this.SyncDeletedRecords)
|
|
@@ -70,9 +70,16 @@ class MeadowSync extends libFableServiceProviderBase
|
|
|
70
70
|
this.meadowSchema = pSchema;
|
|
71
71
|
this.MeadowSchemaTableList = Object.keys(this.meadowSchema.Tables);
|
|
72
72
|
|
|
73
|
+
this.log.info(`Loading schema for ${this.MeadowSchemaTableList.length} tables (mode: ${this.SyncMode})`);
|
|
74
|
+
|
|
75
|
+
let tmpEntityIndex = 0;
|
|
76
|
+
let tmpErrorCount = 0;
|
|
77
|
+
let tmpSuccessCount = 0;
|
|
78
|
+
|
|
73
79
|
this.fable.Utility.eachLimit(this.MeadowSchemaTableList, 1,
|
|
74
80
|
(pEntitySchemaName, fSyncInitializationComplete) =>
|
|
75
81
|
{
|
|
82
|
+
tmpEntityIndex++;
|
|
76
83
|
const tmpEntitySchema = this.meadowSchema.Tables[pEntitySchemaName];
|
|
77
84
|
// If this is in the entity list or none is specified, create the sync entity object.
|
|
78
85
|
if (this.SyncEntityList.length < 1 || this.SyncEntityList.indexOf(tmpEntitySchema.TableName) > -1)
|
|
@@ -97,7 +104,20 @@ class MeadowSync extends libFableServiceProviderBase
|
|
|
97
104
|
|
|
98
105
|
this.MeadowSyncEntities[tmpEntitySchema.TableName] = tmpSyncEntity;
|
|
99
106
|
|
|
100
|
-
return tmpSyncEntity.initialize(
|
|
107
|
+
return tmpSyncEntity.initialize((pInitError) =>
|
|
108
|
+
{
|
|
109
|
+
if (pInitError)
|
|
110
|
+
{
|
|
111
|
+
tmpErrorCount++;
|
|
112
|
+
this.log.warn(`Failed to initialize ${tmpEntitySchema.TableName}: ${pInitError}`);
|
|
113
|
+
}
|
|
114
|
+
else
|
|
115
|
+
{
|
|
116
|
+
tmpSuccessCount++;
|
|
117
|
+
}
|
|
118
|
+
// Always continue to next entity regardless of individual errors
|
|
119
|
+
return fSyncInitializationComplete();
|
|
120
|
+
});
|
|
101
121
|
}
|
|
102
122
|
else
|
|
103
123
|
{
|
|
@@ -111,7 +131,7 @@ class MeadowSync extends libFableServiceProviderBase
|
|
|
111
131
|
this.log.error(`MeadowSync Error creating sync objects: ${pSyncInitializationError}`, pSyncInitializationError);
|
|
112
132
|
}
|
|
113
133
|
|
|
114
|
-
this.log.info(
|
|
134
|
+
this.log.info(`Entity sync objects created: ${tmpSuccessCount} succeeded, ${tmpErrorCount} failed.`);
|
|
115
135
|
|
|
116
136
|
if (this.SyncEntityList.length < 1)
|
|
117
137
|
{
|
|
@@ -129,7 +149,15 @@ class MeadowSync extends libFableServiceProviderBase
|
|
|
129
149
|
this.log.warn(`MeadowSync.syncEntity called for an entity that does not exist: ${pEntityHash}`);
|
|
130
150
|
return fCallback();
|
|
131
151
|
}
|
|
132
|
-
|
|
152
|
+
|
|
153
|
+
this.MeadowSyncEntities[pEntityHash].sync((pError) =>
|
|
154
|
+
{
|
|
155
|
+
if (pError)
|
|
156
|
+
{
|
|
157
|
+
this.log.error(`Sync failed for ${pEntityHash}: ${pError}`);
|
|
158
|
+
}
|
|
159
|
+
return fCallback(pError);
|
|
160
|
+
});
|
|
133
161
|
}
|
|
134
162
|
|
|
135
163
|
syncAll(fCallback)
|