graphql 0.11.0 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
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