graphql 2.0.16 → 2.0.18

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/visitor.rb +42 -35
  3. data/lib/graphql/analysis/ast.rb +2 -2
  4. data/lib/graphql/backtrace/tracer.rb +1 -1
  5. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  6. data/lib/graphql/execution/interpreter/runtime.rb +106 -88
  7. data/lib/graphql/execution/interpreter.rb +14 -9
  8. data/lib/graphql/execution/lazy.rb +6 -12
  9. data/lib/graphql/execution/multiplex.rb +2 -1
  10. data/lib/graphql/graphql_ext.bundle +0 -0
  11. data/lib/graphql/introspection/directive_type.rb +2 -2
  12. data/lib/graphql/introspection/field_type.rb +1 -1
  13. data/lib/graphql/introspection/schema_type.rb +2 -2
  14. data/lib/graphql/introspection/type_type.rb +5 -5
  15. data/lib/graphql/language/lexer.rb +216 -1505
  16. data/lib/graphql/language/lexer.ri +744 -0
  17. data/lib/graphql/language/nodes.rb +39 -31
  18. data/lib/graphql/language/parser.rb +9 -9
  19. data/lib/graphql/language/parser.y +9 -9
  20. data/lib/graphql/language/visitor.rb +191 -83
  21. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  22. data/lib/graphql/query/context.rb +45 -11
  23. data/lib/graphql/query.rb +15 -2
  24. data/lib/graphql/schema/argument.rb +0 -4
  25. data/lib/graphql/schema/directive.rb +12 -2
  26. data/lib/graphql/schema/enum.rb +24 -17
  27. data/lib/graphql/schema/enum_value.rb +5 -3
  28. data/lib/graphql/schema/field.rb +53 -45
  29. data/lib/graphql/schema/interface.rb +0 -10
  30. data/lib/graphql/schema/late_bound_type.rb +2 -0
  31. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -14
  32. data/lib/graphql/schema/member/has_arguments.rb +104 -57
  33. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  34. data/lib/graphql/schema/member/has_fields.rb +14 -2
  35. data/lib/graphql/schema/member/has_interfaces.rb +49 -8
  36. data/lib/graphql/schema/member/has_validators.rb +31 -5
  37. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  38. data/lib/graphql/schema/object.rb +2 -4
  39. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  40. data/lib/graphql/schema/timeout.rb +23 -27
  41. data/lib/graphql/schema/warden.rb +26 -4
  42. data/lib/graphql/schema.rb +37 -19
  43. data/lib/graphql/static_validation/literal_validator.rb +15 -1
  44. data/lib/graphql/static_validation/validator.rb +1 -1
  45. data/lib/graphql/subscriptions/event.rb +2 -7
  46. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  47. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  48. data/lib/graphql/tracing/appsignal_trace.rb +66 -0
  49. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  50. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  51. data/lib/graphql/tracing/notifications_trace.rb +41 -0
  52. data/lib/graphql/tracing/platform_trace.rb +107 -0
  53. data/lib/graphql/tracing/platform_tracing.rb +15 -3
  54. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  55. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  56. data/lib/graphql/tracing/scout_trace.rb +72 -0
  57. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  58. data/lib/graphql/tracing.rb +136 -39
  59. data/lib/graphql/type_kinds.rb +6 -3
  60. data/lib/graphql/types/relay/connection_behaviors.rb +0 -4
  61. data/lib/graphql/types/relay/edge_behaviors.rb +0 -4
  62. data/lib/graphql/types/string.rb +1 -1
  63. data/lib/graphql/version.rb +1 -1
  64. data/lib/graphql.rb +7 -8
  65. metadata +15 -4
  66. data/lib/graphql/language/lexer.rl +0 -280
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module NewRelicTrace
6
+ include PlatformTrace
7
+
8
+ # @param set_transaction_name [Boolean] If true, the GraphQL operation name will be used as the transaction name.
9
+ # This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
10
+ # It can also be specified per-query with `context[:set_new_relic_transaction_name]`.
11
+ def initialize(set_transaction_name: false, **_rest)
12
+ @set_transaction_name = set_transaction_name
13
+ super
14
+ end
15
+
16
+ def execute_query(query:)
17
+ set_this_txn_name = query.context[:set_new_relic_transaction_name]
18
+ if set_this_txn_name == true || (set_this_txn_name.nil? && @set_transaction_name)
19
+ NewRelic::Agent.set_transaction_name(transaction_name(query))
20
+ end
21
+ NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped("GraphQL/execute") do
22
+ super
23
+ end
24
+ end
25
+
26
+ {
27
+ "lex" => "GraphQL/lex",
28
+ "parse" => "GraphQL/parse",
29
+ "validate" => "GraphQL/validate",
30
+ "analyze_query" => "GraphQL/analyze",
31
+ "analyze_multiplex" => "GraphQL/analyze",
32
+ "execute_multiplex" => "GraphQL/execute",
33
+ "execute_query_lazy" => "GraphQL/execute",
34
+ }.each do |trace_method, platform_key|
35
+ module_eval <<-RUBY, __FILE__, __LINE__
36
+ def #{trace_method}(**_keys)
37
+ NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped("#{platform_key}") do
38
+ super
39
+ end
40
+ end
41
+ RUBY
42
+ end
43
+
44
+ def platform_execute_field(platform_key)
45
+ NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(platform_key) do
46
+ yield
47
+ end
48
+ end
49
+
50
+ def platform_authorized(platform_key)
51
+ NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(platform_key) do
52
+ yield
53
+ end
54
+ end
55
+
56
+ def platform_resolve_type(platform_key)
57
+ NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(platform_key) do
58
+ yield
59
+ end
60
+ end
61
+
62
+ def platform_field_key(field)
63
+ "GraphQL/#{field.owner.graphql_name}/#{field.graphql_name}"
64
+ end
65
+
66
+ def platform_authorized_key(type)
67
+ "GraphQL/Authorize/#{type.graphql_name}"
68
+ end
69
+
70
+ def platform_resolve_type_key(type)
71
+ "GraphQL/ResolveType/#{type.graphql_name}"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ # This implementation forwards events to a notification handler (i.e.
6
+ # ActiveSupport::Notifications or Dry::Monitor::Notifications)
7
+ # with a `graphql` suffix.
8
+ module NotificationsTrace
9
+ include PlatformTrace
10
+ # Initialize a new NotificationsTracing instance
11
+ #
12
+ # @param engine [#instrument(key, metadata, block)] The notifications engine to use
13
+ def initialize(engine:, **rest)
14
+ @notifications_engine = engine
15
+ super
16
+ end
17
+
18
+ {
19
+ "lex" => "lex.graphql",
20
+ "parse" => "parse.graphql",
21
+ "validate" => "validate.graphql",
22
+ "analyze_multiplex" => "analyze_multiplex.graphql",
23
+ "analyze_query" => "analyze_query.graphql",
24
+ "execute_query" => "execute_query.graphql",
25
+ "execute_query_lazy" => "execute_query_lazy.graphql",
26
+ "execute_field" => "execute_field.graphql",
27
+ "execute_field_lazy" => "execute_field_lazy.graphql",
28
+ "authorized" => "authorized.graphql",
29
+ "authorized_lazy" => "authorized_lazy.graphql",
30
+ "resolve_type" => "resolve_type.graphql",
31
+ "resolve_type_lazy" => "resolve_type.graphql",
32
+ }.each do |trace_method, platform_key|
33
+ module_eval <<-RUBY, __FILE__, __LINE__
34
+ def #{trace_method}(**metadata, &blk)
35
+ @notifications_engine.instrument("#{platform_key}", metadata, &blk)
36
+ end
37
+ RUBY
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module PlatformTrace
6
+ def initialize(trace_scalars: false, **_options)
7
+ @trace_scalars = trace_scalars
8
+ @platform_field_key_cache = Hash.new { |h, k| h[k] = platform_field_key(k) }
9
+ @platform_authorized_key_cache = Hash.new { |h, k| h[k] = platform_authorized_key(k) }
10
+ @platform_resolve_type_key_cache = Hash.new { |h, k| h[k] = platform_resolve_type_key(k) }
11
+ super
12
+ end
13
+
14
+ def platform_execute_field_lazy(*args, &block)
15
+ platform_execute_field(*args, &block)
16
+ end
17
+
18
+ def platform_authorized_lazy(key, &block)
19
+ platform_authorized(key, &block)
20
+ end
21
+
22
+ def platform_resolve_type_lazy(key, &block)
23
+ platform_resolve_type(key, &block)
24
+ end
25
+
26
+ def self.included(child_class)
27
+ # Don't gather this unless necessary
28
+ pass_data_to_execute_field = child_class.method_defined?(:platform_execute_field) &&
29
+ child_class.instance_method(:platform_execute_field).arity != 1
30
+
31
+ [:execute_field, :execute_field_lazy].each do |field_trace_method|
32
+ child_class.module_eval <<-RUBY, __FILE__, __LINE__
33
+ def #{field_trace_method}(query:, field:, ast_node:, arguments:, object:)
34
+ return_type = field.type.unwrap
35
+ trace_field = if return_type.kind.scalar? || return_type.kind.enum?
36
+ (field.trace.nil? && @trace_scalars) || field.trace
37
+ else
38
+ true
39
+ end
40
+ platform_key = if trace_field
41
+ @platform_field_key_cache[field]
42
+ else
43
+ nil
44
+ end
45
+ if platform_key && trace_field
46
+ platform_#{field_trace_method}(platform_key#{pass_data_to_execute_field ? ", { query: query, field: field, ast_node: ast_node, arguments: arguments, object: object }" : ""}) do
47
+ super
48
+ end
49
+ else
50
+ super
51
+ end
52
+ end
53
+ RUBY
54
+ end
55
+
56
+
57
+ [:authorized, :authorized_lazy].each do |auth_trace_method|
58
+ if !child_class.method_defined?(auth_trace_method)
59
+ child_class.module_eval <<-RUBY, __FILE__, __LINE__
60
+ def #{auth_trace_method}(type:, query:, object:)
61
+ platform_key = @platform_authorized_key_cache[type]
62
+ platform_#{auth_trace_method}(platform_key) do
63
+ super
64
+ end
65
+ end
66
+ RUBY
67
+ end
68
+ end
69
+
70
+ [:resolve_type, :resolve_type_lazy].each do |rt_trace_method|
71
+ if !child_class.method_defined?(rt_trace_method)
72
+ child_class.module_eval <<-RUBY, __FILE__, __LINE__
73
+ def #{rt_trace_method}(query:, type:, object:)
74
+ platform_key = @platform_resolve_type_key_cache[type]
75
+ platform_#{rt_trace_method}(platform_key) do
76
+ super
77
+ end
78
+ end
79
+ RUBY
80
+ end
81
+ end
82
+ end
83
+
84
+
85
+
86
+ private
87
+
88
+ # Get the transaction name based on the operation type and name if possible, or fall back to a user provided
89
+ # one. Useful for anonymous queries.
90
+ def transaction_name(query)
91
+ selected_op = query.selected_operation
92
+ txn_name = if selected_op
93
+ op_type = selected_op.operation_type
94
+ op_name = selected_op.name || fallback_transaction_name(query.context) || "anonymous"
95
+ "#{op_type}.#{op_name}"
96
+ else
97
+ "query.anonymous"
98
+ end
99
+ "GraphQL/#{txn_name}"
100
+ end
101
+
102
+ def fallback_transaction_name(context)
103
+ context[:tracing_fallback_transaction_name]
104
+ end
105
+ end
106
+ end
107
+ end
@@ -40,7 +40,7 @@ module GraphQL
40
40
 
41
41
  platform_key = if trace_field
42
42
  context = data.fetch(:query).context
43
- cached_platform_key(context, field, :field) { platform_field_key(data[:owner], field) }
43
+ cached_platform_key(context, field, :field) { platform_field_key(field.owner, field) }
44
44
  else
45
45
  nil
46
46
  end
@@ -73,8 +73,20 @@ module GraphQL
73
73
  end
74
74
 
75
75
  def self.use(schema_defn, options = {})
76
- tracer = self.new(**options)
77
- schema_defn.tracer(tracer)
76
+ if options[:legacy_tracing]
77
+ tracer = self.new(**options)
78
+ schema_defn.tracer(tracer)
79
+ else
80
+ tracing_name = self.name.split("::").last
81
+ trace_name = tracing_name.sub("Tracing", "Trace")
82
+ if GraphQL::Tracing.const_defined?(trace_name, false)
83
+ trace_module = GraphQL::Tracing.const_get(trace_name)
84
+ schema_defn.trace_with(trace_module, **options)
85
+ else
86
+ tracer = self.new(**options)
87
+ schema_defn.tracer(tracer)
88
+ end
89
+ end
78
90
  end
79
91
 
80
92
  private
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module PrometheusTrace
6
+ include PlatformTrace
7
+
8
+ def initialize(client: PrometheusExporter::Client.default, keys_whitelist: ["execute_field", "execute_field_lazy"], collector_type: "graphql", **rest)
9
+ @client = client
10
+ @keys_whitelist = keys_whitelist
11
+ @collector_type = collector_type
12
+
13
+ super(**rest)
14
+ end
15
+
16
+ {
17
+ 'lex' => "graphql.lex",
18
+ 'parse' => "graphql.parse",
19
+ 'validate' => "graphql.validate",
20
+ 'analyze_query' => "graphql.analyze",
21
+ 'analyze_multiplex' => "graphql.analyze",
22
+ 'execute_multiplex' => "graphql.execute",
23
+ 'execute_query' => "graphql.execute",
24
+ 'execute_query_lazy' => "graphql.execute",
25
+ }.each do |trace_method, platform_key|
26
+ module_eval <<-RUBY, __FILE__, __LINE__
27
+ def #{trace_method}(**data, &block)
28
+ instrument_execution("#{platform_key}", "#{trace_method}", &block)
29
+ end
30
+ RUBY
31
+ end
32
+
33
+ def platform_execute_field(platform_key, &block)
34
+ instrument_execution(platform_key, "execute_field", &block)
35
+ end
36
+
37
+ def platform_execute_field_lazy(platform_key, &block)
38
+ instrument_execution(platform_key, "execute_field_lazy", &block)
39
+ end
40
+
41
+ def platform_authorized(platform_key, &block)
42
+ instrument_execution(platform_key, "authorized", &block)
43
+ end
44
+
45
+ def platform_authorized_lazy(platform_key, &block)
46
+ instrument_execution(platform_key, "authorized_lazy", &block)
47
+ end
48
+
49
+ def platform_resolve_type(platform_key, &block)
50
+ instrument_execution(platform_key, "resolve_type", &block)
51
+ end
52
+
53
+ def platform_resolve_type_lazy(platform_key, &block)
54
+ instrument_execution(platform_key, "resolve_type_lazy", &block)
55
+ end
56
+
57
+ def platform_field_key(field)
58
+ field.path
59
+ end
60
+
61
+ def platform_authorized_key(type)
62
+ "#{type.graphql_name}.authorized"
63
+ end
64
+
65
+ def platform_resolve_type_key(type)
66
+ "#{type.graphql_name}.resolve_type"
67
+ end
68
+
69
+ private
70
+
71
+ def instrument_execution(platform_key, key, &block)
72
+ if @keys_whitelist.include?(key)
73
+ start = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
74
+ result = block.call
75
+ duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
76
+ @client.send_json(
77
+ type: @collector_type,
78
+ duration: duration,
79
+ platform_key: platform_key,
80
+ key: key
81
+ )
82
+ result
83
+ else
84
+ yield
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -27,9 +27,9 @@ module GraphQL
27
27
  super opts
28
28
  end
29
29
 
30
- def platform_trace(platform_key, key, data, &block)
30
+ def platform_trace(platform_key, key, _data, &block)
31
31
  return yield unless @keys_whitelist.include?(key)
32
- instrument_execution(platform_key, key, data, &block)
32
+ instrument_execution(platform_key, key, &block)
33
33
  end
34
34
 
35
35
  def platform_field_key(type, field)
@@ -46,7 +46,7 @@ module GraphQL
46
46
 
47
47
  private
48
48
 
49
- def instrument_execution(platform_key, key, data, &block)
49
+ def instrument_execution(platform_key, key, &block)
50
50
  start = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
51
51
  result = block.call
52
52
  duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module ScoutTrace
6
+ include PlatformTrace
7
+
8
+ INSTRUMENT_OPTS = { scope: true }
9
+
10
+ # @param set_transaction_name [Boolean] If true, the GraphQL operation name will be used as the transaction name.
11
+ # This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
12
+ # It can also be specified per-query with `context[:set_scout_transaction_name]`.
13
+ def initialize(set_transaction_name: false, **_rest)
14
+ self.class.include(ScoutApm::Tracer)
15
+ @set_transaction_name = set_transaction_name
16
+ super
17
+ end
18
+
19
+ {
20
+ "lex" => "lex.graphql",
21
+ "parse" => "parse.graphql",
22
+ "validate" => "validate.graphql",
23
+ "analyze_query" => "analyze.graphql",
24
+ "analyze_multiplex" => "analyze.graphql",
25
+ "execute_multiplex" => "execute.graphql",
26
+ "execute_query" => "execute.graphql",
27
+ "execute_query_lazy" => "execute.graphql",
28
+ }.each do |trace_method, platform_key|
29
+ module_eval <<-RUBY, __FILE__, __LINE__
30
+ def #{trace_method}(**data)
31
+ #{
32
+ if trace_method == "execute_query"
33
+ <<-RUBY
34
+ set_this_txn_name = data[:query].context[:set_scout_transaction_name]
35
+ if set_this_txn_name == true || (set_this_txn_name.nil? && @set_transaction_name)
36
+ ScoutApm::Transaction.rename(transaction_name(data[:query]))
37
+ end
38
+ RUBY
39
+ end
40
+ }
41
+
42
+ self.class.instrument("GraphQL", "#{platform_key}", INSTRUMENT_OPTS) do
43
+ super
44
+ end
45
+ end
46
+ RUBY
47
+ end
48
+
49
+ def platform_execute_field(platform_key, &block)
50
+ self.class.instrument("GraphQL", platform_key, INSTRUMENT_OPTS, &block)
51
+ end
52
+
53
+ def platform_authorized(platform_key, &block)
54
+ self.class.instrument("GraphQL", platform_key, INSTRUMENT_OPTS, &block)
55
+ end
56
+
57
+ alias :platform_resolve_type :platform_authorized
58
+
59
+ def platform_field_key(field)
60
+ field.path
61
+ end
62
+
63
+ def platform_authorized_key(type)
64
+ "#{type.graphql_name}.authorized"
65
+ end
66
+
67
+ def platform_resolve_type_key(type)
68
+ "#{type.graphql_name}.resolve_type"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ module StatsdTrace
6
+ include PlatformTrace
7
+
8
+ # @param statsd [Object] A statsd client
9
+ def initialize(statsd:, **rest)
10
+ @statsd = statsd
11
+ super(**rest)
12
+ end
13
+
14
+ {
15
+ 'lex' => "graphql.lex",
16
+ 'parse' => "graphql.parse",
17
+ 'validate' => "graphql.validate",
18
+ 'analyze_query' => "graphql.analyze_query",
19
+ 'analyze_multiplex' => "graphql.analyze_multiplex",
20
+ 'execute_multiplex' => "graphql.execute_multiplex",
21
+ 'execute_query' => "graphql.execute_query",
22
+ 'execute_query_lazy' => "graphql.execute_query_lazy",
23
+ }.each do |trace_method, platform_key|
24
+ module_eval <<-RUBY, __FILE__, __LINE__
25
+ def #{trace_method}(**data)
26
+ @statsd.time("#{platform_key}") do
27
+ super
28
+ end
29
+ end
30
+ RUBY
31
+ end
32
+
33
+ def platform_execute_field(platform_key, &block)
34
+ @statsd.time(platform_key, &block)
35
+ end
36
+
37
+ def platform_authorized(key, &block)
38
+ @statsd.time(key, &block)
39
+ end
40
+
41
+ alias :platform_resolve_type :platform_authorized
42
+
43
+ def platform_field_key(field)
44
+ "graphql.#{field.path}"
45
+ end
46
+
47
+ def platform_authorized_key(type)
48
+ "graphql.authorized.#{type.graphql_name}"
49
+ end
50
+
51
+ def platform_resolve_type_key(type)
52
+ "graphql.resolve_type.#{type.graphql_name}"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # Legacy tracing:
2
3
  require "graphql/tracing/active_support_notifications_tracing"
3
4
  require "graphql/tracing/platform_tracing"
4
5
  require "graphql/tracing/appoptics_tracing"
@@ -9,51 +10,147 @@ require "graphql/tracing/scout_tracing"
9
10
  require "graphql/tracing/statsd_tracing"
10
11
  require "graphql/tracing/prometheus_tracing"
11
12
 
13
+ # New Tracing:
14
+ require "graphql/tracing/platform_trace"
15
+ require "graphql/tracing/appoptics_trace"
16
+ require "graphql/tracing/appsignal_trace"
17
+ require "graphql/tracing/data_dog_trace"
18
+ require "graphql/tracing/new_relic_trace"
19
+ require "graphql/tracing/notifications_trace"
20
+ require "graphql/tracing/scout_trace"
21
+ require "graphql/tracing/statsd_trace"
22
+ require "graphql/tracing/prometheus_trace"
12
23
  if defined?(PrometheusExporter::Server)
13
24
  require "graphql/tracing/prometheus_tracing/graphql_collector"
14
25
  end
15
26
 
16
27
  module GraphQL
17
- # Library entry point for performance metric reporting.
18
- #
19
- # @example Sending custom events
20
- # query.trace("my_custom_event", { ... }) do
21
- # # do stuff ...
22
- # end
23
- #
24
- # @example Adding a tracer to a schema
25
- # class MySchema < GraphQL::Schema
26
- # tracer MyTracer # <= responds to .trace(key, data, &block)
27
- # end
28
- #
29
- # @example Adding a tracer to a single query
30
- # MySchema.execute(query_str, context: { backtrace: true })
31
- #
32
- # Events:
33
- #
34
- # Key | Metadata
35
- # ----|---------
36
- # lex | `{ query_string: String }`
37
- # parse | `{ query_string: String }`
38
- # validate | `{ query: GraphQL::Query, validate: Boolean }`
39
- # analyze_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
40
- # analyze_query | `{ query: GraphQL::Query }`
41
- # execute_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
42
- # execute_query | `{ query: GraphQL::Query }`
43
- # execute_query_lazy | `{ query: GraphQL::Query?, multiplex: GraphQL::Execution::Multiplex? }`
44
- # execute_field | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
45
- # execute_field_lazy | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
46
- # authorized | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
47
- # authorized_lazy | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
48
- # resolve_type | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
49
- # resolve_type_lazy | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
50
- #
51
- # Note that `execute_field` and `execute_field_lazy` receive different data in different settings:
52
- #
53
- # - When using {GraphQL::Execution::Interpreter}, they receive `{field:, path:, query:}`
54
- # - Otherwise, they receive `{context: ...}`
55
- #
56
28
  module Tracing
29
+ class Trace
30
+ # @param multiplex [GraphQL::Execution::Multiplex, nil]
31
+ # @param query [GraphQL::Query, nil]
32
+ def initialize(multiplex: nil, query: nil, **_options)
33
+ @multiplex = multiplex
34
+ @query = query
35
+ end
36
+
37
+ def lex(query_string:)
38
+ yield
39
+ end
40
+
41
+ def parse(query_string:)
42
+ yield
43
+ end
44
+
45
+ def validate(query:, validate:)
46
+ yield
47
+ end
48
+
49
+ def analyze_multiplex(multiplex:)
50
+ yield
51
+ end
52
+
53
+ def analyze_query(query:)
54
+ yield
55
+ end
56
+
57
+ def execute_multiplex(multiplex:)
58
+ yield
59
+ end
60
+
61
+ def execute_query(query:)
62
+ yield
63
+ end
64
+
65
+ def execute_query_lazy(query:, multiplex:)
66
+ yield
67
+ end
68
+
69
+ def execute_field(field:, query:, ast_node:, arguments:, object:)
70
+ yield
71
+ end
72
+
73
+ def execute_field_lazy(field:, query:, ast_node:, arguments:, object:)
74
+ yield
75
+ end
76
+
77
+ def authorized(query:, type:, object:)
78
+ yield
79
+ end
80
+
81
+ def authorized_lazy(query:, type:, object:)
82
+ yield
83
+ end
84
+
85
+ def resolve_type(query:, type:, object:)
86
+ yield
87
+ end
88
+
89
+ def resolve_type_lazy(query:, type:, object:)
90
+ yield
91
+ end
92
+ end
93
+
94
+ NullTrace = Trace.new
95
+
96
+ class LegacyTrace < Trace
97
+ def lex(query_string:, &block)
98
+ (@multiplex || @query).trace("lex", { query_string: query_string }, &block)
99
+ end
100
+
101
+ def parse(query_string:, &block)
102
+ (@multiplex || @query).trace("parse", { query_string: query_string }, &block)
103
+ end
104
+
105
+ def validate(query:, validate:, &block)
106
+ query.trace("validate", { validate: validate, query: query }, &block)
107
+ end
108
+
109
+ def analyze_multiplex(multiplex:, &block)
110
+ multiplex.trace("analyze_multiplex", { multiplex: multiplex }, &block)
111
+ end
112
+
113
+ def analyze_query(query:, &block)
114
+ query.trace("analyze_query", { query: query }, &block)
115
+ end
116
+
117
+ def execute_multiplex(multiplex:, &block)
118
+ multiplex.trace("execute_multiplex", { multiplex: multiplex }, &block)
119
+ end
120
+
121
+ def execute_query(query:, &block)
122
+ query.trace("execute_query", { query: query }, &block)
123
+ end
124
+
125
+ def execute_query_lazy(query:, multiplex:, &block)
126
+ multiplex.trace("execute_query_lazy", { multiplex: multiplex, query: query }, &block)
127
+ end
128
+
129
+ def execute_field(field:, query:, ast_node:, arguments:, object:, &block)
130
+ query.trace("execute_field", { field: field, query: query, ast_node: ast_node, arguments: arguments, object: object, owner: field.owner, path: query.context[:current_path] }, &block)
131
+ end
132
+
133
+ def execute_field_lazy(field:, query:, ast_node:, arguments:, object:, &block)
134
+ query.trace("execute_field_lazy", { field: field, query: query, ast_node: ast_node, arguments: arguments, object: object, owner: field.owner, path: query.context[:current_path] }, &block)
135
+ end
136
+
137
+ def authorized(query:, type:, object:, &block)
138
+ query.trace("authorized", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
139
+ end
140
+
141
+ def authorized_lazy(query:, type:, object:, &block)
142
+ query.trace("authorized_lazy", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
143
+ end
144
+
145
+ def resolve_type(query:, type:, object:, &block)
146
+ query.trace("resolve_type", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
147
+ end
148
+
149
+ def resolve_type_lazy(query:, type:, object:, &block)
150
+ query.trace("resolve_type_lazy", { context: query.context, type: type, object: object, path: query.context[:current_path] }, &block)
151
+ end
152
+ end
153
+
57
154
  # Objects may include traceable to gain a `.trace(...)` method.
58
155
  # The object must have a `@tracers` ivar of type `Array<<#trace(k, d, &b)>>`.
59
156
  # @api private