A Friedrich
A Friedrich

Reputation: 603

Couldn't match type ‘PersistEntityBackend U’ with ‘SqlBackend’

The following code produces a compile error Couldn't match type ‘PersistEntityBackend U’ with ‘SqlBackend’ arising from a use of ‘insertUser’ due to the commented line:

sampleUser :: Entity User
sampleUser = Entity (toSqlKey 1) $ User
  { userName = "admin"
  , userEmail = "[email protected]"
  }

type U = Entity User

connectInfo :: MySQLConnectInfo
connectInfo = undefined

runAction :: (MonadUnliftIO m, IsPersistBackend r, BaseBackend r ~ SqlBackend) => MySQLConnectInfo -> ReaderT r (LoggingT m) a -> m a
runAction connectInfo action = runStdoutLoggingT $ withMySQLConn connectInfo $ \backend ->
  runReaderT action backend

insertUser :: (PersistEntity U, PersistRecordBackend U SqlBackend) => 
             U -> ReaderT SqlBackend (LoggingT IO) (Key U) 
insertUser = insert

doDBStuff :: IO ()
doDBStuff = do
  runAction connectInfo (runMigration migrateAll)
  runAction connectInfo (insertUser sampleUser) -- compile error
  return ()

As far as I can see, I've specialized all the types in insertUser and have added all necessary constraints (having read the related SO question). What am I missing?

Upvotes: 0

Views: 169

Answers (2)

A Friedrich
A Friedrich

Reputation: 603

Asking ghci :info User gave me the right hint: It shows its class instances. It turns out that it is wrong to use Entity User directly. I suspect that while this creates the entity, all the class instances generated by Database.Persist.TH.share are missing from it. Following code compiles, having also removed the redundant constraint as mentioned by Bjartur:

sampleUser :: User
sampleUser = User
  { userName = "admin"
  , userEmail = "[email protected]"
  }

type U = User

connectInfo :: MySQLConnectInfo
connectInfo = undefined

runAction :: (MonadUnliftIO m, IsPersistBackend r, BaseBackend r ~ SqlBackend) => MySQLConnectInfo -> ReaderT r (LoggingT m) a -> m a
runAction connectInfo action = runStdoutLoggingT $ withMySQLConn connectInfo $ \backend ->
  runReaderT action backend

insertUser :: (PersistRecordBackend U SqlBackend) => 
             U -> ReaderT SqlBackend (LoggingT IO) (Key U) 
insertUser = insert

doDBStuff :: IO ()
doDBStuff = do
  runAction connectInfo (runMigration migrateAll)
  runAction connectInfo (insertUser sampleUser) -- compile error fixed
  return ()

Upvotes: 0

Bjartur Thorlacius
Bjartur Thorlacius

Reputation: 804

You have a PersistRecordBackend U SqlBackend constraint I don't know if you need, but I suspect you need a PersistEntityBackend U ~ SqlBackend constraint for insertUser. Or so the compiler suggests.

See Couldn't match type ‘PersistEntityBackend (Entity a)’ with ‘SqlBackend’

Upvotes: 0

Related Questions