Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Persistent insert rows if not already in database

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 }
like image 678
Kevin Avatar asked Apr 30 '13 06:04

Kevin


1 Answers

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
like image 163
Gabriel Riba Avatar answered Sep 19 '22 10:09

Gabriel Riba