graphql 2.4.8 → 2.4.9

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 386222d0dc13d35729460ee8f3cd9fa30f90db9cb7dc2b2392489c9e0bc8939b
4
- data.tar.gz: 5229e7ee84d4c4e0a0c8afd10ef2b0185b0eedfc611a8db38047171d9c04a6e2
3
+ metadata.gz: 687da1733554d6abed2daad506c7f9d55d9126e373274572af5b255c3d7b4918
4
+ data.tar.gz: c2d2f58175df62c91ab31c3216b970a0bc09d1752250fc8192d1faa958cf1fe9
5
5
  SHA512:
6
- metadata.gz: 4cb91383b995e8714915d2c99d8c2d4fa15eaad91f0069766d7e8d379cae15c2aae6eb7a3961e440d62a961837a044aed604802960f199e8670ecf973c991fb2
7
- data.tar.gz: 8cd21fd942892100a0647bf9897e6e7d8651d184aee76a2988633fa3e9dc505163f330bb1f0ca3f4819cbb3248cd88e9ac252f516449ae169c1a3f47a982e11c
6
+ metadata.gz: f4001700112f8ed43e78b4c739daac90973f08035bef426d5611d91248dd60d4d0070f8fff7042ac57b0549ddac62ac1111262fe0a47c10a83cd3c7a9a0612b8
7
+ data.tar.gz: a6a1aaacf19bba38d2e0ee55ac9cdfa0d46b915706557c2dbac533d8fc58319d7c4ff8509019789fb39c46d6c01767f6cd27a02917fc7a3a7bdc30fc81eca5e4
@@ -36,7 +36,70 @@ module GraphQL
36
36
  private
37
37
 
38
38
  def rows
39
- @rows ||= build_rows(@context, rows: [HEADERS], top: true)
39
+ @rows ||= begin
40
+ query = @context.query
41
+ query_ctx = @context
42
+ runtime_inst = query_ctx.namespace(:interpreter_runtime)[:runtime]
43
+ result = runtime_inst.instance_variable_get(:@response)
44
+ rows = []
45
+ result_path = []
46
+ last_part = nil
47
+ path = @context.current_path
48
+ path.each do |path_part|
49
+ value = value_at(runtime_inst, result_path)
50
+
51
+ if result_path.empty?
52
+ name = query.selected_operation.operation_type || "query"
53
+ if (n = query.selected_operation_name)
54
+ name += " #{n}"
55
+ end
56
+ args = query.variables
57
+ else
58
+ name = result.graphql_field.path
59
+ args = result.graphql_arguments
60
+ end
61
+
62
+ object = result.graphql_parent ? result.graphql_parent.graphql_application_value : result.graphql_application_value
63
+ object = object.object.inspect
64
+
65
+ rows << [
66
+ result.ast_node.position.join(":"),
67
+ name,
68
+ "#{object}",
69
+ args.to_h.inspect,
70
+ inspect_result(value),
71
+ ]
72
+
73
+ result_path << path_part
74
+ if path_part == path.last
75
+ last_part = path_part
76
+ else
77
+ result = result[path_part]
78
+ end
79
+ end
80
+
81
+
82
+ object = result.graphql_application_value.object.inspect
83
+ ast_node = result.graphql_selections.find { |s| s.alias == last_part || s.name == last_part }
84
+ field_defn = query.get_field(result.graphql_result_type, ast_node.name)
85
+ args = query.arguments_for(ast_node, field_defn).to_h
86
+ field_path = field_defn.path
87
+ if ast_node.alias
88
+ field_path += " as #{ast_node.alias}"
89
+ end
90
+
91
+ rows << [
92
+ ast_node.position.join(":"),
93
+ field_path,
94
+ "#{object}",
95
+ args.inspect,
96
+ inspect_result(@override_value)
97
+ ]
98
+
99
+ rows << HEADERS
100
+ rows.reverse!
101
+ rows
102
+ end
40
103
  end
41
104
 
42
105
  # @return [String]
@@ -75,67 +138,44 @@ module GraphQL
75
138
  table
76
139
  end
77
140
 
78
- # @return [Array] 5 items for a backtrace table (not `key`)
79
- def build_rows(context_entry, rows:, top: false)
80
- case context_entry
81
- when Backtrace::Frame
82
- field_alias = context_entry.ast_node.respond_to?(:alias) && context_entry.ast_node.alias
83
- value = if top && @override_value
84
- @override_value
85
- else
86
- value_at(@context.query.context.namespace(:interpreter_runtime)[:runtime], context_entry.path)
87
- end
88
- rows << [
89
- "#{context_entry.ast_node ? context_entry.ast_node.position.join(":") : ""}",
90
- "#{context_entry.field.path}#{field_alias ? " as #{field_alias}" : ""}",
91
- "#{context_entry.object.object.inspect}",
92
- context_entry.arguments.to_h.inspect, # rubocop:disable Development/ContextIsPassedCop -- unrelated method
93
- Backtrace::InspectResult.inspect_result(value),
94
- ]
95
- if (parent = context_entry.parent_frame)
96
- build_rows(parent, rows: rows)
97
- else
98
- rows
99
- end
100
- when GraphQL::Query::Context
101
- query = context_entry.query
102
- op = query.selected_operation
103
- if op
104
- op_type = op.operation_type
105
- position = "#{op.line}:#{op.col}"
106
- else
107
- op_type = "query"
108
- position = "?:?"
109
- end
110
- op_name = query.selected_operation_name
111
- object = query.root_value
112
- if object.is_a?(GraphQL::Schema::Object)
113
- object = object.object
114
- end
115
- value = value_at(context_entry.namespace(:interpreter_runtime)[:runtime], [])
116
- rows << [
117
- "#{position}",
118
- "#{op_type}#{op_name ? " #{op_name}" : ""}",
119
- "#{object.inspect}",
120
- query.variables.to_h.inspect,
121
- Backtrace::InspectResult.inspect_result(value),
122
- ]
123
- else
124
- raise "Unexpected get_rows subject #{context_entry.class} (#{context_entry.inspect})"
125
- end
126
- end
127
141
 
128
142
  def value_at(runtime, path)
129
143
  response = runtime.final_result
130
144
  path.each do |key|
131
- if response && (response = response[key])
132
- next
133
- else
134
- break
135
- end
145
+ response && (response = response[key])
136
146
  end
137
147
  response
138
148
  end
149
+
150
+ def inspect_result(obj)
151
+ case obj
152
+ when Hash
153
+ "{" +
154
+ obj.map do |key, val|
155
+ "#{key}: #{inspect_truncated(val)}"
156
+ end.join(", ") +
157
+ "}"
158
+ when Array
159
+ "[" +
160
+ obj.map { |v| inspect_truncated(v) }.join(", ") +
161
+ "]"
162
+ else
163
+ inspect_truncated(obj)
164
+ end
165
+ end
166
+
167
+ def inspect_truncated(obj)
168
+ case obj
169
+ when Hash
170
+ "{...}"
171
+ when Array
172
+ "[...]"
173
+ when GraphQL::Execution::Lazy
174
+ "(unresolved)"
175
+ else
176
+ "#{obj.inspect}"
177
+ end
178
+ end
139
179
  end
140
180
  end
141
181
  end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/backtrace/inspect_result"
3
2
  require "graphql/backtrace/table"
4
3
  require "graphql/backtrace/traced_error"
5
- require "graphql/backtrace/tracer"
6
- require "graphql/backtrace/trace"
7
4
  module GraphQL
8
5
  # Wrap unhandled errors with {TracedError}.
9
6
  #
@@ -24,7 +21,7 @@ module GraphQL
24
21
  def_delegators :to_a, :each, :[]
25
22
 
26
23
  def self.use(schema_defn)
27
- schema_defn.trace_with(self::Trace)
24
+ schema_defn.using_backtrace = true
28
25
  end
29
26
 
30
27
  def initialize(context, value: nil)
@@ -40,20 +37,5 @@ module GraphQL
40
37
  def to_a
41
38
  @table.to_backtrace
42
39
  end
43
-
44
- # Used for internal bookkeeping
45
- # @api private
46
- class Frame
47
- attr_reader :path, :query, :ast_node, :object, :field, :arguments, :parent_frame
48
- def initialize(path:, query:, ast_node:, object:, field:, arguments:, parent_frame:)
49
- @path = path
50
- @query = query
51
- @ast_node = ast_node
52
- @field = field
53
- @object = object
54
- @arguments = arguments
55
- @parent_frame = parent_frame
56
- end
57
- end
58
40
  end
59
41
  end
@@ -5,7 +5,10 @@ module GraphQL
5
5
  class Interpreter
6
6
  class Runtime
7
7
  module GraphQLResult
8
- def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent, selections, is_eager)
8
+ def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent, selections, is_eager, ast_node, graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
9
+ @ast_node = ast_node
10
+ @graphql_arguments = graphql_arguments
11
+ @graphql_field = graphql_field
9
12
  @graphql_parent = parent_result
10
13
  @graphql_application_value = application_value
11
14
  @graphql_result_type = result_type
@@ -31,14 +34,14 @@ module GraphQL
31
34
 
32
35
  attr_accessor :graphql_dead
33
36
  attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent,
34
- :graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager
37
+ :graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager, :ast_node, :graphql_arguments, :graphql_field
35
38
 
36
39
  # @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
37
40
  attr_accessor :graphql_result_data
38
41
  end
39
42
 
40
43
  class GraphQLResultHash
41
- def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
44
+ def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager, _ast_node, _graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
42
45
  super
43
46
  @graphql_result_data = {}
44
47
  end
@@ -126,7 +129,7 @@ module GraphQL
126
129
  class GraphQLResultArray
127
130
  include GraphQLResult
128
131
 
129
- def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
132
+ def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager, _ast_node, _graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
130
133
  super
131
134
  @graphql_result_data = []
132
135
  end
@@ -168,6 +171,10 @@ module GraphQL
168
171
  def values
169
172
  (@graphql_metadata || @graphql_result_data)
170
173
  end
174
+
175
+ def [](idx)
176
+ (@graphql_metadata || @graphql_result_data)[idx]
177
+ end
171
178
  end
172
179
  end
173
180
  end
@@ -74,7 +74,7 @@ module GraphQL
74
74
  runtime_object = root_type.wrap(query.root_value, context)
75
75
  runtime_object = schema.sync_lazy(runtime_object)
76
76
  is_eager = root_op_type == "mutation"
77
- @response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, root_operation.selections, is_eager)
77
+ @response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, root_operation.selections, is_eager, root_operation, nil, nil)
78
78
  st = get_current_runtime_state
79
79
  st.current_result = @response
80
80
 
@@ -85,7 +85,7 @@ module GraphQL
85
85
  call_method_on_directives(:resolve, runtime_object, root_operation.directives) do # execute query level directives
86
86
  each_gathered_selections(@response) do |selections, is_selection_array|
87
87
  if is_selection_array
88
- selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, selections, is_eager)
88
+ selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, selections, is_eager, root_operation, nil, nil)
89
89
  final_response = @response
90
90
  else
91
91
  selection_response = @response
@@ -574,7 +574,7 @@ module GraphQL
574
574
  r = begin
575
575
  current_type.coerce_result(value, context)
576
576
  rescue StandardError => err
577
- schema.handle_or_reraise(context, err)
577
+ query.handle_or_reraise(err)
578
578
  end
579
579
  set_result(selection_result, result_name, r, false, is_non_null)
580
580
  r
@@ -609,11 +609,11 @@ module GraphQL
609
609
  after_lazy(object_proxy, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_object, runtime_state|
610
610
  continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
611
611
  if HALT != continue_value
612
- response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false)
612
+ response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
613
613
  set_result(selection_result, result_name, response_hash, true, is_non_null)
614
614
  each_gathered_selections(response_hash) do |selections, is_selection_array|
615
615
  if is_selection_array
616
- this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false)
616
+ this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false, ast_node, arguments, field)
617
617
  final_result = response_hash
618
618
  else
619
619
  this_result = response_hash
@@ -634,35 +634,43 @@ module GraphQL
634
634
  # This is true for objects, unions, and interfaces
635
635
  use_dataloader_job = !inner_type.unwrap.kind.input?
636
636
  inner_type_non_null = inner_type.non_null?
637
- response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false)
637
+ response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
638
638
  set_result(selection_result, result_name, response_list, true, is_non_null)
639
639
  idx = nil
640
640
  list_value = begin
641
- value.each do |inner_value|
642
- idx ||= 0
643
- this_idx = idx
644
- idx += 1
645
- if use_dataloader_job
646
- @dataloader.append_job do
641
+ begin
642
+ value.each do |inner_value|
643
+ idx ||= 0
644
+ this_idx = idx
645
+ idx += 1
646
+ if use_dataloader_job
647
+ @dataloader.append_job do
648
+ resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
649
+ end
650
+ else
647
651
  resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
648
652
  end
649
- else
650
- resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
651
653
  end
652
- end
653
654
 
654
- response_list
655
- rescue NoMethodError => err
656
- # Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
657
- if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
658
- # This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
659
- raise ListResultFailedError.new(value: value, field: field, path: current_path)
660
- else
661
- # This was some other NoMethodError -- let it bubble to reveal the real error.
662
- raise
655
+ response_list
656
+ rescue NoMethodError => err
657
+ # Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
658
+ if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
659
+ # This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
660
+ raise ListResultFailedError.new(value: value, field: field, path: current_path)
661
+ else
662
+ # This was some other NoMethodError -- let it bubble to reveal the real error.
663
+ raise
664
+ end
665
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
666
+ ex_err
667
+ rescue StandardError => err
668
+ begin
669
+ query.handle_or_reraise(err)
670
+ rescue GraphQL::ExecutionError => ex_err
671
+ ex_err
672
+ end
663
673
  end
664
- rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
665
- ex_err
666
674
  rescue StandardError => err
667
675
  begin
668
676
  query.handle_or_reraise(err)
@@ -35,10 +35,6 @@ module GraphQL
35
35
  @current_trace = @context[:trace] || schema.new_trace(multiplex: self)
36
36
  @dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
37
37
  @tracers = schema.tracers + (context[:tracers] || [])
38
- # Support `context: {backtrace: true}`
39
- if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
40
- @tracers << GraphQL::Backtrace::Tracer
41
- end
42
38
  @max_complexity = max_complexity
43
39
  end
44
40
  end
@@ -7,7 +7,7 @@ module GraphQL
7
7
  "a __DirectiveLocation describes one such possible adjacencies."
8
8
 
9
9
  GraphQL::Schema::Directive::LOCATIONS.each do |location|
10
- value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location)
10
+ value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location, value_method: false)
11
11
  end
12
12
  introspection true
13
13
  end
data/lib/graphql/query.rb CHANGED
@@ -127,14 +127,6 @@ module GraphQL
127
127
  context_tracers = (context ? context.fetch(:tracers, []) : [])
128
128
  @tracers = schema.tracers + context_tracers
129
129
 
130
- # Support `ctx[:backtrace] = true` for wrapping backtraces
131
- if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
132
- if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
133
- context_tracers += [GraphQL::Backtrace::Tracer]
134
- @tracers << GraphQL::Backtrace::Tracer
135
- end
136
- end
137
-
138
130
  if !context_tracers.empty? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
139
131
  raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
140
132
  end
@@ -298,6 +298,7 @@ module GraphQL
298
298
  description: enum_value_definition.description,
299
299
  directives: builder.prepare_directives(enum_value_definition, type_resolver),
300
300
  ast_node: enum_value_definition,
301
+ value_method: GraphQL::Schema::Enum.respond_to?(enum_value_definition.name.downcase) ? false : nil,
301
302
  )
302
303
  end
303
304
  end
@@ -61,12 +61,17 @@ module GraphQL
61
61
  # @option kwargs [String] :description, the GraphQL description for this value, present in documentation
62
62
  # @option kwargs [String] :comment, the GraphQL comment for this value, present in documentation
63
63
  # @option kwargs [::Object] :value the translated Ruby value for this object (defaults to `graphql_name`)
64
+ # @option kwargs [::Object] :value_method, the method name to fetch `graphql_name` (defaults to `graphql_name.downcase`)
64
65
  # @option kwargs [String] :deprecation_reason if this object is deprecated, include a message here
66
+ # @param value_method [Symbol, false] A method to generate for this value, or `false` to skip generation
65
67
  # @return [void]
66
68
  # @see {Schema::EnumValue} which handles these inputs by default
67
- def value(*args, **kwargs, &block)
69
+ def value(*args, value_method: nil, **kwargs, &block)
68
70
  kwargs[:owner] = self
69
71
  value = enum_value_class.new(*args, **kwargs, &block)
72
+
73
+ generate_value_method(value, value_method)
74
+
70
75
  key = value.graphql_name
71
76
  prev_value = own_values[key]
72
77
  case prev_value
@@ -223,6 +228,21 @@ module GraphQL
223
228
  def own_values
224
229
  @own_values ||= {}
225
230
  end
231
+
232
+ def generate_value_method(value, configured_value_method)
233
+ return if configured_value_method == false
234
+
235
+ value_method_name = configured_value_method || value.graphql_name.downcase
236
+
237
+ if respond_to?(value_method_name.to_sym)
238
+ warn "Failed to define value method for :#{value_method_name}, because " \
239
+ "#{value.owner.name || value.owner.graphql_name} already responds to that method. Use `value_method:` to override the method name " \
240
+ "or `value_method: false` to disable Enum value method generation."
241
+ return
242
+ end
243
+
244
+ instance_eval("def #{value_method_name}; #{value.graphql_name.inspect}; end;")
245
+ end
226
246
  end
227
247
 
228
248
  enum_value_class(GraphQL::Schema::EnumValue)
@@ -22,6 +22,7 @@ module GraphQL
22
22
  include Schema::Member::GraphQLTypeNames
23
23
  # Really we only need description & comment from here, but:
24
24
  extend Schema::Member::BaseDSLMethods
25
+ extend Member::BaseDSLMethods::ConfigurationExtension
25
26
  extend GraphQL::Schema::Member::HasArguments
26
27
  extend GraphQL::Schema::Member::HasValidators
27
28
  include Schema::Member::HasPath
@@ -51,19 +51,36 @@ module GraphQL
51
51
  end
52
52
 
53
53
  def validate(_object, context, value)
54
- matched_conditions = 0
54
+ fully_matched_conditions = 0
55
+ partially_matched_conditions = 0
55
56
 
56
57
  if !value.nil?
57
58
  @one_of.each do |one_of_condition|
58
59
  case one_of_condition
59
60
  when Symbol
60
61
  if value.key?(one_of_condition)
61
- matched_conditions += 1
62
+ fully_matched_conditions += 1
62
63
  end
63
64
  when Array
64
- if one_of_condition.all? { |k| value.key?(k) }
65
- matched_conditions += 1
66
- break
65
+ any_match = false
66
+ full_match = true
67
+
68
+ one_of_condition.each do |k|
69
+ if value.key?(k)
70
+ any_match = true
71
+ else
72
+ full_match = false
73
+ end
74
+ end
75
+
76
+ partial_match = !full_match && any_match
77
+
78
+ if full_match
79
+ fully_matched_conditions += 1
80
+ end
81
+
82
+ if partial_match
83
+ partially_matched_conditions += 1
67
84
  end
68
85
  else
69
86
  raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
@@ -71,7 +88,7 @@ module GraphQL
71
88
  end
72
89
  end
73
90
 
74
- if matched_conditions == 1
91
+ if fully_matched_conditions == 1 && partially_matched_conditions == 0
75
92
  nil # OK
76
93
  else
77
94
  @message || build_message(context)
@@ -159,7 +159,7 @@ module GraphQL
159
159
  end
160
160
  end
161
161
  end
162
- visible_f.ensure_loaded
162
+ visible_f&.ensure_loaded
163
163
  elsif f && @cached_visible_fields[owner][f.ensure_loaded]
164
164
  f
165
165
  else
@@ -167,9 +167,6 @@ module GraphQL
167
167
  mods.each { |mod| new_class.include(mod) }
168
168
  new_class.include(DefaultTraceClass)
169
169
  trace_mode(:default, new_class)
170
- backtrace_class = Class.new(new_class)
171
- backtrace_class.include(GraphQL::Backtrace::Trace)
172
- trace_mode(:default_backtrace, backtrace_class)
173
170
  end
174
171
  trace_class_for(:default, build: true)
175
172
  end
@@ -216,11 +213,6 @@ module GraphQL
216
213
  const_set(:DefaultTrace, Class.new(base_class) do
217
214
  include DefaultTraceClass
218
215
  end)
219
- when :default_backtrace
220
- schema_base_class = trace_class_for(:default, build: true)
221
- const_set(:DefaultTraceBacktrace, Class.new(schema_base_class) do
222
- include(GraphQL::Backtrace::Trace)
223
- end)
224
216
  else
225
217
  # First, see if the superclass has a custom-defined class for this.
226
218
  # Then, if it doesn't, use this class's default trace
@@ -1118,8 +1110,14 @@ module GraphQL
1118
1110
  }
1119
1111
  end
1120
1112
 
1113
+ # @api private
1114
+ attr_accessor :using_backtrace
1115
+
1121
1116
  # @api private
1122
1117
  def handle_or_reraise(context, err)
1118
+ if context[:backtrace] || using_backtrace
1119
+ err = GraphQL::Backtrace::TracedError.new(err, context)
1120
+ end
1123
1121
  handler = Execution::Errors.find_handler_for(self, err.class)
1124
1122
  if handler
1125
1123
  obj = context[:current_object]
@@ -1449,22 +1447,8 @@ module GraphQL
1449
1447
  target = options[:query] || options[:multiplex]
1450
1448
  mode ||= target && target.context[:trace_mode]
1451
1449
 
1452
- trace_mode = if mode
1453
- mode
1454
- elsif target && target.context[:backtrace]
1455
- if default_trace_mode != :default
1456
- raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
1457
- else
1458
- own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
1459
- options_trace_mode = :default
1460
- :default_backtrace
1461
- end
1462
- else
1463
- default_trace_mode
1464
- end
1465
-
1466
- options_trace_mode ||= trace_mode
1467
- base_trace_options = trace_options_for(options_trace_mode)
1450
+ trace_mode = mode || default_trace_mode
1451
+ base_trace_options = trace_options_for(trace_mode)
1468
1452
  trace_options = base_trace_options.merge(options)
1469
1453
  trace_class_for_mode = trace_class_for(trace_mode, build: true)
1470
1454
  trace_class_for_mode.new(**trace_options)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require "set"
3
- require "ostruct"
4
-
5
3
  module GraphQL
6
4
  class Subscriptions
7
5
  # Serialization helpers for passing subscription data around.
@@ -148,7 +146,7 @@ module GraphQL
148
146
  elsif obj.is_a?(Date) || obj.is_a?(Time)
149
147
  # DateTime extends Date; for TimeWithZone, call `.utc` first.
150
148
  { TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
151
- elsif obj.is_a?(OpenStruct)
149
+ elsif defined?(OpenStruct) && obj.is_a?(OpenStruct)
152
150
  { OPEN_STRUCT_KEY => dump_value(obj.to_h) }
153
151
  elsif defined?(ActiveRecord::Relation) && obj.is_a?(ActiveRecord::Relation)
154
152
  dump_value(obj.to_a)
@@ -8,7 +8,7 @@ module GraphQL
8
8
  # "Trace modes" are subclasses of this with custom tracing modules mixed in.
9
9
  #
10
10
  # A trace module may implement any of the methods on `Trace`, being sure to call `super`
11
- # to continue any tracing hooks and call the actual runtime behavior. See {GraphQL::Backtrace::Trace} for example.
11
+ # to continue any tracing hooks and call the actual runtime behavior.
12
12
  #
13
13
  class Trace
14
14
  # @param multiplex [GraphQL::Execution::Multiplex, nil]
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.4.8"
3
+ VERSION = "2.4.9"
4
4
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.8
4
+ version: 2.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-12-10 00:00:00.000000000 Z
10
+ date: 2025-01-29 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: base64
@@ -38,6 +37,20 @@ dependencies:
38
37
  - - ">="
39
38
  - !ruby/object:Gem::Version
40
39
  version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: logger
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
41
54
  - !ruby/object:Gem::Dependency
42
55
  name: benchmark-ips
43
56
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +191,76 @@ dependencies:
178
191
  - - ">="
179
192
  - !ruby/object:Gem::Version
180
193
  version: '0'
194
+ - !ruby/object:Gem::Dependency
195
+ name: simplecov
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ type: :development
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ - !ruby/object:Gem::Dependency
209
+ name: simplecov-lcov
210
+ requirement: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ type: :development
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ - !ruby/object:Gem::Dependency
223
+ name: undercover
224
+ requirement: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ version: '0'
229
+ type: :development
230
+ prerelease: false
231
+ version_requirements: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - ">="
234
+ - !ruby/object:Gem::Version
235
+ version: '0'
236
+ - !ruby/object:Gem::Dependency
237
+ name: pronto
238
+ requirement: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: '0'
243
+ type: :development
244
+ prerelease: false
245
+ version_requirements: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - ">="
248
+ - !ruby/object:Gem::Version
249
+ version: '0'
250
+ - !ruby/object:Gem::Dependency
251
+ name: pronto-undercover
252
+ requirement: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '0'
257
+ type: :development
258
+ prerelease: false
259
+ version_requirements: !ruby/object:Gem::Requirement
260
+ requirements:
261
+ - - ">="
262
+ - !ruby/object:Gem::Version
263
+ version: '0'
181
264
  - !ruby/object:Gem::Dependency
182
265
  name: jekyll
183
266
  requirement: !ruby/object:Gem::Requirement
@@ -248,6 +331,20 @@ dependencies:
248
331
  - - "~>"
249
332
  - !ruby/object:Gem::Version
250
333
  version: 1.5.0
334
+ - !ruby/object:Gem::Dependency
335
+ name: mutex_m
336
+ requirement: !ruby/object:Gem::Requirement
337
+ requirements:
338
+ - - ">="
339
+ - !ruby/object:Gem::Version
340
+ version: '0'
341
+ type: :development
342
+ prerelease: false
343
+ version_requirements: !ruby/object:Gem::Requirement
344
+ requirements:
345
+ - - ">="
346
+ - !ruby/object:Gem::Version
347
+ version: '0'
251
348
  - !ruby/object:Gem::Dependency
252
349
  name: webrick
253
350
  requirement: !ruby/object:Gem::Requirement
@@ -330,11 +427,8 @@ files:
330
427
  - lib/graphql/analysis_error.rb
331
428
  - lib/graphql/autoload.rb
332
429
  - lib/graphql/backtrace.rb
333
- - lib/graphql/backtrace/inspect_result.rb
334
430
  - lib/graphql/backtrace/table.rb
335
- - lib/graphql/backtrace/trace.rb
336
431
  - lib/graphql/backtrace/traced_error.rb
337
- - lib/graphql/backtrace/tracer.rb
338
432
  - lib/graphql/coercion_error.rb
339
433
  - lib/graphql/current.rb
340
434
  - lib/graphql/dataloader.rb
@@ -654,7 +748,6 @@ metadata:
654
748
  bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
655
749
  mailing_list_uri: https://buttondown.email/graphql-ruby
656
750
  rubygems_mfa_required: 'true'
657
- post_install_message:
658
751
  rdoc_options: []
659
752
  require_paths:
660
753
  - lib
@@ -669,8 +762,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
669
762
  - !ruby/object:Gem::Version
670
763
  version: '0'
671
764
  requirements: []
672
- rubygems_version: 3.5.12
673
- signing_key:
765
+ rubygems_version: 3.6.3
674
766
  specification_version: 4
675
767
  summary: A GraphQL language and runtime for Ruby
676
768
  test_files: []
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Backtrace
4
- module InspectResult
5
- module_function
6
-
7
- def inspect_result(obj)
8
- case obj
9
- when Hash
10
- "{" +
11
- obj.map do |key, val|
12
- "#{key}: #{inspect_truncated(val)}"
13
- end.join(", ") +
14
- "}"
15
- when Array
16
- "[" +
17
- obj.map { |v| inspect_truncated(v) }.join(", ") +
18
- "]"
19
- else
20
- inspect_truncated(obj)
21
- end
22
- end
23
-
24
- def inspect_truncated(obj)
25
- case obj
26
- when Hash
27
- "{...}"
28
- when Array
29
- "[...]"
30
- when GraphQL::Execution::Lazy
31
- "(unresolved)"
32
- else
33
- "#{obj.inspect}"
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Backtrace
4
- module Trace
5
- def initialize(*args, **kwargs, &block)
6
- @__backtrace_contexts = {}
7
- @__backtrace_last_context = nil
8
- super
9
- end
10
-
11
- def validate(query:, validate:)
12
- if query.multiplex
13
- push_query_backtrace_context(query)
14
- end
15
- super
16
- end
17
-
18
- def analyze_query(query:)
19
- if query.multiplex # missing for stand-alone static validation
20
- push_query_backtrace_context(query)
21
- end
22
- super
23
- end
24
-
25
- def execute_query(query:)
26
- push_query_backtrace_context(query)
27
- super
28
- end
29
-
30
- def execute_query_lazy(query:, multiplex:)
31
- query ||= multiplex.queries.first
32
- push_query_backtrace_context(query)
33
- super
34
- end
35
-
36
- def execute_field(field:, query:, ast_node:, arguments:, object:)
37
- push_field_backtrace_context(field, query, ast_node, arguments, object)
38
- super
39
- end
40
-
41
- def execute_field_lazy(field:, query:, ast_node:, arguments:, object:)
42
- push_field_backtrace_context(field, query, ast_node, arguments, object)
43
- super
44
- end
45
-
46
- def execute_multiplex(multiplex:)
47
- super
48
- rescue StandardError => err
49
- # This is an unhandled error from execution,
50
- # Re-raise it with a GraphQL trace.
51
- potential_context = @__backtrace_last_context
52
- if potential_context.is_a?(GraphQL::Query::Context) ||
53
- potential_context.is_a?(Backtrace::Frame)
54
- raise TracedError.new(err, potential_context)
55
- else
56
- raise
57
- end
58
- end
59
-
60
- private
61
-
62
- def push_query_backtrace_context(query)
63
- push_data = query
64
- push_key = []
65
- @__backtrace_contexts[push_key] = push_data
66
- @__backtrace_last_context = push_data
67
- end
68
-
69
- def push_field_backtrace_context(field, query, ast_node, arguments, object)
70
- push_key = query.context[:current_path]
71
- push_storage = @__backtrace_contexts
72
- parent_frame = push_storage[push_key[0..-2]]
73
-
74
- if parent_frame.is_a?(GraphQL::Query)
75
- parent_frame = parent_frame.context
76
- end
77
-
78
- push_data = Frame.new(
79
- query: query,
80
- path: push_key,
81
- ast_node: ast_node,
82
- field: field,
83
- object: object,
84
- arguments: arguments,
85
- parent_frame: parent_frame,
86
- )
87
- push_storage[push_key] = push_data
88
- @__backtrace_last_context = push_data
89
- end
90
-
91
- end
92
- end
93
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- class Backtrace
4
- # TODO this is not fiber-friendly
5
- module Tracer
6
- module_function
7
-
8
- # Implement the {GraphQL::Tracing} API.
9
- def trace(key, metadata)
10
- case key
11
- when "lex", "parse"
12
- # No context here, don't have a query yet
13
- nil
14
- when "execute_multiplex", "analyze_multiplex"
15
- # No query context yet
16
- nil
17
- when "validate", "analyze_query", "execute_query", "execute_query_lazy"
18
- push_key = []
19
- if (query = metadata[:query]) || ((queries = metadata[:queries]) && (query = queries.first))
20
- push_data = query
21
- multiplex = query.multiplex
22
- elsif (multiplex = metadata[:multiplex])
23
- push_data = multiplex.queries.first
24
- end
25
- when "execute_field", "execute_field_lazy"
26
- query = metadata[:query]
27
- multiplex = query.multiplex
28
- push_key = query.context[:current_path]
29
- parent_frame = multiplex.context[:graphql_backtrace_contexts][push_key[0..-2]]
30
-
31
- if parent_frame.is_a?(GraphQL::Query)
32
- parent_frame = parent_frame.context
33
- end
34
-
35
- push_data = Frame.new(
36
- query: query,
37
- path: push_key,
38
- ast_node: metadata[:ast_node],
39
- field: metadata[:field],
40
- object: metadata[:object],
41
- arguments: metadata[:arguments],
42
- parent_frame: parent_frame,
43
- )
44
- else
45
- # Custom key, no backtrace data for this
46
- nil
47
- end
48
-
49
- if push_data && multiplex
50
- push_storage = multiplex.context[:graphql_backtrace_contexts] ||= {}
51
- push_storage[push_key] = push_data
52
- multiplex.context[:last_graphql_backtrace_context] = push_data
53
- end
54
-
55
- if key == "execute_multiplex"
56
- multiplex_context = metadata[:multiplex].context
57
- begin
58
- yield
59
- rescue StandardError => err
60
- # This is an unhandled error from execution,
61
- # Re-raise it with a GraphQL trace.
62
- potential_context = multiplex_context[:last_graphql_backtrace_context]
63
-
64
- if potential_context.is_a?(GraphQL::Query::Context) ||
65
- potential_context.is_a?(Backtrace::Frame)
66
- raise TracedError.new(err, potential_context)
67
- else
68
- raise
69
- end
70
- ensure
71
- multiplex_context.delete(:graphql_backtrace_contexts)
72
- multiplex_context.delete(:last_graphql_backtrace_context)
73
- end
74
- else
75
- yield
76
- end
77
- end
78
- end
79
- end
80
- end