meadow-integration 1.0.1 → 1.0.4

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 (52) hide show
  1. package/CONTRIBUTING.md +50 -0
  2. package/README.md +223 -7
  3. package/docs/README.md +107 -7
  4. package/docs/_sidebar.md +38 -0
  5. package/docs/_topbar.md +7 -0
  6. package/docs/cli-reference.md +242 -0
  7. package/docs/comprehensions.md +98 -0
  8. package/docs/cover.md +11 -0
  9. package/docs/css/docuserve.css +73 -0
  10. package/docs/examples-walkthrough.md +138 -0
  11. package/docs/index.html +37 -20
  12. package/docs/integration-adapter.md +109 -0
  13. package/docs/mapping-files.md +140 -0
  14. package/docs/programmatic-api.md +173 -0
  15. package/docs/rest-api-reference.md +731 -0
  16. package/docs/retold-catalog.json +153 -0
  17. package/docs/retold-keyword-index.json +4828 -0
  18. package/examples/Example-001-CSV-Check.sh +29 -0
  19. package/examples/Example-002-CSV-Transform-Implicit.sh +31 -0
  20. package/examples/Example-003-CSV-Transform-CLI-Options.sh +39 -0
  21. package/examples/Example-004-CSV-Transform-Mapping-File.sh +41 -0
  22. package/examples/Example-005-Multi-Entity-Bookstore.sh +60 -0
  23. package/examples/Example-006-Multi-CSV-Intersect.sh +74 -0
  24. package/examples/Example-007-Comprehension-To-Array.sh +41 -0
  25. package/examples/Example-008-Comprehension-To-CSV.sh +51 -0
  26. package/examples/Example-009-JSON-Array-Transform.sh +46 -0
  27. package/examples/Example-010-Programmatic-API.js +138 -0
  28. package/examples/README.md +44 -0
  29. package/examples/output/.gitignore +2 -0
  30. package/package.json +7 -4
  31. package/source/Meadow-Integration.js +3 -1
  32. package/source/cli/Meadow-Integration-CLI-Program.js +4 -1
  33. package/source/cli/commands/Meadow-Integration-Command-ObjectArrayToCSV.js +49 -32
  34. package/source/cli/commands/Meadow-Integration-Command-Serve.js +51 -0
  35. package/source/restserver/Meadow-Integration-Server-Endpoints.js +83 -0
  36. package/source/restserver/Meadow-Integration-Server.js +86 -0
  37. package/source/restserver/endpoints/Endpoint-CSVCheck.js +91 -0
  38. package/source/restserver/endpoints/Endpoint-CSVTransform.js +189 -0
  39. package/source/restserver/endpoints/Endpoint-ComprehensionArray.js +121 -0
  40. package/source/restserver/endpoints/Endpoint-ComprehensionIntersect.js +166 -0
  41. package/source/restserver/endpoints/Endpoint-ComprehensionPush.js +209 -0
  42. package/source/restserver/endpoints/Endpoint-EntityFromTabularFolder.js +252 -0
  43. package/source/restserver/endpoints/Endpoint-JSONArrayTransform.js +238 -0
  44. package/source/restserver/endpoints/Endpoint-ObjectArrayToCSV.js +231 -0
  45. package/source/restserver/endpoints/Endpoint-TSVCheck.js +93 -0
  46. package/source/restserver/endpoints/Endpoint-TSVTransform.js +191 -0
  47. package/test/Meadow-Integration-Server_test.js +1170 -0
  48. package/test/data/test-comprehension-secondary.json +8 -0
  49. package/test/data/test-comprehension.json +8 -0
  50. package/test/data/test-small.csv +6 -0
  51. package/test/data/test-small.json +7 -0
  52. package/test/data/test-small.tsv +6 -0
@@ -0,0 +1,98 @@
1
+ # Comprehensions
2
+
3
+ A Comprehension is the core data structure in meadow-integration. It is a JSON object that stores entity records keyed by their GUID, providing fast lookup and easy merging across data sources.
4
+
5
+ ## Object Format
6
+
7
+ The standard comprehension format stores records as properties of an entity object:
8
+
9
+ ```json
10
+ {
11
+ "EntityName": {
12
+ "GUID-1": { "GUIDEntityName": "GUID-1", "Field1": "value", "Field2": "value" },
13
+ "GUID-2": { "GUIDEntityName": "GUID-2", "Field1": "value", "Field2": "value" }
14
+ }
15
+ }
16
+ ```
17
+
18
+ ### Benefits of Object Format
19
+
20
+ - **O(1) lookup** by GUID -- no scanning required
21
+ - **Natural deduplication** -- duplicate GUIDs merge automatically
22
+ - **Easy merging** -- `Object.assign()` combines records from multiple sources
23
+ - **Multi-entity support** -- one file can hold Books, Authors, and Joins
24
+
25
+ ## Array Format
26
+
27
+ For export or consumption by other tools, comprehensions can be converted to arrays:
28
+
29
+ ```json
30
+ [
31
+ { "GUIDEntityName": "GUID-1", "Field1": "value", "Field2": "value" },
32
+ { "GUIDEntityName": "GUID-2", "Field1": "value", "Field2": "value" }
33
+ ]
34
+ ```
35
+
36
+ Convert between formats using:
37
+
38
+ ```shell
39
+ # Object -> Array
40
+ npx meadow-integration comprehensionarray input.json -e MyEntity -o output.json
41
+
42
+ # Array -> CSV
43
+ npx meadow-integration objectarraytocsv input.json -o output.csv
44
+ ```
45
+
46
+ ## Multi-Entity Comprehensions
47
+
48
+ A single comprehension file can contain records for multiple entity types. This is created by running `csvtransform` multiple times with different mapping files, passing the `-i` flag to merge into the existing comprehension:
49
+
50
+ ```shell
51
+ # Create Book entities
52
+ npx meadow-integration csvtransform books.csv -m mapping_Book.json -o store.json
53
+
54
+ # Add Author entities to the same file
55
+ npx meadow-integration csvtransform books.csv -m mapping_Author.json -i store.json -o store.json
56
+
57
+ # Add BookAuthorJoin entities
58
+ npx meadow-integration csvtransform books.csv -m mapping_Join.json -i store.json -o store.json
59
+ ```
60
+
61
+ Result:
62
+
63
+ ```json
64
+ {
65
+ "Book": { "Book_1": {...}, "Book_2": {...} },
66
+ "Author": { "Author_SuzanneCollins": {...}, "Author_JKRowling": {...} },
67
+ "BookAuthorJoin": { "BAJ_A_SuzanneCollins_B_1": {...} }
68
+ }
69
+ ```
70
+
71
+ ## Merging Comprehensions
72
+
73
+ The `comprehensionintersect` command merges two comprehension files. Records with matching GUIDs have their fields merged (later values overwrite earlier ones):
74
+
75
+ ```shell
76
+ npx meadow-integration comprehensionintersect file1.json -i file2.json -e MyEntity -o merged.json
77
+ ```
78
+
79
+ This is particularly useful when the same entities have data spread across multiple source files (e.g. housing characteristics and housing costs for the same neighborhoods).
80
+
81
+ ## GUID Design
82
+
83
+ GUIDs are the primary key for comprehension records. Good GUID design ensures:
84
+
85
+ - **Uniqueness** -- Each record gets a distinct key
86
+ - **Determinism** -- The same source data always generates the same GUID
87
+ - **Mergeability** -- Related data from different sources can be matched
88
+
89
+ ### GUID Template Patterns
90
+
91
+ | Pattern | Use Case |
92
+ |---------|----------|
93
+ | `Entity_{~D:Record.id~}` | Single-column natural key |
94
+ | `{~D:Record.date~}_{~D:Record.seq~}` | Composite key |
95
+ | `{~PascalCaseIdentifier:Record.name~}` | Name-based key (normalized) |
96
+ | `{~D:Record.shared_key~}` | Cross-file merge key |
97
+
98
+ When the same GUID template is used across multiple csvtransform runs on different source files, the records are automatically merged in the comprehension.
package/docs/cover.md ADDED
@@ -0,0 +1,11 @@
1
+ # Meadow Integration <small>1.0</small>
2
+
3
+ > Data integration toolkit for transforming CSV, TSV, and JSON into Meadow entity comprehensions
4
+
5
+ - Transform tabular data into structured entity records
6
+ - Merge multiple data sources by shared keys
7
+ - Multi-entity extraction from single sources using Solvers
8
+ - CLI utility, programmatic API, and REST integration
9
+
10
+ [GitHub](https://github.com/stevenvelozo/meadow-integration)
11
+ [Get Started](#meadow-integration)
@@ -0,0 +1,73 @@
1
+ /* ============================================================================
2
+ Pict Docuserve - Base Styles
3
+ ============================================================================ */
4
+
5
+ /* Reset and base */
6
+ *, *::before, *::after {
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ html, body {
11
+ margin: 0;
12
+ padding: 0;
13
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
14
+ font-size: 16px;
15
+ line-height: 1.5;
16
+ color: #423D37;
17
+ background-color: #fff;
18
+ -webkit-font-smoothing: antialiased;
19
+ -moz-osx-font-smoothing: grayscale;
20
+ }
21
+
22
+ /* Typography */
23
+ h1, h2, h3, h4, h5, h6 {
24
+ margin-top: 0;
25
+ line-height: 1.3;
26
+ }
27
+
28
+ a {
29
+ color: #2E7D74;
30
+ text-decoration: none;
31
+ }
32
+
33
+ a:hover {
34
+ color: #256861;
35
+ }
36
+
37
+ /* Application container */
38
+ #Docuserve-Application-Container {
39
+ min-height: 100vh;
40
+ }
41
+
42
+ /* Utility: scrollbar styling */
43
+ ::-webkit-scrollbar {
44
+ width: 8px;
45
+ }
46
+
47
+ ::-webkit-scrollbar-track {
48
+ background: #F5F0E8;
49
+ }
50
+
51
+ ::-webkit-scrollbar-thumb {
52
+ background: #D4CCBE;
53
+ border-radius: 4px;
54
+ }
55
+
56
+ ::-webkit-scrollbar-thumb:hover {
57
+ background: #B5AA9A;
58
+ }
59
+
60
+ /* Responsive adjustments */
61
+ @media (max-width: 768px) {
62
+ html {
63
+ font-size: 14px;
64
+ }
65
+
66
+ #Docuserve-Sidebar-Container {
67
+ display: none;
68
+ }
69
+
70
+ .docuserve-body {
71
+ flex-direction: column;
72
+ }
73
+ }
@@ -0,0 +1,138 @@
1
+ # Examples Walkthrough
2
+
3
+ The `examples/` folder contains runnable scripts that demonstrate meadow-integration features. Each script is self-contained and writes output to `examples/output/`.
4
+
5
+ ## Data Sources
6
+
7
+ The examples use data from `docs/examples/data/`:
8
+
9
+ - **books.csv** -- 10,000 book records (id, title, author, isbn, ratings, etc.)
10
+ - **seattle_neighborhoods/** -- Three Seattle census datasets sharing a Neighborhood Name column
11
+
12
+ ## Example 001: CSV Check
13
+
14
+ Analyzes a CSV file to understand its structure before transforming it.
15
+
16
+ ```shell
17
+ ./examples/Example-001-CSV-Check.sh
18
+ ```
19
+
20
+ **What it does:** Runs `csvcheck` on books.csv and produces a statistics file showing row/column counts, headers, and per-column analysis (empty counts, numeric counts, first/last values).
21
+
22
+ **When to use:** As the first step with any new data source to understand what you are working with.
23
+
24
+ ## Example 002: CSV Transform (Implicit)
25
+
26
+ Transforms a CSV with auto-detected settings.
27
+
28
+ ```shell
29
+ ./examples/Example-002-CSV-Transform-Implicit.sh
30
+ ```
31
+
32
+ **What it does:** Runs `csvtransform` with no mapping file or options. The entity name is derived from the filename, the GUID is generated from the first column, and all columns are mapped 1:1.
33
+
34
+ **When to use:** Quick exploration of what a comprehension looks like before writing a mapping file.
35
+
36
+ ## Example 003: CSV Transform (CLI Options)
37
+
38
+ Controls the entity name and GUID template via command-line flags.
39
+
40
+ ```shell
41
+ ./examples/Example-003-CSV-Transform-CLI-Options.sh
42
+ ```
43
+
44
+ **What it does:** Uses `-e Book`, `-n GUIDBook`, and `-g "Book_{~D:Record.id~}"` to explicitly define the entity and GUID structure.
45
+
46
+ **When to use:** One-off transforms where you want specific entity naming but do not need column filtering.
47
+
48
+ ## Example 004: CSV Transform (Mapping File)
49
+
50
+ Uses a JSON mapping file for precise column control.
51
+
52
+ ```shell
53
+ ./examples/Example-004-CSV-Transform-Mapping-File.sh
54
+ ```
55
+
56
+ **What it does:** Reads `mapping_books_Book.json` which maps only 7 fields from the 23-column CSV. Demonstrates computed fields (`PublicationYear` using `Math.roundPrecise`) and static values (`Genre: "Unknown"`).
57
+
58
+ **When to use:** Production data integration where you want to control exactly which fields are included and how they are named.
59
+
60
+ ## Example 005: Multi-Entity Bookstore
61
+
62
+ Builds a complete relational data set from a single CSV.
63
+
64
+ ```shell
65
+ ./examples/Example-005-Multi-Entity-Bookstore.sh
66
+ ```
67
+
68
+ **What it does:** Runs three `csvtransform` passes on books.csv with different mapping files to create:
69
+ 1. **Book** entities (one per book)
70
+ 2. **Author** entities (unique authors, split from comma-separated values using Solvers)
71
+ 3. **BookAuthorJoin** entities (many-to-many relationships)
72
+
73
+ Each pass uses `-i` to merge into the same comprehension file.
74
+
75
+ **When to use:** When a single data source needs to be decomposed into multiple related entity types.
76
+
77
+ ## Example 006: Multi-CSV Intersect
78
+
79
+ Merges three CSV files that share a common key.
80
+
81
+ ```shell
82
+ ./examples/Example-006-Multi-CSV-Intersect.sh
83
+ ```
84
+
85
+ **What it does:** Transforms three Seattle neighborhood CSVs into separate comprehensions keyed on Neighborhood Name, then uses `comprehensionintersect` to merge them into one unified dataset.
86
+
87
+ **When to use:** When the same entities have data spread across multiple source files (e.g. different database tables or API responses).
88
+
89
+ ## Example 007: Comprehension to Array
90
+
91
+ Converts from object-keyed format to a JSON array.
92
+
93
+ ```shell
94
+ ./examples/Example-007-Comprehension-To-Array.sh
95
+ ```
96
+
97
+ **What it does:** Creates a Book comprehension, then converts it from `{ "Book_1": {...} }` format to `[ {...}, {...} ]` format.
98
+
99
+ **When to use:** When downstream consumers need an array (UI tables, further processing, export).
100
+
101
+ ## Example 008: Comprehension to CSV
102
+
103
+ Full round-trip from CSV through comprehension back to CSV.
104
+
105
+ ```shell
106
+ ./examples/Example-008-Comprehension-To-CSV.sh
107
+ ```
108
+
109
+ **What it does:** CSV -> Comprehension -> Array -> CSV export.
110
+
111
+ **When to use:** Reviewing transformed data in a spreadsheet, or creating filtered/cleaned CSVs.
112
+
113
+ ## Example 009: JSON Array Transform
114
+
115
+ Transforms a JSON array file into a comprehension.
116
+
117
+ ```shell
118
+ ./examples/Example-009-JSON-Array-Transform.sh
119
+ ```
120
+
121
+ **What it does:** Creates a JSON array from CSV data, then uses `jsonarraytransform` with a mapping file to create a new comprehension.
122
+
123
+ **When to use:** When your source data comes as JSON (e.g. API responses) instead of CSV.
124
+
125
+ ## Example 010: Programmatic API
126
+
127
+ Uses meadow-integration services directly in Node.js code.
128
+
129
+ ```shell
130
+ node examples/Example-010-Programmatic-API.js
131
+ ```
132
+
133
+ **What it does:** Demonstrates three services without the CLI:
134
+ 1. **TabularCheck** -- collecting statistics on parsed CSV records
135
+ 2. **TabularTransform** -- building a comprehension with explicit configuration
136
+ 3. **GUIDMap** -- tracking bidirectional GUID-to-ID mappings
137
+
138
+ **When to use:** When you are building data integration into a larger application and need programmatic control.
package/docs/index.html CHANGED
@@ -1,22 +1,39 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>Document</title>
6
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7
- <meta name="description" content="Description">
8
- <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
9
- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
10
- </head>
11
- <body>
12
- <div id="app"></div>
13
- <script>
14
- window.$docsify = {
15
- name: '',
16
- repo: ''
17
- }
18
- </script>
19
- <!-- Docsify v4 -->
20
- <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
21
- </body>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
+ <meta name="description" content="Documentation powered by pict-docuserve">
8
+
9
+ <title>Documentation</title>
10
+
11
+ <!-- Application Stylesheet -->
12
+ <link href="css/docuserve.css" rel="stylesheet">
13
+ <!-- KaTeX stylesheet for LaTeX equation rendering -->
14
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
15
+ <!-- PICT Dynamic View CSS Container -->
16
+ <style id="PICT-CSS"></style>
17
+
18
+ <!-- Load the PICT library from jsDelivr CDN -->
19
+ <script src="https://cdn.jsdelivr.net/npm/pict@1/dist/pict.min.js" type="text/javascript"></script>
20
+ <!-- Bootstrap the Application -->
21
+ <script type="text/javascript">
22
+ //<![CDATA[
23
+ Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(PictDocuserve, 2)});
24
+ //]]>
25
+ </script>
26
+ </head>
27
+ <body>
28
+ <!-- The root container for the Pict application -->
29
+ <div id="Docuserve-Application-Container"></div>
30
+
31
+ <!-- Mermaid diagram rendering -->
32
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
33
+ <script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
34
+ <!-- KaTeX for LaTeX equation rendering -->
35
+ <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
36
+ <!-- Load the Docuserve PICT Application Bundle from jsDelivr CDN -->
37
+ <script src="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/pict-docuserve.min.js" type="text/javascript"></script>
38
+ </body>
22
39
  </html>
@@ -0,0 +1,109 @@
1
+ # Integration Adapter
2
+
3
+ The Integration Adapter is the bridge between comprehension data and a running Meadow REST API. It handles record marshaling, GUID generation, schema validation, batch operations, and retry logic.
4
+
5
+ ## Overview
6
+
7
+ ```
8
+ Source Records (from comprehension or external system)
9
+ |
10
+ v
11
+ addSourceRecord()
12
+ |
13
+ v
14
+ marshalRecord() -- map external GUIDs to Meadow GUIDs
15
+ -- validate against Meadow schema
16
+ -- truncate strings to schema limits
17
+ -- strip reserved fields (CreateDate, etc.)
18
+ |
19
+ v
20
+ pushRecordsToServer() -- single or bulk upsert
21
+ -- automatic retry on failure
22
+ |
23
+ v
24
+ GUIDMap updated -- Meadow IDs stored for cross-entity lookups
25
+ ```
26
+
27
+ ## GUID Marshaling
28
+
29
+ External system GUIDs are transformed into deterministic Meadow GUIDs using this pattern:
30
+
31
+ ```
32
+ {AdapterSetGUIDMarshalPrefix}-{EntityGUIDMarshalPrefix}-{ExternalGUID}
33
+ ```
34
+
35
+ For example, with default settings and entity "Book":
36
+
37
+ ```
38
+ External GUID: "12345"
39
+ Meadow GUID: "INTG-DEF-E-Book-12345"
40
+ ```
41
+
42
+ This ensures GUIDs are unique across integration sets and entities.
43
+
44
+ ### Cross-Entity GUID Resolution
45
+
46
+ When a source record contains GUID fields for other entities (e.g. `GUIDAuthor` on a BookAuthorJoin record), the adapter looks up the corresponding Meadow ID via the GUIDMap:
47
+
48
+ ```javascript
49
+ // Source record: { GUIDBookAuthorJoin: "BAJ_1", GUIDBook: "Book_1", GUIDAuthor: "Author_5" }
50
+ // Adapter marshals:
51
+ // - GUIDBookAuthorJoin -> "INTG-DEF-E-BookAuthorJoin-BAJ_1"
52
+ // - GUIDBook -> looks up Meadow ID for external GUID "Book_1" -> IDBook: 42
53
+ // - GUIDAuthor -> looks up Meadow ID for external GUID "Author_5" -> IDAuthor: 17
54
+ ```
55
+
56
+ This is why entity integration order matters -- entities that are referenced by other entities should be integrated first so their IDs are available in the GUIDMap.
57
+
58
+ ## Batch Processing
59
+
60
+ The adapter automatically switches between single and bulk upsert modes:
61
+
62
+ - **Below threshold** (`< RecordThresholdForBulkUpsert`, default 1000): Records are upserted one at a time
63
+ - **Above threshold**: Records are batched into groups of `BulkUpsertBatchSize` (default 100) and sent as bulk upserts
64
+
65
+ ## Retry Logic
66
+
67
+ Failed upsert operations are retried up to `RecordPushRetryThreshold` times (default 5), with a hard cap of 50 retries. The adapter validates server responses to confirm:
68
+
69
+ 1. The response contains the entity ID field
70
+ 2. The ID is a positive number
71
+ 3. The response GUID matches the sent GUID
72
+
73
+ If validation fails, the record is retried.
74
+
75
+ ## Schema Validation
76
+
77
+ When `integrateRecords()` is called, the adapter fetches the entity schema from the Meadow API (`GET /Entity/Schema`). During marshaling:
78
+
79
+ - String fields are truncated to their schema-defined `size`
80
+ - Non-string fields are passed through
81
+ - Unknown fields (not in schema) are dropped
82
+ - Reserved fields (`CreateDate`, `UpdateDate`, `Deleted`, `DeleteDate`) are always stripped
83
+
84
+ ## Delete Operations
85
+
86
+ Records with `Deleted: true` in the source are queued for deletion. The adapter looks up each record by GUID via the API, then issues a DELETE request using the Meadow ID.
87
+
88
+ ## CLI Usage
89
+
90
+ The `load_comprehension` command wraps the Integration Adapter for CLI use:
91
+
92
+ ```shell
93
+ npx meadow-integration load_comprehension ./my-comprehension.json \
94
+ -p "MY-PREFIX" \
95
+ -e "MY-ENTITY-PREFIX"
96
+ ```
97
+
98
+ This automatically creates adapters for every entity in the comprehension and processes them in sequence.
99
+
100
+ ## Static Helper
101
+
102
+ The `getAdapter()` static method provides a convenient way to get or create an adapter:
103
+
104
+ ```javascript
105
+ const libAdapter = require('meadow-integration/source/Meadow-Service-Integration-Adapter.js');
106
+
107
+ // Gets existing adapter for 'Book' or creates a new one
108
+ let tmpAdapter = libAdapter.getAdapter(myFable, 'Book', 'BK');
109
+ ```
@@ -0,0 +1,140 @@
1
+ # Mapping Files
2
+
3
+ Mapping files give you precise control over how source data columns become comprehension fields. They are JSON files that define the entity name, GUID generation template, and field-by-field mappings using Pict templates.
4
+
5
+ ## Basic Structure
6
+
7
+ ```json
8
+ {
9
+ "Entity": "Book",
10
+ "GUIDTemplate": "Book_{~D:Record.id~}",
11
+ "Mappings": {
12
+ "Title": "{~D:Record.title~}",
13
+ "Language": "{~D:Record.language_code~}",
14
+ "ISBN": "{~D:Record.isbn~}",
15
+ "Genre": "Unknown"
16
+ }
17
+ }
18
+ ```
19
+
20
+ ### Fields
21
+
22
+ | Field | Required | Description |
23
+ |-------|----------|-------------|
24
+ | `Entity` | Yes | The entity name. Determines the top-level key in the comprehension. |
25
+ | `GUIDTemplate` | Yes | Pict template that generates a unique GUID for each record. |
26
+ | `GUIDName` | No | Name of the GUID column (default: `GUID{Entity}`). |
27
+ | `Mappings` | Yes | Object mapping output field names to Pict template expressions. |
28
+ | `Solvers` | No | Array of fable expression strings to run before mapping. |
29
+ | `MultipleGUIDUniqueness` | No | When `true`, a single source row produces multiple output records. |
30
+ | `ManyfestAddresses` | No | When `true`, use Manyfest dot-notation for nested field assignment. |
31
+
32
+ ## Pict Template Syntax
33
+
34
+ Templates use the `{~D:...~}` syntax to reference values from the current source record. Each record is available as `Record.<column>`.
35
+
36
+ | Template | Description |
37
+ |----------|-------------|
38
+ | `{~D:Record.title~}` | Direct column reference |
39
+ | `{~D:Record.first~} {~D:Record.last~}` | String concatenation |
40
+ | `"Unknown"` | Static/literal value |
41
+ | `{~D:Fable.Math.roundPrecise(Record.year,0)~}` | Function call on the value |
42
+ | `{~PascalCaseIdentifier:Record.name~}` | Template with format modifier |
43
+
44
+ The full Pict template engine is available, including format modifiers and function calls through the Fable service container.
45
+
46
+ ## Example: Simple Column Mapping
47
+
48
+ Given a CSV with columns `id, name, email, age`:
49
+
50
+ ```json
51
+ {
52
+ "Entity": "User",
53
+ "GUIDTemplate": "User_{~D:Record.id~}",
54
+ "Mappings": {
55
+ "DisplayName": "{~D:Record.name~}",
56
+ "EmailAddress": "{~D:Record.email~}",
57
+ "Age": "{~D:Record.age~}"
58
+ }
59
+ }
60
+ ```
61
+
62
+ This produces records like:
63
+
64
+ ```json
65
+ {
66
+ "GUIDUser": "User_42",
67
+ "DisplayName": "Alice Smith",
68
+ "EmailAddress": "alice@example.com",
69
+ "Age": "30"
70
+ }
71
+ ```
72
+
73
+ ## Example: Computed GUID from Multiple Columns
74
+
75
+ ```json
76
+ {
77
+ "Entity": "Transaction",
78
+ "GUIDTemplate": "TXN_{~D:Record.date~}_{~D:Record.account_id~}_{~D:Record.seq~}",
79
+ "Mappings": {
80
+ "Amount": "{~D:Record.amount~}",
81
+ "AccountID": "{~D:Record.account_id~}",
82
+ "TransactionDate": "{~D:Record.date~}"
83
+ }
84
+ }
85
+ ```
86
+
87
+ Composite GUIDs are useful when the source data has no single unique key.
88
+
89
+ ## Example: Multi-Record Generation with Solvers
90
+
91
+ When a single source row needs to produce multiple comprehension records, use `MultipleGUIDUniqueness` with a Solver expression that splits a value.
92
+
93
+ Given a books CSV where the `authors` column contains comma-separated names:
94
+
95
+ ```json
96
+ {
97
+ "Entity": "Author",
98
+ "MultipleGUIDUniqueness": true,
99
+ "Solvers": [
100
+ "NewRecordsGUIDUniqueness = STRINGGETSEGMENTS(IncomingRecord.authors,\",\")"
101
+ ],
102
+ "GUIDTemplate": "Author_{~PascalCaseIdentifier:Record._GUIDUniqueness~}",
103
+ "Mappings": {
104
+ "Name": "{~D:Record._GUIDUniqueness~}"
105
+ }
106
+ }
107
+ ```
108
+
109
+ The Solver splits the comma-separated author names into an array stored in `NewRecordsGUIDUniqueness`. For each entry, a record is created with `_GUIDUniqueness` set to that entry's value.
110
+
111
+ ## Example: Join Table Mapping
112
+
113
+ To create many-to-many join records between Books and Authors:
114
+
115
+ ```json
116
+ {
117
+ "Entity": "BookAuthorJoin",
118
+ "MultipleGUIDUniqueness": true,
119
+ "Solvers": [
120
+ "NewRecordsGUIDUniqueness = STRINGGETSEGMENTS(IncomingRecord.authors,\",\")"
121
+ ],
122
+ "GUIDTemplate": "BAJ_A_{~PascalCaseIdentifier:Record._GUIDUniqueness~}_B_{~D:Record.id~}",
123
+ "Mappings": {
124
+ "GUIDBook": "Book_{~D:Record.id~}",
125
+ "GUIDAuthor": "Author_{~PascalCaseIdentifier:Record._GUIDUniqueness~}"
126
+ }
127
+ }
128
+ ```
129
+
130
+ This generates one join record per book-author pair, with cross-reference GUIDs that match the Book and Author entities.
131
+
132
+ ## Configuration Priority
133
+
134
+ When running a transform, three layers of configuration are merged:
135
+
136
+ 1. **Implicit** -- Auto-detected from the first record's columns (entity name from filename, 1:1 column mappings)
137
+ 2. **Explicit** -- Loaded from a mapping file via `-m`
138
+ 3. **User** -- Command-line options (`-e`, `-n`, `-g`, `-c`)
139
+
140
+ Each layer overrides the previous, so CLI options always win.