graphql 2.0.16 → 2.0.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) 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/trace.rb +96 -0
  5. data/lib/graphql/backtrace/tracer.rb +1 -1
  6. data/lib/graphql/backtrace.rb +6 -1
  7. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  8. data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -3
  9. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  10. data/lib/graphql/execution/interpreter/runtime.rb +264 -211
  11. data/lib/graphql/execution/interpreter.rb +15 -10
  12. data/lib/graphql/execution/lazy.rb +6 -12
  13. data/lib/graphql/execution/multiplex.rb +2 -1
  14. data/lib/graphql/filter.rb +7 -2
  15. data/lib/graphql/introspection/directive_type.rb +2 -2
  16. data/lib/graphql/introspection/field_type.rb +1 -1
  17. data/lib/graphql/introspection/schema_type.rb +2 -2
  18. data/lib/graphql/introspection/type_type.rb +5 -5
  19. data/lib/graphql/language/document_from_schema_definition.rb +25 -9
  20. data/lib/graphql/language/lexer.rb +216 -1505
  21. data/lib/graphql/language/nodes.rb +66 -40
  22. data/lib/graphql/language/parser.rb +509 -491
  23. data/lib/graphql/language/parser.y +43 -38
  24. data/lib/graphql/language/visitor.rb +191 -83
  25. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  26. data/lib/graphql/pagination/connection.rb +5 -5
  27. data/lib/graphql/query/context.rb +62 -31
  28. data/lib/graphql/query/null_context.rb +1 -1
  29. data/lib/graphql/query.rb +22 -5
  30. data/lib/graphql/schema/argument.rb +7 -13
  31. data/lib/graphql/schema/build_from_definition.rb +15 -3
  32. data/lib/graphql/schema/directive.rb +12 -2
  33. data/lib/graphql/schema/enum.rb +24 -17
  34. data/lib/graphql/schema/enum_value.rb +2 -3
  35. data/lib/graphql/schema/field.rb +68 -57
  36. data/lib/graphql/schema/field_extension.rb +1 -4
  37. data/lib/graphql/schema/find_inherited_value.rb +2 -7
  38. data/lib/graphql/schema/interface.rb +0 -10
  39. data/lib/graphql/schema/late_bound_type.rb +2 -0
  40. data/lib/graphql/schema/member/base_dsl_methods.rb +17 -14
  41. data/lib/graphql/schema/member/has_arguments.rb +105 -58
  42. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  43. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  44. data/lib/graphql/schema/member/has_directives.rb +15 -10
  45. data/lib/graphql/schema/member/has_fields.rb +95 -38
  46. data/lib/graphql/schema/member/has_interfaces.rb +49 -8
  47. data/lib/graphql/schema/member/has_validators.rb +32 -6
  48. data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
  49. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  50. data/lib/graphql/schema/object.rb +2 -4
  51. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  52. data/lib/graphql/schema/resolver.rb +4 -4
  53. data/lib/graphql/schema/timeout.rb +24 -28
  54. data/lib/graphql/schema/validator.rb +1 -1
  55. data/lib/graphql/schema/warden.rb +29 -5
  56. data/lib/graphql/schema.rb +76 -25
  57. data/lib/graphql/static_validation/literal_validator.rb +15 -1
  58. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  59. data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
  60. data/lib/graphql/static_validation/validator.rb +1 -1
  61. data/lib/graphql/subscriptions/event.rb +2 -7
  62. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  63. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  64. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  65. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  66. data/lib/graphql/tracing/legacy_trace.rb +65 -0
  67. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  68. data/lib/graphql/tracing/notifications_trace.rb +42 -0
  69. data/lib/graphql/tracing/platform_trace.rb +109 -0
  70. data/lib/graphql/tracing/platform_tracing.rb +15 -3
  71. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  72. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
  73. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  74. data/lib/graphql/tracing/scout_trace.rb +72 -0
  75. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  76. data/lib/graphql/tracing/trace.rb +75 -0
  77. data/lib/graphql/tracing.rb +16 -39
  78. data/lib/graphql/type_kinds.rb +6 -3
  79. data/lib/graphql/types/relay/base_connection.rb +1 -1
  80. data/lib/graphql/types/relay/connection_behaviors.rb +24 -6
  81. data/lib/graphql/types/relay/edge_behaviors.rb +16 -6
  82. data/lib/graphql/types/relay/node_behaviors.rb +7 -1
  83. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  84. data/lib/graphql/types/relay.rb +0 -1
  85. data/lib/graphql/types/string.rb +1 -1
  86. data/lib/graphql/version.rb +1 -1
  87. data/lib/graphql.rb +16 -9
  88. metadata +34 -9
  89. data/lib/graphql/language/lexer.rl +0 -280
  90. data/lib/graphql/types/relay/default_relay.rb +0 -27
@@ -14,7 +14,7 @@ module GraphQL
14
14
  class << self
15
15
  # Used internally to signal that the query shouldn't be executed
16
16
  # @api private
17
- NO_OPERATION = {}.freeze
17
+ NO_OPERATION = GraphQL::EmptyObjects::EMPTY_HASH
18
18
 
19
19
  # @param schema [GraphQL::Schema]
20
20
  # @param queries [Array<GraphQL::Query, Hash>]
@@ -34,11 +34,12 @@ module GraphQL
34
34
  end
35
35
 
36
36
  multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
37
- multiplex.trace("execute_multiplex", { multiplex: multiplex }) do
37
+ multiplex.current_trace.execute_multiplex(multiplex: multiplex) do
38
38
  schema = multiplex.schema
39
39
  queries = multiplex.queries
40
40
  query_instrumenters = schema.instrumenters[:query]
41
41
  multiplex_instrumenters = schema.instrumenters[:multiplex]
42
+ lazies_at_depth = Hash.new { |h, k| h[k] = [] }
42
43
 
43
44
  # First, run multiplex instrumentation, then query instrumentation for each query
44
45
  call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
@@ -67,10 +68,10 @@ module GraphQL
67
68
  # Although queries in a multiplex _share_ an Interpreter instance,
68
69
  # they also have another item of state, which is private to that query
69
70
  # in particular, assign it here:
70
- runtime = Runtime.new(query: query)
71
+ runtime = Runtime.new(query: query, lazies_at_depth: lazies_at_depth)
71
72
  query.context.namespace(:interpreter_runtime)[:runtime] = runtime
72
73
 
73
- query.trace("execute_query", {query: query}) do
74
+ query.current_trace.execute_query(query: query) do
74
75
  runtime.run_eager
75
76
  end
76
77
  rescue GraphQL::ExecutionError => err
@@ -95,16 +96,13 @@ module GraphQL
95
96
  runtime ? runtime.final_result : nil
96
97
  end
97
98
  final_values.compact!
98
- tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
99
- Interpreter::Resolve.resolve_all(final_values, multiplex.dataloader)
99
+ tracer.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
100
+ Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
100
101
  end
101
102
  queries.each do |query|
102
103
  runtime = query.context.namespace(:interpreter_runtime)[:runtime]
103
104
  if runtime
104
- runtime.delete_interpreter_context(:current_path)
105
- runtime.delete_interpreter_context(:current_field)
106
- runtime.delete_interpreter_context(:current_object)
107
- runtime.delete_interpreter_context(:current_arguments)
105
+ runtime.delete_all_interpreter_context
108
106
  end
109
107
  end
110
108
  }
@@ -146,6 +144,13 @@ module GraphQL
146
144
  # Assign values here so that the query's `@executed` becomes true
147
145
  queries.map { |q| q.result_values ||= {} }
148
146
  raise
147
+ ensure
148
+ queries.map { |query|
149
+ runtime = query.context.namespace(:interpreter_runtime)[:runtime]
150
+ if runtime
151
+ runtime.delete_all_interpreter_context
152
+ end
153
+ }
149
154
  end
150
155
  end
151
156
  end
@@ -12,16 +12,14 @@ module GraphQL
12
12
  # - It has no error-catching functionality
13
13
  # @api private
14
14
  class Lazy
15
- attr_reader :path, :field
15
+ attr_reader :field
16
16
 
17
17
  # Create a {Lazy} which will get its inner value by calling the block
18
- # @param path [Array<String, Integer>]
19
18
  # @param field [GraphQL::Schema::Field]
20
19
  # @param get_value_func [Proc] a block to get the inner value (later)
21
- def initialize(path: nil, field: nil, &get_value_func)
20
+ def initialize(field: nil, &get_value_func)
22
21
  @get_value_func = get_value_func
23
22
  @resolved = false
24
- @path = path
25
23
  @field = field
26
24
  end
27
25
 
@@ -29,15 +27,11 @@ module GraphQL
29
27
  def value
30
28
  if !@resolved
31
29
  @resolved = true
32
- @value = begin
33
- v = @get_value_func.call
34
- if v.is_a?(Lazy)
35
- v = v.value
36
- end
37
- v
38
- rescue GraphQL::ExecutionError => err
39
- err
30
+ v = @get_value_func.call
31
+ if v.is_a?(Lazy)
32
+ v = v.value
40
33
  end
34
+ @value = v
41
35
  end
42
36
 
43
37
  # `SKIP` was made into a subclass of `GraphQL::Error` to improve runtime performance
@@ -25,13 +25,14 @@ module GraphQL
25
25
  class Multiplex
26
26
  include Tracing::Traceable
27
27
 
28
- attr_reader :context, :queries, :schema, :max_complexity, :dataloader
28
+ attr_reader :context, :queries, :schema, :max_complexity, :dataloader, :current_trace
29
29
 
30
30
  def initialize(schema:, queries:, context:, max_complexity:)
31
31
  @schema = schema
32
32
  @queries = queries
33
33
  @queries.each { |q| q.multiplex = self }
34
34
  @context = context
35
+ @current_trace = @context[:trace] || schema.new_trace(multiplex: self)
35
36
  @dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
36
37
  @tracers = schema.tracers + (context[:tracers] || [])
37
38
  # Support `context: {backtrace: true}`
@@ -1,8 +1,13 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/deprecation"
3
+
2
4
  module GraphQL
3
5
  # @api private
4
6
  class Filter
5
- def initialize(only: nil, except: nil)
7
+ def initialize(only: nil, except: nil, silence_deprecation_warning: false)
8
+ if !silence_deprecation_warning
9
+ GraphQL::Deprecation.warn("GraphQL::Filter is deprecated and will be removed in v2.1.0. Implement `visible?` on your schema members instead (https://graphql-ruby.org/authorization/visibility.html).")
10
+ end
6
11
  @only = only
7
12
  @except = except
8
13
  end
@@ -17,7 +22,7 @@ module GraphQL
17
22
  onlies = [self].concat(Array(only))
18
23
  merged_only = MergedOnly.build(onlies)
19
24
  merged_except = MergedExcept.build(Array(except))
20
- self.class.new(only: merged_only, except: merged_except)
25
+ self.class.new(only: merged_only, except: merged_except, silence_deprecation_warning: true)
21
26
  end
22
27
 
23
28
  private
@@ -11,8 +11,8 @@ module GraphQL
11
11
  "to the executor."
12
12
  field :name, String, null: false, method: :graphql_name
13
13
  field :description, String
14
- field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
15
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
14
+ field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false, scope: false
15
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
16
16
  argument :include_deprecated, Boolean, required: false, default_value: false
17
17
  end
18
18
  field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?
@@ -7,7 +7,7 @@ module GraphQL
7
7
  "a name, potentially a list of arguments, and a return type."
8
8
  field :name, String, null: false
9
9
  field :description, String
10
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
10
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
11
11
  argument :include_deprecated, Boolean, required: false, default_value: false
12
12
  end
13
13
  field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
@@ -8,11 +8,11 @@ module GraphQL
8
8
  "available types and directives on the server, as well as the entry points for "\
9
9
  "query, mutation, and subscription operations."
10
10
 
11
- field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
11
+ field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false, scope: false
12
12
  field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
13
  field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at."
14
14
  field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at."
15
- field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
15
+ field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false, scope: false
16
16
  field :description, String, resolver_method: :schema_description
17
17
 
18
18
  def schema_description
@@ -14,15 +14,15 @@ module GraphQL
14
14
  field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
15
15
  field :name, String, method: :graphql_name
16
16
  field :description, String
17
- field :fields, [GraphQL::Schema::LateBoundType.new("__Field")] do
17
+ field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], scope: false do
18
18
  argument :include_deprecated, Boolean, required: false, default_value: false
19
19
  end
20
- field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")]
21
- field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")]
22
- field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")] do
20
+ field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
21
+ field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
22
+ field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], scope: false do
23
23
  argument :include_deprecated, Boolean, required: false, default_value: false
24
24
  end
25
- field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")] do
25
+ field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], scope: false do
26
26
  argument :include_deprecated, Boolean, required: false, default_value: false
27
27
  end
28
28
  field :of_type, GraphQL::Schema::LateBoundType.new("__Type")
@@ -22,8 +22,9 @@ module GraphQL
22
22
  @include_introspection_types = include_introspection_types
23
23
  @include_built_in_scalars = include_built_in_scalars
24
24
  @include_built_in_directives = include_built_in_directives
25
+ @include_one_of = false
25
26
 
26
- filter = GraphQL::Filter.new(only: only, except: except)
27
+ filter = GraphQL::Filter.new(only: only, except: except, silence_deprecation_warning: true)
27
28
  if @schema.respond_to?(:visible?)
28
29
  filter = filter.merge(only: @schema.method(:visible?))
29
30
  end
@@ -245,20 +246,30 @@ module GraphQL
245
246
  end
246
247
 
247
248
  def build_directive_nodes(directives)
248
- if !include_built_in_directives
249
- directives = directives.reject { |directive| directive.default_directive? }
250
- end
251
-
252
249
  directives
253
250
  .map { |directive| build_directive_node(directive) }
254
251
  .sort_by(&:name)
255
252
  end
256
253
 
257
254
  def build_definition_nodes
258
- definitions = []
259
- definitions << build_schema_node if include_schema_node?
260
- definitions += build_directive_nodes(warden.directives)
261
- definitions += build_type_definition_nodes(warden.reachable_types)
255
+ dirs_to_build = warden.directives
256
+ if !include_built_in_directives
257
+ dirs_to_build = dirs_to_build.reject { |directive| directive.default_directive? }
258
+ end
259
+ dir_nodes = build_directive_nodes(dirs_to_build)
260
+
261
+ type_nodes = build_type_definition_nodes(warden.reachable_types)
262
+
263
+ if @include_one_of
264
+ # This may have been set to true when iterating over all types
265
+ dir_nodes.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
266
+ end
267
+
268
+ definitions = [*dir_nodes, *type_nodes]
269
+ if include_schema_node?
270
+ definitions.unshift(build_schema_node)
271
+ end
272
+
262
273
  definitions
263
274
  end
264
275
 
@@ -318,6 +329,11 @@ module GraphQL
318
329
  )
319
330
  end
320
331
  end
332
+
333
+ # If this schema uses this built-in directive definition,
334
+ # include it in the print-out since it's not part of the spec yet.
335
+ @include_one_of ||= dir.class == GraphQL::Schema::Directive::OneOf
336
+
321
337
  GraphQL::Language::Nodes::Directive.new(
322
338
  name: dir.class.graphql_name,
323
339
  arguments: args