--------------------------------------------------------------------------------
module Hakyll.Core.Provider.MetadataCache
    ( resourceMetadata
    , resourceBody
    , resourceLookupMetadataCache
    , resourceInvalidateMetadataCache
    ) where


--------------------------------------------------------------------------------
import           Control.Monad                 (unless)
import           Data.Maybe                    (fromMaybe)
import           Hakyll.Core.Identifier
import           Hakyll.Core.Metadata
import           Hakyll.Core.Provider.Internal
import           Hakyll.Core.Provider.Metadata
import qualified Hakyll.Core.Store             as Store


--------------------------------------------------------------------------------
resourceMetadata :: Provider -> Identifier -> IO Metadata
resourceMetadata :: Provider -> Identifier -> IO Metadata
resourceMetadata Provider
p Identifier
r
    | Bool -> Bool
not (Provider -> Identifier -> Bool
resourceExists Provider
p Identifier
r) = Metadata -> IO Metadata
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Metadata
forall a. Monoid a => a
mempty
    | Bool
otherwise                = do
        -- TODO keep time in md cache
        Provider -> Identifier -> IO ()
load Provider
p Identifier
r
        Metadata -> Maybe Metadata -> Metadata
forall a. a -> Maybe a -> a
fromMaybe Metadata
forall a. Monoid a => a
mempty (Maybe Metadata -> Metadata) -> IO (Maybe Metadata) -> IO Metadata
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Provider -> Identifier -> IO (Maybe Metadata)
resourceLookupMetadataCache Provider
p Identifier
r


--------------------------------------------------------------------------------
resourceBody :: Provider -> Identifier -> IO String
resourceBody :: Provider -> Identifier -> IO String
resourceBody Provider
p Identifier
r = do
    Provider -> Identifier -> IO ()
load Provider
p Identifier
r
    Store.Found bd <- Store -> [String] -> IO (Result (Maybe String))
forall a.
(Binary a, Typeable a) =>
Store -> [String] -> IO (Result a)
Store.get (Provider -> Store
providerStore Provider
p)
        [String
name, Identifier -> String
toFilePath Identifier
r, String
"body"]
    maybe (resourceString p r) return bd


--------------------------------------------------------------------------------
-- | Perform a lookup for metadata in the cache only.
-- Useful internally for invalidation.
resourceLookupMetadataCache :: Provider -> Identifier -> IO (Maybe Metadata)
resourceLookupMetadataCache :: Provider -> Identifier -> IO (Maybe Metadata)
resourceLookupMetadataCache Provider
p Identifier
r = do
    result <- Store -> [String] -> IO (Result BinaryMetadata)
forall a.
(Binary a, Typeable a) =>
Store -> [String] -> IO (Result a)
Store.get (Provider -> Store
providerStore Provider
p) [String
name, Identifier -> String
toFilePath Identifier
r, String
"metadata"]
    pure $ case result of
      Store.Found (BinaryMetadata Metadata
m) -> Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
m
      Result BinaryMetadata
Store.NotFound                 -> Maybe Metadata
forall a. Maybe a
Nothing
      Store.WrongType TypeRep
_ TypeRep
_            -> String -> Maybe Metadata
forall a. HasCallStack => String -> a
error String
"unexpected WrongType"


--------------------------------------------------------------------------------
resourceInvalidateMetadataCache :: Provider -> Identifier -> IO ()
resourceInvalidateMetadataCache :: Provider -> Identifier -> IO ()
resourceInvalidateMetadataCache Provider
p Identifier
r = do
    Store -> [String] -> IO ()
Store.delete (Provider -> Store
providerStore Provider
p) [String
name, Identifier -> String
toFilePath Identifier
r, String
"metadata"]
    Store -> [String] -> IO ()
Store.delete (Provider -> Store
providerStore Provider
p) [String
name, Identifier -> String
toFilePath Identifier
r, String
"body"]


--------------------------------------------------------------------------------
load :: Provider -> Identifier -> IO ()
load :: Provider -> Identifier -> IO ()
load Provider
p Identifier
r = do
    mmof <- Store -> [String] -> IO Bool
Store.isMember Store
store [String]
mdk
    unless mmof $ do
        (md, body) <- loadMetadata p r
        Store.set store mdk (BinaryMetadata md)
        Store.set store bk  body
  where
    store :: Store
store = Provider -> Store
providerStore Provider
p
    mdk :: [String]
mdk   = [String
name, Identifier -> String
toFilePath Identifier
r, String
"metadata"]
    bk :: [String]
bk    = [String
name, Identifier -> String
toFilePath Identifier
r, String
"body"]


--------------------------------------------------------------------------------
name :: String
name :: String
name = String
"Hakyll.Core.Resource.Provider.MetadataCache"