graphql 1.7.7 → 1.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/enum_type.rb +1 -1
- data/lib/graphql/field.rb +10 -1
- data/lib/graphql/input_object_type.rb +3 -1
- data/lib/graphql/introspection/arguments_field.rb +1 -0
- data/lib/graphql/introspection/enum_values_field.rb +1 -0
- data/lib/graphql/introspection/fields_field.rb +1 -0
- data/lib/graphql/introspection/input_fields_field.rb +1 -0
- data/lib/graphql/introspection/interfaces_field.rb +1 -0
- data/lib/graphql/introspection/of_type_field.rb +1 -0
- data/lib/graphql/introspection/possible_types_field.rb +1 -0
- data/lib/graphql/introspection/schema_field.rb +1 -0
- data/lib/graphql/introspection/type_by_name_field.rb +1 -0
- data/lib/graphql/introspection/typename_field.rb +1 -0
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/language/document_from_schema_definition.rb +129 -37
- data/lib/graphql/language/generation.rb +3 -182
- data/lib/graphql/language/nodes.rb +12 -2
- data/lib/graphql/language/parser.rb +63 -55
- data/lib/graphql/language/parser.y +2 -1
- data/lib/graphql/language/printer.rb +351 -0
- data/lib/graphql/object_type.rb +1 -1
- data/lib/graphql/query/arguments.rb +27 -9
- data/lib/graphql/query/literal_input.rb +4 -1
- data/lib/graphql/schema/printer.rb +33 -266
- data/lib/graphql/tracing/scout_tracing.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
- data/spec/graphql/language/generation_spec.rb +21 -186
- data/spec/graphql/language/nodes_spec.rb +21 -0
- data/spec/graphql/language/printer_spec.rb +203 -0
- data/spec/graphql/query/arguments_spec.rb +33 -11
- data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
- data/spec/graphql/schema/printer_spec.rb +14 -14
- metadata +5 -2
data/lib/graphql/object_type.rb
CHANGED
@@ -32,7 +32,7 @@ module GraphQL
|
|
32
32
|
# @return [Hash<String => GraphQL::Field>] Map String fieldnames to their {GraphQL::Field} implementations
|
33
33
|
|
34
34
|
# @!attribute mutation
|
35
|
-
# @return [GraphQL::Relay::Mutation, nil] The mutation this
|
35
|
+
# @return [GraphQL::Relay::Mutation, nil] The mutation this object type was derived from, if it is an auto-generated payload type.
|
36
36
|
|
37
37
|
def initialize
|
38
38
|
super
|
@@ -12,8 +12,8 @@ module GraphQL
|
|
12
12
|
argument_owner.arguments_class = Class.new(self) do
|
13
13
|
self.argument_definitions = argument_definitions
|
14
14
|
|
15
|
-
def initialize(values)
|
16
|
-
super(values, argument_definitions: self.class.argument_definitions)
|
15
|
+
def initialize(values, defaults_used)
|
16
|
+
super(values, argument_definitions: self.class.argument_definitions, defaults_used: defaults_used)
|
17
17
|
end
|
18
18
|
|
19
19
|
argument_definitions.each do |_arg_name, arg_definition|
|
@@ -36,13 +36,16 @@ module GraphQL
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def initialize(values, argument_definitions:)
|
39
|
+
def initialize(values, argument_definitions:, defaults_used:)
|
40
40
|
@argument_values = values.inject({}) do |memo, (inner_key, inner_value)|
|
41
|
-
|
41
|
+
arg_name = inner_key.to_s
|
42
|
+
|
43
|
+
arg_defn = argument_definitions[arg_name]
|
44
|
+
arg_default_used = defaults_used.include?(arg_name)
|
42
45
|
|
43
46
|
arg_value = wrap_value(inner_value, arg_defn.type)
|
44
47
|
string_key = arg_defn.expose_as
|
45
|
-
memo[string_key] = ArgumentValue.new(string_key, arg_value, arg_defn)
|
48
|
+
memo[string_key] = ArgumentValue.new(string_key, arg_value, arg_defn, arg_default_used)
|
46
49
|
memo
|
47
50
|
end
|
48
51
|
end
|
@@ -61,6 +64,13 @@ module GraphQL
|
|
61
64
|
@argument_values.key?(key_s)
|
62
65
|
end
|
63
66
|
|
67
|
+
# @param key [String, Symbol] name of value to access
|
68
|
+
# @return [Boolean] true if the argument default was passed as the argument value to the resolver
|
69
|
+
def default_used?(key)
|
70
|
+
key_s = key.is_a?(String) ? key : key.to_s
|
71
|
+
@argument_values.fetch(key_s, NULL_ARGUMENT_VALUE).default_used?
|
72
|
+
end
|
73
|
+
|
64
74
|
# Get the hash of all values, with stringified keys
|
65
75
|
# @return [Hash] the stringified hash
|
66
76
|
def to_h
|
@@ -85,7 +95,7 @@ module GraphQL
|
|
85
95
|
end
|
86
96
|
end
|
87
97
|
|
88
|
-
NO_ARGS = self.new({}, argument_definitions: [])
|
98
|
+
NO_ARGS = self.new({}, argument_definitions: [], defaults_used: Set.new)
|
89
99
|
|
90
100
|
class << self
|
91
101
|
attr_accessor :argument_definitions
|
@@ -95,14 +105,22 @@ module GraphQL
|
|
95
105
|
|
96
106
|
class ArgumentValue
|
97
107
|
attr_reader :key, :value, :definition
|
98
|
-
|
108
|
+
attr_writer :default_used
|
109
|
+
|
110
|
+
def initialize(key, value, definition, default_used)
|
99
111
|
@key = key
|
100
112
|
@value = value
|
101
113
|
@definition = definition
|
114
|
+
@default_used = default_used
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Boolean] true if the argument default was passed as the argument value to the resolver
|
118
|
+
def default_used?
|
119
|
+
@default_used
|
102
120
|
end
|
103
121
|
end
|
104
122
|
|
105
|
-
NULL_ARGUMENT_VALUE = ArgumentValue.new(nil, nil, nil)
|
123
|
+
NULL_ARGUMENT_VALUE = ArgumentValue.new(nil, nil, nil, nil)
|
106
124
|
|
107
125
|
def wrap_value(value, arg_defn_type)
|
108
126
|
if value.nil?
|
@@ -115,7 +133,7 @@ module GraphQL
|
|
115
133
|
wrap_value(value, arg_defn_type.of_type)
|
116
134
|
when GraphQL::InputObjectType
|
117
135
|
if value.is_a?(Hash)
|
118
|
-
arg_defn_type.arguments_class.new(value)
|
136
|
+
arg_defn_type.arguments_class.new(value, Set.new)
|
119
137
|
else
|
120
138
|
value
|
121
139
|
end
|
@@ -49,6 +49,8 @@ module GraphQL
|
|
49
49
|
def self.from_arguments(ast_arguments, argument_owner, variables)
|
50
50
|
context = variables ? variables.context : nil
|
51
51
|
values_hash = {}
|
52
|
+
defaults_used = Set.new
|
53
|
+
|
52
54
|
indexed_arguments = case ast_arguments
|
53
55
|
when Hash
|
54
56
|
ast_arguments
|
@@ -93,6 +95,7 @@ module GraphQL
|
|
93
95
|
# then add the default value.
|
94
96
|
if arg_defn.default_value? && !values_hash.key?(arg_name)
|
95
97
|
value = arg_defn.default_value
|
98
|
+
defaults_used << arg_name
|
96
99
|
# `context` isn't present when pre-calculating defaults
|
97
100
|
if context
|
98
101
|
value = arg_defn.prepare(value, context)
|
@@ -105,7 +108,7 @@ module GraphQL
|
|
105
108
|
end
|
106
109
|
end
|
107
110
|
|
108
|
-
argument_owner.arguments_class.new(values_hash)
|
111
|
+
argument_owner.arguments_class.new(values_hash, defaults_used)
|
109
112
|
end
|
110
113
|
end
|
111
114
|
end
|
@@ -36,7 +36,7 @@ module GraphQL
|
|
36
36
|
# printer = GraphQL::Schema::Printer.new(MySchema)
|
37
37
|
# puts printer.print_type(post_type)
|
38
38
|
#
|
39
|
-
class Printer
|
39
|
+
class Printer < GraphQL::Language::Printer
|
40
40
|
attr_reader :schema, :warden
|
41
41
|
|
42
42
|
# @param schema [GraphQL::Schema]
|
@@ -45,21 +45,32 @@ module GraphQL
|
|
45
45
|
# @param except [<#call(member, ctx)>]
|
46
46
|
# @param introspection [Boolean] Should include the introspection types in the string?
|
47
47
|
def initialize(schema, context: nil, only: nil, except: nil, introspection: false)
|
48
|
-
@
|
49
|
-
|
48
|
+
@document_from_schema = GraphQL::Language::DocumentFromSchemaDefinition.new(
|
49
|
+
schema,
|
50
|
+
context: context,
|
51
|
+
only: only,
|
52
|
+
except: except,
|
53
|
+
include_introspection_types: introspection,
|
54
|
+
)
|
55
|
+
|
56
|
+
@document = @document_from_schema.document
|
50
57
|
|
51
|
-
|
52
|
-
filter = GraphQL::Filter.new(except: blacklist)
|
53
|
-
@warden = GraphQL::Schema::Warden.new(filter, schema: @schema, context: @context)
|
58
|
+
@schema = schema
|
54
59
|
end
|
55
60
|
|
56
61
|
# Return the GraphQL schema string for the introspection type system
|
57
62
|
def self.print_introspection_schema
|
58
63
|
query_root = ObjectType.define(name: "Root")
|
59
64
|
schema = GraphQL::Schema.define(query: query_root)
|
60
|
-
|
61
|
-
|
62
|
-
|
65
|
+
|
66
|
+
introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
|
67
|
+
schema,
|
68
|
+
except: ->(member, _) { member.name == "Root" },
|
69
|
+
include_introspection_types: true,
|
70
|
+
include_built_in_directives: true,
|
71
|
+
).document
|
72
|
+
|
73
|
+
introspection_schema_ast.to_query_string(printer: IntrospectionPrinter.new)
|
63
74
|
end
|
64
75
|
|
65
76
|
# Return a GraphQL schema string for the defined types in the schema
|
@@ -74,277 +85,33 @@ module GraphQL
|
|
74
85
|
|
75
86
|
# Return a GraphQL schema string for the defined types in the schema
|
76
87
|
def print_schema
|
77
|
-
|
78
|
-
|
79
|
-
printable_types = warden.types.reject(&:default_scalar?)
|
80
|
-
|
81
|
-
type_definitions = printable_types
|
82
|
-
.sort_by(&:name)
|
83
|
-
.map { |type| print_type(type) }
|
84
|
-
|
85
|
-
[print_schema_definition].compact
|
86
|
-
.concat(directive_definitions)
|
87
|
-
.concat(type_definitions).join("\n\n")
|
88
|
+
print(@document)
|
88
89
|
end
|
89
90
|
|
90
91
|
def print_type(type)
|
91
|
-
|
92
|
+
node = @document_from_schema.build_object_type_node(type)
|
93
|
+
print(node)
|
92
94
|
end
|
93
95
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
IS_USER_DEFINED_MEMBER = ->(member) {
|
98
|
-
case member
|
99
|
-
when GraphQL::BaseType
|
100
|
-
!member.introspection?
|
101
|
-
when GraphQL::Directive
|
102
|
-
!member.default_directive?
|
103
|
-
else
|
104
|
-
true
|
105
|
-
end
|
106
|
-
}
|
107
|
-
|
108
|
-
private_constant :IS_USER_DEFINED_MEMBER
|
96
|
+
def print_directive(directive)
|
97
|
+
if directive.name == "deprecated"
|
98
|
+
reason = directive.arguments.find { |arg| arg.name == "reason" }
|
109
99
|
|
110
|
-
|
111
|
-
|
112
|
-
if only
|
113
|
-
->(m, ctx) { !only.call(m, ctx) }
|
114
|
-
elsif except
|
115
|
-
except
|
100
|
+
if reason.value == GraphQL::Directive::DEFAULT_DEPRECATION_REASON
|
101
|
+
"@deprecated"
|
116
102
|
else
|
117
|
-
|
103
|
+
"@deprecated(reason: \"#{reason.value}\")"
|
118
104
|
end
|
119
105
|
else
|
120
|
-
|
121
|
-
->(m, ctx) { !(IS_USER_DEFINED_MEMBER.call(m) && only.call(m, ctx)) }
|
122
|
-
elsif except
|
123
|
-
->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) || except.call(m, ctx) }
|
124
|
-
else
|
125
|
-
->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) }
|
126
|
-
end
|
106
|
+
super
|
127
107
|
end
|
128
108
|
end
|
129
109
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
(schema.subscription.nil? || schema.subscription.name == 'Subscription')
|
134
|
-
return
|
110
|
+
class IntrospectionPrinter < GraphQL::Language::Printer
|
111
|
+
def print_schema_definition(schema)
|
112
|
+
"schema {\n query: Root\n}"
|
135
113
|
end
|
136
|
-
|
137
|
-
operations = [:query, :mutation, :subscription].map do |operation_type|
|
138
|
-
object_type = schema.public_send(operation_type)
|
139
|
-
# Special treatment for the introspection schema, which prints `{ query: "Root" }`
|
140
|
-
if object_type && (warden.get_type(object_type.name) || (object_type.name == "Root" && schema.query == object_type))
|
141
|
-
" #{operation_type}: #{object_type.name}\n"
|
142
|
-
else
|
143
|
-
nil
|
144
|
-
end
|
145
|
-
end.compact.join
|
146
|
-
"schema {\n#{operations}}"
|
147
|
-
end
|
148
|
-
|
149
|
-
def print_directive(directive)
|
150
|
-
TypeKindPrinters::DirectivePrinter.print(warden, directive)
|
151
|
-
end
|
152
|
-
|
153
|
-
module TypeKindPrinters
|
154
|
-
module DeprecatedPrinter
|
155
|
-
def print_deprecated(field_or_enum_value)
|
156
|
-
return unless field_or_enum_value.deprecation_reason
|
157
|
-
|
158
|
-
case field_or_enum_value.deprecation_reason
|
159
|
-
when nil
|
160
|
-
''
|
161
|
-
when '', GraphQL::Directive::DEFAULT_DEPRECATION_REASON
|
162
|
-
' @deprecated'
|
163
|
-
else
|
164
|
-
" @deprecated(reason: #{field_or_enum_value.deprecation_reason.to_s.inspect})"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
module DescriptionPrinter
|
170
|
-
def print_description(definition, indentation='', first_in_block=true)
|
171
|
-
return '' unless definition.description
|
172
|
-
|
173
|
-
description = indentation != '' && !first_in_block ? "\n".dup : "".dup
|
174
|
-
description << GraphQL::Language::Comments.commentize(definition.description, indent: indentation)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
module ArgsPrinter
|
179
|
-
include DescriptionPrinter
|
180
|
-
def print_args(warden, field, indentation = '')
|
181
|
-
arguments = warden.arguments(field)
|
182
|
-
return if arguments.empty?
|
183
|
-
|
184
|
-
if arguments.all?{ |arg| !arg.description }
|
185
|
-
return "(#{arguments.map{ |arg| print_input_value(arg) }.join(", ")})"
|
186
|
-
end
|
187
|
-
|
188
|
-
out = "(\n".dup
|
189
|
-
out << arguments.sort_by(&:name).map.with_index{ |arg, i|
|
190
|
-
"#{print_description(arg, " #{indentation}", i == 0)} #{indentation}"\
|
191
|
-
"#{print_input_value(arg)}"
|
192
|
-
}.join("\n")
|
193
|
-
out << "\n#{indentation})"
|
194
|
-
end
|
195
|
-
|
196
|
-
def print_input_value(arg)
|
197
|
-
if arg.default_value?
|
198
|
-
default_string = " = #{print_value(arg.default_value, arg.type)}"
|
199
|
-
else
|
200
|
-
default_string = nil
|
201
|
-
end
|
202
|
-
|
203
|
-
"#{arg.name}: #{arg.type.to_s}#{default_string}"
|
204
|
-
end
|
205
|
-
|
206
|
-
def print_value(value, type)
|
207
|
-
case type
|
208
|
-
when FLOAT_TYPE
|
209
|
-
return 'null' if value.nil?
|
210
|
-
value.to_f.inspect
|
211
|
-
when INT_TYPE
|
212
|
-
return 'null' if value.nil?
|
213
|
-
value.to_i.inspect
|
214
|
-
when BOOLEAN_TYPE
|
215
|
-
return 'null' if value.nil?
|
216
|
-
(!!value).inspect
|
217
|
-
when ScalarType, ID_TYPE, STRING_TYPE
|
218
|
-
return 'null' if value.nil?
|
219
|
-
value.to_s.inspect
|
220
|
-
when EnumType
|
221
|
-
return 'null' if value.nil?
|
222
|
-
type.coerce_isolated_result(value)
|
223
|
-
when InputObjectType
|
224
|
-
return 'null' if value.nil?
|
225
|
-
fields = value.to_h.map{ |field_name, field_value|
|
226
|
-
field_type = type.input_fields.fetch(field_name.to_s).type
|
227
|
-
"#{field_name}: #{print_value(field_value, field_type)}"
|
228
|
-
}.join(", ")
|
229
|
-
"{#{fields}}"
|
230
|
-
when NonNullType
|
231
|
-
print_value(value, type.of_type)
|
232
|
-
when ListType
|
233
|
-
return 'null' if value.nil?
|
234
|
-
"[#{value.to_a.map{ |v| print_value(v, type.of_type) }.join(", ")}]"
|
235
|
-
else
|
236
|
-
raise NotImplementedError, "Unexpected value type #{type.inspect}"
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
module FieldPrinter
|
242
|
-
include DeprecatedPrinter
|
243
|
-
include ArgsPrinter
|
244
|
-
include DescriptionPrinter
|
245
|
-
def print_fields(warden, type)
|
246
|
-
fields = warden.fields(type)
|
247
|
-
fields.sort_by(&:name).map.with_index { |field, i|
|
248
|
-
"#{print_description(field, ' ', i == 0)}"\
|
249
|
-
" #{field.name}#{print_args(warden, field, ' ')}: #{field.type}#{print_deprecated(field)}"
|
250
|
-
}.join("\n")
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
class DirectivePrinter
|
255
|
-
extend ArgsPrinter
|
256
|
-
extend DescriptionPrinter
|
257
|
-
def self.print(warden, directive)
|
258
|
-
"#{print_description(directive)}"\
|
259
|
-
"directive @#{directive.name}#{print_args(warden, directive)} "\
|
260
|
-
"on #{directive.locations.join(' | ')}"
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
class ScalarPrinter
|
265
|
-
extend DescriptionPrinter
|
266
|
-
def self.print(warden, type)
|
267
|
-
"#{print_description(type)}"\
|
268
|
-
"scalar #{type.name}"
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
class ObjectPrinter
|
273
|
-
extend FieldPrinter
|
274
|
-
extend DescriptionPrinter
|
275
|
-
def self.print(warden, type)
|
276
|
-
interfaces = warden.interfaces(type)
|
277
|
-
if interfaces.any?
|
278
|
-
implementations = " implements #{interfaces.sort_by(&:name).map(&:to_s).join(", ")}"
|
279
|
-
else
|
280
|
-
implementations = nil
|
281
|
-
end
|
282
|
-
|
283
|
-
"#{print_description(type)}"\
|
284
|
-
"type #{type.name}#{implementations} {\n"\
|
285
|
-
"#{print_fields(warden, type)}\n"\
|
286
|
-
"}"
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
class InterfacePrinter
|
291
|
-
extend FieldPrinter
|
292
|
-
extend DescriptionPrinter
|
293
|
-
def self.print(warden, type)
|
294
|
-
"#{print_description(type)}"\
|
295
|
-
"interface #{type.name} {\n#{print_fields(warden, type)}\n}"
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
class UnionPrinter
|
300
|
-
extend DescriptionPrinter
|
301
|
-
def self.print(warden, type)
|
302
|
-
possible_types = warden.possible_types(type)
|
303
|
-
"#{print_description(type)}"\
|
304
|
-
"union #{type.name} = #{possible_types.sort_by(&:name).map(&:to_s).join(" | ")}"
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
class EnumPrinter
|
309
|
-
extend DeprecatedPrinter
|
310
|
-
extend DescriptionPrinter
|
311
|
-
def self.print(warden, type)
|
312
|
-
enum_values = warden.enum_values(type)
|
313
|
-
|
314
|
-
values = enum_values.sort_by(&:name).map.with_index { |v, i|
|
315
|
-
"#{print_description(v, ' ', i == 0)}"\
|
316
|
-
" #{v.name}#{print_deprecated(v)}"
|
317
|
-
}.join("\n")
|
318
|
-
|
319
|
-
"#{print_description(type)}"\
|
320
|
-
"enum #{type.name} {\n#{values}\n}"
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
class InputObjectPrinter
|
325
|
-
extend FieldPrinter
|
326
|
-
extend DescriptionPrinter
|
327
|
-
def self.print(warden, type)
|
328
|
-
arguments = warden.arguments(type)
|
329
|
-
fields = arguments.sort_by(&:name).map.with_index{ |field, i|
|
330
|
-
"#{print_description(field, " ", i == 0)}"\
|
331
|
-
" #{print_input_value(field)}"
|
332
|
-
}.join("\n")
|
333
|
-
"#{print_description(type)}"\
|
334
|
-
"input #{type.name} {\n#{fields}\n}"
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
STRATEGIES = {
|
339
|
-
GraphQL::TypeKinds::SCALAR => ScalarPrinter,
|
340
|
-
GraphQL::TypeKinds::OBJECT => ObjectPrinter,
|
341
|
-
GraphQL::TypeKinds::INTERFACE => InterfacePrinter,
|
342
|
-
GraphQL::TypeKinds::UNION => UnionPrinter,
|
343
|
-
GraphQL::TypeKinds::ENUM => EnumPrinter,
|
344
|
-
GraphQL::TypeKinds::INPUT_OBJECT => InputObjectPrinter,
|
345
|
-
}
|
346
114
|
end
|
347
|
-
private_constant :TypeKindPrinters
|
348
115
|
end
|
349
116
|
end
|
350
117
|
end
|