upgrading/app/upgrades/8.0.0-rc.5-to-8.0.0-rc.6/instructions.md
upgrading/app/upgrades/8.0.0-rc.5-to-8.0.0-rc.6/instructions.mdBrowse 76 files
9,731 bytes
Token encoding: o200k_base
Snapshot fac8604
from: "8.0.0-rc.5" to: "8.0.0-rc.6" changes:
-
id: postgres-temporal-representations summary: | PostgreSQL temporal columns no longer read as JavaScript
Date. Each ofdate,timestamp(p),timestamptz(p)andtime(p)now offers two explicit representations, and five codecs were removed with no compatibility aliases:Retired Replace with (Temporal) Replace with (text) pg/date@1Date→pg/date-temporal@1(Temporal.PlainDate)DateStringpg/timestamp@1Timestamp(p)→pg/timestamp-temporal@1(Temporal.PlainDateTime)TimestampString(p)pg/timestamptz@1Timestamptz(p)→pg/timestamptz-temporal@1(Temporal.Instant)TimestamptzString(p)pg/time@1Time(p)→pg/time-temporal@1(Temporal.PlainTime)TimeString(p)sql/timestamp@1(field.timestamp())Timestamptz(p)orfield.temporal.timestamptz(p)TimestamptzString(p)-
Decide a representation per column. The bare PSL spellings (
Date,Timestamp,Timestamptz,Time) keep working and now select the Temporal-backed codec. If a column's values should stay text — because your code treats them as strings, or because they include values Temporal cannot denote (infinity, non-ISODateStyleoutput, years beyond ±271821) — rename the type to its*Stringspelling. Notepg/time@1already handed back astring: atimecolumn whose value you treat as text needsTimeString(p), notTime(p). -
Replace
field.timestamp(). The generic cross-target helper and itssql/timestamp@1codec are gone. On PostgreSQL usefield.temporal.timestamptz(p)(orfield.temporal.timestamptzString(p)), or the bareTimestamptz(p)type. -
Repoint any codec id you wrote by hand. Ids appear in raw-lane return declarations (
db.raw.sql`now()`.returns('pg/timestamptz@1')), inprepare({ id }), and in hand-built contracts. A retired id no longer resolves and fails contract validation rather than degrading silently. -
Re-emit every contract.
prisma contract emitrewritescontract.jsonandcontract.d.tstogether; the generated application types are where the new representation becomes visible. Commit the regenerated artifacts. A contract emitted before this release references a codec the registry cannot resolve and is rejected at runtime. -
Provide a Temporal implementation if you kept any Temporal-backed column. Prisma bundles no polyfill. Where the runtime has no native
Temporal, install a global one in your entry point before any query runs —import 'temporal-polyfill/full/global';. Takefull/global, notglobal: the default build omits non-ISO calendars and its published types resolve toexport {}, so TypeScript will not see the namespace. Every read of a Temporal-backed column needs it, and so does any insert into a table carryingtemporal.updatedAt(), whose generated value is aTemporal.Instant. Without it the operation fails withRUNTIME.TEMPORAL_UNAVAILABLE, which names the codec and recommends the matching*Stringtype. A contract whose temporal columns are all*Stringneeds no Temporal anywhere. -
Update application code that consumed a
Date.Temporal.Instant.from()parses only an ISO string carrying an offset — it throws on aDate, on an epoch-millisecond number, and on a date-time string with no offset. Convert by source:You have Use a Dateinstant = date.toTemporalInstant(), orTemporal.Instant.fromEpochMilliseconds(date.getTime())epoch milliseconds Temporal.Instant.fromEpochMilliseconds(ms)an ISO string with an offset ( …Z,…+02:00)Temporal.Instant.from(text)an ISO string without an offset pick the zone it meant: Temporal.PlainDateTime.from(text).toZonedDateTime('UTC').toInstant()"now" Temporal.Now.instant()Match the column, not just the type name: a
datecolumn takes aTemporal.PlainDate(Temporal.PlainDate.from('2024-01-01')), atimestampcolumn aTemporal.PlainDateTime, atimecolumn aTemporal.PlainTime. Onlytimestamptztakes anInstant.Temporal.Instant.compare(a, b)replacesa.getTime() - b.getTime(), but both operands must already beInstants — it throws on aDate. Values read back from the ORM already are; convert anything you brought from elsewhere first.In tests, be careful with
toMatchObject. A Temporal value has no own enumerable properties — every accessor lives on the prototype — so a subset matcher finds nothing to compare and passes for any value of the same type.toEqualis not affected (Vitest compares these correctly), buttoMatchObjectwill silently stop checking the timestamp. Where you need a subset match, comparetoString()or use the type's ownequals/compare. detection: glob: "**/*.{ts,mts,cts,prisma,json}" regex: - "pg/(date|timestamp|timestamptz|time)@1" - "sql/timestamp@1" - "field\.timestamp\(" anyMatch: true
-
-
id: literal-default-needs-the-string-spelling summary: | A literal
@default(...)on a Temporal-backed temporal column cannot be emitted today. The default value is encoded through the column's codec while the contract is being emitted, inside the CLI's own process, and stock Node ships noTemporal. SooccurredAt Timestamptz @default("2024-01-01T00:00:00Z")fails
prisma contract emitwithCONTRACT.SOURCE_LOAD_FAILEDand "this runtime has no global Temporal implementation".Use the string spelling for a column that needs a literal default:
occurredAt TimestamptzString @default("2024-01-01T00:00:00Z")Function defaults are unaffected —
@default(now())lowers to a PostgreSQLnow()storage default, never passes through a codec, and works on either representation. detection: glob: "**/*.prisma" regex: - "(Date|Timestamp|Timestamptz|Time)(\([0-9]+\))?\s+@default\("" anyMatch: true -
id: orm-init-no-longer-installs-agent-skills summary: |
prisma orm initno longer installs agent skills: the GitHub fetch (npx skills add) is removed and nothing insideorm initreplaces it. Agent-skills setup belongs to the family-levelprisma initcommand. The--skip-skillsflag is removed with the behavior it opted out of. Existing projects keep whatever skills they already have; only scripts that invokeorm initand expect it to deliver skills (or pass--skip-skills) need to change. detection: glob: "**/*.{sh,yml,yaml,json,md}" regex: - '\borm\s+init\b' anyMatch: true -
id: contract-artifacts-restamp summary: | The emitted
contract.json/contract.d.tsembed the toolchain version, which moves to 8.0.0-rc.6. Runcontract emitonce after upgrading so the emitted artifacts match the installed toolchain. The restamp is independent of the other changes in this release. detection: glob: "**/contract.json" contains: - '"version": "8.0.0-rc.5"'
8.0.0-rc.5 → 8.0.0-rc.6 — User upgrade instructions
PostgreSQL temporal representations
Both entries are schema-and-code renames; there is no codemod, because the choice between the
Temporal and the string representation is per column and only you know which values a column
holds. Work through the schema first, re-emit, then let the generated contract.d.ts types drive
the application-code changes — the compiler will point at every site whose value type moved.
Two behaviours are worth knowing before you choose. A Temporal codec rejects what Temporal cannot
denote — infinity, years beyond roughly ±271821, and output rendered under a non-ISO DateStyle —
naming the *String type that reads the same column losslessly. And a nested read returns the same
text a flat read does, because temporal expressions are cast to text before PostgreSQL builds the
JSON, which means both reflect the session TimeZone.
orm-init-no-longer-installs-agent-skills
Nothing to change in an existing project: skills already on disk stay as they are. Walk every orm init invocation the detection finds (a mention in prose that is not a command needs no action):
- An invocation passing
--skip-skills: drop the flag — it no longer exists and the invocation fails with an unknown-flag error. The behavior it opted out of is gone, so the flagless invocation is the equivalent. - A plain invocation with no flag: the scaffold itself is unchanged, but it no longer installs agent skills. If the script (or the person following it) relied on that, run
prisma initin the project afterwards; that command owns skills setup now. If skills were incidental, no change is needed.
contract-artifacts-restamp
For every contract.json matched by detection, run the project's emit command (prisma contract emit, or the project's contract:emit script) once after upgrading. The only expected diff is the embedded version moving to 8.0.0-rc.6.