graphql 1.10.2 → 1.10.3
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/generators/graphql/core.rb +10 -2
- data/lib/generators/graphql/templates/schema.erb +1 -0
- data/lib/graphql/define/defined_object_proxy.rb +1 -1
- data/lib/graphql/define/instance_definable.rb +1 -1
- data/lib/graphql/execution/interpreter.rb +3 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
- data/lib/graphql/execution/interpreter/runtime.rb +37 -121
- data/lib/graphql/field.rb +1 -1
- data/lib/graphql/language/nodes.rb +41 -83
- data/lib/graphql/language/parser.rb +96 -96
- data/lib/graphql/language/parser.y +96 -96
- data/lib/graphql/pagination/connections.rb +21 -5
- data/lib/graphql/query/null_context.rb +5 -1
- data/lib/graphql/query/variables.rb +9 -3
- data/lib/graphql/schema.rb +18 -2
- data/lib/graphql/schema/build_from_definition.rb +15 -1
- data/lib/graphql/schema/enum.rb +4 -1
- data/lib/graphql/schema/field.rb +11 -0
- data/lib/graphql/schema/field/connection_extension.rb +2 -1
- data/lib/graphql/schema/input_object.rb +21 -38
- data/lib/graphql/schema/member/base_dsl_methods.rb +11 -4
- data/lib/graphql/schema/member/has_arguments.rb +53 -2
- data/lib/graphql/schema/member/has_ast_node.rb +4 -1
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/resolver.rb +2 -2
- data/lib/graphql/schema/resolver/has_payload_type.rb +3 -1
- data/lib/graphql/schema/warden.rb +10 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +0 -1
- data/lib/graphql/subscriptions.rb +14 -9
- data/lib/graphql/subscriptions/subscription_root.rb +2 -1
- data/lib/graphql/version.rb +1 -1
- metadata +4 -3
@@ -23,6 +23,10 @@ module GraphQL
|
|
23
23
|
|
24
24
|
def [](key); end
|
25
25
|
|
26
|
+
def interpreter?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
26
30
|
class << self
|
27
31
|
extend Forwardable
|
28
32
|
|
@@ -32,7 +36,7 @@ module GraphQL
|
|
32
36
|
@instance = self.new
|
33
37
|
end
|
34
38
|
|
35
|
-
def_delegators :instance, :query, :schema, :warden
|
39
|
+
def_delegators :instance, :query, :schema, :warden, :interpreter?
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
@@ -34,7 +34,9 @@ module GraphQL
|
|
34
34
|
if validation_result.valid?
|
35
35
|
if value_was_provided
|
36
36
|
# Add the variable if a value was provided
|
37
|
-
memo[variable_name] = if
|
37
|
+
memo[variable_name] = if ctx.interpreter?
|
38
|
+
provided_value
|
39
|
+
elsif provided_value.nil?
|
38
40
|
nil
|
39
41
|
else
|
40
42
|
schema.error_handler.with_error_handling(context) do
|
@@ -42,8 +44,12 @@ module GraphQL
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
elsif default_value != nil
|
45
|
-
|
46
|
-
|
47
|
+
memo[variable_name] = if ctx.interpreter?
|
48
|
+
default_value
|
49
|
+
else
|
50
|
+
# Add the variable if it wasn't provided but it has a default value (including `null`)
|
51
|
+
GraphQL::Query::LiteralInput.coerce(variable_type, default_value, self)
|
52
|
+
end
|
47
53
|
end
|
48
54
|
end
|
49
55
|
rescue GraphQL::CoercionError, GraphQL::ExecutionError => ex
|
data/lib/graphql/schema.rb
CHANGED
@@ -787,7 +787,7 @@ module GraphQL
|
|
787
787
|
def_delegators :graphql_definition,
|
788
788
|
# Execution
|
789
789
|
:execution_strategy_for_operation,
|
790
|
-
:validate,
|
790
|
+
:validate,
|
791
791
|
# Configuration
|
792
792
|
:metadata, :redefine,
|
793
793
|
:id_from_object_proc, :object_from_id_proc,
|
@@ -942,8 +942,24 @@ module GraphQL
|
|
942
942
|
find_inherited_value(:types, EMPTY_HASH)[type_name]
|
943
943
|
end
|
944
944
|
|
945
|
+
# @api private
|
946
|
+
attr_writer :connections
|
947
|
+
|
945
948
|
# @return [GraphQL::Pagination::Connections] if installed
|
946
|
-
|
949
|
+
def connections
|
950
|
+
if defined?(@connections)
|
951
|
+
@connections
|
952
|
+
else
|
953
|
+
inherited_connections = find_inherited_value(:connections, nil)
|
954
|
+
# This schema is part of an inheritance chain which is using new connections,
|
955
|
+
# make a new instance, so we don't pollute the upstream one.
|
956
|
+
if inherited_connections
|
957
|
+
@connections = Pagination::Connections.new(schema: self)
|
958
|
+
else
|
959
|
+
nil
|
960
|
+
end
|
961
|
+
end
|
962
|
+
end
|
947
963
|
|
948
964
|
def new_connections?
|
949
965
|
!!connections
|
@@ -42,7 +42,6 @@ module GraphQL
|
|
42
42
|
end
|
43
43
|
schema_definition = schema_defns.first
|
44
44
|
types = {}
|
45
|
-
types.merge!(GraphQL::Schema::BUILT_IN_TYPES)
|
46
45
|
directives = {}
|
47
46
|
type_resolver = ->(type) { resolve_type(types, type) }
|
48
47
|
|
@@ -69,6 +68,21 @@ module GraphQL
|
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
71
|
+
# At this point, if types named by the built in types are _late-bound_ types,
|
72
|
+
# that means they were referenced in the schema but not defined in the schema.
|
73
|
+
# That's supported for built-in types. (Eg, you can use `String` without defining it.)
|
74
|
+
# In that case, insert the concrete type definition now.
|
75
|
+
#
|
76
|
+
# However, if the type in `types` is a _concrete_ type definition, that means that
|
77
|
+
# the document contained an explicit definition of the scalar type.
|
78
|
+
# Don't override it in this case.
|
79
|
+
GraphQL::Schema::BUILT_IN_TYPES.each do |scalar_name, built_in_scalar|
|
80
|
+
existing_type = types[scalar_name]
|
81
|
+
if existing_type.is_a?(GraphQL::Schema::LateBoundType)
|
82
|
+
types[scalar_name] = built_in_scalar
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
72
86
|
directives = GraphQL::Schema.default_directives.merge(directives)
|
73
87
|
|
74
88
|
if schema_definition
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -63,8 +63,11 @@ module GraphQL
|
|
63
63
|
def enum_value_class(new_enum_value_class = nil)
|
64
64
|
if new_enum_value_class
|
65
65
|
@enum_value_class = new_enum_value_class
|
66
|
+
elsif defined?(@enum_value_class) && @enum_value_class
|
67
|
+
@enum_value_class
|
68
|
+
else
|
69
|
+
superclass <= GraphQL::Schema::Enum ? superclass.enum_value_class : nil
|
66
70
|
end
|
67
|
-
@enum_value_class || (superclass <= GraphQL::Schema::Enum ? superclass.enum_value_class : nil)
|
68
71
|
end
|
69
72
|
|
70
73
|
def kind
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -648,6 +648,17 @@ module GraphQL
|
|
648
648
|
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
649
649
|
arguments.each do |name, arg_defn|
|
650
650
|
ruby_kwargs_key = arg_defn.keyword
|
651
|
+
|
652
|
+
loads = arg_defn.loads
|
653
|
+
if ruby_kwargs.key?(ruby_kwargs_key) && loads && !arg_defn.from_resolver?
|
654
|
+
value = ruby_kwargs[ruby_kwargs_key]
|
655
|
+
ruby_kwargs[ruby_kwargs_key] = if arg_defn.type.list?
|
656
|
+
value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
|
657
|
+
else
|
658
|
+
load_application_object(arg_defn, loads, value, field_ctx.query.context)
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
651
662
|
if ruby_kwargs.key?(ruby_kwargs_key) && arg_defn.prepare
|
652
663
|
ruby_kwargs[ruby_kwargs_key] = arg_defn.prepare_value(obj, ruby_kwargs[ruby_kwargs_key])
|
653
664
|
end
|
@@ -38,7 +38,8 @@ module GraphQL
|
|
38
38
|
value.max_page_size ||= field.max_page_size
|
39
39
|
value
|
40
40
|
elsif context.schema.new_connections?
|
41
|
-
context.schema.connections.
|
41
|
+
wrappers = context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
42
|
+
context.schema.connections.wrap(field, value, arguments, context, wrappers: wrappers)
|
42
43
|
else
|
43
44
|
if object.is_a?(GraphQL::Schema::Object)
|
44
45
|
object = object.object
|
@@ -5,6 +5,7 @@ module GraphQL
|
|
5
5
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
6
6
|
extend Forwardable
|
7
7
|
extend GraphQL::Schema::Member::HasArguments
|
8
|
+
extend GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader
|
8
9
|
extend GraphQL::Schema::Member::ValidatesInput
|
9
10
|
|
10
11
|
include GraphQL::Dig
|
@@ -23,19 +24,25 @@ module GraphQL
|
|
23
24
|
self.class.arguments.each do |name, arg_defn|
|
24
25
|
@arguments_by_keyword[arg_defn.keyword] = arg_defn
|
25
26
|
ruby_kwargs_key = arg_defn.keyword
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
|
28
|
+
if @ruby_style_hash.key?(ruby_kwargs_key)
|
29
|
+
loads = arg_defn.loads
|
30
|
+
# Resolvers do this loading themselves;
|
31
|
+
# With the interpreter, it's done during `coerce_arguments`
|
32
|
+
if loads && !arg_defn.from_resolver? && !context.interpreter?
|
33
|
+
value = @ruby_style_hash[ruby_kwargs_key]
|
34
|
+
@ruby_style_hash[ruby_kwargs_key] = if arg_defn.type.list?
|
35
|
+
value.map { |val| load_application_object(arg_defn, loads, val, context) }
|
36
|
+
else
|
37
|
+
load_application_object(arg_defn, loads, value, context)
|
38
|
+
end
|
34
39
|
end
|
35
|
-
end
|
36
40
|
|
37
|
-
|
38
|
-
|
41
|
+
# Weirdly, procs are applied during coercion, but not methods.
|
42
|
+
# Probably because these methods require a `self`.
|
43
|
+
if arg_defn.prepare.is_a?(Symbol) || context.nil? || !context.interpreter?
|
44
|
+
@ruby_style_hash[ruby_kwargs_key] = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
|
45
|
+
end
|
39
46
|
end
|
40
47
|
end
|
41
48
|
end
|
@@ -169,7 +176,7 @@ module GraphQL
|
|
169
176
|
# Items in the input that are unexpected
|
170
177
|
input.each do |name, value|
|
171
178
|
if visible_arguments_map[name].nil?
|
172
|
-
result.add_problem("
|
179
|
+
result.add_problem("Field is not defined on #{self.graphql_name}", [name])
|
173
180
|
end
|
174
181
|
end
|
175
182
|
|
@@ -188,32 +195,8 @@ module GraphQL
|
|
188
195
|
if value.nil?
|
189
196
|
return nil
|
190
197
|
end
|
191
|
-
|
192
|
-
|
193
|
-
arguments.each do |name, argument_defn|
|
194
|
-
arg_key = argument_defn.keyword
|
195
|
-
has_value = false
|
196
|
-
|
197
|
-
# Accept either string or symbol
|
198
|
-
field_value = if value.key?(name)
|
199
|
-
has_value = true
|
200
|
-
value[name]
|
201
|
-
elsif value.key?(arg_key)
|
202
|
-
has_value = true
|
203
|
-
value[arg_key]
|
204
|
-
elsif argument_defn.default_value?
|
205
|
-
has_value = true
|
206
|
-
argument_defn.default_value
|
207
|
-
else
|
208
|
-
nil
|
209
|
-
end
|
210
|
-
# Only continue if some value was found for this argument
|
211
|
-
if has_value
|
212
|
-
coerced_value = argument_defn.type.coerce_input(field_value, ctx)
|
213
|
-
prepared_value = argument_defn.prepare_value(nil, coerced_value, context: ctx)
|
214
|
-
input_values[arg_key] = prepared_value
|
215
|
-
end
|
216
|
-
end
|
198
|
+
|
199
|
+
input_values = coerce_arguments(nil, value, ctx)
|
217
200
|
|
218
201
|
input_obj_instance = self.new(ruby_kwargs: input_values, context: ctx, defaults_used: nil)
|
219
202
|
input_obj_instance.prepare
|
@@ -26,7 +26,7 @@ module GraphQL
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def overridden_graphql_name
|
29
|
-
@graphql_name
|
29
|
+
defined?(@graphql_name) ? @graphql_name : nil
|
30
30
|
end
|
31
31
|
|
32
32
|
# Just a convenience method to point out that people should use graphql_name instead
|
@@ -46,8 +46,10 @@ module GraphQL
|
|
46
46
|
def description(new_description = nil)
|
47
47
|
if new_description
|
48
48
|
@description = new_description
|
49
|
-
|
49
|
+
elsif defined?(@description)
|
50
50
|
@description
|
51
|
+
else
|
52
|
+
nil
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
@@ -68,8 +70,10 @@ module GraphQL
|
|
68
70
|
def introspection(new_introspection = nil)
|
69
71
|
if !new_introspection.nil?
|
70
72
|
@introspection = new_introspection
|
71
|
-
|
73
|
+
elsif defined?(@introspection)
|
72
74
|
@introspection
|
75
|
+
else
|
76
|
+
false
|
73
77
|
end
|
74
78
|
end
|
75
79
|
|
@@ -82,8 +86,11 @@ module GraphQL
|
|
82
86
|
def mutation(mutation_class = nil)
|
83
87
|
if mutation_class
|
84
88
|
@mutation = mutation_class
|
89
|
+
elsif defined?(@mutation)
|
90
|
+
@mutation
|
91
|
+
else
|
92
|
+
nil
|
85
93
|
end
|
86
|
-
@mutation
|
87
94
|
end
|
88
95
|
|
89
96
|
# @return [GraphQL::BaseType] Convert this type to a legacy-style object.
|
@@ -63,12 +63,63 @@ module GraphQL
|
|
63
63
|
self.class.argument_class(new_arg_class)
|
64
64
|
end
|
65
65
|
|
66
|
+
# @param values [Hash<String, Object>]
|
67
|
+
# @param context [GraphQL::Query::Context]
|
68
|
+
# @return Hash<Symbol, Object>
|
69
|
+
def coerce_arguments(parent_object, values, context)
|
70
|
+
kwarg_arguments = {}
|
71
|
+
# Cache this hash to avoid re-merging it
|
72
|
+
arg_defns = self.arguments
|
73
|
+
|
74
|
+
arg_defns.each do |arg_name, arg_defn|
|
75
|
+
arg_key = arg_defn.keyword
|
76
|
+
has_value = false
|
77
|
+
if values.key?(arg_name)
|
78
|
+
has_value = true
|
79
|
+
value = values[arg_name]
|
80
|
+
elsif values.key?(arg_key)
|
81
|
+
has_value = true
|
82
|
+
value = values[arg_key]
|
83
|
+
elsif arg_defn.default_value?
|
84
|
+
has_value = true
|
85
|
+
value = arg_defn.default_value
|
86
|
+
end
|
87
|
+
|
88
|
+
if has_value
|
89
|
+
loads = arg_defn.loads
|
90
|
+
loaded_value = nil
|
91
|
+
if loads && !arg_defn.from_resolver?
|
92
|
+
loaded_value = if arg_defn.type.list?
|
93
|
+
value.map { |val| load_application_object(arg_defn, loads, val, context) }
|
94
|
+
else
|
95
|
+
load_application_object(arg_defn, loads, value, context)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
prepared_value = context.schema.error_handler.with_error_handling(context) do
|
100
|
+
|
101
|
+
coerced_value = if loaded_value
|
102
|
+
loaded_value
|
103
|
+
else
|
104
|
+
arg_defn.type.coerce_input(value, context)
|
105
|
+
end
|
106
|
+
|
107
|
+
arg_defn.prepare_value(parent_object, coerced_value, context: context)
|
108
|
+
end
|
109
|
+
kwarg_arguments[arg_defn.keyword] = prepared_value
|
110
|
+
end
|
111
|
+
end
|
112
|
+
kwarg_arguments
|
113
|
+
end
|
114
|
+
|
66
115
|
module ArgumentClassAccessor
|
67
116
|
def argument_class(new_arg_class = nil)
|
68
117
|
if new_arg_class
|
69
118
|
@argument_class = new_arg_class
|
119
|
+
elsif defined?(@argument_class) && @argument_class
|
120
|
+
@argument_class
|
70
121
|
else
|
71
|
-
|
122
|
+
superclass.respond_to?(:argument_class) ? superclass.argument_class : GraphQL::Schema::Argument
|
72
123
|
end
|
73
124
|
end
|
74
125
|
end
|
@@ -85,7 +136,7 @@ module GraphQL
|
|
85
136
|
context.schema.object_from_id(id, context)
|
86
137
|
end
|
87
138
|
|
88
|
-
def load_application_object(argument, lookup_as_type, id)
|
139
|
+
def load_application_object(argument, lookup_as_type, id, context)
|
89
140
|
# See if any object can be found for this ID
|
90
141
|
loaded_application_object = object_from_id(lookup_as_type, id, context)
|
91
142
|
context.schema.after_lazy(loaded_application_object) do |application_object|
|
@@ -70,7 +70,7 @@ module GraphQL
|
|
70
70
|
def field_class(new_field_class = nil)
|
71
71
|
if new_field_class
|
72
72
|
@field_class = new_field_class
|
73
|
-
elsif @field_class
|
73
|
+
elsif defined?(@field_class) && @field_class
|
74
74
|
@field_class
|
75
75
|
elsif self.is_a?(Class)
|
76
76
|
superclass.respond_to?(:field_class) ? superclass.field_class : GraphQL::Schema::Field
|
@@ -285,7 +285,7 @@ module GraphQL
|
|
285
285
|
argument = @arguments_by_keyword[:#{arg_defn.keyword}]
|
286
286
|
lookup_as_type = @arguments_loads_as_type[:#{arg_defn.keyword}]
|
287
287
|
context.schema.after_lazy(values) do |values2|
|
288
|
-
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, lookup_as_type, value) })
|
288
|
+
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, lookup_as_type, value, context) })
|
289
289
|
end
|
290
290
|
end
|
291
291
|
RUBY
|
@@ -294,7 +294,7 @@ module GraphQL
|
|
294
294
|
def load_#{arg_defn.keyword}(value)
|
295
295
|
argument = @arguments_by_keyword[:#{arg_defn.keyword}]
|
296
296
|
lookup_as_type = @arguments_loads_as_type[:#{arg_defn.keyword}]
|
297
|
-
load_application_object(argument, lookup_as_type, value)
|
297
|
+
load_application_object(argument, lookup_as_type, value, context)
|
298
298
|
end
|
299
299
|
RUBY
|
300
300
|
else
|
@@ -26,8 +26,10 @@ module GraphQL
|
|
26
26
|
def field_class(new_class = nil)
|
27
27
|
if new_class
|
28
28
|
@field_class = new_class
|
29
|
+
elsif defined?(@field_class) && @field_class
|
30
|
+
@field_class
|
29
31
|
else
|
30
|
-
|
32
|
+
find_inherited_value(:field_class, GraphQL::Schema::Field)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
@@ -230,6 +230,16 @@ module GraphQL
|
|
230
230
|
unvisited_types << root_type if root_type
|
231
231
|
end
|
232
232
|
unvisited_types.concat(@schema.introspection_system.types.values)
|
233
|
+
|
234
|
+
directives.each do |dir_class|
|
235
|
+
dir_class.arguments.values.each do |arg_defn|
|
236
|
+
arg_t = arg_defn.type.unwrap
|
237
|
+
if get_type(arg_t.graphql_name)
|
238
|
+
unvisited_types << arg_t
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
233
243
|
@schema.orphan_types.each do |orphan_type|
|
234
244
|
if get_type(orphan_type.graphql_name)
|
235
245
|
unvisited_types << orphan_type
|
@@ -27,7 +27,6 @@ module GraphQL
|
|
27
27
|
|
28
28
|
if !valid
|
29
29
|
error_message ||= "Default value for $#{node.name} doesn't match type #{type.to_type_signature}"
|
30
|
-
VariableDefaultValuesAreCorrectlyTypedError
|
31
30
|
add_error(GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTypedError.new(
|
32
31
|
error_message,
|
33
32
|
nodes: node,
|
@@ -88,6 +88,10 @@ module GraphQL
|
|
88
88
|
def execute(subscription_id, event, object)
|
89
89
|
# Lookup the saved data for this subscription
|
90
90
|
query_data = read_subscription(subscription_id)
|
91
|
+
if query_data.nil?
|
92
|
+
# Jump down to the `delete_subscription` call
|
93
|
+
raise GraphQL::Schema::Subscription::UnsubscribedError
|
94
|
+
end
|
91
95
|
# Fetch the required keys from the saved data
|
92
96
|
query_string = query_data.fetch(:query_string)
|
93
97
|
variables = query_data.fetch(:variables)
|
@@ -95,14 +99,12 @@ module GraphQL
|
|
95
99
|
operation_name = query_data.fetch(:operation_name)
|
96
100
|
# Re-evaluate the saved query
|
97
101
|
result = @schema.execute(
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
root_value: object,
|
105
|
-
}
|
102
|
+
query: query_string,
|
103
|
+
context: context,
|
104
|
+
subscription_topic: event.topic,
|
105
|
+
operation_name: operation_name,
|
106
|
+
variables: variables,
|
107
|
+
root_value: object,
|
106
108
|
)
|
107
109
|
deliver(subscription_id, result)
|
108
110
|
rescue GraphQL::Schema::Subscription::NoUpdateError
|
@@ -226,7 +228,10 @@ module GraphQL
|
|
226
228
|
# match query arguments.
|
227
229
|
arg_owner.arguments.each do |name, arg_defn|
|
228
230
|
if arg_defn.default_value? && !normalized_args.key?(arg_defn.name)
|
229
|
-
|
231
|
+
default_value = arg_defn.default_value
|
232
|
+
# We don't have an underlying "object" here, so it can't call methods.
|
233
|
+
# This is broken.
|
234
|
+
normalized_args[arg_defn.name] = arg_defn.prepare_value(nil, default_value, context: GraphQL::Query::NullContext)
|
230
235
|
end
|
231
236
|
end
|
232
237
|
|