8

I'm trying to use the cached function to prevent multiple db queries in different widgets and handlers:

newtype CachedBobId key
    = CachedBobId { unCachedBobId :: key }
    deriving Typeable

getBob' :: Handler BobId
getBob' = do
    uncle <- runInputGet $ ireq textField "bobsuncle"
    (Entity bob _) <- runDB $ getBy404 $ UniqueBob uncle
    return bob

getBob :: Handler BobId
getBob = do
    a <- getBob'
    let b = return $ CachedBobId a
    c <- cached b
    return $ unCachedBobId c

And in a widget somewhere:

renderDerp :: Widget
renderDerp = do
    --these are used in the shakespeare files
    lolBob <- handlerToWidget $ getBob
    nutherBob <- handlerToWidget $ getBob
    $(widgetFile "test")

This compiles but the query to get the ID still runs multiple times.

What am I doing wrong? Or is there a better way to only get bob once and use him in every handler and widget?

user2936306
  • 236
  • 2
  • 8
  • Didn't really read code inside the question (since I had a problem with `cached` too). Someone is going to get really easy 200 points. – Cthulhu Aug 25 '16 at 00:13

1 Answers1

4

I'm pretty new to Yesod, but I think you just need to tweak getBob

getBob :: Handler BobId
getBob = unCachedBobId <$> cached (CachedBobId <$> getBob')

The problem is that your current getBob function starts its do block with a <- getBob'. Remember that a do block sequences monadic actions, so you actually end up calling getBob' first thing every time getBob is called. In an ironic twist, after you've done this, you create a cached version of a handler which returns what you just got from getBob', but end up querying that cached version exactly once (right afterwards with c <- cached b), then it just falls out of scope and the garbage collector gets it.

In the solution I present above, you wrap whatever getBob' gives you in CachedBobId. Then, you pass that handler CachedBobId <$> getBob' :: Handler (CachedBobId BobId), to cached, which gives you back another handler cached (CachedBobId <$> getBob') of the same type, but with caching. Finally, you extract whatever the cached handler gives you to get back a Handler BobId.

Alec
  • 31,829
  • 7
  • 67
  • 114