graphql 1.7.13 → 1.7.14
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/argument.rb +1 -0
- data/lib/graphql/base_type.rb +7 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +110 -0
- data/lib/graphql/directive.rb +1 -0
- data/lib/graphql/enum_type.rb +2 -0
- data/lib/graphql/execution/multiplex.rb +1 -1
- data/lib/graphql/field.rb +2 -0
- data/lib/graphql/language/document_from_schema_definition.rb +1 -1
- data/lib/graphql/language/lexer.rb +65 -51
- data/lib/graphql/language/lexer.rl +2 -0
- data/lib/graphql/language/nodes.rb +118 -71
- data/lib/graphql/language/parser.rb +701 -654
- data/lib/graphql/language/parser.y +14 -8
- data/lib/graphql/language/printer.rb +2 -2
- data/lib/graphql/object_type.rb +0 -5
- data/lib/graphql/relay/relation_connection.rb +1 -1
- data/lib/graphql/schema.rb +1 -0
- data/lib/graphql/schema/build_from_definition.rb +60 -18
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
- data/lib/graphql/unresolved_type_error.rb +3 -2
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/base_type_spec.rb +22 -0
- data/spec/graphql/enum_type_spec.rb +18 -5
- data/spec/graphql/execution/multiplex_spec.rb +1 -1
- data/spec/graphql/input_object_type_spec.rb +13 -0
- data/spec/graphql/language/nodes_spec.rb +0 -12
- data/spec/graphql/language/printer_spec.rb +1 -1
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
- data/spec/graphql/query_spec.rb +26 -0
- data/spec/graphql/relay/relation_connection_spec.rb +7 -1
- data/spec/graphql/schema/build_from_definition_spec.rb +59 -0
- data/spec/graphql/schema/printer_spec.rb +34 -0
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
- metadata +2 -2
@@ -152,12 +152,8 @@ rule
|
|
152
152
|
| operation_type
|
153
153
|
| schema_keyword
|
154
154
|
|
155
|
-
name_list:
|
156
|
-
name { return [make_node(:TypeName, name: val[0])] }
|
157
|
-
| name_list name { val[0] << make_node(:TypeName, name: val[1]) }
|
158
|
-
|
159
155
|
enum_value_definition:
|
160
|
-
enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0])) }
|
156
|
+
enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0]), position_source: val[0]) }
|
161
157
|
|
162
158
|
enum_value_definitions:
|
163
159
|
enum_value_definition { return [val[0]] }
|
@@ -306,11 +302,21 @@ rule
|
|
306
302
|
|
307
303
|
implements_opt:
|
308
304
|
/* none */ { return [] }
|
309
|
-
| IMPLEMENTS
|
305
|
+
| IMPLEMENTS AMP interfaces_list { return val[2] }
|
306
|
+
| IMPLEMENTS interfaces_list { return val[1] }
|
307
|
+
| IMPLEMENTS legacy_interfaces_list { return val[1] }
|
308
|
+
|
309
|
+
interfaces_list:
|
310
|
+
name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
|
311
|
+
| interfaces_list AMP name { val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) }
|
312
|
+
|
313
|
+
legacy_interfaces_list:
|
314
|
+
name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
|
315
|
+
| legacy_interfaces_list name { val[0] << make_node(:TypeName, name: val[1], position_source: val[1]) }
|
310
316
|
|
311
317
|
input_value_definition:
|
312
318
|
name COLON type default_value_opt directives_list_opt {
|
313
|
-
return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4], description: get_description(val[0]))
|
319
|
+
return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
|
314
320
|
}
|
315
321
|
|
316
322
|
input_value_definition_list:
|
@@ -323,7 +329,7 @@ rule
|
|
323
329
|
|
324
330
|
field_definition:
|
325
331
|
name arguments_definitions_opt COLON type directives_list_opt {
|
326
|
-
return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4], description: get_description(val[0]))
|
332
|
+
return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
|
327
333
|
}
|
328
334
|
|
329
335
|
field_definition_list:
|
@@ -154,7 +154,7 @@ module GraphQL
|
|
154
154
|
def print_object_type_definition(object_type)
|
155
155
|
out = print_description(object_type)
|
156
156
|
out << "type #{object_type.name}"
|
157
|
-
out << " implements " << object_type.interfaces.map(&:name).join("
|
157
|
+
out << " implements " << object_type.interfaces.map(&:name).join(" & ") unless object_type.interfaces.empty?
|
158
158
|
out << print_directives(object_type.directives)
|
159
159
|
out << print_field_definitions(object_type.fields)
|
160
160
|
end
|
@@ -339,7 +339,7 @@ module GraphQL
|
|
339
339
|
when Hash
|
340
340
|
"{#{node.map { |k, v| "#{k}: #{print_node(v)}" }.join(", ")}}".dup
|
341
341
|
else
|
342
|
-
|
342
|
+
GraphQL::Language.serialize(node.to_s)
|
343
343
|
end
|
344
344
|
end
|
345
345
|
|
data/lib/graphql/object_type.rb
CHANGED
data/lib/graphql/schema.rb
CHANGED
@@ -80,6 +80,7 @@ module GraphQL
|
|
80
80
|
:orphan_types, :directives,
|
81
81
|
:query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
|
82
82
|
:cursor_encoder,
|
83
|
+
:ast_node,
|
83
84
|
:raise_definition_error
|
84
85
|
|
85
86
|
# Single, long-lived instance of the provided subscriptions class, if there is one.
|
@@ -107,6 +107,8 @@ module GraphQL
|
|
107
107
|
directives directives.values
|
108
108
|
end
|
109
109
|
|
110
|
+
schema.ast_node = schema_definition if schema_definition
|
111
|
+
|
110
112
|
schema
|
111
113
|
end
|
112
114
|
|
@@ -117,18 +119,26 @@ module GraphQL
|
|
117
119
|
NullScalarCoerce = ->(val, _ctx) { val }
|
118
120
|
|
119
121
|
def build_enum_type(enum_type_definition, type_resolver)
|
120
|
-
GraphQL::EnumType.define(
|
122
|
+
enum = GraphQL::EnumType.define(
|
121
123
|
name: enum_type_definition.name,
|
122
124
|
description: enum_type_definition.description,
|
123
125
|
values: enum_type_definition.values.map do |enum_value_definition|
|
124
|
-
EnumType::EnumValue.define(
|
126
|
+
value = EnumType::EnumValue.define(
|
125
127
|
name: enum_value_definition.name,
|
126
128
|
value: enum_value_definition.name,
|
127
129
|
deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
|
128
130
|
description: enum_value_definition.description,
|
129
131
|
)
|
132
|
+
|
133
|
+
value.ast_node = enum_value_definition
|
134
|
+
|
135
|
+
value
|
130
136
|
end
|
131
137
|
)
|
138
|
+
|
139
|
+
enum.ast_node = enum_type_definition
|
140
|
+
|
141
|
+
enum
|
132
142
|
end
|
133
143
|
|
134
144
|
def build_deprecation_reason(directives)
|
@@ -148,6 +158,8 @@ module GraphQL
|
|
148
158
|
coerce: NullScalarCoerce,
|
149
159
|
)
|
150
160
|
|
161
|
+
scalar_type.ast_node = scalar_type_definition
|
162
|
+
|
151
163
|
if default_resolve.respond_to?(:coerce_input)
|
152
164
|
scalar_type = scalar_type.redefine(
|
153
165
|
coerce_input: ->(val, ctx) { default_resolve.coerce_input(scalar_type, val, ctx) },
|
@@ -159,11 +171,15 @@ module GraphQL
|
|
159
171
|
end
|
160
172
|
|
161
173
|
def build_union_type(union_type_definition, type_resolver)
|
162
|
-
GraphQL::UnionType.define(
|
174
|
+
union = GraphQL::UnionType.define(
|
163
175
|
name: union_type_definition.name,
|
164
176
|
description: union_type_definition.description,
|
165
177
|
possible_types: union_type_definition.types.map{ |type_name| type_resolver.call(type_name) },
|
166
178
|
)
|
179
|
+
|
180
|
+
union.ast_node = union_type_definition
|
181
|
+
|
182
|
+
union
|
167
183
|
end
|
168
184
|
|
169
185
|
def build_object_type(object_type_definition, type_resolver, default_resolve:)
|
@@ -175,14 +191,20 @@ module GraphQL
|
|
175
191
|
fields: Hash[build_fields(object_type_definition.fields, type_resolver, default_resolve: typed_resolve_fn)],
|
176
192
|
interfaces: object_type_definition.interfaces.map{ |interface_name| type_resolver.call(interface_name) },
|
177
193
|
)
|
194
|
+
type_def.ast_node = object_type_definition
|
195
|
+
type_def
|
178
196
|
end
|
179
197
|
|
180
198
|
def build_input_object_type(input_object_type_definition, type_resolver)
|
181
|
-
GraphQL::InputObjectType.define(
|
199
|
+
input = GraphQL::InputObjectType.define(
|
182
200
|
name: input_object_type_definition.name,
|
183
201
|
description: input_object_type_definition.description,
|
184
202
|
arguments: Hash[build_input_arguments(input_object_type_definition, type_resolver)],
|
185
203
|
)
|
204
|
+
|
205
|
+
input.ast_node = input_object_type_definition
|
206
|
+
|
207
|
+
input
|
186
208
|
end
|
187
209
|
|
188
210
|
def build_default_value(default_value)
|
@@ -208,25 +230,33 @@ module GraphQL
|
|
208
230
|
kwargs[:default_value] = build_default_value(input_argument.default_value)
|
209
231
|
end
|
210
232
|
|
233
|
+
argument = GraphQL::Argument.define(
|
234
|
+
name: input_argument.name,
|
235
|
+
type: type_resolver.call(input_argument.type),
|
236
|
+
description: input_argument.description,
|
237
|
+
**kwargs,
|
238
|
+
)
|
239
|
+
|
240
|
+
argument.ast_node = input_object_type_definition
|
241
|
+
|
211
242
|
[
|
212
243
|
input_argument.name,
|
213
|
-
|
214
|
-
name: input_argument.name,
|
215
|
-
type: type_resolver.call(input_argument.type),
|
216
|
-
description: input_argument.description,
|
217
|
-
**kwargs,
|
218
|
-
)
|
244
|
+
argument
|
219
245
|
]
|
220
246
|
end
|
221
247
|
end
|
222
248
|
|
223
249
|
def build_directive(directive_definition, type_resolver)
|
224
|
-
GraphQL::Directive.define(
|
250
|
+
directive = GraphQL::Directive.define(
|
225
251
|
name: directive_definition.name,
|
226
252
|
description: directive_definition.description,
|
227
253
|
arguments: Hash[build_directive_arguments(directive_definition, type_resolver)],
|
228
254
|
locations: directive_definition.locations.map(&:to_sym),
|
229
255
|
)
|
256
|
+
|
257
|
+
directive.ast_node = directive_definition
|
258
|
+
|
259
|
+
directive
|
230
260
|
end
|
231
261
|
|
232
262
|
def build_directive_arguments(directive_definition, type_resolver)
|
@@ -237,24 +267,32 @@ module GraphQL
|
|
237
267
|
kwargs[:default_value] = build_default_value(directive_argument.default_value)
|
238
268
|
end
|
239
269
|
|
270
|
+
argument = GraphQL::Argument.define(
|
271
|
+
name: directive_argument.name,
|
272
|
+
type: type_resolver.call(directive_argument.type),
|
273
|
+
description: directive_argument.description,
|
274
|
+
**kwargs,
|
275
|
+
)
|
276
|
+
|
277
|
+
argument.ast_node = directive_argument
|
278
|
+
|
240
279
|
[
|
241
280
|
directive_argument.name,
|
242
|
-
|
243
|
-
name: directive_argument.name,
|
244
|
-
type: type_resolver.call(directive_argument.type),
|
245
|
-
description: directive_argument.description,
|
246
|
-
**kwargs,
|
247
|
-
)
|
281
|
+
argument
|
248
282
|
]
|
249
283
|
end
|
250
284
|
end
|
251
285
|
|
252
286
|
def build_interface_type(interface_type_definition, type_resolver)
|
253
|
-
GraphQL::InterfaceType.define(
|
287
|
+
interface = GraphQL::InterfaceType.define(
|
254
288
|
name: interface_type_definition.name,
|
255
289
|
description: interface_type_definition.description,
|
256
290
|
fields: Hash[build_fields(interface_type_definition.fields, type_resolver, default_resolve: nil)],
|
257
291
|
)
|
292
|
+
|
293
|
+
interface.ast_node = interface_type_definition
|
294
|
+
|
295
|
+
interface
|
258
296
|
end
|
259
297
|
|
260
298
|
def build_fields(field_definitions, type_resolver, default_resolve:)
|
@@ -273,6 +311,8 @@ module GraphQL
|
|
273
311
|
**kwargs,
|
274
312
|
)
|
275
313
|
|
314
|
+
arg.ast_node = argument
|
315
|
+
|
276
316
|
[argument.name, arg]
|
277
317
|
end]
|
278
318
|
|
@@ -285,6 +325,8 @@ module GraphQL
|
|
285
325
|
deprecation_reason: build_deprecation_reason(field_definition.directives),
|
286
326
|
)
|
287
327
|
|
328
|
+
field.ast_node = field_definition
|
329
|
+
|
288
330
|
type_name = resolve_type_name(field_definition.type)
|
289
331
|
field.connection = type_name.end_with?("Connection")
|
290
332
|
[field_definition.name, field]
|
@@ -26,8 +26,9 @@ module GraphQL
|
|
26
26
|
@possible_types = possible_types
|
27
27
|
message = "The value from \"#{field.name}\" on \"#{parent_type}\" could not be resolved to \"#{field.type}\". " \
|
28
28
|
"(Received: `#{resolved_type.inspect}`, Expected: [#{possible_types.map(&:inspect).join(", ")}]) " \
|
29
|
-
"Make sure you have defined a `
|
30
|
-
"gets resolved to a valid type."
|
29
|
+
"Make sure you have defined a `resolve_type` proc on your schema and that value `#{value.inspect}` " \
|
30
|
+
"gets resolved to a valid type. You may need to add your type to `orphan_types` if it implements an " \
|
31
|
+
"interface but isn't a return type of any other field."
|
31
32
|
super(message)
|
32
33
|
end
|
33
34
|
end
|
data/lib/graphql/version.rb
CHANGED
@@ -28,6 +28,28 @@ describe GraphQL::BaseType do
|
|
28
28
|
assert_equal ["Cheese"], Dummy::CheeseType.metadata[:class_names]
|
29
29
|
end
|
30
30
|
|
31
|
+
describe "#name" do
|
32
|
+
describe "when containing spaces" do
|
33
|
+
BaseNameSpaceTest = GraphQL::BaseType.define do
|
34
|
+
name "Some Invalid Name"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "is invalid" do
|
38
|
+
assert_raises(GraphQL::InvalidNameError) { BaseNameSpaceTest.name }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "when containing colons" do
|
43
|
+
BaseNameColonsTest = GraphQL::BaseType.define do
|
44
|
+
name "Some::Invalid::Name"
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'is invalid' do
|
48
|
+
assert_raises(GraphQL::InvalidNameError) { BaseNameColonsTest.name }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
31
53
|
describe "#dup" do
|
32
54
|
let(:obj_type) {
|
33
55
|
GraphQL::ObjectType.define do
|
@@ -37,21 +37,34 @@ describe GraphQL::EnumType do
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
describe "invalid
|
41
|
-
it "rejects names with a space" do
|
40
|
+
describe "invalid values" do
|
41
|
+
it "rejects value names with a space" do
|
42
42
|
assert_raises(GraphQL::InvalidNameError) {
|
43
|
-
|
44
|
-
name "
|
43
|
+
InvalidEnumValueTest = GraphQL::EnumType.define do
|
44
|
+
name "InvalidEnumValueTest"
|
45
45
|
|
46
46
|
value("SPACE IN VALUE", "Invalid enum because it contains spaces", value: 1)
|
47
47
|
end
|
48
48
|
|
49
49
|
# Force evaluation
|
50
|
-
|
50
|
+
InvalidEnumValueTest.name
|
51
51
|
}
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
describe "invalid name" do
|
56
|
+
it "reject names with invalid format" do
|
57
|
+
assert_raises(GraphQL::InvalidNameError) do
|
58
|
+
InvalidEnumNameTest = GraphQL::EnumType.define do
|
59
|
+
name "Some::Invalid::Name"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Force evaluation
|
63
|
+
InvalidEnumNameTest.name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
55
68
|
describe "values that are Arrays" do
|
56
69
|
let(:schema) {
|
57
70
|
enum = GraphQL::EnumType.define do
|
@@ -176,7 +176,7 @@ describe GraphQL::Execution::Multiplex do
|
|
176
176
|
assert_raises(GraphQL::Error) do
|
177
177
|
InspectSchema.execute("{ raiseError }")
|
178
178
|
end
|
179
|
-
unhandled_err_json = '
|
179
|
+
unhandled_err_json = '{}'
|
180
180
|
assert_equal unhandled_err_json, InspectQueryInstrumentation.last_json
|
181
181
|
end
|
182
182
|
end
|
@@ -218,6 +218,19 @@ describe GraphQL::InputObjectType do
|
|
218
218
|
assert_equal(expected, actual)
|
219
219
|
end
|
220
220
|
end
|
221
|
+
|
222
|
+
describe 'with invalid name' do
|
223
|
+
it 'raises the correct error' do
|
224
|
+
assert_raises(GraphQL::InvalidNameError) do
|
225
|
+
InvalidInputTest = GraphQL::InputObjectType.define do
|
226
|
+
name "Some::Invalid Name"
|
227
|
+
end
|
228
|
+
|
229
|
+
# Force evaluation
|
230
|
+
InvalidInputTest.name
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
221
234
|
end
|
222
235
|
end
|
223
236
|
|
@@ -2,18 +2,6 @@
|
|
2
2
|
require "spec_helper"
|
3
3
|
|
4
4
|
describe GraphQL::Language::Nodes::AbstractNode do
|
5
|
-
describe "child and scalar attributes" do
|
6
|
-
it "are inherited by node subclasses" do
|
7
|
-
subclassed_directive = Class.new(GraphQL::Language::Nodes::Directive)
|
8
|
-
|
9
|
-
assert_equal GraphQL::Language::Nodes::Directive.scalar_attributes,
|
10
|
-
subclassed_directive.scalar_attributes
|
11
|
-
|
12
|
-
assert_equal GraphQL::Language::Nodes::Directive.child_attributes,
|
13
|
-
subclassed_directive.child_attributes
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
5
|
describe "#filename" do
|
18
6
|
it "is set after .parse_file" do
|
19
7
|
filename = "spec/support/parser/filename_example.graphql"
|
@@ -115,7 +115,7 @@ describe GraphQL::Language::Printer do
|
|
115
115
|
# Union description
|
116
116
|
union AnnotatedUnion @onUnion = A | B
|
117
117
|
|
118
|
-
type Foo implements Bar {
|
118
|
+
type Foo implements Bar & AnnotatedInterface {
|
119
119
|
one: Type
|
120
120
|
two(argument: InputType!): Type
|
121
121
|
three(argument: InputType, other: String): Int
|
@@ -88,7 +88,7 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
|
|
88
88
|
err = assert_raises(GraphQL::UnresolvedTypeError) { result }
|
89
89
|
expected_message = "The value from \"resolvesToNilInterface\" on \"Query\" could not be resolved to \"SomeInterface\". " \
|
90
90
|
"(Received: `nil`, Expected: [SomeObject]) " \
|
91
|
-
"Make sure you have defined a `
|
91
|
+
"Make sure you have defined a `resolve_type` proc on your schema and that value `1337` " \
|
92
92
|
"gets resolved to a valid type."
|
93
93
|
assert_equal expected_message, err.message
|
94
94
|
end
|
@@ -105,7 +105,7 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
|
|
105
105
|
err = assert_raises(GraphQL::UnresolvedTypeError) { result }
|
106
106
|
expected_message = "The value from \"resolvesToWrongTypeInterface\" on \"Query\" could not be resolved to \"SomeInterface\". " \
|
107
107
|
"(Received: `OtherObject`, Expected: [SomeObject]) " \
|
108
|
-
"Make sure you have defined a `
|
108
|
+
"Make sure you have defined a `resolve_type` proc on your schema and that value `:something` " \
|
109
109
|
"gets resolved to a valid type."
|
110
110
|
assert_equal expected_message, err.message
|
111
111
|
end
|