graphql 2.0.17.2 → 2.0.21

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast.rb +2 -2
  3. data/lib/graphql/backtrace/trace.rb +96 -0
  4. data/lib/graphql/backtrace/tracer.rb +1 -1
  5. data/lib/graphql/backtrace.rb +6 -1
  6. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  7. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -3
  8. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  9. data/lib/graphql/execution/interpreter/runtime.rb +254 -211
  10. data/lib/graphql/execution/interpreter.rb +9 -14
  11. data/lib/graphql/execution/lazy.rb +2 -4
  12. data/lib/graphql/execution/multiplex.rb +2 -1
  13. data/lib/graphql/filter.rb +7 -2
  14. data/lib/graphql/language/document_from_schema_definition.rb +25 -9
  15. data/lib/graphql/language/lexer.rb +216 -1505
  16. data/lib/graphql/language/nodes.rb +27 -9
  17. data/lib/graphql/language/parser.rb +509 -491
  18. data/lib/graphql/language/parser.y +43 -38
  19. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  20. data/lib/graphql/pagination/connection.rb +5 -5
  21. data/lib/graphql/query/context.rb +62 -31
  22. data/lib/graphql/query/null_context.rb +1 -1
  23. data/lib/graphql/query.rb +22 -5
  24. data/lib/graphql/schema/argument.rb +7 -9
  25. data/lib/graphql/schema/build_from_definition.rb +15 -3
  26. data/lib/graphql/schema/enum_value.rb +2 -5
  27. data/lib/graphql/schema/field.rb +44 -31
  28. data/lib/graphql/schema/field_extension.rb +1 -4
  29. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  30. data/lib/graphql/schema/member/base_dsl_methods.rb +13 -11
  31. data/lib/graphql/schema/member/has_arguments.rb +1 -1
  32. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  33. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  34. data/lib/graphql/schema/member/has_directives.rb +15 -10
  35. data/lib/graphql/schema/member/has_fields.rb +87 -37
  36. data/lib/graphql/schema/member/has_validators.rb +2 -2
  37. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  38. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  39. data/lib/graphql/schema/object.rb +2 -4
  40. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  41. data/lib/graphql/schema/resolver.rb +4 -4
  42. data/lib/graphql/schema/timeout.rb +24 -28
  43. data/lib/graphql/schema/validator.rb +1 -1
  44. data/lib/graphql/schema/warden.rb +11 -2
  45. data/lib/graphql/schema.rb +72 -1
  46. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  47. data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
  48. data/lib/graphql/static_validation/validator.rb +1 -1
  49. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  50. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  51. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  52. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  53. data/lib/graphql/tracing/legacy_trace.rb +65 -0
  54. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  55. data/lib/graphql/tracing/notifications_trace.rb +42 -0
  56. data/lib/graphql/tracing/platform_trace.rb +109 -0
  57. data/lib/graphql/tracing/platform_tracing.rb +15 -3
  58. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  59. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
  60. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  61. data/lib/graphql/tracing/scout_trace.rb +72 -0
  62. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  63. data/lib/graphql/tracing/trace.rb +75 -0
  64. data/lib/graphql/tracing.rb +16 -39
  65. data/lib/graphql/type_kinds.rb +6 -3
  66. data/lib/graphql/types/relay/base_connection.rb +1 -1
  67. data/lib/graphql/types/relay/connection_behaviors.rb +24 -2
  68. data/lib/graphql/types/relay/edge_behaviors.rb +16 -2
  69. data/lib/graphql/types/relay/node_behaviors.rb +7 -1
  70. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  71. data/lib/graphql/types/relay.rb +0 -1
  72. data/lib/graphql/version.rb +1 -1
  73. data/lib/graphql.rb +16 -9
  74. metadata +33 -8
  75. data/lib/graphql/language/lexer.rl +0 -280
  76. 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
 
@@ -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
@@ -91,22 +91,31 @@ module GraphQL
91
91
  end
92
92
 
93
93
  class ScopedContext
94
+ NO_PATH = GraphQL::EmptyObjects::EMPTY_ARRAY
95
+ NO_CONTEXT = GraphQL::EmptyObjects::EMPTY_HASH
96
+
94
97
  def initialize(query_context)
95
98
  @query_context = query_context
96
- @scoped_contexts = {}
97
- @no_path = [].freeze
99
+ @scoped_contexts = nil
100
+ @all_keys = nil
98
101
  end
99
102
 
100
103
  def merged_context
101
- merged_ctx = {}
102
- each_present_path_ctx do |path_ctx|
103
- merged_ctx = path_ctx.merge(merged_ctx)
104
+ if @scoped_contexts.nil?
105
+ NO_CONTEXT
106
+ else
107
+ merged_ctx = {}
108
+ each_present_path_ctx do |path_ctx|
109
+ merged_ctx = path_ctx.merge(merged_ctx)
110
+ end
111
+ merged_ctx
104
112
  end
105
- merged_ctx
106
113
  end
107
114
 
108
115
  def merge!(hash)
109
- ctx = @scoped_contexts
116
+ @all_keys ||= Set.new
117
+ @all_keys.merge(hash.keys)
118
+ ctx = @scoped_contexts ||= {}
110
119
  current_path.each do |path_part|
111
120
  ctx = ctx[path_part] ||= { parent: ctx }
112
121
  end
@@ -114,15 +123,12 @@ module GraphQL
114
123
  this_scoped_ctx.merge!(hash)
115
124
  end
116
125
 
117
- def current_path
118
- thread_info = Thread.current[:__graphql_runtime_info]
119
- (thread_info && thread_info[:current_path]) || @no_path
120
- end
121
-
122
126
  def key?(key)
123
- each_present_path_ctx do |path_ctx|
124
- if path_ctx.key?(key)
125
- return true
127
+ if @all_keys && @all_keys.include?(key)
128
+ each_present_path_ctx do |path_ctx|
129
+ if path_ctx.key?(key)
130
+ return true
131
+ end
126
132
  end
127
133
  end
128
134
  false
@@ -137,6 +143,10 @@ module GraphQL
137
143
  nil
138
144
  end
139
145
 
146
+ def current_path
147
+ @query_context.current_path || NO_PATH
148
+ end
149
+
140
150
  def dig(key, *other_keys)
141
151
  each_present_path_ctx do |path_ctx|
142
152
  if path_ctx.key?(key)
@@ -157,19 +167,23 @@ module GraphQL
157
167
  # but look up the tree for previously-assigned scoped values
158
168
  def each_present_path_ctx
159
169
  ctx = @scoped_contexts
160
- current_path.each do |path_part|
161
- if ctx.key?(path_part)
162
- ctx = ctx[path_part]
163
- else
164
- break
170
+ if ctx.nil?
171
+ # no-op
172
+ else
173
+ current_path.each do |path_part|
174
+ if ctx.key?(path_part)
175
+ ctx = ctx[path_part]
176
+ else
177
+ break
178
+ end
165
179
  end
166
- end
167
180
 
168
- while ctx
169
- if (scoped_ctx = ctx[:scoped_context])
170
- yield(scoped_ctx)
181
+ while ctx
182
+ if (scoped_ctx = ctx[:scoped_context])
183
+ yield(scoped_ctx)
184
+ end
185
+ ctx = ctx[:parent]
171
186
  end
172
- ctx = ctx[:parent]
173
187
  end
174
188
  end
175
189
  end
@@ -209,14 +223,30 @@ module GraphQL
209
223
  elsif @provided_values.key?(key)
210
224
  @provided_values[key]
211
225
  elsif RUNTIME_METADATA_KEYS.include?(key)
212
- thread_info = Thread.current[:__graphql_runtime_info]
213
- thread_info && thread_info[key]
226
+ if key == :current_path
227
+ current_path
228
+ else
229
+ (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
230
+ (current_runtime_state.public_send(key))
231
+ end
214
232
  else
215
233
  # not found
216
234
  nil
217
235
  end
218
236
  end
219
237
 
238
+ def current_path
239
+ current_runtime_state = Thread.current[:__graphql_runtime_info]
240
+ path = current_runtime_state &&
241
+ (result = current_runtime_state.current_result) &&
242
+ (result.path)
243
+ if path && (rn = current_runtime_state.current_result_name)
244
+ path = path.dup
245
+ path.push(rn)
246
+ end
247
+ path
248
+ end
249
+
220
250
  def delete(key)
221
251
  if @scoped_context.key?(key)
222
252
  @scoped_context.delete(key)
@@ -229,8 +259,8 @@ module GraphQL
229
259
 
230
260
  def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
231
261
  if RUNTIME_METADATA_KEYS.include?(key)
232
- (thread_info = Thread.current[:__graphql_runtime_info]) &&
233
- thread_info[key]
262
+ (runtime = Thread.current[:__graphql_runtime_info]) &&
263
+ (runtime.public_send(key))
234
264
  elsif @scoped_context.key?(key)
235
265
  scoped_context[key]
236
266
  elsif @provided_values.key?(key)
@@ -246,8 +276,9 @@ module GraphQL
246
276
 
247
277
  def dig(key, *other_keys)
248
278
  if RUNTIME_METADATA_KEYS.include?(key)
249
- (thread_info = Thread.current[:__graphql_runtime_info]).key?(key) &&
250
- thread_info.dig(key, *other_keys)
279
+ (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
280
+ (obj = current_runtime_state.public_send(key)) &&
281
+ obj.dig(*other_keys)
251
282
  elsif @scoped_context.key?(key)
252
283
  @scoped_context.dig(key, *other_keys)
253
284
  else
@@ -24,7 +24,7 @@ module GraphQL
24
24
  @dataloader = GraphQL::Dataloader::NullDataloader.new
25
25
  @schema = NullSchema
26
26
  @warden = NullWarden.new(
27
- GraphQL::Filter.new,
27
+ GraphQL::Filter.new(silence_deprecation_warning: true),
28
28
  context: self,
29
29
  schema: @schema,
30
30
  )
data/lib/graphql/query.rb CHANGED
@@ -95,12 +95,24 @@ module GraphQL
95
95
  @fragments = nil
96
96
  @operations = nil
97
97
  @validate = validate
98
- @tracers = schema.tracers + (context ? context.fetch(:tracers, []) : [])
98
+ context_tracers = (context ? context.fetch(:tracers, []) : [])
99
+ @tracers = schema.tracers + context_tracers
100
+
99
101
  # Support `ctx[:backtrace] = true` for wrapping backtraces
100
102
  if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
101
- @tracers << GraphQL::Backtrace::Tracer
103
+ if schema.trace_class <= GraphQL::Tracing::LegacyTrace
104
+ context_tracers += [GraphQL::Backtrace::Tracer]
105
+ @tracers << GraphQL::Backtrace::Tracer
106
+ elsif !(current_trace.class <= GraphQL::Backtrace::Trace)
107
+ raise "Invariant: `backtrace: true` should have provided a trace class with Backtrace mixed in, but it didnt. (Found: #{current_trace.class.ancestors}). This is a bug in GraphQL-Ruby, please report it on GitHub."
108
+ end
109
+ end
110
+
111
+ if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::LegacyTrace)
112
+ raise ArgumentError, "context[:tracers] are not supported without `trace_class(GraphQL::Tracing::LegacyTrace)` in the schema configuration, please add it."
102
113
  end
103
114
 
115
+
104
116
  @analysis_errors = []
105
117
  if variables.is_a?(String)
106
118
  raise ArgumentError, "Query variables should be a Hash, not a String. Try JSON.parse to prepare variables."
@@ -157,6 +169,11 @@ module GraphQL
157
169
 
158
170
  attr_accessor :multiplex
159
171
 
172
+ # @return [GraphQL::Tracing::Trace]
173
+ def current_trace
174
+ @current_trace ||= multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self)
175
+ end
176
+
160
177
  def subscription_update?
161
178
  @subscription_topic && subscription?
162
179
  end
@@ -305,8 +322,8 @@ module GraphQL
305
322
  # @param value [Object] Any runtime value
306
323
  # @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
307
324
  # @see {#possible_types} to apply filtering from `only` / `except`
308
- def resolve_type(abstract_type, value = :__undefined__)
309
- if value.is_a?(Symbol) && value == :__undefined__
325
+ def resolve_type(abstract_type, value = NOT_CONFIGURED)
326
+ if value.is_a?(Symbol) && value == NOT_CONFIGURED
310
327
  # Old method signature
311
328
  value = abstract_type
312
329
  abstract_type = nil
@@ -362,7 +379,7 @@ module GraphQL
362
379
  parse_error = nil
363
380
  @document ||= begin
364
381
  if query_string
365
- GraphQL.parse(query_string, tracer: self)
382
+ GraphQL.parse(query_string, trace: self.current_trace)
366
383
  end
367
384
  rescue GraphQL::ParseError => err
368
385
  parse_error = err
@@ -7,9 +7,7 @@ module GraphQL
7
7
  include GraphQL::Schema::Member::HasDirectives
8
8
  include GraphQL::Schema::Member::HasDeprecationReason
9
9
  include GraphQL::Schema::Member::HasValidators
10
- include GraphQL::Schema::FindInheritedValue::EmptyObjects
11
-
12
- NO_DEFAULT = :__no_default__
10
+ include GraphQL::EmptyObjects
13
11
 
14
12
  # @return [String] the GraphQL name for this argument, camelized unless `camelize: false` is provided
15
13
  attr_reader :name
@@ -20,8 +18,8 @@ module GraphQL
20
18
 
21
19
  # @param new_prepare [Method, Proc]
22
20
  # @return [Symbol] A method or proc to call to transform this value before sending it to field resolution method
23
- def prepare(new_prepare = NO_DEFAULT)
24
- if new_prepare != NO_DEFAULT
21
+ def prepare(new_prepare = NOT_CONFIGURED)
22
+ if new_prepare != NOT_CONFIGURED
25
23
  @prepare = new_prepare
26
24
  end
27
25
  @prepare
@@ -52,7 +50,7 @@ module GraphQL
52
50
  # @param deprecation_reason [String]
53
51
  # @param validates [Hash, nil] Options for building validators, if any should be applied
54
52
  # @param replace_null_with_default [Boolean] if `true`, incoming values of `null` will be replaced with the configured `default_value`
55
- def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
53
+ def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NOT_CONFIGURED, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
56
54
  arg_name ||= name
57
55
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
58
56
  @type_expr = type_expr || type
@@ -104,8 +102,8 @@ module GraphQL
104
102
 
105
103
  # @param default_value [Object] The value to use when the client doesn't provide one
106
104
  # @return [Object] the value used when the client doesn't provide a value for this argument
107
- def default_value(new_default_value = NO_DEFAULT)
108
- if new_default_value != NO_DEFAULT
105
+ def default_value(new_default_value = NOT_CONFIGURED)
106
+ if new_default_value != NOT_CONFIGURED
109
107
  @default_value = new_default_value
110
108
  end
111
109
  @default_value
@@ -113,7 +111,7 @@ module GraphQL
113
111
 
114
112
  # @return [Boolean] True if this argument has a default value
115
113
  def default_value?
116
- @default_value != NO_DEFAULT
114
+ @default_value != NOT_CONFIGURED
117
115
  end
118
116
 
119
117
  def replace_null_with_default?
@@ -21,6 +21,7 @@ module GraphQL
21
21
 
22
22
  # @api private
23
23
  module Builder
24
+ include GraphQL::EmptyObjects
24
25
  extend self
25
26
 
26
27
  def build(schema_superclass, document, default_resolve:, using: {}, relay:)
@@ -99,6 +100,16 @@ module GraphQL
99
100
  raise InvalidDocumentError.new("Specified subscription type \"#{schema_definition.subscription}\" not found in document.") unless types[schema_definition.subscription]
100
101
  subscription_root_type = types[schema_definition.subscription]
101
102
  end
103
+
104
+ if schema_definition.query.nil? &&
105
+ schema_definition.mutation.nil? &&
106
+ schema_definition.subscription.nil?
107
+ # This schema may have been given with directives only,
108
+ # check for defaults:
109
+ query_root_type = types['Query']
110
+ mutation_root_type = types['Mutation']
111
+ subscription_root_type = types['Subscription']
112
+ end
102
113
  else
103
114
  query_root_type = types['Query']
104
115
  mutation_root_type = types['Mutation']
@@ -107,6 +118,8 @@ module GraphQL
107
118
 
108
119
  raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
109
120
 
121
+ builder = self
122
+
110
123
  schema_class = Class.new(schema_superclass) do
111
124
  begin
112
125
  # Add these first so that there's some chance of resolving late-bound types
@@ -134,6 +147,7 @@ module GraphQL
134
147
 
135
148
  if schema_definition
136
149
  ast_node(schema_definition)
150
+ builder.build_directives(self, schema_definition, type_resolver)
137
151
  end
138
152
 
139
153
  using.each do |plugin, options|
@@ -361,8 +375,6 @@ module GraphQL
361
375
  end
362
376
  end
363
377
 
364
- NO_DEFAULT_VALUE = {}.freeze
365
-
366
378
  def build_arguments(type_class, arguments, type_resolver)
367
379
  builder = self
368
380
 
@@ -370,7 +382,7 @@ module GraphQL
370
382
  default_value_kwargs = if !argument_defn.default_value.nil?
371
383
  { default_value: builder.build_default_value(argument_defn.default_value) }
372
384
  else
373
- NO_DEFAULT_VALUE
385
+ EMPTY_HASH
374
386
  end
375
387
 
376
388
  type_class.argument(
@@ -25,19 +25,16 @@ module GraphQL
25
25
  include GraphQL::Schema::Member::HasDirectives
26
26
  include GraphQL::Schema::Member::HasDeprecationReason
27
27
 
28
- UNDEFINED_VALUE = Object.new.freeze
29
- private_constant :UNDEFINED_VALUE
30
-
31
28
  attr_reader :graphql_name
32
29
 
33
30
  # @return [Class] The enum type that owns this value
34
31
  attr_reader :owner
35
32
 
36
- def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: UNDEFINED_VALUE, deprecation_reason: nil, &block)
33
+ def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: NOT_CONFIGURED, deprecation_reason: nil, &block)
37
34
  @graphql_name = graphql_name.to_s
38
35
  GraphQL::NameValidator.validate!(@graphql_name)
39
36
  @description = desc || description
40
- @value = value === UNDEFINED_VALUE ? @graphql_name : value
37
+ @value = value === NOT_CONFIGURED ? @graphql_name : value
41
38
  if deprecation_reason
42
39
  self.deprecation_reason = deprecation_reason
43
40
  end