graphql 0.12.0 → 0.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b779fe5af77f89213fae236cb0e7441bdfe4b0c1
4
- data.tar.gz: 457dc5cb4468a2c57f758162dc112db07e0801df
3
+ metadata.gz: 6682396f1618ee3660ec3120bf597c109d0e2752
4
+ data.tar.gz: 93a3813ff37f3eb9f4e447eda9aabd3db2688de3
5
5
  SHA512:
6
- metadata.gz: 1910cea7688e8ddd090ee5e7d64300a6ae39524e2ad5677a0552072ba4704a20213cbd25b9889900bcb2b610b6ff5aedfd9c2757614715aaf44ca4535a091ccd
7
- data.tar.gz: cfcbe1c03d9fd8b9ed510af1d64d24dacaf147b337d383eb7de6c596ed200f6a8c2b3c87deef8dfab3cdb7b421811d034a4516c3c6db0e3af089b94758d8cc16
6
+ metadata.gz: 09eb390035a47146f403a393c1695d7d6355a7d7573c70a277547113f2abad887cded1bb275fa7865c57df5631119487fdd3e50ddf859e705960fc0f67c8fe6e
7
+ data.tar.gz: d4bef1a775db4a7bd2d58a60c283bce67942ab41bfb551d3d1a7f8080ecdcfc2959d7c0f51872cb80016e77cca68bd04fbede2479217c4b994e6919fb68f86e8
@@ -18,11 +18,14 @@ class GraphQL::Schema
18
18
  # @param query [GraphQL::ObjectType] the query root for the schema
19
19
  # @param mutation [GraphQL::ObjectType] the mutation root for the schema
20
20
  # @param subscription [GraphQL::ObjectType] the subscription root for the schema
21
- def initialize(query:, mutation: nil, subscription: nil, max_depth: nil)
21
+ # @param max_depth [Integer] maximum query nesting (if it's greater, raise an error)
22
+ # @param types [Array<GraphQL::BaseType>] additional types to include in this schema
23
+ def initialize(query:, mutation: nil, subscription: nil, max_depth: nil, types: [])
22
24
  @query = query
23
25
  @mutation = mutation
24
26
  @subscription = subscription
25
27
  @max_depth = max_depth
28
+ @orphan_types = types
26
29
  @directives = DIRECTIVES.reduce({}) { |m, d| m[d.name] = d; m }
27
30
  @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
28
31
  @rescue_middleware = GraphQL::Schema::RescueMiddleware.new
@@ -37,7 +40,10 @@ class GraphQL::Schema
37
40
 
38
41
  # @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
39
42
  def types
40
- @types ||= TypeReducer.find_all([query, mutation, GraphQL::Introspection::SchemaType].compact)
43
+ @types ||= begin
44
+ all_types = @orphan_types + [query, mutation, GraphQL::Introspection::SchemaType]
45
+ TypeReducer.find_all(all_types.compact)
46
+ end
41
47
  end
42
48
 
43
49
  # Execute a query on itself.
@@ -8,10 +8,14 @@ module GraphQL
8
8
  # If you want a type, but want to handle the undefined case, use {#fetch}.
9
9
  class TypeMap
10
10
  extend Forwardable
11
- def_delegators :@storage, :key?, :keys, :values
11
+ def_delegators :@storage, :key?, :keys, :values, :fetch, :to_h
12
+
13
+ # Used for detecting deprecated interface member inferrance
14
+ attr_accessor :safely_discovered_types
12
15
 
13
16
  def initialize
14
17
  @storage = {}
18
+ @safely_discovered_types = []
15
19
  end
16
20
 
17
21
  def [](key)
@@ -26,8 +30,11 @@ module GraphQL
26
30
  end
27
31
  end
28
32
 
29
- def fetch(key, fallback_value)
30
- @storage.key?(key) ? @storage[key] : fallback_value
33
+ def warnings
34
+ interface_only_types = @storage.values - safely_discovered_types
35
+ interface_only_types.map do |unsafe_type|
36
+ "Type \"#{unsafe_type}\" was inferred from an interface's #possible_types. This won't be supported in the next version of GraphQL. Pass this type with the `types:` argument to `Schema.new` instead!"
37
+ end
31
38
  end
32
39
  end
33
40
  end
@@ -21,8 +21,13 @@ class GraphQL::Schema::TypeReducer
21
21
  def self.find_all(types)
22
22
  type_map = GraphQL::Schema::TypeMap.new
23
23
  types.reduce(type_map) do |memo, type|
24
- self.new(type, memo).result
24
+ type_map.safely_discovered_types << type
25
+ self.new(type.unwrap, memo).result
25
26
  end
27
+ type_map.warnings.each do |warning|
28
+ warn(warning)
29
+ end
30
+ type_map
26
31
  end
27
32
 
28
33
  private
@@ -34,22 +39,29 @@ class GraphQL::Schema::TypeReducer
34
39
  reduce_type(field.type, type_hash)
35
40
  field.arguments.each do |name, argument|
36
41
  reduce_type(argument.type, type_hash)
42
+ safely_discovered(type_hash, argument.type)
37
43
  end
44
+ safely_discovered(type_hash, field.type)
38
45
  end
39
46
  end
40
47
  if type.kind.object?
41
48
  type.interfaces.each do |interface|
42
49
  reduce_type(interface, type_hash)
50
+ safely_discovered(type_hash, interface)
43
51
  end
44
52
  end
45
53
  if type.kind.resolves?
46
54
  type.possible_types.each do |possible_type|
47
55
  reduce_type(possible_type, type_hash)
56
+ if type.kind.union?
57
+ safely_discovered(type_hash, possible_type)
58
+ end
48
59
  end
49
60
  end
50
61
  if type.kind.input_object?
51
62
  type.input_fields.each do |name, input_field|
52
63
  reduce_type(input_field.type, type_hash)
64
+ safely_discovered(type_hash, input_field.type)
53
65
  end
54
66
  end
55
67
 
@@ -72,4 +84,12 @@ class GraphQL::Schema::TypeReducer
72
84
  raise GraphQL::Schema::InvalidTypeError.new(type, errors)
73
85
  end
74
86
  end
87
+
88
+ def safely_discovered(type_hash, type)
89
+ inner_type = type.unwrap
90
+ if !type_hash.safely_discovered_types.include?(inner_type)
91
+
92
+ type_hash.safely_discovered_types << inner_type
93
+ end
94
+ end
75
95
  end
@@ -1,3 +1,3 @@
1
1
  module GraphQL
2
- VERSION = "0.12.0"
2
+ VERSION = "0.12.1"
3
3
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe GraphQL::InterfaceType do
4
4
  let(:interface) { EdibleInterface }
5
5
  it 'has possible types' do
6
- assert_equal([CheeseType, MilkType], interface.possible_types)
6
+ assert_equal([CheeseType, MilkType, HoneyType], interface.possible_types)
7
7
  end
8
8
 
9
9
  it 'resolves types for objects' do
@@ -57,7 +57,7 @@ describe GraphQL::Introspection::TypeType do
57
57
  "animalProduct" => {
58
58
  "name"=>"AnimalProduct",
59
59
  "kind"=>"INTERFACE",
60
- "possibleTypes"=>[{"name"=>"Cheese"}, {"name"=>"Milk"}],
60
+ "possibleTypes"=>[{"name"=>"Cheese"}, {"name"=>"Milk"}, {"name"=>"Honey"}],
61
61
  "fields"=>[
62
62
  {"name"=>"source"},
63
63
  ]
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GraphQL::Schema::TypeReducer do
4
+ let(:type_map) { GraphQL::Schema::TypeMap.new }
4
5
  it 'finds types from a single type and its fields' do
5
- reducer = GraphQL::Schema::TypeReducer.new(CheeseType, {})
6
+ reducer = GraphQL::Schema::TypeReducer.new(CheeseType, type_map)
6
7
  expected = {
7
8
  "Cheese" => CheeseType,
8
9
  "Float" => GraphQL::FLOAT_TYPE,
@@ -13,13 +14,14 @@ describe GraphQL::Schema::TypeReducer do
13
14
  "Milk" => MilkType,
14
15
  "ID" => GraphQL::ID_TYPE,
15
16
  "AnimalProduct" => AnimalProductInterface,
17
+ "Honey" => HoneyType,
16
18
  }
17
19
  assert_equal(expected.keys, reducer.result.keys)
18
- assert_equal(expected, reducer.result)
20
+ assert_equal(expected, reducer.result.to_h)
19
21
  end
20
22
 
21
23
  it 'finds type from arguments' do
22
- reducer = GraphQL::Schema::TypeReducer.new(QueryType, {})
24
+ reducer = GraphQL::Schema::TypeReducer.new(QueryType, type_map)
23
25
  assert_equal(DairyProductInputType, reducer.result["DairyProductInput"])
24
26
  end
25
27
 
@@ -34,13 +36,13 @@ describe GraphQL::Schema::TypeReducer do
34
36
  input_field :child, type_child
35
37
  end
36
38
 
37
- reducer = GraphQL::Schema::TypeReducer.new(type_parent, {})
39
+ reducer = GraphQL::Schema::TypeReducer.new(type_parent, type_map)
38
40
  expected = {
39
41
  "InputTypeParent" => type_parent,
40
42
  "InputTypeChild" => type_child,
41
43
  "String" => GraphQL::STRING_TYPE
42
44
  }
43
- assert_equal(expected, reducer.result)
45
+ assert_equal(expected, reducer.result.to_h)
44
46
  end
45
47
 
46
48
  describe 'when a type is invalid' do
@@ -59,12 +61,12 @@ describe GraphQL::Schema::TypeReducer do
59
61
  }
60
62
 
61
63
  it 'raises an InvalidTypeError when passed nil' do
62
- reducer = GraphQL::Schema::TypeReducer.new(invalid_type, {})
64
+ reducer = GraphQL::Schema::TypeReducer.new(invalid_type, type_map)
63
65
  assert_raises(GraphQL::Schema::InvalidTypeError) { reducer.result }
64
66
  end
65
67
 
66
68
  it 'raises an InvalidTypeError when passed an object that isnt a GraphQL::BaseType' do
67
- reducer = GraphQL::Schema::TypeReducer.new(another_invalid_type, {})
69
+ reducer = GraphQL::Schema::TypeReducer.new(another_invalid_type, type_map)
68
70
  assert_raises(GraphQL::Schema::InvalidTypeError) { reducer.result }
69
71
  end
70
72
  end
@@ -93,4 +95,21 @@ describe GraphQL::Schema::TypeReducer do
93
95
  assert_raises(RuntimeError) { type_map["SomeType"] }
94
96
  end
95
97
  end
98
+
99
+ describe "when a type can only be inferred through an interface" do
100
+ it "logs a warning" do
101
+ out, err = capture_io do
102
+ GraphQL::Schema::TypeReducer.find_all([EdibleInterface])
103
+ end
104
+ assert_match /Type "Milk" was inferred from an interface/, err
105
+ assert_match /Type "Honey" was inferred from an interface/, err
106
+ end
107
+
108
+ it "is ok if the types are passed in explicitly" do
109
+ out, err = capture_io do
110
+ GraphQL::Schema::TypeReducer.find_all([EdibleInterface, HoneyType, MilkType])
111
+ end
112
+ assert_equal "", err
113
+ end
114
+ end
96
115
  end
@@ -73,6 +73,13 @@ MilkType = GraphQL::ObjectType.define do
73
73
  end
74
74
  end
75
75
 
76
+ # No actual data; This type is an "orphan", only accessible through Interfaces
77
+ HoneyType = GraphQL::ObjectType.define do
78
+ name 'Honey'
79
+ description "Sweet, dehydrated bee barf"
80
+ interfaces [EdibleInterface, AnimalProductInterface]
81
+ end
82
+
76
83
  DairyType = GraphQL::ObjectType.define do
77
84
  name 'Dairy'
78
85
  description 'A farm where milk is harvested and cheese is produced'
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.12.0
4
+ version: 0.12.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-03-20 00:00:00.000000000 Z
11
+ date: 2016-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parslet
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: listen
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.0.0
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: minitest
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -243,7 +257,6 @@ files:
243
257
  - lib/graphql/static_validation.rb
244
258
  - lib/graphql/static_validation/all_rules.rb
245
259
  - lib/graphql/static_validation/arguments_validator.rb
246
- - lib/graphql/static_validation/complexity_validator.rb
247
260
  - lib/graphql/static_validation/literal_validator.rb
248
261
  - lib/graphql/static_validation/message.rb
249
262
  - lib/graphql/static_validation/rules/argument_literals_are_compatible.rb
@@ -310,7 +323,6 @@ files:
310
323
  - spec/graphql/schema/type_reducer_spec.rb
311
324
  - spec/graphql/schema/type_validator_spec.rb
312
325
  - spec/graphql/schema_spec.rb
313
- - spec/graphql/static_validation/complexity_validator_spec.rb
314
326
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
315
327
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
316
328
  - spec/graphql/static_validation/rules/directives_are_defined_spec.rb
@@ -333,7 +345,6 @@ files:
333
345
  - spec/graphql/string_type_spec.rb
334
346
  - spec/graphql/union_type_spec.rb
335
347
  - spec/spec_helper.rb
336
- - spec/support/calculator_schema.rb
337
348
  - spec/support/dairy_app.rb
338
349
  - spec/support/dairy_data.rb
339
350
  - spec/support/minimum_input_object.rb
@@ -403,7 +414,6 @@ test_files:
403
414
  - spec/graphql/schema/type_reducer_spec.rb
404
415
  - spec/graphql/schema/type_validator_spec.rb
405
416
  - spec/graphql/schema_spec.rb
406
- - spec/graphql/static_validation/complexity_validator_spec.rb
407
417
  - spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb
408
418
  - spec/graphql/static_validation/rules/arguments_are_defined_spec.rb
409
419
  - spec/graphql/static_validation/rules/directives_are_defined_spec.rb
@@ -426,7 +436,6 @@ test_files:
426
436
  - spec/graphql/string_type_spec.rb
427
437
  - spec/graphql/union_type_spec.rb
428
438
  - spec/spec_helper.rb
429
- - spec/support/calculator_schema.rb
430
439
  - spec/support/dairy_app.rb
431
440
  - spec/support/dairy_data.rb
432
441
  - spec/support/minimum_input_object.rb
@@ -1,27 +0,0 @@
1
- class GraphQL::StaticValidation::ComplexityValidator
2
- include GraphQL::StaticValidation::Message::MessageHelper
3
-
4
- def initialize(max_fields:, list_multiplier:)
5
- @max_fields = max_fields
6
- @list_multiplier = list_multiplier
7
- end
8
-
9
- def validate(context)
10
- visitor = context.visitor
11
- complexity = 0
12
- visitor[GraphQL::Language::Nodes::Field] << -> (node, parent) {
13
- field_type = field_definition.type
14
- if field_type.kind.list?
15
- complexity += list_multiplier
16
- else
17
- complexity += 1
18
- end
19
- }
20
-
21
- visitor[GraphQL::Language::Nodes::Document].exit << -> (node, parent) {
22
- if complexity > @max_fields
23
- context.errors << message("This query is too complex. Request fewer fields.", node)
24
- end
25
- }
26
- end
27
- end
@@ -1,15 +0,0 @@
1
- # require "spec_helper"
2
- #
3
- # describe GraphQL::StaticValidation::ComplexityValidator do
4
- # let(:query_string) {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
@@ -1,74 +0,0 @@
1
- # This GraphQL Schema performs operations on numbers.
2
- # It can perform operations on values you give it and return values
3
- # It also maintains some state which can be updated or read
4
- module Calculator
5
- # You can reduce a list of values to a single value
6
- REDUCERS = {
7
- "SUM" => -> (values) { [values.inject(&:+)] },
8
- "MAX" => :max.to_proc,
9
- "MIN" => :min.to_proc,
10
- }
11
-
12
- ReducerEnum = GraphQL::EnumType.define do
13
- REDUCERS.map do |op_name, op_proc|
14
- value(op_name)
15
- end
16
- end
17
-
18
- # You can make a new list by transforming each member
19
- MAPPERS = {
20
- "ADD" => -> (val, arg) { val + arg },
21
- "SUB" => -> (val, arg) { val - arg },
22
- "EQ" => -> (val, arg) { val == arg ? 1 : 0},
23
- }
24
-
25
- MapperEnum = GraphQL::EnumType.define do
26
- MAPPERS.map do |op_name, op_proc|
27
- value(op_name)
28
- end
29
- end
30
-
31
- # Input a list of integers
32
- ListOfInts = GraphQL::INT_TYPE.to_list_type
33
-
34
- # Expose a list of values and perform operations
35
- ValuesType = GraphQL::ObjectType.define do
36
- field :values, ListOfInts do
37
- resolve -> (obj, _args, _ctx) { obj }
38
- end
39
-
40
- # Get a single value based on the values in this list
41
- field :reduce, types.Int do
42
- argument :operation, !ReducerEnum
43
- resolve -> (obj, args, ctx) {
44
- reduce_name = args[:operation]
45
- reduce_fn = REDUCERS[reduce_name]
46
- reduce_fn.call(obj)
47
- }
48
- end
49
-
50
- # Handle self-referential fields by wrapping the type in a proc.
51
- # It will be lazy-eval'ed
52
- field :map, -> { ValuesType } do
53
- argument :operation, !MapperEnum
54
- argument :argument, !types.Int
55
- resolve -> (obj, args, ctx) {
56
- op_arg = args[:argument]
57
- op_name = args[:operation]
58
- op_func = MAPPERS[op_name]
59
- obj.map { |item| op_func.call(item, op_arg) }
60
- }
61
- end
62
- end
63
-
64
- QueryType = GraphQL::ObjectType.define do
65
- name("Query")
66
-
67
- field :perform, ValuesType do
68
- argument :initial, !ListOfInts
69
- resolve -> (obj, args, ctx) { args[:initial] }
70
- end
71
- end
72
-
73
- Schema = GraphQL::Schema.new(query: QueryType)
74
- end