Prisma: A next-gen ORM

Muhammad Waleed
8 min readNov 26, 2022

--

Prisma is an open-source ORM(Object-Relational Mapping) that makes it fun and safe to work with a database like MySQL, Postgres, SQL Server, or MongoDB. It generates a type-safe client library to provide an awesome Migrate DX in any Node.js or JavaScript project.

The relational database is an ancient technique to work with databases and that has stood the time of the test. SQL may have been used by many big organizations for a long time but it isn’t an ideal abstraction for modern application development. It provides too much low-level control that you’ll probably bang your face on your desk.

To solve this problem, many developers use classic ORM to SQL-ize and express data with object-oriented code like JavaScript or Python.

Prisma is also an ORM to solve the same problem but instead, it has its own declarative schema definition language or DDL(Data Definition Language). You can write a schema to express data and relationships in human-readable format or the schema can be automatically worked out with any existing database then Prisma converts the schema into type definition to perform CURD(Create, Update, Read, Delete) operation with your own database models. In addition, it also supports migration to migrate databases as your data structure evolves.

Prisma also provides an application to visualize your data which allows you to manage your tables in the browser.

Getting Started

To get started you’ll need a relational database like MySQL, Prestige database, or MongoDB. Initialize an app using,

npm init -y

If you haven’t installed Prisma then first write,

npm install prisma

Make sure that you have the Prisma extension installed in your IDE(VSCode),

Prisma Extension for VS Code

Then, on your IDE terminal write,

npx prisma init

It will create the following files in your current working directory,

Prisma Files

Head over to the Prisma directory to define the schema,

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

I’m using SQL Server so my data source will look something like this,

datasource db {
provider = "sqlserver"
url = env("DATABASE_URL")
}

For existing databases (having data), run

npx prisma dp pull

so it can automatically generate a schema from it.

Now define your models in schema.prisma file like,

model User {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(16)
email String @db.VarChar(56)
password String @db.VarChar(1024)
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(56)
slug String @db.VarChar(56)
post String @db.VarChar(225)
userId Int
user User @relation(fields: [userId], references: [id])
}

Notice how each table is represented with the model keyword, then inside braces, we have the column name and its data type as well as optional constraints like we have in SQL.

For example, we might use a relation to create a foreign key constraint between a user and a post.

You can see how our code is more significantly concise compared to traditional SQL.

If we decided to modify our schema like adding an extra timestamp column,

model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(56)
slug String @db.VarChar(56)
post String @db.VarChar(225)
userId Int
user User @relation(fields: [userId], references: [id])
timestamp DateTime @default(now())
}

We also need to modify our database structure which can be automatically handled with the Prisma migration,

npx prisma migrate dev
Prisma Migration

Now to interact with the database on the server, we tell Prisma to generate a client library (before generating the client, make sure you have defined the Database URL in .env file.),

npx prisma generate
Generate a Prisma client

Create an index.js file in the current working directory and import the client to interact with your database.

const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()

Create a user by writing an async function name createUser and

Prisma Queries Method Reference

const createUser = async () => {
const user = await prisma.user.create({
data: {
name: 'notwld',
email: 'notwld@gamil.com',
password: '123456',
}
})
return user
}

createUser().then((user)=> console.log(user))

Notice how it autocompletes the model in the schema, if you are writing something wrong it’ll let you know right away.

Output
Microsoft SQL Server Management Studio

Now, to find all the users we have created, write an async function named findUsers,

const findUsers = async () => {
const users = await prisma.user.findMany({})
return users
}

findUsers().then((users) => {
console.log(users)
})
Output

Create a blog using Prisma query which also allows users to perform join functions as well,

const createBlog = async () => {
const blog = await prisma.post.create({
data: {
title: 'salad adventures#01',
slug: 'salad goes to a park',
post: 'salad goes to a park and meets khalid',
user: {
connect: {
id: 1
}
}
}
})
return blog
}

createBlog().then((blog)=> console.log(blog))
Output
Microsoft SQL Server Management Studio

To get all posted blogs, write an async function name getAllBlogs,

const getAllBlogs = async () => {
const blogs = await prisma.post.findMany({
include: {
user: true
}
})
return blogs
}

getAllBlogs().then((blog) => console.log(blog))
Output

To get a blog by id,

const getBlogById = async () => {
const blog = await prisma.post.findUnique({
where: {
id: 1
},
include: {
user: true
}
})
return blog
}



createBlog().then((blog)=> console.log(blog))
Output

Or by user id,

const getAllBlogsByUserId = async () => {
const blogs = await prisma.user.findUnique({
where: {
id: 1
},
include: {
posts: {
include: {
user: false
}
}
}
})
return blogs
}

getAllBlogsByUserId().then((blog) => console.log(blog))
Output

Notice how I use the include keyword to filter out data, in the above queries I made the password visible for the sake of this article but in production, you might want to hide all these sensitive details, you can do that by using include or select keywords, Here the docs to read further about these keywords.

You can also update the data using an update query,

const updateBlog = async () => {
const blog = await prisma.post.update({
where: {
id: 1
},
data: {
title: 'salad adventures#02',
slug: 'salad goes to a park',
post: 'salad goes to a park and met khalid kashmiri',
}
})
return blog
}
updateBlog().then((blog) => console.log(blog))
Output

Similarly, to delete data using id we can write a query,

const deleteBlog = async () => {
const blog = await prisma.post.delete({
where: {
id: 3
}
})
return blog
}

deleteBlog().then((blog) => console.log(blog))
Output

(Note: All prisma queries returns a promise.)

Prisma knows how to execute complicated SQL under the hood and returns an array of JavaScript objects, ready to use in your application.

Conclusion:

Now that we have covered a few basics of Prisma, the question comes to our mind where to go from here? Well, Prisma has excellent documentation to get started with. Also, there are a lot of tutorials you can find on youtube about Prisma. After covering the fundamentals you can develop a full-stack application using Prisma as your ORM.

Good Luck with Learning!

Full Code:

//Path : prisma/schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "sqlserver"
url = env("DATABASE_URL")
}

model User {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(16)
email String @db.VarChar(56)
password String @db.VarChar(1024)
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(56)
slug String @db.VarChar(56)
post String @db.VarChar(225)
userId Int
user User @relation(fields: [userId], references: [id])
}

//Path : index.js

//Create a User

const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()

const createUser = async () => {
const user = await prisma.user.create({
data: {
name: 'notwld',
email: 'notwld@gamil.com',
password: '123456',
}
})
return user
}

createUser().then((user)=> console.log(user))

//Find all Users

const findUsers = async () => {
const users = await prisma.user.findMany({})
return users
}

findUsers().then((users) => {
console.log(users)
})

//Create a Blog

const createBlog = async () => {
const blog = await prisma.post.create({
data: {
title: 'salad adventures#01',
slug: 'salad goes to a park',
post: 'salad goes to a park and meets khalid',
user: {
connect: {
id: 1
}
}
}
})
return blog
}

createBlog().then((blog)=> console.log(blog))

//Find All Blogs

const getAllBlogs = async () => {
const blogs = await prisma.post.findMany({
include: {
user: true
}
})
return blogs
}

getAllBlogs().then((blog) => console.log(blog))

//Find a specifc Blog by an Id

const getBlogById = async () => {
const blog = await prisma.post.findUnique({
where: {
id: 1
},
include: {
user: true
}
})
return blog
}

createBlog().then((blog)=> console.log(blog))

//Find all Blogs posted by specific user

const getAllBlogsByUserId = async () => {
const blogs = await prisma.user.findUnique({
where: {
id: 1
},
include: {
posts: {
include: {
user: false
}
}
}
})
return blogs
}

getAllBlogsByUserId().then((blog) => console.log(blog))

//Update an existing Blog

const updateBlog = async () => {
const blog = await prisma.post.update({
where: {
id: 1
},
data: {
title: 'salad adventures#02',
slug: 'salad goes to a park',
post: 'salad goes to a park and met khalid kashmiri',
}
})
return blog
}
updateBlog().then((blog) => console.log(blog))

//Delete an existing Blog

const deleteBlog = async () => {
const blog = await prisma.post.delete({
where: {
id: 3
}
})
return blog
}

deleteBlog().then((blog) => console.log(blog))

--

--