graphql 0.18.15 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/define/assign_global_id_field.rb +1 -2
- data/lib/graphql/directive.rb +41 -7
- data/lib/graphql/directive/deprecated_directive.rb +11 -0
- data/lib/graphql/directive/include_directive.rb +2 -2
- data/lib/graphql/directive/skip_directive.rb +2 -2
- data/lib/graphql/input_object_type.rb +14 -0
- data/lib/graphql/internal_representation/node.rb +8 -4
- data/lib/graphql/introspection/arguments_field.rb +0 -1
- data/lib/graphql/introspection/directive_location_enum.rb +3 -2
- data/lib/graphql/introspection/directive_type.rb +12 -7
- data/lib/graphql/introspection/enum_value_type.rb +4 -2
- data/lib/graphql/introspection/enum_values_field.rb +0 -1
- data/lib/graphql/introspection/field_type.rb +8 -7
- data/lib/graphql/introspection/fields_field.rb +0 -1
- data/lib/graphql/introspection/input_fields_field.rb +0 -1
- data/lib/graphql/introspection/input_value_type.rb +8 -10
- data/lib/graphql/introspection/interfaces_field.rb +0 -1
- data/lib/graphql/introspection/of_type_field.rb +0 -1
- data/lib/graphql/introspection/possible_types_field.rb +0 -1
- data/lib/graphql/introspection/schema_type.rb +11 -9
- data/lib/graphql/introspection/type_kind_enum.rb +3 -3
- data/lib/graphql/introspection/type_type.rb +9 -6
- data/lib/graphql/language/generation.rb +4 -1
- data/lib/graphql/language/lexer.rb +353 -316
- data/lib/graphql/language/lexer.rl +8 -6
- data/lib/graphql/language/nodes.rb +12 -0
- data/lib/graphql/language/parser.rb +553 -501
- data/lib/graphql/language/parser.y +26 -16
- data/lib/graphql/language/parser_tests.rb +20 -1
- data/lib/graphql/list_type.rb +5 -1
- data/lib/graphql/non_null_type.rb +4 -0
- data/lib/graphql/object_type.rb +1 -1
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/relay.rb +1 -1
- data/lib/graphql/relay/global_id_resolve.rb +3 -5
- data/lib/graphql/relay/node.rb +34 -0
- data/lib/graphql/scalar_type.rb +1 -1
- data/lib/graphql/schema.rb +43 -15
- data/lib/graphql/schema/loader.rb +2 -2
- data/lib/graphql/schema/printer.rb +50 -8
- data/lib/graphql/schema/unique_within_type.rb +28 -0
- data/lib/graphql/schema/validation.rb +10 -3
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +9 -1
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -2
- data/lib/graphql/type_kinds.rb +12 -12
- data/lib/graphql/version.rb +1 -1
- data/readme.md +6 -5
- data/spec/graphql/argument_spec.rb +1 -1
- data/spec/graphql/execution_error_spec.rb +53 -0
- data/spec/graphql/introspection/directive_type_spec.rb +10 -0
- data/spec/graphql/introspection/input_value_type_spec.rb +23 -0
- data/spec/graphql/language/generation_spec.rb +4 -0
- data/spec/graphql/query/executor_spec.rb +2 -2
- data/spec/graphql/relay/mutation_spec.rb +1 -1
- data/spec/graphql/relay/node_spec.rb +87 -0
- data/spec/graphql/schema/catchall_middleware_spec.rb +1 -1
- data/spec/graphql/schema/loader_spec.rb +37 -4
- data/spec/graphql/schema/printer_spec.rb +30 -7
- data/spec/graphql/schema/unique_within_type_spec.rb +27 -0
- data/spec/graphql/schema/validation_spec.rb +7 -11
- data/spec/graphql/schema_spec.rb +32 -2
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +14 -15
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +10 -10
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +1 -5
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +3 -5
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +7 -11
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +1 -4
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +10 -13
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +3 -5
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -4
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -6
- data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -4
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +7 -7
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -4
- data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -4
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -6
- data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -4
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +12 -14
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +7 -9
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +20 -22
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +27 -23
- data/spec/spec_helper.rb +1 -0
- data/spec/support/dairy_app.rb +2 -2
- data/spec/support/star_wars_schema.rb +15 -18
- data/spec/support/static_validation_helpers.rb +27 -0
- metadata +25 -5
- data/lib/graphql/relay/global_node_identification.rb +0 -138
- 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
|
-
|
|
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
|
-
|
|
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
|
76
|
-
|
|
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
|
159
|
-
|
|
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
|
183
|
-
|
|
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
|
191
|
-
|
|
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
|
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
|
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
|
-
|
|
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
|
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
|
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
|
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, "
|
557
|
+
assert_includes(e.message, "LCURLY")
|
539
558
|
assert_equal(3, e.line)
|
540
559
|
assert_equal(33, e.col)
|
541
560
|
end
|
data/lib/graphql/list_type.rb
CHANGED
@@ -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
|
data/lib/graphql/object_type.rb
CHANGED
@@ -11,7 +11,7 @@ module GraphQL
|
|
11
11
|
# field :director, PersonType
|
12
12
|
# field :cast, CastType
|
13
13
|
# field :starring, types[PersonType] do
|
14
|
-
#
|
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.
|
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,
|
data/lib/graphql/relay.rb
CHANGED
@@ -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(
|
5
|
-
@
|
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
|
-
|
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
|
data/lib/graphql/scalar_type.rb
CHANGED
data/lib/graphql/schema.rb
CHANGED
@@ -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,
|
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["
|
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(
|
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
|
61
|
-
def
|
62
|
-
|
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
|