meadow-integration 1.0.4 → 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.
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 → _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 +13 -10
  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 +367 -0
  64. package/source/services/clone/Meadow-Service-Sync-Entity-Ongoing.js +457 -0
  65. package/source/services/clone/Meadow-Service-Sync.js +142 -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,213 @@
1
+ # Service-TabularCheck (MeadowIntegrationTabularCheck)
2
+
3
+ Statistical analysis service for tabular data records. Collects column-level statistics including row counts, empty value counts, numeric detection, and first/last values for data quality inspection before transformation or integration.
4
+
5
+ **Source:** `source/services/tabular/Service-TabularCheck.js`
6
+
7
+ **Extends:** `fable-serviceproviderbase`
8
+
9
+ ## Constructor
10
+
11
+ ```js
12
+ const tabularCheck = fable.serviceManager.instantiateServiceProvider('TabularCheck', pOptions);
13
+ ```
14
+
15
+ No custom options are required.
16
+
17
+ ## Methods
18
+
19
+ ### `newStatisticsObject(pTabularDatasetName)`
20
+
21
+ Creates a new, empty statistics container object for tracking dataset metrics.
22
+
23
+ | Parameter | Type | Description |
24
+ |-----------|------|-------------|
25
+ | `pTabularDatasetName` | `string` | A name identifying the dataset (e.g. `'airports.csv'`). |
26
+
27
+ **Returns:** `object` -- A statistics object with the following shape:
28
+
29
+ ```js
30
+ {
31
+ DataSet: 'airports.csv', // Name of the dataset
32
+ FirstRow: null, // Reference to the first record processed
33
+ RowCount: 0, // Total number of rows processed
34
+ LastRow: null, // Reference to the most recent record processed
35
+ Headers: [], // Array of column name strings, in discovery order
36
+ ColumnCount: 0, // Total unique columns discovered
37
+ ColumnStatistics: {}, // Per-column statistics (see below)
38
+ Records: null // Array of all records (only if pStoreFullRecord is true)
39
+ }
40
+ ```
41
+
42
+ ### `collectStatistics(pRecord, pStatisticsObject, pStoreFullRecord)`
43
+
44
+ Processes a single record and updates the statistics object with its data.
45
+
46
+ | Parameter | Type | Default | Description |
47
+ |-----------|------|---------|-------------|
48
+ | `pRecord` | `object` | -- | A single data record (key-value object). |
49
+ | `pStatisticsObject` | `object` | *(auto-created)* | The statistics object to update. If not a valid object, a new one is created automatically. |
50
+ | `pStoreFullRecord` | `boolean` | `false` | If `true`, pushes the full record into `Records` array for later inspection. |
51
+
52
+ **Returns:** `object` -- The updated statistics object.
53
+
54
+ **Per-column statistics shape** (each entry in `ColumnStatistics`):
55
+
56
+ ```js
57
+ {
58
+ Count: 0, // Number of records that have this column
59
+ EmptyCount: 0, // Number of records where this column is null or empty string
60
+ NumericCount: 0, // Number of records where this column's value is numeric
61
+ FirstValue: null, // The first non-null value seen for this column
62
+ LastValue: null // The most recent value seen for this column
63
+ }
64
+ ```
65
+
66
+ **Behavior notes:**
67
+ - Each call increments `RowCount` by 1.
68
+ - The first record processed is stored as `FirstRow`; every record updates `LastRow`.
69
+ - New columns are added to `Headers` and `ColumnStatistics` as they are discovered.
70
+ - A value is considered numeric if `fable.Math.parsePrecise(value, NaN)` returns a valid number.
71
+ - A value is considered empty if it is strictly `null` or an empty string `''`.
72
+ - Callers are responsible for ensuring each record is only sent through once.
73
+
74
+ ## Statistics Object Shape (Complete)
75
+
76
+ ```js
77
+ {
78
+ DataSet: 'my-dataset',
79
+ FirstRow: { Name: 'Alice', Age: '30', City: 'Portland' },
80
+ RowCount: 1000,
81
+ LastRow: { Name: 'Zoe', Age: '25', City: 'Seattle' },
82
+ Headers: ['Name', 'Age', 'City'],
83
+ ColumnCount: 3,
84
+ ColumnStatistics:
85
+ {
86
+ Name:
87
+ {
88
+ Count: 1000,
89
+ EmptyCount: 5,
90
+ NumericCount: 0,
91
+ FirstValue: 'Alice',
92
+ LastValue: 'Zoe'
93
+ },
94
+ Age:
95
+ {
96
+ Count: 1000,
97
+ EmptyCount: 12,
98
+ NumericCount: 988,
99
+ FirstValue: '30',
100
+ LastValue: '25'
101
+ },
102
+ City:
103
+ {
104
+ Count: 1000,
105
+ EmptyCount: 50,
106
+ NumericCount: 0,
107
+ FirstValue: 'Portland',
108
+ LastValue: 'Seattle'
109
+ }
110
+ },
111
+ Records: null
112
+ }
113
+ ```
114
+
115
+ ## Usage Examples
116
+
117
+ ### Basic Dataset Statistics
118
+
119
+ ```js
120
+ const libFable = require('fable');
121
+ const libTabularCheck = require('meadow-integration/source/services/tabular/Service-TabularCheck');
122
+
123
+ const fable = new libFable({ Product: 'DataInspector' });
124
+
125
+ fable.serviceManager.addServiceType('TabularCheck', libTabularCheck);
126
+ const checker = fable.serviceManager.instantiateServiceProvider('TabularCheck');
127
+
128
+ // Create a statistics container
129
+ const stats = checker.newStatisticsObject('customers.csv');
130
+
131
+ // Process records one by one (e.g. from a CSV stream)
132
+ const records =
133
+ [
134
+ { Name: 'Alice', Email: 'alice@example.com', Age: '30' },
135
+ { Name: 'Bob', Email: '', Age: '25' },
136
+ { Name: '', Email: 'charlie@example.com', Age: 'unknown' },
137
+ { Name: 'Diana', Email: 'diana@example.com', Age: '35' }
138
+ ];
139
+
140
+ for (const record of records)
141
+ {
142
+ checker.collectStatistics(record, stats);
143
+ }
144
+
145
+ console.log(`Dataset: ${stats.DataSet}`);
146
+ console.log(`Rows: ${stats.RowCount}`); // 4
147
+ console.log(`Columns: ${stats.ColumnCount}`); // 3
148
+ console.log(`Headers: ${stats.Headers.join(', ')}`); // Name, Email, Age
149
+
150
+ console.log('Name empty count:', stats.ColumnStatistics.Name.EmptyCount); // 1
151
+ console.log('Email empty count:', stats.ColumnStatistics.Email.EmptyCount); // 1
152
+ console.log('Age numeric count:', stats.ColumnStatistics.Age.NumericCount); // 3 (30, 25, 35)
153
+ console.log('Age first value:', stats.ColumnStatistics.Age.FirstValue); // '30'
154
+ ```
155
+
156
+ ### Storing Full Records for Inspection
157
+
158
+ ```js
159
+ const stats = checker.newStatisticsObject('products.csv');
160
+ stats.Records = []; // Must initialize the Records array before enabling storage
161
+
162
+ for (const record of productRecords)
163
+ {
164
+ checker.collectStatistics(record, stats, true);
165
+ }
166
+
167
+ console.log(`Stored ${stats.Records.length} records for inspection.`);
168
+ console.log('First stored record:', stats.Records[0]);
169
+ ```
170
+
171
+ ### Auto-Created Statistics Object
172
+
173
+ ```js
174
+ // If you pass a non-object, a statistics object is created automatically
175
+ const stats = checker.collectStatistics({ Name: 'Alice', Age: '30' }, null);
176
+ console.log(stats.DataSet); // 'Unknown-{uuid}'
177
+ console.log(stats.RowCount); // 1
178
+ ```
179
+
180
+ ### Analyzing Column Quality
181
+
182
+ ```js
183
+ const stats = checker.newStatisticsObject('orders.csv');
184
+
185
+ for (const record of orderRecords)
186
+ {
187
+ checker.collectStatistics(record, stats);
188
+ }
189
+
190
+ // Report columns with high empty rates
191
+ for (const header of stats.Headers)
192
+ {
193
+ const colStats = stats.ColumnStatistics[header];
194
+ const emptyRate = (colStats.EmptyCount / colStats.Count * 100).toFixed(1);
195
+
196
+ if (colStats.EmptyCount > 0)
197
+ {
198
+ console.log(`Column "${header}": ${emptyRate}% empty (${colStats.EmptyCount}/${colStats.Count})`);
199
+ }
200
+
201
+ // Detect likely numeric columns
202
+ const numericRate = (colStats.NumericCount / colStats.Count * 100).toFixed(1);
203
+ if (colStats.NumericCount > colStats.Count * 0.9)
204
+ {
205
+ console.log(`Column "${header}": likely numeric (${numericRate}% numeric values)`);
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## Related Services
211
+
212
+ - [Service-TabularTransform](./tabular-transform.md) -- Transforms tabular records using mapping configurations; often used after TabularCheck validates the data shape.
213
+ - [MeadowIntegrationAdapter](./integration-adapter.md) -- Integrates transformed records into a Meadow data store.
@@ -0,0 +1,316 @@
1
+ # Service-TabularTransform (MeadowIntegrationTabularTransform)
2
+
3
+ Transformation service for mapping tabular data records into Meadow entity comprehensions. Uses configurable column mapping templates to convert external data (CSV rows, API results, etc.) into entity records with auto-generated GUIDs, template-based field values, and optional solver-based transformations.
4
+
5
+ **Source:** `source/services/tabular/Service-TabularTransform.js`
6
+
7
+ **Extends:** `fable-serviceproviderbase`
8
+
9
+ ## Constructor
10
+
11
+ ```js
12
+ const transform = fable.serviceManager.instantiateServiceProvider('TabularTransform', pOptions);
13
+ ```
14
+
15
+ No custom options are required.
16
+
17
+ ## Mapping Configuration
18
+
19
+ A mapping configuration defines how incoming data fields map to entity record fields. It can be provided explicitly or generated automatically from the first record.
20
+
21
+ ### Mapping Configuration Shape
22
+
23
+ ```js
24
+ {
25
+ "Entity": "Airport",
26
+ "GUIDTemplate": "Airport-{~D:iata~}",
27
+ "GUIDName": "GUIDAirport", // Auto-derived as GUID{Entity} if omitted
28
+ "Mappings":
29
+ {
30
+ "Code": "{~D:iata~}",
31
+ "Name": "{~D:name~}",
32
+ "Description": "{~D:name~} airport in {~D:city~}",
33
+ "City": "{~D:city~}",
34
+ "State": "{~D:state~}",
35
+ "Country": "{~D:country~}",
36
+ "Latitude": "{~D:lat~}",
37
+ "Longitude": "{~D:long~}"
38
+ },
39
+ "Solvers": [], // Optional array of expression solver definitions
40
+ "MultipleGUIDUniqueness": false, // If true, supports multiple GUID uniqueness entries per record
41
+ "ManyfestAddresses": false // If true, uses Manyfest setValueAtAddress for nested paths
42
+ }
43
+ ```
44
+
45
+ Template expressions use Fable's template engine syntax (e.g., `{~D:fieldname~}` or `{~Data:Record.fieldname~}`).
46
+
47
+ ## Mapping Outcome Object
48
+
49
+ The mapping outcome object tracks the state and results of a transformation operation.
50
+
51
+ ### `newMappingOutcomeObject()`
52
+
53
+ Creates a new, empty mapping outcome object.
54
+
55
+ **Returns:**
56
+
57
+ ```js
58
+ {
59
+ Comprehension: {}, // Generated records keyed by entity name, then by GUID
60
+ ExistingComprehension: false, // Optional existing comprehension for merging with previous data
61
+
62
+ ImplicitConfiguration: false, // Auto-generated configuration from first record
63
+ ExplicitConfiguration: false, // User-provided mapping configuration file
64
+ UserConfiguration: {}, // Runtime overrides (e.g. different entity name)
65
+ Configuration: false, // Final merged configuration (Implicit + Explicit + User)
66
+
67
+ ParsedRowCount: 0, // Number of rows processed
68
+ BadRecords: [] // Records that failed validation (no GUID, invalid data)
69
+ }
70
+ ```
71
+
72
+ ## Methods
73
+
74
+ ### `newMappingOutcomeObject()`
75
+
76
+ Creates a fresh mapping outcome container for a new transformation session.
77
+
78
+ **Returns:** `object` -- An empty mapping outcome object (see shape above).
79
+
80
+ ### `generateMappingConfigurationPrototype(pRepresentativeString, pRecord)`
81
+
82
+ Auto-generates a mapping configuration from a representative string (typically a filename) and a sample record.
83
+
84
+ | Parameter | Type | Description |
85
+ |-----------|------|-------------|
86
+ | `pRepresentativeString` | `string` | A name used to derive the entity name (e.g. `'my favorite cats.csv'` becomes `'MyFavoriteCats'`). |
87
+ | `pRecord` | `object` | A sample record whose keys become the mapping fields. |
88
+
89
+ **Returns:** `object` -- A mapping configuration with auto-generated `Entity`, `GUIDTemplate`, and `Mappings`.
90
+
91
+ **Example:**
92
+
93
+ ```js
94
+ const config = transform.generateMappingConfigurationPrototype('airport data', { iata: 'PDX', name: 'Portland' });
95
+ // Returns:
96
+ // {
97
+ // Entity: 'AirportData',
98
+ // GUIDTemplate: 'GUID-AirportData-{~Data:Record.iata~}',
99
+ // Mappings: {
100
+ // iata: '{~Data:Record.iata~}',
101
+ // name: '{~Data:Record.name~}'
102
+ // }
103
+ // }
104
+ ```
105
+
106
+ ### `createRecordFromMapping(pRecord, pMapping, pRecordPrototype)`
107
+
108
+ Creates a single entity record by applying a mapping configuration to an incoming data record.
109
+
110
+ | Parameter | Type | Description |
111
+ |-----------|------|-------------|
112
+ | `pRecord` | `object` | The incoming data record (used as template data context). |
113
+ | `pMapping` | `object` | The mapping configuration with `GUIDName`, `GUIDTemplate`, and `Mappings`. |
114
+ | `pRecordPrototype` | `object\|null` | Optional base object to merge onto (deep-cloned). Defaults to `{}`. |
115
+
116
+ **Returns:** `object` -- The generated entity record with GUID and mapped fields.
117
+
118
+ **Behavior:**
119
+ - Sets the GUID field using `fable.parseTemplate(GUIDTemplate, pRecord)`.
120
+ - For each key in `Mappings`, resolves the template expression against `pRecord`.
121
+ - If `pMapping.ManyfestAddresses` is `true`, uses `fable.manifest.setValueAtAddress()` for nested property paths.
122
+
123
+ ### `addRecordToComprehension(pIncomingRecord, pMappingOutcome, pNewRecordPrototype, pGUIDUniquenessString)`
124
+
125
+ Creates a record from mapping and adds it to the comprehension within the mapping outcome, handling duplicates and merging with existing data.
126
+
127
+ | Parameter | Type | Description |
128
+ |-----------|------|-------------|
129
+ | `pIncomingRecord` | `object` | The raw incoming data record. |
130
+ | `pMappingOutcome` | `object` | The mapping outcome object containing the comprehension. |
131
+ | `pNewRecordPrototype` | `object` | Optional record prototype for base values. |
132
+ | `pGUIDUniquenessString` | `string` | Optional uniqueness string injected as `_GUIDUniqueness` into the record before mapping. |
133
+
134
+ **Duplicate handling:**
135
+ - If the generated GUID already exists in the current `Comprehension`, the new record is merged onto the existing one via `Object.assign`.
136
+ - If the GUID exists in `ExistingComprehension` (previous run), it is pulled in and merged.
137
+ - If the record has no valid GUID, it is added to `BadRecords`.
138
+
139
+ ### `transformRecord(pIncomingRecord, pMappingOutcomeObject)`
140
+
141
+ The primary entry point for transforming a single incoming record. Handles initialization, solver execution, and comprehension insertion.
142
+
143
+ | Parameter | Type | Description |
144
+ |-----------|------|-------------|
145
+ | `pIncomingRecord` | `object` | The raw incoming data record. |
146
+ | `pMappingOutcomeObject` | `object` | The mapping outcome object (created via `newMappingOutcomeObject()`). |
147
+
148
+ **Behavior:**
149
+ 1. Initializes the mapping outcome if not already done (merges Implicit, Explicit, and User configurations).
150
+ 2. Increments `ParsedRowCount`.
151
+ 3. Creates a solution context object with `IncomingRecord`, `MappingConfiguration`, `RowIndex`, `Fable`, and `AppData`.
152
+ 4. If `Configuration.Solvers` is defined, executes each solver expression via `fable.ExpressionParser.solve()`. Solvers can modify `NewRecordPrototype` and `NewRecordsGUIDUniqueness`.
153
+ 5. If `MultipleGUIDUniqueness` is enabled and uniqueness entries exist, creates one record per uniqueness entry.
154
+ 6. Otherwise, creates a single record and adds it to the comprehension.
155
+
156
+ ### Lifecycle Hooks
157
+
158
+ Two empty methods are available for subclass overrides:
159
+
160
+ - **`onBeforeInitializeMappingOutcomeObject(pMappingOutcomeObject)`** -- Called before configuration merging.
161
+ - **`onAfterInitializeMappingOutcomeObject(pMappingOutcomeObject)`** -- Called after configuration merging and GUID name setup.
162
+
163
+ ## Usage Examples
164
+
165
+ ### Basic CSV-to-Entity Transformation
166
+
167
+ ```js
168
+ const libFable = require('fable');
169
+ const libTabularTransform = require('meadow-integration/source/services/tabular/Service-TabularTransform');
170
+
171
+ const fable = new libFable({ Product: 'DataImporter' });
172
+
173
+ fable.serviceManager.addServiceType('TabularTransform', libTabularTransform);
174
+ const transform = fable.serviceManager.instantiateServiceProvider('TabularTransform');
175
+
176
+ // Define the mapping configuration
177
+ const mappingConfig =
178
+ {
179
+ Entity: 'Airport',
180
+ GUIDTemplate: 'Airport-{~Data:Record.iata~}',
181
+ Mappings:
182
+ {
183
+ Code: '{~Data:Record.iata~}',
184
+ Name: '{~Data:Record.name~}',
185
+ City: '{~Data:Record.city~}',
186
+ State: '{~Data:Record.state~}',
187
+ Country: '{~Data:Record.country~}'
188
+ }
189
+ };
190
+
191
+ // Create a mapping outcome and set the explicit configuration
192
+ const outcome = transform.newMappingOutcomeObject();
193
+ outcome.ExplicitConfiguration = mappingConfig;
194
+
195
+ // Transform each CSV row
196
+ const csvRows =
197
+ [
198
+ { iata: 'PDX', name: 'Portland International', city: 'Portland', state: 'OR', country: 'US' },
199
+ { iata: 'SEA', name: 'Seattle-Tacoma International', city: 'Seattle', state: 'WA', country: 'US' },
200
+ { iata: 'SFO', name: 'San Francisco International', city: 'San Francisco', state: 'CA', country: 'US' }
201
+ ];
202
+
203
+ for (const row of csvRows)
204
+ {
205
+ transform.transformRecord(row, outcome);
206
+ }
207
+
208
+ console.log(`Parsed ${outcome.ParsedRowCount} rows.`);
209
+ console.log(`Bad records: ${outcome.BadRecords.length}`);
210
+ console.log('Airport records:', Object.keys(outcome.Comprehension.Airport));
211
+ // ['Airport-PDX', 'Airport-SEA', 'Airport-SFO']
212
+
213
+ const pdxRecord = outcome.Comprehension.Airport['Airport-PDX'];
214
+ console.log(pdxRecord);
215
+ // {
216
+ // GUIDAirport: 'Airport-PDX',
217
+ // Code: 'PDX',
218
+ // Name: 'Portland International',
219
+ // City: 'Portland',
220
+ // State: 'OR',
221
+ // Country: 'US'
222
+ // }
223
+ ```
224
+
225
+ ### Auto-Generated Configuration from Data
226
+
227
+ ```js
228
+ const transform = fable.serviceManager.instantiateServiceProvider('TabularTransform');
229
+
230
+ // Auto-generate a mapping from a sample record
231
+ const sampleRecord = { iata: 'PDX', name: 'Portland', city: 'Portland', state: 'OR' };
232
+ const autoConfig = transform.generateMappingConfigurationPrototype('airports', sampleRecord);
233
+
234
+ console.log(autoConfig.Entity); // 'Airports'
235
+ console.log(autoConfig.GUIDTemplate); // 'GUID-Airports-{~Data:Record.iata~}'
236
+ console.log(autoConfig.Mappings);
237
+ // {
238
+ // iata: '{~Data:Record.iata~}',
239
+ // name: '{~Data:Record.name~}',
240
+ // city: '{~Data:Record.city~}',
241
+ // state: '{~Data:Record.state~}'
242
+ // }
243
+ ```
244
+
245
+ ### Creating a Single Record from Mapping
246
+
247
+ ```js
248
+ const mapping =
249
+ {
250
+ GUIDName: 'GUIDProduct',
251
+ GUIDTemplate: 'PROD-{~Data:Record.sku~}',
252
+ Mappings:
253
+ {
254
+ Name: '{~Data:Record.name~}',
255
+ Price: '{~Data:Record.price~}'
256
+ }
257
+ };
258
+
259
+ const record = transform.createRecordFromMapping(
260
+ { sku: 'ABC-123', name: 'Widget', price: '19.99' },
261
+ mapping);
262
+
263
+ console.log(record);
264
+ // {
265
+ // GUIDProduct: 'PROD-ABC-123',
266
+ // Name: 'Widget',
267
+ // Price: '19.99'
268
+ // }
269
+ ```
270
+
271
+ ### Merging with Existing Comprehension
272
+
273
+ ```js
274
+ const outcome = transform.newMappingOutcomeObject();
275
+ outcome.ExplicitConfiguration = mappingConfig;
276
+
277
+ // Provide existing data from a previous run
278
+ outcome.ExistingComprehension =
279
+ {
280
+ Airport:
281
+ {
282
+ 'Airport-PDX': { GUIDAirport: 'Airport-PDX', Code: 'PDX', Name: 'Portland Intl', Rating: 5 }
283
+ }
284
+ };
285
+
286
+ // Transform a record that matches an existing GUID
287
+ transform.transformRecord(
288
+ { iata: 'PDX', name: 'Portland International (Updated)', city: 'Portland', state: 'OR', country: 'US' },
289
+ outcome);
290
+
291
+ // The existing record is merged with new data
292
+ const merged = outcome.Comprehension.Airport['Airport-PDX'];
293
+ console.log(merged.Rating); // 5 (preserved from existing)
294
+ console.log(merged.Name); // 'Portland International (Updated)' (overwritten by new data)
295
+ ```
296
+
297
+ ### Using User Configuration Overrides
298
+
299
+ ```js
300
+ const outcome = transform.newMappingOutcomeObject();
301
+ outcome.ExplicitConfiguration = mappingConfig;
302
+
303
+ // Override the entity name at runtime
304
+ outcome.UserConfiguration = { Entity: 'InternationalAirport' };
305
+
306
+ transform.transformRecord(csvRows[0], outcome);
307
+
308
+ // Records are stored under the overridden entity name
309
+ console.log(Object.keys(outcome.Comprehension)); // ['InternationalAirport']
310
+ ```
311
+
312
+ ## Related Services
313
+
314
+ - [Service-TabularCheck](./tabular-check.md) -- Statistical analysis for tabular data; often used before transformation to validate the data shape.
315
+ - [MeadowIntegrationAdapter](./integration-adapter.md) -- Integrates the comprehension output from TabularTransform into a Meadow data store.
316
+ - [MeadowGUIDMap](./guid-map.md) -- Maintains GUID-to-ID mappings that may be needed during integration of transformed records.