Using both the servant
and persistent
libraries to create a REST API and I'm running into a type mismatch error using insertUnique
to create a new Entity.
Here's the offending function:
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
With the following error:
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]
And for reference, the runDb
function:
runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
And the App
newtype:
newtype App a = App
{ runApp :: ReaderT Config (ExceptT ServantErr IO) a } deriving
(Functor, Applicative, Monad, MonadReader Config, MonadError ServantErr, MonadIO)
I've tried type hinting the result of insertUnique
as SqlBackend
, but that causes an equally confusing error. Are the SqlBackend
and PersistentEntityBackend
types not interchangeable?
Or perhaps the monad is malformed?
Any assistance is greatly appreciated.
I was able to figure it out with the help of this answer.
Like get
and others, insertUnique
in this context returns a plain User
not an 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
Makes much more sense in hindsight since runDb
accepts a SqlPersistT
transformed monad.