MS Prisma Guide - PROCEED-Labs/proceed GitHub Wiki
Prisma Guide
Table of Contents
- Introduction
- Installation
- Essential Prisma Commands
- Prisma Schema
- Data Modeling
- Prisma Migrations
- Prisma Client
Introduction
Prisma is a next-generation ORM (Object-Relational Mapping) that simplifies database workflows for application developers. It consists of three main tools:
- Prisma Client: Auto-generated and type-safe query builder for Node.js & TypeScript
- Prisma Migrate: Declarative data modeling & migration system
- Prisma Studio: GUI to view and edit data in your database
Installation
Install Prisma and Prism Client: Prisma Client is an auto-generated database client that's tailored to your database schema
yarn add prisma --dev
yarn add @prisma/client
Essential Prisma Commands
-
Initialize Prisma in your project:
npx prisma initThis creates a
prismadirectory with aschema.prismafile and a.envfile. -
Generate Prisma Client after schema changes:
npx prisma generateThis updates the Prisma Client API based on your schema.
-
Create and apply a migration:
npx prisma migrate dev --name initThis creates a new migration based on your schema changes and applies it to your database.
-
Open Prisma Studio (GUI to view and edit data):
npx prisma studio
Prisma Schema
The Prisma schema file (schema.prisma) is the main configuration file for your Prisma setup. It contains three main parts:
- Data source: Specifies your database connection
- Generator: Indicates that you want to generate Prisma Client
- Data model: Defines your application models
Example:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
Data Modeling
In your schema.prisma file, you can define various types of relations between models.
Foreign Key Relations
Foreign key relations in Prisma are defined using the @relation attribute.
model User {
id String @id @default(uuid())
firstName String?
lastName String?
email String? @unique
systemAdmin SystemAdmin? @relation("systemAdmin")
}
model SystemAdmin {
id String @id @default(uuid())
role String @default("admin")
user User @relation(name: "systemAdmin", fields: [userId], references: [id])
userId String @unique
}
Explanation:
- The
@relationattribute establishes the foreign key relation betweenUserandSystemAdmin. fields: [userId]specifies thatuserIdinSystemAdminholds the foreign key.references: [id]indicates thatuserIdreferences theidfield inUser.- The
@uniqueconstraint onuserIdensures a one-to-one relationship. - The
name: "systemAdmin"parameter gives a name to this specific relation, which is useful when you have multiple relations between the same models.
One-to-One Relations
A one-to-one relation means that one record in a model is associated with exactly one record in another model.
model User {
id String @id @default(uuid())
systemAdmin SystemAdmin? @relation("systemAdmin")
}
model SystemAdmin {
id String @id @default(uuid())
user User @relation(name: "systemAdmin", fields: [userId], references: [id])
userId String @unique
}
Explanation:
- Each
Usercan have at most oneSystemAdminprofile. - Each
SystemAdminbelongs to exactly oneUser. - The
@uniqueconstraint onuserIdin theSystemAdminmodel ensures the one-to-one relationship. - The
?afterSystemAdminin theUsermodel makes it optional, allowing users without admin privileges.
One-to-Many Relations
In a one-to-many relation, one record in a model can be associated with multiple records in another model.
model User {
id String @id @default(uuid())
processes Process[]
}
model Process {
id String @id @default(uuid())
name String
owner User? @relation(fields: [ownerId], references: [id], onDelete: Cascade)
ownerId String
}
Explanation:
- The
Usermodel has aprocessesfield of typeProcess[], indicating that a user can have multiple processes. - The
Processmodel has anownerfield and anownerIdfield for the foreign key. - The
@relationinProcessestablishes the many-to-one relationship withUser. - The
onDelete: Cascadeoption means that if aUseris deleted, all associatedProcessrecords will also be deleted.
Many-to-Many Relations
A many-to-many relation allows multiple records in one model to be associated with multiple records in another model.
model User {
id String @id @default(uuid())
memberIn Membership[]
}
model Space {
id String @id @default(uuid())
name String?
members Membership[]
}
model Membership {
id String @id @default(uuid())
userId String
environmentId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
space Space @relation(fields: [environmentId], references: [id], onDelete: Cascade)
}
Explanation:
- This is an example of a many-to-many relation implemented with an explicit join model (
Membership). - A
Usercan be a member of multipleSpaces, and aSpacecan have multipleUsermembers. - The
Membershipmodel serves as a join table, connectingUserandSpace. - Both
UserandSpacehave a field referencing an array ofMembership. - The
Membershipmodel has foreign keys to bothUserandSpace. - The
onDelete: Cascadeoption ensures that when aUserorSpaceis deleted, the correspondingMembershiprecords are also deleted.
Self-Relations
Self-relations are used when a model needs to reference itself, typically to represent hierarchical data structures.
model Folder {
id String @id @default(uuid())
name String
description String
parentFolder Folder? @relation("parent-child", fields: [parentId], references: [id], onDelete: Cascade)
parentId String?
childrenFolder Folder[] @relation("parent-child")
space Space @relation(fields: [environmentId], references: [id], onDelete: Cascade)
environmentId String
processes Process[]
}
Explanation:
- This
Foldermodel has a self-relation to represent a folder hierarchy. - The
parentFolderfield references anotherFolder, representing the parent folder. parentIdis the foreign key that stores the ID of the parent folder.- The
childrenFolderfield is an array ofFolder, representing subfolders. - Both
parentFolderandchildrenFolderuse the same relation name "folderChildren", creating a two-way relationship. parentIdis optional (String?), allowing for top-level folders that don't have a parent.- The
onDelete: Cascadeoption means that when a parent folder is deleted, all its subfolders are also deleted.
Migrations
Prisma Migrate helps you manage database schemas: Once you have created or made any changes to the schema, apply it to the db
-
Create a migration:
npx prisma migrate dev --name init -
Apply migrations to your database:
npx prisma migrate deploy
Prisma Client
Prisma Client is an auto-generated, type-safe query builder.
-
Generate Prisma Client:
npx prisma generate -
Use Prisma Client in your code:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// use `prisma` in your application to read and write data in your DB
CRUD Operations
Here are some basic CRUD operations using Prisma Client:
// Create
const newUser = await prisma.user.create({
data: {
email: '[email protected]',
name: 'Alice',
},
})
// Read
const user = await prisma.user.findUnique({
where: {
email: '[email protected]',
},
select: {
name:true
}
})
// Update
const updatedUser = await prisma.user.update({
where: {
email: '[email protected]',
},
data: {
name: 'Alicia',
},
})
// Delete
const deletedUser = await prisma.user.delete({
where: {
email: '[email protected]',
},
})
For more detailed information, always refer to the official Prisma documentation.