MCPcopy Index your code
hub / github.com/Quramy/prisma-fabbrica

github.com/Quramy/prisma-fabbrica @v2.3.3

Chat with this repo
repository ↗ · DeepWiki ↗ · release v2.3.3 ↗ · + Follow
478 symbols 909 edges 87 files 0 documented · 0% updated 8d agov2.3.3 · 2025-12-09★ 34610 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

prisma-fabbrica

github actions npm version GitHub license

Prisma generator for model factories.

ToC

Getting started

npm i @quramy/prisma-fabbrica -D

Then, edit your prisma/schema.prisma and append the prisma-fabbrica generator configuration:

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

generator fabbrica {
  provider = "prisma-fabbrica"
}

[!NOTE] prisma-fabbrica also supports prisma-client generator .

And run generate command.

npx prisma generate

The above command generates JavaScript and TypeScript type definition files under src/__generated__/fabbrica directory. You can define your model factory importing them.

For example, if schema.prisma has the following User model, you can import defineUserFactory and define UserFactory using this function.

model User {
  id    String @id
  name  String
  posts Post[]
}
/* src/seed.ts */

import { PrismaClient } from "@prisma/client";

import { initialize, defineUserFactory } from "./__generated__/fabbrica";

const prisma = new PrismaClient();
initialize({ prisma });

async function seed() {
  const UserFactory = defineUserFactory();

  await UserFactory.create();
  await UserFactory.create({ name: "Alice" });
  await UserFactory.create({ id: "user002", name: "Bob" });

  console.log(await prisma.user.count()); // -> 3
}

seed();

[!NOTE] The factories use Prisma client instance passed by initialize function.

If you want to use factories in your test code see Works with jest-prisma section below.

Usage of factories

Field default values

Factory by defined with defineUserFactory automatically fills required scalar fields.

For example, the following User model has some required field, id, email, firstName and lastName .

model User {
  id          Int      @id
  email       String   @unique
  firstName   String
  lastName    String
  middleName  String?
  createdAt   DateTime @default(now())
}
const UserFactory = defineUserFactory();

await UserFactory.create(); // Insert record with auto filled id, email, firstName and lastName values

See https://github.com/Quramy/prisma-fabbrica/blob/main/packages/prisma-fabbrica/src/scalar/gen.ts if you want auto filling rule details.

[!NOTE] prisma-fabbrica auto filling does not generate values of fields with @default() function because these fields are not required and values of them are generated by Prisma engine.

Default filling rule also can be overwritten.

const UserFactory = defineUserFactory({
  defaultData: async () => ({
    email: await generateRandomEmailAddress(),
  }),
});

await UserFactory.create();

Use sequence for scalar fields

seq parameter provides sequential number which increments when called .create() .

const UserFactory = defineUserFactory({
  defaultData: async ({ seq }) => ({
    id: `user${seq.toString().padStart(3, "0")}`,
  }),
});

await UserFactory.create(); // Insert with id: "user000"
await UserFactory.create(); // Insert with id: "user001"
await UserFactory.create(); // Insert with id: "user002"

And the sequential number can be reset via resetSequence .

/* your.testSetup.ts */

import { resetSequence } from "./__generated__/fabbrica";

beforeEach(() => resetSequence());

Shorthand for create list

Each factory provides .createList method to insert multiple records.

await UserFactory.createList(3);

// The above code is equivalent to the following

await Promise.all([0, 1, 2].map(() => UserFactory.create()));

The 2nd argument(optional) accepts an object which is assignable to Partial<Prisma.UserCreateInput> :

await UserFactory.createList(3, { name: "Bob" });

You can also pass list data assignable to Partial<Prisma.UserCreateInput>[] :

await UserFactory.createList([{ id: "user01" }, { id: "user02" }]);

Required relation

Sometimes, creating a model requires other model existence. For example, the following model Post belongs to other model User.

model User {
  id    String @id
  name  String
  posts Post[]
}

model Post {
  id       String @id
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId String
}

You should tell how to connect author field when define Post factory.

Using related model factory (recommended)

The easiest way is to give UserFactory when definePostFactory like this:

const UserFactory = defineUserFactory();

const PostFactory = definePostFactory({
  defaultData: {
    author: UserFactory,
  },
});

The above PostFactory creates User model for each PostFactory.create() calling,

Manual create or connect

Similar to using prisma.post.create, you can also use connect / create / createOrConnect options.

const PostFactory = definePostFactory({
  defaultData: async () => ({
    author: {
      connect: {
        id: (await prisma.user.findFirst()!).id,
      },
      // Alternatively, create or createOrConnect options are allowed.
    },
  }),
});

Connection helper

Required relation rules can be overwritten when .create method. createForConnect can be used to connect.

const UserFactory = defineUserFactory();

const PostFactory = definePostFactory({
  defaultData: {
    author: UserFactory,
  },
});

const author = await UserFactory.createForConnect();
await PostFactory.create({ author: { connect: author } });
await PostFactory.create({ author: { connect: author } });

const { posts } = await prisma.user.findUnique({ where: author, include: { posts: true } });
console.log(posts.length); // -> 2

Build input data only

.build method in factories provides data set to create the model, but never insert.

await UserFactory.create();

// The above code is equivalent to the bellow:
const data = await UserFactory.build();
await prisma.user.create({ data });

For example, you can use .build method in other model's factory definition:

const UserFactory = defineUserFactory();

const PostFactory = definePostFactory({
  defaultData: async () => ({
    author: {
      connectOrCreate: {
        where: {
          id: "user001",
        },
        create: await UserFactory.build({
          id: "user001",
        }),
      },
    },
  }),
});

await PostFactory.create();
await PostFactory.create();

console.log(await prisma.user.count()); // -> 1

Like createList, buildList is also available.

has-many / has-one relation

Sometimes, you may want a user data whose has post record. You can use PostFactory.build or PostFactory.buildList .

await UserFactory.create({
  posts: {
    create: await PostFactory.buildList(2),
  },
});

console.log(await prisma.post.count()); // -> 2

[!NOTE] In the above example, PostFactory.build() resolves JSON data such as:

{
  id: "...",
  title: "...",
  author: { ... } // Derived from PostFactory defaultData
}

The author field is not allowed in prisma.user.create context. So UserFactory automatically filters the author field out in .create method.

Custom scalar field generation

prisma-fabbrica provides function to complete scalar fields( https://github.com/Quramy/prisma-fabbrica/blob/main/packages/prisma-fabbrica/src/scalar/gen.ts ).

registerScalarFieldValueGenerator allows to custom this rule. For example:

import { registerScalarFieldValueGenerator } from "./__generated__/fabbrica";

registerScalarFieldValueGenerator({
  String: ({ modelName, fieldName, seq }) => `${modelName}_${fieldName}_${seq}`,
});

registerScalarFieldValueGenerator accepts an object Record<FiledType, FieldGenerateFunction>. Field type is one of Boolean, String, Int, Float, BigInt, Decimal, DateTime, Bytes, and Json. FieldGenerateFunction is a function to return corresponding fieled type.

See also https://github.com/Quramy/prisma-fabbrica/blob/main/packages/prisma-fabbrica/src/scalar/types.ts .

Traits

Traits allow you to group fields together and apply them to factory.

const UserFactory = defineUserFactory({
  defaultData: {
    name: "sample user",
  },
  traits: {
    withdrawal: {
      data: {
        name: "****",
        status: "WITHDRAWAL",
      },
    },
  },
});

traits option accepts an object and the option object's keys are treated as the trait's name. And you can set data option to the each trait key. The data option accepts value of the same types as the defaultData (i.e. plain object, function, async function)

And you can pass the trait's name to UserFactory.use function:

const deactivatedUser = await UserFactory.use("withdrawal").create();

Multiple traits are also available:

await UserFactory.use("someTrait", "anotherTrait").create();

Callbacks

You can set callback function before or after factory execution.

const UserFactory = defineUserFactory({
  onAfterCreate: async user => {
    await PostFactory.create({
      author: { connect: uesr },
    });
  },
});

await UserFactory.create();

Callback functions are also available within trait definition.

const UserFactory = defineUserFactory({
  traits: {
    withComment: {
      onAfterCreate: async user => {
        await PostFactory.create({
          author: { connect: uesr },
        });
      },
    },
  },
});

await UserFactory.create();
await UserFactory.use("withComment").create();

[!NOTE] The above code is to explain the callback. If you want to create association, first consider to use defaultData and trait.data option as in has-many / has-one relation.

The following three types are available as callback function:

const UserFactory = defineUserFactory({
  onAfterBuild: async createInput => {
    // do something
  },
  onBeforeCreate: async createInput => {
    // do something
  },
  onAfterCreate: async createdData => {
    // do something
  },
});

And here, the parameter types are:

  • createInput is assignable to model create function parameter (e.g. Prsima.UserCreateInput).
  • createdData is resolved object by model create function (e.g. User model type)

Transient fields

Transient fields allow to define arbitrary parameters to factory and to pass them when calling create or build.

const UserFactory = defineUserFactory.withTransientFields({
  loginCount: 0, // `0` is default value of this parameter
})({
  defaultData: async ({ loginCount }) => {
    // using loginCount
  },
});

await UserFactory.create({ name: "Bob", loginCount: 10 });

Transient fields passed from factories' create method don't affect Prisma's create result.

[!NOTE] You can't use model field names defined in your schema.prisma as transient parameters because they're not passed to prisma.user.create method.

Transient fields also can be accessed from traits or callbacks.

const UserFactory = defineUserFactory.withTransientFields({
  loginCount: 0,
})({
  // Transient fields are passed to callback functions as the 2nd argument.
  onAfterCreate: async (createdUser, { loginCount }) => {
    for (let i = 0; i < loginCount; i++) {
      await writeLoginLog(createdUser.id);
    }
  },
  traits: {
    data: async ({ loginCount }) => {
      // using loginCount
    },
  },
});

Field value precedence

Each field is determined in the following priority order(lower numbers have higher priority):

  1. Factory's .create or .build function's argument
  2. The applied trait's data entry
  3. Factories defaultData entry
  4. Value derived from registerScalarFieldValueGenerator if the field is required scalar(or enum)

More examples

There are more example codes in https://github.com/Quramy/prisma-fabbrica/tree/main/examples/example-prj/src .

Generator configuration

The following options are available:

generator fabbrica {
  provider    = "prisma-fabbrica"
  output      = "../src/__generated__/fabbrica"
  tsconfig    = "../tsconfig.json"
  noTranspile = false
}
  • output: Directory path to generate files.
  • tsconfig: TypeScript configuration file path. prisma-fabbrica uses it's compilerOptions when generating `.js

Extension points exported contracts — how you extend this code

Core symbols most depended-on inside this repo

Shape

Function 213
Method 192
Interface 73

Languages

TypeScript100%

Modules by API surface

examples/example-prj-esm/src/__generated__/fabbrica/index.ts77 symbols
packages/artifact-testing/fixtures/field-variation/__generated__/fabbrica/index.ts61 symbols
examples/example-prj/src/__generated__/fabbrica/index.d.ts55 symbols
packages/artifact-testing/fixtures/relations-one-to-many/__generated__/fabbrica/index.ts51 symbols
packages/artifact-testing/fixtures/relations-one-to-one/__generated__/fabbrica/index.ts37 symbols
packages/artifact-testing/fixtures/view-relations/__generated__/fabbrica/index.ts36 symbols
packages/artifact-testing/fixtures/relations-many-to-many/__generated__/fabbrica/index.ts35 symbols
packages/prisma-fabbrica/src/templates/index.ts27 symbols
packages/artifact-testing/fixtures/simple-model/__generated__/fabbrica/index.ts22 symbols
examples/example-prj/src/__generated__/fabbrica/index.js22 symbols
packages/prisma-fabbrica/src/relations/screen.ts9 symbols
packages/prisma-fabbrica/src/templates/ast-tools/comment.ts4 symbols

For agents

$ claude mcp add prisma-fabbrica \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page