Today, we are issuing the twenty-third Preview release: 2.0.0-preview023
(short: preview023
).
This release contains breaking changes, be sure to read the notes below before upgrading!
Breaking changes
Cursor-pagination API changed in Prisma Client
Because Prisma now supports composite unique constraints, the before
and after
API for cursor-pagination (which is based on unique fields) also changes. The cursor is now wrapped in an object which might have multiple fields.
Assume you have this Prisma model:
model Post {
id Int @default(autoincrement())
title String @unique
content String?
}
Before
const cursor = 42
const posts = await prisma.post.findMany({
after: cursor
})
After
const cursor = 42
const posts = await prisma.post.findMany({
after: { id: cursor }
})
Removed the enabled
property in datasource
blocks
The enabled
property was removed from the datasource
blocks.
Major improvements
In this issue, we're lifting a major limitation of Prisma which always required every model to have exactly one primary key constraint. In the Prisma schema, this primary key was represented using the @id
attribute.
With this release, you can now have tables:
- without primary keys (but unique constraints)
- with composite primary keys
- with composite unique constraints
Read below for more information on each of these new features. Lifting these limitations was a major effort, please be sure to report any bugs or other issues you encounter using these new features!
Allows models without IDs
In previous Prisma versions, there was a hard requirement that every model in your Prisma schema needed to have a single @id
field (which maps to a primary key constraint in the underlying database). This requirement is now lifted and your models don't need primary key constraints any more to be compatible with Prisma 2 (they do need at least one unique constraint though).
For example, this data model is now valid:
model Post {
title String @unique
content String?
published Boolean @default(false)
author User?
}
model User {
email String @unique
name String?
posts Post[]
}
Composite primary keys
As of this release, Prisma supports composite IDs (which map to multi-column primary key constraints in the underlying database). Composite IDs are defined on a "model-level" using the @@id
attribute. Here's an example:
model User {
firstName String
lastName String
email String
@@id([firstName, lastName])
}
This also impacts the Prisma Client API and how you're querying for single records, e.g. in findOne
, update
or delete
queries where you need to identify a record by its primary key (or another unique field). These queries take the following type as input:
export type UserWhereUniqueInput = {
firstName_lastName?: FirstNameLastNameCompoundUniqueInput | null
}
export type FirstNameLastNameCompoundUniqueInput = {
firstName: string
lastName: string
}
This means, in order to query for a User
record, you need to provide both firstName
and lastName
fields wrapped inside a firstName_lastName
object:
const user = await prisma.user.findOne({
where: {
firstName_lastName: {
firstName: "Jane",
lastName: "Doe"
}
}
})
Composite unique indexes / constraints
As of this release, Prisma also supports composite unique constraints (which map to multi-column unique constraints in the underlying database). Composite unique constraints are defined on a "model-level" using the @@unique
attribute.
Note: Primary key and unique constraints are very similar but have some differences on the database-level. You can learn more about the differences here.
Here's an example:
model User {
firstName String
lastName String
email String
@@unique([firstName, lastName])
}
This also impacts the Prisma Client API and how you're querying for single records, e.g. in findOne
, update
or delete
queries where you need to identify a record by its primary key (or another unique field). These queries take the following type as input:
export type UserWhereUniqueInput = {
firstName_lastName?: FirstNameLastNameCompoundUniqueInput | null
}
export type FirstNameLastNameCompoundUniqueInput = {
firstName: string
lastName: string
}
This means, in order to query for a User
record, you need to provide both firstName
and lastName
fields wrapped inside a firstName_lastName
object:
const user = await prisma.user.findOne({
where: {
firstName_lastName: {
firstName: "Jane",
lastName: "Doe"
}
}
})
Introspection now recognizes default constraints
Prisma's introspection now reconized DEFAULT
constraints that are defined on a column. These constraints are represented in the generated Prisma schema using the @default
attribute.
Optimize nested GraphQL queries that use Prisma Client ("dataloader")
When building a GraphQL server with Prisma Client, it wasn't easy to avoid the n+1 problem with nested queries. This release of Prisma Client optimizes the execution of GraphQL nested queries by batching requests against the database.
Fixes and improvements per Prisma 2 repository
prisma2
prisma-client-js
prisma-engines