yesodweb/persistent

SQLite: FOREIGN KEY constraint failed when migrating

オープン

#1,125 opened on 2020/09/18

 (7 件のコメント) (5 件のリアクション) (0 人の担当者)Haskell (302 件のフォーク)auto 404
good first issue

Repository metrics

Stars
 (484 個のスター)
PR merge metrics
 (PR metrics pending)

説明

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

import Database.Persist.Sqlite
import Database.Persist.TH

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    -- Uncomment this line in the second run
    -- age Int Maybe
    deriving Show
BlogPost
    title String
    authorId PersonId
    deriving Show
|]

main :: IO ()
main = runSqlite "db" $ do
    runMigration migrateAll
    -- Comment this line in the second run
    johnId <- insert $ Person "John Doe"
    -- Uncomment this line in the second run
    -- johnId <- insert $ Person "John Doe" $ Just 35
    insert $ BlogPost "post" johnId
    pure ()
  1. stack ghc the script above and run.
  2. Edit the script, uncomment 2 lines and comment 1 line.
  3. stack ghc the script and run again.
  4. You will see:
Migrating: CREATE TEMP TABLE "person_backup"("id" INTEGER PRIMARY KEY,"name" VARCHAR NOT NULL,"age" INTEGER NULL)
Migrating: INSERT INTO "person_backup"("id","name") SELECT "id","name" FROM "person"
Migrating: DROP TABLE "person"
main: SQLite3 returned ErrorConstraint while attempting to perform step: FOREIGN KEY constraint failed

The correct way to do migrations in SQLite is documented here: https://sqlite.org/lang_altertable.html#making_other_kinds_of_table_schema_changes

In short, you need to disable foreign keys temporarily using PRAGMA commands when migrating. But this seems impossible because I can only send raw commands inside an automatically started transaction. And inside a transaction, PRAGMA foreign_keys=OFF has no effect.

Could you please change the logic of runMigration so that it follows the 12 steps in SQLite document precisely?

コントリビューターガイド