Skip to content

Commit 56d59b3

Browse files
Ensure dataloader is called only once
1 parent 74bc9c4 commit 56d59b3

File tree

5 files changed

+28
-24
lines changed

5 files changed

+28
-24
lines changed

lib/graphql/fragment_cache/fragment.rb

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ def read_multi(fragments)
1616
return fragments.map { |f| [f, f.read] }.to_h
1717
end
1818

19-
fragments_to_cache_keys = fragments
20-
.map { |f| [f, f.cache_key] }.to_h
19+
fragments_to_cache_keys = fragments.map { |f| [f, f.cache_key] }.to_h
2120

2221
# Filter out all the cache_keys for fragments with renew_cache: true in their context
23-
cache_keys = fragments_to_cache_keys
24-
.reject { |k, _v| k.context[:renew_cache] == true }.values
22+
cache_keys = fragments_to_cache_keys.reject { |k, _v| k.context[:renew_cache] == true }.values
2523

2624
# If there are cache_keys look up values with read_multi otherwise return an empty hash
2725
cache_keys_to_values = if cache_keys.empty?
@@ -46,8 +44,7 @@ def read_multi(fragments)
4644
end
4745

4846
# Fragmenst without values or with renew_cache: true in their context will have nil values like the read method
49-
fragments_to_cache_keys
50-
.map { |fragment, cache_key| [fragment, cache_keys_to_values[cache_key]] }.to_h
47+
fragments_to_cache_keys.map { |fragment, cache_key| [fragment, cache_keys_to_values[cache_key]] }.to_h
5148
end
5249
end
5350

lib/graphql/fragment_cache/object_helpers.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ def cache_fragment(object_to_cache = NO_OBJECT, **options, &block)
4848

4949
fragment = Fragment.new(context_to_use, **options)
5050

51-
if options.delete(:dataloader)
52-
# the following line will block the current fiber until Dataloader is resolved, and we will
53-
# use the resolved value as the `object_to_cache`
54-
object_to_cache = block.call
55-
block = nil
56-
end
57-
5851
GraphQL::FragmentCache::Schema::LazyCacheResolver.new(fragment, context_to_use, object_to_cache, &block)
5952
end
6053
end

lib/graphql/fragment_cache/schema/lazy_cache_resolver.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ def initialize(fragment, query_ctx, object_to_cache, &block)
1616
@block = block
1717

1818
@lazy_state[:pending_fragments] << @fragment
19+
20+
ensure_dataloader_resulution! if @fragment.options[:dataloader]
1921
end
2022

2123
def resolve
@@ -35,6 +37,15 @@ def resolve
3537
@query_ctx.fragments << @fragment
3638
end
3739
end
40+
41+
private
42+
43+
def ensure_dataloader_resulution!
44+
return if FragmentCache.cache_store.exist?(@fragment.cache_key)
45+
46+
@object_to_cache = @block.call
47+
@block = nil
48+
end
3849
end
3950
end
4051
end

spec/graphql/fragment_cache/object_helpers_spec.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,12 +804,13 @@ def post(id:, expires_in: nil)
804804
let!(:post1) { Post.create(id: 1, title: "object test 1", author: user1) }
805805
let!(:post2) { Post.create(id: 2, title: "object test 2", author: user2) }
806806

807+
let(:memory_store) { GraphQL::FragmentCache::MemoryStore.new }
808+
807809
before do
808810
allow(User).to receive(:find_by_post_ids).and_call_original
809811

810812
# warmup cache
811813
execute_query
812-
expect(User).to have_received(:find_by_post_ids).with([post1.id, post2.id])
813814

814815
# make objects dirty
815816
user1.name = "User #1 new"
@@ -827,6 +828,8 @@ def post(id:, expires_in: nil)
827828
"dataloaderCachedAuthor" => {"name" => "User #2"}
828829
}
829830
])
831+
832+
expect(User).to have_received(:find_by_post_ids).with([post1.id, post2.id]).once
830833
end
831834
end
832835

spec/graphql/fragment_cache/schema/lazy_cache_resolver_spec.rb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,27 @@
66
describe "#initialize" do
77
context "lazy cache resolver state management" do
88
let(:state_key) { :lazy_cache_resolver_statez }
9+
let(:gql_context) { instance_double "Context" }
10+
let(:fragment) { GraphQL::FragmentCache::Fragment.new(gql_context) }
11+
12+
before do
13+
allow(gql_context).to receive(:namespace).and_return({})
14+
end
915

1016
it "adds lazy state property to the query context" do
1117
context = {}
1218

1319
expect(context).not_to have_key(state_key)
1420

15-
GraphQL::FragmentCache::Schema::LazyCacheResolver.new(nil, context, {})
21+
GraphQL::FragmentCache::Schema::LazyCacheResolver.new(fragment, context, {})
1622

1723
expect(context).to have_key(state_key)
1824
end
1925

2026
it "has :pending_fragments Set in state" do
2127
context = {}
2228

23-
GraphQL::FragmentCache::Schema::LazyCacheResolver.new({}, context, {})
29+
GraphQL::FragmentCache::Schema::LazyCacheResolver.new(fragment, context, {})
2430

2531
expect(context[state_key]).to have_key(:pending_fragments)
2632
expect(context[state_key][:pending_fragments]).to be_instance_of(Set)
@@ -29,7 +35,7 @@
2935
it "has :resolved_fragments Hash in state" do
3036
context = {}
3137

32-
GraphQL::FragmentCache::Schema::LazyCacheResolver.new({}, context, {})
38+
GraphQL::FragmentCache::Schema::LazyCacheResolver.new(fragment, context, {})
3339

3440
expect(context[state_key]).to have_key(:resolved_fragments)
3541
expect(context[state_key][:resolved_fragments]).to be_instance_of(Hash)
@@ -39,7 +45,7 @@
3945
context = {}
4046
fragments = []
4147

42-
3.times { fragments.push(Object.new) }
48+
3.times { fragments.push(GraphQL::FragmentCache::Fragment.new(gql_context)) }
4349

4450
fragments.each do |f|
4551
GraphQL::FragmentCache::Schema::LazyCacheResolver.new(f, context, {})
@@ -51,10 +57,4 @@
5157
end
5258
end
5359
end
54-
55-
it "has :resolve method" do
56-
lazy_cache_resolver = GraphQL::FragmentCache::Schema::LazyCacheResolver.new({}, {}, {})
57-
58-
expect(lazy_cache_resolver).to respond_to(:resolve)
59-
end
6060
end

0 commit comments

Comments
 (0)