graphql 2.2.5 → 2.2.12

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/field_usage.rb +32 -7
  3. data/lib/graphql/analysis/ast.rb +10 -1
  4. data/lib/graphql/coercion_error.rb +1 -9
  5. data/lib/graphql/dataloader/request.rb +5 -0
  6. data/lib/graphql/execution/interpreter/runtime.rb +9 -0
  7. data/lib/graphql/execution/interpreter.rb +90 -150
  8. data/lib/graphql/introspection/entry_points.rb +9 -3
  9. data/lib/graphql/introspection/schema_type.rb +3 -1
  10. data/lib/graphql/language/document_from_schema_definition.rb +1 -2
  11. data/lib/graphql/language/nodes.rb +1 -1
  12. data/lib/graphql/language/parser.rb +11 -1
  13. data/lib/graphql/language/printer.rb +4 -0
  14. data/lib/graphql/pagination/array_connection.rb +6 -6
  15. data/lib/graphql/query/validation_pipeline.rb +2 -2
  16. data/lib/graphql/query/variables.rb +3 -3
  17. data/lib/graphql/query.rb +1 -1
  18. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  19. data/lib/graphql/schema/field.rb +33 -30
  20. data/lib/graphql/schema/interface.rb +5 -1
  21. data/lib/graphql/schema/member/has_arguments.rb +2 -2
  22. data/lib/graphql/schema/resolver.rb +9 -5
  23. data/lib/graphql/schema/unique_within_type.rb +1 -1
  24. data/lib/graphql/schema.rb +88 -27
  25. data/lib/graphql/static_validation/literal_validator.rb +1 -2
  26. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
  27. data/lib/graphql/static_validation/validator.rb +3 -0
  28. data/lib/graphql/subscriptions/serialize.rb +2 -0
  29. data/lib/graphql/subscriptions.rb +0 -3
  30. data/lib/graphql/testing/helpers.rb +8 -4
  31. data/lib/graphql/tracing/data_dog_trace.rb +21 -34
  32. data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
  33. data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
  34. data/lib/graphql/tracing/platform_tracing.rb +2 -0
  35. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
  36. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  37. data/lib/graphql/tracing.rb +3 -1
  38. data/lib/graphql/version.rb +1 -1
  39. data/lib/graphql.rb +3 -2
  40. metadata +24 -23
  41. data/lib/graphql/schema/base_64_bp.rb +0 -26
  42. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -471,6 +471,8 @@ module GraphQL
471
471
  if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
472
472
  max_possible_page_size = arguments[:last]
473
473
  end
474
+ elsif arguments.is_a?(GraphQL::UnauthorizedError)
475
+ raise arguments
474
476
  end
475
477
 
476
478
  if max_possible_page_size.nil?
@@ -483,41 +485,24 @@ module GraphQL
483
485
  metadata_complexity = 0
484
486
  lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
485
487
 
486
- if (page_info_lookahead = lookahead.selection(:page_info)).selected?
487
- metadata_complexity += 1 # pageInfo
488
- metadata_complexity += page_info_lookahead.selections.size # subfields
489
- end
490
-
491
- if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
492
- metadata_complexity += 1
488
+ lookahead.selections.each do |next_lookahead|
489
+ # this includes `pageInfo`, `nodes` and `edges` and any custom fields
490
+ # TODO this doesn't support procs yet -- unlikely to need it.
491
+ metadata_complexity += next_lookahead.field.complexity
492
+ if next_lookahead.name != :nodes && next_lookahead.name != :edges
493
+ # subfields, eg, for pageInfo -- assumes no subselections
494
+ metadata_complexity += next_lookahead.selections.size
495
+ end
493
496
  end
494
497
 
495
- nodes_edges_complexity = 0
496
- nodes_edges_complexity += 1 if lookahead.selects?(:edges)
497
- nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
498
-
499
498
  # Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
500
- items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
501
- # Add 1 for _this_ field
502
- 1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
499
+ items_complexity = child_complexity - metadata_complexity
500
+ subfields_complexity = (max_possible_page_size * items_complexity) + metadata_complexity
501
+ # Apply this field's own complexity
502
+ apply_own_complexity_to(subfields_complexity, query, nodes)
503
503
  end
504
504
  else
505
- defined_complexity = complexity
506
- case defined_complexity
507
- when Proc
508
- arguments = query.arguments_for(nodes.first, self)
509
- if arguments.is_a?(GraphQL::ExecutionError)
510
- return child_complexity
511
- elsif arguments.respond_to?(:keyword_arguments)
512
- arguments = arguments.keyword_arguments
513
- end
514
-
515
- defined_complexity.call(query.context, arguments, child_complexity)
516
- when Numeric
517
- defined_complexity + child_complexity
518
- else
519
- raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
520
- end
505
+ apply_own_complexity_to(child_complexity, query, nodes)
521
506
  end
522
507
  end
523
508
 
@@ -882,6 +867,24 @@ ERR
882
867
  yield(obj, args)
883
868
  end
884
869
  end
870
+
871
+ def apply_own_complexity_to(child_complexity, query, nodes)
872
+ case (own_complexity = complexity)
873
+ when Numeric
874
+ own_complexity + child_complexity
875
+ when Proc
876
+ arguments = query.arguments_for(nodes.first, self)
877
+ if arguments.is_a?(GraphQL::ExecutionError)
878
+ return child_complexity
879
+ elsif arguments.respond_to?(:keyword_arguments)
880
+ arguments = arguments.keyword_arguments
881
+ end
882
+
883
+ own_complexity.call(query.context, arguments, child_complexity)
884
+ else
885
+ raise ArgumentError, "Invalid complexity for #{self.path}: #{own_complexity.inspect}"
886
+ end
887
+ end
885
888
  end
886
889
  end
887
890
  end
@@ -69,7 +69,11 @@ module GraphQL
69
69
  end
70
70
  elsif child_class < GraphQL::Schema::Object
71
71
  # This is being included into an object type, make sure it's using `implements(...)`
72
- backtrace_line = caller(0, 10).find { |line| line.include?("schema/member/has_interfaces.rb") && line.include?("in `implements'")}
72
+ backtrace_line = caller_locations(0, 10).find do |location|
73
+ location.base_label == "implements" &&
74
+ location.path.end_with?("schema/member/has_interfaces.rb")
75
+ end
76
+
73
77
  if !backtrace_line
74
78
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
75
79
  end
@@ -50,7 +50,7 @@ module GraphQL
50
50
  if loads && arg_defn.type.list?
51
51
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
52
52
  def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
53
- argument = get_argument("#{arg_defn.graphql_name}")
53
+ argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
54
54
  (context || self.context).query.after_lazy(values) do |values2|
55
55
  GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
56
56
  end
@@ -59,7 +59,7 @@ module GraphQL
59
59
  elsif loads
60
60
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
61
61
  def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
62
- argument = get_argument("#{arg_defn.graphql_name}")
62
+ argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
63
63
  load_application_object(argument, value, context || self.context)
64
64
  end
65
65
  RUBY
@@ -166,11 +166,15 @@ module GraphQL
166
166
  args.each_value do |argument|
167
167
  arg_keyword = argument.keyword
168
168
  if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
169
- arg_auth, err = argument.authorized?(self, arg_value, context)
170
- if !arg_auth
171
- return arg_auth, err
172
- else
173
- true
169
+ auth_result = argument.authorized?(self, arg_value, context)
170
+ if auth_result.is_a?(Array)
171
+ # only return this second value if the application returned a second value
172
+ arg_auth, err = auth_result
173
+ if !arg_auth
174
+ return arg_auth, err
175
+ end
176
+ elsif auth_result == false
177
+ return auth_result
174
178
  end
175
179
  else
176
180
  true
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'graphql/schema/base_64_bp'
2
+ require "base64"
3
3
 
4
4
  module GraphQL
5
5
  class Schema
@@ -63,10 +63,6 @@ module GraphQL
63
63
  # Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
64
64
  # (These configurations can be overridden by specific calls to {Schema#execute})
65
65
  #
66
- # Schemas can specify how queries should be executed against them.
67
- # `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
68
- # each apply to corresponding root types.
69
- #
70
66
  # @example defining a schema
71
67
  # class MySchema < GraphQL::Schema
72
68
  # query QueryType
@@ -167,13 +163,20 @@ module GraphQL
167
163
  backtrace_class.include(GraphQL::Backtrace::Trace)
168
164
  trace_mode(:default_backtrace, backtrace_class)
169
165
  end
170
- trace_class_for(:default)
166
+ trace_class_for(:default, build: true)
171
167
  end
172
168
 
173
169
  # @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
174
- def trace_class_for(mode, build: true)
175
- own_trace_modes[mode] ||
176
- (superclass.respond_to?(:trace_class_for) ? superclass.trace_class_for(mode, build: build) : (build ? (own_trace_modes[mode] = build_trace_mode(mode)) : nil))
170
+ def trace_class_for(mode, build: false)
171
+ if (trace_class = own_trace_modes[mode])
172
+ trace_class
173
+ elsif superclass.respond_to?(:trace_class_for) && (trace_class = superclass.trace_class_for(mode, build: false))
174
+ trace_class
175
+ elsif build
176
+ own_trace_modes[mode] = build_trace_mode(mode)
177
+ else
178
+ nil
179
+ end
177
180
  end
178
181
 
179
182
  # Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
@@ -211,20 +214,24 @@ module GraphQL
211
214
  include DefaultTraceClass
212
215
  end
213
216
  when :default_backtrace
214
- schema_base_class = trace_class_for(:default)
217
+ schema_base_class = trace_class_for(:default, build: true)
215
218
  Class.new(schema_base_class) do
216
219
  include(GraphQL::Backtrace::Trace)
217
220
  end
218
221
  else
219
222
  # First, see if the superclass has a custom-defined class for this.
220
223
  # Then, if it doesn't, use this class's default trace
221
- base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode, build: false)) || trace_class_for(:default)
224
+ base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default, build: true)
222
225
  # Prepare the default trace class if it hasn't been initialized yet
223
226
  base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
224
227
  mods = trace_modules_for(mode)
225
228
  if base_class < DefaultTraceClass
226
229
  mods = trace_modules_for(:default) + mods
227
230
  end
231
+ # Copy the existing default options into this mode's options
232
+ default_options = trace_options_for(:default)
233
+ add_trace_options_for(mode, default_options)
234
+
228
235
  Class.new(base_class) do
229
236
  mods.any? && include(*mods)
230
237
  end
@@ -640,27 +647,39 @@ module GraphQL
640
647
  end
641
648
  end
642
649
 
643
- def query_execution_strategy(new_query_execution_strategy = nil)
650
+ def query_execution_strategy(new_query_execution_strategy = nil, deprecation_warning: true)
651
+ if deprecation_warning
652
+ warn "GraphQL::Schema.query_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
653
+ warn " #{caller(1, 1).first}"
654
+ end
644
655
  if new_query_execution_strategy
645
656
  @query_execution_strategy = new_query_execution_strategy
646
657
  else
647
- @query_execution_strategy || find_inherited_value(:query_execution_strategy, self.default_execution_strategy)
658
+ @query_execution_strategy || (superclass.respond_to?(:query_execution_strategy) ? superclass.query_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
648
659
  end
649
660
  end
650
661
 
651
- def mutation_execution_strategy(new_mutation_execution_strategy = nil)
662
+ def mutation_execution_strategy(new_mutation_execution_strategy = nil, deprecation_warning: true)
663
+ if deprecation_warning
664
+ warn "GraphQL::Schema.mutation_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
665
+ warn " #{caller(1, 1).first}"
666
+ end
652
667
  if new_mutation_execution_strategy
653
668
  @mutation_execution_strategy = new_mutation_execution_strategy
654
669
  else
655
- @mutation_execution_strategy || find_inherited_value(:mutation_execution_strategy, self.default_execution_strategy)
670
+ @mutation_execution_strategy || (superclass.respond_to?(:mutation_execution_strategy) ? superclass.mutation_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
656
671
  end
657
672
  end
658
673
 
659
- def subscription_execution_strategy(new_subscription_execution_strategy = nil)
674
+ def subscription_execution_strategy(new_subscription_execution_strategy = nil, deprecation_warning: true)
675
+ if deprecation_warning
676
+ warn "GraphQL::Schema.subscription_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
677
+ warn " #{caller(1, 1).first}"
678
+ end
660
679
  if new_subscription_execution_strategy
661
680
  @subscription_execution_strategy = new_subscription_execution_strategy
662
681
  else
663
- @subscription_execution_strategy || find_inherited_value(:subscription_execution_strategy, self.default_execution_strategy)
682
+ @subscription_execution_strategy || (superclass.respond_to?(:subscription_execution_strategy) ? superclass.subscription_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
664
683
  end
665
684
  end
666
685
 
@@ -743,6 +762,7 @@ module GraphQL
743
762
 
744
763
  def error_bubbling(new_error_bubbling = nil)
745
764
  if !new_error_bubbling.nil?
765
+ warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
746
766
  @error_bubbling = new_error_bubbling
747
767
  else
748
768
  @error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
@@ -814,6 +834,26 @@ module GraphQL
814
834
  end
815
835
  end
816
836
 
837
+ # @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
838
+ # @return [Array<Module>] Type definitions added to this schema
839
+ def extra_types(*new_extra_types)
840
+ if new_extra_types.any?
841
+ new_extra_types = new_extra_types.flatten
842
+ @own_extra_types ||= []
843
+ @own_extra_types.concat(new_extra_types)
844
+ end
845
+ inherited_et = find_inherited_value(:extra_types, nil)
846
+ if inherited_et
847
+ if @own_extra_types
848
+ inherited_et + @own_extra_types
849
+ else
850
+ inherited_et
851
+ end
852
+ else
853
+ @own_extra_types || EMPTY_ARRAY
854
+ end
855
+ end
856
+
817
857
  def orphan_types(*new_orphan_types)
818
858
  if new_orphan_types.any?
819
859
  new_orphan_types = new_orphan_types.flatten
@@ -1044,6 +1084,12 @@ module GraphQL
1044
1084
  end
1045
1085
 
1046
1086
  def instrument(instrument_step, instrumenter, options = {})
1087
+ warn <<~WARN
1088
+ Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
1089
+ (From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
1090
+
1091
+ WARN
1092
+ trace_with(Tracing::LegacyHooksTrace)
1047
1093
  own_instrumenters[instrument_step] << instrumenter
1048
1094
  end
1049
1095
 
@@ -1080,7 +1126,7 @@ module GraphQL
1080
1126
  end
1081
1127
 
1082
1128
  def tracer(new_tracer)
1083
- default_trace = trace_class_for(:default)
1129
+ default_trace = trace_class_for(:default, build: true)
1084
1130
  if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
1085
1131
  trace_with(GraphQL::Tracing::CallLegacyTracers)
1086
1132
  end
@@ -1106,20 +1152,23 @@ module GraphQL
1106
1152
  tc = own_trace_modes[mode] ||= build_trace_mode(mode)
1107
1153
  tc.include(trace_mod)
1108
1154
  own_trace_modules[mode] << trace_mod
1109
-
1155
+ add_trace_options_for(mode, options)
1110
1156
  if mode == :default
1111
1157
  # This module is being added as a default tracer. If any other mode classes
1112
1158
  # have already been created, but get their default behavior from a superclass,
1113
1159
  # Then mix this into this schema's subclass.
1114
1160
  # (But don't mix it into mode classes that aren't default-based.)
1115
1161
  own_trace_modes.each do |other_mode_name, other_mode_class|
1116
- if other_mode_class < DefaultTraceClass && !(other_mode_class < trace_mod)
1117
- other_mode_class.include(trace_mod)
1162
+ if other_mode_class < DefaultTraceClass
1163
+ # Don't add it back to the inheritance tree if it's already there
1164
+ if !(other_mode_class < trace_mod)
1165
+ other_mode_class.include(trace_mod)
1166
+ end
1167
+ # Add any options so they'll be available
1168
+ add_trace_options_for(other_mode_name, options)
1118
1169
  end
1119
1170
  end
1120
1171
  end
1121
- t_opts = trace_options_for(mode)
1122
- t_opts.merge!(options)
1123
1172
  end
1124
1173
  nil
1125
1174
  end
@@ -1129,10 +1178,14 @@ module GraphQL
1129
1178
  def trace_options_for(mode)
1130
1179
  @trace_options_for_mode ||= {}
1131
1180
  @trace_options_for_mode[mode] ||= begin
1181
+ # It may be time to create an options hash for a mode that wasn't registered yet.
1182
+ # Mix in the default options in that case.
1183
+ default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
1184
+ # Make sure this returns a new object so that other hashes aren't modified later
1132
1185
  if superclass.respond_to?(:trace_options_for)
1133
- superclass.trace_options_for(mode).dup
1186
+ superclass.trace_options_for(mode).merge(default_options)
1134
1187
  else
1135
- {}
1188
+ default_options.dup
1136
1189
  end
1137
1190
  end
1138
1191
  end
@@ -1155,15 +1208,17 @@ module GraphQL
1155
1208
  raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
1156
1209
  else
1157
1210
  own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
1211
+ options_trace_mode = :default
1158
1212
  :default_backtrace
1159
1213
  end
1160
1214
  else
1161
1215
  default_trace_mode
1162
1216
  end
1163
1217
 
1164
- base_trace_options = trace_options_for(trace_mode)
1218
+ options_trace_mode ||= trace_mode
1219
+ base_trace_options = trace_options_for(options_trace_mode)
1165
1220
  trace_options = base_trace_options.merge(options)
1166
- trace_class_for_mode = trace_class_for(trace_mode) || raise(ArgumentError, "#{self} has no trace class for mode: #{trace_mode.inspect}")
1221
+ trace_class_for_mode = trace_class_for(trace_mode, build: true)
1167
1222
  trace_class_for_mode.new(**trace_options)
1168
1223
  end
1169
1224
 
@@ -1317,6 +1372,12 @@ module GraphQL
1317
1372
 
1318
1373
  private
1319
1374
 
1375
+ def add_trace_options_for(mode, new_options)
1376
+ t_opts = trace_options_for(mode)
1377
+ t_opts.merge!(new_options)
1378
+ nil
1379
+ end
1380
+
1320
1381
  # @param t [Module, Array<Module>]
1321
1382
  # @return [void]
1322
1383
  def add_type_and_traverse(t, root:)
@@ -1378,7 +1439,7 @@ module GraphQL
1378
1439
  else
1379
1440
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1380
1441
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1381
- @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1442
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
1382
1443
  end
1383
1444
  end
1384
1445
  @lazy_methods
@@ -110,7 +110,7 @@ module GraphQL
110
110
  # TODO - would be nice to use these to create an error message so the caller knows
111
111
  # that required fields are missing
112
112
  required_field_names = @warden.arguments(type)
113
- .select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
113
+ .select { |argument| argument.type.kind.non_null? && !argument.default_value? }
114
114
  .map!(&:name)
115
115
 
116
116
  present_field_names = ast_node.arguments.map(&:name)
@@ -122,7 +122,6 @@ module GraphQL
122
122
  arg_type = @warden.get_argument(type, name).type
123
123
  recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
124
124
  end
125
-
126
125
  if type.one_of? && ast_node.arguments.size != 1
127
126
  results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
128
127
  end
@@ -35,7 +35,7 @@ module GraphQL
35
35
  return unless parent_type && parent_type.kind.input_object?
36
36
 
37
37
  required_fields = context.warden.arguments(parent_type)
38
- .select{|arg| arg.type.kind.non_null?}
38
+ .select{ |arg| arg.type.kind.non_null? && !arg.default_value? }
39
39
  .map!(&:graphql_name)
40
40
 
41
41
  present_fields = ast_node.arguments.map(&:name)
@@ -28,6 +28,7 @@ module GraphQL
28
28
  # @return [Array<Hash>]
29
29
  def validate(query, validate: true, timeout: nil, max_errors: nil)
30
30
  query.current_trace.validate(validate: validate, query: query) do
31
+ begin_t = Time.now
31
32
  errors = if validate == false
32
33
  []
33
34
  else
@@ -52,11 +53,13 @@ module GraphQL
52
53
  end
53
54
 
54
55
  {
56
+ remaining_timeout: timeout ? (timeout - (Time.now - begin_t)) : nil,
55
57
  errors: errors,
56
58
  }
57
59
  end
58
60
  rescue GraphQL::ExecutionError => e
59
61
  {
62
+ remaining_timeout: nil,
60
63
  errors: [e],
61
64
  }
62
65
  end
@@ -148,6 +148,8 @@ module GraphQL
148
148
  { TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
149
149
  elsif obj.is_a?(OpenStruct)
150
150
  { OPEN_STRUCT_KEY => dump_value(obj.to_h) }
151
+ elsif defined?(ActiveRecord::Relation) && obj.is_a?(ActiveRecord::Relation)
152
+ dump_value(obj.to_a)
151
153
  else
152
154
  obj
153
155
  end
@@ -2,7 +2,6 @@
2
2
  require "securerandom"
3
3
  require "graphql/subscriptions/broadcast_analyzer"
4
4
  require "graphql/subscriptions/event"
5
- require "graphql/subscriptions/instrumentation"
6
5
  require "graphql/subscriptions/serialize"
7
6
  require "graphql/subscriptions/action_cable_subscriptions"
8
7
  require "graphql/subscriptions/default_subscription_resolve_extension"
@@ -30,8 +29,6 @@ module GraphQL
30
29
  raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
31
30
  end
32
31
 
33
- instrumentation = Subscriptions::Instrumentation.new(schema: schema)
34
- defn.instrument(:query, instrumentation)
35
32
  options[:schema] = schema
36
33
  schema.subscriptions = self.new(**options)
37
34
  schema.add_subscription_extension_if_necessary
@@ -5,10 +5,7 @@ module GraphQL
5
5
  # @param schema_class [Class<GraphQL::Schema>]
6
6
  # @return [Module] A helpers module which always uses the given schema
7
7
  def self.for(schema_class)
8
- Module.new do
9
- include SchemaHelpers
10
- @@schema_class_for_helpers = schema_class
11
- end
8
+ SchemaHelpers.for(schema_class)
12
9
  end
13
10
 
14
11
  class Error < GraphQL::Error
@@ -119,6 +116,13 @@ module GraphQL
119
116
  # schema will be added later
120
117
  super(nil, *args, **kwargs, &block)
121
118
  end
119
+
120
+ def self.for(schema_class)
121
+ Module.new do
122
+ include SchemaHelpers
123
+ @@schema_class_for_helpers = schema_class
124
+ end
125
+ end
122
126
  end
123
127
  end
124
128
  end
@@ -3,20 +3,18 @@
3
3
  module GraphQL
4
4
  module Tracing
5
5
  module DataDogTrace
6
+ # @param tracer [#trace] Deprecated
6
7
  # @param analytics_enabled [Boolean] Deprecated
7
8
  # @param analytics_sample_rate [Float] Deprecated
8
- def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service: "ruby-graphql", **rest)
9
+ def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service: nil, **rest)
9
10
  if tracer.nil?
10
11
  tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
11
12
  end
12
13
  @tracer = tracer
13
14
 
14
- analytics_available = defined?(Datadog::Contrib::Analytics) \
15
- && Datadog::Contrib::Analytics.respond_to?(:enabled?) \
16
- && Datadog::Contrib::Analytics.respond_to?(:set_sample_rate)
17
-
18
- @analytics_enabled = analytics_available && Datadog::Contrib::Analytics.enabled?(analytics_enabled)
15
+ @analytics_enabled = analytics_enabled
19
16
  @analytics_sample_rate = analytics_sample_rate
17
+
20
18
  @service_name = service
21
19
  @has_prepare_span = respond_to?(:prepare_span)
22
20
  super
@@ -34,12 +32,9 @@ module GraphQL
34
32
  }.each do |trace_method, trace_key|
35
33
  module_eval <<-RUBY, __FILE__, __LINE__
36
34
  def #{trace_method}(**data)
37
- @tracer.trace("#{trace_key}", service: @service_name) do |span|
38
- span.span_type = 'custom'
39
- if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
40
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
41
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, '#{trace_method}')
42
- end
35
+ @tracer.trace("#{trace_key}", service: @service_name, type: 'custom') do |span|
36
+ span.set_tag('component', 'graphql')
37
+ span.set_tag('operation', '#{trace_method}')
43
38
 
44
39
  #{
45
40
  if trace_method == 'execute_multiplex'
@@ -54,10 +49,8 @@ module GraphQL
54
49
  end
55
50
  span.resource = resource if resource
56
51
 
57
- # For top span of query, set the analytics sample rate tag, if available.
58
- if @analytics_enabled
59
- Datadog::Contrib::Analytics.set_sample_rate(span, @analytics_sample_rate)
60
- end
52
+ # [Deprecated] will be removed in the future
53
+ span.set_metric('_dd1.sr.eausr', @analytics_sample_rate) if @analytics_enabled
61
54
  RUBY
62
55
  elsif trace_method == 'execute_query'
63
56
  <<-RUBY
@@ -89,12 +82,10 @@ module GraphQL
89
82
  nil
90
83
  end
91
84
  if platform_key && trace_field
92
- @tracer.trace(platform_key, service: @service_name) do |span|
93
- span.span_type = 'custom'
94
- if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
95
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
96
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
97
- end
85
+ @tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
86
+ span.set_tag('component', 'graphql')
87
+ span.set_tag('operation', span_key)
88
+
98
89
  if @has_prepare_span
99
90
  prepare_span_data = { query: query, field: field, ast_node: ast_node, arguments: arguments, object: object }
100
91
  prepare_span(span_key, prepare_span_data, span)
@@ -125,12 +116,10 @@ module GraphQL
125
116
 
126
117
  def authorized_span(span_key, object, type, query)
127
118
  platform_key = @platform_key_cache[DataDogTrace].platform_authorized_key_cache[type]
128
- @tracer.trace(platform_key, service: @service_name) do |span|
129
- span.span_type = 'custom'
130
- if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
131
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
132
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
133
- end
119
+ @tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
120
+ span.set_tag('component', 'graphql')
121
+ span.set_tag('operation', span_key)
122
+
134
123
  if @has_prepare_span
135
124
  prepare_span(span_key, {object: object, type: type, query: query}, span)
136
125
  end
@@ -158,12 +147,10 @@ module GraphQL
158
147
 
159
148
  def resolve_type_span(span_key, object, type, query)
160
149
  platform_key = @platform_key_cache[DataDogTrace].platform_resolve_type_key_cache[type]
161
- @tracer.trace(platform_key, service: @service_name) do |span|
162
- span.span_type = 'custom'
163
- if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
164
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
165
- span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
166
- end
150
+ @tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
151
+ span.set_tag('component', 'graphql')
152
+ span.set_tag('operation', span_key)
153
+
167
154
  if @has_prepare_span
168
155
  prepare_span(span_key, {object: object, type: type, query: query}, span)
169
156
  end