graphql 2.0.16 → 2.0.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/visitor.rb +42 -35
  3. data/lib/graphql/analysis/ast.rb +2 -2
  4. data/lib/graphql/backtrace/trace.rb +96 -0
  5. data/lib/graphql/backtrace/tracer.rb +1 -1
  6. data/lib/graphql/backtrace.rb +6 -1
  7. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  8. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -3
  9. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  10. data/lib/graphql/execution/interpreter/runtime.rb +264 -211
  11. data/lib/graphql/execution/interpreter.rb +15 -10
  12. data/lib/graphql/execution/lazy.rb +6 -12
  13. data/lib/graphql/execution/multiplex.rb +2 -1
  14. data/lib/graphql/filter.rb +7 -2
  15. data/lib/graphql/introspection/directive_type.rb +2 -2
  16. data/lib/graphql/introspection/field_type.rb +1 -1
  17. data/lib/graphql/introspection/schema_type.rb +2 -2
  18. data/lib/graphql/introspection/type_type.rb +5 -5
  19. data/lib/graphql/language/document_from_schema_definition.rb +25 -9
  20. data/lib/graphql/language/lexer.rb +216 -1505
  21. data/lib/graphql/language/nodes.rb +66 -40
  22. data/lib/graphql/language/parser.rb +509 -491
  23. data/lib/graphql/language/parser.y +43 -38
  24. data/lib/graphql/language/visitor.rb +191 -83
  25. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  26. data/lib/graphql/pagination/connection.rb +5 -5
  27. data/lib/graphql/query/context.rb +62 -31
  28. data/lib/graphql/query/null_context.rb +1 -1
  29. data/lib/graphql/query.rb +22 -5
  30. data/lib/graphql/schema/argument.rb +7 -13
  31. data/lib/graphql/schema/build_from_definition.rb +15 -3
  32. data/lib/graphql/schema/directive.rb +12 -2
  33. data/lib/graphql/schema/enum.rb +24 -17
  34. data/lib/graphql/schema/enum_value.rb +2 -3
  35. data/lib/graphql/schema/field.rb +68 -57
  36. data/lib/graphql/schema/field_extension.rb +1 -4
  37. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  38. data/lib/graphql/schema/interface.rb +0 -10
  39. data/lib/graphql/schema/late_bound_type.rb +2 -0
  40. data/lib/graphql/schema/member/base_dsl_methods.rb +17 -14
  41. data/lib/graphql/schema/member/has_arguments.rb +105 -58
  42. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  43. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  44. data/lib/graphql/schema/member/has_directives.rb +15 -10
  45. data/lib/graphql/schema/member/has_fields.rb +95 -38
  46. data/lib/graphql/schema/member/has_interfaces.rb +49 -8
  47. data/lib/graphql/schema/member/has_validators.rb +32 -6
  48. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  49. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  50. data/lib/graphql/schema/object.rb +2 -4
  51. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  52. data/lib/graphql/schema/resolver.rb +4 -4
  53. data/lib/graphql/schema/timeout.rb +24 -28
  54. data/lib/graphql/schema/validator.rb +1 -1
  55. data/lib/graphql/schema/warden.rb +29 -5
  56. data/lib/graphql/schema.rb +76 -25
  57. data/lib/graphql/static_validation/literal_validator.rb +15 -1
  58. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  59. data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
  60. data/lib/graphql/static_validation/validator.rb +1 -1
  61. data/lib/graphql/subscriptions/event.rb +2 -7
  62. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  63. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  64. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  65. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  66. data/lib/graphql/tracing/legacy_trace.rb +65 -0
  67. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  68. data/lib/graphql/tracing/notifications_trace.rb +42 -0
  69. data/lib/graphql/tracing/platform_trace.rb +109 -0
  70. data/lib/graphql/tracing/platform_tracing.rb +15 -3
  71. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  72. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
  73. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  74. data/lib/graphql/tracing/scout_trace.rb +72 -0
  75. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  76. data/lib/graphql/tracing/trace.rb +75 -0
  77. data/lib/graphql/tracing.rb +16 -39
  78. data/lib/graphql/type_kinds.rb +6 -3
  79. data/lib/graphql/types/relay/base_connection.rb +1 -1
  80. data/lib/graphql/types/relay/connection_behaviors.rb +24 -6
  81. data/lib/graphql/types/relay/edge_behaviors.rb +16 -6
  82. data/lib/graphql/types/relay/node_behaviors.rb +7 -1
  83. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  84. data/lib/graphql/types/relay.rb +0 -1
  85. data/lib/graphql/types/string.rb +1 -1
  86. data/lib/graphql/version.rb +1 -1
  87. data/lib/graphql.rb +16 -9
  88. metadata +34 -9
  89. data/lib/graphql/language/lexer.rl +0 -280
  90. data/lib/graphql/types/relay/default_relay.rb +0 -27
@@ -162,7 +162,7 @@ rule
162
162
  | schema_keyword
163
163
 
164
164
  enum_value_definition:
165
- description_opt enum_name directives_list_opt { result = make_node(:EnumValueDefinition, name: val[1], directives: val[2], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1]) }
165
+ description_opt enum_name directives_list_opt { result = make_node(:EnumValueDefinition, name: val[1], directives: val[2], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1]) }
166
166
 
167
167
  enum_value_definitions:
168
168
  enum_value_definition { result = [val[0]] }
@@ -180,9 +180,9 @@ rule
180
180
  name COLON input_value { result = make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
181
181
 
182
182
  literal_value:
183
- FLOAT { result = val[0].to_f }
184
- | INT { result = val[0].to_i }
185
- | STRING { result = val[0].to_s }
183
+ FLOAT { result = val[0][3].to_f }
184
+ | INT { result = val[0][3].to_i }
185
+ | STRING { result = val[0][3] }
186
186
  | TRUE { result = true }
187
187
  | FALSE { result = false }
188
188
  | null_value
@@ -284,14 +284,18 @@ rule
284
284
  | directive_definition
285
285
 
286
286
  schema_definition:
287
- SCHEMA directives_list_opt LCURLY operation_type_definition_list RCURLY { result = make_node(:SchemaDefinition, position_source: val[0], definition_line: val[0].line, directives: val[1], **val[3]) }
287
+ SCHEMA directives_list_opt operation_type_definition_list_opt { result = make_node(:SchemaDefinition, position_source: val[0], definition_line: val[0][1], directives: val[1], **val[2]) }
288
+
289
+ operation_type_definition_list_opt:
290
+ /* none */ { result = {} }
291
+ | LCURLY operation_type_definition_list RCURLY { result = val[1] }
288
292
 
289
293
  operation_type_definition_list:
290
294
  operation_type_definition
291
295
  | operation_type_definition_list operation_type_definition { result = val[0].merge(val[1]) }
292
296
 
293
297
  operation_type_definition:
294
- operation_type COLON name { result = { val[0].to_s.to_sym => val[2] } }
298
+ operation_type COLON name { result = { val[0][3].to_sym => val[2] } }
295
299
 
296
300
  type_definition:
297
301
  scalar_type_definition
@@ -351,12 +355,12 @@ rule
351
355
 
352
356
  scalar_type_definition:
353
357
  description_opt SCALAR name directives_list_opt {
354
- result = make_node(:ScalarTypeDefinition, name: val[2], directives: val[3], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
358
+ result = make_node(:ScalarTypeDefinition, name: val[2], directives: val[3], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
355
359
  }
356
360
 
357
361
  object_type_definition:
358
362
  description_opt TYPE name implements_opt directives_list_opt field_definition_list_opt {
359
- result = make_node(:ObjectTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
363
+ result = make_node(:ObjectTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
360
364
  }
361
365
 
362
366
  implements_opt:
@@ -378,7 +382,7 @@ rule
378
382
 
379
383
  input_value_definition:
380
384
  description_opt name COLON type default_value_opt directives_list_opt {
381
- result = make_node(:InputValueDefinition, name: val[1], type: val[3], default_value: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
385
+ result = make_node(:InputValueDefinition, name: val[1], type: val[3], default_value: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
382
386
  }
383
387
 
384
388
  input_value_definition_list:
@@ -391,7 +395,7 @@ rule
391
395
 
392
396
  field_definition:
393
397
  description_opt name arguments_definitions_opt COLON type directives_list_opt {
394
- result = make_node(:FieldDefinition, name: val[1], arguments: val[2], type: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
398
+ result = make_node(:FieldDefinition, name: val[1], arguments: val[2], type: val[4], directives: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
395
399
  }
396
400
 
397
401
  field_definition_list_opt:
@@ -405,7 +409,7 @@ rule
405
409
 
406
410
  interface_type_definition:
407
411
  description_opt INTERFACE name implements_opt directives_list_opt field_definition_list_opt {
408
- result = make_node(:InterfaceTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
412
+ result = make_node(:InterfaceTypeDefinition, name: val[2], interfaces: val[3], directives: val[4], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
409
413
  }
410
414
 
411
415
  union_members:
@@ -414,22 +418,22 @@ rule
414
418
 
415
419
  union_type_definition:
416
420
  description_opt UNION name directives_list_opt EQUALS union_members {
417
- result = make_node(:UnionTypeDefinition, name: val[2], directives: val[3], types: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
421
+ result = make_node(:UnionTypeDefinition, name: val[2], directives: val[3], types: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
418
422
  }
419
423
 
420
424
  enum_type_definition:
421
425
  description_opt ENUM name directives_list_opt LCURLY enum_value_definitions RCURLY {
422
- result = make_node(:EnumTypeDefinition, name: val[2], directives: val[3], values: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
426
+ result = make_node(:EnumTypeDefinition, name: val[2], directives: val[3], values: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
423
427
  }
424
428
 
425
429
  input_object_type_definition:
426
430
  description_opt INPUT name directives_list_opt LCURLY input_value_definition_list RCURLY {
427
- result = make_node(:InputObjectTypeDefinition, name: val[2], directives: val[3], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
431
+ result = make_node(:InputObjectTypeDefinition, name: val[2], directives: val[3], fields: val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
428
432
  }
429
433
 
430
434
  directive_definition:
431
435
  description_opt DIRECTIVE DIR_SIGN name arguments_definitions_opt directive_repeatable_opt ON directive_locations {
432
- result = make_node(:DirectiveDefinition, name: val[3], arguments: val[4], locations: val[7], repeatable: !!val[5], description: val[0] || get_description(val[1]), definition_line: val[1].line, position_source: val[0] || val[1])
436
+ result = make_node(:DirectiveDefinition, name: val[3], arguments: val[4], locations: val[7], repeatable: !!val[5], description: val[0] || get_description(val[1]), definition_line: val[1][1], position_source: val[0] || val[1])
433
437
  }
434
438
 
435
439
  directive_repeatable_opt:
@@ -437,8 +441,8 @@ rule
437
441
  | REPEATABLE
438
442
 
439
443
  directive_locations:
440
- name { result = [make_node(:DirectiveLocation, name: val[0].to_s, position_source: val[0])] }
441
- | directive_locations PIPE name { val[0] << make_node(:DirectiveLocation, name: val[2].to_s, position_source: val[2]) }
444
+ name { result = [make_node(:DirectiveLocation, name: val[0][3], position_source: val[0])] }
445
+ | directive_locations PIPE name { val[0] << make_node(:DirectiveLocation, name: val[2][3], position_source: val[2]) }
442
446
  end
443
447
 
444
448
  ---- header ----
@@ -448,22 +452,22 @@ end
448
452
 
449
453
  EMPTY_ARRAY = [].freeze
450
454
 
451
- def initialize(query_string, filename:, tracer: Tracing::NullTracer)
455
+ def initialize(query_string, filename:, trace: Tracing::NullTrace)
452
456
  raise GraphQL::ParseError.new("No query string was present", nil, nil, query_string) if query_string.nil?
453
457
  @query_string = query_string
454
458
  @filename = filename
455
- @tracer = tracer
459
+ @trace = trace
456
460
  @reused_next_token = [nil, nil]
457
461
  end
458
462
 
459
463
  def parse_document
460
464
  @document ||= begin
461
465
  # Break the string into tokens
462
- @tracer.trace("lex", {query_string: @query_string}) do
463
- @tokens ||= GraphQL.scan(@query_string)
466
+ @trace.lex(query_string: @query_string) do
467
+ @tokens ||= GraphQL::Language::Lexer.tokenize(@query_string)
464
468
  end
465
469
  # From the tokens, build an AST
466
- @tracer.trace("parse", {query_string: @query_string}) do
470
+ @trace.parse(query_string: @query_string) do
467
471
  if @tokens.empty?
468
472
  raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @query_string)
469
473
  else
@@ -476,17 +480,17 @@ end
476
480
  class << self
477
481
  attr_accessor :cache
478
482
 
479
- def parse(query_string, filename: nil, tracer: GraphQL::Tracing::NullTracer)
480
- new(query_string, filename: filename, tracer: tracer).parse_document
483
+ def parse(query_string, filename: nil, trace: GraphQL::Tracing::NullTrace)
484
+ new(query_string, filename: filename, trace: trace).parse_document
481
485
  end
482
486
 
483
- def parse_file(filename, tracer: GraphQL::Tracing::NullTracer)
487
+ def parse_file(filename, trace: GraphQL::Tracing::NullTrace)
484
488
  if cache
485
489
  cache.fetch(filename) do
486
- parse(File.read(filename), filename: filename, tracer: tracer)
490
+ parse(File.read(filename), filename: filename, trace: trace)
487
491
  end
488
492
  else
489
- parse(File.read(filename), filename: filename, tracer: tracer)
493
+ parse(File.read(filename), filename: filename, trace: trace)
490
494
  end
491
495
  end
492
496
  end
@@ -498,7 +502,7 @@ def next_token
498
502
  if lexer_token.nil?
499
503
  nil
500
504
  else
501
- @reused_next_token[0] = lexer_token.name
505
+ @reused_next_token[0] = lexer_token[0]
502
506
  @reused_next_token[1] = lexer_token
503
507
  @reused_next_token
504
508
  end
@@ -509,13 +513,13 @@ def get_description(token)
509
513
 
510
514
  loop do
511
515
  prev_token = token
512
- token = token.prev_token
516
+ token = token[4]
513
517
 
514
518
  break if token.nil?
515
- break if token.name != :COMMENT
516
- break if prev_token.line != token.line + 1
519
+ break if token[0] != :COMMENT
520
+ break if prev_token[1] != token[1] + 1
517
521
 
518
- comments.unshift(token.to_s.sub(/^#\s*/, ""))
522
+ comments.unshift(token[3].sub(/^#\s*/, ""))
519
523
  end
520
524
 
521
525
  return nil if comments.empty?
@@ -531,11 +535,12 @@ def on_error(parser_token_id, lexer_token, vstack)
531
535
  if parser_token_name.nil?
532
536
  raise GraphQL::ParseError.new("Parse Error on unknown token: {token_id: #{parser_token_id}, lexer_token: #{lexer_token}} from #{@query_string}", nil, nil, @query_string, filename: @filename)
533
537
  else
534
- line, col = lexer_token.line_and_column
535
- if lexer_token.name == :BAD_UNICODE_ESCAPE
536
- raise GraphQL::ParseError.new("Parse error on bad Unicode escape sequence: #{lexer_token.to_s.inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
538
+ line = lexer_token[1]
539
+ col = lexer_token[2]
540
+ if lexer_token[0] == :BAD_UNICODE_ESCAPE
541
+ raise GraphQL::ParseError.new("Parse error on bad Unicode escape sequence: #{lexer_token[3].inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
537
542
  else
538
- raise GraphQL::ParseError.new("Parse error on #{lexer_token.to_s.inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
543
+ raise GraphQL::ParseError.new("Parse error on #{lexer_token[3].inspect} (#{parser_token_name}) at [#{line}, #{col}]", line, col, @query_string, filename: @filename)
539
544
  end
540
545
  end
541
546
  end
@@ -543,8 +548,8 @@ end
543
548
 
544
549
  def make_node(node_name, assigns)
545
550
  assigns.each do |key, value|
546
- if key != :position_source && value.is_a?(GraphQL::Language::Token)
547
- assigns[key] = value.to_s
551
+ if key != :position_source && value.is_a?(Array) && value[0].is_a?(Symbol)
552
+ assigns[key] = value[3]
548
553
  end
549
554
  end
550
555
 
@@ -65,7 +65,9 @@ module GraphQL
65
65
  # Visit `document` and all children, applying hooks as you go
66
66
  # @return [void]
67
67
  def visit
68
- result = on_node_with_modifications(@document, nil)
68
+ # `@document` may be any kind of node:
69
+ visit_method = :"#{@document.visit_method}_with_modifications"
70
+ result = public_send(visit_method, @document, nil)
69
71
  @result = if result.is_a?(Array)
70
72
  result.first
71
73
  else
@@ -74,104 +76,210 @@ module GraphQL
74
76
  end
75
77
  end
76
78
 
77
- # Call the user-defined handler for `node`.
78
- def visit_node(node, parent)
79
- public_send(node.visit_method, node, parent)
80
- end
79
+ # We don't use `alias` here because it breaks `super`
80
+ def self.make_visit_methods(ast_node_class)
81
+ node_method = ast_node_class.visit_method
82
+ children_of_type = ast_node_class.children_of_type
83
+ child_visit_method = :"#{node_method}_children"
81
84
 
82
- # The default implementation for visiting an AST node.
83
- # It doesn't _do_ anything, but it continues to visiting the node's children.
84
- # To customize this hook, override one of its make_visit_methodes (or the base method?)
85
- # in your subclasses.
86
- #
87
- # For compatibility, it calls hook procs, too.
88
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
89
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
90
- # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
91
- def on_abstract_node(node, parent)
92
- if node.equal?(DELETE_NODE)
93
- # This might be passed to `super(DELETE_NODE, ...)`
94
- # by a user hook, don't want to keep visiting in that case.
95
- nil
96
- else
97
- # Run hooks if there are any
98
- new_node = node
99
- no_hooks = !@visitors.key?(node.class)
100
- if no_hooks || begin_visit(new_node, parent)
101
- node.children.each do |child_node|
102
- new_child_and_node = on_node_with_modifications(child_node, new_node)
103
- # Reassign `node` in case the child hook makes a modification
104
- if new_child_and_node.is_a?(Array)
105
- new_node = new_child_and_node[1]
85
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
86
+ # The default implementation for visiting an AST node.
87
+ # It doesn't _do_ anything, but it continues to visiting the node's children.
88
+ # To customize this hook, override one of its make_visit_methods (or the base method?)
89
+ # in your subclasses.
90
+ #
91
+ # For compatibility, it calls hook procs, too.
92
+ # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
93
+ # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
94
+ # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
95
+ def #{node_method}(node, parent)
96
+ if node.equal?(DELETE_NODE)
97
+ # This might be passed to `super(DELETE_NODE, ...)`
98
+ # by a user hook, don't want to keep visiting in that case.
99
+ [node, parent]
100
+ else
101
+ # Run hooks if there are any
102
+ new_node = node
103
+ no_hooks = !@visitors.key?(node.class)
104
+ if no_hooks || begin_visit(new_node, parent)
105
+ #{
106
+ if method_defined?(child_visit_method)
107
+ "new_node = #{child_visit_method}(new_node)"
108
+ elsif children_of_type
109
+ children_of_type.map do |child_accessor, child_class|
110
+ "node.#{child_accessor}.each do |child_node|
111
+ new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
112
+ # Reassign `node` in case the child hook makes a modification
113
+ if new_child_and_node.is_a?(Array)
114
+ new_node = new_child_and_node[1]
115
+ end
116
+ end"
117
+ end.join("\n")
118
+ else
119
+ ""
120
+ end
121
+ }
122
+ end
123
+ end_visit(new_node, parent) unless no_hooks
124
+
125
+ if new_node.equal?(node)
126
+ [node, parent]
127
+ else
128
+ [new_node, parent]
106
129
  end
107
130
  end
108
131
  end
109
- end_visit(new_node, parent) unless no_hooks
110
132
 
111
- if new_node.equal?(node)
112
- nil
133
+ def #{node_method}_with_modifications(node, parent)
134
+ new_node_and_new_parent = #{node_method}(node, parent)
135
+ apply_modifications(node, parent, new_node_and_new_parent)
136
+ end
137
+ RUBY
138
+ end
139
+
140
+ def on_document_children(document_node)
141
+ new_node = document_node
142
+ document_node.children.each do |child_node|
143
+ visit_method = :"#{child_node.visit_method}_with_modifications"
144
+ new_child_and_node = public_send(visit_method, child_node, new_node)
145
+ # Reassign `node` in case the child hook makes a modification
146
+ if new_child_and_node.is_a?(Array)
147
+ new_node = new_child_and_node[1]
148
+ end
149
+ end
150
+ new_node
151
+ end
152
+
153
+ def on_field_children(new_node)
154
+ new_node.arguments.each do |arg_node| # rubocop:disable Development/ContextIsPassedCop
155
+ new_child_and_node = on_argument_with_modifications(arg_node, new_node)
156
+ # Reassign `node` in case the child hook makes a modification
157
+ if new_child_and_node.is_a?(Array)
158
+ new_node = new_child_and_node[1]
159
+ end
160
+ end
161
+ new_node = visit_directives(new_node)
162
+ new_node = visit_selections(new_node)
163
+ new_node
164
+ end
165
+
166
+ def visit_directives(new_node)
167
+ new_node.directives.each do |dir_node|
168
+ new_child_and_node = on_directive_with_modifications(dir_node, new_node)
169
+ # Reassign `node` in case the child hook makes a modification
170
+ if new_child_and_node.is_a?(Array)
171
+ new_node = new_child_and_node[1]
172
+ end
173
+ end
174
+ new_node
175
+ end
176
+
177
+ def visit_selections(new_node)
178
+ new_node.selections.each do |selection|
179
+ new_child_and_node = case selection
180
+ when GraphQL::Language::Nodes::Field
181
+ on_field_with_modifications(selection, new_node)
182
+ when GraphQL::Language::Nodes::InlineFragment
183
+ on_inline_fragment_with_modifications(selection, new_node)
184
+ when GraphQL::Language::Nodes::FragmentSpread
185
+ on_fragment_spread_with_modifications(selection, new_node)
113
186
  else
114
- [new_node, parent]
187
+ raise ArgumentError, "Invariant: unexpected field selection #{selection.class} (#{selection.inspect})"
188
+ end
189
+ # Reassign `node` in case the child hook makes a modification
190
+ if new_child_and_node.is_a?(Array)
191
+ new_node = new_child_and_node[1]
115
192
  end
116
193
  end
194
+ new_node
117
195
  end
118
196
 
119
- # We don't use `alias` here because it breaks `super`
120
- def self.make_visit_method(node_method)
121
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
122
- def #{node_method}(node, parent)
123
- child_mod = on_abstract_node(node, parent)
124
- # If visiting the children returned changes, continue passing those.
125
- child_mod || [node, parent]
197
+ def on_fragment_definition_children(new_node)
198
+ new_node = visit_directives(new_node)
199
+ new_node = visit_selections(new_node)
200
+ new_node
201
+ end
202
+
203
+ alias :on_inline_fragment_children :on_fragment_definition_children
204
+
205
+ def on_operation_definition_children(new_node)
206
+ new_node.variables.each do |arg_node|
207
+ new_child_and_node = on_variable_definition_with_modifications(arg_node, new_node)
208
+ # Reassign `node` in case the child hook makes a modification
209
+ if new_child_and_node.is_a?(Array)
210
+ new_node = new_child_and_node[1]
126
211
  end
127
- RUBY
212
+ end
213
+ new_node = visit_directives(new_node)
214
+ new_node = visit_selections(new_node)
215
+ new_node
216
+ end
217
+
218
+ def on_argument_children(new_node)
219
+ new_node.children.each do |value_node|
220
+ new_child_and_node = case value_node
221
+ when Language::Nodes::VariableIdentifier
222
+ on_variable_identifier_with_modifications(value_node, new_node)
223
+ when Language::Nodes::InputObject
224
+ on_input_object_with_modifications(value_node, new_node)
225
+ when Language::Nodes::Enum
226
+ on_enum_with_modifications(value_node, new_node)
227
+ when Language::Nodes::NullValue
228
+ on_null_value_with_modifications(value_node, new_node)
229
+ else
230
+ raise ArgumentError, "Invariant: unexpected argument value node #{value_node.class} (#{value_node.inspect})"
231
+ end
232
+ # Reassign `node` in case the child hook makes a modification
233
+ if new_child_and_node.is_a?(Array)
234
+ new_node = new_child_and_node[1]
235
+ end
236
+ end
237
+ new_node
128
238
  end
129
239
 
130
- make_visit_method :on_argument
131
- make_visit_method :on_directive
132
- make_visit_method :on_directive_definition
133
- make_visit_method :on_directive_location
134
- make_visit_method :on_document
135
- make_visit_method :on_enum
136
- make_visit_method :on_enum_type_definition
137
- make_visit_method :on_enum_type_extension
138
- make_visit_method :on_enum_value_definition
139
- make_visit_method :on_field
140
- make_visit_method :on_field_definition
141
- make_visit_method :on_fragment_definition
142
- make_visit_method :on_fragment_spread
143
- make_visit_method :on_inline_fragment
144
- make_visit_method :on_input_object
145
- make_visit_method :on_input_object_type_definition
146
- make_visit_method :on_input_object_type_extension
147
- make_visit_method :on_input_value_definition
148
- make_visit_method :on_interface_type_definition
149
- make_visit_method :on_interface_type_extension
150
- make_visit_method :on_list_type
151
- make_visit_method :on_non_null_type
152
- make_visit_method :on_null_value
153
- make_visit_method :on_object_type_definition
154
- make_visit_method :on_object_type_extension
155
- make_visit_method :on_operation_definition
156
- make_visit_method :on_scalar_type_definition
157
- make_visit_method :on_scalar_type_extension
158
- make_visit_method :on_schema_definition
159
- make_visit_method :on_schema_extension
160
- make_visit_method :on_type_name
161
- make_visit_method :on_union_type_definition
162
- make_visit_method :on_union_type_extension
163
- make_visit_method :on_variable_definition
164
- make_visit_method :on_variable_identifier
240
+ [
241
+ Language::Nodes::Argument,
242
+ Language::Nodes::Directive,
243
+ Language::Nodes::DirectiveDefinition,
244
+ Language::Nodes::DirectiveLocation,
245
+ Language::Nodes::Document,
246
+ Language::Nodes::Enum,
247
+ Language::Nodes::EnumTypeDefinition,
248
+ Language::Nodes::EnumTypeExtension,
249
+ Language::Nodes::EnumValueDefinition,
250
+ Language::Nodes::Field,
251
+ Language::Nodes::FieldDefinition,
252
+ Language::Nodes::FragmentDefinition,
253
+ Language::Nodes::FragmentSpread,
254
+ Language::Nodes::InlineFragment,
255
+ Language::Nodes::InputObject,
256
+ Language::Nodes::InputObjectTypeDefinition,
257
+ Language::Nodes::InputObjectTypeExtension,
258
+ Language::Nodes::InputValueDefinition,
259
+ Language::Nodes::InterfaceTypeDefinition,
260
+ Language::Nodes::InterfaceTypeExtension,
261
+ Language::Nodes::ListType,
262
+ Language::Nodes::NonNullType,
263
+ Language::Nodes::NullValue,
264
+ Language::Nodes::ObjectTypeDefinition,
265
+ Language::Nodes::ObjectTypeExtension,
266
+ Language::Nodes::OperationDefinition,
267
+ Language::Nodes::ScalarTypeDefinition,
268
+ Language::Nodes::ScalarTypeExtension,
269
+ Language::Nodes::SchemaDefinition,
270
+ Language::Nodes::SchemaExtension,
271
+ Language::Nodes::TypeName,
272
+ Language::Nodes::UnionTypeDefinition,
273
+ Language::Nodes::UnionTypeExtension,
274
+ Language::Nodes::VariableDefinition,
275
+ Language::Nodes::VariableIdentifier,
276
+ ].each do |ast_node_class|
277
+ make_visit_methods(ast_node_class)
278
+ end
165
279
 
166
280
  private
167
281
 
168
- # Run the hooks for `node`, and if the hooks return a copy of `node`,
169
- # copy `parent` so that it contains the copy of that node as a child,
170
- # then return the copies
171
- # If a non-array value is returned, consuming functions should ignore
172
- # said value
173
- def on_node_with_modifications(node, parent)
174
- new_node_and_new_parent = visit_node(node, parent)
282
+ def apply_modifications(node, parent, new_node_and_new_parent)
175
283
  if new_node_and_new_parent.is_a?(Array)
176
284
  new_node = new_node_and_new_parent[0]
177
285
  new_parent = new_node_and_new_parent[1]
@@ -7,14 +7,6 @@ module GraphQL
7
7
  class ActiveRecordRelationConnection < Pagination::RelationConnection
8
8
  private
9
9
 
10
- def relation_larger_than(relation, initial_offset, size)
11
- if already_loaded?(relation)
12
- (relation.size + initial_offset) > size
13
- else
14
- set_offset(sliced_nodes, initial_offset + size).exists?
15
- end
16
- end
17
-
18
10
  def relation_count(relation)
19
11
  int_or_hash = if already_loaded?(relation)
20
12
  relation.size
@@ -58,7 +58,7 @@ module GraphQL
58
58
  # @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection
59
59
  # @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given and no `default_page_size` is set.
60
60
  # @param default_page_size [Integer, nil] A configured value to determine the result size when neither first or last are given.
61
- def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, default_page_size: :not_given, last: nil, before: nil, edge_class: nil, arguments: nil)
61
+ def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, last: nil, before: nil, edge_class: nil, arguments: nil)
62
62
  @items = items
63
63
  @parent = parent
64
64
  @context = context
@@ -71,14 +71,14 @@ module GraphQL
71
71
  @edge_class = edge_class || self.class::Edge
72
72
  # This is only true if the object was _initialized_ with an override
73
73
  # or if one is assigned later.
74
- @has_max_page_size_override = max_page_size != :not_given
75
- @max_page_size = if max_page_size == :not_given
74
+ @has_max_page_size_override = max_page_size != NOT_CONFIGURED
75
+ @max_page_size = if max_page_size == NOT_CONFIGURED
76
76
  nil
77
77
  else
78
78
  max_page_size
79
79
  end
80
- @has_default_page_size_override = default_page_size != :not_given
81
- @default_page_size = if default_page_size == :not_given
80
+ @has_default_page_size_override = default_page_size != NOT_CONFIGURED
81
+ @default_page_size = if default_page_size == NOT_CONFIGURED
82
82
  nil
83
83
  else
84
84
  default_page_size