graphql 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/query_complexity.rb +20 -13
- data/lib/graphql/analysis/query_depth.rb +2 -2
- data/lib/graphql/argument.rb +7 -2
- data/lib/graphql/base_type.rb +2 -1
- data/lib/graphql/boolean_type.rb +1 -0
- data/lib/graphql/define/assign_object_field.rb +19 -6
- data/lib/graphql/define/instance_definable.rb +44 -3
- data/lib/graphql/directive.rb +2 -6
- data/lib/graphql/enum_type.rb +11 -14
- data/lib/graphql/field.rb +47 -12
- data/lib/graphql/field/resolve.rb +57 -0
- data/lib/graphql/float_type.rb +2 -0
- data/lib/graphql/id_type.rb +2 -0
- data/lib/graphql/input_object_type.rb +5 -1
- data/lib/graphql/int_type.rb +2 -0
- data/lib/graphql/interface_type.rb +1 -1
- data/lib/graphql/internal_representation/node.rb +18 -29
- data/lib/graphql/internal_representation/rewrite.rb +7 -4
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/input_value_type.rb +1 -1
- data/lib/graphql/language/parser.rb +161 -136
- data/lib/graphql/language/parser.y +9 -1
- data/lib/graphql/object_type.rb +2 -2
- data/lib/graphql/query.rb +4 -4
- data/lib/graphql/query/directive_resolution.rb +2 -2
- data/lib/graphql/query/serial_execution/execution_context.rb +3 -2
- data/lib/graphql/query/serial_execution/field_resolution.rb +2 -5
- data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
- data/lib/graphql/query/serial_execution/value_resolution.rb +2 -2
- data/lib/graphql/scalar_type.rb +2 -0
- data/lib/graphql/schema/timeout_middleware.rb +1 -0
- data/lib/graphql/string_type.rb +2 -0
- data/lib/graphql/union_type.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -3
- data/spec/graphql/analysis/query_complexity_spec.rb +41 -5
- data/spec/graphql/define/instance_definable_spec.rb +2 -2
- data/spec/graphql/field_spec.rb +18 -0
- data/spec/graphql/internal_representation/rewrite_spec.rb +7 -6
- data/spec/graphql/language/parser_spec.rb +5 -0
- data/spec/graphql/query/serial_execution/execution_context_spec.rb +2 -1
- data/spec/graphql/schema/timeout_middleware_spec.rb +29 -28
- data/spec/support/dairy_app.rb +12 -10
- metadata +3 -3
- data/lib/graphql/internal_representation/definition.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24203b4225051e3273a336d37502cdddd29c3c21
|
4
|
+
data.tar.gz: d3c4de442aa838dfde6db055cd4da9e397a89578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d134105d845e9b416078a504048f9ba263943fba5741a4de5d9f3cf229a193614858794b9d6ef5b857b84cb14ea3f1bb14d1b9ffc6beb4ee9e6fff2d9c9fac1c
|
7
|
+
data.tar.gz: e7107d02800a97cf95ed00dc54463056ba7dd0bc38623f5750deb4cc6a0ea736074a84ee77da81859c7c548ffe75b117a9c130e7a98fc13a6339dfdc8a8ba1ea
|
@@ -38,7 +38,7 @@ module GraphQL
|
|
38
38
|
else
|
39
39
|
0
|
40
40
|
end
|
41
|
-
memo[:complexities_on_type].last.merge(irep_node.
|
41
|
+
memo[:complexities_on_type].last.merge(irep_node.definitions, own_complexity)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
memo
|
@@ -56,17 +56,24 @@ module GraphQL
|
|
56
56
|
# Get a complexity value for a field,
|
57
57
|
# by getting the number or calling its proc
|
58
58
|
def get_complexity(irep_node, query, child_complexity)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
59
|
+
max_possible_complexity = 0
|
60
|
+
irep_node.definitions.each do |type_defn, field_defn|
|
61
|
+
defined_complexity = field_defn.complexity
|
62
|
+
type_cpx = case defined_complexity
|
63
|
+
when Proc
|
64
|
+
args = query.arguments_for(irep_node, field_defn)
|
65
|
+
defined_complexity.call(query.context, args, child_complexity)
|
66
|
+
when Numeric
|
67
|
+
defined_complexity + (child_complexity || 0)
|
68
|
+
else
|
69
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{field_defn.name}")
|
70
|
+
end
|
71
|
+
|
72
|
+
if type_cpx > max_possible_complexity
|
73
|
+
max_possible_complexity = type_cpx
|
74
|
+
end
|
69
75
|
end
|
76
|
+
max_possible_complexity
|
70
77
|
end
|
71
78
|
|
72
79
|
# Selections on an object may apply differently depending on what is _actually_ returned by the resolve function.
|
@@ -97,8 +104,8 @@ module GraphQL
|
|
97
104
|
end
|
98
105
|
|
99
106
|
# Store the complexity score for each of `types`
|
100
|
-
def merge(
|
101
|
-
|
107
|
+
def merge(definitions, complexity)
|
108
|
+
definitions.each { |type_defn, field_defn| @types[type_defn] += complexity }
|
102
109
|
end
|
103
110
|
|
104
111
|
private
|
@@ -24,7 +24,7 @@ module GraphQL
|
|
24
24
|
def call(memo, visit_type, irep_node)
|
25
25
|
if irep_node.ast_node.is_a?(GraphQL::Language::Nodes::Field)
|
26
26
|
if visit_type == :enter
|
27
|
-
if GraphQL::Schema::DYNAMIC_FIELDS.include?(irep_node.
|
27
|
+
if GraphQL::Schema::DYNAMIC_FIELDS.include?(irep_node.definition_name)
|
28
28
|
# Don't validate introspection fields
|
29
29
|
memo[:skip_current_scope] = true
|
30
30
|
elsif memo[:skip_current_scope]
|
@@ -33,7 +33,7 @@ module GraphQL
|
|
33
33
|
memo[:current_depth] += 1
|
34
34
|
end
|
35
35
|
else
|
36
|
-
if GraphQL::Schema::DYNAMIC_FIELDS.include?(irep_node.
|
36
|
+
if GraphQL::Schema::DYNAMIC_FIELDS.include?(irep_node.definition_name)
|
37
37
|
memo[:skip_current_scope] = false
|
38
38
|
elsif GraphQL::Query::DirectiveResolution.include_node?(irep_node, memo[:query])
|
39
39
|
if memo[:max_depth] < memo[:current_depth]
|
data/lib/graphql/argument.rb
CHANGED
@@ -17,9 +17,14 @@ module GraphQL
|
|
17
17
|
class Argument
|
18
18
|
include GraphQL::Define::InstanceDefinable
|
19
19
|
accepts_definitions :name, :type, :description, :default_value
|
20
|
-
|
20
|
+
lazy_defined_attr_accessor :type, :description, :default_value
|
21
21
|
|
22
22
|
# @return [String] The name of this argument on its {GraphQL::Field} or {GraphQL::InputObjectType}
|
23
|
-
|
23
|
+
def name
|
24
|
+
ensure_defined
|
25
|
+
@name
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_writer :name
|
24
29
|
end
|
25
30
|
end
|
data/lib/graphql/base_type.rb
CHANGED
@@ -3,8 +3,8 @@ module GraphQL
|
|
3
3
|
class BaseType
|
4
4
|
include GraphQL::Define::NonNullWithBang
|
5
5
|
include GraphQL::Define::InstanceDefinable
|
6
|
-
attr_accessor :name, :description
|
7
6
|
accepts_definitions :name, :description
|
7
|
+
lazy_defined_attr_accessor :name, :description
|
8
8
|
|
9
9
|
# @param other [GraphQL::BaseType] compare to this object
|
10
10
|
# @return [Boolean] are these types equivalent? (incl. non-null, list)
|
@@ -53,6 +53,7 @@ module GraphQL
|
|
53
53
|
# @param ctx [GraphQL::Query::Context]
|
54
54
|
# @return [GraphQL::ObjectType] the type which should expose `object`
|
55
55
|
def resolve_type(object, ctx)
|
56
|
+
ensure_defined
|
56
57
|
instance_exec(object, ctx, &(@resolve_type_proc || DEFAULT_RESOLVE_TYPE))
|
57
58
|
end
|
58
59
|
|
data/lib/graphql/boolean_type.rb
CHANGED
@@ -3,6 +3,7 @@ GraphQL::BOOLEAN_TYPE = GraphQL::ScalarType.define do
|
|
3
3
|
ALLOWED_INPUTS = [true, false]
|
4
4
|
|
5
5
|
name "Boolean"
|
6
|
+
description "Represents `true` or `false` values."
|
6
7
|
|
7
8
|
coerce_input -> (value) { ALLOWED_INPUTS.include?(value) ? value : nil }
|
8
9
|
coerce_result -> (value) { !!value }
|
@@ -2,15 +2,28 @@ module GraphQL
|
|
2
2
|
module Define
|
3
3
|
# Turn field configs into a {GraphQL::Field} and attach it to a {GraphQL::ObjectType} or {GraphQL::InterfaceType}
|
4
4
|
module AssignObjectField
|
5
|
-
def self.call(fields_type, name,
|
6
|
-
if
|
5
|
+
def self.call(fields_type, name, type_or_field = nil, desc = nil, field: nil, deprecation_reason: nil, property: nil, complexity: nil, hash_key: nil, &block)
|
6
|
+
if type_or_field.is_a?(GraphQL::Field)
|
7
|
+
field = type_or_field
|
8
|
+
elsif block_given?
|
7
9
|
field = GraphQL::Field.define(&block)
|
8
|
-
|
9
|
-
field
|
10
|
+
elsif field.nil?
|
11
|
+
field = GraphQL::Field.new
|
10
12
|
end
|
11
|
-
|
13
|
+
|
14
|
+
if !type_or_field.nil? && !type_or_field.is_a?(GraphQL::Field)
|
15
|
+
field.type = type_or_field
|
16
|
+
end
|
17
|
+
|
12
18
|
desc && field.description = desc
|
13
|
-
|
19
|
+
|
20
|
+
# If the field's resolve proc was defined in the config block,
|
21
|
+
# don't override it with `property` or `hash_key`
|
22
|
+
if field.resolve_proc.is_a?(GraphQL::Field::Resolve::BuiltInResolve)
|
23
|
+
property && field.property = property
|
24
|
+
hash_key && field.hash_key = hash_key
|
25
|
+
end
|
26
|
+
|
14
27
|
complexity && field.complexity = complexity
|
15
28
|
deprecation_reason && field.deprecation_reason = deprecation_reason
|
16
29
|
field.name ||= name.to_s
|
@@ -44,12 +44,36 @@ module GraphQL
|
|
44
44
|
base.extend(ClassMethods)
|
45
45
|
end
|
46
46
|
|
47
|
+
# Set the definition block for this instance.
|
48
|
+
# It can be run later with {#ensure_defined}
|
49
|
+
def definition_proc=(defn_block)
|
50
|
+
@definition_proc = defn_block
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Run the definition block if it hasn't been run yet.
|
56
|
+
# This can only be run once: the block is deleted after it's used.
|
57
|
+
# You have to call this before using any value which could
|
58
|
+
# come from the definition block.
|
59
|
+
# @return [void]
|
60
|
+
def ensure_defined
|
61
|
+
if @definition_proc
|
62
|
+
defn_proc = @definition_proc
|
63
|
+
@definition_proc = nil
|
64
|
+
proxy = DefinedObjectProxy.new(self, self.class.dictionary)
|
65
|
+
proxy.instance_eval(&defn_proc)
|
66
|
+
end
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
47
70
|
module ClassMethods
|
48
|
-
#
|
71
|
+
# Prepare the defintion for an instance of this class using its {.definitions}.
|
72
|
+
# Note that the block is not called right away -- instead, it's deferred until
|
73
|
+
# one of the defined fields is needed.
|
49
74
|
def define(&block)
|
50
75
|
instance = self.new
|
51
|
-
|
52
|
-
block && proxy.instance_eval(&block)
|
76
|
+
instance.definition_proc = block
|
53
77
|
instance
|
54
78
|
end
|
55
79
|
|
@@ -60,6 +84,23 @@ module GraphQL
|
|
60
84
|
@own_dictionary = own_dictionary.merge(AssignmentDictionary.create(*accepts))
|
61
85
|
end
|
62
86
|
|
87
|
+
# Define a reader and writer for each of `attr_names` which
|
88
|
+
# ensures that the definition block was called before accessing it.
|
89
|
+
def lazy_defined_attr_accessor(*attr_names)
|
90
|
+
attr_names.each do |attr_name|
|
91
|
+
ivar_name = :"@#{attr_name}"
|
92
|
+
define_method(attr_name) do
|
93
|
+
ensure_defined
|
94
|
+
instance_variable_get(ivar_name)
|
95
|
+
end
|
96
|
+
|
97
|
+
define_method("#{attr_name}=") do |new_value|
|
98
|
+
ensure_defined
|
99
|
+
instance_variable_set(ivar_name, new_value)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
63
104
|
# @return [Hash] combined definitions for self and ancestors
|
64
105
|
def dictionary
|
65
106
|
if superclass.respond_to?(:dictionary)
|
data/lib/graphql/directive.rb
CHANGED
@@ -3,7 +3,7 @@ module GraphQL
|
|
3
3
|
include GraphQL::Define::InstanceDefinable
|
4
4
|
accepts_definitions :locations, :name, :description, :include_proc, argument: GraphQL::Define::AssignArgument
|
5
5
|
|
6
|
-
|
6
|
+
lazy_defined_attr_accessor :locations, :arguments, :name, :description, :include_proc
|
7
7
|
|
8
8
|
LOCATIONS = [
|
9
9
|
QUERY = :QUERY,
|
@@ -20,11 +20,7 @@ module GraphQL
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def include?(arguments)
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
def include_proc=(include_proc)
|
27
|
-
@include_proc = include_proc
|
23
|
+
include_proc.call(arguments)
|
28
24
|
end
|
29
25
|
|
30
26
|
def to_s
|
data/lib/graphql/enum_type.rb
CHANGED
@@ -19,10 +19,10 @@ module GraphQL
|
|
19
19
|
@values_by_value = {}
|
20
20
|
end
|
21
21
|
|
22
|
-
def values=(
|
22
|
+
def values=(new_values)
|
23
23
|
@values_by_name = {}
|
24
24
|
@values_by_value = {}
|
25
|
-
|
25
|
+
new_values.each { |enum_value| add_value(enum_value) }
|
26
26
|
end
|
27
27
|
|
28
28
|
def add_value(enum_value)
|
@@ -31,24 +31,16 @@ module GraphQL
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def values
|
34
|
+
ensure_defined
|
34
35
|
@values_by_name
|
35
36
|
end
|
36
37
|
|
37
|
-
# Define a value within this enum
|
38
|
-
# @deprecated use {.define} API instead
|
39
|
-
# @param name [String] the string representation of this value
|
40
|
-
# @param description [String]
|
41
|
-
# @param deprecation_reason [String] if provided, `deprecated?` will be true
|
42
|
-
# @param value [Object] the underlying value for this enum value
|
43
|
-
def value(name, description=nil, deprecation_reason: nil, value: name)
|
44
|
-
values[name] = EnumValue.new(name: name, description: description, deprecation_reason: deprecation_reason, value: value)
|
45
|
-
end
|
46
|
-
|
47
38
|
def kind
|
48
39
|
GraphQL::TypeKinds::ENUM
|
49
40
|
end
|
50
41
|
|
51
42
|
def validate_non_null_input(value_name)
|
43
|
+
ensure_defined
|
52
44
|
result = GraphQL::Query::InputValidationResult.new
|
53
45
|
|
54
46
|
if !@values_by_name.key?(value_name)
|
@@ -67,11 +59,16 @@ module GraphQL
|
|
67
59
|
# @param value_name [String] the string representation of this enum value
|
68
60
|
# @return [Object] the underlying value for this enum value
|
69
61
|
def coerce_non_null_input(value_name)
|
70
|
-
|
71
|
-
@values_by_name.
|
62
|
+
ensure_defined
|
63
|
+
if @values_by_name.key?(value_name)
|
64
|
+
@values_by_name.fetch(value_name).value
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
72
68
|
end
|
73
69
|
|
74
70
|
def coerce_result(value)
|
71
|
+
ensure_defined
|
75
72
|
@values_by_value.fetch(value).name
|
76
73
|
end
|
77
74
|
|
data/lib/graphql/field.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "graphql/field/resolve"
|
2
|
+
|
1
3
|
module GraphQL
|
2
4
|
# {Field}s belong to {ObjectType}s and {InterfaceType}s.
|
3
5
|
#
|
@@ -57,20 +59,35 @@ module GraphQL
|
|
57
59
|
#
|
58
60
|
class Field
|
59
61
|
include GraphQL::Define::InstanceDefinable
|
60
|
-
accepts_definitions :name, :description, :resolve, :type, :property, :deprecation_reason, :complexity, argument: GraphQL::Define::AssignArgument
|
62
|
+
accepts_definitions :name, :description, :resolve, :type, :property, :deprecation_reason, :complexity, :hash_key, argument: GraphQL::Define::AssignArgument
|
61
63
|
|
62
|
-
|
64
|
+
lazy_defined_attr_accessor :deprecation_reason, :description, :property, :hash_key
|
63
65
|
|
64
66
|
attr_reader :resolve_proc
|
65
67
|
|
66
68
|
# @return [String] The name of this field on its {GraphQL::ObjectType} (or {GraphQL::InterfaceType})
|
67
|
-
|
69
|
+
def name
|
70
|
+
ensure_defined
|
71
|
+
@name
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_writer :name
|
68
75
|
|
69
76
|
# @return [Hash<String => GraphQL::Argument>] Map String argument names to their {GraphQL::Argument} implementations
|
70
|
-
|
77
|
+
def arguments
|
78
|
+
ensure_defined
|
79
|
+
@arguments
|
80
|
+
end
|
81
|
+
|
82
|
+
attr_writer :arguments
|
71
83
|
|
72
84
|
# @return [Numeric, Proc] The complexity for this field (default: 1), as a constant or a proc like `-> (query_ctx, args, child_complexity) { } # Numeric`
|
73
|
-
|
85
|
+
def complexity
|
86
|
+
ensure_defined
|
87
|
+
@complexity
|
88
|
+
end
|
89
|
+
|
90
|
+
attr_writer :complexity
|
74
91
|
|
75
92
|
def initialize
|
76
93
|
@complexity = 1
|
@@ -86,21 +103,27 @@ module GraphQL
|
|
86
103
|
# @param arguments [Hash] Arguments declared in the query
|
87
104
|
# @param context [GraphQL::Query::Context]
|
88
105
|
def resolve(object, arguments, context)
|
89
|
-
|
106
|
+
ensure_defined
|
107
|
+
resolve_proc.call(object, arguments, context)
|
90
108
|
end
|
91
109
|
|
92
110
|
def resolve=(resolve_proc)
|
111
|
+
ensure_defined
|
93
112
|
@resolve_proc = resolve_proc || build_default_resolver
|
94
113
|
end
|
95
114
|
|
96
115
|
def type=(new_return_type)
|
116
|
+
ensure_defined
|
97
117
|
@clean_type = nil
|
98
118
|
@dirty_type = new_return_type
|
99
119
|
end
|
100
120
|
|
101
121
|
# Get the return type for this field.
|
102
122
|
def type
|
103
|
-
@clean_type ||=
|
123
|
+
@clean_type ||= begin
|
124
|
+
ensure_defined
|
125
|
+
GraphQL::BaseType.resolve_related_type(@dirty_type)
|
126
|
+
end
|
104
127
|
end
|
105
128
|
|
106
129
|
# You can only set a field's name _once_ -- this to prevent
|
@@ -108,13 +131,28 @@ module GraphQL
|
|
108
131
|
#
|
109
132
|
# This is important because {#name} may be used by {#resolve}.
|
110
133
|
def name=(new_name)
|
134
|
+
ensure_defined
|
111
135
|
if @name.nil?
|
112
136
|
@name = new_name
|
113
|
-
|
137
|
+
elsif @name != new_name
|
114
138
|
raise("Can't rename an already-named field. (Tried to rename \"#{@name}\" to \"#{new_name}\".) If you're passing a field with the `field:` argument, make sure it's an unused instance of GraphQL::Field.")
|
115
139
|
end
|
116
140
|
end
|
117
141
|
|
142
|
+
# @param new_property [Symbol] A method to call to resolve this field. Overrides the existing resolve proc.
|
143
|
+
def property=(new_property)
|
144
|
+
ensure_defined
|
145
|
+
@property = new_property
|
146
|
+
self.resolve = nil # reset resolve proc
|
147
|
+
end
|
148
|
+
|
149
|
+
# @param new_hash_key [Symbol] A key to access with `#[key]` to resolve this field. Overrides the existing resolve proc.
|
150
|
+
def hash_key=(new_hash_key)
|
151
|
+
ensure_defined
|
152
|
+
@hash_key = new_hash_key
|
153
|
+
self.resolve = nil # reset resolve proc
|
154
|
+
end
|
155
|
+
|
118
156
|
def to_s
|
119
157
|
"<Field: #{name || "not-named"}>"
|
120
158
|
end
|
@@ -122,10 +160,7 @@ module GraphQL
|
|
122
160
|
private
|
123
161
|
|
124
162
|
def build_default_resolver
|
125
|
-
|
126
|
-
resolve_method = self.property || self.name
|
127
|
-
obj.public_send(resolve_method)
|
128
|
-
end
|
163
|
+
GraphQL::Field::Resolve.create_proc(self)
|
129
164
|
end
|
130
165
|
end
|
131
166
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module GraphQL
|
2
|
+
class Field
|
3
|
+
# Create resolve procs ahead of time based on a {GraphQL::Field}'s `name`, `property`, and `hash_key` configuration.
|
4
|
+
module Resolve
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# @param [GraphQL::Field] A field that needs a resolve proc
|
8
|
+
# @return [Proc] A resolver for this field, based on its config
|
9
|
+
def create_proc(field)
|
10
|
+
if field.property
|
11
|
+
MethodResolve.new(field.property.to_sym)
|
12
|
+
elsif !field.hash_key.nil?
|
13
|
+
HashKeyResolve.new(field.hash_key)
|
14
|
+
else
|
15
|
+
NameResolve.new(field)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class BuiltInResolve
|
20
|
+
end
|
21
|
+
|
22
|
+
# Resolve the field by `public_send`ing `@method_name`
|
23
|
+
class MethodResolve < BuiltInResolve
|
24
|
+
def initialize(method_name)
|
25
|
+
@method_name = method_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(obj, args, ctx)
|
29
|
+
obj.public_send(@method_name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Resolve the field by looking up `@hash_key` with `#[]`
|
34
|
+
class HashKeyResolve < BuiltInResolve
|
35
|
+
def initialize(hash_key)
|
36
|
+
@hash_key = hash_key
|
37
|
+
end
|
38
|
+
|
39
|
+
def call(obj, args, ctx)
|
40
|
+
obj[@hash_key]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Call the field's name at query-time since
|
45
|
+
# it might have changed
|
46
|
+
class NameResolve < BuiltInResolve
|
47
|
+
def initialize(field)
|
48
|
+
@field = field
|
49
|
+
end
|
50
|
+
|
51
|
+
def call(obj, args, ctx)
|
52
|
+
obj.public_send(@field.name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|