From 247381335ebb6453f1e2c6af4aff1c2d7df06ff8 Mon Sep 17 00:00:00 2001 From: Adam Renberg Tamm Date: Thu, 22 Feb 2024 14:24:26 +0100 Subject: [PATCH] Priming the cache --- README.md | 16 ++++++++++++++++ lib/graphql/batch/loader.rb | 4 ++++ test/loader_test.rb | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/README.md b/README.md index 6d65f75..15e8d26 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,22 @@ def product(id:) end ``` +### Priming the Cache + +You can prime the loader cache with a specific value, which can be useful in certain situations. + +```ruby +def liked_products + liked_products = Product.where(liked: true).load + liked_products.each do |product| + RecordLoader.for(Product).prime(product.id, product) + end +end +``` + +Priming will add key/value to the loader cache only if it didn't exist before. + + ## Unit Testing Your loaders can be tested outside of a GraphQL query by doing the diff --git a/lib/graphql/batch/loader.rb b/lib/graphql/batch/loader.rb index fca03ec..378a982 100644 --- a/lib/graphql/batch/loader.rb +++ b/lib/graphql/batch/loader.rb @@ -62,6 +62,10 @@ def load_many(keys) ::Promise.all(keys.map { |key| load(key) }) end + def prime(key, value) + cache[cache_key(key)] ||= ::Promise.resolve(value).tap { |p| p.source = self } + end + def resolve #:nodoc: return if resolved? load_keys = queue diff --git a/test/loader_test.rb b/test/loader_test.rb index 44d36e8..e3304ee 100644 --- a/test/loader_test.rb +++ b/test/loader_test.rb @@ -215,4 +215,40 @@ def test_loader_with_failing_perform promise = ExplodingLoader.load([1]).then(nil, ->(err) { error_message = err.message } ).sync assert_equal 'perform failed', error_message end + + def test_prime + loader = EchoLoader.for + loader.prime(:a, :prepared_value) + + assert_equal :prepared_value, loader.load(:a).sync + assert_equal [:prepared_value, :b, :c], loader.load_many([:a, :b, :c]).sync + end + + def test_will_not_call_perform_if_fully_primed + loader = ExplodingLoader.for + loader.prime(:a, 1) + loader.prime(:b, 2) + + assert_equal [1, 2], loader.load_many([:a, :b]).sync + end + + def test_priming_a_key_already_in_queue_does_nothing + loader = EchoLoader.for + + promise = loader.load(:a) + + loader.prime(:a, :not_a) + + assert_equal :a, promise.sync + end + + def test_prime_will_not_replace_already_cached_value + loader = EchoLoader.for + + assert_equal :a, loader.load(:a).sync + + loader.prime(:a, :not_a) + + assert_equal :a, loader.load(:a).sync + end end