Repository navigation
Commit f123f75
fix(rest): keep a nullValues sentinel blank through an inline case transform (#25646)
Fixes #25611
Clause-②: no
Metadata-protocol: none
## What
`applyInlineEntryRules` (`packages/rest/src/import-prepare.ts`) ran an
inline entry's `transform` on a string cell first and the blank test
second. Core's `isBlank` matches a `nullValues` entry exactly (raw or
trimmed spelling), so `uppercase` / `lowercase` rewrote a sentinel out
of being one: with `nullValues: ['n/a']` and `transform: 'uppercase'`,
the cell `n/a` became `N/A` and was stored as a value, skipping the
entry's `defaultValue`, cell coercion's null handling, and `required`.
The fix judges blankness on the raw cell and transforms only a non-blank
string cell. A sentinel stays a sentinel through `defaultValue`,
`required` and cell coercion; a non-blank cell is transformed exactly as
before (including a cell whose transformed spelling matches a sentinel,
which is blank afterwards as it was before).
`packages/core/src/utils/import-coerce.ts` is untouched: `isBlank` keeps
its exact-match semantics for every import door.
## Proof
Six new pins in `packages/rest/src/import-inline-mapping-entry.test.ts`,
through the real `POST /api/v1/data/:object/import` route handler on
sqlite `:memory:`, for `uppercase` (sentinel `n/a`) and `lowercase`
(sentinel `N/A`):
- the sentinel cell is stored unset (`null`), and a non-sentinel cell in
the same request is still transformed (`Jp` to `JP` / `jp`) — the
control;
- with `defaultValue`, the sentinel cell takes the default;
- with `required: true`, the request is refused `400`
`MISSING_REQUIRED_FIELD` and nothing is written.
- Before the fix (test commit `a5c8099acc`): `Tests 6 failed | 8 passed
(14)`, e.g. `expected 'N/A' to be null`, `expected 'n/a' to be
'cn-default'`, `expected undefined to be 400`.
- After the fix (`a0b29be00d`): `Test Files 1 passed (1)`, `Tests 14
passed (14)`; the eight existing cases stay green.
- Ablation (on `a0b29be00d`, via `scripts/ablation-replace.mjs`, anchor
1 to 0, blob `56b834253a13` to `a7b8d42cf5e5`): old order restored,
`Tests 6 failed | 8 passed (14)`; restored by `git checkout HEAD`, blob
back to `56b834253a1304b3b88231bb4b191009fca22a75` = HEAD blob, `git
diff HEAD` empty. The suite imports `./rest-server` from source, so no
`dist/` leg applies.
- `pnpm --filter @objectstack/rest test` on `a0b29be00d`: `Test Files
320 passed (320)`, `Tests 6406 passed | 326 skipped`; `pnpm --filter
@objectstack/rest typecheck`: exit 0; eslint on both touched files: exit
0.
- `dispatch-gates --commands` on `a0b29be00d`: 68 commands run, 67 exit
0; `pnpm check:dual-build-cjs-loads` exit 3 `PREREQUISITE NOT MET` (it
needs a whole-workspace `dist/`, only the rest closure was built) — NOT
MEASURED locally, left to CI's `Lint & Repo Gates`. `--ran`
reconciliation: 68 of 68 accounted for.
## Acceptance notes
- A whitespace-only cell under `transform: 'trim'` is now left as is
rather than trimmed to an empty string by the entry; both spellings are
blank to `isBlank` and to cell coercion, so the stored outcome is
unchanged.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JVTd3PprStGa26aez5omLB)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent f4860da commit f123f75
3 files changed
Lines changed: 78 additions & 2 deletions
File tree
- .changeset
- packages/rest/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
218 | 218 | | |
219 | 219 | | |
220 | 220 | | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
262 | 262 | | |
263 | 263 | | |
264 | 264 | | |
265 | | - | |
| 265 | + | |
266 | 266 | | |
267 | 267 | | |
268 | 268 | | |
| |||
278 | 278 | | |
279 | 279 | | |
280 | 280 | | |
281 | | - | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
282 | 286 | | |
283 | 287 | | |
284 | 288 | | |
| |||
0 commit comments