graphql 1.1.0 → 1.2.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/analyze_query.rb +4 -2
- data/lib/graphql/analysis/field_usage.rb +4 -4
- data/lib/graphql/analysis/query_complexity.rb +16 -21
- data/lib/graphql/argument.rb +13 -6
- data/lib/graphql/base_type.rb +2 -1
- data/lib/graphql/compatibility/execution_specification.rb +76 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +16 -2
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -5
- data/lib/graphql/compatibility/schema_parser_specification.rb +6 -0
- data/lib/graphql/define/assign_argument.rb +8 -2
- data/lib/graphql/define/instance_definable.rb +12 -15
- data/lib/graphql/directive.rb +2 -1
- data/lib/graphql/enum_type.rb +5 -7
- data/lib/graphql/field.rb +6 -11
- data/lib/graphql/field/resolve.rb +1 -0
- data/lib/graphql/input_object_type.rb +9 -9
- data/lib/graphql/interface_type.rb +2 -1
- data/lib/graphql/internal_representation.rb +1 -0
- data/lib/graphql/internal_representation/node.rb +31 -9
- data/lib/graphql/internal_representation/rewrite.rb +26 -26
- data/lib/graphql/internal_representation/selections.rb +41 -0
- data/lib/graphql/introspection/input_value_type.rb +6 -2
- data/lib/graphql/language/generation.rb +2 -0
- data/lib/graphql/language/lexer.rl +4 -0
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +525 -509
- data/lib/graphql/language/parser.y +2 -0
- data/lib/graphql/object_type.rb +2 -2
- data/lib/graphql/query.rb +21 -0
- data/lib/graphql/query/context.rb +52 -4
- data/lib/graphql/query/serial_execution.rb +3 -4
- data/lib/graphql/query/serial_execution/field_resolution.rb +35 -36
- data/lib/graphql/query/serial_execution/operation_resolution.rb +9 -15
- data/lib/graphql/query/serial_execution/selection_resolution.rb +14 -11
- data/lib/graphql/query/serial_execution/value_resolution.rb +18 -17
- data/lib/graphql/query/variables.rb +1 -1
- data/lib/graphql/relay/mutation.rb +5 -8
- data/lib/graphql/scalar_type.rb +1 -2
- data/lib/graphql/schema.rb +2 -13
- data/lib/graphql/schema/build_from_definition.rb +28 -13
- data/lib/graphql/schema/loader.rb +4 -1
- data/lib/graphql/schema/printer.rb +10 -3
- data/lib/graphql/schema/timeout_middleware.rb +18 -2
- data/lib/graphql/schema/unique_within_type.rb +6 -3
- data/lib/graphql/static_validation/literal_validator.rb +3 -1
- data/lib/graphql/union_type.rb +1 -2
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -0
- data/spec/graphql/analysis/analyze_query_spec.rb +6 -8
- data/spec/graphql/argument_spec.rb +18 -0
- data/spec/graphql/define/assign_argument_spec.rb +48 -0
- data/spec/graphql/define/instance_definable_spec.rb +4 -2
- data/spec/graphql/execution_error_spec.rb +66 -0
- data/spec/graphql/input_object_type_spec.rb +81 -0
- data/spec/graphql/internal_representation/rewrite_spec.rb +104 -21
- data/spec/graphql/introspection/input_value_type_spec.rb +43 -6
- data/spec/graphql/introspection/schema_type_spec.rb +1 -0
- data/spec/graphql/introspection/type_type_spec.rb +2 -0
- data/spec/graphql/language/generation_spec.rb +3 -2
- data/spec/graphql/query/arguments_spec.rb +17 -4
- data/spec/graphql/query/context_spec.rb +23 -0
- data/spec/graphql/query/variables_spec.rb +15 -1
- data/spec/graphql/relay/mutation_spec.rb +42 -2
- data/spec/graphql/schema/build_from_definition_spec.rb +4 -2
- data/spec/graphql/schema/loader_spec.rb +59 -1
- data/spec/graphql/schema/printer_spec.rb +2 -0
- data/spec/graphql/schema/reduce_types_spec.rb +1 -1
- data/spec/graphql/schema/timeout_middleware_spec.rb +2 -2
- data/spec/graphql/schema/unique_within_type_spec.rb +9 -0
- data/spec/graphql/schema/validation_spec.rb +15 -3
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +122 -0
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +78 -0
- data/spec/support/dairy_app.rb +9 -0
- data/spec/support/minimum_input_object.rb +4 -0
- data/spec/support/star_wars_schema.rb +1 -1
- metadata +5 -5
- data/lib/graphql/query/serial_execution/execution_context.rb +0 -37
- data/spec/graphql/query/serial_execution/execution_context_spec.rb +0 -54
@@ -18,6 +18,7 @@ describe GraphQL::Introspection::TypeType do
|
|
18
18
|
{"name"=>"id", "isDeprecated" => false, "type" => { "kind" => "NON_NULL", "name" => nil, "ofType" => { "name" => "Int"}}},
|
19
19
|
{"name"=>"nullableCheese", "isDeprecated"=>false, "type"=>{ "kind" => "OBJECT", "name" => "Cheese", "ofType"=>nil}},
|
20
20
|
{"name"=>"origin", "isDeprecated" => false, "type" => { "kind" => "NON_NULL", "name" => nil, "ofType" => { "name" => "String"}}},
|
21
|
+
{"name"=>"selfAsEdible", "isDeprecated"=>false, "type"=>{"kind"=>"INTERFACE", "name"=>"Edible", "ofType"=>nil}},
|
21
22
|
{"name"=>"similarCheese", "isDeprecated"=>false, "type"=>{ "kind" => "OBJECT", "name"=>"Cheese", "ofType"=>nil}},
|
22
23
|
{"name"=>"source", "isDeprecated" => false, "type" => { "kind" => "NON_NULL", "name" => nil, "ofType" => { "name" => "DairyAnimal"}}},
|
23
24
|
]}
|
@@ -49,6 +50,7 @@ describe GraphQL::Introspection::TypeType do
|
|
49
50
|
{"type"=>{"kind"=>"LIST","name"=>nil, "ofType"=>{"name"=>"String"}}},
|
50
51
|
{"type"=>{"kind"=>"NON_NULL","name"=>nil, "ofType"=>{"name"=>"ID"}}},
|
51
52
|
{"type"=>{"kind"=>"NON_NULL","name"=>nil, "ofType"=>{"name"=>"String"}}},
|
53
|
+
{"type"=>{"kind"=>"INTERFACE", "name"=>"Edible", "ofType"=>nil}},
|
52
54
|
{"type"=>{"kind"=>"ENUM","name"=>"DairyAnimal", "ofType"=>nil}},
|
53
55
|
]
|
54
56
|
},
|
@@ -31,7 +31,7 @@ describe GraphQL::Language::Generation do
|
|
31
31
|
describe "inputs" do
|
32
32
|
let(:query_string) {%|
|
33
33
|
query {
|
34
|
-
field(int: 3, float: 4.7e-24, bool: false, string: "☀︎🏆\\n escaped \\" unicode ¶ /", enum: ENUM_NAME, array: [7, 8, 9], object: {a: [1, 2, 3], b: {c: "4"}}, unicode_bom: "\xef\xbb\xbfquery")
|
34
|
+
field(null_value: null, null_in_array: [1, null, 3], int: 3, float: 4.7e-24, bool: false, string: "☀︎🏆\\n escaped \\" unicode ¶ /", enum: ENUM_NAME, array: [7, 8, 9], object: {a: [1, 2, 3], b: {c: "4"}}, unicode_bom: "\xef\xbb\xbfquery")
|
35
35
|
}
|
36
36
|
|}
|
37
37
|
|
@@ -102,7 +102,7 @@ describe GraphQL::Language::Generation do
|
|
102
102
|
end
|
103
103
|
|
104
104
|
describe "full featured schema" do
|
105
|
-
# From: https://github.com/graphql/graphql-js/blob/
|
105
|
+
# From: https://github.com/graphql/graphql-js/blob/bc96406ab44453a120da25a0bd6e2b0237119ddf/src/language/__tests__/schema-kitchen-sink.graphql
|
106
106
|
let(:query_string) {<<-schema
|
107
107
|
schema {
|
108
108
|
query: QueryType
|
@@ -119,6 +119,7 @@ describe GraphQL::Language::Generation do
|
|
119
119
|
four(argument: String = "string"): String
|
120
120
|
five(argument: [String] = ["string", "string"]): String
|
121
121
|
six(argument: InputType = {key: "value"}): Type
|
122
|
+
seven(argument: String = null): Type
|
122
123
|
}
|
123
124
|
|
124
125
|
# Scalar description
|
@@ -168,11 +168,9 @@ describe GraphQL::Query::Arguments do
|
|
168
168
|
assert_equal true, test_inputs.key?(:b)
|
169
169
|
|
170
170
|
assert_equal false, test_inputs.key?(:c)
|
171
|
-
|
172
|
-
# but it was nil, which is not allowed in GraphQL
|
173
|
-
assert_equal false, test_inputs.key?(:d)
|
171
|
+
assert_equal true, test_inputs.key?(:d)
|
174
172
|
|
175
|
-
assert_equal({"a" => 1, "b" => 2}, test_inputs.to_h)
|
173
|
+
assert_equal({"a" => 1, "b" => 2, "d" => nil}, test_inputs.to_h)
|
176
174
|
end
|
177
175
|
|
178
176
|
it "works with variable default values" do
|
@@ -188,5 +186,20 @@ describe GraphQL::Query::Arguments do
|
|
188
186
|
assert_equal false, test_defaults.key?(:d)
|
189
187
|
assert_equal({"a" => 1, "b" => 2}, test_defaults.to_h)
|
190
188
|
end
|
189
|
+
|
190
|
+
it "works with variable default values with null" do
|
191
|
+
schema.execute("query ArgTest($arg: TestInput = {d: null}){ argTest(d: $arg) }")
|
192
|
+
|
193
|
+
test_defaults = arg_values.last["d"]
|
194
|
+
|
195
|
+
assert_equal false, test_defaults.key?(:a)
|
196
|
+
# This is present from default val
|
197
|
+
assert_equal true, test_defaults.key?(:b)
|
198
|
+
|
199
|
+
assert_equal false, test_defaults.key?(:c)
|
200
|
+
assert_equal true, test_defaults.key?(:d)
|
201
|
+
|
202
|
+
assert_equal({"d" => nil, "b" => 2}, test_defaults.to_h)
|
203
|
+
end
|
191
204
|
end
|
192
205
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe GraphQL::Query::Context do
|
4
|
+
CTX = []
|
5
|
+
before { CTX.clear }
|
6
|
+
|
4
7
|
let(:query_type) { GraphQL::ObjectType.define {
|
5
8
|
name "Query"
|
6
9
|
field :context, types.String do
|
@@ -16,6 +19,10 @@ describe GraphQL::Query::Context do
|
|
16
19
|
field :queryName, types.String do
|
17
20
|
resolve ->(target, args, ctx) { ctx.query.class.name }
|
18
21
|
end
|
22
|
+
|
23
|
+
field :pushContext, types.Int do
|
24
|
+
resolve ->(t,a,c) { CTX << c; 1 }
|
25
|
+
end
|
19
26
|
}}
|
20
27
|
let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
|
21
28
|
let(:result) { schema.execute(query_string, context: {"some_key" => "some value"})}
|
@@ -81,4 +88,20 @@ describe GraphQL::Query::Context do
|
|
81
88
|
assert_equal("wow!", context[:some_key])
|
82
89
|
end
|
83
90
|
end
|
91
|
+
|
92
|
+
describe "accessing context after the fact" do
|
93
|
+
let(:query_string) { %|
|
94
|
+
{ pushContext }
|
95
|
+
|}
|
96
|
+
|
97
|
+
it "preserves path information" do
|
98
|
+
assert_equal 1, result["data"]["pushContext"]
|
99
|
+
last_ctx = CTX.pop
|
100
|
+
assert_equal ["pushContext"], last_ctx.path
|
101
|
+
err = GraphQL::ExecutionError.new("Test position info")
|
102
|
+
last_ctx.add_error(err)
|
103
|
+
assert_equal ["pushContext"], err.path
|
104
|
+
assert_equal [2, 9], [err.ast_node.line, err.ast_node.col]
|
105
|
+
end
|
106
|
+
end
|
84
107
|
end
|
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe GraphQL::Query::Variables do
|
4
4
|
let(:query_string) {%|
|
5
|
-
query getCheese($animals: [DairyAnimal]) {
|
5
|
+
query getCheese($animals: [DairyAnimal], $int: Int, $intWithDefault: Int = 10) {
|
6
6
|
cheese(id: 1) {
|
7
7
|
similarCheese(source: $animals)
|
8
8
|
}
|
@@ -25,5 +25,19 @@ describe GraphQL::Query::Variables do
|
|
25
25
|
assert_equal ["YAK"], variables["animals"]
|
26
26
|
end
|
27
27
|
end
|
28
|
+
|
29
|
+
describe "coercing null" do
|
30
|
+
let(:provided_variables) {
|
31
|
+
{"int" => nil, "intWithDefault" => nil}
|
32
|
+
}
|
33
|
+
|
34
|
+
it "null variable" do
|
35
|
+
assert_equal nil, variables["int"]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "preserves explicit null when variable has a default value" do
|
39
|
+
assert_equal nil, variables["intWithDefault"]
|
40
|
+
end
|
41
|
+
end
|
28
42
|
end
|
29
43
|
end
|
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe GraphQL::Relay::Mutation do
|
4
4
|
let(:query_string) {%|
|
5
|
-
mutation addBagel($clientMutationId: String) {
|
6
|
-
introduceShip(input: {shipName:
|
5
|
+
mutation addBagel($clientMutationId: String, $shipName: String = "Bagel") {
|
6
|
+
introduceShip(input: {shipName: $shipName, factionId: "1", clientMutationId: $clientMutationId}) {
|
7
7
|
clientMutationId
|
8
8
|
shipEdge {
|
9
9
|
node { name, id }
|
@@ -25,6 +25,24 @@ describe GraphQL::Relay::Mutation do
|
|
25
25
|
STAR_WARS_DATA["Faction"]["1"].ships.delete("9")
|
26
26
|
end
|
27
27
|
|
28
|
+
it "supports null values" do
|
29
|
+
result = star_wars_query(query_string, "clientMutationId" => "1234", "shipName" => nil)
|
30
|
+
|
31
|
+
expected = {"data" => {
|
32
|
+
"introduceShip" => {
|
33
|
+
"clientMutationId" => "1234",
|
34
|
+
"shipEdge" => {
|
35
|
+
"node" => {
|
36
|
+
"name" => nil,
|
37
|
+
"id" => GraphQL::Schema::UniqueWithinType.encode("Ship", "9"),
|
38
|
+
},
|
39
|
+
},
|
40
|
+
"faction" => {"name" => STAR_WARS_DATA["Faction"]["1"].name }
|
41
|
+
}
|
42
|
+
}}
|
43
|
+
assert_equal(expected, result)
|
44
|
+
end
|
45
|
+
|
28
46
|
it "returns the result & clientMutationId" do
|
29
47
|
result = star_wars_query(query_string, "clientMutationId" => "1234")
|
30
48
|
expected = {"data" => {
|
@@ -71,6 +89,11 @@ describe GraphQL::Relay::Mutation do
|
|
71
89
|
custom_type = custom_return_type
|
72
90
|
GraphQL::Relay::Mutation.define do
|
73
91
|
name "CustomReturnTypeTest"
|
92
|
+
|
93
|
+
input_field :nullDefault, types.String, default_value: nil
|
94
|
+
input_field :noDefault, types.String
|
95
|
+
input_field :stringDefault, types.String, default_value: 'String'
|
96
|
+
|
74
97
|
return_type custom_type
|
75
98
|
resolve ->(obj, input, ctx) {
|
76
99
|
OpenStruct.new(name: "Custom Return Type Test")
|
@@ -78,6 +101,8 @@ describe GraphQL::Relay::Mutation do
|
|
78
101
|
end
|
79
102
|
}
|
80
103
|
|
104
|
+
let(:input) { mutation.field.arguments['input'].type.unwrap }
|
105
|
+
|
81
106
|
let(:schema) {
|
82
107
|
mutation_field = mutation.field
|
83
108
|
|
@@ -102,5 +127,20 @@ describe GraphQL::Relay::Mutation do
|
|
102
127
|
it "doesn't get a mutation in the metadata" do
|
103
128
|
assert_equal nil, custom_return_type.mutation
|
104
129
|
end
|
130
|
+
|
131
|
+
it "supports input fields with nil default value" do
|
132
|
+
assert input.arguments['nullDefault'].default_value?
|
133
|
+
assert_equal nil, input.arguments['nullDefault'].default_value
|
134
|
+
end
|
135
|
+
|
136
|
+
it "supports input fields with no default value" do
|
137
|
+
assert !input.arguments['noDefault'].default_value?
|
138
|
+
assert_equal nil, input.arguments['noDefault'].default_value
|
139
|
+
end
|
140
|
+
|
141
|
+
it "supports input fields with non-nil default value" do
|
142
|
+
assert input.arguments['stringDefault'].default_value?
|
143
|
+
assert_equal "String", input.arguments['stringDefault'].default_value
|
144
|
+
end
|
105
145
|
end
|
106
146
|
end
|
@@ -31,7 +31,7 @@ schema {
|
|
31
31
|
query: Hello
|
32
32
|
}
|
33
33
|
|
34
|
-
directive @foo(arg: Int) on FIELD
|
34
|
+
directive @foo(arg: Int, nullDefault: Int = null) on FIELD
|
35
35
|
|
36
36
|
type Hello {
|
37
37
|
str: String
|
@@ -356,6 +356,7 @@ schema {
|
|
356
356
|
|
357
357
|
input Input {
|
358
358
|
int: Int
|
359
|
+
nullDefault: Int = null
|
359
360
|
}
|
360
361
|
|
361
362
|
type Root {
|
@@ -380,6 +381,7 @@ enum Color {
|
|
380
381
|
type Hello {
|
381
382
|
str(int: Int = 2): String
|
382
383
|
hello(color: Color = RED): String
|
384
|
+
nullable(color: Color = null): String
|
383
385
|
}
|
384
386
|
SCHEMA
|
385
387
|
|
@@ -415,7 +417,7 @@ enum Color {
|
|
415
417
|
}
|
416
418
|
|
417
419
|
type Mutation {
|
418
|
-
hello(str: String, int: Int, color: Color = RED): String
|
420
|
+
hello(str: String, int: Int, color: Color = RED, nullDefault: Int = null): String
|
419
421
|
}
|
420
422
|
|
421
423
|
type Query {
|
@@ -37,6 +37,17 @@ describe GraphQL::Schema::Loader do
|
|
37
37
|
input_field :sub, types[sub_input_type]
|
38
38
|
end
|
39
39
|
|
40
|
+
variant_input_type_with_nulls = GraphQL::InputObjectType.define do
|
41
|
+
name "VariedWithNulls"
|
42
|
+
input_field :id, types.ID, default_value: nil
|
43
|
+
input_field :int, types.Int, default_value: nil
|
44
|
+
input_field :bigint, big_int_type, default_value: nil
|
45
|
+
input_field :float, types.Float, default_value: nil
|
46
|
+
input_field :bool, types.Boolean, default_value: nil
|
47
|
+
input_field :enum, choice_type, default_value: nil
|
48
|
+
input_field :sub, types[sub_input_type], default_value: nil
|
49
|
+
end
|
50
|
+
|
40
51
|
comment_type = GraphQL::ObjectType.define do
|
41
52
|
name "Comment"
|
42
53
|
description "A blog comment"
|
@@ -90,6 +101,7 @@ describe GraphQL::Schema::Loader do
|
|
90
101
|
type post_type
|
91
102
|
argument :id, !types.ID
|
92
103
|
argument :varied, variant_input_type, default_value: { id: "123", int: 234, float: 2.3, enum: :foo, sub: [{ string: "str" }] }
|
104
|
+
argument :variedWithNull, variant_input_type_with_nulls, default_value: { id: nil, int: nil, float: nil, enum: nil, sub: nil, bigint: nil, bool: nil }
|
93
105
|
end
|
94
106
|
|
95
107
|
field :content do
|
@@ -205,7 +217,53 @@ describe GraphQL::Schema::Loader do
|
|
205
217
|
field = type.fields['post']
|
206
218
|
arg = field.arguments['varied']
|
207
219
|
|
208
|
-
assert_equal arg.default_value, { 'id' => "123", '
|
220
|
+
assert_equal arg.default_value, { 'id' => "123", 'int' => 234, 'float' => 2.3, 'enum' => "FOO", 'sub' => [{ 'string' => "str" }] }
|
221
|
+
assert !arg.default_value.key?('bool'), 'Omits default value for unspecified arguments'
|
222
|
+
end
|
223
|
+
|
224
|
+
it "does not set default value when there are none on input fields" do
|
225
|
+
type = loaded_schema.types['Varied']
|
226
|
+
|
227
|
+
assert !type.arguments['id'].default_value?
|
228
|
+
assert !type.arguments['int'].default_value?
|
229
|
+
assert type.arguments['bigint'].default_value?
|
230
|
+
assert !type.arguments['float'].default_value?
|
231
|
+
assert !type.arguments['bool'].default_value?
|
232
|
+
assert !type.arguments['enum'].default_value?
|
233
|
+
assert !type.arguments['sub'].default_value?
|
234
|
+
end
|
235
|
+
|
236
|
+
it "sets correct default values `null` on input fields" do
|
237
|
+
type = loaded_schema.types['VariedWithNulls']
|
238
|
+
|
239
|
+
assert type.arguments['id'].default_value?
|
240
|
+
assert type.arguments['id'].default_value.nil?
|
241
|
+
|
242
|
+
assert type.arguments['int'].default_value?
|
243
|
+
assert type.arguments['int'].default_value.nil?
|
244
|
+
|
245
|
+
assert type.arguments['bigint'].default_value?
|
246
|
+
assert type.arguments['bigint'].default_value.nil?
|
247
|
+
|
248
|
+
assert type.arguments['float'].default_value?
|
249
|
+
assert type.arguments['float'].default_value.nil?
|
250
|
+
|
251
|
+
assert type.arguments['bool'].default_value?
|
252
|
+
assert type.arguments['bool'].default_value.nil?
|
253
|
+
|
254
|
+
assert type.arguments['enum'].default_value?
|
255
|
+
assert type.arguments['enum'].default_value.nil?
|
256
|
+
|
257
|
+
assert type.arguments['sub'].default_value?
|
258
|
+
assert type.arguments['sub'].default_value.nil?
|
259
|
+
end
|
260
|
+
|
261
|
+
it "sets correct default values `null` on complex field arguments" do
|
262
|
+
type = loaded_schema.types['Query']
|
263
|
+
field = type.fields['post']
|
264
|
+
arg = field.arguments['variedWithNull']
|
265
|
+
|
266
|
+
assert_equal arg.default_value, { 'id' => nil, 'int' => nil, 'float' => nil, 'enum' => nil, 'sub' => nil, 'bool' => nil, 'bigint' => nil }
|
209
267
|
end
|
210
268
|
end
|
211
269
|
end
|
@@ -85,6 +85,7 @@ describe GraphQL::Schema::Printer do
|
|
85
85
|
type post_type
|
86
86
|
argument :id, !types.ID, 'Post ID'
|
87
87
|
argument :varied, variant_input_type, default_value: { id: "123", int: 234, float: 2.3, enum: :foo, sub: [{ string: "str" }] }
|
88
|
+
argument :variedWithNulls, variant_input_type, default_value: { id: nil, int: nil, float: nil, enum: nil, sub: nil }
|
88
89
|
resolve ->(obj, args, ctx) { Post.find(args["id"]) }
|
89
90
|
end
|
90
91
|
end
|
@@ -444,6 +445,7 @@ type Query {
|
|
444
445
|
# Post ID
|
445
446
|
id: ID!
|
446
447
|
varied: Varied = {id: \"123\", int: 234, float: 2.3, enum: FOO, sub: [{string: \"str\"}]}
|
448
|
+
variedWithNulls: Varied = {id: null, int: null, float: null, enum: null, sub: null}
|
447
449
|
): Post
|
448
450
|
}
|
449
451
|
|
@@ -10,9 +10,9 @@ describe GraphQL::Schema::ReduceTypes do
|
|
10
10
|
"Cheese" => CheeseType,
|
11
11
|
"Float" => GraphQL::FLOAT_TYPE,
|
12
12
|
"String" => GraphQL::STRING_TYPE,
|
13
|
+
"Edible" => EdibleInterface,
|
13
14
|
"DairyAnimal" => DairyAnimalEnum,
|
14
15
|
"Int" => GraphQL::INT_TYPE,
|
15
|
-
"Edible" => EdibleInterface,
|
16
16
|
"AnimalProduct" => AnimalProductInterface,
|
17
17
|
"LocalProduct" => LocalProductInterface,
|
18
18
|
}
|
@@ -166,7 +166,7 @@ describe GraphQL::Schema::TimeoutMiddleware do
|
|
166
166
|
describe "with a custom block" do
|
167
167
|
let(:timeout_middleware) {
|
168
168
|
GraphQL::Schema::TimeoutMiddleware.new(max_seconds: max_seconds) do |err, query|
|
169
|
-
raise("Query timed out after 2s: #{query.
|
169
|
+
raise("Query timed out after 2s: #{query.operations.count} on #{query.context.ast_node.alias}")
|
170
170
|
end
|
171
171
|
}
|
172
172
|
let(:query_string) {%|
|
@@ -181,7 +181,7 @@ describe GraphQL::Schema::TimeoutMiddleware do
|
|
181
181
|
|
182
182
|
it "calls the block" do
|
183
183
|
err = assert_raises(RuntimeError) { result }
|
184
|
-
assert_equal "Query timed out after 2s:
|
184
|
+
assert_equal "Query timed out after 2s: 1 on d", err.message
|
185
185
|
end
|
186
186
|
end
|
187
187
|
end
|
@@ -9,6 +9,15 @@ describe GraphQL::Schema::UniqueWithinType do
|
|
9
9
|
assert_equal("123", id)
|
10
10
|
end
|
11
11
|
|
12
|
+
it "allows you specify default separator" do
|
13
|
+
GraphQL::Schema::UniqueWithinType.default_id_separator = '|'
|
14
|
+
global_id = GraphQL::Schema::UniqueWithinType.encode("Type-With-UUID", "250cda0e-a89d-41cf-99e1-2872d89f1100")
|
15
|
+
type_name, id = GraphQL::Schema::UniqueWithinType.decode(global_id)
|
16
|
+
assert_equal("Type-With-UUID", type_name)
|
17
|
+
assert_equal("250cda0e-a89d-41cf-99e1-2872d89f1100", id)
|
18
|
+
GraphQL::Schema::UniqueWithinType.default_id_separator = '-'
|
19
|
+
end
|
20
|
+
|
12
21
|
it "allows you to specify the separator" do
|
13
22
|
custom_separator = "---"
|
14
23
|
global_id = GraphQL::Schema::UniqueWithinType.encode("Type-With-UUID", "250cda0e-a89d-41cf-99e1-2872d89f1100", separator: custom_separator)
|
@@ -200,7 +200,7 @@ describe GraphQL::Schema::Validation do
|
|
200
200
|
end
|
201
201
|
}
|
202
202
|
|
203
|
-
let(:
|
203
|
+
let(:invalid_default_argument_for_non_null_argument) {
|
204
204
|
GraphQL::Argument.define do
|
205
205
|
name "InvalidDefault"
|
206
206
|
type !GraphQL::INT_TYPE
|
@@ -208,12 +208,24 @@ describe GraphQL::Schema::Validation do
|
|
208
208
|
end
|
209
209
|
}
|
210
210
|
|
211
|
+
let(:null_default_value) {
|
212
|
+
GraphQL::Argument.define do
|
213
|
+
name "NullDefault"
|
214
|
+
type DairyAnimalEnum
|
215
|
+
default_value nil
|
216
|
+
end
|
217
|
+
}
|
218
|
+
|
211
219
|
it "requires the type is a Base type" do
|
212
220
|
assert_error_includes untyped_argument, "must be a valid input type (Scalar or InputObject), not Symbol"
|
213
221
|
end
|
214
222
|
|
215
|
-
it "does not allow default values for non-null
|
216
|
-
assert_error_includes
|
223
|
+
it "does not allow default values for non-null argument" do
|
224
|
+
assert_error_includes invalid_default_argument_for_non_null_argument, 'Variable InvalidDefault of type "Int!" is required and will not use the default value. Perhaps you meant to use type "Int".'
|
225
|
+
end
|
226
|
+
|
227
|
+
it "allows null default value for nullable argument" do
|
228
|
+
assert_equal nil, GraphQL::Schema::Validation.validate(null_default_value)
|
217
229
|
end
|
218
230
|
end
|
219
231
|
end
|
@@ -65,4 +65,126 @@ describe GraphQL::StaticValidation::ArgumentLiteralsAreCompatible do
|
|
65
65
|
}
|
66
66
|
assert_includes(errors, fragment_error)
|
67
67
|
end
|
68
|
+
|
69
|
+
describe "null value" do
|
70
|
+
describe "nullable arg" do
|
71
|
+
let(:schema) {
|
72
|
+
GraphQL::Schema.from_definition(%|
|
73
|
+
type Query {
|
74
|
+
field(arg: Int): Int
|
75
|
+
}
|
76
|
+
|)
|
77
|
+
}
|
78
|
+
let(:query_string) {%|
|
79
|
+
query {
|
80
|
+
field(arg: null)
|
81
|
+
}
|
82
|
+
|}
|
83
|
+
|
84
|
+
it "finds no errors" do
|
85
|
+
assert_equal [], errors
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "non-nullable arg" do
|
90
|
+
let(:schema) {
|
91
|
+
GraphQL::Schema.from_definition(%|
|
92
|
+
type Query {
|
93
|
+
field(arg: Int!): Int
|
94
|
+
}
|
95
|
+
|)
|
96
|
+
}
|
97
|
+
let(:query_string) {%|
|
98
|
+
query {
|
99
|
+
field(arg: null)
|
100
|
+
}
|
101
|
+
|}
|
102
|
+
|
103
|
+
it "finds error" do
|
104
|
+
assert_equal [{
|
105
|
+
"message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type 'Int!'.",
|
106
|
+
"locations"=>[{"line"=>3, "column"=>11}],
|
107
|
+
"fields"=>["query", "field", "arg"],
|
108
|
+
}], errors
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "non-nullable array" do
|
113
|
+
let(:schema) {
|
114
|
+
GraphQL::Schema.from_definition(%|
|
115
|
+
type Query {
|
116
|
+
field(arg: [Int!]): Int
|
117
|
+
}
|
118
|
+
|)
|
119
|
+
}
|
120
|
+
let(:query_string) {%|
|
121
|
+
query {
|
122
|
+
field(arg: [null])
|
123
|
+
}
|
124
|
+
|}
|
125
|
+
|
126
|
+
it "finds error" do
|
127
|
+
assert_equal [{
|
128
|
+
"message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type '[Int!]'.",
|
129
|
+
"locations"=>[{"line"=>3, "column"=>11}],
|
130
|
+
"fields"=>["query", "field", "arg"],
|
131
|
+
}], errors
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "array with nullable values" do
|
136
|
+
let(:schema) {
|
137
|
+
GraphQL::Schema.from_definition(%|
|
138
|
+
type Query {
|
139
|
+
field(arg: [Int]): Int
|
140
|
+
}
|
141
|
+
|)
|
142
|
+
}
|
143
|
+
let(:query_string) {%|
|
144
|
+
query {
|
145
|
+
field(arg: [null])
|
146
|
+
}
|
147
|
+
|}
|
148
|
+
|
149
|
+
it "finds no errors" do
|
150
|
+
assert_equal [], errors
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "input object" do
|
155
|
+
let(:schema) {
|
156
|
+
GraphQL::Schema.from_definition(%|
|
157
|
+
type Query {
|
158
|
+
field(arg: Input): Int
|
159
|
+
}
|
160
|
+
|
161
|
+
input Input {
|
162
|
+
a: Int
|
163
|
+
b: Int!
|
164
|
+
}
|
165
|
+
|)
|
166
|
+
}
|
167
|
+
let(:query_string) {%|
|
168
|
+
query {
|
169
|
+
field(arg: {a: null, b: null})
|
170
|
+
}
|
171
|
+
|}
|
172
|
+
|
173
|
+
it "finds errors" do
|
174
|
+
assert_equal 2, errors.length
|
175
|
+
|
176
|
+
assert_includes errors, {
|
177
|
+
"message"=> "Argument 'arg' on Field 'field' has an invalid value. Expected type 'Input'.",
|
178
|
+
"locations"=>[{"line"=>3, "column"=>11}],
|
179
|
+
"fields"=>["query", "field", "arg"]
|
180
|
+
}
|
181
|
+
|
182
|
+
assert_includes errors, {
|
183
|
+
"message"=>"Argument 'b' on InputObject 'Input' has an invalid value. Expected type 'Int!'.",
|
184
|
+
"locations"=>[{"line"=>3, "column"=>22}],
|
185
|
+
"fields"=>["query", "field", "arg", "b"]
|
186
|
+
}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
68
190
|
end
|