Skip to content

v0.16.0

Latest

Choose a tag to compare

@github-actions github-actions released this 21 Jul 12:50
Immutable release. Only release title and notes can be modified.
8a17d51

v0.16.0

This release makes contract infer output round-trip cleanly through contract emit, materializes foreign keys and indexes as discrete contract entities, fixes the first-run experience of the Supabase extension end to end, and adds per-codec temporal presets that spell column type and auto-update behavior together.

Breaking changes

  • Foreign keys and indexes are discrete contract entitiescontract emit now materializes each foreign key's constraint/index authoring booleans into separate persisted entities: a foreignKeys[] entry is the referential constraint only, and every backing index (including one backing a foreign key) is its own named indexes[] entry. The authoring surface is unchanged (@relation(index:), TS fk({ constraint, index }), foreignKeyDefaults), and re-running contract emit regenerates the new shape with no source change. TypeScript that read .constraint / .index off a contract's foreignKeys[] entry must read the discrete indexes[] entry instead. No migration or DDL change — the schema the planner and db verify derive is identical. See the 0.15-to-0.16 upgrade recipe and the extension-author recipe. (#989)

    Before:

    "foreignKeys": [ { "source": { "columns": ["user_id"] }, ..., "constraint": true, "index": true } ],
    "indexes": []

    After:

    "foreignKeys": [ { "source": { "columns": ["user_id"] }, ... } ],
    "indexes": [ { "columns": ["user_id"], "name": "identities_user_id_idx" } ]
  • A singular back-relation over a non-unique foreign key is rejected at emit — a schema declaring a 1:1 relation whose foreign-key columns are not covered by a unique constraint previously emitted a contract claiming a guarantee the database cannot enforce. Emit now fails with PSL_NON_UNIQUE_BACKRELATION; add @unique/@@unique to the foreign-key fields, or make the back-relation field a list. (#1015)

    Before (accepted, emitted cardinality: '1:1'):

    model Profile {
      id     Int  @id
      userId Int              // no @unique
      user   User @relation(fields: [userId], references: [id])
    }
    
    model User {
      id      Int      @id
      profile Profile?
    }

    After: the same schema fails emit with PSL_NON_UNIQUE_BACKRELATION. Add @unique to userId (or make profile a Profile[] list).

  • contract infer declares identity-column defaults, and db verify --strict now sees them — infer emits @default(autoincrement()) for a Postgres GENERATED ... AS IDENTITY column (previously nothing), and db verify introspecting a live identity column resolves its default to autoincrement() too. If you run db verify --strict against a table with an identity column whose contract predates this fix, verify reports that default as an unexpected extra — re-run contract infer for the affected table, or add @default(autoincrement()) by hand. Without --strict, nothing changes. (#1011)

  • contract infer back-relation names no longer double-pluralize — the hand-rolled pluralization rule turned already-plural table names into sessionses; infer now uses real inflection (sessions stays sessions, status still becomes statuses). Already-generated .prisma files are untouched, but the next contract infer run against a database with already-plural table names renames the affected back-relation fields — public field names your code reaches via .include()/.select() and the generated types — so diff the regenerated file and update call sites. (#1011)

  • @prisma-next/extension-supabase no longer exports ./test/utils — the bootstrapSupabaseShim subpath typechecked but never worked from npm (it reads fixture files that were never published, so every call failed with ENOENT). Delete the import and any test setup that called it. (#997)

Features

  • Per-codec temporal presets carry execution-default behavior as arguments, so a column's exact type and its auto-update behavior can finally be spelled together — e.g. the timestamp(3) columns Prisma ORM migrations generate for @updatedAt. temporal.updatedAt() survives as shorthand for temporal.timestamptz(onCreate: now, onUpdate: now). (#1003)

    model Page {
      updatedAt temporal.timestamp(3, onCreate: now, onUpdate: now)
      lastSeen  temporal.timestamp(3)
      touched   temporal.timestamptz(onUpdate: now)
    }
  • The Postgres target registers its built-in index types (btree, hash, gin, gist, spgist, brin), so @@index(..., type: "gin") — which contract infer already printed — now emits instead of throwing unregistered index type. (#1011)

Fixes

  • Using @prisma-next/extension-supabase against a stock Supabase project now works first-try: generated migrations for RLS contracts import, typecheck, and run (RLS operations render as methods on the migration base class); migrate's remediation for a missing extension-space migration works when followed verbatim; db verify no longer reports phantom missing constraints; db.asUser(jwt) supports the ES256/JWKS signing current Supabase uses; and db.asServiceRole() queries succeed with the grants a real project provides. (#997)
  • More contract infer round-trip fixes: a plain Decimal field on Postgres no longer throws CODEC_PARAMETERIZATION_MISMATCH at connect, the 1:1 back-relation shape infer prints is accepted by emit, literal-shaped dbgenerated(...) defaults compare equal in db verify instead of reporting permanent drift, and foreign keys pointing outside the introspected scope are explained in infer's output instead of vanishing silently. (#1011)
  • MTI variant-narrowed updateCount, deleteCount, and include-backed deleteAll now compile their predicates through a correlated subquery that joins the variant table — previously the generated SQL could reference the variant table without it being in scope. (#940)
  • An explicit .select(...) on a polymorphic query or include now restricts MTI variant fields to the selection; unselected variant fields no longer leak into results. Omitting the selection keeps the full default shape. (#984)
  • The language server surfaces config-load failures as a diagnostic on the config file (PRISMA_NEXT_CONFIG_LOAD_FAILED) and keeps serving schema diagnostics from the last working configuration when a reload fails, instead of silently wiping every marker. (#974)
  • Migration operations are now ordered by a dependency graph over schema-diff issues instead of a hand-maintained per-kind integer table, fixing drop-order defects (e.g. a column dropping before its own constraint). For code reading the migration-diff internals: SchemaDiffIssue.reason is removed — discriminate via the presence of expected/actual, or the issueOutcome helper from @prisma-next/framework-components/control. (#992)