• Stars
    star
    221
  • Rank 173,946 (Top 4 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 1 year ago
  • Updated 16 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Prisma generator to define model factory

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"
}

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 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 affect fields with @default() function.

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()));

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 / craete / 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();

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 and .d.ts files. If missing tsconfig json file, fallback to --target es2020 --module commonjs.
  • noTranspile: If set true, this generator only generates raw .ts file and stop to transpile to .js and .d.ts .

Tips

Works with jest-prisma

If you use @quramy/jest-prisma or @quramy/jest-prisma-node, you can pass @quramy/prisma-fabbrica/scripts/jest-prisma to setupFilesAfterEnv in your Jest configuration file.

/* jset.config.mjs */

export default {
  preset: "ts-jest",
  transform: {
    "^.+\\.tsx?$": "ts-jest",
  },
  testEnvironment: "@quramy/jest-prisma/environment",
  setupFilesAfterEnv: ["@quramy/prisma-fabbrica/scripts/jest-prisma"],
};

This script calls prisma-fabbrica's initialize function and configures Prisma client used from each factory to integrate to join to transaction managed by jest-prisma.

Suppress TS circular dependencies error

Sometimes, factories need each other factory as the following, however TypeScript compiler emits errors via circular dependencies.

// 'UserFactory' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
export const UserFactory = defineUserFactory({
  defaultData: async () => ({
    posts: {
      connect: await PostFactory.buildList(1),
    },
  }),
});

// 'PostFactory' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
const PostFactory = definePostFactory({
  defaultData: {
    author: UserFactory,
  },
});

FactoryInterface types are available to avoid this error.

import { defineUserFactory, definePostFactory, type UserFactoryInterface } from "./__generated__/fabbrica";

const UserFactory = defineUserFactory({
  defaultData: async () => ({
    posts: {
      connect: await PostFactory.buildList(1),
    },
  }),
});

function getUserFactory(): UserFactoryInterface {
  return UserFactory;
}

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

Version compatibility

License

MIT

More Repositories

1

tsuquyomi

A Vim plugin for TypeScript
Vim Script
1,384
star
2

typed-css-modules

Creates .d.ts files from CSS Modules .css files
TypeScript
918
star
3

lerna-yarn-workspaces-example

How to build TypeScript mono-repo project with yarn and lerna
TypeScript
893
star
4

ts-graphql-plugin

TypeScript Language Service Plugin for GraphQL developers
TypeScript
674
star
5

electron-connect

Livereload tool for Electron
JavaScript
339
star
6

npm-ts-workspaces-example

Monorepos example project using npm workspaces and TypeScript project references
TypeScript
296
star
7

jest-prisma

Jest environment for integrated testing with Prisma client
TypeScript
245
star
8

typescript-eslint-language-service

TypeScript language service plugin for ESLint
TypeScript
243
star
9

eslint-plugin-tutorial

A tutorial/template repository to explain how to create your eslint plugins
TypeScript
190
star
10

gql-study-workshop

TypeScript
144
star
11

vim-js-pretty-template

highlights JavaScript's Template Strings in other FileType syntax rule
Vim Script
143
star
12

electron-jsx-babel-boilerplate

Electron boilerplate with React.js and babel
JavaScript
118
star
13

vison

A Vim plugin for writing JSON with JSON Schema
Vim Script
96
star
14

zisui

Yet another CLI to screenshot your Storybook
TypeScript
72
star
15

angular-puppeteer-demo

A demonstration repository explains how to using Puppeteer in unit testing
TypeScript
58
star
16

pico-ml

A toy programming language which is a subset of OCaml.
TypeScript
50
star
17

x-img-diff

Detect structural difference information of 2 images considering into translation
C++
47
star
18

graphql-decorator

TypeScript
43
star
19

apollo-link-fragment-argument

An Apollo Link to enable to parameterize fragments
TypeScript
40
star
20

better-name

CLI tool to move JavaScript(ES2015) or TypeScript module files
TypeScript
34
star
21

type-dungeon

TypeScript code exercise
TypeScript
31
star
22

talt

Template functions to generate TypeScript AST node object
TypeScript
28
star
23

ngx-typed-forms

Extends Angular reactive forms strongly typed
TypeScript
27
star
24

loadable-ts-transformer

TypeScript custom transformer for loadable-components SSR
TypeScript
26
star
25

typescript-css-modules-demo

A working demo of CSS Modules, using TypeScript, css-modulesify and typed-css-modules
TypeScript
25
star
26

angular2-load-children-loader

A webpack loader for ng2 lazy loading
JavaScript
23
star
27

electron-disclosure

Sample electron app
JavaScript
22
star
28

ng2-lazy-load-demo

A sample repository for Angular2 lazy module loading
TypeScript
22
star
29

opencv-wasm-knnmatch-demo

Web Assembly OpenCV Feature Matching Demonstration
JavaScript
21
star
30

ionic-apollo-simple-app

Explains how to develop Ionic application with Apollo GraphQL client
TypeScript
19
star
31

ngx-zombie-compiler

Fast JiT compiler for Angular testing
TypeScript
15
star
32

decode-tiff

⚡ A lightweight JavaScript TIFF decoder 🎨
JavaScript
15
star
33

ts-server-side-anatomy

Explain what TypeScript server(tsserver) does under your editors
TypeScript
15
star
34

tsuquyomi-vue

vim plugin for TypeScript and Vue.js
Vim Script
15
star
35

generator-ngdoc

Yeoman generator for AngularJS's module documentation
JavaScript
14
star
36

ts-playground-plugin-vim

TypeScript Playground plugin for Vim keybindings
TypeScript
12
star
37

prisma-yoga-example

GraphQL server example using Prisma and graphql-yoga
TypeScript
12
star
38

tsc-react-example

Example to compile React JSX with TypeScript
JavaScript
10
star
39

puppeteer-example

JavaScript
10
star
40

angular-recursive

AngularJS directives for recursive data.
JavaScript
9
star
41

nirvana-js

⚡ JavaScript file runner using Electron
TypeScript
9
star
42

dgeni-ngdocs-example

JavaScript
7
star
43

rxdb-simple-chat-app

simple chat application using RxDB
JavaScript
7
star
44

falcor-firebase

It provides a Falcor datasource from your Firebase database
JavaScript
7
star
45

swagger-codegen-customize-sample

A sample repository for customize swagger-codegen
HTML
6
star
46

zakki

6
star
47

falcor-lambda

creates AWS Lambda handler from Falcor's data source
JavaScript
6
star
48

angular-karma-chrome-headless-demo

TypeScript
6
star
49

server-components-with-container-presentation

TypeScript
6
star
50

storycov

TypeScript
5
star
51

prisma2-nexus-example

TypeScript
5
star
52

screenshot-testing-demo-ngjp18

Demonstration repository "Screenshot test with Angular" session ng-japan18
TypeScript
5
star
53

apollo-angular-example

An example repository to explain how to integrate Apollo and Angular
TypeScript
5
star
54

serverless-falcor-starter

A Serverless project including Falcor routing.
JavaScript
5
star
55

vim-dtsm

A Vim plugin to execute TypeScript dtsm command
Vim Script
4
star
56

dotfiles

settings
Vim Script
4
star
57

arlecchino

TypeScript
4
star
58

angular-sss-demo

Storybook, Screenshot, and Snapshot testing for Angular
TypeScript
4
star
59

graphql-script-sample

Shell script GraphQL client for GitHub v4 API sample
Shell
3
star
60

storybook-angular-cli-helper

TypeScript
3
star
61

storyshots-with-portal-repro

JavaScript
3
star
62

simple-coverage-diff-action

TypeScript
3
star
63

fretted-strings

Mark on your strings and get it's position
TypeScript
3
star
64

face_of_the_year

Python
3
star
65

vim-json-schema-nav

Vim Script
3
star
66

apollo-sandbox

TypeScript
2
star
67

ts-react-css-modules-example

A sample repository for React JSX with CSS Modules for TypeScript
TypeScript
2
star
68

graphql-streaming-example

GraphQL @defer/@stream example
TypeScript
2
star
69

tsjp-resources

TypeScript
2
star
70

karma-nightmare-angular-demo

A working demonstration for visual regression testing of Angular application.
TypeScript
2
star
71

react-apollo-ssr-demo

TypeScript
2
star
72

eslint-plugin-unlearned-kanji

TypeScript
2
star
73

react-css-note

HTML
2
star
74

inspectorium

Inspect your GitHub source code
TypeScript
2
star
75

example-of-generator-ngdoc

An example repository of generator-ngdoc(an Yeoman generator)
JavaScript
2
star
76

test-with-aot-summary

Explains how to Angular's AOT result in unit testing
TypeScript
2
star
77

copl-ts

CoPL本のTypeScript実装
TypeScript
2
star
78

astsx

TypeScript
2
star
79

prignore

Chrome-extension for GitHub PR
JavaScript
2
star
80

abacus-ts

Calculator implemented by only TypeScript type operation
TypeScript
1
star
81

puppeteer-coverage-study

TypeScript
1
star
82

pkg-study

JavaScript
1
star
83

sewordle

A chrome extension which generates tag cloud using user query keywords inputed at search-engine.
JavaScript
1
star
84

react-falcor-demo

Demonstration of Falcor and React
TypeScript
1
star
85

nopmdcheck

A jenkins plugin to check "NOPMD" comments in workspace.
JavaScript
1
star
86

type-apollo-local-state

TypeScript
1
star
87

fuse-postcss-example

A Fuse-Box with PostCSS example repository.
CSS
1
star
88

ts-api-study

TypeScript
1
star
89

dotson

TypeScript
1
star
90

prisma-dmmf-viewer

Display Prisma DMMF(Data Model Meta Format)
JavaScript
1
star
91

typescript-api-tutrial

1
star
92

first-liquidfun

JavaScript
1
star
93

apollo-client-37-study

TypeScript
1
star
94

ccvsample

JavaScript
1
star
95

ossc-hackathon-ardrone-14

JavaScript
1
star
96

Quramy

1
star
97

crudsample

this is a sample application on node (express + mongoose).
JavaScript
1
star
98

reproduce-apollo-react-memleak

To reproduce react-apollo memory leak
TypeScript
1
star
99

groovy-labo

Groovy
1
star
100

es7study

JavaScript
1
star