Today, we are issuing the twenty-fourth Preview release: 2.0.0-preview024
(short: preview024
).
Major improvements
Reduced size of Prisma Client & Azure functions support
This release contains major improvements for Prisma Client. It now supports Windows Azure functions. In addition to that, the generated Prisma Client code inside your node_modules
directory now is a lot smaller.
Another improvement is a better debugging experience. When setting the DEBUG
environment variable (e.g. with export DEBUG="*"
), the logging output now contains the names of Prisma Client API calls.
Use relation fields as ID on a Prisma model
In this release, it's now possible to use relation fields of Prisma models as IDs. In "database-speak", this means that you can now have both a primary key and a foreign key constraint on the same column.
Reference a single-field ID
For example, a Movie
could always be identified by its Director
:
model Movie {
director Director @id
title String
}
model Director {
id Int @id @default(@autoincrement())
name String
}
This is what the corresponding SQL (in SQLite dialect) looks like:
CREATE TABLE "Movie" (
"director" INTEGER NOT NULL ,
"title" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("director"),
FOREIGN KEY ("director") REFERENCES "Director"("id")
);
CREATE TABLE "Director" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL DEFAULT ''
);
<details><summary>Expand to view an example for creating Movie
s and Director
s in Prisma Client</summary>
Nested write to create Movie
with Director
:
// Run inside `async` function
const movie = await prisma.movie.create({
data: {
title: "Hello World",
director: {
create: {
name: "Alice"
}
}
},
})
Nested write to create Director
with Movie
:
// Run inside `async` function
const director = await prisma.director.create({
data: {
name: "Bob",
movies: {
create: [{
title: "Hello World"
}]
}
},
})
</details>
Reference a multi-field ID
You can also create a relation to a multi-field ID:
model Movie {
director Director @id @map(["firstName", "lastName"])
title String
}
model Director {
firstName String
lastName String
@@id([firstName, lastName])
}
Note that in this case, the Movie
table in the underlying database will actually have two physical columns called firstName
and lastName
. These are referencing the respective firstName
and lastName
column on the Director
table.
Here is what the above models correspond to in SQL:
CREATE TABLE "Movie" (
"firstName" TEXT NOT NULL ,
"lastName" TEXT NOT NULL ,
"title" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("firstName","lastName"),
FOREIGN KEY ("firstName","lastName") REFERENCES "Director"("firstName","lastName")
);
CREATE TABLE "Director" (
"firstName" TEXT NOT NULL DEFAULT '' ,
"lastName" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("firstName","lastName")
);
In many cases, it might make sense to name the columns on Movie
differently. For example, they could be called directorFirstName
and directorLastName
. This can be achieved via adding the @map
attribute to the field:
model Movie {
director Director @id @map(["directorFirstName", "directorLastName"]) @relation(references: [firstName, lastName])
title String
}
model Director {
firstName String
lastName String
@@id([firstName, lastName])
}
Note that in this case you could also omit the @relation
attribute, the result would be the same:
model Movie {
director Director @id @map(["directorFirstName", "directorLastName"])
title String
}
model Director {
firstName String
lastName String
@@id([firstName, lastName])
}
In this case, the field names in @map
on Movie
get matched with the field names in @@id
on Director
.
Both cases correspond to the following SQL:
CREATE TABLE "Movie" (
"directorFirstName" TEXT NOT NULL ,
"directorLastName" TEXT NOT NULL ,
"title" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("directorFirstName","directorLastName"),
FOREIGN KEY ("directorFirstName","directorLastName") REFERENCES "Director"("firstName","lastName")
);
CREATE TABLE "Director" (
"firstName" TEXT NOT NULL DEFAULT '' ,
"lastName" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("firstName","lastName")
);
<details><summary>Expand to view an example for creating Movie
s and Director
s in Prisma Client</summary>
Nested write to create Movie
with Director
:
// Run inside `async` function
const movie = await prisma.movie.create({
data: {
title: 'Hello World',
director: {
create: {
firstName: 'Alice',
lastName: 'Allen',
},
},
},
})
Nested write to create Director
with Movie
:
// Run inside `async` function
const director = await prisma.director.create({
data: {
firstName: 'Bob',
lastName: 'Nolan',
movies: {
create: [
{
title: 'Hello World',
},
],
},
},
})
</details>
Multi-field ID with a relation field (which targets a model with a single-field ID)
You can also create a multi-field ID on a model that contains a relation field:
model Movie {
director Director
title String
@@id([director, title])
}
model Director {
id String @id @default(cuid())
name String
}
This corresponds to the following SQL:
CREATE TABLE "Movie" (
"director" TEXT NOT NULL ,
"title" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("director","title"),
FOREIGN KEY ("director") REFERENCES "Director"("id")
);
CREATE TABLE "Director" (
"id" TEXT NOT NULL ,
"name" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("id")
);
<details><summary>Expand to view an example for creating Movie
s and Director
s in Prisma Client</summary>
Nested write to create Movie
with Director
:
// Run inside `async` function
const movie = await prisma.movie.create({
data: {
title: 'Hello World',
director: {
create: {
name: 'Alice',
},
},
},
})
Nested write to create Director
with Movie
:
// Run inside `async` function
const director = await prisma.director.create({
data: {
name: 'Bob',
movies: {
create: [
{
title: 'Hello World 2',
},
],
},
},
})
</details>
Multi-field ID with a relation field (which targets a model with a multi-field ID)
You can also define a multi-field ID on a model which contains a relation field that targets a model with a multi-field ID:
model Movie {
director Director
title String
@@id([director, title])
}
model Director {
firstName String
lastName String
@@id([firstName, lastName])
}
This is what the above code translates to in SQL:
CREATE TABLE "Movie" (
"director_firstName" TEXT NOT NULL ,
"director_lastName" TEXT NOT NULL ,
"title" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("director_firstName","director_lastName","title"),
FOREIGN KEY ("director_firstName","director_lastName") REFERENCES "Director"("firstName","lastName")
);
CREATE TABLE "Director" (
"firstName" TEXT NOT NULL DEFAULT '' ,
"lastName" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("firstName","lastName")
);
Similar to the case before, you can also give names to the added columns on Movie
by using the @map
attributed:
model Movie {
director Director @map(["directorFirstName", "directorLastName"]) @relation(references: [firstName, lastName])
title String
@@id([director, title])
}
model Director {
firstName String
lastName String
@@id([firstName, lastName])
}
And as before you can also omit the @relation
attribute in this scenario:
model Movie {
director Director @map(["directorFirstName", "directorLastName"])
title String
@@id([director, title])
}
model Director {
firstName String
lastName String
@@id([firstName, lastName])
}
In both cases, the models correspond to the following tables:
CREATE TABLE "Movie" (
"directorFirstName" TEXT NOT NULL ,
"directorLastName" TEXT NOT NULL ,
"title" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("directorFirstName","directorLastName","title"),
FOREIGN KEY ("directorFirstName","directorLastName") REFERENCES "Director"("firstName","lastName")
);
CREATE TABLE "Director" (
"firstName" TEXT NOT NULL DEFAULT '' ,
"lastName" TEXT NOT NULL DEFAULT '' ,
PRIMARY KEY ("firstName","lastName")
);
<details><summary>Expand to view an example for creating Movie
s and Director
s in Prisma Client</summary>
Nested write to create Movie
with Director
:
// Run inside `async` function
const movie = await prisma.movie.create({
data: {
title: 'Hello World',
director: {
create: {
firstName: 'Alice',
lastName: 'Allen',
},
},
},
})
Nested write to create Director
with Movie
:
// Run inside `async` function
const director = await prisma.director.create({
data: {
firstName: 'Bob',
lastName: 'Nolan',
movies: {
create: [
{
title: 'Hello World',
},
],
},
},
})
</details>
Breaking changes
MODELGetSelectPayload
and MODELGetIncludePayload
have been merged into MODELGetPayload
. More info here.
Fixes and improvements per Prisma 2 repository
prisma2
migrate
prisma-client-js
prisma-engines