Hello,
In this article, I will try to explain how to create basic data using Prisma ORM while developing a full-stack application with Next.js.
What is Prisma and what does it do?
"Prisma" is a modern and powerful ORM (Object-Relational Mapping) tool that provides developers with ease in managing and querying database operations. In short, its features
include:
- Database Models
- Relationship Establishment (Relations)
- Query Creation
- Database Connection
- TypeScript Support
- Migration Management
What is Seeding and what is its purpose?
"Seeding" refers to adding initial data to the database or populating the database with sample data. This process involves adding default or sample data to database tables that can be used during the development, testing, or initial stages of an application. Seeding ensures the necessary database content for an application to function correctly and be tested.
Used in the sample project:
Framework: Next js
Database: PostgreSQL
ORM: Prisma
Project setup
Since our topic is seeding, I will not talk about application setup and database connection processes too much.
1. Next js installation:
npx create-next-app@latest
2. Install Prisma and other packages:
npm i prisma --save-dev
npm i @prisma/client
npx prisma // you can use prisma cli via this command
npm i lodash
npm i @faker-js/faker --save-dev
npm i bcrypt
3. Database creation and setup:
a. Assuming that a PostgreSQL database is installed on our computer, let's create a database named example_db. Then create an .env file in our project and add the database connection url here.
DATABASE_URL="postgresql://postgres:@localhost:5432/example_db?schema=public"
**b. **Create a folder called prisma
in the project main directory and create a model file called schema.prisma
in it. This file is where we define our database tables.
schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @db.VarChar(255)
content String @db.VarChar(255)
User User @relation(fields: [userId], references: [id])
userId Int
}
model User {
id Int @id @default(autoincrement())
email String @unique
createdAt DateTime @default(now())
name String @db.VarChar(255)
password String? @db.VarChar(255)
posts Post[]
}
c. Then we use the following command to create these tables:
npx prisma db push
If we check the database, we will see that the tables have been created.
4. Seed File Creation
Let's create a seed.ts file inside the prisma folder and create the basic structure.
seed.ts
export default PostSeed;
import {PrismaClient} from "@prisma/client";
const prisma = new PrismaClient();
const main = async () => {
...
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
Now let's create the seeder structure that we will define in the main() function. Here we will benefit from the power of Typescript. First, let's create an abstract class assuming that there will be more than one seeder file.
Seeder.ts
abstract class Seeder {
protected count: number; // decides how much data to generate
protected _data: any = []; // seed data
constructor(count: number) {
this.count = count;
}
protected abstract createData(): void; // function to generate the data
get data(): [] {
return this._data;
}
}
export default Seeder;
Now let's create our seed files for the related tables.
userSeed.ts
import bcrypt from "bcrypt";
import range from "lodash/range";
import { faker } from "@faker-js/faker";
import Seeder from "./Seeder";
class UserSeed extends Seeder {
constructor(count: number = 10) {
super(count);
this.count = count;
this.createData();
}
createData() {
range(this.count).forEach(() => {
this._data.push({
name: faker.person.firstName(),
createdAt: faker.date.anytime(),
email: faker.internet.email(),
password: bcrypt.hashSync("12345678", 10),
});
});
}
}
export default UserSeed;
postSeed.ts
import range from "lodash/range";
import { faker } from "@faker-js/faker";
import Seeder from "./Seeder";
class PostSeed extends Seeder {
constructor(count: number = 10) {
super(count);
this.count = count;
this.createData();
}
createData() {
range(this.count).forEach(() => {
this._data.push({
title: faker.lorem.sentence(),
createdAt: faker.date.anytime(),
updatedAt: faker.date.anytime(),
content: faker.lorem.sentence(),
});
});
}
}
export default PostSeed;
Let's go back to seed.ts and add the seeders we created.
seed.ts
import { Simulate } from "react-dom/test-utils";
import error = Simulate.error;
import { PrismaClient } from "@prisma/client";
import UserSeed from "./data/userSeed";
import PostSeed from "./data/postSeeder";
const prisma = new PrismaClient();
const main = async () => {
try {
await prisma.post.deleteMany();
await prisma.user.deleteMany();
const posts = new PostSeed();
const users = new UserSeed(3);
for (const user of users.data) {
await prisma.user.create({
data: {
...(user as any),
posts: {
create: posts.data,
},
},
});
}
console.log(`Database has been seeded. 🚀`);
} catch (e) {
throw error;
}
};
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
5. Add seed command
To run these seeders we created, we need to add a command to our package.json file. There are some issues to be considered here. For example, when doing this with the Next js project, there may be module insertion errors in the seed file. To prevent this, we need to add a "compiler-options" flag to the seed command. Thus, we will not get a module error when the process is triggered.
package.json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"db-seed": "prisma db seed"
},
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
},
Finally, let's run the command to create our data.
npm run db-seed
As can be seen here, we have successfully generated test data 😊.
You can access the source code of the project from this link github link
Hope to see you in the next article 👋🏻
Top comments (0)