52
loading...
This website collects cookies to deliver better user experience
While we will cover a lot of the cool options available to us when setting up a schema, I do recommend reading the docs to see everything Prisma has to offer.
All the things we cover will apply to the other available database providers as well, unless stated otherwise.
npm
inside of this project and install the prisma
package so we can put it to use!mkdir bookstore-project
cd bookstore-project
npm init
npm i --save prisma
postgres
database.prisma init --datasource-provider=postgresql
schema.prisma
file and we'll get started!docker-compose.yml
. Paste the following into the file:version: '3.1'
services:
db:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: example
ports:
- 5432:5432
adminer:
image: adminer
restart: always
ports:
- 8080:8080
DATABASE_URL="postgresql://postgres:example@localhost:5432/bookstore"
docker-compose up -d
Note: We added the -d flag at the end to run this in detached mode, freeing up our terminal for more commands
postgres
example
postgres
datasource
block, we can create a schema block with the type datasource
, some name (typically db
by convention), and its options.datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Database | Provider String |
---|---|
Postgres | postgresql |
MySQL | mysql |
SQLite | sqlite |
MSSQL | sqlserver |
MongoDB | mongodb |
process.env
for a variable called DATABASE_URL
to get the connection string.The env()
function allows us to access environment variables via dotenv-expand
. It can only be used in two places: the datasource url
field, and the generator binaryTargets
field.
url
option instead of using the env()
function.prisma generate
. You can configure multiple generators per schema, however by default Prisma sets up a single generator and specifies prisma-client-js
as the provider, which builds the Prisma Client
.generator client {
provider = "prisma-client-js"
}
Note the generator is named client
here, but that name could be anything
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
Refer to the docs for a full list of types and attributes
model Person {
id Int @id @default(autoincrement())
}
id
field. First we are letting prisma know that field is an @id
, which signifies this field is the unique identifier for data in this table. Each model needs to have a unique identifier.@default
attribute to specify that the default value for that field should be a number that increments for each row with the autoincrement()
function.Person
though. Let's add some more fields:model Person {
id Int @id @default(autoincrement())
firstName String
lastName String
email String @unique
age Int
updatedAt DateTime @updatedAt
}
@unique
attribute here to let prisma know the email field should be unique in that table. No persons should have the same email!@updatedAt
attribute, which will cause that column to automatically update with a current timestamp whenever the row of data updates. Fields using this attribute MUST be of type DateTime.Person
model. Let's move on to the Book
model.model Book {
title String
productId String
publishedDate DateTime
description String
}
title
and productId
fields that will be used as the Primary Key for this table.description
field to 150 chars by reaching in to Postgres's native types.model Book {
title String
productId String
publishedDate DateTime
description String @db.VarChar(150)
@@id([title, productId], name: "titleProduct")
}
@db
attribute to specify some of the native types available to whichever database provider we are using.title
and productId
. We've also passed it an optional name
parameter to name the compound ID. Otherwise it would be generated as just title_productId
. Subject
. To do this we'll set up an enum
, which is a feature available only to Postgres
, MySQL
, and MongoDB
.enum Subject {
GENERAL
HORROR
MYSTERY
ROMANCE
EDUCATIONAL
}
model Book {
title String
productId String
publishedDate DateTime
description String @db.VarChar(150)
subject Subject @default(GENERAL)
@@id([title, productId], name: "titleProduct")
}
Subject
. When creating a record in this table, if no value is provided for subject
, it will default to GENERAL
because we specified it in the @default
attribute.Author
model and relate it to the Book
model.model Author {
id Int @id @default(autoincrement())
firstName String
lastName String
birthTown String?
}
?
next to the String type on the birthTown
field. This is a type modifier that signifies the field is optional. model Author {
id Int @id @default(autoincrement())
firstName String
lastName String
birthTown String?
Books Book[]
}
Author
will have a potential list of Books
that are related to it. The field name can be anything, I chose Books
just to make it clear. And the type, as you'll notice, is Book
, which corresponds to our Book
model. The []
signifies that it will be an array of books.Book
model. So let's go back to our Book
model and make some adjustmentsmodel Book {
authorId Int
title String
productId String
publishedDate DateTime
description String @db.VarChar(150)
subject Subjects @default(GENERAL)
Author Author @relation(references: [id], fields: [authorId])
@@id([title, productId], name: "titleProduct")
}
authorId
field to the model that will be used to map to our Author
model.Author
field. This field (which could be named anything, I chose Author
for clarity) is of the type Author
. This type corresponds to our Author
model. Book
and Author
. references
option in the relation points to the field on the Author
model we want to match against. The fields
option points to the field on the Book
model that should match the reference field. And this field is not specified as an array, so we know a Book
will have one Author
.Author
and Book
!relation
between the BookLog
and Person
model.model Person {
<...other fields...>
log BookLog[]
}
model BookLog {
id Int @map("log_id") @id @default(autoincrement())
title String
productId String
checkInTime DateTime
checkOutTime DateTime @default(now())
personId Int
person Person @relation(fields: [personId], references: [id])
@@map("book_log")
}
log_id
, which we are using in our model as id
now()
function in its @default
definition. This will set the default value of that field to the timestamp when the record is createdbook_log
, but our model will be BookLog
.Book
model. This one will be a bit trickier though because the Book
model has a compound ID instead of a single primary key!model Book {
<...other fields...>
log BookLog[]
}
model BookLog {
id Int @id @default(autoincrement()) @map("log_id")
title String
productId String
checkInTime DateTime
checkOutTime DateTime @default(now())
personId Int
person Person @relation(fields: [personId], references: [id])
book Book @relation(fields: [title, productId], references: [title, productId])
@@map("book_log")
}
Book
model, we have specified that to match a book to a book log, the Book
table should be joined on the title
and productId
fields.As shown above, you will need to add a field on the opposite relation that defines an array of BookLog
records.
BookLog
table that will index queries using the id
and personId
fieldsmodel BookLog {
id Int @id @default(autoincrement()) @map("log_id")
title String
productId String
checkInTime DateTime
checkOutTime DateTime @default(now())
personId Int
person Person @relation(fields: [personId], references: [id])
book Book @relation(fields: [title, productId], references: [title, productId])
@@index([id, personId])
@@map("book_log")
}
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgres"
url = env("DATABASE_URL")
}
enum Subject {
GENERAL
HORROR
MYSTERY
ROMANCE
EDUCATIONAL
}
model Author {
id Int @id @default(autoincrement())
firstName String
lastName String
birthTown String?
Books Book[]
}
model Book {
authorId Int
title String
productId String
publishedDate DateTime
description String @db.VarChar(150)
subject Subject @default(GENERAL)
Author Author @relation(references: [id], fields: [authorId])
log BookLog[]
@@id([title, productId], name: "titleProduct")
@@unique([title, authorId])
}
model Person {
id Int @id @default(autoincrement())
firstName String
lastName String
dob DateTime @map("date_of_birth") @db.Date
email String @unique
age Int
updatedAt DateTime @updatedAt
log BookLog[]
}
model BookLog {
id Int @id @default(autoincrement()) @map("log_id")
title String
productId String
checkInTime DateTime
checkOutTime DateTime @default(now())
personId Int
person Person @relation(fields: [personId], references: [id])
book Book @relation(fields: [title, productId], references: [title, productId])
@@index([id, personId])
@@map("book_log")
}
Postgres
locally via Docker, feel free to run prisma db push
to build out your database tables on the actual database server. You can then view those tables via the admin view as described in the instructions above.