Haskell Persistent insert rows if not already in database

haskell, haskell-platform, yesod

Solution

insertBy doesn't take a Unique constraint as parameter, getBy is more appropriate.

But insertUnique is a short possibility with Maybe result.

postFeedR :: Handler RepHtml
postFeedR = do
    url <- runInputPost $ ireq urlField "url"
    title <- runInputPost $ ireq textField "title"

    runDB $ do
        feedId <- insertFeed url
        _mbSubscriptionId <- insertUnique $ Subscription feedId title
        return ()

    defaultLayout ...

insertFeed url = do
    f <- insertBy $ Feed url
    case f of
        Left (Entity uid _) -> return uid
        Right uid -> return uid

Problem

I'm trying to use Yesod and persistent to create a website. I'm a bit confused about how to use the persistent API. Here's two of my tables ``` Feed url Text UniqueFeed url Subscription feed FeedId title Text UniqueSubscription feed ``` I'm trying to create a Feed if a feed with that URL does not exists, and then add a subscription to that feed, if a subscription does not already exist. ``` postFeedR :: Handler RepHtml postFeedR = do url <- runInputPost $ ireq urlField "url" title <- runInputPost $ ireq textField "title" runDB $ do feedId <- insertFeed $ UniqueFeed url subscriptionId <- insertSubscription feedId title return defaultLayout [whamlet| <p>done|] insertFeed url = do f <- insertBy $ UniqueFeed url case f of Left (Entity uid _) -> uid Right (Key uid) -> do (Key uid) <- insert $ Feed url return uid insertSubscription feedId title = do s <- insertBy $ UniqueSubscription feedId case s of Left (Entity uid _) -> uid Right (Key uid) -> do (Key uid) <- insert $ Subscription feedId title return uid ``` I get the errors below. I don't understand why ghc thinks that the return value of insertFeed and insertSubscription should be UniqueFeed and UniqueSubscription. I would like those functions to return the keys of the newly created records. Also, it seems like I'm throwing away the Key that I get back in each of the Right clauses of the case. Why does persistent return those keys. In the case where the UniqueSubscription is not in the database, persistent does not have enough information to create a new Subscription record, because it is missing the title, which is not on the UniqueSubscription. If someone could give me some pointers on how to use the persistent API, I would really appreciate it. ``` Handler/Home.hs:62:9: Kind incompatibility when matching types: a0 :: * GHandler App App :: * -> * Expected type: (a0 -> t0) -> (t0 -> a0 -> m0 a0) -> YesodDB App App (m0 a0) Actual type: (a0 -> t0) -> (t0 -> a0 -> m0 a0) -> a0 -> m0 a0 In a stmt of a 'do' block: feedId <- insertFeed $ UniqueFeed url In the second argument of `($)', namely `do { feedId <- insertFeed $ UniqueFeed url; subscriptionId <- insertSubscription feedId title; return }' Handler/Home.hs:62:9: Couldn't match type `YesodPersistBackend App' with `(->)' Expected type: (a0 -> t0) -> (t0 -> a0 -> m0 a0) -> YesodDB App App (m0 a0) Actual type: (a0 -> t0) -> (t0 -> a0 -> m0 a0) -> a0 -> m0 a0 In a stmt of a 'do' block: feedId <- insertFeed $ UniqueFeed url In the second argument of `($)', namely `do { feedId <- insertFeed $ UniqueFeed url; subscriptionId <- insertSubscription feedId title; return }' Handler/Home.hs:74:20: Couldn't match expected type `Unique Feed' with actual type `Database.Persist.Store.PersistValue' In the first argument of `return', namely `uid' In a stmt of a 'do' block: return uid In the expression: do { (Key uid) <- insert $ Feed url; return uid } Handler/Home.hs:83:20: Couldn't match expected type `Unique Subscription' with actual type `Database.Persist.Store.PersistValue' In the first argument of `return', namely `uid' In a stmt of a 'do' block: return uid In the expression: do { (Key uid) <- insert $ Subscription feedId title; return uid } ```

Original source