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
@@ -169,7 +169,15 @@ rule
|
|
169
169
|
object_value_field:
|
170
170
|
name COLON input_value { return make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
|
171
171
|
|
172
|
-
enum_value:
|
172
|
+
enum_value: enum_name { return make_node(:Enum, name: val[0], position_source: val[0])}
|
173
|
+
|
174
|
+
enum_name: /* any identifier, but not "true", "false" or "null" */
|
175
|
+
IDENTIFIER
|
176
|
+
| FRAGMENT
|
177
|
+
| ON
|
178
|
+
| QUERY
|
179
|
+
| MUTATION
|
180
|
+
| SUBSCRIPTION
|
173
181
|
|
174
182
|
directives_list_opt:
|
175
183
|
/* none */ { return [] }
|
data/lib/graphql/object_type.rb
CHANGED
@@ -22,10 +22,9 @@ module GraphQL
|
|
22
22
|
#
|
23
23
|
class ObjectType < GraphQL::BaseType
|
24
24
|
accepts_definitions :interfaces, field: GraphQL::Define::AssignObjectField
|
25
|
-
attr_accessor :name, :description
|
26
25
|
|
27
26
|
# @return [Hash<String => GraphQL::Field>] Map String fieldnames to their {GraphQL::Field} implementations
|
28
|
-
|
27
|
+
lazy_defined_attr_accessor :fields
|
29
28
|
|
30
29
|
def initialize
|
31
30
|
@fields = {}
|
@@ -40,6 +39,7 @@ module GraphQL
|
|
40
39
|
|
41
40
|
def interfaces
|
42
41
|
@clean_interfaces ||= begin
|
42
|
+
ensure_defined
|
43
43
|
@dirty_interfaces.map { |i_type| GraphQL::BaseType.resolve_related_type(i_type) }
|
44
44
|
rescue
|
45
45
|
@dirty_interfaces
|
data/lib/graphql/query.rb
CHANGED
@@ -51,7 +51,7 @@ module GraphQL
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
@arguments_cache = {}
|
54
|
+
@arguments_cache = Hash.new { |h, k| h[k] = {} }
|
55
55
|
end
|
56
56
|
|
57
57
|
# Get the result for this query, executing it once
|
@@ -103,11 +103,11 @@ module GraphQL
|
|
103
103
|
|
104
104
|
# Node-level cache for calculating arguments. Used during execution and query analysis.
|
105
105
|
# @return [GraphQL::Query::Arguments] Arguments for this node, merging default values, literal values and query variables
|
106
|
-
def arguments_for(irep_node)
|
107
|
-
@arguments_cache[irep_node] ||= begin
|
106
|
+
def arguments_for(irep_node, definition)
|
107
|
+
@arguments_cache[irep_node][definition] ||= begin
|
108
108
|
GraphQL::Query::LiteralInput.from_arguments(
|
109
109
|
irep_node.ast_node.arguments,
|
110
|
-
|
110
|
+
definition.arguments,
|
111
111
|
self.variables
|
112
112
|
)
|
113
113
|
end
|
@@ -3,8 +3,8 @@ module GraphQL
|
|
3
3
|
module DirectiveResolution
|
4
4
|
def self.include_node?(irep_node, query)
|
5
5
|
irep_node.directives.each do |directive_node|
|
6
|
-
directive_defn = directive_node.
|
7
|
-
args = query.arguments_for(directive_node)
|
6
|
+
directive_defn = directive_node.definitions.first
|
7
|
+
args = query.arguments_for(directive_node, directive_defn)
|
8
8
|
if !directive_defn.include?(args)
|
9
9
|
return false
|
10
10
|
end
|
@@ -18,8 +18,9 @@ module GraphQL
|
|
18
18
|
@query.fragments[name]
|
19
19
|
end
|
20
20
|
|
21
|
-
def get_field(type,
|
22
|
-
|
21
|
+
def get_field(type, irep_node)
|
22
|
+
# fall back for dynamic fields (eg __typename)
|
23
|
+
irep_node.definitions[type] || @schema.get_field(type, irep_node.definition_name) || raise("No field found on #{type.name} for '#{irep_node.definition_name}' (#{irep_node.ast_node.name})")
|
23
24
|
end
|
24
25
|
|
25
26
|
def add_error(err)
|
@@ -9,11 +9,8 @@ module GraphQL
|
|
9
9
|
@parent_type = parent_type
|
10
10
|
@target = target
|
11
11
|
@execution_context = execution_context
|
12
|
-
@field = execution_context.get_field(parent_type, irep_node
|
13
|
-
|
14
|
-
raise("No field found on #{parent_type.name} '#{parent_type}' for '#{ast_node.name}'")
|
15
|
-
end
|
16
|
-
@arguments = execution_context.query.arguments_for(irep_node)
|
12
|
+
@field = execution_context.get_field(parent_type, irep_node)
|
13
|
+
@arguments = execution_context.query.arguments_for(irep_node, @field)
|
17
14
|
end
|
18
15
|
|
19
16
|
def result
|
@@ -32,7 +32,7 @@ module GraphQL
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def applies_to_type?(irep_node, type, target)
|
35
|
-
irep_node.
|
35
|
+
irep_node.definitions.any? { |child_type, field_defn|
|
36
36
|
GraphQL::Query::TypeResolver.new(target, child_type, type, execution_context.query.context).type
|
37
37
|
}
|
38
38
|
end
|
@@ -57,7 +57,7 @@ module GraphQL
|
|
57
57
|
resolved_type = field_type.resolve_type(value, execution_context)
|
58
58
|
|
59
59
|
unless resolved_type.is_a?(GraphQL::ObjectType)
|
60
|
-
raise GraphQL::ObjectType::UnresolvedTypeError.new(irep_node.
|
60
|
+
raise GraphQL::ObjectType::UnresolvedTypeError.new(irep_node.definition_name, field_type, parent_type)
|
61
61
|
end
|
62
62
|
|
63
63
|
strategy_class = get_strategy_for_kind(resolved_type.kind)
|
@@ -82,7 +82,7 @@ module GraphQL
|
|
82
82
|
# Get the "wrapped" type and resolve the value according to that type
|
83
83
|
def result
|
84
84
|
if value.nil? || value.is_a?(GraphQL::ExecutionError)
|
85
|
-
raise GraphQL::InvalidNullError.new(irep_node.
|
85
|
+
raise GraphQL::InvalidNullError.new(irep_node.definition_name, value)
|
86
86
|
else
|
87
87
|
wrapped_type = field_type.of_type
|
88
88
|
strategy_class = get_strategy_for_kind(wrapped_type.kind)
|
data/lib/graphql/scalar_type.rb
CHANGED
@@ -27,6 +27,7 @@ module GraphQL
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def coerce_non_null_input(value)
|
30
|
+
ensure_defined
|
30
31
|
@coerce_input_proc.call(value)
|
31
32
|
end
|
32
33
|
|
@@ -37,6 +38,7 @@ module GraphQL
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def coerce_result(value)
|
41
|
+
ensure_defined
|
40
42
|
@coerce_result_proc.call(value)
|
41
43
|
end
|
42
44
|
|
@@ -33,6 +33,7 @@ module GraphQL
|
|
33
33
|
|
34
34
|
def call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware)
|
35
35
|
timeout_at = query_context[@context_key] ||= Time.now + @max_seconds
|
36
|
+
|
36
37
|
if timeout_at < Time.now
|
37
38
|
on_timeout(parent_type, parent_object, field_definition, field_args, query_context)
|
38
39
|
else
|
data/lib/graphql/string_type.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
GraphQL::STRING_TYPE = GraphQL::ScalarType.define do
|
2
2
|
name "String"
|
3
|
+
description "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text."
|
4
|
+
|
3
5
|
coerce_result -> (value) { value.to_s }
|
4
6
|
coerce_input -> (value) { value.is_a?(String) ? value : nil }
|
5
7
|
end
|
data/lib/graphql/union_type.rb
CHANGED
@@ -11,7 +11,6 @@ module GraphQL
|
|
11
11
|
#
|
12
12
|
class UnionType < GraphQL::BaseType
|
13
13
|
include GraphQL::BaseType::HasPossibleTypes
|
14
|
-
attr_accessor :name, :description
|
15
14
|
accepts_definitions :possible_types, :resolve_type
|
16
15
|
|
17
16
|
def kind
|
@@ -29,6 +28,7 @@ module GraphQL
|
|
29
28
|
|
30
29
|
def possible_types
|
31
30
|
@clean_possible_types ||= begin
|
31
|
+
ensure_defined
|
32
32
|
@dirty_possible_types.map { |type| GraphQL::BaseType.resolve_related_type(type) }
|
33
33
|
rescue
|
34
34
|
@dirty_possible_types
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -127,9 +127,7 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
|
|
127
127
|
- Problem: how does a field know which schema to look up the name from?
|
128
128
|
- Problem: how can we load types in Rails without accessing the constant?
|
129
129
|
- Maybe support by third-party library? `type("Post!")` could implement "type_missing", keeps `graphql-ruby` very simple
|
130
|
-
- If we eval'd `define { ... }` blocks _lazily_, would that work around all circular dependency issues?
|
131
|
-
- `QueryComplexity` improvements:
|
132
|
-
- Better detection of union / interface possibilities? Right now they're summed
|
133
130
|
- Type check improvements:
|
134
131
|
- Use catch-all type/field/argument definitions instead of terminating traversal
|
135
132
|
- Reduce ad-hoc traversals?
|
133
|
+
- Merge `graphql-relay-ruby` into this Repo so that they can stay in sync?
|
@@ -191,28 +191,47 @@ describe GraphQL::Analysis::QueryComplexity do
|
|
191
191
|
describe "custom complexities" do
|
192
192
|
let(:query) { GraphQL::Query.new(complexity_schema, query_string) }
|
193
193
|
let(:complexity_schema) {
|
194
|
-
|
195
|
-
name "
|
194
|
+
complexity_interface = GraphQL::InterfaceType.define do
|
195
|
+
name "ComplexityInterface"
|
196
|
+
field :value, types.Int
|
197
|
+
end
|
198
|
+
|
199
|
+
single_complexity_type = GraphQL::ObjectType.define do
|
200
|
+
name "SingleComplexity"
|
196
201
|
field :value, types.Int, complexity: 0.1 do
|
197
202
|
resolve -> (obj, args, ctx) { obj }
|
198
203
|
end
|
199
|
-
field :complexity,
|
204
|
+
field :complexity, single_complexity_type do
|
200
205
|
argument :value, types.Int
|
201
206
|
complexity -> (ctx, args, child_complexity) { args[:value] + child_complexity }
|
202
207
|
resolve -> (obj, args, ctx) { args[:value] }
|
203
208
|
end
|
209
|
+
interfaces [complexity_interface]
|
210
|
+
end
|
211
|
+
|
212
|
+
double_complexity_type = GraphQL::ObjectType.define do
|
213
|
+
name "DoubleComplexity"
|
214
|
+
field :value, types.Int, complexity: 4 do
|
215
|
+
resolve -> (obj, args, ctx) { obj }
|
216
|
+
end
|
217
|
+
interfaces [complexity_interface]
|
204
218
|
end
|
205
219
|
|
206
220
|
query_type = GraphQL::ObjectType.define do
|
207
221
|
name "Query"
|
208
|
-
field :complexity,
|
222
|
+
field :complexity, single_complexity_type do
|
209
223
|
argument :value, types.Int
|
210
224
|
complexity -> (ctx, args, child_complexity) { args[:value] + child_complexity }
|
211
225
|
resolve -> (obj, args, ctx) { args[:value] }
|
212
226
|
end
|
227
|
+
|
228
|
+
field :innerComplexity, complexity_interface do
|
229
|
+
argument :value, types.Int
|
230
|
+
resolve -> (obj, args, ctx) { args[:value] }
|
231
|
+
end
|
213
232
|
end
|
214
233
|
|
215
|
-
GraphQL::Schema.new(query: query_type)
|
234
|
+
GraphQL::Schema.new(query: query_type, types: [double_complexity_type])
|
216
235
|
}
|
217
236
|
let(:query_string) {%|
|
218
237
|
{
|
@@ -231,5 +250,22 @@ describe GraphQL::Analysis::QueryComplexity do
|
|
231
250
|
# 10 from `complexity`, `0.3` from `value`
|
232
251
|
assert_equal complexities, [query, 10.3]
|
233
252
|
end
|
253
|
+
|
254
|
+
describe "same field on multiple types" do
|
255
|
+
let(:query_string) {%|
|
256
|
+
{
|
257
|
+
innerComplexity(value: 2) {
|
258
|
+
... on SingleComplexity { value }
|
259
|
+
... on DoubleComplexity { value }
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|}
|
263
|
+
|
264
|
+
it "picks them max for those fields" do
|
265
|
+
reduce_result
|
266
|
+
# 1 for innerComplexity + 4 for DoubleComplexity.value
|
267
|
+
assert_equal complexities, [query, 5]
|
268
|
+
end
|
269
|
+
end
|
234
270
|
end
|
235
271
|
end
|
@@ -10,12 +10,12 @@ module Garden
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class Vegetable
|
13
|
-
attr_accessor :name, :start_planting_on, :end_planting_on
|
14
13
|
include GraphQL::Define::InstanceDefinable
|
14
|
+
lazy_defined_attr_accessor :name, :start_planting_on, :end_planting_on
|
15
15
|
accepts_definitions :name, plant_between: DefinePlantBetween
|
16
16
|
|
17
17
|
# definition added later:
|
18
|
-
|
18
|
+
lazy_defined_attr_accessor :height
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
data/spec/graphql/field_spec.rb
CHANGED
@@ -89,4 +89,22 @@ describe GraphQL::Field do
|
|
89
89
|
assert_equal "QueryType is invalid: field :symbol_name name must return String, not Symbol (:symbol_name)", err.message
|
90
90
|
end
|
91
91
|
end
|
92
|
+
|
93
|
+
describe "#hash_key" do
|
94
|
+
let(:source_field) { MilkType.get_field("source") }
|
95
|
+
after { source_field.hash_key = :source }
|
96
|
+
|
97
|
+
it "looks up a value with obj[hash_key]" do
|
98
|
+
resolved_source = source_field.resolve({source: "Abc", "source" => "Xyz"}, nil, nil)
|
99
|
+
assert_equal :source, source_field.hash_key
|
100
|
+
assert_equal "Abc", resolved_source
|
101
|
+
end
|
102
|
+
|
103
|
+
it "can be reassigned" do
|
104
|
+
source_field.hash_key = "source"
|
105
|
+
resolved_source = source_field.resolve({source: "Abc", "source" => "Xyz"}, nil, nil)
|
106
|
+
assert_equal "source", source_field.hash_key
|
107
|
+
assert_equal "Xyz", resolved_source
|
108
|
+
end
|
109
|
+
end
|
92
110
|
end
|
@@ -26,12 +26,12 @@ describe GraphQL::InternalRepresentation::Rewrite do
|
|
26
26
|
assert_equal QueryType, op_node.return_type
|
27
27
|
first_field = op_node.children.values.first
|
28
28
|
assert_equal 3, first_field.children.length
|
29
|
-
assert_equal [QueryType], first_field.
|
29
|
+
assert_equal [QueryType], first_field.definitions.keys
|
30
30
|
assert_equal CheeseType, first_field.return_type
|
31
31
|
|
32
32
|
second_field = op_node.children.values.last
|
33
33
|
assert_equal 1, second_field.children.length
|
34
|
-
assert_equal [QueryType], second_field.
|
34
|
+
assert_equal [QueryType], second_field.definitions.keys
|
35
35
|
assert_equal CheeseType, second_field.return_type
|
36
36
|
end
|
37
37
|
end
|
@@ -48,7 +48,8 @@ describe GraphQL::InternalRepresentation::Rewrite do
|
|
48
48
|
it "gets dynamic field definitions" do
|
49
49
|
cheese_field = rewrite_result[nil].children["cheese"]
|
50
50
|
typename_field = cheese_field.children["typename"]
|
51
|
-
assert_equal "__typename", typename_field.
|
51
|
+
assert_equal "__typename", typename_field.definitions.values.first.name
|
52
|
+
assert_equal "__typename", typename_field.definition_name
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
@@ -112,9 +113,9 @@ describe GraphQL::InternalRepresentation::Rewrite do
|
|
112
113
|
similar_sheep_field = similar_cow_field.children["similarCheese"]
|
113
114
|
assert_equal ["flavor", "source"], similar_sheep_field.children.keys
|
114
115
|
|
115
|
-
assert_equal
|
116
|
-
assert_equal
|
117
|
-
assert_equal
|
116
|
+
assert_equal [EdibleInterface], cheese_field.children["origin"].definitions.keys
|
117
|
+
assert_equal [CheeseType, EdibleInterface], cheese_field.children["fatContent"].definitions.keys
|
118
|
+
assert_equal [CheeseType], cheese_field.children["flavor"].definitions.keys
|
118
119
|
end
|
119
120
|
end
|
120
121
|
end
|
@@ -190,6 +190,7 @@ describe GraphQL::Language::Parser do
|
|
190
190
|
array: [7, 8, 9]
|
191
191
|
object: {a: [1,2,3], b: {c: "4"}}
|
192
192
|
unicode_bom: "\xef\xbb\xbfquery"
|
193
|
+
keywordEnum: on
|
193
194
|
)
|
194
195
|
}
|
195
196
|
|}
|
@@ -234,6 +235,10 @@ describe GraphQL::Language::Parser do
|
|
234
235
|
obj = inputs[7].value
|
235
236
|
assert_equal %|\xef\xbb\xbfquery|, inputs[7].value
|
236
237
|
end
|
238
|
+
|
239
|
+
it "parses enum 'on''" do
|
240
|
+
assert_equal "on", inputs[8].value.name
|
241
|
+
end
|
237
242
|
end
|
238
243
|
end
|
239
244
|
|
@@ -39,7 +39,8 @@ describe GraphQL::Query::SerialExecution::ExecutionContext do
|
|
39
39
|
|
40
40
|
describe "get_field" do
|
41
41
|
it "returns the respective field from the schema" do
|
42
|
-
|
42
|
+
irep_node = OpenStruct.new(definition_name: "cheese", definitions: {DairyType => DairyType.fields["cheese"]})
|
43
|
+
field = execution_context.get_field(DairyType, irep_node)
|
43
44
|
assert_equal("cheese", field.name)
|
44
45
|
end
|
45
46
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe GraphQL::Schema::TimeoutMiddleware do
|
4
|
-
let(:max_seconds) {
|
5
|
-
let(:timeout_middleware) { GraphQL::Schema::TimeoutMiddleware.new(max_seconds:
|
4
|
+
let(:max_seconds) { 1 }
|
5
|
+
let(:timeout_middleware) { GraphQL::Schema::TimeoutMiddleware.new(max_seconds: max_seconds) }
|
6
6
|
let(:timeout_schema) {
|
7
7
|
|
8
8
|
sleep_for_seconds_resolve = -> (obj, args, ctx) {
|
@@ -45,18 +45,18 @@ describe GraphQL::Schema::TimeoutMiddleware do
|
|
45
45
|
describe "timeout part-way through" do
|
46
46
|
let(:query_string) {%|
|
47
47
|
{
|
48
|
-
a: sleepFor(seconds: 0.
|
49
|
-
b: sleepFor(seconds: 0.
|
50
|
-
c: sleepFor(seconds: 0.
|
51
|
-
d: sleepFor(seconds: 0.
|
52
|
-
e: sleepFor(seconds: 0.
|
48
|
+
a: sleepFor(seconds: 0.4)
|
49
|
+
b: sleepFor(seconds: 0.4)
|
50
|
+
c: sleepFor(seconds: 0.4)
|
51
|
+
d: sleepFor(seconds: 0.4)
|
52
|
+
e: sleepFor(seconds: 0.4)
|
53
53
|
}
|
54
54
|
|}
|
55
55
|
it "returns a partial response and error messages" do
|
56
56
|
expected_data = {
|
57
|
-
"a"=>0.
|
58
|
-
"b"=>0.
|
59
|
-
"c"=>0.
|
57
|
+
"a"=>0.4,
|
58
|
+
"b"=>0.4,
|
59
|
+
"c"=>0.4,
|
60
60
|
"d"=>nil,
|
61
61
|
"e"=>nil,
|
62
62
|
}
|
@@ -79,11 +79,11 @@ describe GraphQL::Schema::TimeoutMiddleware do
|
|
79
79
|
describe "timeout in nested fields" do
|
80
80
|
let(:query_string) {%|
|
81
81
|
{
|
82
|
-
a: nestedSleep(seconds:
|
82
|
+
a: nestedSleep(seconds: 0.3) {
|
83
83
|
seconds
|
84
|
-
b: nestedSleep(seconds: 0.
|
84
|
+
b: nestedSleep(seconds: 0.3) {
|
85
85
|
seconds
|
86
|
-
c: nestedSleep(seconds: 0.
|
86
|
+
c: nestedSleep(seconds: 0.3) {
|
87
87
|
seconds
|
88
88
|
d: nestedSleep(seconds: 0.4) {
|
89
89
|
seconds
|
@@ -96,14 +96,15 @@ describe GraphQL::Schema::TimeoutMiddleware do
|
|
96
96
|
}
|
97
97
|
}
|
98
98
|
|}
|
99
|
+
|
99
100
|
it "returns a partial response and error messages" do
|
100
101
|
expected_data = {
|
101
102
|
"a" => {
|
102
|
-
"seconds" =>
|
103
|
+
"seconds" => 0.3,
|
103
104
|
"b" => {
|
104
|
-
"seconds" => 0.
|
105
|
+
"seconds" => 0.3,
|
105
106
|
"c" => {
|
106
|
-
"seconds"=>0.
|
107
|
+
"seconds"=>0.3,
|
107
108
|
"d" => {
|
108
109
|
"seconds"=>nil,
|
109
110
|
"e"=>nil
|
@@ -131,17 +132,17 @@ describe GraphQL::Schema::TimeoutMiddleware do
|
|
131
132
|
describe "long-running fields" do
|
132
133
|
let(:query_string) {%|
|
133
134
|
{
|
134
|
-
a: sleepFor(seconds: 0.
|
135
|
-
b: sleepFor(seconds: 0.
|
136
|
-
c: sleepFor(seconds:
|
135
|
+
a: sleepFor(seconds: 0.2)
|
136
|
+
b: sleepFor(seconds: 0.2)
|
137
|
+
c: sleepFor(seconds: 0.8)
|
137
138
|
d: sleepFor(seconds: 0.1)
|
138
139
|
}
|
139
140
|
|}
|
140
141
|
it "doesn't terminate long-running field execution" do
|
141
142
|
expected_data = {
|
142
|
-
"a"=>0.
|
143
|
-
"b"=>0.
|
144
|
-
"c"=>
|
143
|
+
"a"=>0.2,
|
144
|
+
"b"=>0.2,
|
145
|
+
"c"=>0.8,
|
145
146
|
"d"=>nil,
|
146
147
|
}
|
147
148
|
|
@@ -159,17 +160,17 @@ describe GraphQL::Schema::TimeoutMiddleware do
|
|
159
160
|
|
160
161
|
describe "with a custom block" do
|
161
162
|
let(:timeout_middleware) {
|
162
|
-
GraphQL::Schema::TimeoutMiddleware.new(max_seconds:
|
163
|
+
GraphQL::Schema::TimeoutMiddleware.new(max_seconds: max_seconds) do |err, query|
|
163
164
|
raise("Query timed out after 2s: #{query.class.name}")
|
164
165
|
end
|
165
166
|
}
|
166
167
|
let(:query_string) {%|
|
167
168
|
{
|
168
|
-
a: sleepFor(seconds: 0.
|
169
|
-
b: sleepFor(seconds: 0.
|
170
|
-
c: sleepFor(seconds: 0.
|
171
|
-
d: sleepFor(seconds: 0.
|
172
|
-
e: sleepFor(seconds: 0.
|
169
|
+
a: sleepFor(seconds: 0.4)
|
170
|
+
b: sleepFor(seconds: 0.4)
|
171
|
+
c: sleepFor(seconds: 0.4)
|
172
|
+
d: sleepFor(seconds: 0.4)
|
173
|
+
e: sleepFor(seconds: 0.4)
|
173
174
|
}
|
174
175
|
|}
|
175
176
|
|