🐛

[Prisma] スキーマの default value を削除するときは バグに気をつけろ [MySQL]

2025/02/10に公開

はじめに

https://github.com/prisma/prisma/issues/26284

Issue 作りました。

環境

  • MySQL 8 系
  • Prisma 5.22.0 ~ 6.3.1 (20250210 現在の最新)

発生

    status String? @default("hoge")

👆 default 値を持っている + Nullable なものを

    status String?

default 値だけ無くして migration するとバグる。

事象

上記フィールドに undefined を渡して create すると Prisma が勝手に「Nullable ではない」と Violation を出すようになる。

Null constraint violation on the fields: (`status`)

もちろん、プロパティ自体を指定せずに create しても同じ。
しかし、なぜか null を明示的に渡すと成功する。不思議。

ちなみに Debug log を見たところ、DB へのクエリは発行されていないので、完全に Prisma 側のドジっ子である。

原因

DDL で見ていく。

-   `limit_kw` decimal(10,6) DEFAULT "hoge",
+   `limit_kw` decimal(10,6) DEFAULT NULL,

本来は上記のようになるべき。の様子。
prisma db push をすると上記の形になって、当該バグは起きない。

-   `limit_kw` decimal(10,6) DEFAULT "hoge",
+   `limit_kw` decimal(10,6),

上記が事象発生状態。
「default を削除した = DEFAUT を DROP する」という組み分けしか出来ていない様子。
本来は DEFAULT NULL が残るべき。
いや、残らなくても MySQL としては Null を許容するのだけども、Prisma は明示的に求めている様子。

ALTER TABLE `task` ALTER COLUMN `status` DROP DEFAULT;

ワークアラウンド

1. nullを明示的に渡す。

前述したやり方。

        await prisma.task.create({
            data: {
                title: 'Task 1',
                status: null,
            },
        });

でも、そう 美しくない。
もしまた デフォルト値を適用することになったらどうする?
メンテナンス性が下がっているのは明白。

2. migration を適用しなおす

DEFAULT NULL を復活させるやり方。

    status String

👆 一回 Nullable じゃなくしてから prisma migrate dev

そのあと、

    status String?

Nullable にして、また prisma migrate dev する。

そうすると migration.sql が2つできるので、1つ目を完全に消す。
これで DDL が意図したものになるため、成功するようになる。

Discussion