Prisma For Beginers

Author: Priyank Rai Date: 20 Jun, 2024

About Prisma

It is an Open Source ORM for proivding full  type safety i.e with the help of @prisma/client the types can be leveraged in backend.

prisma/client can be used in any nodeJS or TypeScript environment or framework.

- Prisma provide declarative approach for the schema definition unlike query generators.

Getting Started

Getting started is simple and can be checked from prisma.io though i will be covering for NextJS using app directory.

 

1. Setting up NextJS

>  npx create-next-app@latest my-nextjs-prisma-app
>  cd my-nextjs-prisma-app

2.  Install prisma

> npm install prisma @prisma/cli --save-dev

3. Set Up Prisma
Initialize Prisma in your project. Prisma will create a prisma directory and generate some initial files:

> npx prisma init

4. Configure 'schema.prisma' file

datasource db {
  provider     = "sqlite"
  url          = env("DATABASE_URL")

}

A datasource determines how prisma ORM connect with your db.

In datasource block we define a filed called provider which contain name of database that we are going to use like: postgresql, mongodb ...

A prisma schema can only have one data source.

5. Sync The Schema With Database

After you define the schema and models -> translates to table or collection in terms of dbs. you can use below command to sync db with schema

> npx prisma db push

Data Base Schema

Schema defines how you wanna structure and map the data in the db

The default location for the prisma schema file is

./prisma/schema.prisma

./schema.prisma

Alternatively you can specify your own custom location in package.json

"prisma": {
  "schema": "db/schema.prisma"
}

Multi-File Prisma Schema

The directory that is created by npx prisma init i.e prisma directory can be used to create a new folder called schema and all other schema file can be nested like <your-file-name>.schema where replace <your-file-name> with fileName

my-app/
├─ ...
├─ prisma/
│  ├─ schema/
│  │  ├─ post.prisma
│  │  ├─ schema.prisma
│  │  ├─ user.prisma
├─ ...

 

Data Models In Prisma

In Data Models section we will gonna know about Models, Relations, Indexes and VIews

Models

Defining Models means Defining Tables or Collections in mongodb

In schema definition we define model i.e table which will have entity like Name,  Email,  id etc.. and also the data type of same with relation like

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?
  role    Role     @default(USER)
  posts   Post[]
  profile Profile?
}

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
  userId Int    @unique
}

model Post {
  id         Int        @id @default(autoincrement())
  createdAt  DateTime   @default(now())
  updatedAt  DateTime   @updatedAt
  title      String
  published  Boolean    @default(false)
  author     User       @relation(fields: [authorId], references: [id])
  authorId   Int
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[]
}

enum Role {
  USER
  ADMIN
}
// From the above code fragment we can see there is mode
model table_name {

Email  String  @unique

RollNo Int @unique @id @default(autoincrement())

}

so in above example fileds look like

Entity_Name  Data_Type Attributes

NOTE: In General PascalCase naming in models  like model StudentData might not translate directly to table name.

There is a way out to control the table name manually using @@map(NAME_OF_TABLE)

model StudentInformation {
  // Fields

  @@map("student_information")
}

 

Fields

The properties of models are called fields.

Structured as:

FieldName        Field_Type            Optional_Modifiers&_Attributes

for ex:

Email                 String                     @unique

Field Types

All the fields types fall into 2 categories:

- Scalar Types

- Relational Types

1. Scalar Types:  There are the types provided by database or mapped to native database types.

2. Relational Types

These are the types which have it's type as another model

i.e a Company Model having field called Employee will have type Employee which will refer to Model Employee.

Prisma also support Native Types Provided by database

example:

model Post {
  id      Int    @id
  title   String @db.VarChar(200)
  content String
}

Type Modifiers :

  • [] Make a field a list
  • ? Make a field optional

Scalar List:

List help in storing list of items of modes like

// Post Field Inside User will
model User {

post Post\[\] // list of posts

}

NOTE: Every Filed Data is mandatory untill type have ? -> representing optional field. Default value of optional field is null.

There is possibility of encountering unsupported type in prisma. You can create unsupported type during introspection of db. or pulling pre-created schema from db

You will find something like unsupported("TYPE_NAME") for example

positions Unsupported("circle")

location Unsupported("POLYGON")?

Defining Attributes

Attributes are used to modify the behaviour of fields and model block.

example includes:

@id -> used to create primary_field.

@default -> used to create default value of scalar fields

@unique ->

In an relational db. If a model does not have an @id @@id ,It is mandatory to define a @unique or @@unique block.

In non-relational like mongoDB

or you can define primary key as combination of model fields.

model User {
  firstName String
  lastName  String
  email     String  @unique
  isAdmin   Boolean @default(false)

  @@id(name: "fullName", fields: [firstName, lastName])
}

 Defining an Index:

You can define index on one or multiple filed

model Post {
  id      Int     @id @default(autoincrement())
  title   String
  content String?

  @@index([title, content])
}

 Enums:

It is scalar data type in prisma , enums are defined via enum block for example user has a role

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  role  Role    @default(USER)
}

enum Role {
  USER
  ADMIN
}

Composite Types :

We can define the type for emmbeded document

model Product {
  id     String  @id @default(auto()) @map("_id") @db.ObjectId
  name   String
  photos Photo[]
}

type Photo {
  height Int
  width  Int
  url    String
}

Functions for prisma models.

Prisma schema supports multiple function that enhances functionality

like

autoincrement() -> autoincrement the value

now() -> return the value of current time.

uuid() and cuid() for the id generator.

these are the functions implemented at database level.

Queries in Prisma

queries help us in interaction with the db and perform crud operation

The list of available crude queries:

 

Relations In Prisma

Relation is a connection between two models in the prisma schema.

relation can be one -> one a Employee can have designation

one-> many   a user can have multiple post

many -> one a posts can have users tagged

example: one -> many relation b/w user and posts

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int // relation scalar field  (used in the `@relation` attribute above)
}

in the above example user have posts field of type mode i.e Post Model means it will store list of posts

In model post field author is defined as relation using @relation(fields:[authorId], refrence: [id]) means ultimately authorId will hold model User having field id

Ultimately relation author will not be appearing as field in database rather cosider it a way for defining foreign key.

Types of realations:

1. one - one

model User {
  id      Int      @id @default(autoincrement())
  profile Profile?
}

model Profile {
  id     Int  @id @default(autoincrement())
  user   User @relation(fields: [userId], references: [id])
  userId Int  @unique // relation scalar field (used in the `@relation` attribute above)
}

2. one- many

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}

 

3 many - many

model Post {
  id         Int        @id @default(autoincrement())
  title      String
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[]
}

Referential Action in Prisma

These are the policy that determine how the prisma should handle referenced record in update or delete query.

There are 2 refrential action

- onDelete

- onUpdate

and they can have values as Cascade Restrict NoAction SetNull SetDefault

Referential actions are defined in the @realation() attribute and maps to foreign key constraint.

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
  authorId Int
}

model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

CASCADE:

If the user is deleted their referenced post will be deleted and if user.id is update post authorId which is refrenced from User Model will be updated as well.

RESTRICT:

It will prevent Model which will have referenced field to be deleted or updated untill and unless referenced model itself is not exist in db.

NOACTION: will folllow db default behaviour.

SETNULL:

When deleting a User, the authorId will be set to NULL for all its authored posts.

When changing a User's id, the authorId will be set to NULL for all its authored posts.

 What's Next: Learn about prisma client to explore how to leverage query for efficient CRUD and data filtering.