Skip to content

TML-3537: Changing a value object or a variant is a migration, and Postgres checks value object and discriminator columns - #30869

Open
wmadden-electric wants to merge 105 commits into
mainfrom
tml-3537-value-objects-storage
Open

wmadden-electric wants to merge 105 commits into
mainfrom
tml-3537-value-objects-storage

Conversation

@wmadden-electric

Copy link
Copy Markdown
Contributor

Linked issue

Refs TML-3537. This is the third of four pull requests for the remaining migration statements. The first two (namespaces, enum values) are merged. The fourth adds the value object and variant statements on top of this one.

At a glance

A model stores a value object in one jsonb column:

type Address {
  street String
  city   String
}

model User {
  id      Int      @id
  address Address?
  @@map("user")
}

Before this change, contract.json kept Address in the domain plane, and the field named it:

"domain": { "namespaces": { "public": {
  "models": { "User": { "fields": {
    "address": { "nullable": true, "type": { "kind": "valueObject", "name": "Address" } }
  } } },
  "valueObjects": { "Address": { "fields": {
    "city":   { "nullable": false, "type": { "kind": "scalar", "codecId": "pg/text@1" } },
    "street": { "nullable": false, "type": { "kind": "scalar", "codecId": "pg/text@1" } }
  } } }
} } }

Now Address is a storage entity, and the field refers to it by its storage coordinate:

"domain": { "namespaces": { "public": { "models": { "User": { "fields": {
  "address": { "nullable": true, "type": { "kind": "valueObject", "plane": "storage", "namespaceId": "public", "entityKind": "valueObject", "entityName": "Address" } }
} } } } } },
"storage": { "namespaces": { "public": { "entries": { "valueObject": { "Address": { "fields": {
  "city":   { "nullable": false, "type": { "kind": "scalar", "codecId": "pg/text@1" } },
  "street": { "nullable": false, "type": { "kind": "scalar", "codecId": "pg/text@1" } }
} } } } } } }

On a managed Postgres table, the column gets a derived check. migration plan writes it:

CONSTRAINT "user_address_shape_<hash>" CHECK ("address" IS NULL OR jsonb_path_match("address", 'strict $.type() == "null" || ($.type() == "object"
  && exists($.keyvalue() ? (@.key == "city" && (@.value.type() == "string")))
  && exists($.keyvalue() ? (@.key == "street" && (@.value.type() == "string")))
  && !exists($.keyvalue() ? (@.key != "city" && @.key != "street")))') IS TRUE)

Before, renaming street changed only the domain plane. The storage hash stayed the same, and migration plan reported "No changes detected" while every row kept the old key. Now the rename changes the storage hash and the check, so the migration system sees it.

Summary

The migration system tells database states apart by the storage hash. A value object's fields and a discriminator's values are stored data, so they now live in storage, where the hash covers them. The decision is recorded in ADR 309.

Decision

This PR ships four things:

  1. Value objects are storage entities, in both the SQL and MongoDB families, at storage.namespaces.<ns>.entries.valueObject.<Name>, with the definition they had in the domain plane. A domain field refers to one by storage coordinate. This is the first reference from the domain plane to the storage plane. A contract that still keeps valueObjects in the domain is refused with a message that says to re-emit it.
  2. A SQL discriminator column names a value set. The build writes one value set per base model with variants, keyed <Base>.<field> (for example Task.type), holding the variants' values sorted. The base table's discriminator column refers to it, as an enum column refers to its enum's value set. MongoDB writes none, because its collection validator already lists each variant's value.
  3. Postgres derives two checks on a managed table: <table>_<column>_shape_<hash> for a value object column, and <table>_<column>_check_<hash> for a discriminator column ("type" IN ('bug', 'feature')). The checks are content-named, so any change to the value object or the variants drops the old check and adds the new one.
  4. A plan whose storage hash changed but has no operations is written and applied. migration plan writes the migration with no operations and names what changed. db migrate and db update move the marker to the new hash. Before, such a plan was refused.

Every contract with value objects or variants is re-emitted, and the prisma-8-demo initial migration now creates the two checks. Projects upgrade with a script.

Reviewer notes

  • Most of the diff is re-emitted fixtures. Every committed contract with value objects or variants, its contract.d.ts and the example migration snapshots changed hash. pnpm fixtures:check is clean. The source changes are in the families' authoring, emit, ORM and validator code, the Postgres check derivation and the CLI's no-operation plan.
  • The value object check is one jsonpath predicate, ending in IS TRUE, so an unknown result fails. A required member must be present and of its codec's JSON type, a nullable member may be absent or JSON null, and no other key is allowed. A value object that contains itself is checked down to where it refers back to itself, as the MongoDB validator does.
  • Each Postgres codec declares the JSON type its value is written as, in a new jsonType field ('string' | 'number' | 'boolean' | 'object' | 'array' | 'any'), as MongoDB data types declare bsonTypes. The check reads it. TypeScript requires the field. At run time a codec package built before this release still loads; only a value object member that uses such a codec is refused, with CONTRACT.CODEC_JSON_TYPE_MISSING, naming the codec and the member.
  • SQL value objects hold no unions or dictionaries. No SQL authoring surface writes one, and the check cannot enforce one, so a hand-written SQL contract with one is refused when it is validated.
  • The framework now defines the valueObject storage entity kind, with one schema both families use, because domain fields refer to it. ADR 221 says families and packs own entity kinds, so ADR 309 and a note in ADR 221 record the exception.
  • A clash between an enum's value set and a discriminator's is refused. It needs an enum named exactly like <Base>.<field> in the same namespace. No authoring surface writes that name, so only a hand-written definition reaches the refusal.
  • The SQL TypeScript builder has no value objects. The main SQL ORM test contract used to patch one into its built contract, which left its storage hash stale. It now stores User.address as plain jsonb, and the value object type tests read a new PSL fixture. This is recorded in projects/migration-statements/deferred.md.
  • The mongo-demo and retail-store migration chains fail db migrate on mongodb-memory-server with MIGRATION.SCHEMA_VERIFY_FAILED. They fail the same way on origin/main, so this PR did not cause it. Filed as TML-3749.

How it fits together

  1. Contract shape and validation. The framework contract types gain the storage value object and the field's storage coordinate. Both families' validators check that each coordinate resolves to a storage entry, and that a value object member's enum refers to a storage value set. See packages/1-framework/0-foundation/contract/src/domain-types.ts and packages/1-framework/0-foundation/contract/src/storage-value-objects.ts.
  2. Authoring writes storage. SQL PSL, MongoDB PSL, the MongoDB TypeScript builder and the Prisma 6 reader write value objects into storage before the storage hash is computed. SQL PSL now pairs each @@discriminator with its variants before the build, so the discriminator value set is in the hash. See packages/2-sql-family/2-authoring/contract-ts/src/build-contract.ts and packages/2-sql-family/2-authoring/contract-psl/src/interpreter.ts.
  3. Emit and types read storage. contract.d.ts types a value object field from the storage plane, through a new, required sixth parameter of FieldTypesFromDomain, so every contract.d.ts changes. A SQL discriminator field is typed by its variants' values ('bug' | 'feature'). See packages/1-framework/0-foundation/contract/src/field-value-types.ts.
  4. Runtime and tools follow the reference. The SQL and MongoDB ORMs and query builders, the MongoDB validator derivation, contract print, contract infer and the statement resolver find a value object through the field's coordinate.
  5. Postgres derives the checks, from the storage value object and the discriminator value set. The SQL family resolves each value object and its members' JSON types once, and the build and contract print share that derivation. See packages/2-sql-family/1-core/contract/src/check-expressions.ts and packages/3-targets/postgres/1-target/src/core/check-expressions.ts.
  6. The CLI writes and applies a plan with no operations when the storage hash changed, and names the storage entities that changed (changedStorageEntities in --json). When rows break a new check, the runner reports which check and column, and the CLI gives the query that finds the rows and the way to keep their data. See packages/1-framework/3-tooling/cli/src/control-api/operations/migration-plan.ts and packages/1-framework/3-tooling/cli/src/utils/runner-failure-advice.ts.

Behavior changes & evidence

  • A value object column on a managed Postgres table is checked. A row the ORM writes is accepted. A row with an undeclared key or a missing member is refused, naming the check. Evidence: test/integration/test/cli-journeys/value-object-checks.e2e.test.ts (V1), packages/3-targets/postgres/1-target/test/check-expressions.value-object.test.ts.
  • Changing a value object is a migration. Adding a member, or making one nullable, drops the old check and adds the new one; rows that fit the new shape stay. Adding a required member to a table with a row that lacks it fails at apply and changes nothing. The error names the check and the column, gives the query that finds the rows, and says how to keep their data: an update in migration.ts between the drop of the old check and the add of the new one. Following that advice applies cleanly. Evidence: value-object-checks.e2e.test.ts (V2, V3).
  • Adding a variant replaces the discriminator check, and the new variant's value is accepted. Evidence: value-object-checks.e2e.test.ts (V4).
  • A storage change with no operation is written and applied. Changing a value object that only an external table's column holds writes a migration with no operations, and migrate moves the marker. Evidence: value-object-checks.e2e.test.ts (V5), test/integration/test/cli-journeys/plans-with-no-operations.e2e.test.ts and its SQLite and MongoDB twins.
  • On MongoDB, a value object change still updates the collection validator. Evidence: test/integration/test/cli-journeys/value-object-validator.mongo.e2e.test.ts.
  • A contract with valueObjects in the domain is refused with CONTRACT.VALIDATION_FAILED, saying to re-emit it. Evidence: packages/1-framework/0-foundation/contract/test/validate-domain.test.ts.

Every journey runs through migration plan and migrate, and through db update, and ends with db verify --schema-only clean and a further plan empty.

Upgrade

The upgrade instructions are in upgrade-instructions/pending/value-objects-in-storage/. For an app:

  1. Apply every pending migration to each database with the release you are upgrading from, and commit your work.
  2. Upgrade the Prisma packages to this release.
  3. Run the script from the project root: node <guide>/scripts/value-objects-in-storage/value-objects-in-storage.ts. It rewrites every contract and snapshot, renames each snapshot directory to its new storage hash, and rewrites the migrations, refs, migration.ts and contract.d.ts files that name an old hash. It prints each <old> -> <new> hash. A second run changes nothing.
  4. Sign each database: prisma db sign --db "$DATABASE_URL". A database you could not migrate first is signed at the new hash of its marker's hash with prisma db sign --contract <new hash> --no-advance-ref, then migrated.
  5. Re-emit the contract: prisma contract emit.
  6. On Postgres, find the rows that would fail the new checks with the query the guide gives, and fix them. Then plan the migration that adds the checks with prisma migration plan, and apply it with prisma db migrate --advance-ref db --db "$DATABASE_URL". On MongoDB there is nothing to plan.

Adding a check takes a lock on the table while Postgres reads every row, and a later change to the value object replaces the check and reads the rows again. The guide says so.

Extension authors:

  • read value objects from contract.storage: contractModelToMongoResultShape, contractFieldToMongoFieldShape and compileMongoQuery take the storage, and MongoValueObjects is removed;
  • ValueObjectTypesFromDomain is now ValueObjectTypesFromStorage, and FieldTypesFromDomain takes the storage namespaces as a required sixth argument;
  • each Postgres codec declares jsonType, and the check expression types moved to @prisma/orm-postgres/family-contract/check-expressions.

The script and both guides were run from start to finish on copies of prisma-8-demo and mongo-demo with real migration histories, including a database behind the last migration and a row that breaks the new check. A second migration plan afterwards writes nothing.

Testing performed

  • New journeys: value-object-checks.e2e.test.ts (10 cases) and value-object-validator.mongo.e2e.test.ts (2 cases).
  • Existing journeys: enum value statements (Postgres and SQLite), namespace statements, plans with no operations (Postgres, SQLite, MongoDB).
  • test/integration/test/sql-orm-client/ (142 files), the upgrade script's integration test, the print round-trip files.
  • pnpm fixtures:check, pnpm lint:deps, pnpm lint:ratchets, pnpm check:error-reference, pnpm check:upgrade-coverage --mode pr.
  • Typecheck, lint and test --coverage in each touched package.

Skill update

skills/prisma-8/references/contract.md says value objects are lowered to storage value objects, describes the derived Postgres checks and the discriminator value set, and says a value object change is a migration.

Follow-ups

  • The value object and variant statements (--rename Address.street:Address.line1, --convert Bug, --delete Bug) are the next pull request. It also adds --backfill for a new required value object member, so rows that lack it can be filled without a hand-written update.
  • TML-3750: the SQL ORM cannot create a variant through the variant's own model (orm.Bug.create); orm.Task.variant('bug').create works. This fails on main too.
  • Recorded in projects/migration-statements/deferred.md: the SQL TypeScript builder has no value objects; SQL PSL does not namespace composite types; a column's value set reference is not checked against storage; the SQL ORM cannot write a BigInt or Bytes member of a value object.

Alternatives considered

  • Keep value objects in the domain plane, because the tables do not change. Then the migration system can never see a value object change, even to refuse it, and the old keys stay in every row.
  • Keep them in the domain plane and record a change as a migration from a hash to itself. Snapshots are saved by storage hash, so a plan's previous contract can be several changes old, and db update, which runs no data operations, still could not apply it.
  • Copy the definition into storage and keep the domain copy. Two copies of one definition invite drift, and the domain plane can already refer to storage.
  • Feed the domain value objects into the storage hash without moving them. The hash would change, but the planner compares storage, so it still could not tell what changed.
  • Record the facts in storage without enforcing them. The planner would see every change, but Postgres and MongoDB would give up enforcing the shape and the variants' values, which the ORM never enforced either.
  • Check a flat value object with the key-set operators ?& and -. One strict jsonpath predicate covers nesting, lists, member types and nullability, and one form for every shape is simpler to derive and to read back.

Checklist

  • All commits are signed off (git commit -s) per the DCO.
  • I read CONTRIBUTING.md and the change is scoped to one logical concern.
  • Tests are updated.
  • The PR title is in TML-NNNN: <sentence-case title> form.
  • The Skill update section above is filled in.

Agent: radagast-20

…ch briefs

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…he storage changed

When the storage hash changes but the planner plans nothing, migration plan
writes the package with an empty ops.json and names the storage entities
that changed (changedStorageEntities in --json). db migrate and db update
move the marker. Only a first migration with no operations is still refused.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…dinate

EntityCoordinate moves to @internal/contract, so the foundation can use it.
ValueObjectFieldType is EntityCoordinate<'storage', 'valueObject'> with
kind 'valueObject'; ValueSetRef extends EntityCoordinate. The domain plane
no longer has valueObjects. Domain validation checks each value object
reference against storage.namespaces.<ns>.entries.valueObject and refuses
the old domain key. valueObjectAt and storageValueObjectsAtDefaultNamespace
replace domainValueObjectsAtDefaultNamespace.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ueObject

A StorageValueObject entity kind with its schema; a member typed by an enum
refers to the storage value set. A domain field type refers to the value
object by its storage coordinate. The domain namespace schema drops
valueObjects, and an old contract that has it is refused with a message
that says to re-emit. The editor JSON schema is regenerated.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…alueObject

A MongoValueObject entity kind with its schema; a member typed by an enum
refers to the storage value set. A domain field type refers to the value
object by its storage coordinate. The domain namespace schema and the
contract serializer refuse the old domain valueObjects key with a message
that says to re-emit. Readers of a field's value object name use entityName.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…sets into storage

The SQL build writes each value object to entries.valueObject of the default
namespace before the storage hash, and fields and nested members refer to it
by its storage coordinate; an enum member refers to the storage value set.
A model node now carries its discriminator, variants and base, so the build
writes the <Base>.<field> value set and points the discriminator column at it.
An enum-typed discriminator keeps the enum's value set, and an enum named like
the discriminator's value set is refused. SQL PSL pairs variants before the
build instead of patching them in afterwards.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The Mongo builder writes value objects to entries.valueObject and
buildMongoStorage hashes them. field.valueObject, Mongo PSL and the
Prisma 6 reader write the storage coordinate. A value object member typed
by an enum refers to the storage value set, and the validator refusals
count such enums. The Mongo target serializer carries every entries kind
through deserialize and serialize. The derived validators do not change.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…hanged

The no-operations sentence is appended to the existing summary, so an
automatic baseline keeps its baseline text and a plan keeps its extension
migration directories.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ed when no entity did

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…no operations

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…re-emitted

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…espace without entries

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ue set

ContractValueObjectField types valueSet as EntityCoordinate<'storage',
'valueSet'>, so a value object cannot refer to the domain plane by type. The
SQL and Mongo builders write members and model fields through separate
functions.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…e-set check as deferred

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…s reference names

FieldTypesFromDomain takes the storage namespaces as a last type parameter with a default, so a contract without value objects types its fields as before. ValueObjectTypesFromStorage replaces ValueObjectTypesFromDomain and is keyed by storage namespace.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The SQL and Mongo emitters write entries.valueObject in the storage namespaces type. A value object field type is its storage coordinate. The domain valueObjects line and the top-level valueObjects block are gone. A value object member's override reads the storage value set it names. The Mongo builder types value objects in storage too. A contract without value objects emits the same text as before.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ration order does not change the storage hash

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…e already has a value set of that name

The refusal checks the base table's storage namespace, not every enum, and uses the colon form of the other enumType messages.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…espaces are refused

Every value object is stored in the default storage namespace and models refer to composite types by bare name, so the second one silently replaced the first.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…en storage is a class instance

Real families hydrate storage into a class, which isPlainRecord rejects, so every such plan said the change was outside the storage entities.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…orrected reason for the clash refusal

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… the field's storage reference

Run time reads go through valueObjectAt; type-level reads go through the new ContractValueObjectAt. The dead fallback to the flat valueObjects block of contract.d.ts is gone.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The statement resolver still refuses a statement that names a value object, but looks for it under storage entries.valueObject. A statement contract now carries its storage namespaces.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… check accepts for it, and the check reads it through the stack's codec lookup instead of a table in the target

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…valueObjectJsonType

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…names end in _shape

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… _shape check names

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…eck reads every row under a lock, and NOT VALID checks are deferred

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…migration it writes, and decides a migration with no operations from its operations

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…fields of storage value objects, and both family storage validators run it

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…pe names the upgrade script for a stored contract, and the Mongo schema keeps no copy of it

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ts principle stops, and which changes have no operations; the Prisma 6 reader no longer promises @Map on composite fields; small doc fixes

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…and the contract README lists the validate-storage export

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…eview

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…en as; the SQL family resolves each value object member's JSON type, and the check renderer reads only its input

jsonType is one of string, number, boolean, object, array or any. The SQL family codecs declare it on their templates, and postgresCodec keeps it. The family reads it when it resolves a value object and refuses a member whose codec declares none with CONTRACT.CODEC_JSON_TYPE_MISSING. The Postgres registries accept a descriptor without it, so an older codec package keeps working where it is not in a value object.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…mespaces'>, and ContractWithDomain stays on functions that read the domain

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…elds and value object members in both families; ContractValueObjectSchema is named after its type; SQL's value object schema leaves out unions and dictionaries by its structure, and its refusal names the value object and the member

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…union and dictionary value object members and checks a domain field's type

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… changedStorageEntities, the words its README and summary use

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…DB value object member leaves it out, and drops dict false

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…nd reads the valueSet slot; ADR 309 describes the codec's JSON type, and its first consequence and the rejected alternative agree with the cases that have no operations

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…e SQL refusal, and the missing jsonType error says why without guessing the codec's age

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…he upgrade script keeps a malformed nullable, and ADR 309 gives the full check name

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…and db update says when it signs a changed contract with no operations and names what changed

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
… names the check, table and column, gives the query that finds the rows, and the route that keeps them

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…d apply with --advance-ref db, so the next plan writes nothing; the advice to fix rows re-runs db migrate with its flags

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric
wmadden-electric requested a review from a team as a code owner October 23, 2026 19:21
@coderabbitai

coderabbitai Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Warning

Review details and warnings were omitted to fit the comment limit.

@pkg-pr-new

pkg-pr-new Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@prisma/orm-extension-arktype-json

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-extension-arktype-json@30869

@prisma/orm-extension-middleware-cache

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-extension-middleware-cache@30869

@prisma/orm-extension-paradedb

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-extension-paradedb@30869

@prisma/orm-extension-pgvector

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-extension-pgvector@30869

@prisma/orm-extension-postgis

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-extension-postgis@30869

@prisma/orm-extension-supabase

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-extension-supabase@30869

@prisma/orm-family-mongo

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-family-mongo@30869

@prisma/orm-family-sql

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-family-sql@30869

@prisma/orm-framework

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-framework@30869

@prisma/orm-mongo

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

@prisma/orm-mysql

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-mysql@30869

@prisma/orm-postgres

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-postgres@30869

@prisma/orm-sqlite

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-sqlite@30869

@prisma/orm-target-mongo

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-target-mongo@30869

@prisma/orm-target-mysql

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-target-mysql@30869

@prisma/orm-target-postgres

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-target-postgres@30869

@prisma/orm-target-sqlite

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-target-sqlite@30869

@prisma/orm-toolchain

npm i https://pkg.pr.new/prisma/orm/@prisma/orm-toolchain@30869

commit: d846707

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
postgres / no-emit 271.07 KB (+1.23% 🔺)
postgres / emit 236.6 KB (+0.51% 🔺)
mongo / no-emit 226.22 KB (+0.44% 🔺)
mongo / emit 183.88 KB (+0.49% 🔺)
cf-worker / no-emit 333.18 KB (+1.09% 🔺)
cf-worker / emit 295.02 KB (+0.54% 🔺)

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>

This branch has not been deployed

No deployments
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