graphql 2.3.8 → 2.4.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.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis.rb +1 -1
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +3 -2
- data/lib/graphql/dataloader/source.rb +6 -3
- data/lib/graphql/dataloader.rb +35 -11
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +10 -6
- data/lib/graphql/execution/interpreter/runtime.rb +23 -19
- data/lib/graphql/execution/interpreter.rb +2 -0
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +4 -19
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +38 -4
- data/lib/graphql/language/lexer.rb +15 -12
- data/lib/graphql/language/nodes.rb +24 -16
- data/lib/graphql/language/parser.rb +14 -1
- data/lib/graphql/language/printer.rb +23 -7
- data/lib/graphql/language.rb +6 -5
- data/lib/graphql/query/context.rb +4 -2
- data/lib/graphql/query/null_context.rb +1 -5
- data/lib/graphql/query.rb +49 -20
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +1 -0
- data/lib/graphql/schema/always_visible.rb +6 -3
- data/lib/graphql/schema/argument.rb +14 -1
- data/lib/graphql/schema/build_from_definition.rb +9 -1
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/enum.rb +49 -15
- data/lib/graphql/schema/enum_value.rb +9 -1
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +91 -36
- data/lib/graphql/schema/input_object.rb +20 -7
- data/lib/graphql/schema/interface.rb +21 -4
- data/lib/graphql/schema/introspection_system.rb +3 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +9 -5
- data/lib/graphql/schema/member/has_fields.rb +5 -5
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/resolver.rb +3 -4
- data/lib/graphql/schema/validator/all_validator.rb +2 -0
- data/lib/graphql/schema/validator/required_validator.rb +28 -4
- data/lib/graphql/schema/visibility/migration.rb +186 -0
- data/lib/graphql/schema/visibility/profile.rb +523 -0
- data/lib/graphql/schema/visibility.rb +75 -0
- data/lib/graphql/schema/warden.rb +80 -21
- data/lib/graphql/schema.rb +254 -85
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +2 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +2 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +11 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +10 -1
- data/lib/graphql/static_validation/validation_context.rb +15 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
- data/lib/graphql/subscriptions.rb +3 -1
- data/lib/graphql/testing/helpers.rb +7 -3
- data/lib/graphql/tracing/notifications_trace.rb +2 -2
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -0
- metadata +28 -7
- data/lib/graphql/schema/subset.rb +0 -397
|
@@ -19,7 +19,7 @@ module GraphQL
|
|
|
19
19
|
@scanner.eos?
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
attr_reader :pos
|
|
22
|
+
attr_reader :pos, :tokens_count
|
|
23
23
|
|
|
24
24
|
def advance
|
|
25
25
|
@scanner.skip(IGNORE_REGEXP)
|
|
@@ -57,20 +57,23 @@ module GraphQL
|
|
|
57
57
|
@scanner.skip(IDENTIFIER_REGEXP)
|
|
58
58
|
:IDENTIFIER
|
|
59
59
|
when ByteFor::NUMBER
|
|
60
|
-
@scanner.skip(NUMERIC_REGEXP)
|
|
60
|
+
if len = @scanner.skip(NUMERIC_REGEXP)
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
if GraphQL.reject_numbers_followed_by_names
|
|
63
|
+
new_pos = @scanner.pos
|
|
64
|
+
peek_byte = @string.getbyte(new_pos)
|
|
65
|
+
next_first_byte = FIRST_BYTES[peek_byte]
|
|
66
|
+
if next_first_byte == ByteFor::NAME || next_first_byte == ByteFor::IDENTIFIER
|
|
67
|
+
number_part = token_value
|
|
68
|
+
name_part = @scanner.scan(IDENTIFIER_REGEXP)
|
|
69
|
+
raise_parse_error("Name after number is not allowed (in `#{number_part}#{name_part}`)")
|
|
70
|
+
end
|
|
70
71
|
end
|
|
72
|
+
# Check for a matched decimal:
|
|
73
|
+
@scanner[1] ? :FLOAT : :INT
|
|
74
|
+
else
|
|
75
|
+
raise_parse_error("Expected a number, but it was malformed (#{@string[@pos].inspect})")
|
|
71
76
|
end
|
|
72
|
-
# Check for a matched decimal:
|
|
73
|
-
@scanner[1] ? :FLOAT : :INT
|
|
74
77
|
when ByteFor::ELLIPSIS
|
|
75
78
|
if @string.getbyte(@pos + 1) != 46 || @string.getbyte(@pos + 2) != 46
|
|
76
79
|
raise_parse_error("Expected `...`, actual: #{@string[@pos..@pos + 2].inspect}")
|
|
@@ -34,11 +34,11 @@ module GraphQL
|
|
|
34
34
|
attr_reader :filename
|
|
35
35
|
|
|
36
36
|
def line
|
|
37
|
-
@line ||= @source
|
|
37
|
+
@line ||= @source&.line_at(@pos)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def col
|
|
41
|
-
@col ||= @source
|
|
41
|
+
@col ||= @source&.column_at(@pos)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def definition_line
|
|
@@ -270,15 +270,17 @@ module GraphQL
|
|
|
270
270
|
"col: nil",
|
|
271
271
|
"pos: nil",
|
|
272
272
|
"filename: nil",
|
|
273
|
-
"source: nil"
|
|
273
|
+
"source: nil"
|
|
274
274
|
]
|
|
275
275
|
|
|
276
|
+
IGNORED_MARSHALLING_KEYWORDS = [:comment]
|
|
277
|
+
|
|
276
278
|
def generate_initialize
|
|
277
279
|
return if method_defined?(:marshal_load, false) # checking for `:initialize` doesn't work right
|
|
278
280
|
|
|
279
281
|
scalar_method_names = @scalar_methods
|
|
280
282
|
# TODO: These probably should be scalar methods, but `types` returns an array
|
|
281
|
-
[:types, :description].each do |extra_method|
|
|
283
|
+
[:types, :description, :comment].each do |extra_method|
|
|
282
284
|
if method_defined?(extra_method)
|
|
283
285
|
scalar_method_names += [extra_method]
|
|
284
286
|
end
|
|
@@ -307,6 +309,12 @@ module GraphQL
|
|
|
307
309
|
keywords = scalar_method_names.map { |m| "#{m}: #{m}"} +
|
|
308
310
|
children_method_names.map { |m| "#{m}: #{m}" }
|
|
309
311
|
|
|
312
|
+
ignored_keywords = IGNORED_MARSHALLING_KEYWORDS.map do |keyword|
|
|
313
|
+
"#{keyword.to_s}: nil"
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
marshalling_method_names = all_method_names - IGNORED_MARSHALLING_KEYWORDS
|
|
317
|
+
|
|
310
318
|
module_eval <<-RUBY, __FILE__, __LINE__
|
|
311
319
|
def initialize(#{arguments.join(", ")})
|
|
312
320
|
@line = line
|
|
@@ -317,7 +325,7 @@ module GraphQL
|
|
|
317
325
|
#{assignments.join("\n")}
|
|
318
326
|
end
|
|
319
327
|
|
|
320
|
-
def self.from_a(filename, line, col, #{
|
|
328
|
+
def self.from_a(filename, line, col, #{marshalling_method_names.join(", ")}, #{ignored_keywords.join(", ")})
|
|
321
329
|
self.new(filename: filename, line: line, col: col, #{keywords.join(", ")})
|
|
322
330
|
end
|
|
323
331
|
|
|
@@ -325,12 +333,12 @@ module GraphQL
|
|
|
325
333
|
[
|
|
326
334
|
line, col, # use methods here to force them to be calculated
|
|
327
335
|
@filename,
|
|
328
|
-
#{
|
|
336
|
+
#{marshalling_method_names.map { |n| "@#{n}," }.join}
|
|
329
337
|
]
|
|
330
338
|
end
|
|
331
339
|
|
|
332
340
|
def marshal_load(values)
|
|
333
|
-
@line, @col, @filename #{
|
|
341
|
+
@line, @col, @filename #{marshalling_method_names.map { |n| ", @#{n}"}.join} = values
|
|
334
342
|
end
|
|
335
343
|
RUBY
|
|
336
344
|
end
|
|
@@ -635,7 +643,7 @@ module GraphQL
|
|
|
635
643
|
end
|
|
636
644
|
|
|
637
645
|
class ScalarTypeDefinition < AbstractNode
|
|
638
|
-
attr_reader :description
|
|
646
|
+
attr_reader :description, :comment
|
|
639
647
|
scalar_methods :name
|
|
640
648
|
children_methods({
|
|
641
649
|
directives: GraphQL::Language::Nodes::Directive,
|
|
@@ -652,7 +660,7 @@ module GraphQL
|
|
|
652
660
|
end
|
|
653
661
|
|
|
654
662
|
class InputValueDefinition < AbstractNode
|
|
655
|
-
attr_reader :description
|
|
663
|
+
attr_reader :description, :comment
|
|
656
664
|
scalar_methods :name, :type, :default_value
|
|
657
665
|
children_methods({
|
|
658
666
|
directives: GraphQL::Language::Nodes::Directive,
|
|
@@ -661,7 +669,7 @@ module GraphQL
|
|
|
661
669
|
end
|
|
662
670
|
|
|
663
671
|
class FieldDefinition < AbstractNode
|
|
664
|
-
attr_reader :description
|
|
672
|
+
attr_reader :description, :comment
|
|
665
673
|
scalar_methods :name, :type
|
|
666
674
|
children_methods({
|
|
667
675
|
arguments: GraphQL::Language::Nodes::InputValueDefinition,
|
|
@@ -681,7 +689,7 @@ module GraphQL
|
|
|
681
689
|
end
|
|
682
690
|
|
|
683
691
|
class ObjectTypeDefinition < AbstractNode
|
|
684
|
-
attr_reader :description
|
|
692
|
+
attr_reader :description, :comment
|
|
685
693
|
scalar_methods :name, :interfaces
|
|
686
694
|
children_methods({
|
|
687
695
|
directives: GraphQL::Language::Nodes::Directive,
|
|
@@ -700,7 +708,7 @@ module GraphQL
|
|
|
700
708
|
end
|
|
701
709
|
|
|
702
710
|
class InterfaceTypeDefinition < AbstractNode
|
|
703
|
-
attr_reader :description
|
|
711
|
+
attr_reader :description, :comment
|
|
704
712
|
scalar_methods :name
|
|
705
713
|
children_methods({
|
|
706
714
|
interfaces: GraphQL::Language::Nodes::TypeName,
|
|
@@ -721,7 +729,7 @@ module GraphQL
|
|
|
721
729
|
end
|
|
722
730
|
|
|
723
731
|
class UnionTypeDefinition < AbstractNode
|
|
724
|
-
attr_reader :description, :types
|
|
732
|
+
attr_reader :description, :comment, :types
|
|
725
733
|
scalar_methods :name
|
|
726
734
|
children_methods({
|
|
727
735
|
directives: GraphQL::Language::Nodes::Directive,
|
|
@@ -739,7 +747,7 @@ module GraphQL
|
|
|
739
747
|
end
|
|
740
748
|
|
|
741
749
|
class EnumValueDefinition < AbstractNode
|
|
742
|
-
attr_reader :description
|
|
750
|
+
attr_reader :description, :comment
|
|
743
751
|
scalar_methods :name
|
|
744
752
|
children_methods({
|
|
745
753
|
directives: GraphQL::Language::Nodes::Directive,
|
|
@@ -748,7 +756,7 @@ module GraphQL
|
|
|
748
756
|
end
|
|
749
757
|
|
|
750
758
|
class EnumTypeDefinition < AbstractNode
|
|
751
|
-
attr_reader :description
|
|
759
|
+
attr_reader :description, :comment
|
|
752
760
|
scalar_methods :name
|
|
753
761
|
children_methods({
|
|
754
762
|
directives: GraphQL::Language::Nodes::Directive,
|
|
@@ -767,7 +775,7 @@ module GraphQL
|
|
|
767
775
|
end
|
|
768
776
|
|
|
769
777
|
class InputObjectTypeDefinition < AbstractNode
|
|
770
|
-
attr_reader :description
|
|
778
|
+
attr_reader :description, :comment
|
|
771
779
|
scalar_methods :name
|
|
772
780
|
children_methods({
|
|
773
781
|
directives: GraphQL::Language::Nodes::Directive,
|
|
@@ -49,6 +49,11 @@ module GraphQL
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def tokens_count
|
|
53
|
+
parse
|
|
54
|
+
@lexer.tokens_count
|
|
55
|
+
end
|
|
56
|
+
|
|
52
57
|
def line_at(pos)
|
|
53
58
|
line = lines_at.bsearch_index { |l| l >= pos }
|
|
54
59
|
if line.nil?
|
|
@@ -141,7 +146,12 @@ module GraphQL
|
|
|
141
146
|
parse_operation_type
|
|
142
147
|
end
|
|
143
148
|
|
|
144
|
-
op_name =
|
|
149
|
+
op_name = case token_name
|
|
150
|
+
when :LPAREN, :LCURLY, :DIR_SIGN
|
|
151
|
+
nil
|
|
152
|
+
else
|
|
153
|
+
parse_name
|
|
154
|
+
end
|
|
145
155
|
|
|
146
156
|
variable_definitions = if at?(:LPAREN)
|
|
147
157
|
expect_token(:LPAREN)
|
|
@@ -398,6 +408,9 @@ module GraphQL
|
|
|
398
408
|
def parse_union_members
|
|
399
409
|
if at?(:EQUALS)
|
|
400
410
|
expect_token :EQUALS
|
|
411
|
+
if at?(:PIPE)
|
|
412
|
+
advance_token
|
|
413
|
+
end
|
|
401
414
|
list = [parse_type_name]
|
|
402
415
|
while at?(:PIPE)
|
|
403
416
|
advance_token
|
|
@@ -255,14 +255,14 @@ module GraphQL
|
|
|
255
255
|
|
|
256
256
|
|
|
257
257
|
def print_scalar_type_definition(scalar_type, extension: false)
|
|
258
|
-
extension ? print_string("extend ") :
|
|
258
|
+
extension ? print_string("extend ") : print_description_and_comment(scalar_type)
|
|
259
259
|
print_string("scalar ")
|
|
260
260
|
print_string(scalar_type.name)
|
|
261
261
|
print_directives(scalar_type.directives)
|
|
262
262
|
end
|
|
263
263
|
|
|
264
264
|
def print_object_type_definition(object_type, extension: false)
|
|
265
|
-
extension ? print_string("extend ") :
|
|
265
|
+
extension ? print_string("extend ") : print_description_and_comment(object_type)
|
|
266
266
|
print_string("type ")
|
|
267
267
|
print_string(object_type.name)
|
|
268
268
|
print_implements(object_type) unless object_type.interfaces.empty?
|
|
@@ -294,7 +294,7 @@ module GraphQL
|
|
|
294
294
|
end
|
|
295
295
|
|
|
296
296
|
def print_arguments(arguments, indent: "")
|
|
297
|
-
if arguments.all? { |arg| !arg.description }
|
|
297
|
+
if arguments.all? { |arg| !arg.description && !arg.comment }
|
|
298
298
|
print_string("(")
|
|
299
299
|
arguments.each_with_index do |arg, i|
|
|
300
300
|
print_input_value_definition(arg)
|
|
@@ -306,6 +306,7 @@ module GraphQL
|
|
|
306
306
|
|
|
307
307
|
print_string("(\n")
|
|
308
308
|
arguments.each_with_index do |arg, i|
|
|
309
|
+
print_comment(arg, indent: " " + indent, first_in_block: i == 0)
|
|
309
310
|
print_description(arg, indent: " " + indent, first_in_block: i == 0)
|
|
310
311
|
print_string(" ")
|
|
311
312
|
print_string(indent)
|
|
@@ -328,7 +329,7 @@ module GraphQL
|
|
|
328
329
|
end
|
|
329
330
|
|
|
330
331
|
def print_interface_type_definition(interface_type, extension: false)
|
|
331
|
-
extension ? print_string("extend ") :
|
|
332
|
+
extension ? print_string("extend ") : print_description_and_comment(interface_type)
|
|
332
333
|
print_string("interface ")
|
|
333
334
|
print_string(interface_type.name)
|
|
334
335
|
print_implements(interface_type) if interface_type.interfaces.any?
|
|
@@ -337,7 +338,7 @@ module GraphQL
|
|
|
337
338
|
end
|
|
338
339
|
|
|
339
340
|
def print_union_type_definition(union_type, extension: false)
|
|
340
|
-
extension ? print_string("extend ") :
|
|
341
|
+
extension ? print_string("extend ") : print_description_and_comment(union_type)
|
|
341
342
|
print_string("union ")
|
|
342
343
|
print_string(union_type.name)
|
|
343
344
|
print_directives(union_type.directives)
|
|
@@ -355,7 +356,7 @@ module GraphQL
|
|
|
355
356
|
end
|
|
356
357
|
|
|
357
358
|
def print_enum_type_definition(enum_type, extension: false)
|
|
358
|
-
extension ? print_string("extend ") :
|
|
359
|
+
extension ? print_string("extend ") : print_description_and_comment(enum_type)
|
|
359
360
|
print_string("enum ")
|
|
360
361
|
print_string(enum_type.name)
|
|
361
362
|
print_directives(enum_type.directives)
|
|
@@ -363,6 +364,7 @@ module GraphQL
|
|
|
363
364
|
print_string(" {\n")
|
|
364
365
|
enum_type.values.each.with_index do |value, i|
|
|
365
366
|
print_description(value, indent: " ", first_in_block: i == 0)
|
|
367
|
+
print_comment(value, indent: " ", first_in_block: i == 0)
|
|
366
368
|
print_enum_value_definition(value)
|
|
367
369
|
end
|
|
368
370
|
print_string("}")
|
|
@@ -377,7 +379,7 @@ module GraphQL
|
|
|
377
379
|
end
|
|
378
380
|
|
|
379
381
|
def print_input_object_type_definition(input_object_type, extension: false)
|
|
380
|
-
extension ? print_string("extend ") :
|
|
382
|
+
extension ? print_string("extend ") : print_description_and_comment(input_object_type)
|
|
381
383
|
print_string("input ")
|
|
382
384
|
print_string(input_object_type.name)
|
|
383
385
|
print_directives(input_object_type.directives)
|
|
@@ -385,6 +387,7 @@ module GraphQL
|
|
|
385
387
|
print_string(" {\n")
|
|
386
388
|
input_object_type.fields.each.with_index do |field, i|
|
|
387
389
|
print_description(field, indent: " ", first_in_block: i == 0)
|
|
390
|
+
print_comment(field, indent: " ", first_in_block: i == 0)
|
|
388
391
|
print_string(" ")
|
|
389
392
|
print_input_value_definition(field)
|
|
390
393
|
print_string("\n")
|
|
@@ -424,6 +427,18 @@ module GraphQL
|
|
|
424
427
|
print_string(GraphQL::Language::BlockString.print(node.description, indent: indent))
|
|
425
428
|
end
|
|
426
429
|
|
|
430
|
+
def print_comment(node, indent: "", first_in_block: true)
|
|
431
|
+
return unless node.comment
|
|
432
|
+
|
|
433
|
+
print_string("\n") if indent != "" && !first_in_block
|
|
434
|
+
print_string(GraphQL::Language::Comment.print(node.comment, indent: indent))
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def print_description_and_comment(node)
|
|
438
|
+
print_description(node)
|
|
439
|
+
print_comment(node)
|
|
440
|
+
end
|
|
441
|
+
|
|
427
442
|
def print_field_definitions(fields)
|
|
428
443
|
return if fields.empty?
|
|
429
444
|
|
|
@@ -431,6 +446,7 @@ module GraphQL
|
|
|
431
446
|
i = 0
|
|
432
447
|
fields.each do |field|
|
|
433
448
|
print_description(field, indent: " ", first_in_block: i == 0)
|
|
449
|
+
print_comment(field, indent: " ", first_in_block: i == 0)
|
|
434
450
|
print_string(" ")
|
|
435
451
|
print_field_definition(field)
|
|
436
452
|
print_string("\n")
|
data/lib/graphql/language.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require "graphql/language/block_string"
|
|
3
|
+
require "graphql/language/comment"
|
|
3
4
|
require "graphql/language/printer"
|
|
4
5
|
require "graphql/language/sanitized_printer"
|
|
5
6
|
require "graphql/language/document_from_schema_definition"
|
|
@@ -48,19 +49,19 @@ module GraphQL
|
|
|
48
49
|
inside_single_quoted_string = false
|
|
49
50
|
new_query_str = nil
|
|
50
51
|
while !scanner.eos?
|
|
51
|
-
if
|
|
52
|
-
new_query_str <<
|
|
53
|
-
elsif scanner.
|
|
52
|
+
if scanner.skip(/(?:\\"|[^"\n\r]|""")+/m)
|
|
53
|
+
new_query_str && (new_query_str << scanner.matched)
|
|
54
|
+
elsif scanner.skip('"')
|
|
54
55
|
new_query_str && (new_query_str << '"')
|
|
55
56
|
inside_single_quoted_string = !inside_single_quoted_string
|
|
56
|
-
elsif scanner.
|
|
57
|
+
elsif scanner.skip("\n")
|
|
57
58
|
if inside_single_quoted_string
|
|
58
59
|
new_query_str ||= query_str[0, scanner.pos - 1]
|
|
59
60
|
new_query_str << '\\n'
|
|
60
61
|
else
|
|
61
62
|
new_query_str && (new_query_str << "\n")
|
|
62
63
|
end
|
|
63
|
-
elsif scanner.
|
|
64
|
+
elsif scanner.skip("\r")
|
|
64
65
|
if inside_single_quoted_string
|
|
65
66
|
new_query_str ||= query_str[0, scanner.pos - 1]
|
|
66
67
|
new_query_str << '\\r'
|
|
@@ -82,12 +82,14 @@ module GraphQL
|
|
|
82
82
|
@provided_values[key] = value
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
def_delegators :@query, :trace
|
|
85
|
+
def_delegators :@query, :trace
|
|
86
86
|
|
|
87
87
|
def types
|
|
88
|
-
@query.types
|
|
88
|
+
@types ||= @query.types
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
attr_writer :types
|
|
92
|
+
|
|
91
93
|
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
|
92
94
|
# @!method []=(key, value)
|
|
93
95
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
|
@@ -27,12 +27,8 @@ module GraphQL
|
|
|
27
27
|
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def interpreter?
|
|
31
|
-
true
|
|
32
|
-
end
|
|
33
|
-
|
|
34
30
|
def types
|
|
35
|
-
@types ||=
|
|
31
|
+
@types ||= Schema::Warden::VisibilityProfile.new(@warden)
|
|
36
32
|
end
|
|
37
33
|
end
|
|
38
34
|
end
|
data/lib/graphql/query.rb
CHANGED
|
@@ -95,21 +95,24 @@ module GraphQL
|
|
|
95
95
|
# @param root_value [Object] the object used to resolve fields on the root type
|
|
96
96
|
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
|
|
97
97
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
|
98
|
-
|
|
98
|
+
# @param visibility_profile [Symbol]
|
|
99
|
+
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, visibility_profile: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_visibility_profile: nil)
|
|
99
100
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
|
100
101
|
variables ||= {}
|
|
101
102
|
@schema = schema
|
|
102
103
|
@context = schema.context_class.new(query: self, values: context)
|
|
103
104
|
|
|
104
|
-
if
|
|
105
|
-
|
|
105
|
+
if use_visibility_profile.nil?
|
|
106
|
+
use_visibility_profile = warden ? false : schema.use_visibility_profile?
|
|
106
107
|
end
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
@visibility_profile = visibility_profile
|
|
110
|
+
|
|
111
|
+
if use_visibility_profile
|
|
112
|
+
@visibility_profile = @schema.visibility.profile_for(@context, visibility_profile)
|
|
113
|
+
@warden = Schema::Warden::NullWarden.new(context: @context, schema: @schema)
|
|
111
114
|
else
|
|
112
|
-
@
|
|
115
|
+
@visibility_profile = nil
|
|
113
116
|
@warden = warden
|
|
114
117
|
end
|
|
115
118
|
|
|
@@ -187,9 +190,8 @@ module GraphQL
|
|
|
187
190
|
@query_string ||= (document ? document.to_query_string : nil)
|
|
188
191
|
end
|
|
189
192
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
end
|
|
193
|
+
# @return [Symbol, nil]
|
|
194
|
+
attr_reader :visibility_profile
|
|
193
195
|
|
|
194
196
|
attr_accessor :multiplex
|
|
195
197
|
|
|
@@ -207,15 +209,19 @@ module GraphQL
|
|
|
207
209
|
def lookahead
|
|
208
210
|
@lookahead ||= begin
|
|
209
211
|
ast_node = selected_operation
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
if ast_node.nil?
|
|
213
|
+
GraphQL::Execution::Lookahead::NULL_LOOKAHEAD
|
|
214
|
+
else
|
|
215
|
+
root_type = case ast_node.operation_type
|
|
216
|
+
when nil, "query"
|
|
217
|
+
types.query_root # rubocop:disable Development/ContextIsPassedCop
|
|
218
|
+
when "mutation"
|
|
219
|
+
types.mutation_root # rubocop:disable Development/ContextIsPassedCop
|
|
220
|
+
when "subscription"
|
|
221
|
+
types.subscription_root # rubocop:disable Development/ContextIsPassedCop
|
|
222
|
+
end
|
|
223
|
+
GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
|
|
217
224
|
end
|
|
218
|
-
GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
|
|
219
225
|
end
|
|
220
226
|
end
|
|
221
227
|
|
|
@@ -347,10 +353,33 @@ module GraphQL
|
|
|
347
353
|
with_prepared_ast { @warden }
|
|
348
354
|
end
|
|
349
355
|
|
|
350
|
-
|
|
356
|
+
def get_type(type_name)
|
|
357
|
+
types.type(type_name) # rubocop:disable Development/ContextIsPassedCop
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def get_field(owner, field_name)
|
|
361
|
+
types.field(owner, field_name) # rubocop:disable Development/ContextIsPassedCop
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def possible_types(type)
|
|
365
|
+
types.possible_types(type) # rubocop:disable Development/ContextIsPassedCop
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def root_type_for_operation(op_type)
|
|
369
|
+
case op_type
|
|
370
|
+
when "query"
|
|
371
|
+
types.query_root # rubocop:disable Development/ContextIsPassedCop
|
|
372
|
+
when "mutation"
|
|
373
|
+
types.mutation_root # rubocop:disable Development/ContextIsPassedCop
|
|
374
|
+
when "subscription"
|
|
375
|
+
types.subscription_root # rubocop:disable Development/ContextIsPassedCop
|
|
376
|
+
else
|
|
377
|
+
raise ArgumentError, "unexpected root type name: #{op_type.inspect}; expected 'query', 'mutation', or 'subscription'"
|
|
378
|
+
end
|
|
379
|
+
end
|
|
351
380
|
|
|
352
381
|
def types
|
|
353
|
-
@
|
|
382
|
+
@visibility_profile || warden.visibility_profile
|
|
354
383
|
end
|
|
355
384
|
|
|
356
385
|
# @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_relative "./base_cop"
|
|
3
|
+
|
|
4
|
+
module GraphQL
|
|
5
|
+
module Rubocop
|
|
6
|
+
module GraphQL
|
|
7
|
+
# Identify (and auto-correct) any field whose type configuration isn't given
|
|
8
|
+
# in the configuration block.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# # bad, immediately causes Rails to load `app/graphql/types/thing.rb`
|
|
12
|
+
# field :thing, Types::Thing
|
|
13
|
+
#
|
|
14
|
+
# # good, defers loading until the file is needed
|
|
15
|
+
# field :thing do
|
|
16
|
+
# type(Types::Thing)
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
class FieldTypeInBlock < BaseCop
|
|
20
|
+
MSG = "type configuration can be moved to a block to defer loading the type's file"
|
|
21
|
+
|
|
22
|
+
BUILT_IN_SCALAR_NAMES = ["Float", "Int", "Integer", "String", "ID", "Boolean"]
|
|
23
|
+
def_node_matcher :field_config_with_inline_type, <<-Pattern
|
|
24
|
+
(
|
|
25
|
+
send {nil? _} :field sym ${const array} ...
|
|
26
|
+
)
|
|
27
|
+
Pattern
|
|
28
|
+
|
|
29
|
+
def_node_matcher :field_config_with_inline_type_and_block, <<-Pattern
|
|
30
|
+
(
|
|
31
|
+
block
|
|
32
|
+
(send {nil? _} :field sym ${const array} ...) ...
|
|
33
|
+
(args)
|
|
34
|
+
_
|
|
35
|
+
|
|
36
|
+
)
|
|
37
|
+
Pattern
|
|
38
|
+
|
|
39
|
+
def on_block(node)
|
|
40
|
+
ignore_node(node)
|
|
41
|
+
field_config_with_inline_type_and_block(node) do |type_const|
|
|
42
|
+
type_const_str = get_type_argument_str(node, type_const)
|
|
43
|
+
if ignore_inline_type_str?(type_const_str)
|
|
44
|
+
# Do nothing ...
|
|
45
|
+
else
|
|
46
|
+
add_offense(type_const) do |corrector|
|
|
47
|
+
cleaned_node_source = delete_type_argument(node, type_const)
|
|
48
|
+
field_indent = determine_field_indent(node)
|
|
49
|
+
cleaned_node_source.sub!(/(\{|do)/, "\\1\n#{field_indent} type #{type_const_str}")
|
|
50
|
+
corrector.replace(node, cleaned_node_source)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def on_send(node)
|
|
57
|
+
return if part_of_ignored_node?(node)
|
|
58
|
+
field_config_with_inline_type(node) do |type_const|
|
|
59
|
+
type_const_str = get_type_argument_str(node, type_const)
|
|
60
|
+
if ignore_inline_type_str?(type_const_str)
|
|
61
|
+
# Do nothing -- not loading from another file
|
|
62
|
+
else
|
|
63
|
+
add_offense(type_const) do |corrector|
|
|
64
|
+
cleaned_node_source = delete_type_argument(node, type_const)
|
|
65
|
+
field_indent = determine_field_indent(node)
|
|
66
|
+
cleaned_node_source += " do\n#{field_indent} type #{type_const_str}\n#{field_indent}end"
|
|
67
|
+
corrector.replace(node, cleaned_node_source)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def ignore_inline_type_str?(type_str)
|
|
77
|
+
if BUILT_IN_SCALAR_NAMES.include?(type_str)
|
|
78
|
+
true
|
|
79
|
+
elsif (inner_type_str = type_str.sub(/\[([A-Za-z]+)(, null: (true|false))?\]/, '\1')) && BUILT_IN_SCALAR_NAMES.include?(inner_type_str)
|
|
80
|
+
true
|
|
81
|
+
else
|
|
82
|
+
false
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def get_type_argument_str(send_node, type_const)
|
|
87
|
+
first_pos = type_const.location.expression.begin_pos
|
|
88
|
+
end_pos = type_const.location.expression.end_pos
|
|
89
|
+
node_source = send_node.source_range.source
|
|
90
|
+
node_first_pos = send_node.location.expression.begin_pos
|
|
91
|
+
|
|
92
|
+
relative_first_pos = first_pos - node_first_pos
|
|
93
|
+
end_removal_pos = end_pos - node_first_pos
|
|
94
|
+
|
|
95
|
+
node_source[relative_first_pos...end_removal_pos]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def delete_type_argument(send_node, type_const)
|
|
99
|
+
first_pos = type_const.location.expression.begin_pos
|
|
100
|
+
end_pos = type_const.location.expression.end_pos
|
|
101
|
+
node_source = send_node.source_range.source
|
|
102
|
+
node_first_pos = send_node.location.expression.begin_pos
|
|
103
|
+
|
|
104
|
+
relative_first_pos = first_pos - node_first_pos
|
|
105
|
+
end_removal_pos = end_pos - node_first_pos
|
|
106
|
+
|
|
107
|
+
begin_removal_pos = relative_first_pos
|
|
108
|
+
while node_source[begin_removal_pos] != ","
|
|
109
|
+
begin_removal_pos -= 1
|
|
110
|
+
if begin_removal_pos < 1
|
|
111
|
+
raise "Invariant: somehow backtracked to beginning of node looking for a comma (node source: #{node_source.inspect})"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
node_source[0...begin_removal_pos] + node_source[end_removal_pos..-1]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def determine_field_indent(send_node)
|
|
119
|
+
type_defn_node = send_node
|
|
120
|
+
|
|
121
|
+
while (type_defn_node && !(type_defn_node.class_definition? || type_defn_node.module_definition?))
|
|
122
|
+
type_defn_node = type_defn_node.parent
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
if type_defn_node.nil?
|
|
126
|
+
raise "Invariant: Something went wrong in GraphQL-Ruby, couldn't find surrounding class definition for field (#{send_node}).\n\nPlease report this error on GitHub."
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
type_defn_source = type_defn_node.source
|
|
130
|
+
indent_test_idx = send_node.location.expression.begin_pos - type_defn_node.source_range.begin_pos - 1
|
|
131
|
+
field_indent = "".dup
|
|
132
|
+
while type_defn_source[indent_test_idx] == " "
|
|
133
|
+
field_indent << " "
|
|
134
|
+
indent_test_idx -= 1
|
|
135
|
+
if indent_test_idx == 0
|
|
136
|
+
raise "Invariant: somehow backtracted to beginning of class when looking for field indent (source: #{node_source.inspect})"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
field_indent
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|