Open46

Prismaメモ

RerrahRerrah

ORM (Object-Relational Mapping) ツールのPrismaを使う.

https://www.prisma.io

RerrahRerrah

mysqlモジュールやmongodbモジュールを使ってもデータベースの操作はできるが,クエリを文字列として直接書かないと行けなかったりする.

Mongoを使うならMongooseを使ったら良さそうだけど,今回はデータベースをMySQLに以降してみたくなったのでパスした.

https://mongoosejs.com

最近はDrizzleと比較されるらしい.こちらはスキーマをTypeScriptで定義できる.クエリをSQLに近い形で書くので,Prismaでは難しい痒いところに手が届くみたい.SQLにもっと詳しくなったらこっちを使ってみるのもアリかも.

https://orm.drizzle.team

RerrahRerrah

ORM

データベースのデータをクライアント側でオブジェクトのように扱うための技法.素のSQL文を叩いてデータベースのCRUD操作をするのに比べて,オブジェクトのメソッドを通して操作するのでオブジェクト指向プログラミングのコードと親和性が高い.

PrismaはTypeScriptネイティブのORMツールで,型安全でありながらデータベースを操作できる.

RerrahRerrah

Prismaの構成

Prismaは以下3つのツールで構成される.

  • Prisma Client: SQL文を自動で作成してデータベースとのやり取りを行うクエリビルダー
  • Prisma Migrate: スキーマの変更をデータベースに反映(マイグレーション)を行うツール
  • Prisma Studio: データベースの中身を確認・編集できるGUIアプリ

特に上2つはよく使いそう.

RerrahRerrah

似た名前のパッケージがチュートリアルに2つ登場してきて混乱した.それぞれの違いは以下の通り.

prisma

Prisma ORMの機能を提供するアプリ.npx prismaで実行することにより,クライアントの作成やマイグレーション,クエリ実行を行う.

@prisma/client

TSのコード中でPrisma ORMの機能を利用してクエリ実行するためのライブラリ.

RerrahRerrah

開発コンテナー

Dockerコンテナー内で開発を行う.nodeの適当なイメージをプルしてコンテナーを作る.

Bunの公式Dockerイメージから作ったコンテナだと,prismaのコマンドが応答なしになった.どうもバグらしい.
ここはおとなしくnodeイメージを使いましょう.

https://tech.natsuneko.blog/entry/2024/07/07/220533

RerrahRerrah

@prisma/clientをインストールする.

yarn add -D -E @prisma/client
RerrahRerrah

セットアップ (MongoDB🍊)

MongoDBサーバーを別コンテナーで起動させた.Prismaで接続できるようにする.
今回は新しいデータベースを作成する.

公式チュートリアルの手順をとりあえずなぞる.

https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/mongodb-typescript-mongodb

RerrahRerrah

prismaのinitコマンドでセットアップのためのファイルを生成させる.

npx prisma init

コマンド出力の"Next steps:"は,既にあるデータベースと接続するための手順なので今回は無視する.

RerrahRerrah

データベースのURLの設定

.envファイルにDATABASE_URLが定義されるので,MongoDBのデータベースのアドレスを設定する.

.env
DATABASE_URL="mongodb://username:password@localhost:27017/mydb"
RerrahRerrah

スキーマの定義

prisma/schema.prismaファイルが生成されているので,ファイルを開いてdatasourceproviderを修正する.

prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
-  provider = "postgresql"
+  provider = "mongodb"
  url      = env("DATABASE_URL")
}

また,データベースのコレクション(テーブル)のスキーマとなるmodelを定義する.
スキーマはDSLで記述する.DSLのリファレンスを参考にする.

RerrahRerrah

prisma generateコマンドを実行して,定義したスキーマをもとにしたクエリビルダーであるクライアントを生成する.

npx prisma generate
RerrahRerrah

dockerでMongoDBを動かすにはレプリカセットを自前で設定しないといけない.

レプリカセットはデータベースのレプリケーションのために用意するサーバーのセットのこと.レプリケーションはリアルタイムでデータベースのレプリカ(複製)を作成し,サーバーの冗長性を持たせることでシステム障害が生じた際にフェイルオーバーする.

https://www.mongodb.com/ja-jp/docs/manual/replication/

MongoDB Atlasを使えば簡単に設定できる.一度テストでアカウントを作ったからセットアップできるけど,今回は個人データを使うので外部クラウドサーバーにデータを渡したくない.

RerrahRerrah

スキーマの書き方

https://www.prisma.io/docs/orm/reference/prisma-schema-reference#model

  • modelのフィールドにフィールド名,型,属性の順番で記載する.
  • 型名はデータベースによって異なるので注意
  • 型には配列やオプショナル型も設定できる
RerrahRerrah

属性

@id, @@id

主キーを示す.テーブルのフィールドで一つのみ設定できる.テーブル内で値が一意かつ非nullとなる.
@@idは引数に複数のフィールドの配列をとって複合主キーを表す.

MongoDBではString型かつ@map("_id") @db.ObjectIdをつける必要がある.

@map

そのフィールドをデータベースでは引数で指定した名前のフィールドとして保持する.

@default

デフォルト値を設定する.値はスカラー以外にも関数で生成した値を設定できる.

MondoDBだと自動でidを生成してくれる@default(auto())などが使える.

@unique, @@unique

ユニークキーを設定する.テーブル内で値が一意となる.
@@uniqueは複合ユニークキーを設定する.

RerrahRerrah

@relation

リレーションフィールドを定義する.引数にリレーションスカラーフィールドと対応するモデルのフィールドを指定する.

対応するモデルのフィールドは@id@uniqueでなければならない.

RerrahRerrah

enum

列挙体を定義できる.

model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId

  name           String
  supportingClub Club   @default(VisselKobe)
}

enum Club {
  VisselKobe
  GambaOsaka
  CerezoOsaka
  KyotoSanga
  FCOsaka
  NaraClub
}
RerrahRerrah

埋め込みデータ (Composite Type)

MongoDBを使っているときは埋め込みデータを使える.

Composite typeは1対1の関係にあるドキュメントをそれぞれ別のコレクションで管理するのではなく,ドキュメントのフィールドとしてドキュメントを埋め込むことになる.

https://www.mongodb.com/ja-jp/docs/rapid/data-modeling/concepts/embedding-vs-references/#std-label-embedding-vs-references

クエリでフィールドから直接Composite typeのフィールドを呼び出すことができるのがメリット.その代わりデータサイズが大きくなったり,2つのデータが密接に関係するので独立して柔軟に管理できないのがデメリット.

model Product {
  id   String @id @default(auto()) @map("_id") @db.ObjectId
  name String

  // 埋め込みデータPhotoの配列
  photos Photo[]
}

// 埋め込みデータの定義
type Photo {
  width  Int
  height Int
  url    String
}

https://www.prisma.io/docs/orm/prisma-schema/data-model/models#defining-composite-types

RerrahRerrah

リレーション定義

1対1関係

参照元のモデルに参照先のモデルを表すリレーションフィールドと外部キーとしてふるまうリレーションスカラーフィールドを設定する.参照先のモデルには参照先のモデルのリレーションフィールドを設定する.

// 参照元モデル
model Profile {
  id     String @id @default(auto()) @map("_id") @db.ObjectId

  // リレーションフィールド
  // データベースには実体のないフィールドとなる
  // Profile.userIdをUser.idの外部キーとする
  user   User   @relation(fields: [userId], references: [id])

  // リレーションスカラーフィールド
  // データーベースでは外部キーとなる
  userId String @unique @db.ObjectId
}

// 参照先モデル
model User {
  id String   @id @default(auto()) @map("_id") @db.ObjectId

  // リレーションフィールド
  // データベースには実体のないフィールドとなる
  // Userから見るとProfileとは紐づかないこともあるのでオプショナル型とする
  profile Profile?
}

https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/one-to-one-relations

RerrahRerrah

1対多関係

1対1関係と同様の定義を行う.違いは参照先のモデルの型がオプショナル型ではなく配列型になる.空の配列がリレーションなしの状態を示す.

// 参照元モデル
model Post {
  id String @id @default(auto()) @map("_id") @db.ObjectId

  // リレーションフィールド
  // データベースには実体のないフィールドとなる
  // Post.userIdをUser.idの外部キーとする
  user User @relation(fields: [userId], references: [id])

  // リレーションスカラーフィールド
  // データーベースでは外部キーとなる
  userId String @db.ObjectId
}

// 参照先モデル
model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId

  // リレーションフィールド
  // データベースには実体のないフィールドとなる
  // 複数のPostと関係があるので配列型にする
  profile Post[]
}

https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/one-to-many-relations

RerrahRerrah

多対多関係

多対多関係はRDBとMongoDBで扱いが異なる.

明示的な多対多関係 (Explicit many-to-many relations)

通常は多対多関係になるときは正規化を行って中間テーブルによるリレーション管理を行う.Prismaではこれを明示的な多対多関係と呼んでいる.

// 多モデルその1
model Post {
  id Int @id @default(autoincrement())
  categories CategoriesOnPosts[]
}

// 多モデルその2
model Category {
  id Int @id @default(autoincrement())
  posts CategoriesOnPosts[]
}

// 中間モデル
model CategoriesOnPosts {
  post Post @relation(fields: [postId], references: [id])
  postId Int

  category Category @relation(fields: [categoryId], references: [id])
  categoryId Int
  
  // 複合主キーを設定
  @@id([postId, categoryId])
}

なお,この方法はMongoDBでは定義できない.

暗黙的な多対多関係 (Implicit many-to-many relations)

Prismaでは中間モデルを定義せずに多対多関係を設定することもできる.これを暗黙的な多対多関係と呼んでいる.

// 多モデルその1
model Post {
  id Int @id @default(autoincrement())
  categories Category[]
}

// 多モデルその2
model Category {
  id Int @id @default(autoincrement())
  posts Post[]
}

このときスキーマでは中間モデルは定義しないが,データベース上には中間テーブルが自動的に作成される.

MongoDBで多対多関係を表現するにはこちらを使用する.

使い分け

基本的にはPrisma ORMが自動的にデータベースを構築するので,簡潔に表現できる暗黙的な多対多関係表現の使用が推奨される.
中間テーブルに情報を追加したいときなどは明示的な多対多関係表現を使う.

https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/many-to-many-relations

RerrahRerrah

同じモデルに対する複数のリレーションの設定

モデル内の異なるフィールドが同じモデルに対してそれぞれリレーションを持つ場合,リレーションに名前を付けてその関係を明確にする必要がある.

// 参照元モデル
model Post {
  id String @id @default(auto()) @map("_id") @db.ObjectId

  // リレーション "WrittenPosts"
  author   User   @relation(name: "WrittenPosts", fields: [authorId], references: [id])
  authorId String @unique @db.ObjectId

  // リレーション "PinnedPost"
  pinnedBy   User?   @relation(name: "PinnedPost", fields: [pinnedById], references: [id])
  pinnedById String? @unique @db.ObjectId
}

// 参照先モデル
model User {
  id String @id @default(auto()) @map("_id") @db.ObjectId

  // リレーション "WrittenPosts"
  writtenPosts Post[] @relation(name: "WrittenPosts")

  // リレーション "PinnedPost"
  pinnedPost Post? @relation(name: "PinnedPost")
}

https://www.prisma.io/docs/orm/prisma-schema/data-model/relations#disambiguating-relations

RerrahRerrah

セットアップ (PostgreSQL)

結局今回のデータはスキーマで設定できるあたり,RDBで管理する方があってる気がするので,PostgreSQLでやってみる.

https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-postgresql

RerrahRerrah

シェルで実行:

yarn add -D -E prisma
npx prisma init

.envを更新:

.env
DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/mydb?schema=public"

スキーマを更新:

prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

適当にモデル定義を書く.

RerrahRerrah

マイグレーションを実行する.

npx prisma migrate dev --name init

このコマンドでPrismaはシャドーDBと呼ばれる一時的なDBを作成し,マイグレーションの履歴によってシャドーDB上に作成されるスキーマとschema.prismaで定義している最新のスキーマを比較し,新たなマイグレーション履歴のファイルを作成する.
また,自動でprisma generateを実行し,クエリビルダーであるクライアントも作成する.

マイグレーションの履歴は./prisma/migrations以下に出力される.フォルダーを確認すると,マイグレーションの履歴ごとにSQLファイルが生成されているのが分かる.

RerrahRerrah

ここで@prisma/clientがインストールされていないとprisma generateは実行されないので,手動で行う.

yarn add -D -E @prisma/client
npx prisma generate
RerrahRerrah

クエリ

PrismaClientを通してデータベースを操作する.
このインスタンスのプロパティとして,スキーマで定義したモデル(テーブル)にアクセスできる.

接続を終了するときはPrismaClient.$disconnectを必ず呼び出す.

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

const prisma = new PrismaClient();

async function main() {
  // findMany()ですべてのレコードを取得する
  const allUsers = await prisma.user.findMany();
  console.log(allUsers);
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    // 必ず実行する
    await prisma.$disconnect();
  });

初回接続時は何もデータがないので,このコードでは空の配列が標準出力される.

RerrahRerrah

createはその引数dataのオブジェクト内でリレーションデータが存在するとき,そのデータのプロパティにcreateプロパティを持つオブジェクトを渡すことで入れ子状にデータの作成が行える.

  await prisma.user.create({
    data: {
      name: "Hoge",
      email: "hoge@fuga.com",
      // 入れ子で作成
      posts: {
        create: {
          title: "Kon'nichiwa!",
        },
      },
      // 入れ子で作成
      profile: {
        create: {
          bio: "Nemui.",
        },
      },
    },
  });
RerrahRerrah

findUniquefindManyなどでレコードを取得しても,リレーションデータに関しては取得できない.
このときはオプションでinclude指定してプロパティを取得するか真偽値またはselectオプションで指定する.

  // リレーションデータのうちpostsの全カラムも取得する
  const allUsers = await prisma.user.findMany({
    include: { posts: true },
  });

  // リレーションデータのうちposts.titleのみ取得する
  const allUsers2 = await prisma.user.findMany({
    include: {
      posts: {
        select: {
          title: true,
        },
      },
    },
  });

なお,リレーションデータのカラムとそれ以外のカラムでselectを組み合せたいときはincludeではなくselectのネストで指定しないといけない.

  // user.nameとuser.posts.titleのみを取得する
  const allUsers3 = await prisma.user.findMany({
    select: {
      name: true,
      posts: {
        select: {
          title: true,
        },
      },
    },
  });

https://www.prisma.io/docs/orm/prisma-client/queries/select-fields
https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries

RerrahRerrah

一つ前の投稿の「リレーションデータの情報を取得する」というのはいわゆる内部結合 (inner join)にあたる.

結合 (Join) の種類

SQLにおける2つのテーブルの結合には列方向の結合と行方向の結合に分けられる.

列方向の結合

内部結合 (Inner Join)

2つのテーブルの指定した列において,双方でデータが一致したレコードのみ抜き出し,列で結合して出力する.

左外部結合 (Left Outer Join)

2つのテーブルの指定した列において,左側のテーブルを基準にその列の値に位置した右のテーブルのレコードを抜き出し,列を結合する.一致した値が右のテーブルにないときは,結合後のレコードの足りないカラムはNULLとなる.

右外部結合 (Right Outer Join)

左外部結合とは逆に,右側のテーブルを基準にして同じ操作を行う.

自然結合 (Natural Join)

列の指定を行わず,2つのテーブルで名前が一致する列を基準にして結合する.内部結合,左右外部結合かはクエリの指定による.

行方向の結合

統合結合 (Union)

2つのテーブルが同じカラムで構成されていることを条件に,双方のレコードの重複を取り除いて結合する.

Union All

Unionの重複を許すときはALLをつける.

どうもPrismaは内部結合のみサポートしている?
PrismaClientでは全ての操作に対応しているわけではないので,細かい操作を行いたいなら$queryRawTypedで生SQL文を書くか,ORMに頼らないのがいいのかも...

RerrahRerrah

Generated Types

スキーマで定義したモデルをTypeScriptの型に変換したもの.Prisma名前空間にモデル名+CRUD操作のメソッド名などの形式で生成される.

// スキーマでモデルUserを定義したとき

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

const prisma = new PrismaClient();

// prisma.user.createの引数となるレコードの型
Prisma.UserCreateInput
// prisma.user.findManyなどのselectとして渡すオブジェクトの型
Prisma.UserSelect
// prisma.user.findManyなどのincludeとして渡すオブジェクトの型
Prisma.UserInclude

型アノテーションやsatisfiesで使える.

https://www.prisma.io/docs/orm/prisma-client/type-safety

RerrahRerrah

データの検証

データに対する検証は,DBサーバーが行うものと,クライアント側で行うものの2つが設定できる.

RerrahRerrah

DBサーバー側での検証

DBサーバーが行う検証としてCHECK制約がある.SQLの場合,CREATE TABLEでフィールドを定義するときにCHECKキーワードを使うことで,そのフィールドに入力可能なデータの制約(文字数や値域など)を設定できる.

Prismaではスキーマ定義でCHECKを指定することができないみたい.直接SQL文を叩いてテーブル定義するしかないようだ.

https://www.prisma.io/docs/orm/more/help-and-troubleshooting/help-articles/check-constraints

RerrahRerrah

クライアント側での検証

クライアント側ではZodなどのバリデーションライブラリーを使って,入力されたデータが特定のルールに適合しているかを検証する.

Prismaの場合,Prisma Client Extensionを利用してデータ検証を行う.Client Extensionのカスタムクエリ指定では,CRUD操作のメソッドを上書きすることができる.ここでカスタム定義したメソッドの中でバリデーションライブラリーを使用することで,CRUD操作操作時にデータ検証を行うことができる.

prisma.schema
model Product {
  id          Int    @id @default(autoincrement())
  name        String
  description String
}
validate.ts
import { Prisma } from "@prisma/client";
import { z } from "zod";

// Zodによるレコードの文字列型チェックと文字数,パターンチェックを行うスキーマの定義
export const ProductCreateInput = z.object({
  name: z.string().max(100),
  description: z.string().max(1000),
}) satisfies z.Schema<Prisma.ProductCreateInput>;
main.ts
import { PrismaClient } from "@prisma/client";
import { ProductCreateInput } from "./validate";

const prisma = new PrismaClient().$extends({
  query: {
    // Client Extensionsのカスタムクエリ定義
    product: {
      create({ args, query }) {
        args.data = ProductCreateInput.parse(args.data)
        return query(args)
      },
      update({ args, query }) {
        args.data = ProductCreateInput.partial().parse(args.data)
        return query(args)
      },
      updateMany({ args, query }) {
        args.data = ProductCreateInput.partial().parse(args.data)
        return query(args)
      },
      upsert({ args, query }) {
        args.create = ProductCreateInput.parse(args.create)
        args.update = ProductCreateInput.partial().parse(args.update)
        return query(args)
      },
    },
  },
})

https://www.prisma.io/docs/orm/prisma-client/client-extensions/query
https://www.prisma.io/docs/orm/prisma-client/queries/custom-validation

RerrahRerrah

トランザクション

データベースに対する手続きを1つのトランザクションとして扱うことによって,ACID特性による堅牢性・信頼性の恩恵を受けることができる.

ACID特性

以下の特性の頭文字をとったもの.

Atomicity(原子性)

操作が完全に実行されるか全くなかったかの2つの状態にしかならないこと.エラーにより途中の状態で中断されたままになることは許されない.

Consistency(一貫性)

操作前と操作後で整合性が保たれていること.決められた制約が操作によって破綻するようなことは許されない.

Isolation(独立性)

同時に複数の処理が実行されてもそれぞれは独立した処理として実行され,1つずつ処理を実行したときと同じ結果であること.ある処理が別の処理の途中結果に影響されることは許されない.

Durability(耐久性)

処理が完了した後の状態が永久的に記録されていること.障害が発生して,過去の処理の結果が失われることは許されない.

RerrahRerrah

Prismaではトランザクションを以下3つの方法で扱うことができる.

  • Nested write
  • Bulk operations
  • $transaction API
RerrahRerrah

Nested Write

createメソッドのオプションとして,relationのテーブルのcreateを指定することができる.
これによってrelatedなテーブルでレコードを追加した後に,メイン操作するテーブルにレコードを追加する,という2つのデータベース操作を1トランザクションとして実行できる.

const newUser: User = await prisma.user.create({
  data: {
    name: "Hoge",
    // Userテーブルに対して1対多関係であるPostテーブルにレコードを同時に追加する
    posts: {
      create: [
        { title: "Fuga" },
        { title: "Piyo" },
      ],
    },
  },
});

なお,find***系のメソッドにおけるincludeselectによるリレーションデータの同時読み取りもトランザクションの1つ (Nested read).

https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries

RerrahRerrah

Bulk Operations

ある条件を満たすレコードに対して,バッチ処理のように一つずつ操作を行うトランザクションがメソッドとして用意してある.
例えばupdateManyの場合,whereでフィルタリングされたレコードに対してdataで指定した値に更新する.

// Emailレコード中のUser.nameが"Hoge"なレコードはstarをtrueにする
await prisma.email.updateMany({
  where: {
    // relatedなデータのフィールドに対しても条件づけできる
    user: {
      name: "Hoge",
    },
  },
  data: {
    star: true,
  },
})

https://www.prisma.io/docs/orm/prisma-client/queries/transactions#bulk-operations

RerrahRerrah

$transaction API

Prisma Clientの$transactionメソッドを使って,複数のクエリをトランザクションとして扱う.
Sequential operationsとInteractive transactionsの2つの方法がある.

https://www.prisma.io/docs/orm/prisma-client/queries/transactions#the-transaction-api

Sequential Operations

$transactionの引数にPrisma Clientのクエリメソッドが返すPromiseオブジェクトのリストを渡す.こうすることで,リストの先頭から順にクエリのPromiseが実行される.メソッドの戻り値は各クエリの実行結果を並べたリストになる.

const [30olds, nUser] = prisma.$transaction([
  prisma.user.findMany({ where: { age: 30 } }),
  prisma.user.count(),
]);

Interactive Transactions

$transactionの引数に,PrismaClientを引数で受け取り,処理の結果を返すasync関数(アロー関数)を渡す.こうすることで,async関数の内部で記述した任意の処理がトランザクションとして実行される.
async関数の内部にはPrisma Clientのクエリメソッド呼び出し以外に,通常の処理(値の検証など)も記載することができる.

// Promiseを返すメソッドを作れば汎用性が上がる
function updateMatch(winner: Club, loser: Club, difference: number): Promise<void> {
  return await prisma.$transaction(async (client) => {
    // 1. クエリその1実行
    await client.club.update({
      where: {
        name: winner.name
      },
      data: {
        point: {
          increment: difference === 0 ? 1 : 3,
        },
        goalDifference: {
          increment: difference,
        },
      },
    });

    // 2. クエリ以外の処理を実行
    if (winner.name === loser.name) {
      // エラーを投げたときはトランザクション中止によりロールバックされる
      throw new Error(`A winner and a loser are the same club: ${winner.name}`);
    }

    // 3. クエリその2実行
    await client.club.update({
      where: {
        name: loser.name
      },
      data: {
        point: {
          increment: difference === 0 ? 1 : 0,
        },
        goalDifference: {
          decrement: difference,
        },
      },
    });

    // 処理が完了するとトランザクションはコミットされる.
  });
}

await updateMatch(VisselKobe, GambaOsaka, 1);

Interactive transactionsの方が柔軟性があって使い勝手が良さそう.

RerrahRerrah

Prisma Studio

Prismaで接続しているデータベースを可視化,操作しやすくするWebアプリ.

https://www.prisma.io/studio

スキーマファイルでデータベースへの接続設定が記載されていれば,以下のコマンド一発でデータベースへの接続とWebアプリの起動まで行われる.

npx prisma studio

テーブルUIを直接操作して,データベースへのレコード書き込み・削除・編集を行える.

RerrahRerrah

初期データの設定

Dockerコンテナ起動時に初期データをテーブルにセットしておきたいときはシーディングすればいい.

prisma/seed.tsなどのような場所に既存のレコードの削除と初期レコードの登録のクエリを記載したスクリプトを書いておく.そのあと,package.jsonのscriptsに以下の記述を追加する.

package.json
"scripts": {
  "seed": "tsx prisma/seed.ts"
},

これでyarn seedと実行すればテーブルの初期化が行えるようになる.