meadow-integration 1.0.5 → 1.0.7

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.
Files changed (67) hide show
  1. package/.dockerignore +11 -0
  2. package/Docker-Build.sh +2 -0
  3. package/Docker-Compose.sh +2 -0
  4. package/Docker-Push.sh +2 -0
  5. package/Docker-Tag.sh +2 -0
  6. package/Dockerfile +28 -0
  7. package/Dockerfile_LUXURYCode +23 -0
  8. package/README.md +139 -25
  9. package/docker-compose.yml +16 -0
  10. package/docs/README.md +65 -18
  11. package/docs/_cover.md +3 -2
  12. package/docs/_sidebar.md +52 -7
  13. package/docs/_topbar.md +2 -0
  14. package/docs/api/clone-rest-client.md +278 -0
  15. package/docs/api/connection-manager.md +179 -0
  16. package/docs/api/guid-map.md +234 -0
  17. package/docs/api/integration-adapter.md +283 -0
  18. package/docs/api/operation.md +241 -0
  19. package/docs/api/sync-entity-initial.md +227 -0
  20. package/docs/api/sync-entity-ongoing.md +244 -0
  21. package/docs/api/sync.md +213 -0
  22. package/docs/api/tabular-check.md +213 -0
  23. package/docs/api/tabular-transform.md +316 -0
  24. package/docs/architecture.md +423 -0
  25. package/docs/cli/comprehensionarray.md +111 -0
  26. package/docs/cli/comprehensionintersect.md +132 -0
  27. package/docs/cli/csvcheck.md +111 -0
  28. package/docs/cli/csvtransform.md +170 -0
  29. package/docs/cli/data-clone.md +277 -0
  30. package/docs/cli/jsonarraytransform.md +166 -0
  31. package/docs/cli/load-comprehension.md +129 -0
  32. package/docs/cli/objectarraytocsv.md +159 -0
  33. package/docs/cli/overview.md +96 -0
  34. package/docs/cli/serve.md +102 -0
  35. package/docs/cli/tsvtransform.md +144 -0
  36. package/docs/data-clone/configuration.md +357 -0
  37. package/docs/data-clone/connection-manager.md +206 -0
  38. package/docs/data-clone/docker.md +290 -0
  39. package/docs/data-clone/overview.md +173 -0
  40. package/docs/data-clone/sync-modes.md +186 -0
  41. package/docs/implementation-reference.md +311 -0
  42. package/docs/overview.md +156 -0
  43. package/docs/quickstart.md +233 -0
  44. package/docs/rest/comprehension-push.md +209 -0
  45. package/docs/rest/comprehension.md +506 -0
  46. package/docs/rest/csv.md +255 -0
  47. package/docs/rest/entity-generation.md +158 -0
  48. package/docs/rest/json-array.md +243 -0
  49. package/docs/rest/overview.md +120 -0
  50. package/docs/rest/status.md +63 -0
  51. package/docs/rest/tsv.md +241 -0
  52. package/docs/retold-catalog.json +93 -3
  53. package/docs/retold-keyword-index.json +23683 -1901
  54. package/package.json +6 -3
  55. package/scripts/run.sh +18 -0
  56. package/source/Meadow-Integration.js +15 -1
  57. package/source/cli/Default-Meadow-Integration-Configuration.json +37 -2
  58. package/source/cli/Meadow-Integration-CLI-Program.js +4 -1
  59. package/source/cli/commands/Meadow-Integration-Command-DataClone.js +284 -0
  60. package/source/services/clone/Meadow-Service-ConnectionManager.js +251 -0
  61. package/source/services/clone/Meadow-Service-Operation.js +196 -0
  62. package/source/services/clone/Meadow-Service-RestClient.js +364 -0
  63. package/source/services/clone/Meadow-Service-Sync-Entity-Initial.js +502 -0
  64. package/source/services/clone/Meadow-Service-Sync-Entity-Ongoing.js +592 -0
  65. package/source/services/clone/Meadow-Service-Sync.js +154 -0
  66. /package/docs/examples/bookstore/{mapping_books_Author.json → mapping_books_author.json} +0 -0
  67. /package/docs/examples/bookstore/{mapping_books_Book.json → mapping_books_book.json} +0 -0
@@ -0,0 +1,278 @@
1
+ # MeadowCloneRestClient
2
+
3
+ REST client for communicating with a remote Meadow API server. Provides authentication, session management, CRUD operations, and paginated entity set downloads for the data-clone pipeline.
4
+
5
+ **Source:** `source/services/clone/Meadow-Service-RestClient.js`
6
+
7
+ **Extends:** `fable-serviceproviderbase`
8
+
9
+ **Service Type:** `MeadowCloneRestClient`
10
+
11
+ ## Constructor
12
+
13
+ ```js
14
+ const restClient = fable.serviceManager.instantiateServiceProvider('MeadowCloneRestClient', pOptions);
15
+ ```
16
+
17
+ ### Options
18
+
19
+ | Option | Type | Default | Description |
20
+ |--------|------|---------|-------------|
21
+ | `DownloadBatchSize` | `number` | `100` | Number of records per page when downloading entity sets. |
22
+ | `ServerURL` | `string` | `'https://localhost:8080/1.0/'` | Base URL for all API requests. |
23
+ | `UserID` | `string\|false` | `false` | Username for authentication. If `false`, `authenticate()` is a no-op. |
24
+ | `Password` | `string\|false` | `false` | Password for authentication. If `false`, `authenticate()` is a no-op. |
25
+ | `SessionToken` | `string` | *(none)* | Optional pre-existing session token to use instead of authenticating. |
26
+
27
+ ## Properties
28
+
29
+ ### `session`
30
+
31
+ *Getter* -- Returns the current session data object, or `false` if not authenticated.
32
+
33
+ ### `loggedIn`
34
+
35
+ *Getter* -- Returns `boolean`. `true` after a successful call to `authenticate()`, `false` after `deauthenticate()` or before login.
36
+
37
+ ### `serverURL`
38
+
39
+ The base URL string used for all API requests.
40
+
41
+ ### `cache`
42
+
43
+ Object map of per-entity `ObjectCache` instances. Populated automatically by `getEntity()` and `getEntitySet()`.
44
+
45
+ ## Methods
46
+
47
+ ### `authenticate(fCallback)`
48
+
49
+ Authenticates with the Meadow API server using the configured `UserID` and `Password`.
50
+
51
+ | Parameter | Type | Description |
52
+ |-----------|------|-------------|
53
+ | `fCallback` | `function(pError, pSessionData)` | Callback with the session data on success. |
54
+
55
+ Posts to `{ServerURL}/Authenticate` with `{ UserName, Password }`. On success, stores session data and sets a `UserSession` cookie for subsequent requests.
56
+
57
+ If `UserID` or `Password` is falsy, authentication is skipped and the callback is invoked immediately.
58
+
59
+ ### `deauthenticate(fCallback)`
60
+
61
+ Logs out from the Meadow API server and clears session data.
62
+
63
+ | Parameter | Type | Description |
64
+ |-----------|------|-------------|
65
+ | `fCallback` | `function(pError, pSessionData)` | Callback invoked after logout. `pSessionData` will be `false`. |
66
+
67
+ ### `getJSON(pURL, fCallback)`
68
+
69
+ Performs a GET request for JSON data at the given URL path (appended to `ServerURL`).
70
+
71
+ | Parameter | Type | Description |
72
+ |-----------|------|-------------|
73
+ | `pURL` | `string` | URL path appended to `ServerURL`. |
74
+ | `fCallback` | `function(pError, pResponse, pBody)` | Standard REST callback. |
75
+
76
+ ### `createEntity(pEntity, pRecord, fCallback)`
77
+
78
+ Creates a new entity record on the server via POST.
79
+
80
+ | Parameter | Type | Description |
81
+ |-----------|------|-------------|
82
+ | `pEntity` | `string` | Entity name (e.g. `'Animal'`). |
83
+ | `pRecord` | `object` | Record data to create. |
84
+ | `fCallback` | `function(pError, pBody)` | Callback with the created record body. |
85
+
86
+ ### `updateEntity(pEntity, pRecord, fCallback)`
87
+
88
+ Updates an existing entity record on the server via PUT.
89
+
90
+ | Parameter | Type | Description |
91
+ |-----------|------|-------------|
92
+ | `pEntity` | `string` | Entity name. |
93
+ | `pRecord` | `object` | Record data to update (must include the identifier). |
94
+ | `fCallback` | `function(pError, pBody)` | Callback with the updated record body. |
95
+
96
+ ### `upsertEntity(pEntity, pRecord, fCallback)`
97
+
98
+ Creates or updates an entity record on the server via PUT to the `/Upsert` endpoint.
99
+
100
+ | Parameter | Type | Description |
101
+ |-----------|------|-------------|
102
+ | `pEntity` | `string` | Entity name. |
103
+ | `pRecord` | `object` | Record data to upsert. |
104
+ | `fCallback` | `function(pError, pBody)` | Callback with the upserted record body. |
105
+
106
+ ### `deleteEntity(pEntity, pIDRecord, fCallback)`
107
+
108
+ Deletes an entity record by ID from the server via DELETE.
109
+
110
+ | Parameter | Type | Description |
111
+ |-----------|------|-------------|
112
+ | `pEntity` | `string` | Entity name. |
113
+ | `pIDRecord` | `number\|string` | The ID of the record to delete. |
114
+ | `fCallback` | `function(pError, pBody)` | Callback with the response body. |
115
+
116
+ ### `getEntity(pEntity, pIDRecord, fCallback)`
117
+
118
+ Retrieves a single entity record by ID. Uses an in-memory cache (max age 30s, max 10000 entries) to avoid redundant requests.
119
+
120
+ | Parameter | Type | Description |
121
+ |-----------|------|-------------|
122
+ | `pEntity` | `string` | Entity name. |
123
+ | `pIDRecord` | `number\|string` | The ID of the record to retrieve. |
124
+ | `fCallback` | `function(pError, pBody)` | Callback with the record body (from cache or server). |
125
+
126
+ ### `getEntitySet(pEntity, pMeadowFilterExpression, fCallback)`
127
+
128
+ Downloads a full set of entity records matching a Meadow filter expression. Automatically paginates using `DownloadBatchSize`.
129
+
130
+ | Parameter | Type | Description |
131
+ |-----------|------|-------------|
132
+ | `pEntity` | `string` | Entity name. |
133
+ | `pMeadowFilterExpression` | `string` | Meadow filter expression (e.g. `'FBV~Deleted~EQ~0'`). |
134
+ | `fCallback` | `function(pError, pEntitySet)` | Callback with the full array of records. |
135
+
136
+ **Algorithm:**
137
+ 1. Requests the count from `{Entity}s/Count/FilteredTo/{Filter}`.
138
+ 2. Generates paginated URL fragments based on `DownloadBatchSize`.
139
+ 3. Downloads each page sequentially and concatenates results.
140
+
141
+ ### `setSessionToken(pSessionToken)`
142
+
143
+ Manually sets the session token for subsequent requests. The token is appended as a `SessionToken` query parameter when no session data cookie is present.
144
+
145
+ | Parameter | Type | Description |
146
+ |-----------|------|-------------|
147
+ | `pSessionToken` | `string` | The session token string. |
148
+
149
+ ### `setSessionData(pSessionData)`
150
+
151
+ Sets session data and configures the `UserSession` cookie on the underlying REST client.
152
+
153
+ | Parameter | Type | Description |
154
+ |-----------|------|-------------|
155
+ | `pSessionData` | `object` | Session data object. If it has a `SessionID` property, that value is used as the cookie. |
156
+
157
+ ### `resetSessionData()`
158
+
159
+ Clears all session data and cookies. Called internally by `deauthenticate()`.
160
+
161
+ ## Usage Examples
162
+
163
+ ### Authentication and Reading Entities
164
+
165
+ ```js
166
+ const libFable = require('fable');
167
+ const libRestClient = require('meadow-integration/source/services/clone/Meadow-Service-RestClient');
168
+
169
+ const fable = new libFable({ Product: 'CloneApp' });
170
+
171
+ fable.serviceManager.addServiceType('MeadowCloneRestClient', libRestClient);
172
+ const restClient = fable.serviceManager.instantiateServiceProvider('MeadowCloneRestClient',
173
+ {
174
+ ServerURL: 'https://api.example.com/1.0/',
175
+ UserID: 'sync_user',
176
+ Password: 'sync_password',
177
+ DownloadBatchSize: 250
178
+ });
179
+
180
+ restClient.authenticate(
181
+ (pError, pSessionData) =>
182
+ {
183
+ if (pError)
184
+ {
185
+ console.error('Auth failed:', pError.message);
186
+ return;
187
+ }
188
+ console.log('Logged in:', restClient.loggedIn);
189
+ console.log('Session ID:', pSessionData.SessionID);
190
+ });
191
+ ```
192
+
193
+ ### Reading a Single Entity
194
+
195
+ ```js
196
+ restClient.getEntity('Animal', 42,
197
+ (pError, pRecord) =>
198
+ {
199
+ if (pError)
200
+ {
201
+ console.error('Read failed:', pError.message);
202
+ return;
203
+ }
204
+ console.log('Animal name:', pRecord.Name);
205
+ });
206
+ ```
207
+
208
+ ### Downloading a Filtered Entity Set
209
+
210
+ ```js
211
+ restClient.getEntitySet('Animal', 'FBV~Deleted~EQ~0',
212
+ (pError, pRecords) =>
213
+ {
214
+ if (pError)
215
+ {
216
+ console.error('Download failed:', pError.message);
217
+ return;
218
+ }
219
+ console.log(`Downloaded ${pRecords.length} animals.`);
220
+
221
+ for (const tmpRecord of pRecords)
222
+ {
223
+ console.log(` ${tmpRecord.IDAnimal}: ${tmpRecord.Name}`);
224
+ }
225
+ });
226
+ ```
227
+
228
+ ### Using a Pre-existing Session Token
229
+
230
+ ```js
231
+ const restClient = fable.serviceManager.instantiateServiceProvider('MeadowCloneRestClient',
232
+ {
233
+ ServerURL: 'https://api.example.com/1.0/',
234
+ SessionToken: 'abc-123-def-456'
235
+ });
236
+
237
+ // No need to call authenticate() -- the token is appended automatically
238
+ restClient.getJSON('Animal/1',
239
+ (pError, pResponse, pBody) =>
240
+ {
241
+ console.log('Record:', pBody);
242
+ });
243
+ ```
244
+
245
+ ### Upserting and Deleting Records
246
+
247
+ ```js
248
+ // Upsert
249
+ restClient.upsertEntity('Animal', { GUIDAnimal: 'ANIMAL-001', Name: 'Felix', Type: 'Cat' },
250
+ (pError, pBody) =>
251
+ {
252
+ console.log('Upserted:', pBody);
253
+ });
254
+
255
+ // Delete
256
+ restClient.deleteEntity('Animal', 42,
257
+ (pError, pBody) =>
258
+ {
259
+ console.log('Deleted:', pBody);
260
+ });
261
+ ```
262
+
263
+ ### Deauthentication
264
+
265
+ ```js
266
+ restClient.deauthenticate(
267
+ (pError) =>
268
+ {
269
+ console.log('Logged out. Session:', restClient.session); // false
270
+ });
271
+ ```
272
+
273
+ ## Related Services
274
+
275
+ - [MeadowConnectionManager](./connection-manager.md) -- Manages the local database connection pool.
276
+ - [MeadowSync](./sync.md) -- Orchestrator that uses this REST client to download records from the server.
277
+ - [MeadowSyncEntityInitial](./sync-entity-initial.md) -- Uses this client to fetch max IDs, counts, and paginated record sets.
278
+ - [MeadowSyncEntityOngoing](./sync-entity-ongoing.md) -- Uses this client for update-based differential sync.
@@ -0,0 +1,179 @@
1
+ # MeadowConnectionManager
2
+
3
+ Database connection manager supporting MySQL and MSSQL providers for the meadow data-clone services.
4
+
5
+ **Source:** `source/services/clone/Meadow-Service-ConnectionManager.js`
6
+
7
+ **Extends:** `fable-serviceproviderbase`
8
+
9
+ **Service Type:** `MeadowConnectionManager`
10
+
11
+ ## Constructor
12
+
13
+ ```js
14
+ const connectionManager = fable.serviceManager.instantiateServiceProvider('MeadowConnectionManager', pOptions);
15
+ ```
16
+
17
+ ### Options
18
+
19
+ | Option | Type | Default | Description |
20
+ |--------|------|---------|-------------|
21
+ | `Provider` | `string` | `'MySQL'` | Database provider to use. Supported values: `'MySQL'`, `'MSSQL'`. |
22
+ | `MySQL` | `object` | *(see below)* | MySQL-specific connection configuration. |
23
+ | `MySQL.server` | `string` | `'127.0.0.1'` | MySQL server hostname. |
24
+ | `MySQL.port` | `number` | `3306` | MySQL server port. |
25
+ | `MySQL.user` | `string` | `'root'` | MySQL authentication user. |
26
+ | `MySQL.password` | `string` | `''` | MySQL authentication password. |
27
+ | `MySQL.database` | `string` | `'meadow'` | MySQL database name. |
28
+ | `MySQL.connectionLimit` | `number` | `20` | Maximum number of connections in the MySQL pool. |
29
+ | `MSSQL` | `object` | *(see below)* | MSSQL-specific connection configuration. |
30
+ | `MSSQL.server` | `string` | `'127.0.0.1'` | MSSQL server hostname. |
31
+ | `MSSQL.port` | `number` | `1433` | MSSQL server port. |
32
+ | `MSSQL.user` | `string` | `'sa'` | MSSQL authentication user. |
33
+ | `MSSQL.password` | `string` | `''` | MSSQL authentication password. |
34
+ | `MSSQL.database` | `string` | `'meadow'` | MSSQL database name. |
35
+ | `MSSQL.ConnectionPoolLimit` | `number` | `20` | Maximum number of connections in the MSSQL pool. |
36
+
37
+ ## Properties
38
+
39
+ ### `connected`
40
+
41
+ *Getter* -- Returns `boolean`.
42
+
43
+ Indicates whether the connection manager has successfully established a connection to the database.
44
+
45
+ ### `ConnectionPool`
46
+
47
+ The underlying database connection pool object. Set to `false` before `connect()` is called. After a successful connection, holds the provider-specific pool instance.
48
+
49
+ ### `Provider`
50
+
51
+ The active database provider string (`'MySQL'` or `'MSSQL'`).
52
+
53
+ ## Methods
54
+
55
+ ### `connect(fCallback)`
56
+
57
+ Establishes a connection to the database using the configured provider.
58
+
59
+ | Parameter | Type | Description |
60
+ |-----------|------|-------------|
61
+ | `fCallback` | `function(pError, pConnectionPool)` | Callback invoked when the connection attempt completes. On success, `pConnectionPool` is the active pool. |
62
+
63
+ **Behavior:**
64
+ - For `MySQL`: Requires the `meadow-connection-mysql` package. Registers and instantiates a `MeadowMySQLProvider` service, then calls `connectAsync`. Also applies `connectionLimit` to `fable.settings`.
65
+ - For `MSSQL`: Requires the `meadow-connection-mssql` package. Registers and instantiates a `MeadowMSSQLProvider` service, then calls `connectAsync`.
66
+ - For unsupported providers: Calls back with an `Error`.
67
+
68
+ ### `createIndex(pEntitySchema, pColumn, pIsUnique, fCallback)`
69
+
70
+ Creates a database index on the specified column for the given entity, if the index does not already exist.
71
+
72
+ | Parameter | Type | Description |
73
+ |-----------|------|-------------|
74
+ | `pEntitySchema` | `object` | Entity schema object. Must have a `TableName` property. |
75
+ | `pColumn` | `object` | Column descriptor object. Must have a `Column` property (string). |
76
+ | `pIsUnique` | `boolean` | If `true`, creates a unique index. |
77
+ | `fCallback` | `function(pError)` | Callback invoked when the index creation attempt completes. |
78
+
79
+ **Index naming convention (MySQL):** `AK_{TableName}_{ColumnName}`
80
+
81
+ **Provider-specific behavior:**
82
+ - **MySQL:** Checks `INFORMATION_SCHEMA.STATISTICS` for an existing index before creating. Silently ignores `ER_DUP_KEYNAME` errors.
83
+ - **MSSQL:** Uses `IF NOT EXISTS(SELECT * FROM sys.indexes ...)` to conditionally create. Errors are logged but not passed to the callback (the callback always succeeds).
84
+
85
+ ## Usage Examples
86
+
87
+ ### MySQL Connection
88
+
89
+ ```js
90
+ const libFable = require('fable');
91
+ const libConnectionManager = require('meadow-integration/source/services/clone/Meadow-Service-ConnectionManager');
92
+
93
+ const fable = new libFable({ Product: 'MyApp' });
94
+
95
+ fable.serviceManager.addServiceType('MeadowConnectionManager', libConnectionManager);
96
+ const connectionManager = fable.serviceManager.instantiateServiceProvider('MeadowConnectionManager',
97
+ {
98
+ Provider: 'MySQL',
99
+ MySQL:
100
+ {
101
+ server: 'db.example.com',
102
+ port: 3306,
103
+ user: 'app_user',
104
+ password: 'secret',
105
+ database: 'production',
106
+ connectionLimit: 10
107
+ }
108
+ });
109
+
110
+ connectionManager.connect(
111
+ (pError, pConnectionPool) =>
112
+ {
113
+ if (pError)
114
+ {
115
+ console.error('Connection failed:', pError.message);
116
+ return;
117
+ }
118
+ console.log('Connected:', connectionManager.connected); // true
119
+ // pConnectionPool is now available for queries
120
+ });
121
+ ```
122
+
123
+ ### MSSQL Connection
124
+
125
+ ```js
126
+ const fable = new libFable({ Product: 'MyApp' });
127
+
128
+ fable.serviceManager.addServiceType('MeadowConnectionManager', libConnectionManager);
129
+ const connectionManager = fable.serviceManager.instantiateServiceProvider('MeadowConnectionManager',
130
+ {
131
+ Provider: 'MSSQL',
132
+ MSSQL:
133
+ {
134
+ server: 'sql.example.com',
135
+ port: 1433,
136
+ user: 'sa',
137
+ password: 'secret',
138
+ database: 'production',
139
+ ConnectionPoolLimit: 20
140
+ }
141
+ });
142
+
143
+ connectionManager.connect(
144
+ (pError, pConnectionPool) =>
145
+ {
146
+ if (pError)
147
+ {
148
+ console.error('MSSQL connection failed:', pError.message);
149
+ return;
150
+ }
151
+ console.log('Connected to MSSQL:', connectionManager.connected);
152
+ });
153
+ ```
154
+
155
+ ### Creating an Index
156
+
157
+ ```js
158
+ const entitySchema = { TableName: 'Animal' };
159
+ const guidColumn = { Column: 'GUIDAnimal', DataType: 'GUID' };
160
+
161
+ connectionManager.createIndex(entitySchema, guidColumn, true,
162
+ (pError) =>
163
+ {
164
+ if (pError)
165
+ {
166
+ console.error('Index creation failed:', pError.message);
167
+ return;
168
+ }
169
+ // Index AK_Animal_GUIDAnimal now exists
170
+ console.log('Index created successfully.');
171
+ });
172
+ ```
173
+
174
+ ## Related Services
175
+
176
+ - [MeadowCloneRestClient](./clone-rest-client.md) -- REST client for communicating with the remote Meadow API server.
177
+ - [MeadowSync](./sync.md) -- Orchestrates full entity synchronization using a ConnectionManager pool.
178
+ - [MeadowSyncEntityInitial](./sync-entity-initial.md) -- Initial sync uses the connection pool for table and index creation.
179
+ - [MeadowSyncEntityOngoing](./sync-entity-ongoing.md) -- Ongoing sync uses the connection pool for table and index creation.
@@ -0,0 +1,234 @@
1
+ # MeadowGUIDMap
2
+
3
+ In-memory bidirectional mapping service between Meadow GUIDs, Meadow IDs, and external system GUIDs. Used by the integration adapter to resolve entity references across system boundaries.
4
+
5
+ **Source:** `source/Meadow-Service-Integration-GUIDMap.js`
6
+
7
+ **Extends:** `fable-serviceproviderbase`
8
+
9
+ **Service Type:** `MeadowGUIDMap`
10
+
11
+ ## Constructor
12
+
13
+ ```js
14
+ const guidMap = fable.addAndInstantiateServiceType('MeadowGUIDMap', libMeadowGUIDMap);
15
+ ```
16
+
17
+ The `MeadowGUIDMap` is typically instantiated automatically by `MeadowIntegrationAdapter` if one does not already exist on the Fable instance.
18
+
19
+ ### Options
20
+
21
+ The default options object is empty. No configuration is currently required.
22
+
23
+ ## Internal Data Structures
24
+
25
+ The GUIDMap maintains three parallel in-memory maps, each keyed by entity name:
26
+
27
+ | Map | Description |
28
+ |-----|-------------|
29
+ | `_GUIDMap` | `{ Entity: { MeadowGUID: MeadowID } }` -- Maps Meadow GUIDs to numeric IDs. |
30
+ | `_IDMap` | `{ Entity: { MeadowID: MeadowGUID } }` -- Reverse map of numeric IDs to Meadow GUIDs. |
31
+ | `_ExternalGUIDMap` | `{ Entity: { ExternalGUID: MeadowGUID } }` -- Maps external system GUIDs to Meadow GUIDs. |
32
+
33
+ ## Methods
34
+
35
+ ### `addEntity(pEntity)`
36
+
37
+ Initializes the mapping tables for a given entity if they do not already exist.
38
+
39
+ | Parameter | Type | Description |
40
+ |-----------|------|-------------|
41
+ | `pEntity` | `string` | Entity name (e.g. `'Customer'`). |
42
+
43
+ **Returns:** `true`
44
+
45
+ Called automatically by other methods when an entity is encountered for the first time.
46
+
47
+ ### `mapGUIDToID(pEntity, pGUID, pID)`
48
+
49
+ Stores a bidirectional mapping between a Meadow GUID and its numeric ID.
50
+
51
+ | Parameter | Type | Description |
52
+ |-----------|------|-------------|
53
+ | `pEntity` | `string` | Entity name. |
54
+ | `pGUID` | `string` | The Meadow GUID value. |
55
+ | `pID` | `number\|string` | The numeric ID value. |
56
+
57
+ **Returns:** `true`
58
+
59
+ Updates both `_GUIDMap[Entity][GUID] = ID` and `_IDMap[Entity][ID] = GUID`.
60
+
61
+ ### `getIDFromGUID(pEntity, pGUID)`
62
+
63
+ Looks up the numeric ID for a given Meadow GUID.
64
+
65
+ | Parameter | Type | Description |
66
+ |-----------|------|-------------|
67
+ | `pEntity` | `string` | Entity name. |
68
+ | `pGUID` | `string` | The Meadow GUID to look up. |
69
+
70
+ **Returns:** `number|string|false` -- The ID if found, or `false` if the GUID is not mapped.
71
+
72
+ ### `getIDFromGUIDAsync(pEntity, pGUID, fCallback)`
73
+
74
+ Asynchronous version of `getIDFromGUID`. If the GUID is not in the local map, attempts to fetch the record from the server via `fable.MeadowRestClient.getEntityByGUID()`.
75
+
76
+ | Parameter | Type | Description |
77
+ |-----------|------|-------------|
78
+ | `pEntity` | `string` | Entity name. |
79
+ | `pGUID` | `string` | The Meadow GUID to look up. |
80
+ | `fCallback` | `function(pError, pID)` | Callback with the ID if found, or `false`. |
81
+
82
+ If the record is fetched from the server, the GUID-to-ID mapping is stored for future lookups.
83
+
84
+ ### `getGUIDFromID(pEntity, pID)`
85
+
86
+ Looks up the Meadow GUID for a given numeric ID.
87
+
88
+ | Parameter | Type | Description |
89
+ |-----------|------|-------------|
90
+ | `pEntity` | `string` | Entity name. |
91
+ | `pID` | `number\|string` | The numeric ID to look up. |
92
+
93
+ **Returns:** `string|false` -- The GUID if found, or `false` if the ID is not mapped.
94
+
95
+ ### `mapExternalGUIDtoMeadowGUID(pEntity, pExternalGUID, pMeadowGUID)`
96
+
97
+ Stores a one-directional mapping from an external system GUID to a Meadow GUID.
98
+
99
+ | Parameter | Type | Description |
100
+ |-----------|------|-------------|
101
+ | `pEntity` | `string` | Entity name. |
102
+ | `pExternalGUID` | `string` | The external system's GUID value. |
103
+ | `pMeadowGUID` | `string` | The corresponding Meadow GUID. |
104
+
105
+ **Returns:** `true`
106
+
107
+ ### `getMeadowGUIDFromExternalGUID(pEntity, pExternalGUID)`
108
+
109
+ Looks up the Meadow GUID for a given external system GUID.
110
+
111
+ | Parameter | Type | Description |
112
+ |-----------|------|-------------|
113
+ | `pEntity` | `string` | Entity name. |
114
+ | `pExternalGUID` | `string` | The external system's GUID to look up. |
115
+
116
+ **Returns:** `string|false` -- The Meadow GUID if found, or `false`.
117
+
118
+ ### `getMeadowIDFromExternalGUID(pEntity, pExternalGUID)`
119
+
120
+ Resolves an external system GUID all the way to a Meadow numeric ID by chaining `getMeadowGUIDFromExternalGUID()` and `getIDFromGUID()`.
121
+
122
+ | Parameter | Type | Description |
123
+ |-----------|------|-------------|
124
+ | `pEntity` | `string` | Entity name. |
125
+ | `pExternalGUID` | `string` | The external system's GUID to resolve. |
126
+
127
+ **Returns:** `number|string|false` -- The Meadow ID if both mappings exist, or `false`.
128
+
129
+ ## Usage Examples
130
+
131
+ ### Basic GUID-to-ID Mapping
132
+
133
+ ```js
134
+ const libFable = require('fable');
135
+ const libGUIDMap = require('meadow-integration/source/Meadow-Service-Integration-GUIDMap');
136
+
137
+ const fable = new libFable({ Product: 'Mapper' });
138
+ const guidMap = fable.addAndInstantiateServiceType('MeadowGUIDMap', libGUIDMap);
139
+
140
+ // Store a mapping
141
+ guidMap.mapGUIDToID('Customer', 'INTG-CUST-001', 42);
142
+
143
+ // Look up by GUID
144
+ const id = guidMap.getIDFromGUID('Customer', 'INTG-CUST-001');
145
+ console.log(id); // 42
146
+
147
+ // Look up by ID (reverse)
148
+ const guid = guidMap.getGUIDFromID('Customer', 42);
149
+ console.log(guid); // 'INTG-CUST-001'
150
+ ```
151
+
152
+ ### External GUID Resolution Chain
153
+
154
+ ```js
155
+ // Step 1: Map external GUID to Meadow GUID
156
+ guidMap.mapExternalGUIDtoMeadowGUID('Customer', 'CRM-42', 'INTG-DEF-E-Customer-CRM-42');
157
+
158
+ // Step 2: Map Meadow GUID to Meadow ID (done by the adapter after server upsert)
159
+ guidMap.mapGUIDToID('Customer', 'INTG-DEF-E-Customer-CRM-42', 100);
160
+
161
+ // Step 3: Resolve external GUID directly to Meadow GUID
162
+ const meadowGUID = guidMap.getMeadowGUIDFromExternalGUID('Customer', 'CRM-42');
163
+ console.log(meadowGUID); // 'INTG-DEF-E-Customer-CRM-42'
164
+
165
+ // Step 4: Resolve external GUID all the way to Meadow ID
166
+ const meadowID = guidMap.getMeadowIDFromExternalGUID('Customer', 'CRM-42');
167
+ console.log(meadowID); // 100
168
+ ```
169
+
170
+ ### Cross-Entity Reference Resolution
171
+
172
+ ```js
173
+ // After integrating Customers, their mappings exist
174
+ guidMap.mapExternalGUIDtoMeadowGUID('Customer', 'CRM-42', 'INTG-DEF-E-Customer-CRM-42');
175
+ guidMap.mapGUIDToID('Customer', 'INTG-DEF-E-Customer-CRM-42', 100);
176
+
177
+ // When integrating Orders, resolve the Customer reference
178
+ const customerID = guidMap.getMeadowIDFromExternalGUID('Customer', 'CRM-42');
179
+ console.log(customerID); // 100
180
+
181
+ // The adapter uses this to set IDCustomer on the Order record
182
+ const orderRecord = {
183
+ GUIDOrder: 'INTG-DEF-E-Order-ORD-500',
184
+ IDCustomer: customerID,
185
+ Total: 99.99
186
+ };
187
+ ```
188
+
189
+ ### Async GUID Lookup (Server Fallback)
190
+
191
+ ```js
192
+ guidMap.getIDFromGUIDAsync('Customer', 'INTG-DEF-E-Customer-CRM-99',
193
+ (pError, pID) =>
194
+ {
195
+ if (pError)
196
+ {
197
+ console.error('Lookup failed:', pError.message);
198
+ return;
199
+ }
200
+ if (pID)
201
+ {
202
+ console.log('Found Customer ID:', pID);
203
+ }
204
+ else
205
+ {
206
+ console.log('Customer not found on server.');
207
+ }
208
+ });
209
+ ```
210
+
211
+ ## Mapping Flow Diagram
212
+
213
+ ```
214
+ External System MeadowGUIDMap Meadow Server
215
+ --------------- ------------- -------------
216
+ CRM-42 --mapExternalGUIDtoMeadowGUID-->
217
+ INTG-DEF-E-Customer-CRM-42
218
+ --mapGUIDToID-->
219
+ GUID: INTG-DEF-E-Customer-CRM-42 => ID: 100
220
+
221
+ Later lookups:
222
+ getMeadowGUIDFromExternalGUID('Customer', 'CRM-42')
223
+ => 'INTG-DEF-E-Customer-CRM-42'
224
+
225
+ getMeadowIDFromExternalGUID('Customer', 'CRM-42')
226
+ => 100
227
+
228
+ getGUIDFromID('Customer', 100)
229
+ => 'INTG-DEF-E-Customer-CRM-42'
230
+ ```
231
+
232
+ ## Related Services
233
+
234
+ - [MeadowIntegrationAdapter](./integration-adapter.md) -- The primary consumer; uses GUIDMap for all GUID resolution during record marshaling and upsert.