如何解决SqlBackend和PersistEntityBackend之间的类型不匹配?

时间:2016-11-23 04:54:54

标签: haskell monads servant

同时使用servantpersistent库创建REST API,并使用insertUnique创建新实体时遇到类型不匹配错误。

以下是有问题的功能:

createUser :: Entity User -> App Int64
createUser p = do
    maybeNewUser <- runDb (insertUnique (User (userUsername $ entityVal p) (userSpotifyUser $ entityVal p)))
    case maybeNewUser of
        Nothing -> throwError err400
        Just newUser -> return $ fromSqlKey newUser

出现以下错误:

Couldn't match expected type ‘persistent-2.2.4.1:Database.Persist.Sql.Types.SqlBackend’
        with actual type ‘persistent-2.2.4.1:Database.Persist.Class.PersistEntity.PersistEntityBackend
                            (String
                             -> String
                             -> time-1.5.0.1:Data.Time.Clock.UTC.UTCTime
                             -> time-1.5.0.1:Data.Time.Clock.UTC.UTCTime
                             -> User)’
In the first argument of ‘runDb’, namely
[snip]

供参考,runDb功能:

runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
    pool <- asks getPool
    liftIO $ runSqlPool query pool

App newtype:

newtype App a = App
    { runApp :: ReaderT Config (ExceptT ServantErr IO) a } deriving
        (Functor, Applicative, Monad, MonadReader Config, MonadError ServantErr, MonadIO)

我已尝试将insertUnique的结果提示为SqlBackend,但这会导致同样令人困惑的错误。 SqlBackendPersistentEntityBackend类型不可互换吗?

或许monad是畸形的?

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

我能够在this answer的帮助下解决这个问题。

get和其他人一样,此上下文中的insertUnique会返回普通User而不是Entity User

createUser :: User -> App Int64
createUser p = do
    user <- (User (userUsername $ entityVal p) (userSpotifyUser $ entityVal p))
    let insertUser = insertUnique user :: SqlPersistT IO (Maybe (Key User))
    maybeNewUserKey <- runDb insertUser
    case maybeNewUserKey of
        Nothing -> throwError err400
        Just newUserKey ->
            return $ fromSqlKey newUserKey

事后看来更有道理,因为runDb接受了SqlPersistT转换后的monad。