graphql 1.6.4 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +47 -0
  3. data/lib/generators/graphql/install_generator.rb +15 -20
  4. data/lib/generators/graphql/mutation_generator.rb +31 -1
  5. data/lib/generators/graphql/templates/mutation.erb +2 -2
  6. data/lib/generators/graphql/templates/mutation_type.erb +5 -0
  7. data/lib/generators/graphql/templates/schema.erb +0 -1
  8. data/lib/graphql/argument.rb +6 -5
  9. data/lib/graphql/backwards_compatibility.rb +18 -4
  10. data/lib/graphql/base_type.rb +1 -1
  11. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +1 -1
  12. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -1
  13. data/lib/graphql/compatibility/lazy_execution_specification.rb +9 -2
  14. data/lib/graphql/define.rb +1 -0
  15. data/lib/graphql/define/defined_object_proxy.rb +1 -1
  16. data/lib/graphql/define/no_definition_error.rb +7 -0
  17. data/lib/graphql/enum_type.rb +4 -0
  18. data/lib/graphql/execution/execute.rb +3 -3
  19. data/lib/graphql/execution/field_result.rb +1 -1
  20. data/lib/graphql/execution/lazy/resolve.rb +10 -9
  21. data/lib/graphql/execution/multiplex.rb +6 -5
  22. data/lib/graphql/input_object_type.rb +5 -1
  23. data/lib/graphql/interface_type.rb +12 -3
  24. data/lib/graphql/query.rb +21 -5
  25. data/lib/graphql/query/context.rb +11 -0
  26. data/lib/graphql/schema.rb +48 -27
  27. data/lib/graphql/schema/build_from_definition.rb +1 -1
  28. data/lib/graphql/schema/build_from_definition/resolve_map.rb +2 -2
  29. data/lib/graphql/schema/loader.rb +1 -1
  30. data/lib/graphql/schema/traversal.rb +91 -0
  31. data/lib/graphql/schema/validation.rb +1 -1
  32. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +41 -7
  33. data/lib/graphql/union_type.rb +13 -2
  34. data/lib/graphql/version.rb +1 -1
  35. data/readme.md +1 -3
  36. data/spec/generators/graphql/install_generator_spec.rb +3 -1
  37. data/spec/generators/graphql/mutation_generator_spec.rb +14 -0
  38. data/spec/graphql/analysis/max_query_complexity_spec.rb +12 -1
  39. data/spec/graphql/analysis/query_complexity_spec.rb +1 -1
  40. data/spec/graphql/argument_spec.rb +29 -0
  41. data/spec/graphql/define/assign_argument_spec.rb +4 -4
  42. data/spec/graphql/define/instance_definable_spec.rb +1 -1
  43. data/spec/graphql/enum_type_spec.rb +8 -0
  44. data/spec/graphql/execution/lazy_spec.rb +30 -3
  45. data/spec/graphql/interface_type_spec.rb +44 -0
  46. data/spec/graphql/introspection/schema_type_spec.rb +3 -0
  47. data/spec/graphql/introspection/type_type_spec.rb +1 -0
  48. data/spec/graphql/object_type_spec.rb +8 -3
  49. data/spec/graphql/query/context_spec.rb +18 -0
  50. data/spec/graphql/query/executor_spec.rb +1 -1
  51. data/spec/graphql/query/literal_input_spec.rb +31 -15
  52. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -1
  53. data/spec/graphql/query/variables_spec.rb +25 -1
  54. data/spec/graphql/query_spec.rb +24 -9
  55. data/spec/graphql/relay/mutation_spec.rb +1 -1
  56. data/spec/graphql/schema/build_from_definition_spec.rb +1 -1
  57. data/spec/graphql/schema/loader_spec.rb +1 -1
  58. data/spec/graphql/schema/printer_spec.rb +1 -1
  59. data/spec/graphql/schema/{reduce_types_spec.rb → traversal_spec.rb} +21 -4
  60. data/spec/graphql/schema/warden_spec.rb +1 -1
  61. data/spec/graphql/schema_spec.rb +23 -2
  62. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +133 -0
  63. data/spec/graphql/union_type_spec.rb +53 -0
  64. data/spec/spec_helper.rb +9 -0
  65. data/spec/support/dummy/data.rb +14 -5
  66. data/spec/support/dummy/schema.rb +46 -5
  67. data/spec/support/star_wars/data.rb +10 -6
  68. data/spec/support/star_wars/schema.rb +5 -2
  69. metadata +8 -7
  70. data/lib/graphql/schema/instrumented_field_map.rb +0 -40
  71. data/lib/graphql/schema/reduce_types.rb +0 -69
  72. data/lib/graphql/schema/type_map.rb +0 -31
@@ -26,6 +26,59 @@ describe GraphQL::UnionType do
26
26
  assert_equal(false, union.include?(type_3))
27
27
  end
28
28
 
29
+ it '#resolve_type raises error if resolved type is not in possible_types' do
30
+ test_str = 'Hello world'
31
+ union.resolve_type = ->(value, ctx) {
32
+ "This is not the types you are looking for"
33
+ }
34
+ fake_ctx = OpenStruct.new(query: GraphQL::Query.new(Dummy::Schema, ""))
35
+
36
+ assert_raises(RuntimeError) {
37
+ union.resolve_type(test_str, fake_ctx)
38
+ }
39
+ end
40
+
41
+ describe "#resolve_type" do
42
+ let(:result) { Dummy::Schema.execute(query_string) }
43
+ let(:query_string) {%|
44
+ {
45
+ allAnimal {
46
+ type: __typename
47
+ ... on Cow {
48
+ cowName: name
49
+ }
50
+ ... on Goat {
51
+ goatName: name
52
+ }
53
+ }
54
+
55
+ allAnimalAsCow {
56
+ type: __typename
57
+ ... on Cow {
58
+ name
59
+ }
60
+ }
61
+ }
62
+ |}
63
+
64
+ it 'returns correct types for general schema and specific union' do
65
+ expected_result = {
66
+ # When using Query#resolve_type
67
+ "allAnimal" => [
68
+ { "type" => "Cow", "cowName" => "Billy" },
69
+ { "type" => "Goat", "goatName" => "Gilly" }
70
+ ],
71
+
72
+ # When using UnionType#resolve_type
73
+ "allAnimalAsCow" => [
74
+ { "type" => "Cow", "name" => "Billy" },
75
+ { "type" => "Cow", "name" => "Gilly" }
76
+ ]
77
+ }
78
+ assert_equal expected_result, result["data"]
79
+ end
80
+ end
81
+
29
82
  describe "typecasting from union to union" do
30
83
  let(:result) { Dummy::Schema.execute(query_string) }
31
84
  let(:query_string) {%|
data/spec/spec_helper.rb CHANGED
@@ -6,10 +6,12 @@ require "rails/all"
6
6
  require "rails/generators"
7
7
  require "jdbc/sqlite3" if RUBY_ENGINE == 'jruby'
8
8
  require "sqlite3" if RUBY_ENGINE == 'ruby'
9
+ require "pg" if RUBY_ENGINE == 'ruby'
9
10
  require "sequel"
10
11
  require "graphql"
11
12
  require "graphql/rake_task"
12
13
  require "benchmark"
14
+ require "pry"
13
15
  require "minitest/autorun"
14
16
  require "minitest/focus"
15
17
  require "minitest/reporters"
@@ -24,9 +26,11 @@ Minitest.backtrace_filter = Minitest::BacktraceFilter.new
24
26
 
25
27
  # This is for convenient access to metadata in test definitions
26
28
  assign_metadata_key = ->(target, key, value) { target.metadata[key] = value }
29
+ assign_metadata_flag = ->(target, flag) { target.metadata[flag] = true }
27
30
  GraphQL::BaseType.accepts_definitions(metadata: assign_metadata_key)
28
31
  GraphQL::Field.accepts_definitions(metadata: assign_metadata_key)
29
32
  GraphQL::Argument.accepts_definitions(metadata: assign_metadata_key)
33
+ GraphQL::Argument.accepts_definitions(metadata_flag: assign_metadata_flag)
30
34
  GraphQL::EnumType::EnumValue.accepts_definitions(metadata: assign_metadata_key)
31
35
 
32
36
  # Can be used as a GraphQL::Schema::Warden for some purposes, but allows nothing
@@ -36,6 +40,11 @@ module NothingWarden
36
40
  end
37
41
  end
38
42
 
43
+ # Use this when a schema requires a `resolve_type` hook
44
+ # but you know it won't be called
45
+ NO_OP_RESOLVE_TYPE = ->(type, obj, ctx) {
46
+ raise "this should never be called"
47
+ }
39
48
  # Load support files
40
49
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
41
50
 
@@ -6,6 +6,11 @@ module Dummy
6
6
  # This is buggy on purpose -- it shouldn't be called during execution.
7
7
  other.id == id
8
8
  end
9
+
10
+ # Alias for when this is treated as milk in EdibleAsMilkInterface
11
+ def fatContent # rubocop:disable Style/MethodName
12
+ fat_content
13
+ end
9
14
  end
10
15
 
11
16
  CHEESES = {
@@ -25,9 +30,13 @@ module Dummy
25
30
  milks: [MILKS[1]]
26
31
  )
27
32
 
28
- COW = OpenStruct.new(
29
- id: 1,
30
- name: "Billy",
31
- last_produced_dairy: MILKS[1]
32
- )
33
+ Cow = Struct.new(:id, :name, :last_produced_dairy)
34
+ COWS = {
35
+ 1 => Cow.new(1, "Billy", MILKS[1])
36
+ }
37
+
38
+ Goat = Struct.new(:id, :name, :last_produced_dairy)
39
+ GOATS = {
40
+ 1 => Goat.new(1, "Gilly", MILKS[1]),
41
+ }
33
42
  end
@@ -21,6 +21,12 @@ module Dummy
21
21
  field :selfAsEdible, EdibleInterface, resolve: ->(o, a, c) { o }
22
22
  end
23
23
 
24
+ EdibleAsMilkInterface = EdibleInterface.redefine do
25
+ name "EdibleAsMilk"
26
+ description "Milk :+1:"
27
+ resolve_type ->(obj, ctx) { MilkType }
28
+ end
29
+
24
30
  AnimalProductInterface = GraphQL::InterfaceType.define do
25
31
  name "AnimalProduct"
26
32
  description "Comes from an animal, no joke"
@@ -48,7 +54,7 @@ module Dummy
48
54
  name "Cheese"
49
55
  class_names ["Cheese"]
50
56
  description "Cultured dairy product"
51
- interfaces [EdibleInterface, AnimalProductInterface, LocalProductInterface]
57
+ interfaces [EdibleInterface, EdibleAsMilkInterface, AnimalProductInterface, LocalProductInterface]
52
58
 
53
59
  # Can have (name, type, desc)
54
60
  field :id, !types.Int, "Unique identifier"
@@ -96,7 +102,7 @@ module Dummy
96
102
  MilkType = GraphQL::ObjectType.define do
97
103
  name "Milk"
98
104
  description "Dairy beverage"
99
- interfaces [EdibleInterface, AnimalProductInterface, LocalProductInterface]
105
+ interfaces [EdibleInterface, EdibleAsMilkInterface, AnimalProductInterface, LocalProductInterface]
100
106
  field :id, !types.ID
101
107
  field :source, !DairyAnimalEnum, "Animal which produced this milk", hash_key: :source
102
108
  field :origin, !types.String, "Place the milk comes from"
@@ -152,7 +158,7 @@ module Dummy
152
158
 
153
159
  CowType = GraphQL::ObjectType.define do
154
160
  name "Cow"
155
- description "A farm where milk is harvested and cheese is produced"
161
+ description "A bovine animal that produces milk"
156
162
  field :id, !types.ID
157
163
  field :name, types.String
158
164
  field :last_produced_dairy, DairyProductUnion
@@ -168,6 +174,29 @@ module Dummy
168
174
  end
169
175
  end
170
176
 
177
+ GoatType = GraphQL::ObjectType.define do
178
+ name "Goat"
179
+ description "An caprinae animal that produces milk"
180
+ field :id, !types.ID
181
+ field :name, types.String
182
+ field :last_produced_dairy, DairyProductUnion
183
+ end
184
+
185
+ AnimalUnion = GraphQL::UnionType.define do
186
+ name "Animal"
187
+ description "Species of living things"
188
+ possible_types [CowType, GoatType]
189
+ end
190
+
191
+ AnimalAsCowUnion = GraphQL::UnionType.define do
192
+ name "AnimalAsCow"
193
+ description "All animals go mooooo!"
194
+ possible_types [CowType]
195
+ resolve_type ->(obj, ctx) {
196
+ CowType
197
+ }
198
+ end
199
+
171
200
  ResourceOrderType = GraphQL::InputObjectType.define {
172
201
  name "ResourceOrderType"
173
202
  description "Properties used to determine ordering"
@@ -271,7 +300,7 @@ module Dummy
271
300
  field :dairy, function: GetSingleton.new(type: DairyType, data: DAIRY)
272
301
  field :fromSource, &SourceFieldDefn
273
302
  field :favoriteEdible, FavoriteFieldDefn
274
- field :cow, function: GetSingleton.new(type: CowType, data: COW)
303
+ field :cow, function: GetSingleton.new(type: CowType, data: COWS[1])
275
304
  field :searchDairy do
276
305
  description "Find dairy products matching a description"
277
306
  type !DairyProductUnion
@@ -287,6 +316,14 @@ module Dummy
287
316
  }
288
317
  end
289
318
 
319
+ field :allAnimal, !types[AnimalUnion] do
320
+ resolve ->(obj, args, ctx) { COWS.values + GOATS.values }
321
+ end
322
+
323
+ field :allAnimalAsCow, !types[AnimalAsCowUnion] do
324
+ resolve ->(obj, args, ctx) { COWS.values + GOATS.values }
325
+ end
326
+
290
327
  field :allDairy, types[DairyProductUnion] do
291
328
  argument :executionErrorAtIndex, types.Int
292
329
  resolve ->(obj, args, ctx) {
@@ -300,6 +337,10 @@ module Dummy
300
337
  resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
301
338
  end
302
339
 
340
+ field :allEdibleAsMilk, types[EdibleAsMilkInterface] do
341
+ resolve ->(obj, args, ctx) { CHEESES.values + MILKS.values }
342
+ end
343
+
303
344
  field :error do
304
345
  description "Raise an error"
305
346
  type GraphQL::STRING_TYPE
@@ -375,7 +416,7 @@ module Dummy
375
416
 
376
417
  rescue_from(NoSuchDairyError) { |err| err.message }
377
418
 
378
- resolve_type ->(obj, ctx) {
419
+ resolve_type ->(type, obj, ctx) {
379
420
  Schema.types[obj.class.name.split("::").last]
380
421
  }
381
422
  end
@@ -21,10 +21,20 @@ module StarWars
21
21
  # ActiveRecord::Base.logger = Logger.new(STDOUT)
22
22
  `rm -f ./_test_.db`
23
23
  # Set up "Bases" in ActiveRecord
24
+
24
25
  if jruby?
25
26
  ActiveRecord::Base.establish_connection(adapter: "jdbcsqlite3", database: "./_test_.db")
27
+ Sequel.connect('jdbc:sqlite:./_test_.db')
28
+ elsif ENV['DATABASE'] == 'POSTGRESQL'
29
+ ActiveRecord::Base.establish_connection(
30
+ adapter: "postgresql",
31
+ username: "postgres",
32
+ database: "graphql_ruby_test"
33
+ )
34
+ DB = Sequel.connect('postgres://postgres:@localhost:5432/graphql_ruby_test')
26
35
  else
27
36
  ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: "./_test_.db")
37
+ DB = Sequel.sqlite("./_test_.db")
28
38
  end
29
39
 
30
40
  ActiveRecord::Schema.define do
@@ -46,12 +56,6 @@ module StarWars
46
56
  Base.create!(name: "Shield Generator", planet: "Endor", faction_id: 2)
47
57
  Base.create!(name: "Headquarters", planet: "Coruscant", faction_id: 2)
48
58
 
49
- # Also, set up Bases with Sequel
50
- DB = if jruby?
51
- Sequel.connect('jdbc:sqlite:./_test_.db')
52
- else
53
- Sequel.sqlite("./_test_.db")
54
- end
55
59
  class SequelBase < Sequel::Model(:bases)
56
60
  end
57
61
 
@@ -304,7 +304,10 @@ module StarWars
304
304
 
305
305
  connection :newestBasesGroupedByFaction, BaseType.connection_type do
306
306
  resolve ->(obj, args, ctx) {
307
- Base.order('sum(faction_id) desc').group(:faction_id)
307
+ Base
308
+ .having('id in (select max(id) from bases group by faction_id)')
309
+ .group(:id)
310
+ .order('faction_id desc')
308
311
  }
309
312
  end
310
313
 
@@ -359,7 +362,7 @@ module StarWars
359
362
  mutation(MutationType)
360
363
  default_max_page_size 3
361
364
 
362
- resolve_type ->(object, ctx) {
365
+ resolve_type ->(type, object, ctx) {
363
366
  if object == :test_error
364
367
  :not_a_type
365
368
  elsif object.is_a?(Base)
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: 1.6.4
4
+ version: 1.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-20 00:00:00.000000000 Z
11
+ date: 2017-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -299,6 +299,7 @@ extra_rdoc_files: []
299
299
  files:
300
300
  - ".yardopts"
301
301
  - MIT-LICENSE
302
+ - lib/generators/graphql/core.rb
302
303
  - lib/generators/graphql/enum_generator.rb
303
304
  - lib/generators/graphql/function_generator.rb
304
305
  - lib/generators/graphql/install_generator.rb
@@ -312,6 +313,7 @@ files:
312
313
  - lib/generators/graphql/templates/interface.erb
313
314
  - lib/generators/graphql/templates/loader.erb
314
315
  - lib/generators/graphql/templates/mutation.erb
316
+ - lib/generators/graphql/templates/mutation_type.erb
315
317
  - lib/generators/graphql/templates/object.erb
316
318
  - lib/generators/graphql/templates/query_type.erb
317
319
  - lib/generators/graphql/templates/schema.erb
@@ -351,6 +353,7 @@ files:
351
353
  - lib/graphql/define/assign_object_field.rb
352
354
  - lib/graphql/define/defined_object_proxy.rb
353
355
  - lib/graphql/define/instance_definable.rb
356
+ - lib/graphql/define/no_definition_error.rb
354
357
  - lib/graphql/define/non_null_with_bang.rb
355
358
  - lib/graphql/define/type_definer.rb
356
359
  - lib/graphql/directive.rb
@@ -465,18 +468,16 @@ files:
465
468
  - lib/graphql/schema/catchall_middleware.rb
466
469
  - lib/graphql/schema/default_parse_error.rb
467
470
  - lib/graphql/schema/default_type_error.rb
468
- - lib/graphql/schema/instrumented_field_map.rb
469
471
  - lib/graphql/schema/invalid_type_error.rb
470
472
  - lib/graphql/schema/loader.rb
471
473
  - lib/graphql/schema/middleware_chain.rb
472
474
  - lib/graphql/schema/null_mask.rb
473
475
  - lib/graphql/schema/possible_types.rb
474
476
  - lib/graphql/schema/printer.rb
475
- - lib/graphql/schema/reduce_types.rb
476
477
  - lib/graphql/schema/rescue_middleware.rb
477
478
  - lib/graphql/schema/timeout_middleware.rb
479
+ - lib/graphql/schema/traversal.rb
478
480
  - lib/graphql/schema/type_expression.rb
479
- - lib/graphql/schema/type_map.rb
480
481
  - lib/graphql/schema/unique_within_type.rb
481
482
  - lib/graphql/schema/validation.rb
482
483
  - lib/graphql/schema/warden.rb
@@ -600,9 +601,9 @@ files:
600
601
  - spec/graphql/schema/loader_spec.rb
601
602
  - spec/graphql/schema/middleware_chain_spec.rb
602
603
  - spec/graphql/schema/printer_spec.rb
603
- - spec/graphql/schema/reduce_types_spec.rb
604
604
  - spec/graphql/schema/rescue_middleware_spec.rb
605
605
  - spec/graphql/schema/timeout_middleware_spec.rb
606
+ - spec/graphql/schema/traversal_spec.rb
606
607
  - spec/graphql/schema/type_expression_spec.rb
607
608
  - spec/graphql/schema/unique_within_type_spec.rb
608
609
  - spec/graphql/schema/validation_spec.rb
@@ -750,9 +751,9 @@ test_files:
750
751
  - spec/graphql/schema/loader_spec.rb
751
752
  - spec/graphql/schema/middleware_chain_spec.rb
752
753
  - spec/graphql/schema/printer_spec.rb
753
- - spec/graphql/schema/reduce_types_spec.rb
754
754
  - spec/graphql/schema/rescue_middleware_spec.rb
755
755
  - spec/graphql/schema/timeout_middleware_spec.rb
756
+ - spec/graphql/schema/traversal_spec.rb
756
757
  - spec/graphql/schema/type_expression_spec.rb
757
758
  - spec/graphql/schema/unique_within_type_spec.rb
758
759
  - spec/graphql/schema/validation_spec.rb
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Schema
4
- # A two-level map with fields as the last values.
5
- # The first level is type names, which point to a second map.
6
- # The second level is field names, which point to fields.
7
- #
8
- # The catch is, the fields in this map _may_ have been modified by being instrumented.
9
- class InstrumentedFieldMap
10
- # Build a map using types from `schema` and instrumenters in `field_instrumenters`
11
- # @param schema [GraphQL::Schema]
12
- # @param field_instrumenters [Array<#instrument(type, field)>]
13
- def initialize(schema, field_instrumenters)
14
- @storage = Hash.new { |h, k| h[k] = {} }
15
- schema.types.each do |type_name, type|
16
- if type.kind.fields?
17
- type.all_fields.each do |field_defn|
18
- instrumented_field_defn = field_instrumenters.reduce(field_defn) do |defn, inst|
19
- inst.instrument(type, defn)
20
- end
21
- self.set(type.name, field_defn.name, instrumented_field_defn)
22
- end
23
- end
24
- end
25
- end
26
-
27
- def set(type_name, field_name, field)
28
- @storage[type_name][field_name] = field
29
- end
30
-
31
- def get(type_name, field_name)
32
- @storage[type_name][field_name]
33
- end
34
-
35
- def get_all(type_name)
36
- @storage[type_name]
37
- end
38
- end
39
- end
40
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Schema
4
- module ReduceTypes
5
- # @param types [Array<GraphQL::BaseType>] members of a schema to crawl for all member types
6
- # @return [GraphQL::Schema::TypeMap] `{name => Type}` pairs derived from `types`
7
- def self.reduce(types)
8
- type_map = GraphQL::Schema::TypeMap.new
9
- types.each do |type|
10
- reduce_type(type, type_map, type.name)
11
- end
12
- type_map
13
- end
14
-
15
- private
16
-
17
- # Based on `type`, add members to `type_hash`.
18
- # If `type` has already been visited, just return the `type_hash` as-is
19
- def self.reduce_type(type, type_hash, context_description)
20
- if !type.is_a?(GraphQL::BaseType)
21
- message = "#{context_description} has an invalid type: must be an instance of GraphQL::BaseType, not #{type.class.inspect} (#{type.inspect})"
22
- raise GraphQL::Schema::InvalidTypeError.new(message)
23
- end
24
-
25
- type = type.unwrap
26
-
27
- # Don't re-visit a type
28
- if !type_hash.fetch(type.name, nil).equal?(type)
29
- validate_type(type, context_description)
30
- type_hash[type.name] = type
31
- crawl_type(type, type_hash, context_description)
32
- end
33
- end
34
-
35
- def self.crawl_type(type, type_hash, context_description)
36
- if type.kind.fields?
37
- type.all_fields.each do |field|
38
- reduce_type(field.type, type_hash, "Field #{type.name}.#{field.name}")
39
- field.arguments.each do |name, argument|
40
- reduce_type(argument.type, type_hash, "Argument #{name} on #{type.name}.#{field.name}")
41
- end
42
- end
43
- end
44
- if type.kind.object?
45
- type.interfaces.each do |interface|
46
- reduce_type(interface, type_hash, "Interface on #{type.name}")
47
- end
48
- end
49
- if type.kind.union?
50
- type.possible_types.each do |possible_type|
51
- reduce_type(possible_type, type_hash, "Possible type for #{type.name}")
52
- end
53
- end
54
- if type.kind.input_object?
55
- type.arguments.each do |argument_name, argument|
56
- reduce_type(argument.type, type_hash, "Input field #{type.name}.#{argument_name}")
57
- end
58
- end
59
- end
60
-
61
- def self.validate_type(type, context_description)
62
- error_message = GraphQL::Schema::Validation.validate(type)
63
- if error_message
64
- raise GraphQL::Schema::InvalidTypeError.new("#{context_description} is invalid: #{error_message}")
65
- end
66
- end
67
- end
68
- end
69
- end