gpt4 book ai didi

haskell - 持久性:CRUD TypeClass

转载 作者:行者123 更新时间:2023-12-04 04:38:41 26 4
gpt4 key购买 nike

我正在尝试编写一个类型类,以简化使用持久性、aeson 和 scotty 编写 CRUD 后端

这是我的想法:

runDB x = liftIO $ do info <- mysqlInfo
runResourceT $ SQL.withMySQLConn info $ SQL.runSqlConn x

class (J.FromJSON a, J.ToJSON a, SQL.PersistEntity a) => CRUD a where
getBasePath :: a -> String
getCrudName :: a -> String

getFromBody :: a -> ActionM a
getFromBody _ = do body <- jsonData
return body

mkInsertRoute :: a -> ScottyM ()
mkInsertRoute el =
do post (fromString ((getBasePath el) ++ "/" ++ (getCrudName el))) $ do
body <- getFromBody el
runDB $ SQL.insert body
json $ J.Bool True

mkUpdateRoute :: a -> ScottyM ()
mkDeleteRoute :: a -> ScottyM ()
mkGetRoute :: a -> ScottyM ()
mkGetAllRoute :: a -> ScottyM ()

这不编译,我得到这个错误:
Could not deduce (SQL.PersistEntityBackend a
~ Database.Persist.GenericSql.Raw.SqlBackend)
from the context (CRUD a)
bound by the class declaration for `CRUD'
at WebIf/CRUD.hs:(18,1)-(36,36)
Expected type: SQL.PersistEntityBackend a
Actual type: SQL.PersistMonadBackend
(SQL.SqlPersist (Control.Monad.Trans.Resource.ResourceT IO))
In the second argument of `($)', namely `SQL.insert body'
In a stmt of a 'do' block: runDB $ SQL.insert body
In the second argument of `($)', namely
`do { body <- getFromBody el;
runDB $ SQL.insert body;
json $ J.Bool True }'

看来我必须添加另一个类型约束,例如 PersistMonadBackend m ~ PersistEntityBackend a ,但我不知道如何。

最佳答案

约束意味着 PersistEntity 的关联后端类型实例需要是 SqlBackend ,所以当用户实现 PersistEntity类作为实现 CRUD 的一部分类,他们将需要指定。

从您的角度来看,您只需要启用 TypeFamilies扩展并将该约束添加到您的类定义中:

class ( J.FromJSON a, J.ToJSON a, SQL.PersistEntity a
, SQL.PersistEntityBackend a ~ SQL.SqlBackend
) => CRUD a where
...

在定义 PersistEntity 的实例时对于某些类型 FooCRUD 的用户将需要定义 PersistEntityBackend类型为 SqlBackend :
instance PersistEntity Foo where
type PersistEntityBackend Foo = SqlBackend

这是我通过 GHC 类型检查器的完整代码副本:
{-# LANGUAGE TypeFamilies #-}

import Control.Monad.Logger
import Control.Monad.Trans
import qualified Data.Aeson as J
import Data.Conduit
import Data.String ( fromString )
import qualified Database.Persist.Sql as SQL
import Web.Scotty

-- incomplete definition, not sure why this instance is now needed
-- but it's not related to your problem
instance MonadLogger IO

-- I can't build persistent-mysql on Windows so I replaced it with a stub
runDB x = liftIO $ runResourceT $ SQL.withSqlConn undefined $ SQL.runSqlConn x

class ( J.FromJSON a, J.ToJSON a, SQL.PersistEntity a
, SQL.PersistEntityBackend a ~ SQL.SqlBackend
) => CRUD a where

getBasePath :: a -> String
getCrudName :: a -> String

getFromBody :: a -> ActionM a
getFromBody _ = do body <- jsonData
return body

mkInsertRoute :: a -> ScottyM ()
mkInsertRoute el =
do post (fromString ((getBasePath el) ++ "/" ++ (getCrudName el))) $ do
body <- getFromBody el
runDB $ SQL.insert body
json $ J.Bool True

mkUpdateRoute :: a -> ScottyM ()
mkDeleteRoute :: a -> ScottyM ()
mkGetRoute :: a -> ScottyM ()
mkGetAllRoute :: a -> ScottyM ()

关于haskell - 持久性:CRUD TypeClass,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15945675/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com