Commit 4d8ab61
authored
TML-2952: type SQL enum columns through the codec instead of printing their stored values (#896)
An enum column/field's TypeScript type is the union of its allowed
values (`'low' | 'high' | 'urgent'`). Today that union is built by
printing the stored, codec-encoded values straight to TS literals in two
separate emit-path spots — which **bypasses the codec**, the one
component that knows a stored value's real TypeScript type. It's correct
only by coincidence: today's enums use text/int codecs where the encoded
form happens to equal the output type. This routes emit typing through
the codec, on one path, and removes the duplication. SQL only; Mongo is
the sibling
[TML-2953](https://linear.app/prisma-company/issue/TML-2953).
No user-visible change for today's enums — correctness + de-duplication.
## What changed
- **New codec seam.** `renderValueType(encodedValue, channel)` on
`CodecDescriptor` and `renderValueTypeFor` on `CodecLookup` — the
value-keyed counterpart of the existing `renderOutputType`. It renders a
single codec-encoded value as its TS output literal, or `undefined` when
the codec can't (e.g. a `Date`-output codec — no base-class default, so
non-identity codecs opt out). Implemented for the Postgres and Mongo
primitive codecs.
- **SQL column emit** now renders each value-set value through the codec
via a shared `renderValueSetType` helper, instead of printing the stored
values directly (`renderValueSetUnionBase`/`renderValueSetLiteral`
deleted).
- **Framework field emit** no longer special-cases enums. The hardcoded
domain-enum override (`DomainEnumLookup`, `renderEnumValueUnion`,
`renderEnumMemberLiteral`) is deleted; a new **family-supplied**
`EmissionSpi.resolveFieldValueSet` hook supplies a field's permitted
values, rendered through the same codec helper. The domain `enum` is no
longer a typing input — it keeps only the runtime `db.enums` dictionary.
## Keeping Mongo byte-identical (the one design call worth flagging)
`FieldOutputTypes` is generated once for **both** families, and the
framework emitter must not read `storage`. So deleting the shared
override bare would regress Mongo's emitted enum fields (the demo `role:
'admin' | 'author' | 'reader'` would widen to `string`). The resolver
hook resolves this cleanly:
- **SQL** sources permitted values from the **storage value set** (field
→ column → value set) — the domain enum stops being a SQL typing input.
- **Mongo** supplies an **interim** resolver reading `domain.enum` (it
has no value-set entity yet), keeping its output byte-identical. This is
removed by **TML-2953**, which brings Mongo onto the value-set model.
So the acceptance criterion "domain enum is not a typing input" holds
for SQL now, and repo-wide once TML-2953 lands.
The no-emit (`typeof contract`) path is unchanged — it already
propagated the authored, typed values, and is the reference the emit
path now matches.
## Acceptance evidence
- **A1** — every emit-path enum type goes through the codec; a
structural guard keeps the deleted direct-render helpers gone.
- **A2** — the guard pins the only domain-enum *typing* readers to the
`db.enums` dictionary block and the Mongo interim resolver; the SQL
emitter reads none.
- **A4** — byte-identical for identity codecs, **both families**: empty
`contract.json` diff, `fixtures:check` clean, the mongo-demo
`contract.d.ts`/`.json` git-unchanged across every commit.
- **A5** — a non-identity test codec (encodes `0|1|2`, outputs
`'low'|'high'|'urgent'`) types as the codec **output**, not the raw
encoded literal — on both the column and field surfaces.
- **A6** — the emitted field type equals the no-emit `typeof contract`
union.
- **A7** — no new casts (`lint:casts` delta 0), `lint:deps` clean;
build, typecheck, and the full test suites
(`packages`/`integration`/`e2e`) green.
## Notes
- Shaping artifacts (spec + dispatch plan) live under
`projects/refactor-enum-typing-via-codec/`. The spec was corrected
during shaping: the family-resolver design (the framework must not reach
into storage) and the SQL-scoping of A2.
- The change is additive at the framework layer (the new SPI hook is
optional), so no downstream extension needed updating; one Mongo *test*
harness updated its mock lookup to mirror production.
- Verified on `main` including #880 (Mongo enums in retail-store), which
re-emits byte-identically under this change.
## Upgrade instructions (0.14 → 0.15)
-
`skills/extension-author/prisma-next-extension-upgrade/upgrades/0.14-to-0.15/`
— a real entry: an extension that types a value-set-restricted (enum)
column via a custom `CodecDescriptorImpl` must implement
`renderValueLiteral` (and expose `renderValueLiteralFor` on a hand-built
`CodecLookup`), or the column widens to the codec output type.
Framework-built lookups already supply it. Validated by execution
(reverting `packages/3-extensions/` reddens the mongo enum e2e;
re-applying reproduces the branch, tests green).
- `skills/upgrade/prisma-next-upgrade/upgrades/0.14-to-0.15/` — user
side is incidental (`changes: []`); the only `examples/` touch is a type
test and the emitted contract is byte-identical.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Value-restricted fields now emit more precise literal unions instead
of broad `string` types.
* Type generation now uses codec-based literal rendering across
supported databases, improving output for enums and similar restricted
values.
* **Bug Fixes**
* Fixed cases where restricted field types could fall back to overly
generic types.
* Improved handling for non-identity codecs so emitted types stay
aligned with stored values.
* **Tests**
* Added coverage for literal rendering, value-set narrowing, and
fallback behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>1 parent 3a34e7c commit 4d8ab61
25 files changed
Lines changed: 1006 additions & 168 deletions
File tree
- examples/prisma-next-demo/test
- packages
- 1-framework
- 1-core/framework-components
- src
- control
- exports
- test
- 3-tooling/emitter
- src
- test
- 2-mongo-family/3-tooling/emitter/src
- 2-sql/3-tooling/emitter
- src
- test
- 3-extensions/mongo/test
- 3-mongo-target/2-mongo-adapter/src/core
- 3-targets/3-targets/postgres
- src/core
- test
- projects/refactor-enum-typing-via-codec
- skills
- extension-author/prisma-next-extension-upgrade/upgrades/0.14-to-0.15
- upgrade/prisma-next-upgrade/upgrades/0.14-to-0.15
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
49 | 59 | | |
50 | 60 | | |
51 | 61 | | |
| |||
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
1 | 2 | | |
2 | 3 | | |
3 | 4 | | |
| |||
310 | 311 | | |
311 | 312 | | |
312 | 313 | | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
313 | 318 | | |
314 | 319 | | |
315 | 320 | | |
| |||
337 | 342 | | |
338 | 343 | | |
339 | 344 | | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
340 | 348 | | |
341 | 349 | | |
342 | 350 | | |
| |||
376 | 384 | | |
377 | 385 | | |
378 | 386 | | |
| 387 | + | |
379 | 388 | | |
380 | 389 | | |
381 | 390 | | |
| |||
Lines changed: 14 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
36 | 49 | | |
37 | 50 | | |
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| 30 | + | |
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| |||
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
45 | 46 | | |
46 | 47 | | |
47 | 48 | | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
48 | 60 | | |
49 | 61 | | |
50 | 62 | | |
| |||
83 | 95 | | |
84 | 96 | | |
85 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
86 | 101 | | |
87 | 102 | | |
88 | 103 | | |
| |||
Lines changed: 6 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
54 | 60 | | |
55 | 61 | | |
56 | 62 | | |
| |||
Lines changed: 31 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
Lines changed: 27 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
730 | 730 | | |
731 | 731 | | |
732 | 732 | | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
733 | 760 | | |
734 | 761 | | |
735 | 762 | | |
| |||
Lines changed: 57 additions & 27 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | 2 | | |
4 | 3 | | |
5 | 4 | | |
6 | 5 | | |
7 | 6 | | |
8 | 7 | | |
9 | | - | |
10 | 8 | | |
11 | 9 | | |
12 | 10 | | |
| |||
291 | 289 | | |
292 | 290 | | |
293 | 291 | | |
294 | | - | |
295 | | - | |
296 | | - | |
297 | | - | |
298 | | - | |
299 | | - | |
300 | | - | |
301 | | - | |
302 | | - | |
303 | | - | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
304 | 325 | | |
305 | 326 | | |
306 | | - | |
307 | | - | |
| 327 | + | |
| 328 | + | |
308 | 329 | | |
309 | 330 | | |
310 | 331 | | |
| |||
314 | 335 | | |
315 | 336 | | |
316 | 337 | | |
317 | | - | |
| 338 | + | |
318 | 339 | | |
319 | 340 | | |
320 | 341 | | |
321 | 342 | | |
322 | 343 | | |
323 | | - | |
324 | | - | |
325 | | - | |
326 | | - | |
327 | | - | |
328 | | - | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
329 | 358 | | |
330 | | - | |
331 | | - | |
| 359 | + | |
| 360 | + | |
332 | 361 | | |
333 | 362 | | |
334 | 363 | | |
| |||
394 | 423 | | |
395 | 424 | | |
396 | 425 | | |
397 | | - | |
| 426 | + | |
398 | 427 | | |
399 | 428 | | |
400 | 429 | | |
| |||
415 | 444 | | |
416 | 445 | | |
417 | 446 | | |
418 | | - | |
| 447 | + | |
| 448 | + | |
419 | 449 | | |
420 | 450 | | |
421 | 451 | | |
| |||
443 | 473 | | |
444 | 474 | | |
445 | 475 | | |
446 | | - | |
| 476 | + | |
447 | 477 | | |
448 | 478 | | |
449 | 479 | | |
| |||
456 | 486 | | |
457 | 487 | | |
458 | 488 | | |
459 | | - | |
| 489 | + | |
460 | 490 | | |
461 | 491 | | |
462 | 492 | | |
| |||
Lines changed: 5 additions & 13 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | 6 | | |
8 | 7 | | |
9 | 8 | | |
| |||
14 | 13 | | |
15 | 14 | | |
16 | 15 | | |
17 | | - | |
18 | 16 | | |
19 | 17 | | |
20 | 18 | | |
| |||
152 | 150 | | |
153 | 151 | | |
154 | 152 | | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
165 | 157 | | |
166 | 158 | | |
167 | 159 | | |
| |||
171 | 163 | | |
172 | 164 | | |
173 | 165 | | |
174 | | - | |
| 166 | + | |
175 | 167 | | |
176 | 168 | | |
177 | 169 | | |
| |||
0 commit comments