graphql 0.19.3 → 0.19.4
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/max_query_complexity.rb +1 -1
- data/lib/graphql/analysis/max_query_depth.rb +1 -1
- data/lib/graphql/boolean_type.rb +2 -2
- data/lib/graphql/define/instance_definable.rb +2 -2
- data/lib/graphql/enum_type.rb +3 -3
- data/lib/graphql/field.rb +6 -6
- data/lib/graphql/float_type.rb +2 -2
- data/lib/graphql/id_type.rb +2 -2
- data/lib/graphql/input_object_type.rb +1 -1
- data/lib/graphql/int_type.rb +2 -2
- data/lib/graphql/internal_representation/rewrite.rb +12 -12
- data/lib/graphql/introspection/arguments_field.rb +1 -1
- data/lib/graphql/introspection/enum_value_type.rb +1 -1
- data/lib/graphql/introspection/enum_values_field.rb +1 -1
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/fields_field.rb +1 -1
- data/lib/graphql/introspection/input_fields_field.rb +1 -1
- data/lib/graphql/introspection/input_value_type.rb +2 -2
- data/lib/graphql/introspection/interfaces_field.rb +1 -1
- data/lib/graphql/introspection/of_type_field.rb +1 -1
- data/lib/graphql/introspection/possible_types_field.rb +1 -1
- data/lib/graphql/introspection/schema_field.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +5 -5
- data/lib/graphql/introspection/type_by_name_field.rb +1 -1
- data/lib/graphql/introspection/type_type.rb +6 -6
- data/lib/graphql/introspection/typename_field.rb +1 -1
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/language/comments.rb +44 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/generation.rb +35 -12
- data/lib/graphql/language/lexer.rb +29 -10
- data/lib/graphql/language/lexer.rl +25 -6
- data/lib/graphql/language/nodes.rb +30 -23
- data/lib/graphql/language/parser.rb +33 -14
- data/lib/graphql/language/parser.y +33 -14
- data/lib/graphql/language/parser_tests.rb +86 -2
- data/lib/graphql/language/token.rb +3 -2
- data/lib/graphql/language/visitor.rb +3 -3
- data/lib/graphql/object_type.rb +1 -1
- data/lib/graphql/query/arguments.rb +23 -2
- data/lib/graphql/query/serial_execution/field_resolution.rb +31 -14
- data/lib/graphql/relay/base_connection.rb +1 -3
- data/lib/graphql/relay/connection_type.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -1
- data/lib/graphql/relay/relation_connection.rb +7 -3
- data/lib/graphql/scalar_type.rb +1 -1
- data/lib/graphql/schema.rb +19 -8
- data/lib/graphql/schema/loader.rb +2 -2
- data/lib/graphql/schema/printer.rb +63 -8
- data/lib/graphql/schema/timeout_middleware.rb +11 -11
- data/lib/graphql/schema/validation.rb +12 -12
- data/lib/graphql/static_validation/arguments_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +3 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +9 -4
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +3 -3
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +6 -6
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/string_type.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- data/spec/graphql/analysis/analyze_query_spec.rb +3 -3
- data/spec/graphql/analysis/query_complexity_spec.rb +7 -7
- data/spec/graphql/introspection/directive_type_spec.rb +2 -2
- data/spec/graphql/introspection/introspection_query_spec.rb +26 -26
- data/spec/graphql/language/generation_spec.rb +137 -53
- data/spec/graphql/language/lexer_spec.rb +22 -0
- data/spec/graphql/language/visitor_spec.rb +6 -6
- data/spec/graphql/query/arguments_spec.rb +45 -1
- data/spec/graphql/query/context_spec.rb +4 -4
- data/spec/graphql/query/executor_spec.rb +1 -1
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -1
- data/spec/graphql/relay/mutation_spec.rb +2 -2
- data/spec/graphql/relay/node_spec.rb +2 -2
- data/spec/graphql/relay/relation_connection_spec.rb +16 -0
- data/spec/graphql/schema/loader_spec.rb +2 -2
- data/spec/graphql/schema/middleware_chain_spec.rb +6 -6
- data/spec/graphql/schema/printer_spec.rb +268 -18
- data/spec/graphql/schema/rescue_middleware_spec.rb +1 -1
- data/spec/graphql/schema/timeout_middleware_spec.rb +2 -2
- data/spec/graphql/schema_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +13 -0
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -1
- data/spec/graphql/static_validation/type_stack_spec.rb +1 -1
- data/spec/support/dairy_app.rb +25 -25
- data/spec/support/dairy_data.rb +2 -0
- data/spec/support/star_wars_data.rb +2 -1
- data/spec/support/star_wars_schema.rb +18 -18
- metadata +19 -2
@@ -54,35 +54,52 @@ module GraphQL
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
57
|
# Get the result of:
|
59
58
|
# - Any middleware on this schema
|
60
59
|
# - The field's resolve method
|
61
60
|
# If the middleware chain returns a GraphQL::ExecutionError, its message
|
62
61
|
# is added to the "errors" key.
|
63
62
|
def get_raw_value
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
middlewares = execution_context.query.schema.middleware
|
64
|
+
field_resolve_step = FieldResolveStep.new(irep_node)
|
65
|
+
resolve_arguments = [parent_type, target, field, arguments, execution_context.query.context]
|
66
|
+
# only run a middleware chain if there are any middleware
|
67
|
+
if middlewares.any?
|
68
|
+
chain = GraphQL::Schema::MiddlewareChain.new(
|
69
|
+
steps: middlewares + [field_resolve_step],
|
70
|
+
arguments: resolve_arguments
|
71
|
+
)
|
72
|
+
chain.call
|
73
|
+
else
|
74
|
+
field_resolve_step.call(*resolve_arguments)
|
75
|
+
end
|
70
76
|
rescue GraphQL::ExecutionError => err
|
71
77
|
err
|
72
78
|
end
|
73
79
|
|
74
80
|
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
+
# A `.call`-able suitable to be the last step in a middleware chain
|
82
|
+
class FieldResolveStep
|
83
|
+
def initialize(irep_node)
|
84
|
+
@irep_node = irep_node
|
85
|
+
end
|
86
|
+
|
87
|
+
# Execute the field's resolve method
|
88
|
+
def call(_parent_type, parent_object, field_definition, field_args, context, _next = nil)
|
89
|
+
# setup
|
90
|
+
context.ast_node = @irep_node.ast_node
|
91
|
+
context.irep_node = @irep_node
|
92
|
+
|
93
|
+
# resolve
|
81
94
|
value = field_definition.resolve(parent_object, field_args, context)
|
95
|
+
|
96
|
+
# teardown
|
82
97
|
context.ast_node = nil
|
83
98
|
context.irep_node = nil
|
99
|
+
|
100
|
+
# return
|
84
101
|
value
|
85
|
-
|
102
|
+
end
|
86
103
|
end
|
87
104
|
end
|
88
105
|
end
|
@@ -74,7 +74,7 @@ module GraphQL
|
|
74
74
|
deprecate(:object, :nodes, 2016, 9)
|
75
75
|
|
76
76
|
# Provide easy access to provided arguments:
|
77
|
-
METHODS_FROM_ARGUMENTS = [:first, :after, :last, :before
|
77
|
+
METHODS_FROM_ARGUMENTS = [:first, :after, :last, :before]
|
78
78
|
|
79
79
|
# @!method first
|
80
80
|
# The value passed as `first:`, if there was one
|
@@ -84,8 +84,6 @@ module GraphQL
|
|
84
84
|
# The value passed as `last:`, if there was one
|
85
85
|
# @!method before
|
86
86
|
# The value passed as `before:`, if there was one
|
87
|
-
# @!method order
|
88
|
-
# The value passed as `order:`, if there was one
|
89
87
|
METHODS_FROM_ARGUMENTS.each do |arg_name|
|
90
88
|
define_method(arg_name) do
|
91
89
|
arguments[arg_name]
|
@@ -6,8 +6,13 @@ module GraphQL
|
|
6
6
|
# - `Sequel::Dataset`
|
7
7
|
class RelationConnection < BaseConnection
|
8
8
|
def cursor_from_node(item)
|
9
|
-
|
10
|
-
|
9
|
+
item_index = paged_nodes_array.index(item)
|
10
|
+
if item_index.nil?
|
11
|
+
raise("Can't generate cursor, item not found in connection: #{item}")
|
12
|
+
else
|
13
|
+
offset = starting_offset + item_index + 1
|
14
|
+
Base64.strict_encode64(offset.to_s)
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
13
18
|
def has_next_page
|
@@ -81,7 +86,6 @@ module GraphQL
|
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
84
|
-
|
85
89
|
if defined?(ActiveRecord::Relation)
|
86
90
|
BaseConnection.register_connection_implementation(ActiveRecord::Relation, RelationConnection)
|
87
91
|
end
|
data/lib/graphql/scalar_type.rb
CHANGED
@@ -44,7 +44,7 @@ module GraphQL
|
|
44
44
|
def validate_non_null_input(value)
|
45
45
|
result = Query::InputValidationResult.new
|
46
46
|
if coerce_non_null_input(value).nil?
|
47
|
-
result.add_problem("Could not coerce value #{JSON.
|
47
|
+
result.add_problem("Could not coerce value #{JSON.generate(value, quirks_mode: true)} to #{name}")
|
48
48
|
end
|
49
49
|
result
|
50
50
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -50,9 +50,9 @@ module GraphQL
|
|
50
50
|
:max_depth, :max_complexity,
|
51
51
|
:orphan_types, :resolve_type,
|
52
52
|
:object_from_id, :id_from_object,
|
53
|
-
query_analyzer: ->
|
54
|
-
middleware: ->
|
55
|
-
rescue_from: ->
|
53
|
+
query_analyzer: ->(schema, analyzer) { schema.query_analyzers << analyzer },
|
54
|
+
middleware: ->(schema, middleware) { schema.middleware << middleware },
|
55
|
+
rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block)}
|
56
56
|
|
57
57
|
lazy_defined_attr_accessor \
|
58
58
|
:query, :mutation, :subscription,
|
@@ -61,7 +61,7 @@ module GraphQL
|
|
61
61
|
:orphan_types,
|
62
62
|
:query_analyzers, :middleware
|
63
63
|
|
64
|
-
DIRECTIVES = [GraphQL::Directive::
|
64
|
+
DIRECTIVES = [GraphQL::Directive::IncludeDirective, GraphQL::Directive::SkipDirective, GraphQL::Directive::DeprecatedDirective]
|
65
65
|
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
|
66
66
|
|
67
67
|
attr_reader :directives, :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
|
@@ -86,8 +86,7 @@ module GraphQL
|
|
86
86
|
@orphan_types = types
|
87
87
|
@directives = DIRECTIVES.reduce({}) { |m, d| m[d.name] = d; m }
|
88
88
|
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
89
|
-
@
|
90
|
-
@middleware = [@rescue_middleware]
|
89
|
+
@middleware = []
|
91
90
|
@query_analyzers = []
|
92
91
|
@resolve_type_proc = nil
|
93
92
|
@object_from_id_proc = nil
|
@@ -100,12 +99,12 @@ module GraphQL
|
|
100
99
|
|
101
100
|
def rescue_from(*args, &block)
|
102
101
|
ensure_defined
|
103
|
-
|
102
|
+
rescue_middleware.rescue_from(*args, &block)
|
104
103
|
end
|
105
104
|
|
106
105
|
def remove_handler(*args, &block)
|
107
106
|
ensure_defined
|
108
|
-
|
107
|
+
rescue_middleware.remove_handler(*args, &block)
|
109
108
|
end
|
110
109
|
|
111
110
|
def define(**kwargs, &block)
|
@@ -258,5 +257,17 @@ module GraphQL
|
|
258
257
|
ensure_defined
|
259
258
|
@id_from_object_proc = new_proc
|
260
259
|
end
|
260
|
+
|
261
|
+
private
|
262
|
+
|
263
|
+
# Lazily create a middleware and add it to the schema
|
264
|
+
# (Don't add it if it's not used)
|
265
|
+
def rescue_middleware
|
266
|
+
@rescue_middleware ||= begin
|
267
|
+
middleware = GraphQL::Schema::RescueMiddleware.new
|
268
|
+
@middleware << middleware
|
269
|
+
middleware
|
270
|
+
end
|
271
|
+
end
|
261
272
|
end
|
262
273
|
end
|
@@ -14,7 +14,7 @@ module GraphQL
|
|
14
14
|
schema = introspection_result.fetch("data").fetch("__schema")
|
15
15
|
|
16
16
|
types = {}
|
17
|
-
type_resolver = ->
|
17
|
+
type_resolver = ->(type) { -> { resolve_type(types, type) } }
|
18
18
|
|
19
19
|
schema.fetch("types").each do |type|
|
20
20
|
next if type.fetch("name").start_with?("__")
|
@@ -31,7 +31,7 @@ module GraphQL
|
|
31
31
|
Schema.define(**kargs)
|
32
32
|
end
|
33
33
|
|
34
|
-
NullResolveType = ->
|
34
|
+
NullResolveType = ->(obj, ctx) {
|
35
35
|
raise(NotImplementedError, "This schema was loaded from string, so it can't resolve types for objects")
|
36
36
|
}
|
37
37
|
|
@@ -18,7 +18,7 @@ module GraphQL
|
|
18
18
|
# Return the GraphQL schema string for the introspection type system
|
19
19
|
def print_introspection_schema
|
20
20
|
query_root = ObjectType.define do
|
21
|
-
name "
|
21
|
+
name "Root"
|
22
22
|
end
|
23
23
|
schema = GraphQL::Schema.define(query: query_root)
|
24
24
|
print_filtered_schema(schema, method(:is_spec_directive), method(:is_introspection_type))
|
@@ -33,11 +33,18 @@ module GraphQL
|
|
33
33
|
types = schema.types.values.select{ |type| type_filter.call(type) }.sort_by(&:name)
|
34
34
|
type_definitions = types.map{ |type| print_type(type) }
|
35
35
|
|
36
|
-
[print_schema_definition(schema)].
|
36
|
+
[print_schema_definition(schema)].compact
|
37
|
+
.concat(directive_definitions)
|
37
38
|
.concat(type_definitions).join("\n\n")
|
38
39
|
end
|
39
40
|
|
40
41
|
def print_schema_definition(schema)
|
42
|
+
if (schema.query.nil? || schema.query.name == 'Query') &&
|
43
|
+
(schema.mutation.nil? || schema.mutation.name == 'Mutation') &&
|
44
|
+
(schema.subscription.nil? || schema.subscription.name == 'Subscription')
|
45
|
+
return
|
46
|
+
end
|
47
|
+
|
41
48
|
operations = [:query, :mutation, :subscription].map do |operation_type|
|
42
49
|
object_type = schema.public_send(operation_type)
|
43
50
|
" #{operation_type}: #{object_type.name}\n" if object_type
|
@@ -84,10 +91,32 @@ module GraphQL
|
|
84
91
|
end
|
85
92
|
end
|
86
93
|
|
94
|
+
module DescriptionPrinter
|
95
|
+
def print_description(definition, indentation='', first_in_block=true)
|
96
|
+
return '' unless definition.description
|
97
|
+
|
98
|
+
description = indentation != '' && !first_in_block ? "\n" : ""
|
99
|
+
description << GraphQL::Language::Comments.commentize(definition.description, indent: indentation)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
87
103
|
module ArgsPrinter
|
88
|
-
|
104
|
+
include DescriptionPrinter
|
105
|
+
def print_args(field, indentation = '')
|
89
106
|
return if field.arguments.empty?
|
90
|
-
|
107
|
+
|
108
|
+
field_arguments = field.arguments.values
|
109
|
+
|
110
|
+
if field_arguments.all?{ |arg| !arg.description }
|
111
|
+
return "(#{field_arguments.map{ |arg| print_input_value(arg) }.join(", ")})"
|
112
|
+
end
|
113
|
+
|
114
|
+
out = "(\n"
|
115
|
+
out << field_arguments.map.with_index{ |arg, i|
|
116
|
+
"#{print_description(arg, " #{indentation}", i == 0)} #{indentation}"\
|
117
|
+
"#{print_input_value(arg)}"
|
118
|
+
}.join("\n")
|
119
|
+
out << "\n)"
|
91
120
|
end
|
92
121
|
|
93
122
|
def print_input_value(arg)
|
@@ -131,64 +160,90 @@ module GraphQL
|
|
131
160
|
module FieldPrinter
|
132
161
|
include DeprecatedPrinter
|
133
162
|
include ArgsPrinter
|
163
|
+
include DescriptionPrinter
|
134
164
|
def print_fields(type)
|
135
|
-
type.all_fields.map{ |field|
|
136
|
-
"
|
165
|
+
type.all_fields.map.with_index{ |field, i|
|
166
|
+
"#{print_description(field, ' ', i == 0)}"\
|
167
|
+
" #{field.name}#{print_args(field, ' ')}: #{field.type}#{print_deprecated(field)}"
|
137
168
|
}.join("\n")
|
138
169
|
end
|
139
170
|
end
|
140
171
|
|
141
172
|
class DirectivePrinter
|
142
173
|
extend ArgsPrinter
|
174
|
+
extend DescriptionPrinter
|
143
175
|
def self.print(directive)
|
176
|
+
"#{print_description(directive)}"\
|
144
177
|
"directive @#{directive.name}#{print_args(directive)} "\
|
145
178
|
"on #{directive.locations.join(' | ')}"
|
146
179
|
end
|
147
180
|
end
|
148
181
|
|
149
182
|
class ScalarPrinter
|
183
|
+
extend DescriptionPrinter
|
150
184
|
def self.print(type)
|
185
|
+
"#{print_description(type)}"\
|
151
186
|
"scalar #{type.name}"
|
152
187
|
end
|
153
188
|
end
|
154
189
|
|
155
190
|
class ObjectPrinter
|
156
191
|
extend FieldPrinter
|
192
|
+
extend DescriptionPrinter
|
157
193
|
def self.print(type)
|
158
194
|
if type.interfaces.any?
|
159
195
|
implementations = " implements #{type.interfaces.map(&:to_s).join(", ")}"
|
160
196
|
else
|
161
197
|
implementations = nil
|
162
198
|
end
|
163
|
-
|
199
|
+
|
200
|
+
"#{print_description(type)}"\
|
201
|
+
"type #{type.name}#{implementations} {\n"\
|
202
|
+
"#{print_fields(type)}\n"\
|
203
|
+
"}"
|
164
204
|
end
|
165
205
|
end
|
166
206
|
|
167
207
|
class InterfacePrinter
|
168
208
|
extend FieldPrinter
|
209
|
+
extend DescriptionPrinter
|
169
210
|
def self.print(type)
|
211
|
+
"#{print_description(type)}"\
|
170
212
|
"interface #{type.name} {\n#{print_fields(type)}\n}"
|
171
213
|
end
|
172
214
|
end
|
173
215
|
|
174
216
|
class UnionPrinter
|
217
|
+
extend DescriptionPrinter
|
175
218
|
def self.print(type)
|
219
|
+
"#{print_description(type)}"\
|
176
220
|
"union #{type.name} = #{type.possible_types.map(&:to_s).join(" | ")}"
|
177
221
|
end
|
178
222
|
end
|
179
223
|
|
180
224
|
class EnumPrinter
|
181
225
|
extend DeprecatedPrinter
|
226
|
+
extend DescriptionPrinter
|
182
227
|
def self.print(type)
|
183
228
|
values = type.values.values.map{ |v| " #{v.name}#{print_deprecated(v)}" }.join("\n")
|
229
|
+
values = type.values.values.map.with_index { |v, i|
|
230
|
+
"#{print_description(v, ' ', i == 0)}"\
|
231
|
+
" #{v.name}#{print_deprecated(v)}"
|
232
|
+
}.join("\n")
|
233
|
+
"#{print_description(type)}"\
|
184
234
|
"enum #{type.name} {\n#{values}\n}"
|
185
235
|
end
|
186
236
|
end
|
187
237
|
|
188
238
|
class InputObjectPrinter
|
189
239
|
extend FieldPrinter
|
240
|
+
extend DescriptionPrinter
|
190
241
|
def self.print(type)
|
191
|
-
fields = type.input_fields.values.map{ |field|
|
242
|
+
fields = type.input_fields.values.map.with_index{ |field, i|
|
243
|
+
"#{print_description(field, " ", i == 0)}"\
|
244
|
+
" #{print_input_value(field)}"
|
245
|
+
}.join("\n")
|
246
|
+
"#{print_description(type)}"\
|
192
247
|
"input #{type.name} {\n#{fields}\n}"
|
193
248
|
end
|
194
249
|
end
|
@@ -50,18 +50,18 @@ module GraphQL
|
|
50
50
|
end
|
51
51
|
err
|
52
52
|
end
|
53
|
-
end
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
54
|
+
# This error is raised when a query exceeds `max_seconds`.
|
55
|
+
# Since it's a child of {GraphQL::ExecutionError},
|
56
|
+
# its message will be added to the response's `errors` key.
|
57
|
+
#
|
58
|
+
# To raise an error that will stop query resolution, use a custom block
|
59
|
+
# to take this error and raise a new one which _doesn't_ descend from {GraphQL::ExecutionError},
|
60
|
+
# such as `RuntimeError`.
|
61
|
+
class TimeoutError < GraphQL::ExecutionError
|
62
|
+
def initialize(parent_type, field_defn)
|
63
|
+
super("Timeout on #{parent_type.name}.#{field_defn.name}")
|
64
|
+
end
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
@@ -24,7 +24,7 @@ module GraphQL
|
|
24
24
|
# @return [Proc] A proc which will validate the input by calling `property_name` and asserting it is an instance of one of `allowed_classes`
|
25
25
|
def self.assert_property(property_name, *allowed_classes)
|
26
26
|
allowed_classes_message = allowed_classes.map(&:name).join(" or ")
|
27
|
-
->
|
27
|
+
->(obj) {
|
28
28
|
property_value = obj.public_send(property_name)
|
29
29
|
is_valid_value = allowed_classes.any? { |allowed_class| property_value.is_a?(allowed_class) }
|
30
30
|
is_valid_value ? nil : "#{property_name} must return #{allowed_classes_message}, not #{property_value.class.name} (#{property_value.inspect})"
|
@@ -36,7 +36,7 @@ module GraphQL
|
|
36
36
|
# @param to_class [Class] The class for values in the return value
|
37
37
|
# @return [Proc] A proc to validate that validates the input by calling `property_name` and asserting that the return value is a Hash of `{from_class => to_class}` pairs
|
38
38
|
def self.assert_property_mapping(property_name, from_class, to_class)
|
39
|
-
->
|
39
|
+
->(obj) {
|
40
40
|
property_value = obj.public_send(property_name)
|
41
41
|
error_message = nil
|
42
42
|
if !property_value.is_a?(Hash)
|
@@ -56,7 +56,7 @@ module GraphQL
|
|
56
56
|
# @param list_member_class [Class] The class which each member of the returned array should be an instance of
|
57
57
|
# @return [Proc] A proc to validate the input by calling `property_name` and asserting that the return is an Array of `list_member_class` instances
|
58
58
|
def self.assert_property_list_of(property_name, list_member_class)
|
59
|
-
->
|
59
|
+
->(obj) {
|
60
60
|
property_value = obj.public_send(property_name)
|
61
61
|
if !property_value.is_a?(Array)
|
62
62
|
"#{property_name} must be an Array of #{list_member_class.name}, not a #{property_value.class.name} (#{property_value.inspect})"
|
@@ -72,7 +72,7 @@ module GraphQL
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def self.assert_named_items_are_valid(item_name, get_items_proc)
|
75
|
-
->
|
75
|
+
->(type) {
|
76
76
|
items = get_items_proc.call(type)
|
77
77
|
error_message = nil
|
78
78
|
items.each do |item|
|
@@ -87,18 +87,18 @@ module GraphQL
|
|
87
87
|
end
|
88
88
|
|
89
89
|
|
90
|
-
FIELDS_ARE_VALID = Rules.assert_named_items_are_valid("field", ->
|
90
|
+
FIELDS_ARE_VALID = Rules.assert_named_items_are_valid("field", ->(type) { type.all_fields })
|
91
91
|
|
92
|
-
HAS_ONE_OR_MORE_POSSIBLE_TYPES = ->
|
92
|
+
HAS_ONE_OR_MORE_POSSIBLE_TYPES = ->(type) {
|
93
93
|
type.possible_types.length >= 1 ? nil : "must have at least one possible type"
|
94
94
|
}
|
95
95
|
|
96
96
|
NAME_IS_STRING = Rules.assert_property(:name, String)
|
97
97
|
DESCRIPTION_IS_STRING_OR_NIL = Rules.assert_property(:description, String, NilClass)
|
98
98
|
ARGUMENTS_ARE_STRING_TO_ARGUMENT = Rules.assert_property_mapping(:arguments, String, GraphQL::Argument)
|
99
|
-
ARGUMENTS_ARE_VALID = Rules.assert_named_items_are_valid("argument", ->
|
99
|
+
ARGUMENTS_ARE_VALID = Rules.assert_named_items_are_valid("argument", ->(type) { type.arguments.values })
|
100
100
|
|
101
|
-
DEFAULT_VALUE_IS_VALID_FOR_TYPE = ->
|
101
|
+
DEFAULT_VALUE_IS_VALID_FOR_TYPE = ->(type) {
|
102
102
|
if !type.default_value.nil?
|
103
103
|
coerced_value = begin
|
104
104
|
type.type.coerce_result(type.default_value)
|
@@ -114,7 +114,7 @@ module GraphQL
|
|
114
114
|
end
|
115
115
|
}
|
116
116
|
|
117
|
-
TYPE_IS_VALID_INPUT_TYPE = ->
|
117
|
+
TYPE_IS_VALID_INPUT_TYPE = ->(type) {
|
118
118
|
outer_type = type.type
|
119
119
|
inner_type = outer_type.is_a?(GraphQL::BaseType) ? outer_type.unwrap : nil
|
120
120
|
|
@@ -126,7 +126,7 @@ module GraphQL
|
|
126
126
|
end
|
127
127
|
}
|
128
128
|
|
129
|
-
SCHEMA_CAN_RESOLVE_TYPES = ->
|
129
|
+
SCHEMA_CAN_RESOLVE_TYPES = ->(schema) {
|
130
130
|
if schema.types.values.any? { |type| type.kind.resolves? } && schema.resolve_type_proc.nil?
|
131
131
|
"schema contains Interfaces or Unions, so you must define a `resolve_type (obj, ctx) -> { ... }` function"
|
132
132
|
else
|
@@ -134,7 +134,7 @@ module GraphQL
|
|
134
134
|
end
|
135
135
|
}
|
136
136
|
|
137
|
-
SCHEMA_CAN_FETCH_IDS = ->
|
137
|
+
SCHEMA_CAN_FETCH_IDS = ->(schema) {
|
138
138
|
has_node_field = schema.query && schema.query.all_fields.any? { |f| f.metadata[:relay_node_field] }
|
139
139
|
if has_node_field && schema.object_from_id_proc.nil?
|
140
140
|
"schema contains `node(id:...)` field, so you must define a `object_from_id (id, ctx) -> { ... }` function"
|
@@ -143,7 +143,7 @@ module GraphQL
|
|
143
143
|
end
|
144
144
|
}
|
145
145
|
|
146
|
-
SCHEMA_CAN_GENERATE_IDS = ->
|
146
|
+
SCHEMA_CAN_GENERATE_IDS = ->(schema) {
|
147
147
|
has_id_field = schema.types.values.any? { |t| t.kind.fields? && t.all_fields.any? { |f| f.resolve_proc.is_a?(GraphQL::Relay::GlobalIdResolve) } }
|
148
148
|
if has_id_field && schema.id_from_object_proc.nil?
|
149
149
|
"schema contains `global_id_field`, so you must define a `id_from_object (obj, type, ctx) -> { ... }` function"
|