{-# LANGUAGE EmptyCase #-}
{-# OPTIONS_HADDOCK not-home #-}

-- | Supporting functionality for fine-grained dependency tracking.
module Hasura.Incremental.Internal.Dependency
  ( Access (AccessedAll),
    Accesses,
    Cacheable (..),
    Dependency (..),
    DependencyKey (DependencyRoot),
    recordAccess,
    selectD,
    selectKeyD,
  )
where

import Data.Aeson (Key, Value)
import Data.Aeson.KeyMap qualified as KM
import Data.ByteString (ByteString)
import Data.CaseInsensitive (CI)
import Data.Dependent.Map qualified as DM
import Data.Functor.Classes (Eq1 (..), Eq2 (..))
import "some" Data.GADT.Compare
import Data.HashMap.Strict qualified as HM
import Data.HashMap.Strict.InsOrd qualified as OHM
import Data.HashMap.Strict.NonEmpty (NEHashMap)
import Data.HashMap.Strict.NonEmpty qualified as NEHashMap
import Data.HashSet.InsOrd qualified as OSet
import Data.Int
import Data.Map.Strict as M
import Data.Scientific (Scientific)
import Data.Sequence.NonEmpty qualified as NESeq
import Data.Set (Set)
import Data.Text.NonEmpty
import Data.Time
import Data.URL.Template qualified as UT
import Data.Vector (Vector)
import Data.Word
import GHC.Generics
  ( Generic (..),
    K1 (..),
    M1 (..),
    U1 (..),
    V1,
    (:*:) (..),
    (:+:) (..),
  )
import Hasura.GraphQL.Parser qualified as P
import Hasura.Incremental.Select
import Hasura.Prelude
import Language.GraphQL.Draft.Syntax qualified as G
import Network.URI.Extended qualified as N
import Servant.Client (BaseUrl, Scheme)
import System.Cron.Types

-- | A 'Dependency' represents a value that a 'Rule' can /conditionally/ depend on. A 'Dependency'
-- is created using 'newDependency', and it can be “opened” again using 'dependOn'. What makes a
-- 'Dependency' useful is the way it cooperates with 'cache'---if a 'Dependency' is passed to a
-- cached rule, but that rule (or any of its sub-rules) never “opens” it using 'dependOn', then
-- subsequent executions of the rule will ignore the 'Dependency' when computing whether or not it
-- is necessary to re-execute the rule.
--
-- The above functionality is useful on its own to express conditional dependencies, but even more
-- useful is the ability to express /partial/ dependencies. For example, if a 'Dependency' contains
-- a 'HashMap', a rule can choose to only depend on the value associated with a particular key by
-- using 'selectKeyD' (or the more general 'selectD'). Only the parts that are actually used will be
-- counted when computing whether a rule needs to be re-executed.
data Dependency a = Dependency !(DependencyKey a) !a

instance (Eq a) => Eq (Dependency a) where
  Dependency DependencyKey a
_ a
a == :: Dependency a -> Dependency a -> Bool
== Dependency DependencyKey a
_ a
b = a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
b

-- | Applies a 'Selector' to select part of a 'Dependency'.
selectD :: (Select a) => Selector a b -> Dependency a -> Dependency b
selectD :: Selector a b -> Dependency a -> Dependency b
selectD Selector a b
k (Dependency DependencyKey a
dk a
a) = DependencyKey b -> b -> Dependency b
forall a. DependencyKey a -> a -> Dependency a
Dependency (Selector a b -> DependencyKey a -> DependencyKey b
forall a b.
Select a =>
Selector a b -> DependencyKey a -> DependencyKey b
DependencyChild Selector a b
k DependencyKey a
dk) (Selector a b -> a -> b
forall a b. Select a => Selector a b -> a -> b
select Selector a b
k a
a)

-- | Selects a single key from a dependency containing a map-like data structure.
selectKeyD :: (Select a, Selector a ~ ConstS k v) => k -> Dependency a -> Dependency v
selectKeyD :: k -> Dependency a -> Dependency v
selectKeyD = ConstS k v v -> Dependency a -> Dependency v
forall a b.
Select a =>
Selector a b -> Dependency a -> Dependency b
selectD (ConstS k v v -> Dependency a -> Dependency v)
-> (k -> ConstS k v v) -> k -> Dependency a -> Dependency v
forall b c a. (b -> c) -> (a -> b) -> a -> c
. k -> ConstS k v v
forall k a. k -> ConstS k a a
ConstS

-- | Tracks whether a 'Dependency' is a “root” dependency created by 'newDependency' or a “child”
-- dependency created from an existing dependency using 'selectD'.
data DependencyKey a where
  DependencyRoot :: !(UniqueS a) -> DependencyKey a
  DependencyChild :: (Select a) => !(Selector a b) -> !(DependencyKey a) -> DependencyKey b

instance GEq DependencyKey where
  DependencyRoot UniqueS a
a geq :: DependencyKey a -> DependencyKey b -> Maybe (a :~: b)
`geq` DependencyRoot UniqueS b
b
    | Just a :~: b
Refl <- UniqueS a
a UniqueS a -> UniqueS b -> Maybe (a :~: b)
forall k (f :: k -> *) (a :: k) (b :: k).
GEq f =>
f a -> f b -> Maybe (a :~: b)
`geq` UniqueS b
b =
      (a :~: a) -> Maybe (a :~: a)
forall a. a -> Maybe a
Just a :~: a
forall k (a :: k). a :~: a
Refl
  DependencyChild Selector a a
a1 DependencyKey a
a2 `geq` DependencyChild Selector a b
b1 DependencyKey a
b2
    | Just a :~: a
Refl <- DependencyKey a
a2 DependencyKey a -> DependencyKey a -> Maybe (a :~: a)
forall k (f :: k -> *) (a :: k) (b :: k).
GEq f =>
f a -> f b -> Maybe (a :~: b)
`geq` DependencyKey a
b2,
      Just a :~: b
Refl <- Selector a a
a1 Selector a a -> Selector a b -> Maybe (a :~: b)
forall k (f :: k -> *) (a :: k) (b :: k).
GEq f =>
f a -> f b -> Maybe (a :~: b)
`geq` Selector a b
Selector a b
b1 =
      (a :~: a) -> Maybe (a :~: a)
forall a. a -> Maybe a
Just a :~: a
forall k (a :: k). a :~: a
Refl
  DependencyKey a
_ `geq` DependencyKey b
_ = Maybe (a :~: b)
forall a. Maybe a
Nothing

instance GCompare DependencyKey where
  DependencyRoot UniqueS a
a gcompare :: DependencyKey a -> DependencyKey b -> GOrdering a b
`gcompare` DependencyRoot UniqueS b
b = case UniqueS a -> UniqueS b -> GOrdering a b
forall k (f :: k -> *) (a :: k) (b :: k).
GCompare f =>
f a -> f b -> GOrdering a b
gcompare UniqueS a
a UniqueS b
b of
    GOrdering a b
GLT -> GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GLT
    GOrdering a b
GEQ -> GOrdering a b
forall k (a :: k). GOrdering a a
GEQ
    GOrdering a b
GGT -> GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GGT
  DependencyChild Selector a a
a1 DependencyKey a
a2 `gcompare` DependencyChild Selector a b
b1 DependencyKey a
b2 = case DependencyKey a -> DependencyKey a -> GOrdering a a
forall k (f :: k -> *) (a :: k) (b :: k).
GCompare f =>
f a -> f b -> GOrdering a b
gcompare DependencyKey a
a2 DependencyKey a
b2 of
    GOrdering a a
GLT -> GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GLT
    GOrdering a a
GEQ -> case Selector a a -> Selector a b -> GOrdering a b
forall k (f :: k -> *) (a :: k) (b :: k).
GCompare f =>
f a -> f b -> GOrdering a b
gcompare Selector a a
a1 Selector a b
Selector a b
b1 of
      GOrdering a b
GLT -> GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GLT
      GOrdering a b
GEQ -> GOrdering a b
forall k (a :: k). GOrdering a a
GEQ
      GOrdering a b
GGT -> GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GGT
    GOrdering a a
GGT -> GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GGT
  DependencyRoot UniqueS a
_ `gcompare` DependencyChild Selector a b
_ DependencyKey a
_ = GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GLT
  DependencyChild Selector a a
_ DependencyKey a
_ `gcompare` DependencyRoot UniqueS b
_ = GOrdering a b
forall k (a :: k) (b :: k). GOrdering a b
GGT

-- | A typeclass that implements the dependency-checking machinery used by 'cache'. Morally, this
-- class is like 'Eq', but it only checks the parts of a 'Dependency' that were actually accessed on
-- the previous execution. It is highly unlikely you will need to implement any 'Cacheable'
-- instances yourself; the default implementation uses 'Generic' to derive an instance
-- automatically.
class (Eq a) => Cacheable a where
  unchanged :: Accesses -> a -> a -> Bool
  default unchanged :: (Generic a, GCacheable (Rep a)) => Accesses -> a -> a -> Bool
  unchanged Accesses
accesses a
a a
b = Rep a Any -> Rep a Any -> Accesses -> Bool
forall (f :: * -> *) p.
GCacheable f =>
f p -> f p -> Accesses -> Bool
gunchanged (a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
a) (a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
b) Accesses
accesses
  {-# INLINEABLE unchanged #-}

instance (Cacheable a) => Cacheable (NESeq a) where
  unchanged :: Accesses -> NESeq a -> NESeq a -> Bool
unchanged Accesses
access = Accesses -> Seq a -> Seq a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
access (Seq a -> Seq a -> Bool)
-> (NESeq a -> Seq a) -> NESeq a -> NESeq a -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` NESeq a -> Seq a
forall a. NESeq a -> Seq a
NESeq.toSeq

-- | A mapping from root 'Dependency' keys to the accesses made against those dependencies.
newtype Accesses = Accesses {Accesses -> DMap UniqueS Access
unAccesses :: DM.DMap UniqueS Access}

instance Semigroup Accesses where
  Accesses DMap UniqueS Access
a <> :: Accesses -> Accesses -> Accesses
<> Accesses DMap UniqueS Access
b = DMap UniqueS Access -> Accesses
Accesses (DMap UniqueS Access -> Accesses)
-> DMap UniqueS Access -> Accesses
forall a b. (a -> b) -> a -> b
$ (forall v. UniqueS v -> Access v -> Access v -> Access v)
-> DMap UniqueS Access
-> DMap UniqueS Access
-> DMap UniqueS Access
forall k1 (k2 :: k1 -> *) (f :: k1 -> *).
GCompare k2 =>
(forall (v :: k1). k2 v -> f v -> f v -> f v)
-> DMap k2 f -> DMap k2 f -> DMap k2 f
DM.unionWithKey ((Access v -> Access v -> Access v)
-> UniqueS v -> Access v -> Access v -> Access v
forall a b. a -> b -> a
const Access v -> Access v -> Access v
forall a. Semigroup a => a -> a -> a
(<>)) DMap UniqueS Access
a DMap UniqueS Access
b

instance Monoid Accesses where
  mempty :: Accesses
mempty = DMap UniqueS Access -> Accesses
Accesses DMap UniqueS Access
forall k1 (k2 :: k1 -> *) (f :: k1 -> *). DMap k2 f
DM.empty

recordAccess :: DependencyKey a -> Access a -> Accesses -> Accesses
recordAccess :: DependencyKey a -> Access a -> Accesses -> Accesses
recordAccess DependencyKey a
depKey !Access a
access (Accesses DMap UniqueS Access
accesses) = case DependencyKey a
depKey of
  DependencyRoot UniqueS a
rootKey -> DMap UniqueS Access -> Accesses
Accesses (DMap UniqueS Access -> Accesses)
-> DMap UniqueS Access -> Accesses
forall a b. (a -> b) -> a -> b
$ (Access a -> Access a -> Access a)
-> UniqueS a
-> Access a
-> DMap UniqueS Access
-> DMap UniqueS Access
forall k1 (k2 :: k1 -> *) (f :: k1 -> *) (v :: k1).
GCompare k2 =>
(f v -> f v -> f v) -> k2 v -> f v -> DMap k2 f -> DMap k2 f
DM.insertWith' Access a -> Access a -> Access a
forall a. Semigroup a => a -> a -> a
(<>) UniqueS a
rootKey Access a
access DMap UniqueS Access
accesses
  DependencyChild Selector a a
selector DependencyKey a
parentKey ->
    DependencyKey a -> Access a -> Accesses -> Accesses
forall a. DependencyKey a -> Access a -> Accesses -> Accesses
recordAccess DependencyKey a
parentKey (DMap (Selector a) Access -> Access a
forall a. Select a => DMap (Selector a) Access -> Access a
AccessedParts (DMap (Selector a) Access -> Access a)
-> DMap (Selector a) Access -> Access a
forall a b. (a -> b) -> a -> b
$ Selector a a -> Access a -> DMap (Selector a) Access
forall k1 (k2 :: k1 -> *) (v :: k1) (f :: k1 -> *).
k2 v -> f v -> DMap k2 f
DM.singleton Selector a a
selector Access a
access) (DMap UniqueS Access -> Accesses
Accesses DMap UniqueS Access
accesses)

-- | Records the accesses made within a single 'Dependency' and its children. The 'Semigroup'
-- instance for 'Access' computes a least upper bound:
--
--   * 'AccessedAll' serves as the top of the lattice and records the dependency’s entire value was
--     accessed.
--   * 'AccessedParts' records a set of accesses for individual parts of a dependency.
data Access a where
  AccessedAll :: (Cacheable a) => Access a
  AccessedParts :: (Select a) => !(DM.DMap (Selector a) Access) -> Access a

instance Semigroup (Access a) where
  Access a
AccessedAll <> :: Access a -> Access a -> Access a
<> Access a
_ = Access a
forall a. Cacheable a => Access a
AccessedAll
  Access a
_ <> Access a
AccessedAll = Access a
forall a. Cacheable a => Access a
AccessedAll
  AccessedParts DMap (Selector a) Access
a <> AccessedParts DMap (Selector a) Access
b = DMap (Selector a) Access -> Access a
forall a. Select a => DMap (Selector a) Access -> Access a
AccessedParts (DMap (Selector a) Access -> Access a)
-> DMap (Selector a) Access -> Access a
forall a b. (a -> b) -> a -> b
$ (forall v. Selector a v -> Access v -> Access v -> Access v)
-> DMap (Selector a) Access
-> DMap (Selector a) Access
-> DMap (Selector a) Access
forall k1 (k2 :: k1 -> *) (f :: k1 -> *).
GCompare k2 =>
(forall (v :: k1). k2 v -> f v -> f v -> f v)
-> DMap k2 f -> DMap k2 f -> DMap k2 f
DM.unionWithKey ((Access v -> Access v -> Access v)
-> Selector a v -> Access v -> Access v -> Access v
forall a b. a -> b -> a
const Access v -> Access v -> Access v
forall a. Semigroup a => a -> a -> a
(<>)) DMap (Selector a) Access
a DMap (Selector a) Access
b

instance (Cacheable a) => Cacheable (Dependency a) where
  unchanged :: Accesses -> Dependency a -> Dependency a -> Bool
unchanged Accesses
accesses (Dependency DependencyKey a
key1 a
v1) (Dependency DependencyKey a
_ a
v2) =
    -- look up which parts of this dependency were previously accessed
    case DependencyKey a -> Either Bool (Access a)
forall b. DependencyKey b -> Either Bool (Access b)
lookupAccess DependencyKey a
key1 of
      -- looking up the access was enough to determine the result
      Left Bool
result -> Bool
result
      -- otherwise, look through the accessed children
      Right Access a
access -> a -> a -> Access a -> Bool
forall b. b -> b -> Access b -> Bool
unchangedBy a
v1 a
v2 Access a
access
    where
      -- Looks up the Access associated with the given DependencyKey, if it exists.
      lookupAccess :: DependencyKey b -> Either Bool (Access b)
      lookupAccess :: DependencyKey b -> Either Bool (Access b)
lookupAccess = \case
        DependencyRoot UniqueS b
key -> Maybe (Access b) -> Either Bool (Access b)
forall b. Maybe b -> Either Bool b
handleNoAccess (Maybe (Access b) -> Either Bool (Access b))
-> Maybe (Access b) -> Either Bool (Access b)
forall a b. (a -> b) -> a -> b
$ UniqueS b -> DMap UniqueS Access -> Maybe (Access b)
forall k1 (k2 :: k1 -> *) (f :: k1 -> *) (v :: k1).
GCompare k2 =>
k2 v -> DMap k2 f -> Maybe (f v)
DM.lookup UniqueS b
key (Accesses -> DMap UniqueS Access
unAccesses Accesses
accesses)
        DependencyChild Selector a b
selector DependencyKey a
key ->
          DependencyKey a -> Either Bool (Access a)
forall b. DependencyKey b -> Either Bool (Access b)
lookupAccess DependencyKey a
key Either Bool (Access a)
-> (Access a -> Either Bool (Access b)) -> Either Bool (Access b)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
            Access a
AccessedAll -> Bool -> Either Bool (Access b)
forall a b. a -> Either a b
Left (Accesses -> a -> a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses a
v1 a
v2)
            AccessedParts DMap (Selector a) Access
parts -> Maybe (Access b) -> Either Bool (Access b)
forall b. Maybe b -> Either Bool b
handleNoAccess (Maybe (Access b) -> Either Bool (Access b))
-> Maybe (Access b) -> Either Bool (Access b)
forall a b. (a -> b) -> a -> b
$ Selector a b -> DMap (Selector a) Access -> Maybe (Access b)
forall k1 (k2 :: k1 -> *) (f :: k1 -> *) (v :: k1).
GCompare k2 =>
k2 v -> DMap k2 f -> Maybe (f v)
DM.lookup Selector a b
selector DMap (Selector a) Access
parts
        where
          -- if this dependency was never accessed, then it’s certainly unchanged
          handleNoAccess :: Maybe b -> Either Bool b
handleNoAccess = Either Bool b -> (b -> Either Bool b) -> Maybe b -> Either Bool b
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
True) b -> Either Bool b
forall a b. b -> Either a b
Right

      -- Walks the given values guided by the given Access, checking that all the subparts
      -- identified by the AccessedAll leaves are unchanged.
      unchangedBy :: forall b. b -> b -> Access b -> Bool
      unchangedBy :: b -> b -> Access b -> Bool
unchangedBy b
a b
b = \case
        Access b
AccessedAll -> Accesses -> b -> b -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses b
a b
b
        AccessedParts DMap (Selector b) Access
parts -> (forall v. Selector b v -> Access v -> Bool -> Bool)
-> Bool -> DMap (Selector b) Access -> Bool
forall k1 (k2 :: k1 -> *) (f :: k1 -> *) b.
(forall (v :: k1). k2 v -> f v -> b -> b) -> b -> DMap k2 f -> b
DM.foldrWithKey forall c. Select b => Selector b c -> Access c -> Bool -> Bool
forall v. Selector b v -> Access v -> Bool -> Bool
reduce Bool
True DMap (Selector b) Access
parts
        where
          reduce :: (Select b) => Selector b c -> Access c -> Bool -> Bool
          reduce :: Selector b c -> Access c -> Bool -> Bool
reduce Selector b c
selector = Bool -> Bool -> Bool
(&&) (Bool -> Bool -> Bool)
-> (Access c -> Bool) -> Access c -> Bool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. c -> c -> Access c -> Bool
forall b. b -> b -> Access b -> Bool
unchangedBy (Selector b c -> b -> c
forall a b. Select a => Selector a b -> a -> b
select Selector b c
selector b
a) (Selector b c -> b -> c
forall a b. Select a => Selector a b -> a -> b
select Selector b c
selector b
b)

-- -------------------------------------------------------------------------------------------------
-- boilerplate Cacheable instances

instance Cacheable Char where unchanged :: Accesses -> Char -> Char -> Bool
unchanged Accesses
_ = Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Double where unchanged :: Accesses -> Double -> Double -> Bool
unchanged Accesses
_ = Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Int where unchanged :: Accesses -> Int -> Int -> Bool
unchanged Accesses
_ = Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Int32 where unchanged :: Accesses -> Int32 -> Int32 -> Bool
unchanged Accesses
_ = Int32 -> Int32 -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Int64 where unchanged :: Accesses -> Int64 -> Int64 -> Bool
unchanged Accesses
_ = Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Integer where unchanged :: Accesses -> Integer -> Integer -> Bool
unchanged Accesses
_ = Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Scientific where unchanged :: Accesses -> Scientific -> Scientific -> Bool
unchanged Accesses
_ = Scientific -> Scientific -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Text where unchanged :: Accesses -> Text -> Text -> Bool
unchanged Accesses
_ = Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable NonEmptyText where unchanged :: Accesses -> NonEmptyText -> NonEmptyText -> Bool
unchanged Accesses
_ = NonEmptyText -> NonEmptyText -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable N.URIAuth where unchanged :: Accesses -> URIAuth -> URIAuth -> Bool
unchanged Accesses
_ = URIAuth -> URIAuth -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable G.Name where unchanged :: Accesses -> Name -> Name -> Bool
unchanged Accesses
_ = Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable DiffTime where unchanged :: Accesses -> DiffTime -> DiffTime -> Bool
unchanged Accesses
_ = DiffTime -> DiffTime -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable NominalDiffTime where unchanged :: Accesses -> NominalDiffTime -> NominalDiffTime -> Bool
unchanged Accesses
_ = NominalDiffTime -> NominalDiffTime -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable UTCTime where unchanged :: Accesses -> UTCTime -> UTCTime -> Bool
unchanged Accesses
_ = UTCTime -> UTCTime -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Day where unchanged :: Accesses -> Day -> Day -> Bool
unchanged Accesses
_ = Day -> Day -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable TimeOfDay where unchanged :: Accesses -> TimeOfDay -> TimeOfDay -> Bool
unchanged Accesses
_ = TimeOfDay -> TimeOfDay -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable LocalTime where unchanged :: Accesses -> LocalTime -> LocalTime -> Bool
unchanged Accesses
_ = LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable ByteString where unchanged :: Accesses -> ByteString -> ByteString -> Bool
unchanged Accesses
_ = ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Float where unchanged :: Accesses -> Float -> Float -> Bool
unchanged Accesses
_ = Float -> Float -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Word where unchanged :: Accesses -> Word -> Word -> Bool
unchanged Accesses
_ = Word -> Word -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Word8 where unchanged :: Accesses -> Word8 -> Word8 -> Bool
unchanged Accesses
_ = Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Word16 where unchanged :: Accesses -> Word16 -> Word16 -> Bool
unchanged Accesses
_ = Word16 -> Word16 -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance Cacheable Key where unchanged :: Accesses -> Key -> Key -> Bool
unchanged Accesses
_ = Key -> Key -> Bool
forall a. Eq a => a -> a -> Bool
(==)

-- instances for CronSchedule from package `cron`
instance Cacheable StepField

instance Cacheable RangeField

instance Cacheable SpecificField

instance Cacheable BaseField

instance Cacheable CronField

instance Cacheable MonthSpec

instance Cacheable DayOfMonthSpec

instance Cacheable DayOfWeekSpec

instance Cacheable HourSpec

instance Cacheable MinuteSpec

instance Cacheable CronSchedule

instance (Cacheable a) => Cacheable (Seq a) where
  unchanged :: Accesses -> Seq a -> Seq a -> Bool
unchanged = (a -> a -> Bool) -> Seq a -> Seq a -> Bool
forall (f :: * -> *) a b.
Eq1 f =>
(a -> b -> Bool) -> f a -> f b -> Bool
liftEq ((a -> a -> Bool) -> Seq a -> Seq a -> Bool)
-> (Accesses -> a -> a -> Bool)
-> Accesses
-> Seq a
-> Seq a
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Accesses -> a -> a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged

instance (Cacheable a) => Cacheable (Vector a) where
  unchanged :: Accesses -> Vector a -> Vector a -> Bool
unchanged = (a -> a -> Bool) -> Vector a -> Vector a -> Bool
forall (f :: * -> *) a b.
Eq1 f =>
(a -> b -> Bool) -> f a -> f b -> Bool
liftEq ((a -> a -> Bool) -> Vector a -> Vector a -> Bool)
-> (Accesses -> a -> a -> Bool)
-> Accesses
-> Vector a
-> Vector a
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Accesses -> a -> a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged

instance (Cacheable k, Cacheable v) => Cacheable (HashMap k v) where
  unchanged :: Accesses -> HashMap k v -> HashMap k v -> Bool
unchanged Accesses
accesses = (k -> k -> Bool)
-> (v -> v -> Bool) -> HashMap k v -> HashMap k v -> Bool
forall (f :: * -> * -> *) a b c d.
Eq2 f =>
(a -> b -> Bool) -> (c -> d -> Bool) -> f a c -> f b d -> Bool
liftEq2 (Accesses -> k -> k -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses) (Accesses -> v -> v -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses)

instance (Cacheable k, Cacheable v) => Cacheable (NEHashMap k v) where
  unchanged :: Accesses -> NEHashMap k v -> NEHashMap k v -> Bool
unchanged Accesses
accesses = Accesses -> HashMap k v -> HashMap k v -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses (HashMap k v -> HashMap k v -> Bool)
-> (NEHashMap k v -> HashMap k v)
-> NEHashMap k v
-> NEHashMap k v
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` NEHashMap k v -> HashMap k v
forall k v. NEHashMap k v -> HashMap k v
NEHashMap.toHashMap

instance (Cacheable a) => Cacheable (HashSet a) where
  unchanged :: Accesses -> HashSet a -> HashSet a -> Bool
unchanged = (a -> a -> Bool) -> HashSet a -> HashSet a -> Bool
forall (f :: * -> *) a b.
Eq1 f =>
(a -> b -> Bool) -> f a -> f b -> Bool
liftEq ((a -> a -> Bool) -> HashSet a -> HashSet a -> Bool)
-> (Accesses -> a -> a -> Bool)
-> Accesses
-> HashSet a
-> HashSet a
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Accesses -> a -> a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged

instance (Cacheable a) => Cacheable (OSet.InsOrdHashSet a) where
  unchanged :: Accesses -> InsOrdHashSet a -> InsOrdHashSet a -> Bool
unchanged Accesses
accesses InsOrdHashSet a
l InsOrdHashSet a
r = Accesses -> HashSet a -> HashSet a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses (InsOrdHashSet a -> HashSet a
forall k. InsOrdHashSet k -> HashSet k
OSet.toHashSet InsOrdHashSet a
l) (InsOrdHashSet a -> HashSet a
forall k. InsOrdHashSet k -> HashSet k
OSet.toHashSet InsOrdHashSet a
r)

instance (Cacheable a) => Cacheable (CI a) where
  unchanged :: Accesses -> CI a -> CI a -> Bool
unchanged Accesses
_ = CI a -> CI a -> Bool
forall a. Eq a => a -> a -> Bool
(==)

instance (Cacheable a) => Cacheable (Set a) where
  unchanged :: Accesses -> Set a -> Set a -> Bool
unchanged = (a -> a -> Bool) -> Set a -> Set a -> Bool
forall (f :: * -> *) a b.
Eq1 f =>
(a -> b -> Bool) -> f a -> f b -> Bool
liftEq ((a -> a -> Bool) -> Set a -> Set a -> Bool)
-> (Accesses -> a -> a -> Bool)
-> Accesses
-> Set a
-> Set a
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Accesses -> a -> a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged

instance (Hashable k, Cacheable k, Cacheable v) => Cacheable (InsOrdHashMap k v) where
  unchanged :: Accesses -> InsOrdHashMap k v -> InsOrdHashMap k v -> Bool
unchanged Accesses
accesses InsOrdHashMap k v
l InsOrdHashMap k v
r = Accesses -> HashMap k v -> HashMap k v -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses (InsOrdHashMap k v -> HashMap k v
forall v. InsOrdHashMap k v -> HashMap k v
toHashMap InsOrdHashMap k v
l) (InsOrdHashMap k v -> HashMap k v
forall v. InsOrdHashMap k v -> HashMap k v
toHashMap InsOrdHashMap k v
r)
    where
      toHashMap :: InsOrdHashMap k v -> HashMap k v
toHashMap = [(k, v)] -> HashMap k v
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HM.fromList ([(k, v)] -> HashMap k v)
-> (InsOrdHashMap k v -> [(k, v)])
-> InsOrdHashMap k v
-> HashMap k v
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InsOrdHashMap k v -> [(k, v)]
forall k v. InsOrdHashMap k v -> [(k, v)]
OHM.toList

instance (Cacheable k, Cacheable v) => Cacheable (M.Map k v) where
  unchanged :: Accesses -> Map k v -> Map k v -> Bool
unchanged Accesses
accesses = (k -> k -> Bool) -> (v -> v -> Bool) -> Map k v -> Map k v -> Bool
forall (f :: * -> * -> *) a b c d.
Eq2 f =>
(a -> b -> Bool) -> (c -> d -> Bool) -> f a c -> f b d -> Bool
liftEq2 (Accesses -> k -> k -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses) (Accesses -> v -> v -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses)

instance (Cacheable v) => Cacheable (KM.KeyMap v) where
  -- This instance takes advantage of the fact that the (default) internal
  -- representation of `Data.Aeson.KeyMap` is `Data.Strict.Map Data.Aeson.Key`
  -- from aeson-2.0.1.0 and onwards.
  unchanged :: Accesses -> KeyMap v -> KeyMap v -> Bool
unchanged Accesses
accesses KeyMap v
l KeyMap v
r = Accesses -> Map Key v -> Map Key v -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses (KeyMap v -> Map Key v
forall v. KeyMap v -> Map Key v
toMap KeyMap v
l) (KeyMap v -> Map Key v
forall v. KeyMap v -> Map Key v
toMap KeyMap v
r)
    where
      toMap :: KeyMap v -> Map Key v
toMap = KeyMap v -> Map Key v
forall v. KeyMap v -> Map Key v
KM.toMap

instance Cacheable ()

instance (Cacheable a, Cacheable b) => Cacheable (a, b)

instance (Cacheable a, Cacheable b, Cacheable c) => Cacheable (a, b, c)

instance (Cacheable a, Cacheable b, Cacheable c, Cacheable d) => Cacheable (a, b, c, d)

instance (Cacheable a, Cacheable b, Cacheable c, Cacheable d, Cacheable e) => Cacheable (a, b, c, d, e)

instance (Cacheable a, Cacheable b, Cacheable c, Cacheable d, Cacheable e, Cacheable f) => Cacheable (a, b, c, d, e, f)

instance (Cacheable a, Cacheable b, Cacheable c, Cacheable d, Cacheable e, Cacheable f, Cacheable g) => Cacheable (a, b, c, d, e, f, g)

instance Cacheable Bool

instance Cacheable Void

instance Cacheable Value

instance Cacheable G.FragmentDefinition

instance Cacheable G.GType

instance Cacheable G.Nullability

instance Cacheable G.OperationType

instance Cacheable G.VariableDefinition

instance Cacheable G.InputValueDefinition

instance Cacheable G.EnumValueDefinition

instance (Cacheable a) => Cacheable (G.FieldDefinition a)

instance Cacheable G.ScalarTypeDefinition

instance Cacheable G.UnionTypeDefinition

instance (Cacheable possibleTypes, Cacheable a) => Cacheable (G.InterfaceTypeDefinition a possibleTypes)

instance Cacheable G.EnumTypeDefinition

instance (Cacheable a) => Cacheable (G.InputObjectTypeDefinition a)

instance (Cacheable a) => Cacheable (G.ObjectTypeDefinition a)

instance (Cacheable a, Cacheable possibleTypes) => Cacheable (G.TypeDefinition a possibleTypes)

instance Cacheable a => Cacheable (Identity a)

instance Cacheable N.URI

instance Cacheable UT.Variable

instance Cacheable UT.TemplateItem

instance Cacheable UT.URLTemplate

instance (Cacheable a) => Cacheable (Maybe a)

instance (Cacheable a, Cacheable b) => Cacheable (Either a b)

instance Cacheable a => Cacheable [a]

instance Cacheable a => Cacheable (NonEmpty a)

instance Cacheable a => Cacheable (G.Directive a)

instance Cacheable a => Cacheable (G.ExecutableDefinition a)

instance (Cacheable (a b), Cacheable b) => Cacheable (G.Field a b)

instance Cacheable a => Cacheable (G.FragmentSpread a)

instance (Cacheable (a b), Cacheable b) => Cacheable (G.InlineFragment a b)

instance (Cacheable (a b), Cacheable b) => Cacheable (G.OperationDefinition a b)

instance (Cacheable (a b), Cacheable b) => Cacheable (G.Selection a b)

instance (Cacheable (a b), Cacheable b) => Cacheable (G.TypedOperationDefinition a b)

instance Cacheable a => Cacheable (G.Value a)

instance Cacheable a => Cacheable (Const a b)

deriving instance Cacheable G.Description

deriving instance Cacheable G.EnumValue

deriving instance Cacheable a => Cacheable (G.ExecutableDocument a)

instance Cacheable G.RootOperationTypeDefinition

instance Cacheable G.SchemaDefinition

instance Cacheable G.TypeSystemDefinition

instance Cacheable G.SchemaDocument

instance Cacheable G.SchemaIntrospection

instance Cacheable Scheme

instance Cacheable BaseUrl

instance (Cacheable v) => Cacheable (P.InputValue v)

instance Cacheable P.Variable

instance Cacheable P.VariableInfo

class GCacheable f where
  gunchanged :: f p -> f p -> Accesses -> Bool

instance GCacheable V1 where
  gunchanged :: V1 p -> V1 p -> Accesses -> Bool
gunchanged V1 p
a = case V1 p
a of {}
  {-# INLINE gunchanged #-}

instance GCacheable U1 where
  gunchanged :: U1 p -> U1 p -> Accesses -> Bool
gunchanged U1 p
U1 U1 p
U1 Accesses
_ = Bool
True
  {-# INLINE gunchanged #-}

instance (Cacheable a) => GCacheable (K1 t a) where
  gunchanged :: K1 t a p -> K1 t a p -> Accesses -> Bool
gunchanged (K1 a
a) (K1 a
b) Accesses
accesses = Accesses -> a -> a -> Bool
forall a. Cacheable a => Accesses -> a -> a -> Bool
unchanged Accesses
accesses a
a a
b
  {-# INLINE gunchanged #-}

instance (GCacheable f) => GCacheable (M1 t m f) where
  gunchanged :: M1 t m f p -> M1 t m f p -> Accesses -> Bool
gunchanged (M1 f p
a) (M1 f p
b) = f p -> f p -> Accesses -> Bool
forall (f :: * -> *) p.
GCacheable f =>
f p -> f p -> Accesses -> Bool
gunchanged f p
a f p
b
  {-# INLINE gunchanged #-}

instance (GCacheable f, GCacheable g) => GCacheable (f :*: g) where
  gunchanged :: (:*:) f g p -> (:*:) f g p -> Accesses -> Bool
gunchanged (f p
a1 :*: g p
a2) (f p
b1 :*: g p
b2) = (Bool -> Bool -> Bool)
-> (Accesses -> Bool) -> (Accesses -> Bool) -> Accesses -> Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(&&) (f p -> f p -> Accesses -> Bool
forall (f :: * -> *) p.
GCacheable f =>
f p -> f p -> Accesses -> Bool
gunchanged f p
a1 f p
b1) (g p -> g p -> Accesses -> Bool
forall (f :: * -> *) p.
GCacheable f =>
f p -> f p -> Accesses -> Bool
gunchanged g p
a2 g p
b2)
  {-# INLINE gunchanged #-}

instance (GCacheable f, GCacheable g) => GCacheable (f :+: g) where
  gunchanged :: (:+:) f g p -> (:+:) f g p -> Accesses -> Bool
gunchanged (L1 f p
a) (L1 f p
b) = f p -> f p -> Accesses -> Bool
forall (f :: * -> *) p.
GCacheable f =>
f p -> f p -> Accesses -> Bool
gunchanged f p
a f p
b
  gunchanged (R1 g p
a) (R1 g p
b) = g p -> g p -> Accesses -> Bool
forall (f :: * -> *) p.
GCacheable f =>
f p -> f p -> Accesses -> Bool
gunchanged g p
a g p
b
  gunchanged (:+:) f g p
_ (:+:) f g p
_ = Bool -> Accesses -> Bool
forall a b. a -> b -> a
const Bool
False
  {-# INLINE gunchanged #-}