{-|
Module      : Slick.Shake
Description : DEPRECATED -- Advanced caching tools for using slick with shake
Copyright   : (c) Chris Penner, 2019
License     : BSD3
-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TypeFamilies               #-}

module Slick.Caching {-# DEPRECATED "No longer necessary with slick >= 0.3.0.0" #-}
  ( simpleJsonCache
  , simpleJsonCache'
  , jsonCache
  , jsonCache'
  )
where

import Data.Aeson                 as A
import Data.ByteString.Lazy
import Development.Shake          hiding (Resource)
import Development.Shake.Classes
import GHC.Generics               (Generic)

--------------------------------------------------------------------------------

newtype CacheQuery q =
  CacheQuery q
  deriving (Int -> CacheQuery q -> ShowS
forall q. Show q => Int -> CacheQuery q -> ShowS
forall q. Show q => [CacheQuery q] -> ShowS
forall q. Show q => CacheQuery q -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CacheQuery q] -> ShowS
$cshowList :: forall q. Show q => [CacheQuery q] -> ShowS
show :: CacheQuery q -> String
$cshow :: forall q. Show q => CacheQuery q -> String
showsPrec :: Int -> CacheQuery q -> ShowS
$cshowsPrec :: forall q. Show q => Int -> CacheQuery q -> ShowS
Show, CacheQuery q -> CacheQuery q -> Bool
forall q. Eq q => CacheQuery q -> CacheQuery q -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CacheQuery q -> CacheQuery q -> Bool
$c/= :: forall q. Eq q => CacheQuery q -> CacheQuery q -> Bool
== :: CacheQuery q -> CacheQuery q -> Bool
$c== :: forall q. Eq q => CacheQuery q -> CacheQuery q -> Bool
Eq, forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall q x. Rep (CacheQuery q) x -> CacheQuery q
forall q x. CacheQuery q -> Rep (CacheQuery q) x
$cto :: forall q x. Rep (CacheQuery q) x -> CacheQuery q
$cfrom :: forall q x. CacheQuery q -> Rep (CacheQuery q) x
Generic, Get (CacheQuery q)
[CacheQuery q] -> Put
CacheQuery q -> Put
forall q. Binary q => Get (CacheQuery q)
forall q. Binary q => [CacheQuery q] -> Put
forall q. Binary q => CacheQuery q -> Put
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
putList :: [CacheQuery q] -> Put
$cputList :: forall q. Binary q => [CacheQuery q] -> Put
get :: Get (CacheQuery q)
$cget :: forall q. Binary q => Get (CacheQuery q)
put :: CacheQuery q -> Put
$cput :: forall q. Binary q => CacheQuery q -> Put
Binary, CacheQuery q -> ()
forall q. NFData q => CacheQuery q -> ()
forall a. (a -> ()) -> NFData a
rnf :: CacheQuery q -> ()
$crnf :: forall q. NFData q => CacheQuery q -> ()
NFData, Int -> CacheQuery q -> Int
CacheQuery q -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
forall {q}. Hashable q => Eq (CacheQuery q)
forall q. Hashable q => Int -> CacheQuery q -> Int
forall q. Hashable q => CacheQuery q -> Int
hash :: CacheQuery q -> Int
$chash :: forall q. Hashable q => CacheQuery q -> Int
hashWithSalt :: Int -> CacheQuery q -> Int
$chashWithSalt :: forall q. Hashable q => Int -> CacheQuery q -> Int
Hashable)

type instance RuleResult (CacheQuery q) = ByteString

-- | Note that you probably don't need this if you're using the recommended @Development.Shake.Forward@ module. It can do a lot of caching for you, otherwise look at 'Development.Shake.Forward.cacheAction'.
--
-- A wrapper around 'addOracleCache' which given a @q@ which is a 'ShakeValue'
-- allows caching and retrieving 'Value's within Shake. See documentation on
-- 'addOracleCache' or see Slick examples for more info.
--
-- > -- We need to define a unique datatype as our cache key
-- > newtype PostFilePath =
-- >   PostFilePath String
-- > -- We can derive the classes we need (using GeneralizedNewtypeDeriving)
-- > -- so long as the underlying type implements them
-- >   deriving (Show, Eq, Hashable, Binary, NFData)
-- > -- now in our shake rules we can create a cache by providing a loader action
-- >
-- > do
-- > postCache <- jsonCache $ \(PostFilePath path) ->
-- >   readFile' path >>= markdownToHTML . Text.pack
-- > -- Now use postCache inside an Action to load your post with caching!
jsonCache :: ShakeValue q => (q -> Action Value) -> Rules (q -> Action Value)
jsonCache :: forall q.
ShakeValue q =>
(q -> Action Value) -> Rules (q -> Action Value)
jsonCache = forall a q.
(ToJSON a, FromJSON a, ShakeValue q) =>
(q -> Action a) -> Rules (q -> Action a)
jsonCache'

-- | Like 'jsonCache' but allows caching/retrieving any JSON serializable
-- objects.
jsonCache'
  :: forall a q
   . (ToJSON a, FromJSON a, ShakeValue q)
  => (q -> Action a)
  -> Rules (q -> Action a)
jsonCache' :: forall a q.
(ToJSON a, FromJSON a, ShakeValue q) =>
(q -> Action a) -> Rules (q -> Action a)
jsonCache' q -> Action a
loader = FromJSON a => (CacheQuery q -> Action ByteString) -> q -> Action a
unpackJSON
  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall q a.
(RuleResult q ~ a, ShakeValue q, ShakeValue a, Partial) =>
(q -> Action a) -> Rules (q -> Action a)
addOracleCache (\(CacheQuery q
q) -> forall a. ToJSON a => a -> ByteString
A.encode forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> q -> Action a
loader q
q)
 where
  unpackJSON
    :: FromJSON a => (CacheQuery q -> Action ByteString) -> q -> Action a
  unpackJSON :: FromJSON a => (CacheQuery q -> Action ByteString) -> q -> Action a
unpackJSON CacheQuery q -> Action ByteString
runCacheQuery = \q
q -> do
    ByteString
bytes <- CacheQuery q -> Action ByteString
runCacheQuery forall a b. (a -> b) -> a -> b
$ forall q. q -> CacheQuery q
CacheQuery q
q
    case forall a. FromJSON a => ByteString -> Either String a
A.eitherDecode ByteString
bytes of
      Left  String
err -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err
      Right a
res -> forall (f :: * -> *) a. Applicative f => a -> f a
pure a
res

-- | Note that you probably don't need this if you're using the recommended @Development.Shake.Forward@ module. It can do a lot of caching for you, otherwise look at 'Development.Shake.Forward.cacheAction'.
--
-- A wrapper around 'jsonCache' which simplifies caching of values which do NOT
-- depend on an input parameter. Unfortunately Shake still requires that the
-- key type implement several typeclasses, however this is easily accomplished
-- using @GeneralizedNewtypeDeriving@ and a wrapper around @()@.
-- example usage:
--
-- > {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- > module Main where
-- > newtype ProjectList = ProjectList ()
-- >   deriving (Show, Eq, Hashable, Binary, NFData)
--  Within your shake Rules:
--
-- > projectCache = simpleJsonCache (ProjectList ()) $ do
-- >   -- load your project list here; returning it as a Value
simpleJsonCache :: ShakeValue q => q -> Action Value -> Rules (Action Value)
simpleJsonCache :: forall q. ShakeValue q => q -> Action Value -> Rules (Action Value)
simpleJsonCache = forall q a.
(ToJSON a, FromJSON a, ShakeValue q) =>
q -> Action a -> Rules (Action a)
simpleJsonCache'

-- | Like 'simpleJsonCache' but allows caching any JSON serializable object.
simpleJsonCache'
  :: forall q a
   . (ToJSON a, FromJSON a, ShakeValue q)
  => q
  -> Action a
  -> Rules (Action a)
simpleJsonCache' :: forall q a.
(ToJSON a, FromJSON a, ShakeValue q) =>
q -> Action a -> Rules (Action a)
simpleJsonCache' q
q Action a
loader = do
  q -> Action a
cacheGetter <- forall a q.
(ToJSON a, FromJSON a, ShakeValue q) =>
(q -> Action a) -> Rules (q -> Action a)
jsonCache' (forall a b. a -> b -> a
const Action a
loader)
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ q -> Action a
cacheGetter q
q