Creating Seeding with Prisma

melihs

Melih Şahin

Posted on February 5, 2024

Creating Seeding with Prisma

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
Enter fullscreen mode Exit fullscreen mode

Image description

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

**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[]
}
Enter fullscreen mode Exit fullscreen mode

c. Then we use the following command to create these tables:

npx prisma db push
Enter fullscreen mode Exit fullscreen mode

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);
  });
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
  });
Enter fullscreen mode Exit fullscreen mode

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"
  },
Enter fullscreen mode Exit fullscreen mode

Finally, let's run the command to create our data.

npm run db-seed
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

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 👋🏻

💖 💪 🙅 🚩
melihs
Melih Şahin

Posted on February 5, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Creating Seeding with Prisma
prisma Creating Seeding with Prisma

February 5, 2024