Skip to content

Commit 24f797a

Browse files
authored
Merge pull request #4903 from rmosolgo/better-mutation-cache-clearing
Mutation: clear dataloader cache right before resolving
2 parents b0738a0 + f40af0d commit 24f797a

File tree

3 files changed

+88
-5
lines changed

3 files changed

+88
-5
lines changed

lib/graphql/schema/mutation.rb

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ class Mutation < GraphQL::Schema::Resolver
6262
extend GraphQL::Schema::Member::HasFields
6363
extend GraphQL::Schema::Resolver::HasPayloadType
6464

65+
# @api private
66+
def call_resolve(_args_hash)
67+
# Clear any cached values from `loads` or authorization:
68+
dataloader.clear_cache
69+
super
70+
end
71+
6572
class << self
6673
def visible?(context)
6774
true

lib/graphql/schema/resolver.rb

+10-5
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,7 @@ def resolve_with_support(**args)
103103
end
104104
elsif authorized_val
105105
# Finally, all the hooks have passed, so resolve it
106-
if loaded_args.any?
107-
public_send(self.class.resolve_method, **loaded_args)
108-
else
109-
public_send(self.class.resolve_method)
110-
end
106+
call_resolve(loaded_args)
111107
else
112108
raise GraphQL::UnauthorizedFieldError.new(context: context, object: object, type: field.owner, field: field)
113109
end
@@ -117,6 +113,15 @@ def resolve_with_support(**args)
117113
end
118114
end
119115

116+
# @api private {GraphQL::Schema::Mutation} uses this to clear the dataloader cache
117+
def call_resolve(args_hash)
118+
if args_hash.any?
119+
public_send(self.class.resolve_method, **args_hash)
120+
else
121+
public_send(self.class.resolve_method)
122+
end
123+
end
124+
120125
# Do the work. Everything happens here.
121126
# @return [Object] An object corresponding to the return type
122127
def resolve(**args)

spec/graphql/schema/mutation_spec.rb

+71
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,75 @@ def resolve(**inputs)
258258
res = schema.execute("mutation { child(thingName: \"abc\", thingId: \"123\") { inputs } }")
259259
assert_equal "{:thing_id=>\"123\", :thing_name=>\"abc\"}", res["data"]["child"]["inputs"]
260260
end
261+
262+
describe "flushing dataloader cache" do
263+
class MutationDataloaderCacheSchema < GraphQL::Schema
264+
module Database
265+
DATA = {}
266+
def self.get(id)
267+
value = DATA[id] ||= 0
268+
OpenStruct.new(id: id, value: value)
269+
end
270+
271+
def self.increment(id)
272+
DATA[id] ||= 0
273+
DATA[id] += 1
274+
end
275+
276+
def self.clear
277+
DATA.clear
278+
end
279+
end
280+
281+
class CounterSource < GraphQL::Dataloader::Source
282+
def fetch(ids)
283+
ids.map { |id| Database.get(id) }
284+
end
285+
end
286+
class CounterType < GraphQL::Schema::Object
287+
def self.authorized?(obj, ctx)
288+
# Just force the load here, too:
289+
ctx.dataloader.with(CounterSource).load(obj.id)
290+
true
291+
end
292+
field :value, Integer
293+
end
294+
class Increment < GraphQL::Schema::Mutation
295+
field :counter, CounterType
296+
argument :counter_id, ID, loads: CounterType
297+
298+
def resolve(counter:)
299+
Database.increment(counter.id)
300+
{
301+
counter: dataloader.with(CounterSource).load(counter.id)
302+
}
303+
end
304+
end
305+
306+
class Mutation < GraphQL::Schema::Object
307+
field :increment, mutation: Increment
308+
end
309+
310+
mutation(Mutation)
311+
312+
def self.object_from_id(id, ctx)
313+
ctx.dataloader.with(CounterSource).load(id)
314+
end
315+
316+
def self.resolve_type(abs_type, obj, ctx)
317+
CounterType
318+
end
319+
320+
use GraphQL::Dataloader
321+
end
322+
323+
it "clears the cache after authorized and loads" do
324+
MutationDataloaderCacheSchema::Database.clear
325+
res = MutationDataloaderCacheSchema.execute("mutation { increment(counterId: \"4\") { counter { value } } }")
326+
assert_equal 1, res["data"]["increment"]["counter"]["value"]
327+
328+
res2 = MutationDataloaderCacheSchema.execute("mutation { increment(counterId: \"4\") { counter { value } } }")
329+
assert_equal 2, res2["data"]["increment"]["counter"]["value"]
330+
end
331+
end
261332
end

0 commit comments

Comments
 (0)