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?
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With