meadow-integration 1.0.5 → 1.0.6
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/.dockerignore +11 -0
- package/Docker-Build.sh +2 -0
- package/Docker-Compose.sh +2 -0
- package/Docker-Push.sh +2 -0
- package/Docker-Tag.sh +2 -0
- package/Dockerfile +28 -0
- package/Dockerfile_LUXURYCode +23 -0
- package/README.md +139 -25
- package/docker-compose.yml +16 -0
- package/docs/README.md +65 -18
- package/docs/_cover.md +3 -2
- package/docs/_sidebar.md +52 -7
- package/docs/_topbar.md +2 -0
- package/docs/api/clone-rest-client.md +278 -0
- package/docs/api/connection-manager.md +179 -0
- package/docs/api/guid-map.md +234 -0
- package/docs/api/integration-adapter.md +283 -0
- package/docs/api/operation.md +241 -0
- package/docs/api/sync-entity-initial.md +227 -0
- package/docs/api/sync-entity-ongoing.md +244 -0
- package/docs/api/sync.md +213 -0
- package/docs/api/tabular-check.md +213 -0
- package/docs/api/tabular-transform.md +316 -0
- package/docs/architecture.md +423 -0
- package/docs/cli/comprehensionarray.md +111 -0
- package/docs/cli/comprehensionintersect.md +132 -0
- package/docs/cli/csvcheck.md +111 -0
- package/docs/cli/csvtransform.md +170 -0
- package/docs/cli/data-clone.md +277 -0
- package/docs/cli/jsonarraytransform.md +166 -0
- package/docs/cli/load-comprehension.md +129 -0
- package/docs/cli/objectarraytocsv.md +159 -0
- package/docs/cli/overview.md +96 -0
- package/docs/cli/serve.md +102 -0
- package/docs/cli/tsvtransform.md +144 -0
- package/docs/data-clone/configuration.md +357 -0
- package/docs/data-clone/connection-manager.md +206 -0
- package/docs/data-clone/docker.md +290 -0
- package/docs/data-clone/overview.md +173 -0
- package/docs/data-clone/sync-modes.md +186 -0
- package/docs/implementation-reference.md +311 -0
- package/docs/overview.md +156 -0
- package/docs/quickstart.md +233 -0
- package/docs/rest/comprehension-push.md +209 -0
- package/docs/rest/comprehension.md +506 -0
- package/docs/rest/csv.md +255 -0
- package/docs/rest/entity-generation.md +158 -0
- package/docs/rest/json-array.md +243 -0
- package/docs/rest/overview.md +120 -0
- package/docs/rest/status.md +63 -0
- package/docs/rest/tsv.md +241 -0
- package/docs/retold-catalog.json +93 -3
- package/docs/retold-keyword-index.json +23683 -1901
- package/package.json +6 -3
- package/scripts/run.sh +18 -0
- package/source/Meadow-Integration.js +15 -1
- package/source/cli/Default-Meadow-Integration-Configuration.json +37 -2
- package/source/cli/Meadow-Integration-CLI-Program.js +4 -1
- package/source/cli/commands/Meadow-Integration-Command-DataClone.js +284 -0
- package/source/services/clone/Meadow-Service-ConnectionManager.js +251 -0
- package/source/services/clone/Meadow-Service-Operation.js +196 -0
- package/source/services/clone/Meadow-Service-RestClient.js +364 -0
- package/source/services/clone/Meadow-Service-Sync-Entity-Initial.js +367 -0
- package/source/services/clone/Meadow-Service-Sync-Entity-Ongoing.js +457 -0
- package/source/services/clone/Meadow-Service-Sync.js +142 -0
- /package/docs/examples/bookstore/{mapping_books_Author.json → mapping_books_author.json} +0 -0
- /package/docs/examples/bookstore/{mapping_books_Book.json → mapping_books_book.json} +0 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# MeadowIntegrationAdapter
|
|
2
|
+
|
|
3
|
+
Adapter for integrating records from an external system into a Meadow-backed data store. Handles GUID marshaling between external and internal identifiers, record transformation, schema-aware field truncation, and batch upsert operations with retry logic.
|
|
4
|
+
|
|
5
|
+
**Source:** `source/Meadow-Service-Integration-Adapter.js`
|
|
6
|
+
|
|
7
|
+
**Extends:** `fable-serviceproviderbase`
|
|
8
|
+
|
|
9
|
+
**Service Type:** `IntegrationAdapter`
|
|
10
|
+
|
|
11
|
+
## Constructor
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
const adapter = fable.instantiateServiceProvider('IntegrationAdapter', pOptions, pServiceHash);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Options
|
|
18
|
+
|
|
19
|
+
| Option | Type | Default | Description |
|
|
20
|
+
|--------|------|---------|-------------|
|
|
21
|
+
| `Entity` | `string` | `'DefaultEntity'` | The Meadow entity name this adapter manages (e.g. `'Customer'`). |
|
|
22
|
+
| `AdapterSetGUIDMarshalPrefix` | `string\|false` | `false` | Prefix for the adapter set in generated GUIDs. Falls back to `fable.settings.AdapterSetGUIDMarshalPrefix`, then `'INTG-DEF'`. |
|
|
23
|
+
| `EntityGUIDMarshalPrefix` | `string\|false` | `false` | Per-entity prefix in generated GUIDs. Defaults to `'E-{Entity}'`. |
|
|
24
|
+
| `PerformUpserts` | `boolean` | `true` | Whether to push marshaled records to the server. |
|
|
25
|
+
| `PerformDeletes` | `boolean` | `true` | Whether to process deleted records. |
|
|
26
|
+
| `RecordPushRetryThreshold` | `number` | `5` | Maximum number of retry attempts per upsert before giving up. Hard cap of 50. |
|
|
27
|
+
| `RecordThresholdForBulkUpsert` | `number` | `1000` | If total records exceed this count, uses bulk upsert. |
|
|
28
|
+
| `BulkUpsertBatchSize` | `number` | `100` | Number of records per bulk upsert batch. |
|
|
29
|
+
| `ApiURLPrefix` | `string` | `'/1.0/'` | URL prefix for the Meadow API. |
|
|
30
|
+
| `ServerURL` | `string` | *(auto)* | Server URL override. Defaults to `RestClient.serverURL` or `http://localhost:8086{ApiURLPrefix}`. |
|
|
31
|
+
|
|
32
|
+
## Properties
|
|
33
|
+
|
|
34
|
+
### `Entity`
|
|
35
|
+
|
|
36
|
+
`string` -- The entity name this adapter manages.
|
|
37
|
+
|
|
38
|
+
### `EntityGUIDName`
|
|
39
|
+
|
|
40
|
+
`string` -- The GUID column name, derived as `'GUID{Entity}'` (e.g. `'GUIDCustomer'`).
|
|
41
|
+
|
|
42
|
+
### `EntityIDName`
|
|
43
|
+
|
|
44
|
+
`string` -- The ID column name, derived as `'ID{Entity}'` (e.g. `'IDCustomer'`).
|
|
45
|
+
|
|
46
|
+
### `AdapterSetGUIDMarshalPrefix`
|
|
47
|
+
|
|
48
|
+
`string` -- The adapter set prefix used in GUID generation.
|
|
49
|
+
|
|
50
|
+
### `EntityGUIDMarshalPrefix`
|
|
51
|
+
|
|
52
|
+
`string` -- The entity-specific prefix used in GUID generation.
|
|
53
|
+
|
|
54
|
+
### `meadowSchema`
|
|
55
|
+
|
|
56
|
+
`object` -- The entity's JSON Schema, fetched from the server during `integrateRecords()`. Used for field type checking and string truncation.
|
|
57
|
+
|
|
58
|
+
## Methods
|
|
59
|
+
|
|
60
|
+
### `addSourceRecord(pRecord)`
|
|
61
|
+
|
|
62
|
+
Adds a record from the external system to the source record buffer for later marshaling.
|
|
63
|
+
|
|
64
|
+
| Parameter | Type | Description |
|
|
65
|
+
|-----------|------|-------------|
|
|
66
|
+
| `pRecord` | `object` | A record object. Must have a property matching `EntityGUIDName` (e.g. `GUIDCustomer`) with a truthy value. |
|
|
67
|
+
|
|
68
|
+
**Returns:** `false` if the record is invalid, otherwise `undefined`.
|
|
69
|
+
|
|
70
|
+
Records are keyed by their external GUID value in the internal `_SourceRecords` map.
|
|
71
|
+
|
|
72
|
+
### `generateMeadowGUIDFromExternalGUID(pExternalGUID)`
|
|
73
|
+
|
|
74
|
+
Generates a deterministic Meadow GUID from an external system GUID.
|
|
75
|
+
|
|
76
|
+
| Parameter | Type | Description |
|
|
77
|
+
|-----------|------|-------------|
|
|
78
|
+
| `pExternalGUID` | `string` | The external system's GUID value. |
|
|
79
|
+
|
|
80
|
+
**Returns:** `string` -- Format: `'{AdapterSetGUIDMarshalPrefix}-{EntityGUIDMarshalPrefix}-{pExternalGUID}'`
|
|
81
|
+
|
|
82
|
+
**Example:** `'INTG-DEF-E-Customer-EXT-12345'`
|
|
83
|
+
|
|
84
|
+
### `marshalRecord(pSourceRecord)`
|
|
85
|
+
|
|
86
|
+
Transforms an external source record into a Meadow-compatible record.
|
|
87
|
+
|
|
88
|
+
| Parameter | Type | Description |
|
|
89
|
+
|-----------|------|-------------|
|
|
90
|
+
| `pSourceRecord` | `object` | The external record with external GUIDs. |
|
|
91
|
+
|
|
92
|
+
**Returns:** `object` -- The marshaled record with internal Meadow GUIDs.
|
|
93
|
+
|
|
94
|
+
**Transformation logic:**
|
|
95
|
+
1. Generates the internal Meadow GUID for the entity from the external GUID.
|
|
96
|
+
2. Maps the external GUID to the Meadow GUID in the `MeadowGUIDMap`.
|
|
97
|
+
3. For other `GUID*` properties: looks up the corresponding Meadow ID via `MeadowGUIDMap.getMeadowIDFromExternalGUID()` and sets the `ID{Entity}` property.
|
|
98
|
+
4. For `_GUID*` properties (already-Meadow GUIDs): looks up the ID via `MeadowGUIDMap.getIDFromGUID()`.
|
|
99
|
+
5. For schema-defined properties: copies values, truncating strings that exceed the schema-defined `size`.
|
|
100
|
+
6. Strips reserved Meadow fields: `CreateDate`, `UpdateDate`, `Deleted`, `DeleteDate`.
|
|
101
|
+
|
|
102
|
+
### `marshalSourceRecords(fCallback, fMarshalExtraData)`
|
|
103
|
+
|
|
104
|
+
Marshals all records in the source buffer into the marshaled records buffer.
|
|
105
|
+
|
|
106
|
+
| Parameter | Type | Description |
|
|
107
|
+
|-----------|------|-------------|
|
|
108
|
+
| `fCallback` | `function()` | Callback invoked when marshaling is complete. |
|
|
109
|
+
| `fMarshalExtraData` | `function(pSourceRecord, pMarshaledRecord)` | Optional hook called after each record is marshaled. |
|
|
110
|
+
|
|
111
|
+
Deleted source records (where `Deleted === true`) are moved to the `_DeletedRecords` buffer instead. Duplicate GUIDs are merged with `Object.assign`.
|
|
112
|
+
|
|
113
|
+
### `integrateRecords(fCallback, fMarshalExtraData)`
|
|
114
|
+
|
|
115
|
+
Performs the full integration pipeline: fetch schema, marshal source records, and push to server.
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Description |
|
|
118
|
+
|-----------|------|-------------|
|
|
119
|
+
| `fCallback` | `function(pError)` | Callback invoked when integration is complete. |
|
|
120
|
+
| `fMarshalExtraData` | `function(pSourceRecord, pMarshaledRecord)` | Optional hook for extra marshaling logic. |
|
|
121
|
+
|
|
122
|
+
**Pipeline stages (sequential via Anticipate):**
|
|
123
|
+
1. Fetches the entity's JSON Schema from `{ServerURL}{Entity}/Schema`.
|
|
124
|
+
2. Calls `marshalSourceRecords()` to transform all buffered source records.
|
|
125
|
+
3. Calls `pushRecordsToServer()` to upsert all marshaled records.
|
|
126
|
+
|
|
127
|
+
### `upsertSingleRecord(fCallback, pRecordGUID, pRetryCount)`
|
|
128
|
+
|
|
129
|
+
Upserts a single marshaled record to the server with retry logic.
|
|
130
|
+
|
|
131
|
+
| Parameter | Type | Description |
|
|
132
|
+
|-----------|------|-------------|
|
|
133
|
+
| `fCallback` | `function()` | Callback invoked when the upsert completes (or retries are exhausted). |
|
|
134
|
+
| `pRecordGUID` | `string` | The internal Meadow GUID of the record to upsert. |
|
|
135
|
+
| `pRetryCount` | `number` | Current retry count (incremented on failure). |
|
|
136
|
+
|
|
137
|
+
On successful upsert, maps the returned GUID to its server-assigned ID in the `MeadowGUIDMap`.
|
|
138
|
+
|
|
139
|
+
### `upsertBulkRecords(fCallback, pRecordGUIDs, pRetryCount)`
|
|
140
|
+
|
|
141
|
+
Upserts a batch of marshaled records to the server with retry logic.
|
|
142
|
+
|
|
143
|
+
| Parameter | Type | Description |
|
|
144
|
+
|-----------|------|-------------|
|
|
145
|
+
| `fCallback` | `function()` | Callback invoked when the bulk upsert completes. |
|
|
146
|
+
| `pRecordGUIDs` | `Array<string>` | Array of internal Meadow GUIDs to upsert. |
|
|
147
|
+
| `pRetryCount` | `number` | Current retry count. |
|
|
148
|
+
|
|
149
|
+
Sends all records in the batch to the server's bulk upsert endpoint. On success, maps all returned GUIDs to their IDs.
|
|
150
|
+
|
|
151
|
+
## Static Methods
|
|
152
|
+
|
|
153
|
+
### `MeadowIntegrationAdapter.getAdapter(pFable, pEntity, pEntityPrefix)`
|
|
154
|
+
|
|
155
|
+
Factory/lookup helper for getting or creating an adapter for a given entity.
|
|
156
|
+
|
|
157
|
+
| Parameter | Type | Description |
|
|
158
|
+
|-----------|------|-------------|
|
|
159
|
+
| `pFable` | `object` | The Fable instance. |
|
|
160
|
+
| `pEntity` | `string` | Entity name. |
|
|
161
|
+
| `pEntityPrefix` | `string` | Optional `EntityGUIDMarshalPrefix`. |
|
|
162
|
+
|
|
163
|
+
**Returns:** `MeadowIntegrationAdapter` -- An existing adapter instance if one is registered for the entity, otherwise creates and returns a new one.
|
|
164
|
+
|
|
165
|
+
## Usage Examples
|
|
166
|
+
|
|
167
|
+
### Basic Integration Workflow
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
const libFable = require('fable');
|
|
171
|
+
const libAdapter = require('meadow-integration/source/Meadow-Service-Integration-Adapter');
|
|
172
|
+
|
|
173
|
+
const fable = new libFable(
|
|
174
|
+
{
|
|
175
|
+
Product: 'Importer',
|
|
176
|
+
AdapterSetGUIDMarshalPrefix: 'CRM-SYNC'
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
fable.serviceManager.addServiceType('IntegrationAdapter', libAdapter);
|
|
180
|
+
|
|
181
|
+
const customerAdapter = fable.instantiateServiceProvider('IntegrationAdapter',
|
|
182
|
+
{
|
|
183
|
+
Entity: 'Customer',
|
|
184
|
+
EntityGUIDMarshalPrefix: 'CUST',
|
|
185
|
+
ServerURL: 'https://api.example.com/1.0/',
|
|
186
|
+
RecordPushRetryThreshold: 3
|
|
187
|
+
},
|
|
188
|
+
'Customer');
|
|
189
|
+
|
|
190
|
+
// Add source records from the external CRM
|
|
191
|
+
customerAdapter.addSourceRecord(
|
|
192
|
+
{
|
|
193
|
+
GUIDCustomer: 'CRM-42',
|
|
194
|
+
Name: 'Alice Smith',
|
|
195
|
+
Email: 'alice@example.com'
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
customerAdapter.addSourceRecord(
|
|
199
|
+
{
|
|
200
|
+
GUIDCustomer: 'CRM-43',
|
|
201
|
+
Name: 'Bob Jones',
|
|
202
|
+
Email: 'bob@example.com'
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Run the full pipeline
|
|
206
|
+
customerAdapter.integrateRecords(
|
|
207
|
+
(pError) =>
|
|
208
|
+
{
|
|
209
|
+
if (pError)
|
|
210
|
+
{
|
|
211
|
+
console.error('Integration failed:', pError);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
console.log('Customer integration complete!');
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Using the Static getAdapter Helper
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
const libAdapter = require('meadow-integration/source/Meadow-Service-Integration-Adapter');
|
|
222
|
+
|
|
223
|
+
// Returns an existing adapter if one is registered, otherwise creates a new one
|
|
224
|
+
const orderAdapter = libAdapter.getAdapter(fable, 'Order', 'ORD');
|
|
225
|
+
|
|
226
|
+
orderAdapter.addSourceRecord(
|
|
227
|
+
{
|
|
228
|
+
GUIDOrder: 'EXT-ORD-100',
|
|
229
|
+
GUIDCustomer: 'CRM-42',
|
|
230
|
+
Total: 99.99
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
orderAdapter.integrateRecords(
|
|
234
|
+
(pError) =>
|
|
235
|
+
{
|
|
236
|
+
console.log('Order integration complete!');
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### GUID Marshaling
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
const adapter = libAdapter.getAdapter(fable, 'Product', 'PROD');
|
|
244
|
+
|
|
245
|
+
// Generate internal GUID from external one
|
|
246
|
+
const meadowGUID = adapter.generateMeadowGUIDFromExternalGUID('SKU-ABC-123');
|
|
247
|
+
// Result: 'CRM-SYNC-PROD-SKU-ABC-123'
|
|
248
|
+
|
|
249
|
+
// Marshal a record manually
|
|
250
|
+
const marshaled = adapter.marshalRecord(
|
|
251
|
+
{
|
|
252
|
+
GUIDProduct: 'SKU-ABC-123',
|
|
253
|
+
Name: 'Widget',
|
|
254
|
+
Price: 19.99,
|
|
255
|
+
GUIDCategory: 'CAT-5' // Will be looked up in GUIDMap
|
|
256
|
+
});
|
|
257
|
+
// marshaled.GUIDProduct => 'CRM-SYNC-PROD-SKU-ABC-123'
|
|
258
|
+
// marshaled.IDCategory => (looked up from GUIDMap, or logged as warning if not found)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### With Extra Marshal Data Hook
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
customerAdapter.integrateRecords(
|
|
265
|
+
(pError) =>
|
|
266
|
+
{
|
|
267
|
+
console.log('Done!');
|
|
268
|
+
},
|
|
269
|
+
(pSourceRecord, pMarshaledRecord) =>
|
|
270
|
+
{
|
|
271
|
+
// Custom transformation after standard marshaling
|
|
272
|
+
if (pSourceRecord.ExternalStatus === 'VIP')
|
|
273
|
+
{
|
|
274
|
+
pMarshaledRecord.Tier = 'Premium';
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Related Services
|
|
280
|
+
|
|
281
|
+
- [MeadowGUIDMap](./guid-map.md) -- Maintains the GUID-to-ID and external-to-internal GUID mappings used by this adapter.
|
|
282
|
+
- [MeadowCloneRestClient](./clone-rest-client.md) -- Alternative REST client for clone operations (this adapter uses its own `EntityProvider`).
|
|
283
|
+
- [MeadowOperation](./operation.md) -- Can be used alongside this adapter for progress tracking.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# MeadowOperation
|
|
2
|
+
|
|
3
|
+
Utility class providing timestamp management, progress tracking, and memory usage logging for long-running data-clone and sync operations.
|
|
4
|
+
|
|
5
|
+
**Source:** `source/services/clone/Meadow-Service-Operation.js`
|
|
6
|
+
|
|
7
|
+
**Note:** This is a plain class (not a Fable service provider). It is instantiated directly with `new MeadowOperation(pFable)`.
|
|
8
|
+
|
|
9
|
+
## Constructor
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const libMeadowOperation = require('meadow-integration/source/services/clone/Meadow-Service-Operation');
|
|
13
|
+
const operation = new libMeadowOperation(fable);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
| Parameter | Type | Description |
|
|
17
|
+
|-----------|------|-------------|
|
|
18
|
+
| `pFable` | `object` | A Fable instance. The `log` property is used for logging. |
|
|
19
|
+
|
|
20
|
+
## Properties
|
|
21
|
+
|
|
22
|
+
### `timeStamps`
|
|
23
|
+
|
|
24
|
+
`object` -- Map of timestamp hash names to epoch millisecond values. Populated by `createTimeStamp()`.
|
|
25
|
+
|
|
26
|
+
### `progressTrackers`
|
|
27
|
+
|
|
28
|
+
`object` -- Map of progress tracker hash names to progress tracker objects. Populated by `createProgressTracker()`.
|
|
29
|
+
|
|
30
|
+
### `log`
|
|
31
|
+
|
|
32
|
+
Reference to `pFable.log` for logging output.
|
|
33
|
+
|
|
34
|
+
## Timestamp Methods
|
|
35
|
+
|
|
36
|
+
### `createTimeStamp(pTimeStampHash)`
|
|
37
|
+
|
|
38
|
+
Records the current time as a named timestamp.
|
|
39
|
+
|
|
40
|
+
| Parameter | Type | Default | Description |
|
|
41
|
+
|-----------|------|---------|-------------|
|
|
42
|
+
| `pTimeStampHash` | `string` | `'Default'` | Name for this timestamp. |
|
|
43
|
+
|
|
44
|
+
**Returns:** `number` -- The epoch millisecond value of the timestamp.
|
|
45
|
+
|
|
46
|
+
### `getTimeDelta(pTimeStampHash)`
|
|
47
|
+
|
|
48
|
+
Calculates the elapsed time in milliseconds since the named timestamp was created.
|
|
49
|
+
|
|
50
|
+
| Parameter | Type | Default | Description |
|
|
51
|
+
|-----------|------|---------|-------------|
|
|
52
|
+
| `pTimeStampHash` | `string` | `'Default'` | Name of the timestamp to measure from. |
|
|
53
|
+
|
|
54
|
+
**Returns:** `number` -- Elapsed milliseconds, or `-1` if the timestamp does not exist.
|
|
55
|
+
|
|
56
|
+
### `logTimeDelta(pTimeStampHash, pMessage)`
|
|
57
|
+
|
|
58
|
+
Logs the elapsed time since the named timestamp and returns it.
|
|
59
|
+
|
|
60
|
+
| Parameter | Type | Default | Description |
|
|
61
|
+
|-----------|------|---------|-------------|
|
|
62
|
+
| `pTimeStampHash` | `string` | `'Default'` | Name of the timestamp to measure from. |
|
|
63
|
+
| `pMessage` | `string` | `'Elapsed for {hash}: '` | Custom message prefix for the log output. |
|
|
64
|
+
|
|
65
|
+
**Returns:** `number` -- Elapsed milliseconds.
|
|
66
|
+
|
|
67
|
+
**Log output format:** `{pMessage} ({milliseconds}ms)`
|
|
68
|
+
|
|
69
|
+
## Progress Tracker Methods
|
|
70
|
+
|
|
71
|
+
### Progress Tracker Object Shape
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
{
|
|
75
|
+
Hash: 'TrackerName', // The tracker's identifier
|
|
76
|
+
StartTime: 1700000000000, // Epoch ms when tracker was created
|
|
77
|
+
EndTime: 0, // Epoch ms elapsed at completion (0 while running)
|
|
78
|
+
CurrentTime: 0, // Epoch ms elapsed at last update
|
|
79
|
+
PercentComplete: -1, // 0-100 float, -1 before first update
|
|
80
|
+
AverageOperationTime: -1, // ms per operation, -1 before first update
|
|
81
|
+
EstimatedCompletionTime: -1, // ms remaining, -1 before calculable
|
|
82
|
+
TotalCount: 100, // Total expected operations
|
|
83
|
+
CurrentCount: -1 // Completed operations (-1 before first update)
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### `createProgressTracker(pTotalOperations, pProgressTrackerHash)`
|
|
88
|
+
|
|
89
|
+
Creates a new progress tracker with the specified total operation count.
|
|
90
|
+
|
|
91
|
+
| Parameter | Type | Default | Description |
|
|
92
|
+
|-----------|------|---------|-------------|
|
|
93
|
+
| `pTotalOperations` | `number` | `100` | Total number of operations expected. |
|
|
94
|
+
| `pProgressTrackerHash` | `string` | `'DefaultProgressTracker'` | Name for this tracker. |
|
|
95
|
+
|
|
96
|
+
**Returns:** `object` -- The progress tracker object.
|
|
97
|
+
|
|
98
|
+
Also creates a corresponding timestamp with the same hash name.
|
|
99
|
+
|
|
100
|
+
### `updateProgressTrackerStatus(pProgressTrackerHash, pCurrentOperations)`
|
|
101
|
+
|
|
102
|
+
Sets the current operation count to an absolute value and recalculates statistics.
|
|
103
|
+
|
|
104
|
+
| Parameter | Type | Default | Description |
|
|
105
|
+
|-----------|------|---------|-------------|
|
|
106
|
+
| `pProgressTrackerHash` | `string` | `'DefaultProgressTracker'` | Tracker name. |
|
|
107
|
+
| `pCurrentOperations` | `number` | -- | The absolute current operation count. |
|
|
108
|
+
|
|
109
|
+
**Returns:** `object|false` -- The updated progress tracker object, or `false` if the operation count is `NaN`.
|
|
110
|
+
|
|
111
|
+
Creates the tracker automatically if it does not exist.
|
|
112
|
+
|
|
113
|
+
### `incrementProgressTrackerStatus(pProgressTrackerHash, pIncrementSize)`
|
|
114
|
+
|
|
115
|
+
Increments the current operation count by a given amount and recalculates statistics.
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Default | Description |
|
|
118
|
+
|-----------|------|---------|-------------|
|
|
119
|
+
| `pProgressTrackerHash` | `string` | `'DefaultProgressTracker'` | Tracker name. |
|
|
120
|
+
| `pIncrementSize` | `number` | -- | How many operations to add to the current count. |
|
|
121
|
+
|
|
122
|
+
**Returns:** `object|false` -- The updated progress tracker object, or `false` if the increment is `NaN`.
|
|
123
|
+
|
|
124
|
+
Creates the tracker automatically if it does not exist.
|
|
125
|
+
|
|
126
|
+
### `setProgressTrackerEndTime(pProgressTrackerHash, pCurrentOperations)`
|
|
127
|
+
|
|
128
|
+
Marks the progress tracker as complete by setting the end time. Optionally updates the final operation count.
|
|
129
|
+
|
|
130
|
+
| Parameter | Type | Default | Description |
|
|
131
|
+
|-----------|------|---------|-------------|
|
|
132
|
+
| `pProgressTrackerHash` | `string` | `'DefaultProgressTracker'` | Tracker name. |
|
|
133
|
+
| `pCurrentOperations` | `number` | *(none)* | Optional final operation count. |
|
|
134
|
+
|
|
135
|
+
**Returns:** `object|false` -- The finalized progress tracker object, or `false` if the tracker does not exist.
|
|
136
|
+
|
|
137
|
+
### `printProgressTrackerStatus(pProgressTrackerHash)`
|
|
138
|
+
|
|
139
|
+
Logs the current status of a progress tracker in a human-readable format.
|
|
140
|
+
|
|
141
|
+
| Parameter | Type | Default | Description |
|
|
142
|
+
|-----------|------|---------|-------------|
|
|
143
|
+
| `pProgressTrackerHash` | `string` | `'DefaultProgressTracker'` | Tracker name. |
|
|
144
|
+
|
|
145
|
+
**Log output varies by state:**
|
|
146
|
+
- **No operations completed:** Reports elapsed time since start.
|
|
147
|
+
- **In progress:** Reports percent complete, operation counts, elapsed time, median time per operation, and estimated completion time in both milliseconds and minutes.
|
|
148
|
+
- **Completed (EndTime set):** Reports final operation counts and total elapsed time.
|
|
149
|
+
|
|
150
|
+
## Memory Methods
|
|
151
|
+
|
|
152
|
+
### `logMemoryResourcesUsed()`
|
|
153
|
+
|
|
154
|
+
Logs the current heap memory usage of the Node.js process.
|
|
155
|
+
|
|
156
|
+
**Log output format:** `Memory usage at {X.XX} MB`
|
|
157
|
+
|
|
158
|
+
## Usage Examples
|
|
159
|
+
|
|
160
|
+
### Timing an Operation
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
const libMeadowOperation = require('meadow-integration/source/services/clone/Meadow-Service-Operation');
|
|
164
|
+
const operation = new libMeadowOperation(fable);
|
|
165
|
+
|
|
166
|
+
operation.createTimeStamp('DataLoad');
|
|
167
|
+
|
|
168
|
+
// ... perform work ...
|
|
169
|
+
|
|
170
|
+
const elapsed = operation.getTimeDelta('DataLoad');
|
|
171
|
+
console.log(`Data load took ${elapsed}ms`);
|
|
172
|
+
|
|
173
|
+
// Or log it directly with a custom message
|
|
174
|
+
operation.logTimeDelta('DataLoad', 'Data loading completed');
|
|
175
|
+
// Logs: "Data loading completed (1234ms)"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Tracking Progress of a Batch Operation
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
const operation = new libMeadowOperation(fable);
|
|
182
|
+
|
|
183
|
+
const totalRecords = 5000;
|
|
184
|
+
operation.createProgressTracker(totalRecords, 'ImportRecords');
|
|
185
|
+
|
|
186
|
+
// Print initial status
|
|
187
|
+
operation.printProgressTrackerStatus('ImportRecords');
|
|
188
|
+
// Logs: ">> Progress Tracker ImportRecords has no completed operations. {X}ms have elapsed since it was started."
|
|
189
|
+
|
|
190
|
+
// Process records in batches
|
|
191
|
+
let processedCount = 0;
|
|
192
|
+
for (const batch of recordBatches)
|
|
193
|
+
{
|
|
194
|
+
// Process the batch...
|
|
195
|
+
processedCount += batch.length;
|
|
196
|
+
|
|
197
|
+
operation.updateProgressTrackerStatus('ImportRecords', processedCount);
|
|
198
|
+
operation.printProgressTrackerStatus('ImportRecords');
|
|
199
|
+
// Logs: ">> Progress Tracker ImportRecords is 25.000% completed - 1250 / 5000 operations over 3200ms (median 2.560 per). Estimated completion in 9600ms or 0.16 minutes"
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Mark complete
|
|
203
|
+
operation.setProgressTrackerEndTime('ImportRecords', totalRecords);
|
|
204
|
+
operation.printProgressTrackerStatus('ImportRecords');
|
|
205
|
+
// Logs: ">> Progress Tracker ImportRecords is done and completed 5000 / 5000 operations in 12800ms."
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Incrementing Progress One at a Time
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
const operation = new libMeadowOperation(fable);
|
|
212
|
+
operation.createProgressTracker(100, 'SyncCustomers');
|
|
213
|
+
|
|
214
|
+
for (const record of records)
|
|
215
|
+
{
|
|
216
|
+
// Process record...
|
|
217
|
+
operation.incrementProgressTrackerStatus('SyncCustomers', 1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
operation.setProgressTrackerEndTime('SyncCustomers');
|
|
221
|
+
operation.printProgressTrackerStatus('SyncCustomers');
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Logging Memory Usage
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
const operation = new libMeadowOperation(fable);
|
|
228
|
+
|
|
229
|
+
operation.logMemoryResourcesUsed();
|
|
230
|
+
// Logs: "Memory usage at 45.23 MB"
|
|
231
|
+
|
|
232
|
+
// ... perform memory-intensive operation ...
|
|
233
|
+
|
|
234
|
+
operation.logMemoryResourcesUsed();
|
|
235
|
+
// Logs: "Memory usage at 128.71 MB"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Related Services
|
|
239
|
+
|
|
240
|
+
- [MeadowSyncEntityInitial](./sync-entity-initial.md) -- Uses MeadowOperation for timing and progress tracking during initial sync.
|
|
241
|
+
- [MeadowSyncEntityOngoing](./sync-entity-ongoing.md) -- Uses MeadowOperation for timing and progress tracking during ongoing sync.
|