github prisma/orm v8.0.0-rc.14

latest release: v8.0.0-rc.14-dev.3
pre-release2 hours ago

v8.0.0-rc.14

In this release, connect() on the Postgres serverless client returns a connection with db.orm, db.transaction(...) and db.prepare(...), the same members as a postgres() client. A date or time default is stored in one canonical text for each value, so its storage hash no longer depends on how the default was written. The Mongo ORM passes every value it writes, reads or filters on through its field's codec. The Postgres CLI commands now work with date and time defaults on Node 24, which has no Temporal.

The upgrade recipes for this hop: the app recipe and the extension recipe. Each breaking change below names the change id to look for in them.

Breaking changes

  • Serverless connect() returns a connection, not a Runtime. postgresServerless(...).connect({ url }) from @prisma/orm-postgres/serverless now returns a connection with the members of a postgres() client except connect. Replace runtime.query(plan) with db.runtime().query(plan), and pass db.runtime() wherever the connect() result was used as a runtime. connect() now opens the database connection before it returns, and rejects with DRIVER.CONNECTION_FAILED when the database cannot be reached. Reads no longer go through a server-side cursor by default. The cursor option is now PostgresCursorOptions, { batchSize?: number }, so delete cursor: { disabled: true }. See serverless-connect-returns-connection and serverless-cursor-default-off in the app recipe. (#30482)

    Before:

    await using runtime = await db.connect({ url: env.HYPERDRIVE.connectionString });
    const rows = await runtime.query(db.sql.public.user.select('id').build());

    After:

    await using db = await postgres.connect({ url: env.HYPERDRIVE.connectionString });
    const rows = await db.runtime().query(db.sql.public.user.select('id').build());
  • A date or time default is stored in its type's canonical form. On Postgres and SQLite, prisma contract emit stores each date or time default as one text for each value: @default("2024-01-01T01:00:00+01:00") on a DateTime column is stored as "2024-01-01T00:00:00Z". TypeScript contracts store the same text. A default that was not already in that form gets a new storage hash. The database does not change: re-emit, then run prisma db sign, or record an empty migration with prisma migration new. contract emit now refuses a default that the column's type does not hold, such as an offset on a Timestamp column, with PSL_INVALID_DEFAULT_LITERAL. See date-time-default-stored-in-canonical-form, date-time-default-refused-text and date-time-ts-default-stored-in-canonical-form in the app recipe. (#30532)

    Before, accepted and stored as written:

    model Event {
      id      Int       @id
      localAt Timestamp @default("2024-01-01T00:00:00Z")
    }

    After, because a Timestamp column holds no offset:

    model Event {
      id      Int       @id
      localAt Timestamp @default("2024-01-01T00:00:00")
    }
  • The Mongo ORM checks every value through its field's codec. A write of a value of the wrong type, of a fraction or an out-of-range number to an Int32 field, of a value outside the field's enum, or of null to a required field now fails with RUNTIME.ENCODE_FAILED naming the field. Before, some of these were stored as given. A filter expression passed to where() is encoded the same way, so a filter on an Int64 field needs a bigint. create() and createAll() return the document as stored, decoded like a read, and a nullable field missing from a stored document reads as null, not undefined. The query builder's match() still sends values as given. See the mongo-* entries in the app recipe. (#30519)

    Before:

    db.orm.posts.where(MongoFieldFilter.gt('views', Long.fromNumber(5)))

    After:

    db.orm.posts.where(MongoFieldFilter.gt('views', new MongoParamRef(5n)))
  • temporal-polyfill is a peer dependency of the Postgres packages. @prisma/orm-postgres and @prisma/orm-target-postgres now declare temporal-polyfill as a required peer dependency. npm, pnpm and bun install it automatically. A project that installs with Yarn must add temporal-polyfill (^1.0.4) to its own dependencies. See temporal-polyfill-is-a-peer-dependency in the app recipe. (#30520)

  • The toolchain requires @prisma/cli-engine 0.6.2. A project that pins @prisma/cli-engine itself must move the pin from 0.6.1 to 0.6.2. With this engine, hints, warnings and errors print the name of the CLI, as in prisma db migrate, where they used to print a literal {bin}. A script that matches {bin} in the CLI's output must match the CLI name instead. See engine-pin-moves-to-0-6-2 in the app recipe. (#30503)

  • Contract source warnings are diagnostics. prisma contract emit and prisma contract print report a source warning, such as PSL_DEPRECATED_SCALAR_NAME, as a warn diagnostic of the result instead of a free-text warning … line. With --json, it is in the diagnostics of the result. A script that read the old lines must read diagnostics instead. See contract-source-warnings-are-diagnostics in the app recipe. (#30519)

  • Extension authors: Mongo result shapes, insert results and codecs changed. contractModelToMongoResultShape takes includes, a map from relation name to the shape of the included document, instead of includeRelationNames. compileMongoQuery takes the contract's value objects as a fifth argument. InsertOneResult and InsertManyResult carry the inserted documents as stored, so a Mongo driver of your own must yield them. The mongo/double@1 codec's encode returns the driver's Double, and the other Mongo codecs refuse a value of the wrong type. reportUnknownFieldPreset takes the authoringContributions. See the extension recipe. (#30519)

    Before:

    contractModelToMongoResultShape(model, { includeRelationNames: ['author'] });

    After:

    contractModelToMongoResultShape(model, { includes: { author: authorShape }, valueObjects });

Features

  • A serverless connection has db.orm, db.transaction(...) and db.prepare(...). Inside a request, code written for a postgres() client works on the connection that postgres.connect({ url }) returns, so a hand-built orm({ runtime, context }) and withTransaction(runtime, fn) are no longer needed. The serverless client also gains raw, enums and nativeEnums. (#30482)
  • postgres() takes a cursor option. postgres({ ..., cursor: { batchSize: 100 } }) reads through a server-side cursor in batches, as postgresServerless() does with the same option. Without the option, reads are buffered. (#30482)
  • The language server reads a multi-file schema as one project. When contract in prisma.config.ts names a pattern such as ./*.prisma, files you have not opened contribute their models to the others and receive diagnostics. Before, the server read the pattern as a literal file path. (#30456)

Fixes

  • On Node 24, which has no Temporal, prisma contract emit, db init, db update, contract infer, node migration.ts, the Vite plugin and the language server work on a Postgres schema with a date or time default. Before, they failed with a message that the runtime has no global Temporal implementation. (#30520)
  • A Mongo Double field stores a whole number as a BSON double. Before, the write failed with Document failed validation. ObjectId[], Int64[], Decimal128[] and Binary[] fields can be written, and a query-builder filter that compares with an ObjectId, Long, Decimal128 or Binary matches the stored value. (#30519)
  • Mongo reads decode documents from include() and composite-type fields through their codecs, so an ObjectId in them reads as a hex string and an Int64 as a bigint. (#30519)
  • A Mongo upsert() whose create sets a field that has an update default, such as temporal.updatedAt(), inserts the create value. Before, the insert got the current time. (#30519)
  • prisma db update on MongoDB can confirm and apply a destructive change. A validator change that only admits more values, such as Json to Bson, is no longer called destructive. (#30519)
  • On SQLite, a new DateTime column's default is the same text the application writes for the same instant, so rows that took the default compare and sort correctly against rows the application wrote. (#30532)
  • When two namespaces declare models with the same name, each relation points to the model in its own namespace. Before, a relation could point to the same-named model in another namespace. An unknown field type reports one diagnostic instead of two. (#30478)
  • A Postgres policy_* block whose target model is declared outside the block's namespace is stored in the namespace of the table it protects. (#30381)
  • When prisma db sign refuses because the database does not match the contract, it offers both ways out: change the database with prisma db update, or change the contract source to describe the database and emit again. It says which one changes the database. (#30438)
  • The 8.0.0-rc.12 to 8.0.0-rc.13 upgrade guides include a script that renames the default references in migration snapshots, in place of the renaming by hand. (#30453)

Don't miss a new orm release

NewReleases is sending notifications on new releases.