👍
prisma-fabbricaを試す
まずは、Prisma ORM
を軽くおさらい
Prisma ORM
Prisma Generators
- ジェネレーターは、
prisma generate
コマンドを実行したときに動く -
schema.prisma
のモデルをインプットとして、様々なアウトプットを得ることができる- 公式の prisma-client-js だったり、
-
コミュニティが作成したジェネレーターがある
- DBML: prisma-dbml-generator
- API reference: prisma-docs-generator
- etc...
必要に応じてジェネレータを追加できる
prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
generator dbml {
provider = "prisma-dbml-generator"
}
generator docs {
provider = "node node_modules/prisma-docs-generator"
}
prisma-fabbrica
- Prisma Community generators のひとつ
- ヘルパーを得られる
Getting started
npm i @quramy/prisma-fabbrica -D
npm list --depth=0
(...抜粋...)
├── next@14.2.4
├── react@18.3.1
├── typescript@5.4.5
├── @trpc/client@10.45.2
├── @trpc/react-query@10.45.2
├── @trpc/server@10.45.2
├── prisma@5.14.0
├── @prisma/client@5.14.0
├── @quramy/prisma-fabbrica@2.2.0
prisma/schema.prisma
+generator fabbrica {
+ provider = "prisma-fabbrica"
+}
npx prisma generate
Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
Error:
✔ Generated Prisma Client (v5.14.0) to .\node_modules\@prisma\client in 64ms
prisma-fabbrica: Failed to TypeScript transpilation. Please try "noTranspile = true"
-
Prisma Client
は成功 -
prisma-fabbrica
は失敗- アウトプットのディレクトリはできるものの、ファイルは何も出力されない
-
Please try "noTranspile = true"
をどこへ追記する???
prisma/schema.prisma
generator fabbrica {
provider = "prisma-fabbrica"
+ noTranspile = true
}
npx prisma generate
Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
✔ Generated Prisma Client (v5.14.0) to .\node_modules\@prisma\client in 64ms
✔ Generated DBML Schema to .\node_modules\.prisma\dbml in 12ms
✔ Generated Prisma Docs Generator to .\node_modules\.prisma\docs in 36ms
✔ Generated fabbrica to .\node_modules\.prisma\fabbrica in 89ms
生成されたものを確認してみる
src\__generated__\fabbrica\index.ts
node_modules\.prisma\fabbrica\index.ts
import type { Account } from "@prisma/client";
import type { Session } from "@prisma/client";
(...略...)
import type { Prisma, PrismaClient } from "@prisma/client";
import { createInitializer, createScreener, getScalarFieldValueGenerator, normalizeResolver, normalizeList, getSequenceCounter, createCallbackChain, destructure } from "@quramy/prisma-fabbrica/lib/internal";
import type { ModelWithFields, Resolver, } from "@quramy/prisma-fabbrica/lib/internal";
export { resetSequence, registerScalarFieldValueGenerator, resetScalarFieldValueGenerator } from "@quramy/prisma-fabbrica/lib/internal";
type BuildDataOptions<TTransients extends Record<string, unknown>> = {
readonly seq: number;
} & TTransients;
type TraitName = string | symbol;
type CallbackDefineOptions<TCreated, TCreateInput, TTransients extends Record<string, unknown>> = {
onAfterBuild?: (createInput: TCreateInput, transientFields: TTransients) => void | PromiseLike<void>;
onBeforeCreate?: (createInput: TCreateInput, transientFields: TTransients) => void | PromiseLike<void>;
onAfterCreate?: (created: TCreated, transientFields: TTransients) => void | PromiseLike<void>;
};
const initializer = createInitializer();
const { getClient } = initializer;
export const { initialize } = initializer;
const modelFieldDefinitions: ModelWithFields[] = [{
name: "Account",
fields: [{
name: "user",
type: "User",
relationName: "AccountToUser"
}]
}, {
name: "Session",
fields: [{
name: "user",
type: "User",
relationName: "SessionToUser"
}]
}, {
(...略...)
Usage of factories
seed してみる
prisma/seed.ts
import { PrismaClient, Prisma } from '@prisma/client'
import { initialize, defineProductFactory, defineUserFactory, defineRecipeFactory } from "../src/__generated__/fabbrica";
import { productData } from "./seed-sources";
const prisma = new PrismaClient();
initialize({ prisma });
async function seed() {
// Product
const ProductFactory = defineProductFactory();
console.log(await prisma.product.count());
// 自動入力
await ProductFactory.create();
// 指定入力
await ProductFactory.create({ userId: "TestUserId", sort: 0, category: "TestCategory", name: "TestName", unit: "pc", });
console.log(await prisma.product.count());
// User
const UserFactory = defineUserFactory({
defaultData: async ({ seq }) => ({
name: `user${seq.toString().padStart(3, "0")}`,
}),
})
// Recipe >>> User
const RecipeFactory = defineRecipeFactory({
defaultData: {
user: UserFactory,
},
});
await RecipeFactory.create();
await RecipeFactory.createList(3);
// User >>> Recipe
await UserFactory.create({
recipes: {
create: await RecipeFactory.buildList(2),
},
});
}
seed();
- 上記のような、いくつかのパターンを試したところ、想定通りの動きをデータベースのレコードとともに確認できた。
テスティング・ライブラリとの連携
- 後ほど、試してみたい
Discussion