graphql 2.0.20 → 2.0.22

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/backtrace/trace.rb +96 -0
  3. data/lib/graphql/backtrace.rb +6 -1
  4. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  5. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
  6. data/lib/graphql/execution/interpreter/runtime.rb +274 -209
  7. data/lib/graphql/execution/interpreter.rb +2 -3
  8. data/lib/graphql/execution/lookahead.rb +1 -1
  9. data/lib/graphql/filter.rb +8 -2
  10. data/lib/graphql/language/document_from_schema_definition.rb +37 -17
  11. data/lib/graphql/language/lexer.rb +5 -3
  12. data/lib/graphql/language/nodes.rb +2 -2
  13. data/lib/graphql/language/parser.rb +475 -458
  14. data/lib/graphql/language/parser.y +5 -1
  15. data/lib/graphql/pagination/connection.rb +5 -5
  16. data/lib/graphql/query/context.rb +22 -12
  17. data/lib/graphql/query/null_context.rb +4 -1
  18. data/lib/graphql/query.rb +25 -11
  19. data/lib/graphql/schema/argument.rb +12 -14
  20. data/lib/graphql/schema/build_from_definition.rb +15 -3
  21. data/lib/graphql/schema/enum_value.rb +2 -5
  22. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  23. data/lib/graphql/schema/field.rb +17 -16
  24. data/lib/graphql/schema/field_extension.rb +1 -4
  25. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  26. data/lib/graphql/schema/input_object.rb +1 -1
  27. data/lib/graphql/schema/member/has_arguments.rb +10 -8
  28. data/lib/graphql/schema/member/has_directives.rb +4 -6
  29. data/lib/graphql/schema/member/has_fields.rb +80 -36
  30. data/lib/graphql/schema/member/has_validators.rb +2 -2
  31. data/lib/graphql/schema/object.rb +1 -1
  32. data/lib/graphql/schema/printer.rb +3 -1
  33. data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
  34. data/lib/graphql/schema/resolver.rb +8 -8
  35. data/lib/graphql/schema/validator.rb +1 -1
  36. data/lib/graphql/schema/warden.rb +11 -3
  37. data/lib/graphql/schema.rb +41 -12
  38. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  39. data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
  40. data/lib/graphql/tracing/appsignal_trace.rb +6 -0
  41. data/lib/graphql/tracing/legacy_trace.rb +65 -0
  42. data/lib/graphql/tracing/notifications_trace.rb +5 -1
  43. data/lib/graphql/tracing/platform_trace.rb +21 -19
  44. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
  45. data/lib/graphql/tracing/trace.rb +75 -0
  46. data/lib/graphql/tracing.rb +4 -123
  47. data/lib/graphql/version.rb +1 -1
  48. data/lib/graphql.rb +4 -0
  49. data/readme.md +1 -1
  50. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b2e44f17a5ec90e92b165e06f843931585a3775096c7404966a51703a65fdb9
4
- data.tar.gz: b79ce54109470f38f6cd50cd8ff79af7beaefbea4564ec7e876c3a58ffd0249f
3
+ metadata.gz: 2564f5f0788db163950385832a4255c88b47b72ddb45175ec30f0f42c6dc0b04
4
+ data.tar.gz: c1760c1a43453ece3baed09bde3e30f6012bd4357ec597781e4616a7c67a2bc4
5
5
  SHA512:
6
- metadata.gz: 59c16753d159b0d25862dfa72e84a72037e19da288db049297d90ede697d4b4eb0456b5bd9b65b7517ef1f375a94c9d0d3cb246a34f5b6100fc347665f94f688
7
- data.tar.gz: 96fb931b54905ee12fd04ac76847e7f20c69f66023b6241e39e69b6de862b7cb8b7ff2dc4db53725e11b0625c55c2c73fbe070a4278ce6eb839a99c2847ac306
6
+ metadata.gz: 4e1d1747ceb4450228b9b7cb9b123f61585fe8eea3d6442627b56818f4a146e2b507e5a0b8665e25334a64dca79eb8a089c2aa0ff3e8d710fb6adec080623da0
7
+ data.tar.gz: f1ec3b93d97f4546184496aed5bc03d5ba1a5af1655aaeeb40ac20461e7c722431a116ca8e1a019d8b7e7eda59e7748f862985ea1dd131b3005ceb9ca3c9fa7c
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Backtrace
4
+ module Trace
5
+ def validate(query:, validate:)
6
+ if query.multiplex
7
+ push_query_backtrace_context(query)
8
+ end
9
+ super
10
+ end
11
+
12
+ def analyze_query(query:)
13
+ if query.multiplex # missing for stand-alone static validation
14
+ push_query_backtrace_context(query)
15
+ end
16
+ super
17
+ end
18
+
19
+ def execute_query(query:)
20
+ push_query_backtrace_context(query)
21
+ super
22
+ end
23
+
24
+ def execute_query_lazy(query:, multiplex:)
25
+ query ||= multiplex.queries.first
26
+ push_query_backtrace_context(query)
27
+ super
28
+ end
29
+
30
+ def execute_field(field:, query:, ast_node:, arguments:, object:)
31
+ push_field_backtrace_context(field, query, ast_node, arguments, object)
32
+ super
33
+ end
34
+
35
+ def execute_field_lazy(field:, query:, ast_node:, arguments:, object:)
36
+ push_field_backtrace_context(field, query, ast_node, arguments, object)
37
+ super
38
+ end
39
+
40
+ def execute_multiplex(multiplex:)
41
+ super
42
+ rescue StandardError => err
43
+ # This is an unhandled error from execution,
44
+ # Re-raise it with a GraphQL trace.
45
+ multiplex_context = multiplex.context
46
+ potential_context = multiplex_context[:last_graphql_backtrace_context]
47
+
48
+ if potential_context.is_a?(GraphQL::Query::Context) ||
49
+ potential_context.is_a?(Backtrace::Frame)
50
+ raise TracedError.new(err, potential_context)
51
+ else
52
+ raise
53
+ end
54
+ ensure
55
+ multiplex_context = multiplex.context
56
+ multiplex_context.delete(:graphql_backtrace_contexts)
57
+ multiplex_context.delete(:last_graphql_backtrace_context)
58
+ end
59
+
60
+ private
61
+
62
+ def push_query_backtrace_context(query)
63
+ push_data = query
64
+ multiplex = query.multiplex
65
+ push_key = []
66
+ push_storage = multiplex.context[:graphql_backtrace_contexts] ||= {}
67
+ push_storage[push_key] = push_data
68
+ multiplex.context[:last_graphql_backtrace_context] = push_data
69
+ end
70
+
71
+ def push_field_backtrace_context(field, query, ast_node, arguments, object)
72
+ multiplex = query.multiplex
73
+ push_key = query.context[:current_path]
74
+ push_storage = multiplex.context[:graphql_backtrace_contexts]
75
+ parent_frame = push_storage[push_key[0..-2]]
76
+
77
+ if parent_frame.is_a?(GraphQL::Query)
78
+ parent_frame = parent_frame.context
79
+ end
80
+
81
+ push_data = Frame.new(
82
+ query: query,
83
+ path: push_key,
84
+ ast_node: ast_node,
85
+ field: field,
86
+ object: object,
87
+ arguments: arguments,
88
+ parent_frame: parent_frame,
89
+ )
90
+
91
+ push_storage[push_key] = push_data
92
+ multiplex.context[:last_graphql_backtrace_context] = push_data
93
+ end
94
+ end
95
+ end
96
+ end
@@ -3,6 +3,7 @@ require "graphql/backtrace/inspect_result"
3
3
  require "graphql/backtrace/table"
4
4
  require "graphql/backtrace/traced_error"
5
5
  require "graphql/backtrace/tracer"
6
+ require "graphql/backtrace/trace"
6
7
  module GraphQL
7
8
  # Wrap unhandled errors with {TracedError}.
8
9
  #
@@ -23,7 +24,7 @@ module GraphQL
23
24
  def_delegators :to_a, :each, :[]
24
25
 
25
26
  def self.use(schema_defn)
26
- schema_defn.tracer(self::Tracer)
27
+ schema_defn.trace_with(self::Trace)
27
28
  end
28
29
 
29
30
  def initialize(context, value: nil)
@@ -54,5 +55,9 @@ module GraphQL
54
55
  @parent_frame = parent_frame
55
56
  end
56
57
  end
58
+
59
+ class DefaultBacktraceTrace < GraphQL::Tracing::Trace
60
+ include GraphQL::Backtrace::Trace
61
+ end
57
62
  end
58
63
  end
@@ -80,7 +80,7 @@ module GraphQL
80
80
  )
81
81
  end
82
82
 
83
- NO_ARGS = {}.freeze
83
+ NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
84
84
  EMPTY = self.new(argument_values: nil, keyword_arguments: NO_ARGS).freeze
85
85
  end
86
86
  end
@@ -7,57 +7,57 @@ module GraphQL
7
7
  def initialize(query)
8
8
  @query = query
9
9
  @dataloader = query.context.dataloader
10
- @storage = Hash.new do |h, ast_node|
11
- h[ast_node] = Hash.new do |h2, arg_owner|
12
- h2[arg_owner] = Hash.new do |h3, parent_object|
13
- dataload_for(ast_node, arg_owner, parent_object) do |kwarg_arguments|
14
- h3[parent_object] = @query.schema.after_lazy(kwarg_arguments) do |resolved_args|
15
- h3[parent_object] = resolved_args
16
- end
17
- end
18
-
19
- if !h3.key?(parent_object)
20
- # TODO should i bother putting anything here?
21
- h3[parent_object] = NO_ARGUMENTS
22
- else
23
- h3[parent_object]
24
- end
10
+ @storage = Hash.new do |h, argument_owner|
11
+ args_by_parent = if argument_owner.arguments_statically_coercible?
12
+ shared_values_cache = {}
13
+ Hash.new do |h2, ignored_parent_object|
14
+ h2[ignored_parent_object] = shared_values_cache
15
+ end
16
+ else
17
+ Hash.new do |h2, parent_object|
18
+ args_by_node = {}
19
+ args_by_node.compare_by_identity
20
+ h2[parent_object] = args_by_node
25
21
  end
26
22
  end
23
+ args_by_parent.compare_by_identity
24
+ h[argument_owner] = args_by_parent
27
25
  end
26
+ @storage.compare_by_identity
28
27
  end
29
28
 
30
29
  def fetch(ast_node, argument_owner, parent_object)
31
- # If any jobs were enqueued, run them now,
32
- # since this might have been called outside of execution.
33
- # (The jobs are responsible for updating `result` in-place.)
34
- if !@storage.key?(ast_node) || !@storage[ast_node].key?(argument_owner)
35
- @dataloader.run_isolated do
36
- @storage[ast_node][argument_owner][parent_object]
30
+ # This runs eagerly if no block is given
31
+ @storage[argument_owner][parent_object][ast_node] ||= begin
32
+ args_hash = self.class.prepare_args_hash(@query, ast_node)
33
+ kwarg_arguments = argument_owner.coerce_arguments(parent_object, args_hash, @query.context)
34
+ @query.after_lazy(kwarg_arguments) do |resolved_args|
35
+ @storage[argument_owner][parent_object][ast_node] = resolved_args
37
36
  end
38
37
  end
39
- # Ack, the _hash_ is updated, but the key is eventually
40
- # overridden with an immutable arguments instance.
41
- # The first call queues up the job,
42
- # then this call fetches the result.
43
- # TODO this should be better, find a solution
44
- # that works with merging the runtime.rb code
45
- @storage[ast_node][argument_owner][parent_object]
38
+
46
39
  end
47
40
 
48
41
  # @yield [Interpreter::Arguments, Lazy<Interpreter::Arguments>] The finally-loaded arguments
49
42
  def dataload_for(ast_node, argument_owner, parent_object, &block)
50
43
  # First, normalize all AST or Ruby values to a plain Ruby hash
51
- args_hash = self.class.prepare_args_hash(@query, ast_node)
52
- argument_owner.coerce_arguments(parent_object, args_hash, @query.context, &block)
44
+ arg_storage = @storage[argument_owner][parent_object]
45
+ if (args = arg_storage[ast_node])
46
+ yield(args)
47
+ else
48
+ args_hash = self.class.prepare_args_hash(@query, ast_node)
49
+ argument_owner.coerce_arguments(parent_object, args_hash, @query.context) do |resolved_args|
50
+ arg_storage[ast_node] = resolved_args
51
+ yield(resolved_args)
52
+ end
53
+ end
53
54
  nil
54
55
  end
55
56
 
56
57
  private
57
58
 
58
- NO_ARGUMENTS = {}.freeze
59
-
60
- NO_VALUE_GIVEN = Object.new
59
+ NO_ARGUMENTS = GraphQL::EmptyObjects::EMPTY_HASH
60
+ NO_VALUE_GIVEN = NOT_CONFIGURED
61
61
 
62
62
  def self.prepare_args_hash(query, ast_arg_or_hash_or_value)
63
63
  case ast_arg_or_hash_or_value