Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
@quramy/prisma-fabbrica
Advanced tools
Prisma generator for model factories.
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.
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()
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());
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" }]);
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.
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,
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.
},
}),
});
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
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.
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.
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 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();
Each field is determined in the following priority order(lower numbers have higher priority):
.create
or .build
function's argumentdata
entrydefaultData
entryregisterScalarFieldValueGenerator
if the field is required scalar(or enum)There are more example codes in https://github.com/Quramy/prisma-fabbrica/tree/main/examples/example-prj/src .
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
.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.
/* jest.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.
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(),
},
});
@quramy/prisma-fabbrica@2.x.x
.@quramy/prisma-fabbrica@1.x.x
.MIT
FAQs
Prisma generator for model factories
The npm package @quramy/prisma-fabbrica receives a total of 19,066 weekly downloads. As such, @quramy/prisma-fabbrica popularity was classified as popular.
We found that @quramy/prisma-fabbrica demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.