graphql 0.13.0 → 0.14.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/define/assign_argument.rb +3 -5
  3. data/lib/graphql/field.rb +1 -3
  4. data/lib/graphql/input_object_type.rb +4 -1
  5. data/lib/graphql/language.rb +1 -0
  6. data/lib/graphql/language/generation.rb +94 -0
  7. data/lib/graphql/language/lexer.rb +229 -201
  8. data/lib/graphql/language/lexer.rl +24 -7
  9. data/lib/graphql/language/nodes.rb +4 -0
  10. data/lib/graphql/language/parser.rb +195 -187
  11. data/lib/graphql/language/parser.y +11 -4
  12. data/lib/graphql/object_type.rb +21 -0
  13. data/lib/graphql/query.rb +8 -3
  14. data/lib/graphql/query/serial_execution/operation_resolution.rb +2 -2
  15. data/lib/graphql/query/serial_execution/value_resolution.rb +5 -0
  16. data/lib/graphql/schema.rb +11 -19
  17. data/lib/graphql/schema/invalid_type_error.rb +6 -0
  18. data/lib/graphql/schema/reduce_types.rb +68 -0
  19. data/lib/graphql/schema/type_expression.rb +6 -16
  20. data/lib/graphql/schema/type_map.rb +1 -5
  21. data/lib/graphql/schema/validation.rb +164 -0
  22. data/lib/graphql/version.rb +1 -1
  23. data/readme.md +3 -4
  24. data/spec/graphql/argument_spec.rb +20 -0
  25. data/spec/graphql/field_spec.rb +16 -0
  26. data/spec/graphql/introspection/schema_type_spec.rb +1 -0
  27. data/spec/graphql/language/generation_spec.rb +42 -0
  28. data/spec/graphql/language/parser_spec.rb +136 -26
  29. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +23 -0
  30. data/spec/graphql/query_spec.rb +51 -0
  31. data/spec/graphql/schema/{type_reducer_spec.rb → reduce_types_spec.rb} +16 -14
  32. data/spec/graphql/schema/type_expression_spec.rb +4 -4
  33. data/spec/graphql/schema/validation_spec.rb +219 -0
  34. data/spec/support/dairy_app.rb +3 -0
  35. metadata +14 -13
  36. data/lib/graphql/schema/each_item_validator.rb +0 -21
  37. data/lib/graphql/schema/field_validator.rb +0 -17
  38. data/lib/graphql/schema/implementation_validator.rb +0 -31
  39. data/lib/graphql/schema/type_reducer.rb +0 -79
  40. data/lib/graphql/schema/type_validator.rb +0 -58
  41. data/spec/graphql/schema/field_validator_spec.rb +0 -21
  42. data/spec/graphql/schema/type_validator_spec.rb +0 -81
@@ -6,20 +6,20 @@ describe GraphQL::Schema::TypeExpression do
6
6
  document = GraphQL.parse("query dostuff($var: #{type_name}) { id } ")
7
7
  document.definitions.first.variables.first.type
8
8
  }
9
- let(:type_expression) { GraphQL::Schema::TypeExpression.new(schema, ast_node) }
9
+ let(:type_expression_result) { GraphQL::Schema::TypeExpression.build_type(schema, ast_node) }
10
10
 
11
11
  describe "#type" do
12
12
  describe "simple types" do
13
13
  let(:type_name) { "DairyProductInput" }
14
14
  it "it gets types from the schema" do
15
- assert_equal(DairyProductInputType, type_expression.type)
15
+ assert_equal(DairyProductInputType, type_expression_result)
16
16
  end
17
17
  end
18
18
 
19
19
  describe "non-null types" do
20
20
  let(:type_name) { "String!"}
21
21
  it "makes non-null types" do
22
- assert_equal(GraphQL::STRING_TYPE.to_non_null_type, type_expression.type)
22
+ assert_equal(GraphQL::STRING_TYPE.to_non_null_type,type_expression_result)
23
23
  end
24
24
  end
25
25
 
@@ -31,7 +31,7 @@ describe GraphQL::Schema::TypeExpression do
31
31
  .to_non_null_type
32
32
  .to_list_type
33
33
  .to_non_null_type
34
- assert_equal(expected, type_expression.type)
34
+ assert_equal(expected, type_expression_result)
35
35
  end
36
36
  end
37
37
  end
@@ -0,0 +1,219 @@
1
+ require "spec_helper"
2
+
3
+ describe GraphQL::Schema::Validation do
4
+ def assert_error_includes(object, error_substring)
5
+ validation_error = GraphQL::Schema::Validation.validate(object)
6
+ assert_includes validation_error, error_substring
7
+ end
8
+
9
+ describe "validating Fields" do
10
+ let(:unnamed_field) {
11
+ GraphQL::Field.define do
12
+ type GraphQL::STRING_TYPE
13
+ end
14
+ }
15
+
16
+ let(:untyped_field) {
17
+ GraphQL::Field.define do
18
+ name "Untyped"
19
+ type :something_invalid
20
+ end
21
+ }
22
+
23
+ let(:bad_arguments_field) {
24
+ field = GraphQL::Field.define do
25
+ name "BadArgs"
26
+ type !GraphQL::BOOLEAN_TYPE
27
+ end
28
+ field.arguments[:bad_key] = :bad_value
29
+ field
30
+ }
31
+
32
+ let(:invalid_argument_member_field) {
33
+ GraphQL::Field.define do
34
+ name "InvalidArgument"
35
+ type !types[!GraphQL::INT_TYPE]
36
+ argument :invalid do
37
+ type GraphQL::STRING_TYPE
38
+ default_value [1,2,3]
39
+ end
40
+ end
41
+ }
42
+
43
+ it "requires a String for name" do
44
+ assert_error_includes unnamed_field, "must return String, not NilClass"
45
+ end
46
+
47
+ it "requires a BaseType for type" do
48
+ assert_error_includes untyped_field, "must return GraphQL::BaseType, not Symbol"
49
+ end
50
+
51
+ it "requires String => Argument arguments" do
52
+ assert_error_includes bad_arguments_field, "must map String => GraphQL::Argument, not Symbol => Symbol"
53
+ end
54
+
55
+ it "applies validation to its member Arguments" do
56
+ assert_error_includes invalid_argument_member_field, "default value [1, 2, 3] is not valid for type String"
57
+ end
58
+ end
59
+
60
+ describe "validating BaseType" do
61
+ let(:unnamed_type) {
62
+ GraphQL::BaseType.define do
63
+ name :invalid_name
64
+ end
65
+ }
66
+
67
+ let(:wrongly_described_type) {
68
+ GraphQL::BaseType.define do
69
+ name "WronglyDescribed"
70
+ description 12345
71
+ end
72
+ }
73
+ it "requires a String name" do
74
+ assert_error_includes unnamed_type, "must return String, not Symbol"
75
+ end
76
+
77
+ it "requires String-or-nil description" do
78
+ assert_error_includes wrongly_described_type, "must return String or NilClass, not Fixnum"
79
+ end
80
+ end
81
+
82
+ describe "validating ObjectTypes" do
83
+ let(:invalid_interfaces_object) {
84
+ GraphQL::ObjectType.define do
85
+ name "InvalidInterfaces"
86
+ interfaces({a: 1})
87
+ end
88
+ }
89
+ let(:invalid_interface_member_object) {
90
+ GraphQL::ObjectType.define do
91
+ name "InvalidInterfaceMember"
92
+ interfaces [:not_an_interface]
93
+ end
94
+ }
95
+
96
+ let(:invalid_field_object) {
97
+ GraphQL::ObjectType.define do
98
+ name "InvalidField"
99
+ field :invalid, :nonsense
100
+ end
101
+ }
102
+
103
+ it "requires an Array for interfaces" do
104
+ assert_error_includes invalid_interfaces_object, "must be an Array of GraphQL::InterfaceType, not a Hash"
105
+ assert_error_includes invalid_interface_member_object, "must contain GraphQL::InterfaceType, not Symbol"
106
+ end
107
+
108
+ it "validates the fields" do
109
+ assert_error_includes invalid_field_object, "must return GraphQL::BaseType, not Symbol"
110
+ end
111
+ end
112
+
113
+ describe "validating UnionTypes" do
114
+ let(:non_array_union) {
115
+ GraphQL::UnionType.define do
116
+ name "NonArray"
117
+ possible_types 55
118
+ end
119
+ }
120
+
121
+ let(:non_object_type_union) {
122
+ GraphQL::UnionType.define do
123
+ name "NonObjectTypes"
124
+ possible_types [
125
+ GraphQL::InterfaceType.new
126
+ ]
127
+ end
128
+ }
129
+
130
+ let(:no_possible_types_union) {
131
+ GraphQL::UnionType.define do
132
+ name "NoPossibleTypes"
133
+ possible_types []
134
+ end
135
+ }
136
+
137
+ it "requires an array of ObjectTypes for possible_types" do
138
+ assert_error_includes non_array_union, "must be an Array of GraphQL::ObjectType, not a Fixnum"
139
+
140
+ assert_error_includes non_object_type_union, "must contain GraphQL::ObjectType, not GraphQL::InterfaceType"
141
+ end
142
+
143
+ it "requires at least one possible_types" do
144
+ assert_error_includes no_possible_types_union, "must have at least one possible type"
145
+ end
146
+ end
147
+
148
+ describe "validating InputObjectTypes" do
149
+ let(:invalid_arguments_input) {
150
+ input = GraphQL::InputObjectType.define do
151
+ name "InvalidArgumentsHash"
152
+ end
153
+ input.arguments[123] = :nonsense
154
+ input
155
+ }
156
+
157
+ let(:invalid_argument_member_input) {
158
+ GraphQL::InputObjectType.define do
159
+ name "InvalidArgumentMember"
160
+ argument :nonsense do
161
+ type GraphQL::FLOAT_TYPE
162
+ default_value "xyz"
163
+ end
164
+ end
165
+ }
166
+
167
+ it "requires {String => Argument} arguments" do
168
+ assert_error_includes invalid_arguments_input, "map String => GraphQL::Argument, not Fixnum => Symbol"
169
+ end
170
+
171
+ it "applies validation to its member Arguments" do
172
+ assert_error_includes invalid_argument_member_input, "default value \"xyz\" is not valid for type Float"
173
+ end
174
+ end
175
+
176
+ describe "validating InterfaceTypes" do
177
+ let(:invalid_field_interface) {
178
+ GraphQL::InterfaceType.define do
179
+ name "InvalidField"
180
+ field :invalid do
181
+ type GraphQL::BOOLEAN_TYPE
182
+ argument :invalid do
183
+ type GraphQL::STRING_TYPE
184
+ default_value 4.56
185
+ end
186
+ end
187
+ end
188
+ }
189
+
190
+ it "validates fields" do
191
+ assert_error_includes invalid_field_interface, "default value 4.56 is not valid for type String"
192
+ end
193
+ end
194
+
195
+ describe "validating Arguments" do
196
+ let(:untyped_argument) {
197
+ GraphQL::Argument.define do
198
+ name "Untyped"
199
+ type :Bogus
200
+ end
201
+ }
202
+
203
+ let(:invalid_default_argument) {
204
+ GraphQL::Argument.define do
205
+ name "InvalidDefault"
206
+ type GraphQL::INT_TYPE
207
+ default_value "abc"
208
+ end
209
+ }
210
+
211
+ it "requires the type is a Base type" do
212
+ assert_error_includes untyped_argument, "must be a valid input type (Scalar or InputObject), not Symbol"
213
+ end
214
+
215
+ it "requires the default value is compatible" do
216
+ assert_error_includes invalid_default_argument, 'default value "abc" is not valid for type Int'
217
+ end
218
+ end
219
+ end
@@ -200,6 +200,9 @@ FavoriteFieldDefn = Proc.new {
200
200
  QueryType = GraphQL::ObjectType.define do
201
201
  name "Query"
202
202
  description "Query root of the system"
203
+ field :root, types.String do
204
+ resolve ->(root_value, args, c) { root_value }
205
+ end
203
206
  field :cheese, field: FetchField.create(type: CheeseType, data: CHEESES)
204
207
  field :milk, field: FetchField.create(type: MilkType, data: MILKS, id_type: !types.ID)
205
208
  field :dairy, field: SingletonField.create(type: DairyType, data: DAIRY)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-29 00:00:00.000000000 Z
11
+ date: 2016-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: codeclimate-test-reporter
@@ -233,6 +233,7 @@ files:
233
233
  - lib/graphql/introspection/typename_field.rb
234
234
  - lib/graphql/invalid_null_error.rb
235
235
  - lib/graphql/language.rb
236
+ - lib/graphql/language/generation.rb
236
237
  - lib/graphql/language/lexer.rb
237
238
  - lib/graphql/language/lexer.rl
238
239
  - lib/graphql/language/nodes.rb
@@ -261,17 +262,15 @@ files:
261
262
  - lib/graphql/query/variables.rb
262
263
  - lib/graphql/scalar_type.rb
263
264
  - lib/graphql/schema.rb
264
- - lib/graphql/schema/each_item_validator.rb
265
- - lib/graphql/schema/field_validator.rb
266
- - lib/graphql/schema/implementation_validator.rb
265
+ - lib/graphql/schema/invalid_type_error.rb
267
266
  - lib/graphql/schema/middleware_chain.rb
268
267
  - lib/graphql/schema/possible_types.rb
269
268
  - lib/graphql/schema/printer.rb
269
+ - lib/graphql/schema/reduce_types.rb
270
270
  - lib/graphql/schema/rescue_middleware.rb
271
271
  - lib/graphql/schema/type_expression.rb
272
272
  - lib/graphql/schema/type_map.rb
273
- - lib/graphql/schema/type_reducer.rb
274
- - lib/graphql/schema/type_validator.rb
273
+ - lib/graphql/schema/validation.rb
275
274
  - lib/graphql/static_validation.rb
276
275
  - lib/graphql/static_validation/all_rules.rb
277
276
  - lib/graphql/static_validation/arguments_validator.rb
@@ -303,6 +302,7 @@ files:
303
302
  - lib/graphql/union_type.rb
304
303
  - lib/graphql/version.rb
305
304
  - readme.md
305
+ - spec/graphql/argument_spec.rb
306
306
  - spec/graphql/base_type_spec.rb
307
307
  - spec/graphql/boolean_type_spec.rb
308
308
  - spec/graphql/define/instance_definable_spec.rb
@@ -320,6 +320,7 @@ files:
320
320
  - spec/graphql/introspection/introspection_query_spec.rb
321
321
  - spec/graphql/introspection/schema_type_spec.rb
322
322
  - spec/graphql/introspection/type_type_spec.rb
323
+ - spec/graphql/language/generation_spec.rb
323
324
  - spec/graphql/language/parser_spec.rb
324
325
  - spec/graphql/language/visitor_spec.rb
325
326
  - spec/graphql/list_type_spec.rb
@@ -333,13 +334,12 @@ files:
333
334
  - spec/graphql/query/variables_spec.rb
334
335
  - spec/graphql/query_spec.rb
335
336
  - spec/graphql/scalar_type_spec.rb
336
- - spec/graphql/schema/field_validator_spec.rb
337
337
  - spec/graphql/schema/middleware_chain_spec.rb
338
338
  - spec/graphql/schema/printer_spec.rb
339
+ - spec/graphql/schema/reduce_types_spec.rb
339
340
  - spec/graphql/schema/rescue_middleware_spec.rb
340
341
  - spec/graphql/schema/type_expression_spec.rb
341
- - spec/graphql/schema/type_reducer_spec.rb
342
- - spec/graphql/schema/type_validator_spec.rb
342
+ - spec/graphql/schema/validation_spec.rb
343
343
  - spec/graphql/schema_spec.rb
344
344
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
345
345
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
@@ -394,6 +394,7 @@ signing_key:
394
394
  specification_version: 4
395
395
  summary: A GraphQL server implementation for Ruby
396
396
  test_files:
397
+ - spec/graphql/argument_spec.rb
397
398
  - spec/graphql/base_type_spec.rb
398
399
  - spec/graphql/boolean_type_spec.rb
399
400
  - spec/graphql/define/instance_definable_spec.rb
@@ -411,6 +412,7 @@ test_files:
411
412
  - spec/graphql/introspection/introspection_query_spec.rb
412
413
  - spec/graphql/introspection/schema_type_spec.rb
413
414
  - spec/graphql/introspection/type_type_spec.rb
415
+ - spec/graphql/language/generation_spec.rb
414
416
  - spec/graphql/language/parser_spec.rb
415
417
  - spec/graphql/language/visitor_spec.rb
416
418
  - spec/graphql/list_type_spec.rb
@@ -424,13 +426,12 @@ test_files:
424
426
  - spec/graphql/query/variables_spec.rb
425
427
  - spec/graphql/query_spec.rb
426
428
  - spec/graphql/scalar_type_spec.rb
427
- - spec/graphql/schema/field_validator_spec.rb
428
429
  - spec/graphql/schema/middleware_chain_spec.rb
429
430
  - spec/graphql/schema/printer_spec.rb
431
+ - spec/graphql/schema/reduce_types_spec.rb
430
432
  - spec/graphql/schema/rescue_middleware_spec.rb
431
433
  - spec/graphql/schema/type_expression_spec.rb
432
- - spec/graphql/schema/type_reducer_spec.rb
433
- - spec/graphql/schema/type_validator_spec.rb
434
+ - spec/graphql/schema/validation_spec.rb
434
435
  - spec/graphql/schema_spec.rb
435
436
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
436
437
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
@@ -1,21 +0,0 @@
1
- module GraphQL
2
- class Schema
3
- class EachItemValidator
4
- def initialize(errors)
5
- @errors = errors
6
- end
7
-
8
- def validate(items, as:, must_be:)
9
- if !items.is_a?(Array)
10
- @errors << "#{as} must be an Array, not #{items.inspect}"
11
- return
12
- else
13
- invalid_items = items.select {|k| !yield(k) }
14
- if invalid_items.any?
15
- @errors << "#{as} must be #{must_be}, but some aren't: #{invalid_items.map(&:to_s).join(", ")}"
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,17 +0,0 @@
1
- module GraphQL
2
- class Schema
3
- class FieldValidator
4
- def validate(field, errors)
5
- implementation = GraphQL::Schema::ImplementationValidator.new(field, as: "Field", errors: errors)
6
- implementation.must_respond_to(:name)
7
- implementation.must_respond_to(:type)
8
- implementation.must_respond_to(:description)
9
- implementation.must_respond_to(:arguments) do |arguments|
10
- validator = GraphQL::Schema::EachItemValidator.new(errors)
11
- validator.validate(arguments.keys, as: "#{field.name}.arguments keys", must_be: "Strings") { |k| k.is_a?(String) }
12
- end
13
- implementation.must_respond_to(:deprecation_reason)
14
- end
15
- end
16
- end
17
- end
@@ -1,31 +0,0 @@
1
- module GraphQL
2
- class Schema
3
- # A helper to ensure `object` implements the concept `as`
4
- class ImplementationValidator
5
- attr_reader :object, :errors, :implementation_as
6
- def initialize(object, as:, errors:)
7
- @object = object
8
- @implementation_as = as
9
- @errors = errors
10
- end
11
-
12
- # Ensure the object responds to `method_name`.
13
- # If `block_given?`, yield the return value of that method
14
- # If provided, use `as` in the error message, overriding class-level `as`.
15
- def must_respond_to(method_name, args: [], as: nil)
16
- local_as = as || implementation_as
17
- method_signature = "##{method_name}(#{args.join(", ")})"
18
- if !object.respond_to?(method_name)
19
- errors << "#{object.to_s} must respond to #{method_signature} to be a #{local_as}"
20
- elsif block_given?
21
- return_value = object.public_send(method_name)
22
- if return_value.nil?
23
- errors << "#{object.to_s} must return a value for #{method_signature} to be a #{local_as}"
24
- else
25
- yield(return_value)
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,79 +0,0 @@
1
- module GraphQL
2
- class Schema
3
- # Starting from a given type, discover other types in the system by
4
- # traversing that type's fields, possible_types, etc
5
- class TypeReducer
6
- attr_reader :type, :existing_type_hash
7
-
8
- def initialize(type, existing_type_hash)
9
- validate_type(type)
10
- if type.respond_to?(:name) && existing_type_hash.fetch(type.name, nil).equal?(type)
11
- @result = existing_type_hash
12
- else
13
- @type = type
14
- end
15
- @existing_type_hash = existing_type_hash
16
- end
17
-
18
- def result
19
- @result ||= find_types(type, existing_type_hash)
20
- end
21
-
22
- # Reduce all of `types` and return the combined result
23
- def self.find_all(types)
24
- type_map = GraphQL::Schema::TypeMap.new
25
- types.reduce(type_map) do |memo, type|
26
- self.new(type, memo).result
27
- end
28
- end
29
-
30
- private
31
-
32
- def find_types(type, type_hash)
33
- type_hash[type.name] = type
34
- if type.kind.fields?
35
- type.all_fields.each do |field|
36
- reduce_type(field.type, type_hash, "Field #{type.name}.#{field.name}")
37
- field.arguments.each do |name, argument|
38
- reduce_type(argument.type, type_hash, "Argument #{name} on #{type.name}.#{field.name}")
39
- end
40
- end
41
- end
42
- if type.kind.object?
43
- type.interfaces.each do |interface|
44
- reduce_type(interface, type_hash, "Interface on #{type.name}")
45
- end
46
- end
47
- if type.kind.union?
48
- type.possible_types.each do |possible_type|
49
- reduce_type(possible_type, type_hash, "Possible type for #{type.name}")
50
- end
51
- end
52
- if type.kind.input_object?
53
- type.input_fields.each do |name, input_field|
54
- reduce_type(input_field.type, type_hash, "Input field #{type.name}.#{name}")
55
- end
56
- end
57
-
58
- type_hash
59
- end
60
-
61
- def reduce_type(type, type_hash, name = nil)
62
- if type.is_a?(GraphQL::BaseType)
63
- self.class.new(type.unwrap, type_hash).result
64
- else
65
- raise GraphQL::Schema::InvalidTypeError.new(type, name)
66
- end
67
- end
68
-
69
- def validate_type(type)
70
- errors = []
71
- type_validator = GraphQL::Schema::TypeValidator.new
72
- type_validator.validate(type, errors)
73
- if errors.any?
74
- raise GraphQL::Schema::InvalidTypeError.new(type, errors)
75
- end
76
- end
77
- end
78
- end
79
- end