Próbuję napisać typeclass który ułatwia pisanie backend CRUD używając trwałe, ajzon i ScottyPersistent: CRUD TypeClass
Oto mój pomysł:
runDB x = liftIO $ do info <- mysqlInfo
runResourceT $ SQL.withMySQLConn info $ SQL.runSqlConn x
class (J.FromJSON a, J.ToJSON a, SQL.PersistEntity a) => 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()
To nie robi Kompilacja, pojawia się ten błąd:
Could not deduce (SQL.PersistEntityBackend a
~ Database.Persist.GenericSql.Raw.SqlBackend)
from the context (CRUD a)
bound by the class declaration for `CRUD'
at WebIf/CRUD.hs:(18,1)-(36,36)
Expected type: SQL.PersistEntityBackend a
Actual type: SQL.PersistMonadBackend
(SQL.SqlPersist (Control.Monad.Trans.Resource.ResourceT IO))
In the second argument of `($)', namely `SQL.insert body'
In a stmt of a 'do' block: runDB $ SQL.insert body
In the second argument of `($)', namely
`do { body <- getFromBody el;
runDB $ SQL.insert body;
json $ J.Bool True }'
Wygląda na to, że muszę dodać kolejne ograniczenie typu, takie jak PersistMonadBackend m ~ PersistEntityBackend a
, ale nie widzę sposobu.
Dzięki! :-) Skończyłem z czymś takim, ale bardzo chciałbym, aby działał ze wszystkimi stałymi backendami, nie tylko tymi opartymi na SQL. Wiem, że bieżący runDB wymusza to, więc myślę, że prawdopodobnie potrzebuję jeszcze więcej abstrakcji. – agrafix
Ograniczenie pochodzi z domyślnej implementacji mkInsertRoute. Być może powinieneś usunąć domyślną definicję klasy lub abstrakcję poprzez bit 'runDB $ SQL.insert'? –
Myślę, że wystarczy streścić 'runDB'? – agrafix