2019-11-18 21:45:54 +03:00
|
|
|
|
{-# LANGUAGE Arrows #-}
|
|
|
|
|
|
|
|
|
|
module Hasura.IncrementalSpec (spec) where
|
|
|
|
|
|
2021-09-24 01:56:37 +03:00
|
|
|
|
import Control.Arrow.Extended
|
|
|
|
|
import Control.Monad.Unique
|
|
|
|
|
import Data.HashMap.Strict qualified as M
|
|
|
|
|
import Data.HashSet qualified as S
|
|
|
|
|
import Hasura.Incremental qualified as Inc
|
|
|
|
|
import Hasura.Prelude
|
|
|
|
|
import Test.Hspec
|
2019-11-18 21:45:54 +03:00
|
|
|
|
|
|
|
|
|
spec :: Spec
|
|
|
|
|
spec = do
|
|
|
|
|
describe "cache" $ do
|
|
|
|
|
it "skips re-running rules if the input didn’t change" $ do
|
2019-12-15 16:28:23 +03:00
|
|
|
|
let add1 :: (MonadState Integer m) => m ()
|
2021-09-24 01:56:37 +03:00
|
|
|
|
add1 = modify' (+ 1)
|
2019-11-18 21:45:54 +03:00
|
|
|
|
|
|
|
|
|
rule = proc (a, b) -> do
|
2019-11-27 01:49:42 +03:00
|
|
|
|
Inc.cache $ arrM (\_ -> add1) -< a
|
|
|
|
|
Inc.cache $ arrM (\_ -> add1 *> add1) -< b
|
2019-11-18 21:45:54 +03:00
|
|
|
|
|
2019-12-15 16:28:23 +03:00
|
|
|
|
(result1, state1) <- runStateT (Inc.build rule (False, False)) 0
|
2019-11-18 21:45:54 +03:00
|
|
|
|
state1 `shouldBe` 3
|
2019-12-15 16:28:23 +03:00
|
|
|
|
(result2, state2) <- runStateT (Inc.rebuild result1 (True, False)) 0
|
2019-11-18 21:45:54 +03:00
|
|
|
|
state2 `shouldBe` 1
|
2019-12-15 16:28:23 +03:00
|
|
|
|
(_, state3) <- runStateT (Inc.rebuild result2 (True, True)) 0
|
2019-11-18 21:45:54 +03:00
|
|
|
|
state3 `shouldBe` 2
|
|
|
|
|
|
2020-10-27 22:52:19 +03:00
|
|
|
|
it "tracks dependencies within nested uses of cache across multiple executions" do
|
2021-09-24 01:56:37 +03:00
|
|
|
|
let rule ::
|
|
|
|
|
(MonadWriter String m, MonadUnique m) =>
|
|
|
|
|
Inc.Rule m (Inc.InvalidationKey, Inc.InvalidationKey) ()
|
2020-10-27 22:52:19 +03:00
|
|
|
|
rule = proc (key1, key2) -> do
|
|
|
|
|
dep1 <- Inc.newDependency -< key2
|
2021-09-24 01:56:37 +03:00
|
|
|
|
(key1, dep1)
|
|
|
|
|
>-
|
|
|
|
|
Inc.cache
|
|
|
|
|
( proc (_, dep2) ->
|
|
|
|
|
dep2
|
|
|
|
|
>-
|
|
|
|
|
Inc.cache
|
|
|
|
|
( proc dep3 -> do
|
|
|
|
|
Inc.dependOn -< dep3
|
|
|
|
|
arrM tell -< "executed"
|
|
|
|
|
)
|
|
|
|
|
)
|
2020-10-27 22:52:19 +03:00
|
|
|
|
returnA -< ()
|
|
|
|
|
|
|
|
|
|
let key1 = Inc.initialInvalidationKey
|
|
|
|
|
key2 = Inc.invalidate key1
|
|
|
|
|
|
|
|
|
|
(result1, log1) <- runWriterT $ Inc.build rule (key1, key1)
|
|
|
|
|
log1 `shouldBe` "executed"
|
|
|
|
|
|
|
|
|
|
(result2, log2) <- runWriterT $ Inc.rebuild result1 (key2, key1)
|
|
|
|
|
log2 `shouldBe` ""
|
|
|
|
|
|
|
|
|
|
(_, log3) <- runWriterT $ Inc.rebuild result2 (key2, key2)
|
|
|
|
|
log3 `shouldBe` "executed"
|
|
|
|
|
|
2019-11-18 21:45:54 +03:00
|
|
|
|
describe "keyed" $ do
|
|
|
|
|
it "preserves incrementalization when entries don’t change" $ do
|
2021-09-24 01:56:37 +03:00
|
|
|
|
let rule ::
|
|
|
|
|
(MonadWriter (S.HashSet (String, Integer)) m, MonadUnique m) =>
|
|
|
|
|
Inc.Rule m (M.HashMap String Integer) (M.HashMap String Integer)
|
2019-11-27 01:49:42 +03:00
|
|
|
|
rule = proc m ->
|
2021-09-24 01:56:37 +03:00
|
|
|
|
(|
|
|
|
|
|
Inc.keyed
|
|
|
|
|
( \k v -> do
|
|
|
|
|
Inc.cache $ arrM (tell . S.singleton) -< (k, v)
|
|
|
|
|
returnA -< v * 2
|
|
|
|
|
)
|
2019-11-27 01:49:42 +03:00
|
|
|
|
|) m
|
2019-11-18 21:45:54 +03:00
|
|
|
|
|
2019-12-15 16:28:23 +03:00
|
|
|
|
(result1, log1) <- runWriterT . Inc.build rule $ M.fromList [("a", 1), ("b", 2)]
|
2019-11-18 21:45:54 +03:00
|
|
|
|
Inc.result result1 `shouldBe` M.fromList [("a", 2), ("b", 4)]
|
|
|
|
|
log1 `shouldBe` S.fromList [("a", 1), ("b", 2)]
|
2019-12-15 16:28:23 +03:00
|
|
|
|
(result2, log2) <- runWriterT . Inc.rebuild result1 $ M.fromList [("a", 1), ("b", 3), ("c", 4)]
|
2019-11-18 21:45:54 +03:00
|
|
|
|
Inc.result result2 `shouldBe` M.fromList [("a", 2), ("b", 6), ("c", 8)]
|
|
|
|
|
log2 `shouldBe` S.fromList [("b", 3), ("c", 4)]
|