Prisma: A next-gen ORM
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),
Then, on your IDE terminal write,
npx prisma init
It will create the following files in your current working directory,
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
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
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
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.
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)
})
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))
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))
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))
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))
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))
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))
(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))