0

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 = "admin@test.com"
  }

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?

A Friedrich
  • 593
  • 6
  • 11

2 Answers2

0

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’

  • The error remains; I was under the impression that `PersistEntityBackend U ~ SqlBackend` was already covered by the `PersistRecordBackend U SqlBackend` constraint alias. – A Friedrich Feb 19 '20 at 16:28
  • You're absolutely right, as can be seen in in an appendix in an answer to the very Q&A we both linked. I should've read further before dismissing this as a duplicate question. It follows that your PersistEntity U constraint on the type of insertUser is redundant. – Bjartur Thorlacius Feb 20 '20 at 09:00
0

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 = "admin@test.com"
  }

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 ()
A Friedrich
  • 593
  • 6
  • 11