@veap/database includes defineFactory, the Factory base class, Seeder, and runSeeders. Use them for repeatable local data and test fixtures—not as a substitute for production data migrations.
Define a factory#
import { defineFactory } from "@veap/database";
import { Article } from "../models/Article.js";
export const ArticleFactory = defineFactory(Article, () => ({
title: "Example article",
slug: `example-${crypto.randomUUID()}`,
body: "Fixture content",
published: false,
}));The factory helper returns a callable factory constructor with methods such as count, state, sequence, make, makeOne, create, and createOne.
make/makeOneinstantiate model objects without saving.create/createOnepersist model objects.stateapplies an object override or a transformation callback.sequencerotates through a list of attribute objects.count(n)requests multiple model instances.
const draft = await ArticleFactory.makeOne({ published: false });
const published = await ArticleFactory.count(3).create({ published: true });Use unique slugs and other unique fields when creating multiple records.
Create a seeder#
import { Seeder } from "@veap/database";
export class ArticleSeeder extends Seeder {
async run(): Promise<void> {
await ArticleFactory.count(5).create();
}
}Then run the seeder after the database has been initialized:
import { runSeeders } from "@veap/database";
import { ArticleSeeder } from "./ArticleSeeder.js";
await runSeeders(ArticleSeeder, { inTransaction: true });runSeeders accepts a seeder class or an array of classes. Seeders run sequentially. The optional inTransaction setting wraps the run in a single database transaction.
Safety#
- Do not run destructive seeders automatically in production.
- Keep reference-data seeding separate from schema migrations.
- Make fixtures deterministic when tests depend on exact values.
- Ensure the schema is migrated before factories execute.