v8.0.0-rc.17
Migrations no longer lose data without being told to: prisma migration plan and prisma db update ask about each model or field a plan would drop, answered with --delete or with the new --rename, which keeps the rows. The ORM client gains row locks, apply and scope are renamed to with and fragment, and db.enums holds each member as a query returns it.
The upgrade recipes for this hop: the app recipe and the extension recipe. Each breaking change below names the change ids to look for in them.
Breaking changes
-
--confirmno longer consents to data loss.prisma migration planandprisma db updateask one question for each model, field or table a plan would lose data from, before they write or apply anything. Answer with--delete <subject>to let the data go, or--rename <old>:<new>to keep it.db updatealso asks before an operation that widens who can read or write a model's rows, such as dropping a row-level-security policy, answered with--allow <Model>. Where nobody can answer, the command fails withCLI.CONSENT_REQUIRED, whosenextActionsgive the flags. Replace each--confirmin scripts and CI. Seemigration-plan-refuses-data-lossanddb-update-confirm-no-longer-consentsin the app recipe. (#30648)Before:
prisma db update --confirm appdb
After:
prisma db update --delete Legacy --rename User.name:User.fullName
-
destructivenow means data loss. Dropping an index, a constraint, a check, a default or a native enum type, PostgressetNotNull, and type changes that keep every value are nowwideningoperations, and no longer ask for consent. Amigration.tsno database has applied yet writes a differentops.jsonandmigrationHashwhen run again. Seenon-data-drops-are-wideninganddestructive-means-data-lossin the app recipe. (#30638, #30648) -
The control API answers questions through a callback.
executeMigrationPlanCommand,executeDbUpdateand the control client'sdbUpdaterequire ananswerQuestionscallback, and loseconsent.acceptDataLoss: trueno longer covers access widening; passacceptAccessWidening: truetoo. The errorsMIGRATION.DESTRUCTIVE_CHANGESandMIGRATION.CONSENT_PLAN_MISMATCHare no longer raised. Seecontrol-api-answer-questionsandconsent-errors-removedin the app recipe. (#30648) -
The collection method
applyis nowwith, andscopeis nowfragment. A reusable function from a collection to a collection is a query fragment, made withdb.orm.fragment(...)orcollection.fragment(...)and run withcollection.with(...). The typesScope,FieldScopeandScopeFactsare nowFragment,FieldFragmentandFragmentFacts. This applies to the SQL ORM client only. Seecollection-apply-is-now-withandorm-scope-is-now-fragmentin the app recipe. (#30635, #30647)Before:
const postSummary = db.orm.public.Post.scope((posts) => posts.select('id', 'title').include('user')); const posts = await db.orm.public.Post.apply(notDeleted).apply(postSummary).all();
After:
const postSummary = db.orm.public.Post.fragment((posts) => posts.select('id', 'title').include('user')); const posts = await db.orm.public.Post.with(notDeleted).with(postSummary).all();
-
db.enumsholds each member as a query returns it. A member whose codec stores another form incontract.jsonchanges: a bigint member is abigint, a date member aDateor a Temporal value, a byte member aUint8Array, and a NaN or infinite float member a number.has(),nameOf()andordinalOf()now find a value read from the database. Remove conversions your code applied to these members, and re-emit the contract. Code that builds the MongoDB ORM itself withmongoOrm()orcreateMongoCollection()must pass the enum accessors. Seedb-enums-members-hold-read-valuesandmongo-orm-takes-enum-accessorsin the app recipe. (#30628)Before:
// Level is @@type("pg/int8@1") with Low = "1" db.enums.public.Level.members.Low; // "1"
After:
db.enums.public.Level.members.Low; // 1n
-
Enum members and values must be written as the database stores them. A Postgres
numericorinetenum member written in a form Postgres prints differently, such as"01.5"or"10.0.0.1/32", is refused, and the message says what to write. Enums can no longer use codecs whose values never equal a member:pg/timestamp-string@1,pg/timestamptz-string@1,pg/bytea@1,pg/tsquery@1,pg/json@1, and on MongoDBmongo/json@1andmongo/bson@1, plus PSL enums on BSON types the collection validator cannot list. Seets-enum-members-written-as-stored,psl-enum-members-written-as-stored,enum-codecs-refused,enum-json-codec-refusedandpsl-enum-bson-types-refusedin the app recipe. (#30628)Before:
enum Ratio { @@type("pg/numeric@1") Half = "01.5" }
After:
enum Ratio { @@type("pg/numeric@1") Half = "1.5" }
-
Contracts from a Prisma 7 schema state the constraint names Prisma 7 chose.
prisma7Schema(...)now writes the name of each primary key and foreign key whose Prisma 7 name differs from the one Prisma 8 derives. A contract with such a constraint gets a new storage hash: re-emit, then sign the database, plan a migration or rundb update, depending on who manages it. Seeprisma7-schema-states-constraint-namesin the app recipe. (#30606) -
The CHECK constraint on an enum list column compares in the column's own type. The constraint's expression and name change, so re-emit and apply a migration that replaces it. See
enum-list-check-compares-in-column-typein the app recipe. (#30628) -
Each foreign key in
contract.jsonnames the index that backs it. A newindexfield on each foreign key says whether an index, the primary key or a unique constraint serves its lookups, so every SQL contract with a foreign key gets a new storage hash. Re-emit, then followmigration plan's advice: write an empty migration withprisma migration new --from <hash>, or runprisma db signon a database you manage withdb initordb update. Two related changes can alter your database: a partial index, or an index with a non-defaulttypeoroptions, no longer counts as a relation's backing index, somigration plancreates one beside it; and an unnamed@@indexon exactly the columns of a unique constraint or the primary key is left out of the contract, somigration plandrops it. To keep the database as it is, writeindex: "<name>"on the relation, or give the plain index aname. Seeforeign-keys-name-their-backing-index,partial-or-typed-index-no-longer-backs-a-foreign-keyandunnamed-index-on-unique-columns-left-outin the app recipe. (#30561)author User @relation(fields: [authorId], references: [id], index: "post_author_live") -
MongoDB PSL writes an index's sort direction as
sort(field, direction). The oldfield(sort: Desc)form is no longer accepted in@@index,@@uniqueand@@textIndex. The database index does not change. Seemongo-index-sort-functionin the app recipe. (#30636)Before:
@@index([createdAt(sort: Desc), authorId])After:
@@index([sort(createdAt, Desc), authorId]) -
Extension authors: migration planners take statements and report what they lose. A planner's
plan(...)takes requiredstatementsandorigin, and its success result carriesappliedStatements,dataLossandaccessWidening.ControlFamilyInstancerequiresstorageNameOf.plannerSuccesstakesappliedStatementsand the subjects lists. See the planner entries in the extension recipe. (#30638, #30648) -
Extension authors: enum accessors read members through codecs.
buildNamespacedEnums()andbuildEnumsMapForNamespace()take a codec lookup. A codec an enum may use must declare theequalitytrait, and can refuse enums withenumRefusal.decodeJsonIntegerTextrefuses leading zeros and negative zero. A target facade'sdefineContractcarries anEnumstype parameter.CollectionStatehas a requiredlockingkey. See the extension recipe. (#30628, #30555) -
Extension authors: foreign keys name their backing index. Regenerate bundled SQL contracts that have a foreign key; their storage hash changes. A bundled relation with
index: falsewhose model has a key or index starting with its columns names it withindex: "<name>".materializeForeignKeysAndIndexes()takes one object, andbackingIndexColumnKeys(),isBackedByColumnKeys()andBackingIndexCandidatesare removed. See the extension recipe. (#30561)
Features
prisma migration planandprisma db updateaccept--rename <old>:<new>, repeatable, to rename a model or a field and keep its rows instead of dropping and creating its table or column. On MongoDB, renames are refused in this release. (#30638)- ORM collections lock the rows a read selects with
forUpdate(),forNoKeyUpdate(),forShare()andforKeyShare(), each with optionalnowaitorskipLocked. Re-emit the contract to pick up the capabilities they need. (#30555) - Giving an existing integer column
@default(autoincrement())now plans a sequence that starts past the column's current maximum, where it used to plan nothing. (#30606) - A relation can name the index, unique constraint or primary key that backs its foreign key with
index: "<name>", so no extra index is created.prisma contract emitwarns when two named indexes of a table are identical (PN_INDEX_DUPLICATE), or when a named plain index has the same columns as a unique constraint or the primary key (PN_INDEX_REDUNDANT). (#30561)
Fixes
- When a contract change needs no database change,
prisma migration planexplains why and names the command to run next, instead of suggestingdb verify --schema-only. (#30639) - Dropping a constraint of a table with a long name no longer fails: Prisma 8 derives the name Postgres stores for it. (#30606)
- An
inetenum list column takes host addresses such as127.0.0.1; its CHECK constraint refused every one. (#30628) - A
numericdefault with a leading zero, or aninetdefault in a form Postgres prints differently, is stored as Postgres prints it, sodb init,db updateanddb migrateapply it instead of failing schema verification. (#30628) - The MongoDB ORM accepts writes of enum values whose stored form is not the value, such as bigint and date members. (#30628)