Reputation: 1443
I'm new to Haskell, coming from Scala. I like Haskell, but I feel like I'm fighting the type system when it comes to using persistent
.
My Request: I'd like to separate some insert logic into its own method. I can't quite figure out the types, or the right way to do this. All my failed attempts won't compile. More succinct questions below.
Here is the data declaration:
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Curator
name String
url String
feed String
UniqueUrl url
deriving Show
Article
url String
title String
content String
curatorId CuratorId Eq
deriving Show
|]
Here's a failed attempt that doesn't work:
insertArticle :: String -> String -> String -> MaybeT (???)
insertArticle url title content = do
curatorId <- selectFirst [curatorName ==. "Fake Name"]
lift $ do
curator <- curatorId
insert (Article url title content curator)
So, my questions:
???
? lift
in the right place? (usually the compiler is more helpful).PS - I have successfully abstracted other logic away, e.g. The insert is just causing me a world of pain. I was unable to get it to compile while using SqlPersistM
getFeeds :: SqlPersistM [Curator]
getFeeds = do
curatorIds <- selectList [] [Asc CuratorName]
let curatorGenerics = map entityVal curatorIds
let curators = map (\x -> x :: Curator) curatorGenerics
return curators
Upvotes: 2
Views: 335
Reputation: 6703
The return type of insertArticle
should be SqlPersistM (Maybe ArticleId)
, because it returns Just
an inserted article id or Nothing
in SqlPersistM
monad.
You can implement the function something like:
insertArticle :: String -> String -> String -> SqlPersistM (Maybe ArticleId)
insertArticle url title content = do
curatorEntity <- selectFirst [CuratorName ==. "Fake Name"] []
for curatorEntity $ \(Entity curatorId _) ->
insert (Article url title content curatorId)
I use for
from Data.Traversable
to handle the Maybe
value selectFirst
returns here.
But, actually, I don't like this type signature because it sticks to the sql backend. To make it more generalized, you can write a type annotation like this.
insertArticle :: (Applicative m, PersistQuery m, PersistMonadBackend m ~ PersistEntityBackend Curator) =>
String -> String -> String -> m (Maybe ArticleId)
The signature is a bit complex, but this function works with any backends.
By the way, your getFeeds
can be simplified.
getFeeds :: (Functor m, PersistQuery m, PersistMonadBackend m ~ PersistEntityBackend Curator) =>
m [Curator]
getFeeds = map entityVal <$> selectList [] [Asc CuratorName]
Upvotes: 1