Skip to content

TML-2986: postgres native types as bare PSL scalar types; Json→pg/json, new Jsonb#975

Open
SevInf wants to merge 26 commits into
remove-db-attributes-from-pslfrom
tml-2986-native-types-as-scalars
Open

TML-2986: postgres native types as bare PSL scalar types; Json→pg/json, new Jsonb#975
SevInf wants to merge 26 commits into
remove-db-attributes-from-pslfrom
tml-2986-native-types-as-scalars

Conversation

@SevInf

@SevInf SevInf commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

At a glance

The eleven former @db.* native types become first-class bare PSL scalar types on the postgres target — Uuid, SmallInt, Real, Date, VarChar(191), Char(12), Numeric(10,2), Timestamp(3), Timestamptz(6), Time(3), Timetz(2) — authorable in named-type declarations and directly in field position. JSON executes its settled re-binding: Json now means native json (pg/json@1); new Jsonb carries pg/jsonb@1 (previously bare Json meant jsonb). @db.* continues to work untouched — its removal is slice 4, after slice 3 migrates consumers.

Slice 2 of 4 of the remove-db-attributes project (spec: projects/remove-db-attributes/spec.md).

The decisions

Bare T is sugar for T(). The bare-name criterion broadened from "declares zero args" to "instantiable with an empty argument list": bare resolution is zero-arg instantiation — one resolution path, no duplicated template logic. VarChar sans parens works exactly as @db.VarChar did; constructors with required args or entity refs stay bare-ineligible with the existing diagnostic.

The symbol table no longer knows scalar names (operator-gated simplification — landed). buildSymbolTable's scalarTypes input and the isScalarBinding ScalarSymbol/TypeAliasSymbol split are gone: types {} declarations collect into one namedType symbol kind, and the interpreter (which always re-classified authoritatively) is the single classification authority. LSP presentation re-derives the distinction at query time; its tests pass unweakened. The parser layer is now family-blind — the framework-vocabulary ratchet tightened from 840 to 837.

Native types are adapter contributions with parity proven against the live oracle. The eleven types live beside the base scalars in the postgres adapter's authoring contributions, with declarative optional args (omitted args omit typeParams keys, matching @db.* exactly — including Numeric's precision ≥ 1 rule). Parity tests emit each type through both the bare path and the live @db.* path in the same run and require deep-equality — a drift on either side fails.

JSON re-bind with byte-stable legacy. @db.Json still resolves identically (NATIVE_TYPE_SPECS untouched); value-object storage explicitly prefers Jsonb so composite-type columns stay jsonb; TS↔PSL parity pairs field.json() (jsonb, unchanged — TS surface is a project non-goal) with PSL Jsonb. sqlite/mongo Json bindings are pinned untouched.

Consumer impact

Upgrade entry postgres-json-rebound-to-native-json added to both upgrade-skill clusters (upgrades/0.14-to-0.15/): postgres schemas using Json for jsonb storage switch to Jsonb and re-emit.

Verification

Parity suite (21 table-driven cases × 3 assertions), bare-vs-call equivalence tests, invalid-arg diagnostics, @db.Json byte-stability, per-target JSON-binding pins. pnpm typecheck, test:packages, fixtures:check (zero drift), lint:deps, framework-vocabulary (837/837), check:upgrade-coverage — green. Known environmental exceptions on the dev host only: mongodb-memory-server NixOS bootstrap failures and two 500ms CLI cold-start flakes, both pre-existing.

Refs: TML-2986

SevInf added 9 commits July 14, 2026 12:20
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…o-arg instantiability

A top-level type constructor is now bare-eligible when it is instantiable
with an empty argument list (all args optional, no entityRefArg, output
template resolvable with no args), and the projection entry is exactly
the zero-arg instantiation output — one resolution path for T and T().
The named-type bare-base path now threads the base descriptor typeParams
through instead of dropping them, so bare T and T() emit identical
storage in both syntactic positions.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…namedTypes symbol kind

The ScalarSymbol/TypeAliasSymbol split was a pre-classification the
interpreter re-derives authoritatively; no consumer needed it from the
symbol table. types {} bindings now collect into a single namedTypes
record (kind: namedType) and the parser layer stays family-blind.

The LSP, the only surface that showed the distinction, re-derives it at
query time from the binding baseType/isConstructor and the control
stack scalarTypes it already holds (named-type-classification.ts); its
semantic-token and completion tests pass unweakened. The SQL
interpreter resolves scalar-refinement bindings ahead of alias and
constructor bindings, keeping emitted artifacts byte-identical to the
order the retired split induced.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…e constructors (postgres)

The postgres adapter now contributes VarChar, Char, Numeric, Timestamp,
Timestamptz, Time, Timetz, Uuid, SmallInt, Real, and Date as top-level
type-constructor descriptors (postgresNativeAuthoringTypes, merged with
the base scalars into postgresAuthoringTypes on the adapter descriptor).
Parameterized constructors declare optional integer args whose typeParams
keys materialize only when the argument is given, mirroring the legacy
@db.* attribute path (NATIVE_TYPE_SPECS) exactly; Date pins the explicit
{ codecId: pg/timestamptz@1, nativeType: date } pair.

Parity is proven live-vs-live: native-type-parity.test.ts emits each
form through both the bare-type path and the @db.* path in the same run
and deep-equals the storage shapes, for all eleven types, in both
named-type and field position, arg-present and arg-omitted (incl. the
Numeric(10) one-arg form), plus declarative-machinery rejection of
out-of-range/non-integer/excess arguments.

Note: per the slice spec table, Numeric precision has minimum 0 while
the legacy @db.Numeric path rejected precision < 1 — flagged in the
dispatch report.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
… (>= 1)

The spec table's "precision >= 0" was a transcription error; the parity
oracle is the law: the legacy @db.Numeric path rejects precision < 1
("positive integer precision"). Raise the declarative minimum to 1 and
prove Numeric(0) is rejected in both named-type and field position.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…ng pg/jsonb@1

The Json scalar contribution on the postgres adapter now means native json;
the new bare Jsonb scalar carries the former pg/jsonb@1 binding. PSL
value-object storage columns keep jsonb by preferring the target Jsonb
scalar with a Json fallback (sqlite unchanged). The legacy @db.Json path
(NATIVE_TYPE_SPECS) is untouched and byte-stable; sqlite/mongo Json
bindings and the TS builder surface (field.json(), jsonbColumn) are
unchanged. In-repo postgres schemas meaning jsonb migrate to Jsonb;
upgrade-instruction entries recorded in both skill clusters
(postgres-json-rebound-to-native-json).

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
… trace ledger

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…-as-scalars

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…peDescriptors channel

Main brought the lsp-interpret slice still referencing the deleted
scalarTypeDescriptors context field. The interpretation context flows
verbatim into provider interpret(), which now derives scalar types from
authoringContributions.type itself, so the field is simply dropped:

- config-resolution.ts: remove scalarTypeDescriptors from the assembled
  ContractSourceContext (unified channel rides along as
  authoringContributions)
- config-resolution.test.ts: stub contributes Int via a zero-arg type
  constructor in authoringContributions.type and exposes scalarTypes;
  assertions follow

Also tighten the framework-vocabulary ratchet 840 → 837 to lock in the
symbol-table simplification reduction.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
@SevInf
SevInf requested a review from a team as a code owner July 14, 2026 17:04
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: ced1516a-f6db-4b38-a8eb-5cb2c62cfbec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2986-native-types-as-scalars

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@975

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@975

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@975

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@975

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@975

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@975

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@975

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@975

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@975

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@975

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@975

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@975

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@975

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@975

@prisma-next/extension-supabase

npm i https://pkg.pr.new/@prisma-next/extension-supabase@975

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@975

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@975

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@975

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@975

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@975

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@975

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@975

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@975

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@975

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@975

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@975

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@975

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@975

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@975

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@975

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@975

@prisma-next/config-loader

npm i https://pkg.pr.new/@prisma-next/config-loader@975

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@975

@prisma-next/language-server

npm i https://pkg.pr.new/@prisma-next/language-server@975

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@975

prisma-next

npm i https://pkg.pr.new/prisma-next@975

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@975

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@975

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@975

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@975

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@975

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@975

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@975

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@975

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@975

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@975

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@975

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@975

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@975

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@975

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@975

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@975

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@975

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@975

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@975

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@975

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@975

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@975

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@975

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@975

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@975

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@975

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@975

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@975

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@975

commit: d08dfac

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 158.95 KB (0%)
postgres / emit 132.47 KB (+0.01% 🔺)
mongo / no-emit 98.7 KB (0%)
mongo / emit 89.43 KB (0%)
cf-worker / no-emit 185.14 KB (-0.01% 🔽)
cf-worker / emit 155.9 KB (-0.01% 🔽)

SevInf added 15 commits July 15, 2026 15:30
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…nto tml-2986-native-types-as-scalars

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…rs dialect

Main brought ts-psl-rls-parity.test.ts speaking the deleted channel.
Mirror the already-migrated sibling ts-psl-parity.real-packs.test.ts:

- derive descriptors via collectScalarTypeConstructors(
  stack.authoringContributions.type) instead of reading
  stack.scalarTypeDescriptors + codec-lookup joins
- drop the retired scalarTypes option from buildSymbolTable
- pass the interpreter input under its current name,
  scalarColumnDescriptors

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…age (QA F-1)

`id Uuid @id @default(uuid())` silently emitted sql/char@1/char(36):
the generator-default lowering let resolveGeneratedColumnDescriptor
replace the field descriptor unless the field used a named type — an
exemption built when named types were the only explicit-storage
spelling. Bare native scalars (Uuid) and constructor calls (Char(36))
fell through it.

Provenance now rides on the type descriptor: adapters mark family base
scalars (String, Int, …) with `baseScalar: true`, meaning the storage
is the target default choice rather than a user opinion.
collectScalarTypeConstructors propagates the marker onto the scalar
view, resolveFieldTypeDescriptor reports it for bare and zero-arg call
forms alike (T ≡ T()), and the override applies only to base-scalar
resolutions. Named types, enums, native scalars, presets, and
entity-ref constructors always keep their declared storage; the legacy
convenience (String @default(uuid()) → char(36)) is byte-identical.

The marker never reaches emitted contracts: storage columns are built
by picking named descriptor fields.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…et at 837

The baseScalar marker docstring said the generator "may re-pick a
column's concrete storage" — "column" is family vocabulary counted by
lint-framework-vocabulary, pushing the framework scope to 838 > 837.
"field's concrete storage" says the same thing in framework terms; no
threshold bump needed.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…tates storage

The type position is the only storage decider (operator-decided 2026-07-15).
Retired wholesale: generatedColumnDescriptor/resolveGeneratedColumnDescriptor
in @prisma-next/ids and MutationDefaultGeneratorDescriptor, the override block
in psl-field-resolution.ts, and the transitional baseScalar marker (framework
authoring descriptor, scalar view, ColumnDescriptor, adapter contributions).

New semantics pinned: String @default(uuid()) emits the target String storage
(pg: text) plus the uuidv4 execution default; nanoid/cuid on String stay text;
named type TId = String + generator stays text; Uuid @default(uuid()) keeps
pg/uuid@1 by construction; a generator on an inapplicable codec still
diagnoses PSL_INVALID_DEFAULT_APPLICABILITY (applicableCodecIds validation
survives — it validates, it does not mutate). TS field presets are untouched
and keep bundling char(N) explicitly.

TS↔PSL parity fixtures re-pair preset spellings with explicit Char(N) on the
PSL side; examples with committed char(36) artifacts re-author to Char(36)
(byte-stable contracts and migration chains); the cloudflare-worker example
regenerates to text (no committed DDL depends on its storage). Upgrade entry
default-generators-no-longer-set-storage recorded in both 0.14-to-0.15
clusters.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…-as-scalars

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>

# Conflicts:
#	examples/prisma-next-cloudflare-worker/src/prisma/contract.d.ts
#	examples/prisma-next-cloudflare-worker/src/prisma/contract.json
…facts, relocate upgrade entries to 0.15-to-0.16

The origin/main merge took main's side of the cloudflare-worker contract
artifacts (char(36) ids); the example's schema is still String-typed with
generator defaults, so under the retired storage override they re-emit with
text storage (8 columns sql/char@1 -> pg/text@1, storage hash updated).

v0.15.0 shipped without this project's changes, so the three entries the
project had authored into upgrades/0.14-to-0.15 (scalar-type-descriptors-
channel-removed, postgres-json-rebound-to-native-json, default-generators-
no-longer-set-storage) describe 0.15 -> 0.16 work. Both 0.14-to-0.15
instructions.md files reset to origin/main (shipped content only); the three
entries move into both clusters' existing 0.15-to-0.16 files with their
version references advanced (pre-0.15/from-0.15 -> pre-0.16/from-0.16).

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
The v0.15.0 merge brought the expanded Supabase auth contract, authored
before this branch re-bound postgres Json to pg/json@1. Its 18 bare Json
fields mirror real Supabase jsonb columns, so they re-author to Jsonb per
the slice edge-case rule; the committed contract.json/d.ts re-emit
byte-identical (36 pg/jsonb@1 entries unchanged). The Payload named type
keeps Json @db.Json — that column really is json.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…race

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…es-as-scalars

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
if (typeof nativeType !== 'string') continue;
result.set(name, { codecId: value.output.codecId, nativeType });
if (value.args?.some((arg) => arg.optional !== true)) continue;
try {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this try catch? We already checked for optional arguments before, this should be enough

*/
const CHAR_COLUMN_TYPE = { codecId: 'sql/char@1', nativeType: 'character' } as const;

const specCharLengthById: Record<Exclude<BuiltinGeneratorId, 'nanoid'>, number> = {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we remove this out of generated column descriptor? It is possible to remove storage type change magic from PSL while keeping TS surface consistent.

descriptor = scalarColumnDescriptors.get('Json');
// Value objects store in the richest JSON storage the target contributes
// (postgres: Jsonb -> jsonb); targets without a Jsonb scalar fall back to Json.
descriptor = scalarColumnDescriptors.get('Jsonb') ?? scalarColumnDescriptors.get('Json');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad robot! This leaks postgres-specific detail all the way down to authoring layer.
This should be handled by postgres/sqlite targets, not authoring layer.

SevInf added 2 commits July 20, 2026 15:58
Finding 1 — collectScalarTypeConstructors: replace the try/catch control
flow with a declarative bare-eligibility check. The only residual throw
after the all-optional-args and entityRefArg guards was a nativeType
template that does not resolve without arguments (missing template or
arg-ref with no default); resolve it explicitly with the existing
resolveAuthoringTemplateValue machinery and exclude non-string results.
Instantiation can no longer fail for an eligible constructor.

Finding 2 — @prisma-next/ids: restore the generator metadata as the
single source of the storage each TS spec helper bundles. Each entry in
builtinGeneratorMetadataById now carries a generatedStorage resolver
(char length per generator id, nanoid size resolution), consumed by
createGeneratedSpec; the CHAR_COLUMN_TYPE/specCharLengthById/
specCharLength shadow table is merged into it. Named generatedStorage
(rather than generatedColumnDescriptor) to keep the framework scope
family-blind; the PSL interpreter still never consults it (no
production import from contract-psl). Framework-vocabulary count drops
837->810->808; threshold locked at 808.

Finding 3 — value-object storage: the family layer no longer hardcodes
Jsonb/Json type names. Targets declare their value-object storage type
via a valueObjectStorage marker on the contributed type constructor
(postgres: Jsonb, sqlite: Json); the new framework helper
findValueObjectStorageTypeName reads the single marked top-level
constructor generically (throws on ambiguity), and psl-field-resolution
looks the declared name up in the derived scalar map. A target that
declares none skips value-object fields, preserving the pre-existing
no-storage behavior. Pinned by tests: postgres value objects still emit
pg/jsonb@1 (fixtures byte-stable), sqlite value objects store as
sqlite/json@1 text, unmarked contributions skip the field even when
Jsonb is present in the scalar map.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Round-2 operator correction on PR #975 finding 3: replace the per-
descriptor valueObjectStorage boolean marker with a single named
property on the contributing component descriptor -
authoring.valueObjectStorageType (postgres adapter declares Jsonb,
sqlite declares Json). One slot per component makes within-component
ambiguity impossible by shape: no namespace scan, no two-marks error
path.

The property rides through assembleAuthoringContributions like other
component metadata: assembly rejects two components both declaring it
with the existing contributor-attribution error style (naming both
descriptors), and one validation replaces the scan - the declared name
must exist as a top-level bare-eligible constructor in the assembled
namespace (error naming the type and the declaring component). The
assembled single value lands on AssembledAuthoringContributions and
flows to the family interpreter through the existing context; psl-
field-resolution reads it directly.

findValueObjectStorageTypeName and the descriptor-level marker are
deleted - no dual mechanism. Field resolution behavior is unchanged:
postgres value objects still emit pg/jsonb@1 (fixtures byte-stable),
sqlite value objects store as sqlite/json@1 text, and a stack that
declares no value-object storage skips the field, all pinned by the
reshaped tests. Framework-vocabulary count stays at 808.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant