什么可能导致 Yesod + sqlite3 出现 ErrorConstraint SqliteException 错误?

What may cause an ErrorConstraint SqliteException error with Yesod + sqlite3?

什么可能导致以下错误?

 uncaught exception: SqliteException (SQLite3 returned ErrorConstraint while attempting to perform step.)

奇怪的是,大多数使用 withApp.

的规范都因此错误而失败

但是,如果我将 TestImport.hs 中的 wipeDB 修改为

system "rm project-name_test.sqlite3*"

然后突然所有规格再次通过。尽管 test-运行 花费了大约 4-5 倍的时间,这并不理想。

难道wipeDB的逻辑(由stack new生成)不够彻底?

我试图查看 models 文件,看看我是否在其中指定了唯一性约束,但我没有发现任何不合适的地方。

我已经评论了 models 中的所有内容,除了:

User
    emailAddress Text
    password ByteString
    verified Bool
    verifyKey Text
    resetPasswordKey Text
    deriving Show

Foo
    userA UserId
    userB UserId
    deriving Show

如果有约束,它们会在这个文件中,不是吗?还是可以有其他地方声明约束?无论如何,异常可能指的是什么约束?

我还没有像我希望的那样缩小它的范围,但似乎所有这些都可以追溯到 runDB $ insert $ Foo,如果我删除它,有问题的异常就消失了,更多的规范通过了,只有少数失败了,因为他们期望插入已经发生。而且它们也因断言失败而失败,而不是 ErrorConstraint 异常。

如果此错误有多种可能的原因,我想听听它们,因为我发现异常比我想要的更模糊。

This 是我找到的最佳解决方案。看起来像 "official" 解决方案。

所以在我的项目中我已经完成了 this way

现在这是我的 wipeDB 函数:

wipeDB :: App -> IO ()
wipeDB app = do
    let settings = appSettings app
        logFunc = messageLoggerSource app (appLogger app)

    sqliteConn <- rawConnection (sqlDatabase $ appDatabaseConf settings)
    let infoNoFK = set fkEnabled False $ mkSqliteConnectionInfo ""
        wrapper = wrapConnectionInfo infoNoFK sqliteConn
    pool <- runLoggingT (createSqlPool wrapper 1) logFunc

    flip runSqlPersistMPool pool $ do
        tables <- getTables
        sqlBackend <- ask
        let queries = map (\t -> "DELETE FROM " ++ (connEscapeName sqlBackend $ DBName t)) tables
        forM_ queries (\q -> rawExecute q [])