ymmr
Recent Articles
    公開日: 2023/10/18

    Prisma で NOT NULL 制約をかけたフィールドを追加する

    既にレコードが存在するテーブルに対して、NOT NULL 制約付きのフィールドを追加したいとします。しかし、既存のデータは追加するフィールドの値を持たないので、NOT NULL 制約を違反してしまいます。これらを共存させるには一手間必要なので、Prisma と SQLite を用いて方法を解説します。

    大まかな手順は以下の通りです。

    1. 一時的に NULL 許容でフィールドを追加する。
    2. すべてのレコードに追加したフィールドの値をセットする。
    3. 追加したフィールドに NOT NULL 制約を追加する。

    想定する環境

    Prisma で定義されたスキーマがあり、DB である SQLite 上に members テーブルが生成されているとします。既存のレコードを削除することなく、members テーブルに TEXT 型の kana フィールド (NOT NULL 制約付き) を追加するのが目標です。

    /prisma/schema.prisma
    model Member {
      id     Int    @id @default(autoincrement())
      name   String
      avatar String
    
      @@map("members")
    }
    
    CREATE TABLE IF NOT EXISTS "members" (
        "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        "name" TEXT NOT NULL,
        "avatar" TEXT NOT NULL
    );
    
    sqlite> SELECT * FROM "members";
    id|name|avatar
    1|鈴木|https://picsum.photos/200/300.jpg?random=1
    2|佐藤|https://picsum.photos/200/300.jpg?random=2
    3|田中|https://picsum.photos/200/300.jpg?random=3
    

    手順

    SQLite の CLI でデータベースに接続します。テーブルを操作できれば、DB への接続手段は問いません。

    sqlite3 prisma/dev.db
    

    はじめにスキーマを変更して、NULL 許容で kana フィールドを追加します。

    diff --git a/prisma/schema.prisma b/prisma/schema.prisma
    index 078feff..24c96d7 100644
    --- a/prisma/schema.prisma
    +++ b/prisma/schema.prisma
    @@ -8,8 +8,9 @@ datasource db {
     }
    
     model Member {
       id     Int     @id @default(autoincrement())
       name   String
    +  kana   String?
       avatar String
    
       @@map("members")
    

    続いて DB に変更を適用します。今回はデモのため Prisma CLI の push コマンドを使用しますが、変更の履歴 (マイグレーションファイル) が必要な場合は migrate コマンドに適宜切り替えてください。

    npx prisma db push
    
    Environment variables loaded from .env
    Prisma schema loaded from prisma/schema.prisma
    Datasource "db": SQLite database "dev.db" at "file:./dev.db"
    
    🚀  Your database is now in sync with your Prisma schema. Done in 8ms
    
    ✔ Generated Prisma Client (v5.4.2) to ./node_modules/@prisma/client in 48ms
    

    テーブルを確認すると kana フィールドが追加されています。

    sqlite> .schema members
    id|name|avatar|kana
    1|鈴木|https://picsum.photos/200/300.jpg?random=1|NULL
    2|佐藤|https://picsum.photos/200/300.jpg?random=2|NULL
    3|田中|https://picsum.photos/200/300.jpg?random=3|NULL
    

    既存のレコードに対して、kana フィールドの値を更新します。

    set_kana.sql
    UPDATE "members"
    SET "kana" = CASE
      WHEN "id" = "1" THEN "スズキ"
      WHEN "id" = "2" THEN "サトウ"
      WHEN "id" = "3" THEN "タナカ"
      ELSE ""
    END;
    
    sqlite> .read set_kana.sql
    
    sqlite> SELECT * FROM "members";
    id|name|avatar|kana
    1|鈴木|https://picsum.photos/200/300.jpg?random=1|スズキ
    2|佐藤|https://picsum.photos/200/300.jpg?random=2|サトウ
    3|田中|https://picsum.photos/200/300.jpg?random=3|タナカ
    

    最後にスキーマを変更することで、NOT NULL 制約を付与します。

    diff --git a/prisma/schema.prisma b/prisma/schema.prisma
    index 078feff..24c96d7 100644
    --- a/prisma/schema.prisma
    +++ b/prisma/schema.prisma
    @@ -8,8 +8,9 @@ datasource db {
     }
    
     model Member {
       id     Int     @id @default(autoincrement())
       name   String
    +  kana   String?
       avatar String
    
       @@map("members")
    
    npx prisma db push
    
    Environment variables loaded from .env
    Prisma schema loaded from prisma/schema.prisma
    Datasource "db": SQLite database "dev.db" at "file:./dev.db"
    
    🚀  Your database is now in sync with your Prisma schema. Done in 8ms
    
    ✔ Generated Prisma Client (v5.4.2) to ./node_modules/@prisma/client in 55ms
    

    これでフィールドの追加は完了です。テーブル定義が以下のように変更されました!

     CREATE TABLE IF NOT EXISTS "members" (
         "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
         "name" TEXT NOT NULL,
    +    "kana" TEXT NOT NULL,
         "avatar" TEXT NOT NULL
     );
    

    おわりに

    最近はもっぱらフロント周辺の技術を勉強していたので、久しぶりに DB 周りを触れて楽しかったです 🌝