{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE BangPatterns #-}
module Haxl.Core.RequestStore
( BlockedFetches(..)
, BlockedFetchInternal(..)
, RequestStore
, isEmpty
, noRequests
, addRequest
, contents
, getSize
, ReqCountMap(..)
, emptyReqCounts
, filterRCMap
, getMapFromRCMap
, getSummaryMapFromRCMap
, addToCountMap
, subFromCountMap
) where
import Haxl.Core.DataSource
import Haxl.Core.Stats
import Data.Map (Map)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Map.Strict as Map
import Data.Proxy
import Data.Text (Text)
import Data.Typeable
import Unsafe.Coerce
newtype RequestStore u = RequestStore (Map TypeRep (BlockedFetches u))
newtype BlockedFetchInternal = BlockedFetchInternal CallId
data BlockedFetches u =
forall r. (DataSource u r) =>
BlockedFetches [BlockedFetch r] [BlockedFetchInternal]
isEmpty :: RequestStore u -> Bool
isEmpty (RequestStore m) = Map.null m
noRequests :: RequestStore u
noRequests = RequestStore Map.empty
addRequest
:: forall u r. (DataSource u r)
=> BlockedFetch r -> BlockedFetchInternal -> RequestStore u -> RequestStore u
addRequest bf bfi (RequestStore m) =
RequestStore $ Map.insertWith combine ty (BlockedFetches [bf] [bfi]) m
where
combine :: BlockedFetches u -> BlockedFetches u -> BlockedFetches u
combine _ (BlockedFetches bfs bfis)
| typeOf1 (getR bfs) == ty = BlockedFetches (unsafeCoerce bf:bfs) (bfi:bfis)
| otherwise = error "RequestStore.insert"
getR :: [BlockedFetch r1] -> r1 a
getR _ = undefined
ty :: TypeRep
!ty = typeOf1 (undefined :: r a)
contents :: RequestStore u -> [BlockedFetches u]
contents (RequestStore m) = Map.elems m
getSize :: RequestStore u -> Int
getSize (RequestStore m) = Map.size m
newtype ReqCountMap = ReqCountMap (Map Text (Map TypeRep Int))
deriving (Show)
emptyReqCounts :: ReqCountMap
emptyReqCounts = ReqCountMap Map.empty
addToCountMap
:: forall (r :: * -> *). (DataSourceName r, Typeable r)
=> Proxy r
-> Int
-> ReqCountMap
-> ReqCountMap
addToCountMap = updateCountMap (+)
subFromCountMap
:: forall (r :: * -> *). (DataSourceName r, Typeable r)
=> Proxy r
-> Int
-> ReqCountMap
-> ReqCountMap
subFromCountMap = updateCountMap (-)
updateCountMap
:: forall (r :: * -> *). (DataSourceName r, Typeable r)
=> (Int -> Int -> Int)
-> Proxy r
-> Int
-> ReqCountMap
-> ReqCountMap
updateCountMap op p n (ReqCountMap m) = ReqCountMap $ Map.insertWith
(flip (Map.unionWith op))
(dataSourceName p) (Map.singleton ty n)
m
where
ty :: TypeRep
!ty = typeOf1 (undefined :: r a)
filterRCMap :: ReqCountMap -> ReqCountMap
filterRCMap (ReqCountMap m) = ReqCountMap $
Map.filter ((> 0) . Map.size) (Map.filter (> 0) <$> m)
getMapFromRCMap :: ReqCountMap -> Map Text (Map TypeRep Int)
getMapFromRCMap r
| ReqCountMap m <- filterRCMap r = m
getSummaryMapFromRCMap :: ReqCountMap -> HashMap.HashMap Text Int
getSummaryMapFromRCMap (ReqCountMap m) = HashMap.fromList
[ (k, s)
| (k, v) <- Map.toList m
, not $ Map.null v
, let s = sum $ Map.elems v
, s > 0
]