Skip to content

Commit 51d7c88

Browse files
committed
Centralize default resolve in HasFields
1 parent ba0655c commit 51d7c88

File tree

6 files changed

+55
-22
lines changed

6 files changed

+55
-22
lines changed

lib/graphql/introspection/base_object.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ def self.field(*args, **kwargs, &block)
99

1010
def self.inherited(child_class)
1111
child_class.introspection(true)
12+
super
1213
end
1314
end
1415
end

lib/graphql/schema/interface.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ def included(child_class)
2929
child_class.own_interfaces.each do |interface_defn|
3030
child_class.extend(interface_defn::DefinitionMethods)
3131
end
32-
# Also, prepare a place for default field implementations
33-
default_resolve_module = Module.new
34-
child_class.const_set(:DefaultResolve, default_resolve_module)
35-
child_class.include(default_resolve_module)
3632
elsif child_class < GraphQL::Schema::Object
3733
# This is being included into an object type, make sure it's using `implements(...)`
3834
backtrace_line = caller(0, 10).find { |line| line.include?("schema/object.rb") && line.include?("in `implements'")}

lib/graphql/schema/member/has_fields.rb

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,42 @@ class Schema
44
class Member
55
# Shared code for Object and Interface
66
module HasFields
7+
class << self
8+
# When this module is added to a class,
9+
# add a place for that class's default behaviors
10+
def self.extended(child_class)
11+
add_default_resolve_module(child_class)
12+
super
13+
end
14+
15+
def add_default_resolve_module(child_class)
16+
if child_class.instance_variable_get(:@_default_resolve)
17+
# This can happen when an object implements an interface,
18+
# since that interface has the `included` hook above.
19+
return
20+
end
21+
22+
default_resolve_module = Module.new
23+
child_class.instance_variable_set(:@_default_resolve, default_resolve_module)
24+
child_class.include(default_resolve_module)
25+
end
26+
end
27+
28+
# When this is included into interfaces,
29+
# add a place for default field behaviors
30+
def included(child_class)
31+
HasFields.add_default_resolve_module(child_class)
32+
# Also, prepare a place for default field implementations
33+
super
34+
end
35+
36+
# When a subclass of objects are created,
37+
# add a place for that subclass's default field behaviors
38+
def inherited(child_class)
39+
HasFields.add_default_resolve_module(child_class)
40+
super
41+
end
42+
743
# Add a field to this object or interface with the given definition
844
# @see {GraphQL::Schema::Field#initialize} for method signature
945
# @return [void]
@@ -31,15 +67,23 @@ def fields
3167
# @return [void]
3268
def add_field(field_defn)
3369
own_fields[field_defn.name] = field_defn
34-
if defined?(self::DefaultResolve)
35-
field_key = field_defn.name.inspect
36-
self::DefaultResolve.module_eval <<-RUBY, __FILE__, __LINE__ + 1
37-
def #{field_defn.method_sym}(**args)
38-
field_inst = self.class.fields[#{field_key}] || raise(%|Failed to find field #{field_key} for \#{self.class} among \#{self.class.fields.keys}|)
39-
field_inst.resolve_field_method(self, args, context)
40-
end
41-
RUBY
70+
# Add a `super` method for implementing this field:
71+
field_key = field_defn.name.inspect
72+
default_resolve_module = self.instance_variable_get(:@_default_resolve)
73+
if default_resolve_module.nil?
74+
# This should have been set up in one of the inherited or included hooks above,
75+
# if it wasn't, it's because those hooks weren't called because `super` wasn't present.
76+
raise <<-ERR
77+
Uh oh! #{self} doesn't have a default resolve module. This probably means that an `inherited` hook didn't call super.
78+
Check `inherited` on #{self}'s superclasses.
79+
ERR
4280
end
81+
default_resolve_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
82+
def #{field_defn.method_sym}(**args)
83+
field_inst = self.class.fields[#{field_key}] || raise(%|Failed to find field #{field_key} for \#{self.class} among \#{self.class.fields.keys}|)
84+
field_inst.resolve_field_method(self, args, context)
85+
end
86+
RUBY
4387
nil
4488
end
4589

lib/graphql/schema/mutation.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def resolve(**args)
8585
class << self
8686
def inherited(base)
8787
base.null(null)
88+
super
8889
end
8990

9091
# Override the method from HasFields to support `field: Mutation.field`, for backwards compat.

lib/graphql/schema/object.rb

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,6 @@ def to_graphql
7171

7272
obj_type
7373
end
74-
75-
# When a subclass is created, give it a DefaultResolve module.
76-
# That module has the base methods for executing fields.
77-
# That way, later method definitions can call `super` to get the default behavior.
78-
def inherited(child_class)
79-
default_resolve_module = Module.new
80-
child_class.const_set(:DefaultResolve, default_resolve_module)
81-
child_class.include(default_resolve_module)
82-
super
83-
end
8474
end
8575
end
8676
end

lib/graphql/schema/relay_classic_mutation.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class RelayClassicMutation < GraphQL::Schema::Mutation
2626
class << self
2727
def inherited(base)
2828
base.null(true)
29+
super
2930
end
3031

3132
# The base class for generated input object types

0 commit comments

Comments
 (0)