graphql 0.18.15 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/define/assign_global_id_field.rb +1 -2
  3. data/lib/graphql/directive.rb +41 -7
  4. data/lib/graphql/directive/deprecated_directive.rb +11 -0
  5. data/lib/graphql/directive/include_directive.rb +2 -2
  6. data/lib/graphql/directive/skip_directive.rb +2 -2
  7. data/lib/graphql/input_object_type.rb +14 -0
  8. data/lib/graphql/internal_representation/node.rb +8 -4
  9. data/lib/graphql/introspection/arguments_field.rb +0 -1
  10. data/lib/graphql/introspection/directive_location_enum.rb +3 -2
  11. data/lib/graphql/introspection/directive_type.rb +12 -7
  12. data/lib/graphql/introspection/enum_value_type.rb +4 -2
  13. data/lib/graphql/introspection/enum_values_field.rb +0 -1
  14. data/lib/graphql/introspection/field_type.rb +8 -7
  15. data/lib/graphql/introspection/fields_field.rb +0 -1
  16. data/lib/graphql/introspection/input_fields_field.rb +0 -1
  17. data/lib/graphql/introspection/input_value_type.rb +8 -10
  18. data/lib/graphql/introspection/interfaces_field.rb +0 -1
  19. data/lib/graphql/introspection/of_type_field.rb +0 -1
  20. data/lib/graphql/introspection/possible_types_field.rb +0 -1
  21. data/lib/graphql/introspection/schema_type.rb +11 -9
  22. data/lib/graphql/introspection/type_kind_enum.rb +3 -3
  23. data/lib/graphql/introspection/type_type.rb +9 -6
  24. data/lib/graphql/language/generation.rb +4 -1
  25. data/lib/graphql/language/lexer.rb +353 -316
  26. data/lib/graphql/language/lexer.rl +8 -6
  27. data/lib/graphql/language/nodes.rb +12 -0
  28. data/lib/graphql/language/parser.rb +553 -501
  29. data/lib/graphql/language/parser.y +26 -16
  30. data/lib/graphql/language/parser_tests.rb +20 -1
  31. data/lib/graphql/list_type.rb +5 -1
  32. data/lib/graphql/non_null_type.rb +4 -0
  33. data/lib/graphql/object_type.rb +1 -1
  34. data/lib/graphql/query/literal_input.rb +1 -1
  35. data/lib/graphql/relay.rb +1 -1
  36. data/lib/graphql/relay/global_id_resolve.rb +3 -5
  37. data/lib/graphql/relay/node.rb +34 -0
  38. data/lib/graphql/scalar_type.rb +1 -1
  39. data/lib/graphql/schema.rb +43 -15
  40. data/lib/graphql/schema/loader.rb +2 -2
  41. data/lib/graphql/schema/printer.rb +50 -8
  42. data/lib/graphql/schema/unique_within_type.rb +28 -0
  43. data/lib/graphql/schema/validation.rb +10 -3
  44. data/lib/graphql/static_validation/rules/fields_will_merge.rb +9 -1
  45. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -2
  46. data/lib/graphql/type_kinds.rb +12 -12
  47. data/lib/graphql/version.rb +1 -1
  48. data/readme.md +6 -5
  49. data/spec/graphql/argument_spec.rb +1 -1
  50. data/spec/graphql/execution_error_spec.rb +53 -0
  51. data/spec/graphql/introspection/directive_type_spec.rb +10 -0
  52. data/spec/graphql/introspection/input_value_type_spec.rb +23 -0
  53. data/spec/graphql/language/generation_spec.rb +4 -0
  54. data/spec/graphql/query/executor_spec.rb +2 -2
  55. data/spec/graphql/relay/mutation_spec.rb +1 -1
  56. data/spec/graphql/relay/node_spec.rb +87 -0
  57. data/spec/graphql/schema/catchall_middleware_spec.rb +1 -1
  58. data/spec/graphql/schema/loader_spec.rb +37 -4
  59. data/spec/graphql/schema/printer_spec.rb +30 -7
  60. data/spec/graphql/schema/unique_within_type_spec.rb +27 -0
  61. data/spec/graphql/schema/validation_spec.rb +7 -11
  62. data/spec/graphql/schema_spec.rb +32 -2
  63. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +14 -15
  64. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +10 -10
  65. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +1 -5
  66. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +3 -5
  67. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +7 -11
  68. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +1 -4
  69. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +10 -13
  70. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +3 -5
  71. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -4
  72. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -6
  73. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -4
  74. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +7 -7
  75. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -4
  76. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -4
  77. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -6
  78. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -4
  79. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +12 -14
  80. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +7 -9
  81. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +20 -22
  82. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +27 -23
  83. data/spec/spec_helper.rb +1 -0
  84. data/spec/support/dairy_app.rb +2 -2
  85. data/spec/support/star_wars_schema.rb +15 -18
  86. data/spec/support/static_validation_helpers.rb +27 -0
  87. metadata +25 -5
  88. data/lib/graphql/relay/global_node_identification.rb +0 -138
  89. data/spec/graphql/relay/global_node_identification_spec.rb +0 -153
@@ -46,7 +46,7 @@ rule
46
46
 
47
47
  variable_definitions_opt:
48
48
  /* none */ { return [] }
49
- | RPAREN variable_definitions_list LPAREN { return val[1] }
49
+ | LPAREN variable_definitions_list RPAREN { return val[1] }
50
50
 
51
51
  variable_definitions_list:
52
52
  variable_definition { return [val[0]] }
@@ -65,15 +65,15 @@ rule
65
65
  type:
66
66
  name { return make_node(:TypeName, name: val[0])}
67
67
  | type BANG { return make_node(:NonNullType, of_type: val[0]) }
68
- | RBRACKET type LBRACKET { return make_node(:ListType, of_type: val[1]) }
68
+ | LBRACKET type RBRACKET { return make_node(:ListType, of_type: val[1]) }
69
69
 
70
70
  default_value_opt:
71
71
  /* none */ { return nil }
72
72
  | EQUALS input_value { return val[1] }
73
73
 
74
74
  selection_set:
75
- RCURLY LCURLY { return [] }
76
- | RCURLY selection_list LCURLY { return val[1] }
75
+ LCURLY RCURLY { return [] }
76
+ | LCURLY selection_list RCURLY { return val[1] }
77
77
 
78
78
  selection_set_opt:
79
79
  /* none */ { return [] }
@@ -155,8 +155,8 @@ rule
155
155
 
156
156
  arguments_opt:
157
157
  /* none */ { return [] }
158
- | RPAREN LPAREN { return [] }
159
- | RPAREN arguments_list LPAREN { return val[1] }
158
+ | LPAREN RPAREN { return [] }
159
+ | LPAREN arguments_list RPAREN { return val[1] }
160
160
 
161
161
  arguments_list:
162
162
  argument { return [val[0]] }
@@ -179,16 +179,16 @@ rule
179
179
  variable: VAR_SIGN name { return make_node(:VariableIdentifier, name: val[1], position_source: val[0]) }
180
180
 
181
181
  list_value:
182
- RBRACKET LBRACKET { return [] }
183
- | RBRACKET list_value_list LBRACKET { return val[1] }
182
+ LBRACKET RBRACKET { return [] }
183
+ | LBRACKET list_value_list RBRACKET { return val[1] }
184
184
 
185
185
  list_value_list:
186
186
  input_value { return [val[0]] }
187
187
  | list_value_list input_value { val[0] << val[1] }
188
188
 
189
189
  object_value:
190
- RCURLY LCURLY { return make_node(:InputObject, arguments: [], position_source: val[0])}
191
- | RCURLY object_value_list LCURLY { return make_node(:InputObject, arguments: val[1], position_source: val[0])}
190
+ LCURLY RCURLY { return make_node(:InputObject, arguments: [], position_source: val[0])}
191
+ | LCURLY object_value_list RCURLY { return make_node(:InputObject, arguments: val[1], position_source: val[0])}
192
192
 
193
193
  object_value_list:
194
194
  object_value_field { return [val[0]] }
@@ -249,9 +249,10 @@ rule
249
249
  type_system_definition:
250
250
  schema_definition
251
251
  | type_definition
252
+ | directive_definition
252
253
 
253
254
  schema_definition:
254
- SCHEMA RCURLY operation_type_definition_list LCURLY { return make_node(:SchemaDefinition, val[2]) }
255
+ SCHEMA LCURLY operation_type_definition_list RCURLY { return make_node(:SchemaDefinition, val[2]) }
255
256
 
256
257
  operation_type_definition_list:
257
258
  operation_type_definition
@@ -271,7 +272,7 @@ rule
271
272
  scalar_type_definition: SCALAR name directives_list_opt { return make_node(:ScalarTypeDefinition, name: val[1], directives: val[2]) }
272
273
 
273
274
  object_type_definition:
274
- TYPE name implements_opt directives_list_opt RCURLY field_definition_list LCURLY {
275
+ TYPE name implements_opt directives_list_opt LCURLY field_definition_list RCURLY {
275
276
  return make_node(:ObjectTypeDefinition, name: val[1], interfaces: val[2], directives: val[3], fields: val[5])
276
277
  }
277
278
 
@@ -290,7 +291,7 @@ rule
290
291
 
291
292
  arguments_definitions_opt:
292
293
  /* none */ { return [] }
293
- | RPAREN input_value_definition_list LPAREN { return val[1] }
294
+ | LPAREN input_value_definition_list RPAREN { return val[1] }
294
295
 
295
296
  field_definition:
296
297
  name arguments_definitions_opt COLON type directives_list_opt {
@@ -302,7 +303,7 @@ rule
302
303
  | field_definition_list field_definition { val[0] << val[1] }
303
304
 
304
305
  interface_type_definition:
305
- INTERFACE name directives_list_opt RCURLY field_definition_list LCURLY {
306
+ INTERFACE name directives_list_opt LCURLY field_definition_list RCURLY {
306
307
  return make_node(:InterfaceTypeDefinition, name: val[1], directives: val[2], fields: val[4])
307
308
  }
308
309
 
@@ -316,14 +317,23 @@ rule
316
317
  }
317
318
 
318
319
  enum_type_definition:
319
- ENUM name directives_list_opt RCURLY enum_value_definitions LCURLY {
320
+ ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY {
320
321
  return make_node(:EnumTypeDefinition, name: val[1], directives: val[2], values: val[4])
321
322
  }
322
323
 
323
324
  input_object_type_definition:
324
- INPUT name directives_list_opt RCURLY input_value_definition_list LCURLY {
325
+ INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY {
325
326
  return make_node(:InputObjectTypeDefinition, name: val[1], directives: val[2], fields: val[4])
326
327
  }
328
+
329
+ directive_definition:
330
+ DIRECTIVE DIR_SIGN name arguments_definitions_opt ON directive_locations {
331
+ return make_node(:DirectiveDefinition, name: val[2], arguments: val[3], locations: val[5])
332
+ }
333
+
334
+ directive_locations:
335
+ name { return [val[0].to_s] }
336
+ | directive_locations PIPE name { val[0] << val[2].to_s }
327
337
  end
328
338
 
329
339
  ---- header ----
@@ -380,6 +380,25 @@ module GraphQL
380
380
  assert_equal 'No longer supported', deprecated_directive.arguments[0].value
381
381
  end
382
382
 
383
+ it "parses directive definition" do
384
+ document = subject.parse('
385
+ directive @include(if: Boolean!)
386
+ on FIELD
387
+ | FRAGMENT_SPREAD
388
+ | INLINE_FRAGMENT
389
+ ')
390
+
391
+ type = document.definitions.first
392
+ assert_equal GraphQL::Language::Nodes::DirectiveDefinition, type.class
393
+ assert_equal 'include', type.name
394
+
395
+ assert_equal 1, type.arguments.length
396
+ assert_equal 'if', type.arguments[0].name
397
+ assert_equal 'Boolean', type.arguments[0].type.of_type.name
398
+
399
+ assert_equal ['FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'], type.locations
400
+ end
401
+
383
402
  it "parses scalar types" do
384
403
  document = subject.parse('scalar DateTime')
385
404
 
@@ -535,7 +554,7 @@ module GraphQL
535
554
  ")
536
555
  end
537
556
  assert_includes(e.message, '"{"')
538
- assert_includes(e.message, "RCURLY")
557
+ assert_includes(e.message, "LCURLY")
539
558
  assert_equal(3, e.line)
540
559
  assert_equal(33, e.col)
541
560
  end
@@ -53,7 +53,11 @@ module GraphQL
53
53
  end
54
54
 
55
55
  def coerce_non_null_input(value)
56
- ensure_array(value).map{ |item| of_type.coerce_input(item) }
56
+ ensure_array(value).map { |item| of_type.coerce_input(item) }
57
+ end
58
+
59
+ def coerce_result(value)
60
+ ensure_array(value).map { |item| item.nil? ? nil : of_type.coerce_result(item) }
57
61
  end
58
62
 
59
63
  private
@@ -57,6 +57,10 @@ module GraphQL
57
57
  of_type.coerce_input(value)
58
58
  end
59
59
 
60
+ def coerce_result(value)
61
+ of_type.coerce_result(value)
62
+ end
63
+
60
64
  def kind
61
65
  GraphQL::TypeKinds::NON_NULL
62
66
  end
@@ -11,7 +11,7 @@ module GraphQL
11
11
  # field :director, PersonType
12
12
  # field :cast, CastType
13
13
  # field :starring, types[PersonType] do
14
- # arguments :limit, types.Int
14
+ # argument :limit, types.Int
15
15
  # resolve -> (object, args, ctx) {
16
16
  # stars = object.cast.stars
17
17
  # args[:limit] && stars = stars.limit(args[:limit])
@@ -16,7 +16,7 @@ module GraphQL
16
16
  values_hash = {}
17
17
  argument_defns.each do |arg_name, arg_defn|
18
18
  ast_arg = ast_arguments.find { |ast_arg| ast_arg.name == arg_name }
19
- arg_default_value = arg_defn.type.coerce_input(arg_defn.default_value)
19
+ arg_default_value = arg_defn.default_value
20
20
  if ast_arg.nil? && arg_default_value.nil?
21
21
  # If it wasn't in the document,
22
22
  # and there's no provided default,
@@ -1,6 +1,5 @@
1
1
  require 'base64'
2
2
 
3
- require 'graphql/relay/global_node_identification'
4
3
  require 'graphql/relay/page_info'
5
4
  require 'graphql/relay/edge'
6
5
  require 'graphql/relay/edge_type'
@@ -9,6 +8,7 @@ require 'graphql/relay/array_connection'
9
8
  require 'graphql/relay/relation_connection'
10
9
  require 'graphql/relay/global_id_resolve'
11
10
  require 'graphql/relay/mutation'
11
+ require 'graphql/relay/node'
12
12
  require 'graphql/relay/connection_field'
13
13
  require 'graphql/relay/connection_resolve'
14
14
  require 'graphql/relay/connection_type'
@@ -1,14 +1,12 @@
1
1
  module GraphQL
2
2
  module Relay
3
3
  class GlobalIdResolve
4
- def initialize(type_name:, property:)
5
- @property = property
6
- @type_name = type_name
4
+ def initialize(type:)
5
+ @type = type
7
6
  end
8
7
 
9
8
  def call(obj, args, ctx)
10
- id_value = obj.public_send(@property)
11
- ctx.query.schema.node_identification.to_global_id(@type_name, id_value)
9
+ ctx.query.schema.id_from_object(obj, @type, ctx)
12
10
  end
13
11
  end
14
12
  end
@@ -0,0 +1,34 @@
1
+ module GraphQL
2
+ module Relay
3
+ # Helpers for working with Relay-specific Node objects.
4
+ module Node
5
+ # @return [GraphQL::Field] a field for finding objects by their global ID.
6
+ def self.field
7
+ # We have to define it fresh each time because
8
+ # its name will be modified and its description
9
+ # _may_ be modified.
10
+ GraphQL::Field.define do
11
+ type(GraphQL::Relay::Node.interface)
12
+ description("Fetches an object given its ID")
13
+ argument(:id, !types.ID, "ID of the object")
14
+ resolve(GraphQL::Relay::Node::FindNode)
15
+ end
16
+ end
17
+
18
+ # @return [GraphQL::InterfaceType] The interface which all Relay types must implement
19
+ def self.interface
20
+ @interface ||= GraphQL::InterfaceType.define do
21
+ name "Node"
22
+ field :id, !types.ID
23
+ end
24
+ end
25
+
26
+ # A field resolve for finding an object by ID
27
+ module FindNode
28
+ def self.call(obj, args, ctx)
29
+ ctx.query.schema.object_from_id(args[:id], ctx )
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -62,7 +62,7 @@ module GraphQL
62
62
 
63
63
  def coerce_result(value)
64
64
  ensure_defined
65
- @coerce_result_proc.call(value)
65
+ @coerce_result_proc ? @coerce_result_proc.call(value) : value
66
66
  end
67
67
 
68
68
  def coerce_result=(proc)
@@ -1,12 +1,13 @@
1
1
  require "graphql/schema/catchall_middleware"
2
2
  require "graphql/schema/invalid_type_error"
3
3
  require "graphql/schema/middleware_chain"
4
- require "graphql/schema/rescue_middleware"
5
4
  require "graphql/schema/possible_types"
5
+ require "graphql/schema/rescue_middleware"
6
6
  require "graphql/schema/reduce_types"
7
7
  require "graphql/schema/timeout_middleware"
8
8
  require "graphql/schema/type_expression"
9
9
  require "graphql/schema/type_map"
10
+ require "graphql/schema/unique_within_type"
10
11
  require "graphql/schema/validation"
11
12
 
12
13
  module GraphQL
@@ -47,8 +48,8 @@ module GraphQL
47
48
  :query, :mutation, :subscription,
48
49
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
49
50
  :max_depth, :max_complexity,
50
- :node_identification,
51
51
  :orphan_types, :resolve_type,
52
+ :object_from_id, :id_from_object,
52
53
  query_analyzer: -> (schema, analyzer) { schema.query_analyzers << analyzer },
53
54
  middleware: -> (schema, middleware) { schema.middleware << middleware },
54
55
  rescue_from: -> (schema, err_class, &block) { schema.rescue_from(err_class, &block)}
@@ -57,23 +58,16 @@ module GraphQL
57
58
  :query, :mutation, :subscription,
58
59
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
59
60
  :max_depth, :max_complexity,
60
- :orphan_types, :node_identification,
61
+ :orphan_types,
61
62
  :query_analyzers, :middleware
62
63
 
63
-
64
- DIRECTIVES = [GraphQL::Directive::SkipDirective, GraphQL::Directive::IncludeDirective]
64
+ DIRECTIVES = [GraphQL::Directive::SkipDirective, GraphQL::Directive::IncludeDirective, GraphQL::Directive::DeprecatedDirective]
65
65
  DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
66
- RESOLVE_TYPE_PROC_REQUIRED = -> (obj, ctx) { raise("Schema.resolve_type is undefined, can't resolve type for #{obj.inspect}") }
66
+ RESOLVE_TYPE_PROC_REQUIRED = -> (obj, ctx) { raise(NotImplementedError, "Schema.resolve_type is undefined, can't resolve type for #{obj.inspect}") }
67
+ OBJECT_FROM_ID_PROC_REQUIRED = -> (id, ctx) { raise(NotImplementedError, "Schema.object_from_id is undefined, can't fetch object for #{id.inspect}") }
68
+ ID_FROM_OBJECT_PROC_REQUIRED = -> (obj, type, ctx) { raise(NotImplementedError, "Schema.id_from_object is undefined, can't return an ID for #{obj.inspect}") }
67
69
 
68
- attr_reader :directives, :static_validator
69
-
70
- # @!attribute node_identification
71
- # @return [GraphQL::Relay::GlobalNodeIdentification] the node identification instance for this schema, when using Relay
72
-
73
- def node_identification=(new_node_ident)
74
- new_node_ident.schema = self
75
- @node_identification = new_node_ident
76
- end
70
+ attr_reader :directives, :static_validator, :object_from_id_proc, :id_from_object_proc
77
71
 
78
72
  # @!attribute [r] middleware
79
73
  # @return [Array<#call>] Middlewares suitable for MiddlewareChain, applied to fields during execution
@@ -99,6 +93,8 @@ module GraphQL
99
93
  @middleware = [@rescue_middleware]
100
94
  @query_analyzers = []
101
95
  @resolve_type_proc = RESOLVE_TYPE_PROC_REQUIRED
96
+ @object_from_id_proc = OBJECT_FROM_ID_PROC_REQUIRED
97
+ @id_from_object_proc = ID_FROM_OBJECT_PROC_REQUIRED
102
98
  # Default to the built-in execution strategy:
103
99
  @query_execution_strategy = GraphQL::Query::SerialExecution
104
100
  @mutation_execution_strategy = GraphQL::Query::SerialExecution
@@ -192,6 +188,8 @@ module GraphQL
192
188
 
193
189
  # Determine the GraphQL type for a given object.
194
190
  # This is required for unions and interfaces (include Relay's node interface)
191
+ # @param object [Any] An application object which GraphQL is currently resolving on
192
+ # @param ctx [GraphQL::Query::Context] The context for the current query
195
193
  # @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
196
194
  def resolve_type(object, ctx)
197
195
  ensure_defined
@@ -210,5 +208,35 @@ module GraphQL
210
208
  ensure_defined
211
209
  @resolve_type_proc = new_resolve_type_proc
212
210
  end
211
+
212
+ # Fetch an application object by its unique id
213
+ # @param id [String] A unique identifier, provided previously by this GraphQL schema
214
+ # @param ctx [GraphQL::Query::Context] The context for the current query
215
+ # @return [Any] The application object identified by `id`
216
+ def object_from_id(id, ctx)
217
+ ensure_defined
218
+ @object_from_id_proc.call(id, ctx)
219
+ end
220
+
221
+ # @param new_proc [#call] A new callable for fetching objects by ID
222
+ def object_from_id=(new_proc)
223
+ ensure_defined
224
+ @object_from_id_proc = new_proc
225
+ end
226
+
227
+ # Get a unique identifier from this object
228
+ # @param object [Any] An application object
229
+ # @param ctx [GraphQL::Query::Context] the context for the current query
230
+ # @return [String] a unique identifier for `object` which clients can use to refetch it
231
+ def id_from_object(type, object, ctx)
232
+ ensure_defined
233
+ @id_from_object_proc.call(type, object, ctx)
234
+ end
235
+
236
+ # @param new_proc [#call] A new callable for generating unique IDs
237
+ def id_from_object=(new_proc)
238
+ ensure_defined
239
+ @id_from_object_proc = new_proc
240
+ end
213
241
  end
214
242
  end
@@ -58,7 +58,7 @@ module GraphQL
58
58
  name: enum["name"],
59
59
  description: enum["description"],
60
60
  deprecation_reason: enum["deprecationReason"],
61
- value: enum["value"]
61
+ value: enum["name"]
62
62
  )
63
63
  })
64
64
  when "INTERFACE"
@@ -102,7 +102,7 @@ module GraphQL
102
102
  name: type["name"],
103
103
  type: type_resolver.call(type["type"]),
104
104
  description: type["description"],
105
- default_value: type["defaultValue"]
105
+ default_value: type["defaultValue"] ? JSON.parse(type["defaultValue"], quirks_mode: true) : nil
106
106
  )
107
107
  when "SCALAR"
108
108
  case type.fetch("name")
@@ -12,7 +12,7 @@ module GraphQL
12
12
  # Return a GraphQL schema string for the defined types in the schema
13
13
  # @param schema [GraphQL::Schema]
14
14
  def print_schema(schema)
15
- print_filtered_schema(schema, method(:is_defined_type))
15
+ print_filtered_schema(schema, lambda { |n| !is_spec_directive(n) }, method(:is_defined_type))
16
16
  end
17
17
 
18
18
  # Return the GraphQL schema string for the introspection type system
@@ -21,16 +21,20 @@ module GraphQL
21
21
  name "Query"
22
22
  end
23
23
  schema = GraphQL::Schema.define(query: query_root)
24
- print_filtered_schema(schema, method(:is_introspection_type))
24
+ print_filtered_schema(schema, method(:is_spec_directive), method(:is_introspection_type))
25
25
  end
26
26
 
27
27
  private
28
28
 
29
- def print_filtered_schema(schema, type_filter)
29
+ def print_filtered_schema(schema, directive_filter, type_filter)
30
+ directives = schema.directives.values.select{ |directive| directive_filter.call(directive) }
31
+ directive_definitions = directives.map{ |directive| print_directive(directive) }
32
+
30
33
  types = schema.types.values.select{ |type| type_filter.call(type) }.sort_by(&:name)
31
34
  type_definitions = types.map{ |type| print_type(type) }
32
35
 
33
- [print_schema_definition(schema)].concat(type_definitions).join("\n\n")
36
+ [print_schema_definition(schema)].concat(directive_definitions)
37
+ .concat(type_definitions).join("\n\n")
34
38
  end
35
39
 
36
40
  def print_schema_definition(schema)
@@ -44,6 +48,10 @@ module GraphQL
44
48
  BUILTIN_SCALARS = Set.new(["String", "Boolean", "Int", "Float", "ID"])
45
49
  private_constant :BUILTIN_SCALARS
46
50
 
51
+ def is_spec_directive(directive)
52
+ ['skip', 'include', 'deprecated'].include?(directive.name)
53
+ end
54
+
47
55
  def is_introspection_type(type)
48
56
  type.name.start_with?("__")
49
57
  end
@@ -56,12 +64,27 @@ module GraphQL
56
64
  TypeKindPrinters::STRATEGIES.fetch(type.kind).print(type)
57
65
  end
58
66
 
67
+ def print_directive(directive)
68
+ TypeKindPrinters::DirectivePrinter.print(directive)
69
+ end
70
+
59
71
  module TypeKindPrinters
60
- module FieldPrinter
61
- def print_fields(type)
62
- type.all_fields.map{ |field| " #{field.name}#{print_args(field)}: #{field.type}" }.join("\n")
72
+ module DeprecatedPrinter
73
+ def print_deprecated(field_or_enum_value)
74
+ return unless field_or_enum_value.deprecation_reason
75
+
76
+ case field_or_enum_value.deprecation_reason
77
+ when nil
78
+ ''
79
+ when '', GraphQL::Directive::DEFAULT_DEPRECATION_REASON
80
+ ' @deprecated'
81
+ else
82
+ " @deprecated(reason: #{field_or_enum_value.deprecation_reason.to_s.inspect})"
83
+ end
63
84
  end
85
+ end
64
86
 
87
+ module ArgsPrinter
65
88
  def print_args(field)
66
89
  return if field.arguments.empty?
67
90
  "(#{field.arguments.values.map{ |arg| print_input_value(arg) }.join(", ")})"
@@ -105,6 +128,24 @@ module GraphQL
105
128
  end
106
129
  end
107
130
 
131
+ module FieldPrinter
132
+ include DeprecatedPrinter
133
+ include ArgsPrinter
134
+ def print_fields(type)
135
+ type.all_fields.map{ |field|
136
+ " #{field.name}#{print_args(field)}: #{field.type}#{print_deprecated(field)}"
137
+ }.join("\n")
138
+ end
139
+ end
140
+
141
+ class DirectivePrinter
142
+ extend ArgsPrinter
143
+ def self.print(directive)
144
+ "directive @#{directive.name}#{print_args(directive)} "\
145
+ "on #{directive.locations.join(' | ')}"
146
+ end
147
+ end
148
+
108
149
  class ScalarPrinter
109
150
  def self.print(type)
110
151
  "scalar #{type.name}"
@@ -137,8 +178,9 @@ module GraphQL
137
178
  end
138
179
 
139
180
  class EnumPrinter
181
+ extend DeprecatedPrinter
140
182
  def self.print(type)
141
- values = type.values.values.map{ |v| " #{v.name}" }.join("\n")
183
+ values = type.values.values.map{ |v| " #{v.name}#{print_deprecated(v)}" }.join("\n")
142
184
  "enum #{type.name} {\n#{values}\n}"
143
185
  end
144
186
  end