Guide to Seeding Mock Data for PostgreSQL Using Prisma and Snaplet Seed

Introduction

@snaplet/seed is a highly powerful library that supports automatic mock data generation for databases based on the Prisma schema. Instead of manually writing hundreds of lines of complex insert code, @snaplet/seed automatically analyzes relations in the database to generate logical, consistent and data-integrity-assured data. Standout advantages include the ability to automatically reset the database, inherently understand foreign key constraints and support concise syntax for easily creating nested data structures.

Prerequisites

This article is used alongside Prisma in a NestJS project, I will not specifically mention how to set up Prisma anymore, you can review the previous article to have the necessary preparation before proceeding

Detail

First, install the package

yarn add -D @snaplet/seed

Then, add the following scripts to package.json

{
  "scripts": {
    "seed:init": "npx @snaplet/seed init prisma/seed",
    "seed:sync": "npx @snaplet/seed sync",
    "prisma:seed": "prisma db seed"
  }
}

Below is the content of the prisma/schema.prisma file, which establishes the relationship between the Product and Category tables

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

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

generator nestgraphql {
  provider = "prisma-nestjs-graphql"
  output   = "../gen/graphql"
}

model Category {
  id       Int       @id @default(autoincrement())
  name     String
  products Product[]
}

model Product {
  id         Int      @id @default(autoincrement())
  name       String
  price      Float
  categoryId Int
  category   Category @relation(fields: [categoryId], references: [id])
}

Please execute the following command to create the prisma/seed folder

yarn seed:init


Create the prisma/seed/seed.config.ts file with the !*_prisma_migrations configuration to skip Prisma system tables (which are tables generated automatically by Prisma, not our data tables)

import {SeedPrisma} from '@snaplet/seed/adapter-prisma'
import {defineConfig} from '@snaplet/seed/config'
import * as dotenv from 'dotenv'
import {PrismaService} from '../../src/service/prisma.service'

dotenv.config()

export default defineConfig({
  adapter: () => {
    const client = new PrismaService()
    return new SeedPrisma(client)
  },
  select: [
    '!*_prisma_migrations',
  ],
})

Create the prisma/seed/seed.ts file

import {createSeedClient} from '@snaplet/seed'

async function main() {
  const seed = await createSeedClient()

  await seed.$resetDatabase()

  await seed.category(x =>
    x(10, {
      products: x => x({min: 2, max: 5}),
    })
  )

  console.log('🚀 Seeding Category and Product have completed!')
  process.exit(0)
}

main().catch(e => {
  console.error('❌ Seeding Error:', e)
  process.exit(1)
})
  • seed.$resetDatabase(): Cleanly reset the database before pouring new data
  • Mock data generation: Create 10 Category rows, each row accompanied by random Products
  • Snaplet will automatically mock realistic Category names (name) and Product details (name, price).
  • Each category randomly generates from 2 to 5 products belonging to that category

Because by default @snaplet/seed only supports random data in a technical format, which will not resemble real-world data, I will give you another version of the prisma/seed/seed.ts file using @faker-js/faker with support for more diverse data types

import {faker} from '@faker-js/faker'
import {createSeedClient} from '@snaplet/seed'

async function main() {
  const seed = await createSeedClient()

  await seed.$resetDatabase()

  await seed.category(x =>
    x(10, () => ({
      name: faker.commerce.department(),

      products: x =>
        x({min: 2, max: 5}, () => ({
          name: faker.commerce.productName(),

          price: faker.number.int({min: 10, max: 1000}),
        })),
    }))
  )

  console.log('🚀 Seeding Category and Product have completed!')
  process.exit(0)
}

main().catch(e => {
  console.error('❌ Seeding Error:', e)
  process.exit(1)
})
  • faker.commerce.department(): Use pure faker, generate a realistic department name
  • faker.commerce.productName(): Define the products belonging to this category
  • faker.number.int({min: 10, max: 1000}): Create an Integer from 10 to 1000

Update the prisma.config.ts file, you only need to add the migrations field and point to the seed.ts file created above

import {defineConfig, env} from '@prisma/config'
import * as dotenv from 'dotenv'

dotenv.config()

export default defineConfig({
  migrations: {
    seed: 'ts-node ./prisma/seed/seed.ts',
  },
  datasource: {
    url: env('DATABASE_URL'),
  },
})

After that, just execute the following 2 commands to sync between prisma and seed then create the seed data

$ yarn seed:sync

$ yarn prisma:seed
yarn run v1.22.22
$ prisma db seed
Loaded Prisma config from prisma.config.ts.

Running seed command `ts-node ./prisma/seed/seed.ts` ...
🚀 Seeding Category and Product completed!

🌱  The seed command has been executed.
✨  Done in 2.25s.


Check the results in PostgreSQL as follows


Happy coding!

See more articles here.

Comments

Popular posts from this blog

All Practice Series

Kubernetes Deployment for Zero Downtime

Deploying a NodeJS Server on Google Kubernetes Engine

Setting up Kubernetes Dashboard with Kind

Monitoring with cAdvisor, Prometheus and Grafana on Docker

Using Kafka with Docker and NodeJS

Practicing with Google Cloud Platform - Google Kubernetes Engine to deploy nginx

Kubernetes Practice Series

Sitemap

DevOps Practice Series