graphql 0.18.15 → 0.19.0

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 (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