Skip to content

Commit 36a18af

Browse files
committed
docs(rest): name the third import door and the inline entry rules
The contract review on PR #25540 found two stale prose claims: the changeset named two of the three doors that parse through prepareImportRequest (plugin-auth's admin user import is the third), and the import-mappings page still called the inline form a rename only and did not list the two new whole-request refusals. The import-mapping.ts seam docblock is brought in line with the same rule. No code changes. Claude-Session: https://claude.ai/code/session_01CxBKycaiUpA1yGx1XyoGqX Co-authored-by: Claude <noreply@anthropic.com>
1 parent b5a3141 commit 36a18af

3 files changed

Lines changed: 10 additions & 6 deletions

File tree

‎.changeset/25491-import-inline-mapping-entry-rules.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
fix(rest)!: an inline import mapping entry's `transform`, `defaultValue` and `required` are applied, not dropped
66

7-
`POST /api/v1/data/:object/import` (and the async import job, which parses the same body) accepts `mapping` as a `FieldMappingEntry[]`, whose entries carry `transform`, `defaultValue` and `required`. The request parser kept only the column each entry names with `sourceField` and the field it names with `targetField` and dropped the rest, so a request asking for `transform: 'uppercase'` validated, ran, and stored the cell unchanged. Each entry's rules now run on its column before the cells are coerced:
7+
`POST /api/v1/data/:object/import`, the async import job and plugin-auth's admin user import (`POST /api/v1/auth/admin/import-users`) all parse their body through the same request parser, which accepts `mapping` as a `FieldMappingEntry[]`, whose entries carry `transform`, `defaultValue` and `required`. The request parser kept only the column each entry names with `sourceField` and the field it names with `targetField` and dropped the rest, so a request asking for `transform: 'uppercase'` validated, ran, and stored the cell unchanged. Each entry's rules now run on its column before the cells are coerced:
88

99
- `trim`, `uppercase` and `lowercase` rewrite a string cell. `none` and `lookup` copy it; a `lookup` cell is resolved to a record id by the import's reference resolution, as before.
1010
- `defaultValue` fills a cell that is blank (absent, empty, whitespace or one of the request's `nullValues`).
@@ -13,7 +13,7 @@ fix(rest)!: an inline import mapping entry's `transform`, `defaultValue` and `re
1313

1414
A plain `{ sourceField, targetField }` entry, and the compact `{ column: field }` record, map columns exactly as before.
1515

16-
Clause-②: no (narrowing) — the import doors refuse two request shapes they used to run: an inline mapping entry declaring `transform: 'date_format'` (or a transform name outside the declared set), and an entry marked `required: true` whose column a row leaves blank. Nothing is widened.
16+
Clause-②: no (narrowing) — the import doors (the sync import, the async import job and plugin-auth's admin user import) refuse two request shapes they used to run: an inline mapping entry declaring `transform: 'date_format'` (or a transform name outside the declared set), and an entry marked `required: true` whose column a row leaves blank. Nothing is widened.
1717

1818
Metadata-protocol: none (a REST import request's handling; nothing a metadata author writes changes)
1919

‎content/docs/data-modeling/import-mappings.mdx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ sending both is `400 CONFLICTING_MAPPING`.
198198
| | inline `mapping` | `mappingName` |
199199
|:---|:---|:---|
200200
| Shape | A flat `{ "<source column>": "<field>" }` rename (or a `sourceField`/`targetField` array) | A registered `mapping` artifact |
201-
| Transforms | None — rename only | The `fieldMapping` pipeline |
201+
| Transforms | Per entry of the array form: `transform` (`trim`, `uppercase`, `lowercase`; `none` and `lookup` copy the cell), `defaultValue` for a blank cell, `required`. The flat record is a rename only | The `fieldMapping` pipeline |
202202
| Unmapped columns | **Pass through** to the write path under their own header | **Dropped.** The artifact is a strict projection: only mapped targets survive |
203203
| Lives | In the one request | In a package or in metadata, reusable |
204204

@@ -218,7 +218,8 @@ These are whole-request failures — nothing is written, and there is no per-row
218218
| 400 | `MAPPING_TARGET_MISMATCH` | The artifact's `targetObject` is not the object in the URL. |
219219
| 400 | `MAPPING_FORMAT_UNSUPPORTED` | The artifact declares `sourceFormat: 'xml'` or `'sql'`; the endpoint accepts csv, json and xlsx payloads only. |
220220
| 400 | `MAPPING_FORMAT_MISMATCH` | The declared `sourceFormat` contradicts the payload actually sent. A `csv` mapping does apply to an `xlsx` payload — those rows are tabular in the same way — but a `json` mapping does not. |
221-
| 400 | `UNSUPPORTED_TRANSFORM` | Some entry declares `javascript`, or a transform name the pipeline does not implement. |
221+
| 400 | `UNSUPPORTED_TRANSFORM` | Some artifact entry declares `javascript`, or a transform name the pipeline does not implement; or an inline entry declares `date_format` (it carries no format to apply) or a name outside `none`, `lookup`, `trim`, `uppercase`, `lowercase`. |
222+
| 400 | `MISSING_REQUIRED_FIELD` | An inline entry is marked `required: true` and some row leaves its column blank after its `defaultValue`. The error names the column and the rows; it applies to the dry run and the commit alike. |
222223
| 400 | `CONFLICTING_MAPPING` | Both `mappingName` and an inline `mapping` were supplied. |
223224
| 400 | `INVALID_REQUEST` | No recognizable payload, or `writeMode` resolved to update/upsert with no `matchFields` from either the request or the artifact. |
224225
| 413 | `PAYLOAD_TOO_LARGE` | More than 5,000 rows on the synchronous route. |

‎packages/rest/src/import-mapping.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
* pipeline to parsed rows.
77
*
88
* Seam with the inline request `mapping`:
9-
* • inline = a plain `{ sourceColumn: targetField }` RENAME for one-off,
10-
* wizard-driven imports — unmapped columns pass through untouched.
9+
* • inline = a `{ sourceColumn: targetField }` rename (or a
10+
* `FieldMappingEntry[]` whose entries may add `transform`
11+
* trim/uppercase/lowercase, `defaultValue` and `required`, applied in
12+
* `import-prepare.ts`) for one-off, wizard-driven imports — unmapped
13+
* columns pass through untouched.
1114
* • artifact = a reusable, governed ETL projection for recurring /
1215
* programmatic imports — the output row contains ONLY the mapped
1316
* targets (a strict projection; source files from external systems

0 commit comments

Comments
 (0)