The constraint means that the associated backend type for a PersistEntity
instance needs to be SqlBackend
, so when a user implements the PersistEntity
class as part of implementing the CRUD
class they will need to specify that.
From your point of view, you just need to enable the TypeFamilies
extension and add that constraint to your class definition:
class ( J.FromJSON a, J.ToJSON a, SQL.PersistEntity a
, SQL.PersistEntityBackend a ~ SQL.SqlBackend
) => CRUD a where
...
When defining an instance of PersistEntity
for some type Foo
, the user of CRUD
will need to define the PersistEntityBackend
type to be SqlBackend
:
instance PersistEntity Foo where
type PersistEntityBackend Foo = SqlBackend
Here's my complete copy of your code that passes the GHC type-checker:
{-# 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 ()