graphql 0.11.0 → 0.11.1

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/base_type.rb +6 -2
  3. data/lib/graphql/definition_helpers.rb +0 -5
  4. data/lib/graphql/definition_helpers/defined_by_config.rb +106 -102
  5. data/lib/graphql/definition_helpers/non_null_with_bang.rb +13 -9
  6. data/lib/graphql/definition_helpers/string_named_hash.rb +19 -15
  7. data/lib/graphql/definition_helpers/type_definer.rb +25 -21
  8. data/lib/graphql/enum_type.rb +8 -2
  9. data/lib/graphql/float_type.rb +1 -1
  10. data/lib/graphql/input_object_type.rb +27 -6
  11. data/lib/graphql/interface_type.rb +10 -0
  12. data/lib/graphql/introspection/fields_field.rb +2 -2
  13. data/lib/graphql/list_type.rb +12 -2
  14. data/lib/graphql/non_null_type.rb +11 -1
  15. data/lib/graphql/object_type.rb +19 -0
  16. data/lib/graphql/query.rb +2 -14
  17. data/lib/graphql/query/input_validation_result.rb +23 -0
  18. data/lib/graphql/query/literal_input.rb +3 -1
  19. data/lib/graphql/query/serial_execution/field_resolution.rb +3 -1
  20. data/lib/graphql/query/serial_execution/selection_resolution.rb +21 -15
  21. data/lib/graphql/query/variable_validation_error.rb +18 -0
  22. data/lib/graphql/query/variables.rb +4 -8
  23. data/lib/graphql/scalar_type.rb +10 -4
  24. data/lib/graphql/schema.rb +4 -2
  25. data/lib/graphql/schema/printer.rb +12 -3
  26. data/lib/graphql/schema/type_reducer.rb +4 -3
  27. data/lib/graphql/static_validation.rb +1 -0
  28. data/lib/graphql/static_validation/all_rules.rb +1 -0
  29. data/lib/graphql/static_validation/rules/document_does_not_exceed_max_depth.rb +79 -0
  30. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  31. data/lib/graphql/static_validation/validation_context.rb +63 -0
  32. data/lib/graphql/static_validation/validator.rb +1 -52
  33. data/lib/graphql/version.rb +1 -1
  34. data/readme.md +21 -22
  35. data/spec/graphql/enum_type_spec.rb +8 -0
  36. data/spec/graphql/input_object_type_spec.rb +101 -3
  37. data/spec/graphql/introspection/schema_type_spec.rb +6 -6
  38. data/spec/graphql/introspection/type_type_spec.rb +6 -6
  39. data/spec/graphql/language/transform_spec.rb +9 -5
  40. data/spec/graphql/list_type_spec.rb +23 -0
  41. data/spec/graphql/object_type_spec.rb +11 -4
  42. data/spec/graphql/query/executor_spec.rb +34 -5
  43. data/spec/graphql/query_spec.rb +22 -3
  44. data/spec/graphql/scalar_type_spec.rb +28 -0
  45. data/spec/graphql/schema/type_reducer_spec.rb +2 -2
  46. data/spec/graphql/static_validation/complexity_validator_spec.rb +15 -0
  47. data/spec/graphql/static_validation/rules/document_does_not_exceed_max_depth_spec.rb +93 -0
  48. data/spec/support/dairy_app.rb +2 -2
  49. data/spec/support/minimum_input_object.rb +8 -5
  50. metadata +10 -4
  51. data/spec/graphql/static_validation/complexity_validator.rb +0 -15
@@ -18,18 +18,25 @@ describe GraphQL::ObjectType do
18
18
  assert_equal([EdibleInterface, AnimalProductInterface], type.interfaces)
19
19
  end
20
20
 
21
- describe '.fields ' do
21
+ describe '#get_field ' do
22
22
  it 'exposes fields' do
23
- field = type.fields["id"]
23
+ field = type.get_field("id")
24
24
  assert_equal(GraphQL::TypeKinds::NON_NULL, field.type.kind)
25
25
  assert_equal(GraphQL::TypeKinds::SCALAR, field.type.of_type.kind)
26
26
  end
27
27
 
28
28
  it 'exposes defined field property' do
29
- field_without_prop = CheeseType.fields['flavor']
30
- field_with_prop = CheeseType.fields['fatContent']
29
+ field_without_prop = CheeseType.get_field('flavor')
30
+ field_with_prop = CheeseType.get_field('fatContent')
31
31
  assert_equal(field_without_prop.property, nil)
32
32
  assert_equal(field_with_prop.property, :fat_content)
33
33
  end
34
+
35
+ it "looks up from interfaces" do
36
+ field_from_self = CheeseType.get_field('fatContent')
37
+ field_from_iface = MilkType.get_field('fatContent')
38
+ assert_equal(field_from_self.property, :fat_content)
39
+ assert_equal(field_from_iface.property, nil)
40
+ end
34
41
  end
35
42
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GraphQL::Query::Executor do
4
- let(:debug) { false }
4
+ let(:debug) { true }
5
5
  let(:operation_name) { nil }
6
6
  let(:schema) { DummySchema }
7
7
  let(:variables) { {"cheeseId" => 2} }
@@ -221,6 +221,26 @@ describe GraphQL::Query::Executor do
221
221
  end
222
222
  end
223
223
 
224
+ describe "for required input objects" do
225
+ let(:variables) { { } }
226
+ let(:query_string) {%| mutation M($input: ReplaceValuesInput!) { replaceValues(input: $input) } |}
227
+ it "returns a variable validation error" do
228
+ expected = {
229
+ "errors"=>[
230
+ {
231
+ "message" => "Variable input of type ReplaceValuesInput! was provided invalid value",
232
+ "locations" => [{ "line" => 1, "column" => 14 }],
233
+ "value" => nil,
234
+ "problems" => [
235
+ { "path" => [], "explanation" => "Expected value to not be null" }
236
+ ]
237
+ }
238
+ ]
239
+ }
240
+ assert_equal(expected, result)
241
+ end
242
+ end
243
+
224
244
  describe "for required input object fields" do
225
245
  let(:variables) { {"input" => {} } }
226
246
  let(:query_string) {%| mutation M($input: ReplaceValuesInput!) { replaceValues(input: $input) } |}
@@ -228,8 +248,12 @@ describe GraphQL::Query::Executor do
228
248
  expected = {
229
249
  "errors"=>[
230
250
  {
231
- "message" => "Variable input of type ReplaceValuesInput! was provided invalid value {}",
232
- "locations" => [{"line"=>1, "column"=>14}]
251
+ "message" => "Variable input of type ReplaceValuesInput! was provided invalid value",
252
+ "locations" => [{ "line" => 1, "column" => 14 }],
253
+ "value" => {},
254
+ "problems" => [
255
+ { "path" => ["values"], "explanation" => "Expected value to not be null" }
256
+ ]
233
257
  }
234
258
  ]
235
259
  }
@@ -244,8 +268,13 @@ describe GraphQL::Query::Executor do
244
268
  expected = {
245
269
  "errors"=>[
246
270
  {
247
- "message" => "Variable input of type [DairyProductInput] was provided invalid value [{\"foo\":\"bar\"}]",
248
- "locations" => [{"line"=>1, "column"=>11}]
271
+ "message" => "Variable input of type [DairyProductInput] was provided invalid value",
272
+ "locations" => [{ "line" => 1, "column" => 11 }],
273
+ "value" => [{ "foo" => "bar" }],
274
+ "problems" => [
275
+ { "path" => [0, "foo"], "explanation" => "Field is not defined on DairyProductInput" },
276
+ { "path" => [0, "source"], "explanation" => "Expected value to not be null" }
277
+ ]
249
278
  }
250
279
  ]
251
280
  }
@@ -244,7 +244,17 @@ describe GraphQL::Query do
244
244
  let(:query_variables) { {"cheeseId" => "2"} }
245
245
 
246
246
  it "raises an error" do
247
- assert_equal(result["errors"][0]["message"], %{Variable cheeseId of type Int! was provided invalid value "2"})
247
+ expected = {
248
+ "errors" => [
249
+ {
250
+ "message" => "Variable cheeseId of type Int! was provided invalid value",
251
+ "locations"=>[{ "line" => 2, "column" => 24 }],
252
+ "value" => "2",
253
+ "problems" => [{ "path" => [], "explanation" => 'Could not coerce value "2" to Int' }]
254
+ }
255
+ ]
256
+ }
257
+ assert_equal(expected, result)
248
258
  end
249
259
  end
250
260
 
@@ -252,8 +262,17 @@ describe GraphQL::Query do
252
262
  let(:query_variables) { {} }
253
263
 
254
264
  it "raises an error" do
255
- expected = "Variable cheeseId of type Int! can't be null"
256
- assert_equal(result["errors"][0]["message"], expected)
265
+ expected = {
266
+ "errors" => [
267
+ {
268
+ "message" => "Variable cheeseId of type Int! was provided invalid value",
269
+ "locations" => [{"line" => 2, "column" => 24}],
270
+ "value" => nil,
271
+ "problems" => [{ "path" => [], "explanation" => "Expected value to not be null" }]
272
+ }
273
+ ]
274
+ }
275
+ assert_equal(expected, result)
257
276
  end
258
277
  end
259
278
 
@@ -21,4 +21,32 @@ describe GraphQL::ScalarType do
21
21
  it 'coerces result value for serialization' do
22
22
  assert_equal(bignum.to_s, scalar.coerce_result(bignum))
23
23
  end
24
+
25
+ describe 'validate_input with good input' do
26
+ let(:result) { GraphQL::INT_TYPE.validate_input(150) }
27
+
28
+ it 'returns a valid result' do
29
+ assert(result.valid?)
30
+ end
31
+ end
32
+
33
+ describe 'validate_input with bad input' do
34
+ let(:result) { GraphQL::INT_TYPE.validate_input('bad num') }
35
+
36
+ it 'returns an invalid result for bad input' do
37
+ assert(!result.valid?)
38
+ end
39
+
40
+ it 'has one problem' do
41
+ assert_equal(result.problems.length, 1)
42
+ end
43
+
44
+ it 'has the correct explanation' do
45
+ assert(result.problems[0]['explanation'].include?('Could not coerce value'))
46
+ end
47
+
48
+ it 'has an empty path' do
49
+ assert(result.problems[0]['path'].empty?)
50
+ end
51
+ end
24
52
  end
@@ -5,10 +5,10 @@ describe GraphQL::Schema::TypeReducer do
5
5
  reducer = GraphQL::Schema::TypeReducer.new(CheeseType, {})
6
6
  expected = {
7
7
  "Cheese" => CheeseType,
8
- "Int" => GraphQL::INT_TYPE,
8
+ "Float" => GraphQL::FLOAT_TYPE,
9
9
  "String" => GraphQL::STRING_TYPE,
10
10
  "DairyAnimal" => DairyAnimalEnum,
11
- "Float" => GraphQL::FLOAT_TYPE,
11
+ "Int" => GraphQL::INT_TYPE,
12
12
  "Edible" => EdibleInterface,
13
13
  "Milk" => MilkType,
14
14
  "ID" => GraphQL::ID_TYPE,
@@ -0,0 +1,15 @@
1
+ # require "spec_helper"
2
+ #
3
+ # describe GraphQL::StaticValidation::ComplexityValidator do
4
+ # let(:document) { GraphQL.parse(query_string)}
5
+ # let(:validator) { GraphQL::StaticValidation::Validator.new(schema: DummySchema, rules: [complexity_validator]) }
6
+ # let(:errors) { validator.validate(document) }
7
+ # let(:complexity_validator) { GraphQL::StaticValidation::ComplexityValidator.new(max_fields: 6, list_multiplier: 2) }
8
+ #
9
+ # describe "too many fields" do
10
+ # it "adds errors if there are too many fields"
11
+ # it "counts fields for each time they're included from fragments"
12
+ # end
13
+ #
14
+ # it "multiplies fields inside list types"
15
+ # end
@@ -0,0 +1,93 @@
1
+ require "spec_helper"
2
+
3
+ describe GraphQL::StaticValidation::DocumentDoesNotExceedMaxDepth do
4
+ let(:rule) { GraphQL::StaticValidation::DocumentDoesNotExceedMaxDepth }
5
+ let(:validator) { GraphQL::StaticValidation::Validator.new(schema: DummySchema, rules: [rule]) }
6
+ let(:errors) { validator.validate(GraphQL.parse(query_string)) }
7
+
8
+ let(:query_string) { "
9
+ {
10
+ cheese(id: 1) {
11
+ similarCheese(source: SHEEP) {
12
+ similarCheese(source: SHEEP) {
13
+ similarCheese(source: SHEEP) {
14
+ similarCheese(source: SHEEP) {
15
+ similarCheese(source: SHEEP) {
16
+ id
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
22
+ }
23
+ }
24
+ "}
25
+
26
+ describe "when the query is deeper than max depth" do
27
+ it "adds an error message for a too-deep query" do
28
+ assert_equal 1, errors.length
29
+ end
30
+ end
31
+
32
+ describe "When the query is not deeper than max_depth" do
33
+ before do
34
+ @prev_max_depth = DummySchema.max_depth
35
+ DummySchema.max_depth = 100
36
+ end
37
+
38
+ after do
39
+ DummySchema.max_depth = @prev_max_depth
40
+ end
41
+
42
+ it "doesn't add an error" do
43
+ assert_equal 0, errors.length
44
+ end
45
+ end
46
+
47
+ describe "when the max depth isn't set" do
48
+ before do
49
+ @prev_max_depth = DummySchema.max_depth
50
+ DummySchema.max_depth = nil
51
+ end
52
+
53
+ after do
54
+ DummySchema.max_depth = @prev_max_depth
55
+ end
56
+
57
+ it "doesn't add an error message" do
58
+ assert_equal 0, errors.length
59
+ end
60
+ end
61
+
62
+ describe "when a fragment exceeds max depth" do
63
+ let(:query_string) { "
64
+ {
65
+ cheese(id: 1) {
66
+ ...moreFields
67
+ }
68
+ }
69
+
70
+ fragment moreFields on Cheese {
71
+ similarCheese(source: SHEEP) {
72
+ similarCheese(source: SHEEP) {
73
+ similarCheese(source: SHEEP) {
74
+ ...evenMoreFields
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ fragment evenMoreFields on Cheese {
81
+ similarCheese(source: SHEEP) {
82
+ similarCheese(source: SHEEP) {
83
+ id
84
+ }
85
+ }
86
+ }
87
+ "}
88
+
89
+ it "adds an error message for a too-deep query" do
90
+ assert_equal 1, errors.length
91
+ end
92
+ end
93
+ end
@@ -5,7 +5,7 @@ class NoSuchDairyError < StandardError; end
5
5
  EdibleInterface = GraphQL::InterfaceType.define do
6
6
  name "Edible"
7
7
  description "Something you can eat, yum"
8
- field :fatContent, !types.Float, "Percentage which is fat", property: :bogus_property
8
+ field :fatContent, !types.Float, "Percentage which is fat"
9
9
  field :origin, !types.String, "Place the edible comes from"
10
10
  end
11
11
 
@@ -65,7 +65,6 @@ MilkType = GraphQL::ObjectType.define do
65
65
  field :id, !types.ID
66
66
  field :source, DairyAnimalEnum, "Animal which produced this milk"
67
67
  field :origin, !types.String, "Place the milk comes from"
68
- field :fatContent, !types.Float, "Percentage which is milkfat"
69
68
  field :flavors, types[types.String], "Chocolate, Strawberry, etc" do
70
69
  argument :limit, types.Int
71
70
  resolve -> (milk, args, ctx) {
@@ -251,5 +250,6 @@ DummySchema = GraphQL::Schema.new(
251
250
  query: QueryType,
252
251
  mutation: MutationType,
253
252
  subscription: SubscriptionType,
253
+ max_depth: 5,
254
254
  )
255
255
  DummySchema.rescue_from(NoSuchDairyError) { |err| err.message }
@@ -1,13 +1,16 @@
1
1
  # This is the minimum required interface for an input object
2
2
  class MinimumInputObject
3
- KEY_VALUE_PAIRS = [["source", "COW"], ["fatContent", 0.4]]
3
+ include Enumerable
4
4
 
5
- def all?
6
- KEY_VALUE_PAIRS.all? { |pair| yield(pair) }
5
+ def initialize(values)
6
+ @values = values
7
+ end
8
+
9
+ def each(&block)
10
+ @values.each(&block)
7
11
  end
8
12
 
9
13
  def [](key)
10
- pair = KEY_VALUE_PAIRS.find { |k, v| k == key }
11
- pair[1]
14
+ @values[key]
12
15
  end
13
16
  end
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.11.0
4
+ version: 0.11.1
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-02-28 00:00:00.000000000 Z
11
+ date: 2016-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet
@@ -212,6 +212,7 @@ files:
212
212
  - lib/graphql/query/context.rb
213
213
  - lib/graphql/query/directive_chain.rb
214
214
  - lib/graphql/query/executor.rb
215
+ - lib/graphql/query/input_validation_result.rb
215
216
  - lib/graphql/query/literal_input.rb
216
217
  - lib/graphql/query/serial_execution.rb
217
218
  - lib/graphql/query/serial_execution/execution_context.rb
@@ -220,6 +221,7 @@ files:
220
221
  - lib/graphql/query/serial_execution/selection_resolution.rb
221
222
  - lib/graphql/query/serial_execution/value_resolution.rb
222
223
  - lib/graphql/query/type_resolver.rb
224
+ - lib/graphql/query/variable_validation_error.rb
223
225
  - lib/graphql/query/variables.rb
224
226
  - lib/graphql/repl.rb
225
227
  - lib/graphql/scalar_type.rb
@@ -243,6 +245,7 @@ files:
243
245
  - lib/graphql/static_validation/rules/argument_literals_are_compatible.rb
244
246
  - lib/graphql/static_validation/rules/arguments_are_defined.rb
245
247
  - lib/graphql/static_validation/rules/directives_are_defined.rb
248
+ - lib/graphql/static_validation/rules/document_does_not_exceed_max_depth.rb
246
249
  - lib/graphql/static_validation/rules/fields_are_defined_on_type.rb
247
250
  - lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb
248
251
  - lib/graphql/static_validation/rules/fields_will_merge.rb
@@ -257,6 +260,7 @@ files:
257
260
  - lib/graphql/static_validation/rules/variables_are_input_types.rb
258
261
  - lib/graphql/static_validation/rules/variables_are_used_and_defined.rb
259
262
  - lib/graphql/static_validation/type_stack.rb
263
+ - lib/graphql/static_validation/validation_context.rb
260
264
  - lib/graphql/static_validation/validator.rb
261
265
  - lib/graphql/string_type.rb
262
266
  - lib/graphql/type_kinds.rb
@@ -297,10 +301,11 @@ files:
297
301
  - spec/graphql/schema/type_reducer_spec.rb
298
302
  - spec/graphql/schema/type_validator_spec.rb
299
303
  - spec/graphql/schema_spec.rb
300
- - spec/graphql/static_validation/complexity_validator.rb
304
+ - spec/graphql/static_validation/complexity_validator_spec.rb
301
305
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
302
306
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
303
307
  - spec/graphql/static_validation/rules/directives_are_defined_spec.rb
308
+ - spec/graphql/static_validation/rules/document_does_not_exceed_max_depth_spec.rb
304
309
  - spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb
305
310
  - spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb
306
311
  - spec/graphql/static_validation/rules/fields_will_merge_spec.rb
@@ -383,10 +388,11 @@ test_files:
383
388
  - spec/graphql/schema/type_reducer_spec.rb
384
389
  - spec/graphql/schema/type_validator_spec.rb
385
390
  - spec/graphql/schema_spec.rb
386
- - spec/graphql/static_validation/complexity_validator.rb
391
+ - spec/graphql/static_validation/complexity_validator_spec.rb
387
392
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
388
393
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
389
394
  - spec/graphql/static_validation/rules/directives_are_defined_spec.rb
395
+ - spec/graphql/static_validation/rules/document_does_not_exceed_max_depth_spec.rb
390
396
  - spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb
391
397
  - spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb
392
398
  - spec/graphql/static_validation/rules/fields_will_merge_spec.rb
@@ -1,15 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe GraphQL::StaticValidation::ComplexityValidator do
4
- let(:document) { GraphQL.parse(query_string)}
5
- let(:validator) { GraphQL::StaticValidation::Validator.new(schema: DummySchema, rules: [complexity_validator]) }
6
- let(:errors) { validator.validate(document) }
7
- let(:complexity_validator) { GraphQL::StaticValidation::ComplexityValidator.new(max_fields: 6, list_multiplier: 2) }
8
-
9
- describe "too many fields" do
10
- it "adds errors if there are too many fields"
11
- it "counts fields for each time they're included from fragments"
12
- end
13
-
14
- it "multiplies fields inside list types"
15
- end