Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

[#1 Mita.ts] Prisma Schema から コード生成

sugiken
August 28, 2024

[#1 Mita.ts] Prisma Schema から コード生成

sugiken

August 28, 2024
Tweet

More Decks by sugiken

Other Decks in Programming

Transcript

  1. なぜ生成したいか • Rails のように db のテーブルと Model を1対1で作りたい • Repository

    もテーブルと1対1 • テストのための fixture(mock オブジェクト)もテーブルで1対1 ボイラープレートいっぱい!
  2. Prisma Schema と generator datasource db { url = env("DATABASE_URL")

    provider = "postgresql" } generator client { provider = "prisma-client-js" } model User { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) email String @unique name String? } 最もシンプルな Schema generator の役割 provider の実装に沿って、コードを生成する。 node_modules/.prisma/client に Prisma Client を生成するための指定に用いることが多 い。 このおかげで、model ファイルの作成等なしに、 型定義された ORM として振る舞うことができ る。
  3. generator は任意に追加できる 公式から抜粋 A Prisma schema can have one or

    more generators. The main property provider defines which Prisma Client (language specific) is created - currently, only prisma-client-js is available. Alternatively you can define any npm package that follows our generator specification. generator の要件満たしていれば任意に追加して ok!🤙
  4. provider と output は任意のパスで ok generator entity { provider =

    "./scripts/entity_generator.js" output = "../shark/entities" }
  5. Generator Specification に準拠 ./scripts/entity_generator.ts import { generatorHandler } from "@prisma/generator-helper";

    generatorHandler({ onManifest() { return { version: "0.0.0", prettyName: "Shark Base Schema", defaultOutput: "src", }; }, async onGenerate(options) { // ここで色々 }, });
  6. options の中身 - Schema の情報がまるっと type Model = ReadonlyDeep<{ name:

    string; dbName: string | null; fields: Field[]; uniqueFields: string[][]; uniqueIndexes: uniqueIndex[]; documentation?: string; primaryKey: PrimaryKey | null; isGenerated?: boolean; }>; type Field = ReadonlyDeep<{ kind: FieldKind; name: string; isRequired: boolean; isUnique: boolean; dbName?: string | null; hasDefaultValue: boolean; relationFromFields?: string[]; relationToFields?: string[]; relationOnDelete?: string; relationName?: string; documentation?: string; }>;
  7. 新たな登場人物 ts-morph import { IndentationText, Project } from "ts-morph"; const

    project = new Project({ manipulationSettings: { indentationText: IndentationText.TwoSpaces, }, }); const path = `${outputPath}/repository/${name}.repository.ts`; const sourceFile = project.createSourceFile(path, {}, { overwrite: false }); sourceFile.addClass({ name: `${className}Repository`, isExported: true, }); await project.save();
  8. 例: 一番面倒な感じの箇所 { name: `build${className}Entity`, initializer: `<K extends keyof ${model.name}>(

    props?: { [key in K]: ${model.name}[key]; } ): ${entityName} => { return ${entityName}.Reconstruct<${model.name}, ${entityName}>({ ...defaultValue, ...props }); }`, },
  9. まとめ バックテックの場合 • Prisma Generator ◦ Prisma の Schema 構造を公式な手段で

    Object として取得するための手段 ◦ Prisma Client が作られるときと同じタイミングでトリガーする • ts-morph ◦ TS のファイルを生成 この2つをかけ合わせて自動生成するお話でした!