graphql 2.0.30 → 2.3.6

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.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  4. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  5. data/lib/generators/graphql/install_generator.rb +3 -0
  6. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  7. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  8. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  9. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  10. data/lib/generators/graphql/templates/base_field.erb +2 -0
  11. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  12. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  13. data/lib/generators/graphql/templates/base_object.erb +2 -0
  14. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  15. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  16. data/lib/generators/graphql/templates/base_union.erb +2 -0
  17. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  18. data/lib/generators/graphql/templates/loader.erb +2 -0
  19. data/lib/generators/graphql/templates/mutation.erb +2 -0
  20. data/lib/generators/graphql/templates/node_type.erb +2 -0
  21. data/lib/generators/graphql/templates/query_type.erb +2 -0
  22. data/lib/generators/graphql/templates/schema.erb +5 -0
  23. data/lib/graphql/analysis/analyzer.rb +89 -0
  24. data/lib/graphql/analysis/field_usage.rb +82 -0
  25. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  26. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  27. data/lib/graphql/analysis/query_complexity.rb +183 -0
  28. data/lib/graphql/analysis/query_depth.rb +58 -0
  29. data/lib/graphql/analysis/visitor.rb +282 -0
  30. data/lib/graphql/analysis.rb +92 -1
  31. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  32. data/lib/graphql/backtrace/trace.rb +12 -15
  33. data/lib/graphql/coercion_error.rb +1 -9
  34. data/lib/graphql/dataloader/async_dataloader.rb +88 -0
  35. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  36. data/lib/graphql/dataloader/request.rb +5 -0
  37. data/lib/graphql/dataloader/source.rb +11 -3
  38. data/lib/graphql/dataloader.rb +112 -142
  39. data/lib/graphql/duration_encoding_error.rb +16 -0
  40. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  41. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  42. data/lib/graphql/execution/interpreter/runtime.rb +163 -365
  43. data/lib/graphql/execution/interpreter.rb +92 -158
  44. data/lib/graphql/execution/lookahead.rb +88 -21
  45. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  46. data/lib/graphql/introspection/entry_points.rb +11 -5
  47. data/lib/graphql/introspection/schema_type.rb +3 -1
  48. data/lib/graphql/language/block_string.rb +34 -18
  49. data/lib/graphql/language/definition_slice.rb +1 -1
  50. data/lib/graphql/language/document_from_schema_definition.rb +38 -38
  51. data/lib/graphql/language/lexer.rb +305 -193
  52. data/lib/graphql/language/nodes.rb +113 -66
  53. data/lib/graphql/language/parser.rb +787 -1986
  54. data/lib/graphql/language/printer.rb +303 -146
  55. data/lib/graphql/language/sanitized_printer.rb +20 -22
  56. data/lib/graphql/language/static_visitor.rb +167 -0
  57. data/lib/graphql/language/visitor.rb +20 -81
  58. data/lib/graphql/language.rb +61 -0
  59. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  60. data/lib/graphql/pagination/array_connection.rb +6 -6
  61. data/lib/graphql/pagination/connection.rb +28 -1
  62. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  63. data/lib/graphql/query/context/scoped_context.rb +101 -0
  64. data/lib/graphql/query/context.rb +66 -131
  65. data/lib/graphql/query/null_context.rb +4 -11
  66. data/lib/graphql/query/validation_pipeline.rb +4 -4
  67. data/lib/graphql/query/variables.rb +3 -3
  68. data/lib/graphql/query.rb +17 -26
  69. data/lib/graphql/railtie.rb +9 -6
  70. data/lib/graphql/rake_task.rb +3 -12
  71. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  72. data/lib/graphql/schema/addition.rb +21 -11
  73. data/lib/graphql/schema/argument.rb +43 -8
  74. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  75. data/lib/graphql/schema/build_from_definition.rb +9 -12
  76. data/lib/graphql/schema/directive/one_of.rb +12 -0
  77. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  78. data/lib/graphql/schema/directive.rb +3 -1
  79. data/lib/graphql/schema/enum.rb +3 -3
  80. data/lib/graphql/schema/field/connection_extension.rb +1 -15
  81. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  82. data/lib/graphql/schema/field.rb +49 -35
  83. data/lib/graphql/schema/has_single_input_argument.rb +157 -0
  84. data/lib/graphql/schema/input_object.rb +4 -4
  85. data/lib/graphql/schema/interface.rb +10 -10
  86. data/lib/graphql/schema/introspection_system.rb +4 -2
  87. data/lib/graphql/schema/late_bound_type.rb +4 -0
  88. data/lib/graphql/schema/list.rb +2 -2
  89. data/lib/graphql/schema/loader.rb +2 -3
  90. data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
  91. data/lib/graphql/schema/member/has_arguments.rb +63 -73
  92. data/lib/graphql/schema/member/has_directives.rb +1 -1
  93. data/lib/graphql/schema/member/has_fields.rb +8 -5
  94. data/lib/graphql/schema/member/has_interfaces.rb +23 -9
  95. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  96. data/lib/graphql/schema/member/scoped.rb +19 -0
  97. data/lib/graphql/schema/member/type_system_helpers.rb +1 -2
  98. data/lib/graphql/schema/member/validates_input.rb +3 -3
  99. data/lib/graphql/schema/mutation.rb +7 -0
  100. data/lib/graphql/schema/object.rb +8 -0
  101. data/lib/graphql/schema/printer.rb +8 -7
  102. data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
  103. data/lib/graphql/schema/resolver.rb +27 -13
  104. data/lib/graphql/schema/scalar.rb +3 -3
  105. data/lib/graphql/schema/subscription.rb +11 -4
  106. data/lib/graphql/schema/union.rb +1 -1
  107. data/lib/graphql/schema/unique_within_type.rb +1 -1
  108. data/lib/graphql/schema/warden.rb +96 -95
  109. data/lib/graphql/schema.rb +323 -102
  110. data/lib/graphql/static_validation/all_rules.rb +1 -1
  111. data/lib/graphql/static_validation/base_visitor.rb +1 -1
  112. data/lib/graphql/static_validation/literal_validator.rb +2 -3
  113. data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
  114. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  115. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +2 -2
  116. data/lib/graphql/static_validation/validation_context.rb +5 -5
  117. data/lib/graphql/static_validation/validator.rb +3 -0
  118. data/lib/graphql/static_validation.rb +0 -1
  119. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
  120. data/lib/graphql/subscriptions/broadcast_analyzer.rb +1 -1
  121. data/lib/graphql/subscriptions/event.rb +8 -2
  122. data/lib/graphql/subscriptions/serialize.rb +2 -0
  123. data/lib/graphql/subscriptions.rb +15 -13
  124. data/lib/graphql/testing/helpers.rb +151 -0
  125. data/lib/graphql/testing.rb +2 -0
  126. data/lib/graphql/tracing/appoptics_trace.rb +2 -2
  127. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  128. data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
  129. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  130. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
  131. data/lib/graphql/tracing/prometheus_trace.rb +9 -9
  132. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  133. data/lib/graphql/tracing/trace.rb +1 -0
  134. data/lib/graphql/tracing.rb +3 -1
  135. data/lib/graphql/type_kinds.rb +1 -1
  136. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  137. data/lib/graphql/types/relay/connection_behaviors.rb +32 -2
  138. data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
  139. data/lib/graphql/types.rb +1 -0
  140. data/lib/graphql/version.rb +1 -1
  141. data/lib/graphql.rb +13 -13
  142. data/readme.md +12 -2
  143. metadata +33 -26
  144. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  145. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  146. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  147. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  148. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  149. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  150. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  151. data/lib/graphql/analysis/ast.rb +0 -81
  152. data/lib/graphql/deprecation.rb +0 -9
  153. data/lib/graphql/filter.rb +0 -59
  154. data/lib/graphql/language/parser.y +0 -560
  155. data/lib/graphql/schema/base_64_bp.rb +0 -26
  156. data/lib/graphql/static_validation/type_stack.rb +0 -216
  157. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Query
4
+ class Context
5
+ class ScopedContext
6
+ def initialize(query_context)
7
+ @query_context = query_context
8
+ @scoped_contexts = nil
9
+ @all_keys = nil
10
+ end
11
+
12
+ def merged_context
13
+ if @scoped_contexts.nil?
14
+ GraphQL::EmptyObjects::EMPTY_HASH
15
+ else
16
+ merged_ctx = {}
17
+ each_present_path_ctx do |path_ctx|
18
+ merged_ctx = path_ctx.merge(merged_ctx)
19
+ end
20
+ merged_ctx
21
+ end
22
+ end
23
+
24
+ def merge!(hash, at: current_path)
25
+ @all_keys ||= Set.new
26
+ @all_keys.merge(hash.keys)
27
+ ctx = @scoped_contexts ||= {}
28
+ at.each do |path_part|
29
+ ctx = ctx[path_part] ||= { parent: ctx }
30
+ end
31
+ this_scoped_ctx = ctx[:scoped_context] ||= {}
32
+ this_scoped_ctx.merge!(hash)
33
+ end
34
+
35
+ def key?(key)
36
+ if @all_keys && @all_keys.include?(key)
37
+ each_present_path_ctx do |path_ctx|
38
+ if path_ctx.key?(key)
39
+ return true
40
+ end
41
+ end
42
+ end
43
+ false
44
+ end
45
+
46
+ def [](key)
47
+ each_present_path_ctx do |path_ctx|
48
+ if path_ctx.key?(key)
49
+ return path_ctx[key]
50
+ end
51
+ end
52
+ nil
53
+ end
54
+
55
+ def current_path
56
+ @query_context.current_path || GraphQL::EmptyObjects::EMPTY_ARRAY
57
+ end
58
+
59
+ def dig(key, *other_keys)
60
+ each_present_path_ctx do |path_ctx|
61
+ if path_ctx.key?(key)
62
+ found_value = path_ctx[key]
63
+ if other_keys.any?
64
+ return found_value.dig(*other_keys)
65
+ else
66
+ return found_value
67
+ end
68
+ end
69
+ end
70
+ nil
71
+ end
72
+
73
+ private
74
+
75
+ # Start at the current location,
76
+ # but look up the tree for previously-assigned scoped values
77
+ def each_present_path_ctx
78
+ ctx = @scoped_contexts
79
+ if ctx.nil?
80
+ # no-op
81
+ else
82
+ current_path.each do |path_part|
83
+ if ctx.key?(path_part)
84
+ ctx = ctx[path_part]
85
+ else
86
+ break
87
+ end
88
+ end
89
+
90
+ while ctx
91
+ if (scoped_ctx = ctx[:scoped_context])
92
+ yield(scoped_ctx)
93
+ end
94
+ ctx = ctx[:parent]
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -1,39 +1,11 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/query/context/scoped_context"
3
+
2
4
  module GraphQL
3
5
  class Query
4
6
  # Expose some query-specific info to field resolve functions.
5
7
  # It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
6
8
  class Context
7
- module SharedMethods
8
- # Return this value to tell the runtime
9
- # to exclude this field from the response altogether
10
- def skip
11
- GraphQL::Execution::SKIP
12
- end
13
-
14
- # Add error at query-level.
15
- # @param error [GraphQL::ExecutionError] an execution error
16
- # @return [void]
17
- def add_error(error)
18
- if !error.is_a?(ExecutionError)
19
- raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
20
- end
21
- errors << error
22
- nil
23
- end
24
-
25
- # @example Print the GraphQL backtrace during field resolution
26
- # puts ctx.backtrace
27
- #
28
- # @return [GraphQL::Backtrace] The backtrace for this point in query execution
29
- def backtrace
30
- GraphQL::Backtrace.new(self)
31
- end
32
-
33
- def execution_errors
34
- @execution_errors ||= ExecutionErrors.new(self)
35
- end
36
- end
37
9
 
38
10
  class ExecutionErrors
39
11
  def initialize(ctx)
@@ -57,7 +29,6 @@ module GraphQL
57
29
  alias :push :add
58
30
  end
59
31
 
60
- include SharedMethods
61
32
  extend Forwardable
62
33
 
63
34
  # @return [Array<GraphQL::ExecutionError>] errors returned during execution
@@ -75,11 +46,10 @@ module GraphQL
75
46
  # Make a new context which delegates key lookup to `values`
76
47
  # @param query [GraphQL::Query] the query who owns this context
77
48
  # @param values [Hash] A hash of arbitrary values which will be accessible at query-time
78
- def initialize(query:, schema: query.schema, values:, object:)
49
+ def initialize(query:, schema: query.schema, values:)
79
50
  @query = query
80
51
  @schema = schema
81
52
  @provided_values = values || {}
82
- @object = object
83
53
  # Namespaced storage, where user-provided values are in `nil` namespace:
84
54
  @storage = Hash.new { |h, k| h[k] = {} }
85
55
  @storage[nil] = @provided_values
@@ -90,104 +60,6 @@ module GraphQL
90
60
  @scoped_context = ScopedContext.new(self)
91
61
  end
92
62
 
93
- class ScopedContext
94
- NO_PATH = GraphQL::EmptyObjects::EMPTY_ARRAY
95
- NO_CONTEXT = GraphQL::EmptyObjects::EMPTY_HASH
96
-
97
- def initialize(query_context)
98
- @query_context = query_context
99
- @scoped_contexts = nil
100
- @all_keys = nil
101
- end
102
-
103
- def merged_context
104
- if @scoped_contexts.nil?
105
- NO_CONTEXT
106
- else
107
- merged_ctx = {}
108
- each_present_path_ctx do |path_ctx|
109
- merged_ctx = path_ctx.merge(merged_ctx)
110
- end
111
- merged_ctx
112
- end
113
- end
114
-
115
- def merge!(hash)
116
- @all_keys ||= Set.new
117
- @all_keys.merge(hash.keys)
118
- ctx = @scoped_contexts ||= {}
119
- current_path.each do |path_part|
120
- ctx = ctx[path_part] ||= { parent: ctx }
121
- end
122
- this_scoped_ctx = ctx[:scoped_context] ||= {}
123
- this_scoped_ctx.merge!(hash)
124
- end
125
-
126
- def key?(key)
127
- if @all_keys && @all_keys.include?(key)
128
- each_present_path_ctx do |path_ctx|
129
- if path_ctx.key?(key)
130
- return true
131
- end
132
- end
133
- end
134
- false
135
- end
136
-
137
- def [](key)
138
- each_present_path_ctx do |path_ctx|
139
- if path_ctx.key?(key)
140
- return path_ctx[key]
141
- end
142
- end
143
- nil
144
- end
145
-
146
- def current_path
147
- @query_context.current_path || NO_PATH
148
- end
149
-
150
- def dig(key, *other_keys)
151
- each_present_path_ctx do |path_ctx|
152
- if path_ctx.key?(key)
153
- found_value = path_ctx[key]
154
- if other_keys.any?
155
- return found_value.dig(*other_keys)
156
- else
157
- return found_value
158
- end
159
- end
160
- end
161
- nil
162
- end
163
-
164
- private
165
-
166
- # Start at the current location,
167
- # but look up the tree for previously-assigned scoped values
168
- def each_present_path_ctx
169
- ctx = @scoped_contexts
170
- if ctx.nil?
171
- # no-op
172
- else
173
- current_path.each do |path_part|
174
- if ctx.key?(path_part)
175
- ctx = ctx[path_part]
176
- else
177
- break
178
- end
179
- end
180
-
181
- while ctx
182
- if (scoped_ctx = ctx[:scoped_context])
183
- yield(scoped_ctx)
184
- end
185
- ctx = ctx[:parent]
186
- end
187
- end
188
- end
189
- end
190
-
191
63
  # @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
192
64
  def response_extensions
193
65
  namespace(:__query_result_extensions__)
@@ -236,6 +108,35 @@ module GraphQL
236
108
  end
237
109
  end
238
110
 
111
+ # Return this value to tell the runtime
112
+ # to exclude this field from the response altogether
113
+ def skip
114
+ GraphQL::Execution::SKIP
115
+ end
116
+
117
+ # Add error at query-level.
118
+ # @param error [GraphQL::ExecutionError] an execution error
119
+ # @return [void]
120
+ def add_error(error)
121
+ if !error.is_a?(ExecutionError)
122
+ raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
123
+ end
124
+ errors << error
125
+ nil
126
+ end
127
+
128
+ # @example Print the GraphQL backtrace during field resolution
129
+ # puts ctx.backtrace
130
+ #
131
+ # @return [GraphQL::Backtrace] The backtrace for this point in query execution
132
+ def backtrace
133
+ GraphQL::Backtrace.new(self)
134
+ end
135
+
136
+ def execution_errors
137
+ @execution_errors ||= ExecutionErrors.new(self)
138
+ end
139
+
239
140
  def current_path
240
141
  current_runtime_state = Thread.current[:__graphql_runtime_info]
241
142
  query_runtime_state = current_runtime_state && current_runtime_state[@query]
@@ -333,6 +234,10 @@ module GraphQL
333
234
  @storage.key?(ns)
334
235
  end
335
236
 
237
+ def logger
238
+ @query && @query.logger
239
+ end
240
+
336
241
  def inspect
337
242
  "#<Query::Context ...>"
338
243
  end
@@ -345,6 +250,36 @@ module GraphQL
345
250
  scoped_merge!(key => value)
346
251
  nil
347
252
  end
253
+
254
+ # Use this when you need to do a scoped set _inside_ a lazy-loaded (or batch-loaded)
255
+ # block of code.
256
+ #
257
+ # @example using scoped context inside a promise
258
+ # scoped_ctx = context.scoped
259
+ # SomeBatchLoader.load(...).then do |thing|
260
+ # # use a scoped_ctx which was created _before_ dataloading:
261
+ # scoped_ctx.set!(:thing, thing)
262
+ # end
263
+ # @return [Context::Scoped]
264
+ def scoped
265
+ Scoped.new(@scoped_context, current_path)
266
+ end
267
+
268
+ class Scoped
269
+ def initialize(scoped_context, path)
270
+ @path = path
271
+ @scoped_context = scoped_context
272
+ end
273
+
274
+ def merge!(hash)
275
+ @scoped_context.merge!(hash, at: @path)
276
+ end
277
+
278
+ def set!(key, value)
279
+ @scoped_context.merge!({ key => value }, at: @path)
280
+ nil
281
+ end
282
+ end
348
283
  end
349
284
  end
350
285
  end
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/query/context"
2
3
  module GraphQL
3
4
  class Query
4
5
  # This object can be `ctx` in places where there is no query
5
- class NullContext
6
+ class NullContext < Context
7
+ include Singleton
8
+
6
9
  class NullQuery
7
10
  def after_lazy(value)
8
11
  yield(value)
@@ -27,16 +30,6 @@ module GraphQL
27
30
  def interpreter?
28
31
  true
29
32
  end
30
-
31
- class << self
32
- extend Forwardable
33
-
34
- def instance
35
- @instance ||= self.new
36
- end
37
-
38
- def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
39
- end
40
33
  end
41
34
  end
42
35
  end
@@ -14,7 +14,7 @@ module GraphQL
14
14
  #
15
15
  # @api private
16
16
  class ValidationPipeline
17
- attr_reader :max_depth, :max_complexity
17
+ attr_reader :max_depth, :max_complexity, :validate_timeout_remaining
18
18
 
19
19
  def initialize(query:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
20
20
  @validation_errors = []
@@ -71,7 +71,7 @@ module GraphQL
71
71
  validator = @query.static_validator || @schema.static_validator
72
72
  validation_result = validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
73
73
  @validation_errors.concat(validation_result[:errors])
74
-
74
+ @validate_timeout_remaining = validation_result[:remaining_timeout]
75
75
  if @validation_errors.empty?
76
76
  @validation_errors.concat(@query.variables.errors)
77
77
  end
@@ -100,10 +100,10 @@ module GraphQL
100
100
  # Depending on the analysis engine, we must use different analyzers
101
101
  # remove this once everything has switched over to AST analyzers
102
102
  if max_depth
103
- qa << GraphQL::Analysis::AST::MaxQueryDepth
103
+ qa << GraphQL::Analysis::MaxQueryDepth
104
104
  end
105
105
  if max_complexity
106
- qa << GraphQL::Analysis::AST::MaxQueryComplexity
106
+ qa << GraphQL::Analysis::MaxQueryComplexity
107
107
  end
108
108
  qa
109
109
  else
@@ -26,7 +26,7 @@ module GraphQL
26
26
  # - Then, fall back to the default value from the query string
27
27
  # If it's still nil, raise an error if it's required.
28
28
  variable_type = schema.type_from_ast(ast_variable.type, context: ctx)
29
- if variable_type.nil?
29
+ if variable_type.nil? || !variable_type.unwrap.kind.input?
30
30
  # Pass -- it will get handled by a validator
31
31
  else
32
32
  variable_name = ast_variable.name
@@ -80,12 +80,12 @@ module GraphQL
80
80
  else
81
81
  val
82
82
  end
83
- end
83
+ end
84
84
 
85
85
  def add_max_errors_reached_message
86
86
  message = "Too many errors processing variables, max validation error limit reached. Execution aborted"
87
87
  validation_result = GraphQL::Query::InputValidationResult.from_problem(message)
88
- errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
88
+ errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
89
89
  end
90
90
  end
91
91
  end
data/lib/graphql/query.rb CHANGED
@@ -95,16 +95,11 @@ module GraphQL
95
95
  # @param root_value [Object] the object used to resolve fields on the root type
96
96
  # @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
97
97
  # @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
98
- # @param except [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns truthy
99
- # @param only [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns false
100
- def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
98
+ def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil)
101
99
  # Even if `variables: nil` is passed, use an empty hash for simpler logic
102
100
  variables ||= {}
103
101
  @schema = schema
104
- if only || except
105
- merge_filters(except: except, only: only)
106
- end
107
- @context = schema.context_class.new(query: self, object: root_value, values: context)
102
+ @context = schema.context_class.new(query: self, values: context)
108
103
  @warden = warden
109
104
  @subscription_topic = subscription_topic
110
105
  @root_value = root_value
@@ -120,8 +115,6 @@ module GraphQL
120
115
  if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
121
116
  context_tracers += [GraphQL::Backtrace::Tracer]
122
117
  @tracers << GraphQL::Backtrace::Tracer
123
- elsif !(current_trace.class <= GraphQL::Backtrace::Trace)
124
- raise "Invariant: `backtrace: true` should have provided a trace class with Backtrace mixed in, but it didnt. (Found: #{current_trace.class.ancestors}). This is a bug in GraphQL-Ruby, please report it on GitHub."
125
118
  end
126
119
  end
127
120
 
@@ -129,7 +122,6 @@ module GraphQL
129
122
  raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
130
123
  end
131
124
 
132
-
133
125
  @analysis_errors = []
134
126
  if variables.is_a?(String)
135
127
  raise ArgumentError, "Query variables should be a Hash, not a String. Try JSON.parse to prepare variables."
@@ -168,6 +160,14 @@ module GraphQL
168
160
 
169
161
  @result_values = nil
170
162
  @executed = false
163
+
164
+ @logger = if context && context[:logger] == false
165
+ Logger.new(IO::NULL)
166
+ elsif context && (l = context[:logger])
167
+ l
168
+ else
169
+ schema.default_logger
170
+ end
171
171
  end
172
172
 
173
173
  # If a document was provided to `GraphQL::Schema#execute` instead of the raw query string, we will need to get it from the document
@@ -222,7 +222,7 @@ module GraphQL
222
222
  end
223
223
 
224
224
  # Get the result for this query, executing it once
225
- # @return [Hash] A GraphQL response, with `"data"` and/or `"errors"` keys
225
+ # @return [GraphQL::Query::Result] A Hash-like GraphQL response, with `"data"` and/or `"errors"` keys
226
226
  def result
227
227
  if !@executed
228
228
  Execution::Interpreter.run_all(@schema, [self], context: @context)
@@ -304,7 +304,7 @@ module GraphQL
304
304
 
305
305
  # @return [String] An opaque hash for identifying this query's given query string and selected operation
306
306
  def operation_fingerprint
307
- @operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string)}"
307
+ @operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string || "")}"
308
308
  end
309
309
 
310
310
  # @return [String] An opaque hash for identifying this query's given a variable values (not including defaults)
@@ -317,7 +317,7 @@ module GraphQL
317
317
  end
318
318
 
319
319
  def_delegators :validation_pipeline, :validation_errors,
320
- :analyzers, :ast_analyzers, :max_depth, :max_complexity
320
+ :analyzers, :ast_analyzers, :max_depth, :max_complexity, :validate_timeout_remaining
321
321
 
322
322
  attr_accessor :analysis_errors
323
323
  def valid?
@@ -354,17 +354,6 @@ module GraphQL
354
354
  with_prepared_ast { @query }
355
355
  end
356
356
 
357
- # @return [void]
358
- def merge_filters(only: nil, except: nil)
359
- if @prepared_ast
360
- raise "Can't add filters after preparing the query"
361
- else
362
- @filter ||= @schema.default_filter
363
- @filter = @filter.merge(only: only, except: except)
364
- end
365
- nil
366
- end
367
-
368
357
  def subscription?
369
358
  with_prepared_ast { @subscription }
370
359
  end
@@ -386,6 +375,8 @@ module GraphQL
386
375
  end
387
376
  end
388
377
 
378
+ attr_reader :logger
379
+
389
380
  private
390
381
 
391
382
  def find_operation(operations, operation_name)
@@ -400,11 +391,11 @@ module GraphQL
400
391
 
401
392
  def prepare_ast
402
393
  @prepared_ast = true
403
- @warden ||= @schema.warden_class.new(@filter, schema: @schema, context: @context)
394
+ @warden ||= @schema.warden_class.new(schema: @schema, context: @context)
404
395
  parse_error = nil
405
396
  @document ||= begin
406
397
  if query_string
407
- GraphQL.parse(query_string, trace: self.current_trace)
398
+ GraphQL.parse(query_string, trace: self.current_trace, max_tokens: @schema.max_query_string_tokens)
408
399
  end
409
400
  rescue GraphQL::ParseError => err
410
401
  parse_error = err
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module GraphQL
3
4
  class Railtie < Rails::Railtie
4
- config.before_configuration do
5
- # Bootsnap compile cache has similar expiration properties,
6
- # so we assume that if the user has bootsnap setup it's ok
7
- # to piggy back on it.
8
- if ::Object.const_defined?("Bootsnap::CompileCache::ISeq") && Bootsnap::CompileCache::ISeq.cache_dir
9
- Language::Parser.cache ||= Language::Cache.new(Pathname.new(Bootsnap::CompileCache::ISeq.cache_dir).join('graphql'))
5
+ config.graphql = ActiveSupport::OrderedOptions.new
6
+ config.graphql.parser_cache = false
7
+
8
+ initializer("graphql.cache") do |app|
9
+ if config.graphql.parser_cache
10
+ Language::Parser.cache ||= Language::Cache.new(
11
+ app.root.join("tmp/cache/graphql")
12
+ )
10
13
  end
11
14
  end
12
15
  end
@@ -9,8 +9,7 @@ module GraphQL
9
9
  # By default, schemas are looked up by name as constants using `schema_name:`.
10
10
  # You can provide a `load_schema` function to return your schema another way.
11
11
  #
12
- # `load_context:`, `only:` and `except:` are supported so that
13
- # you can keep an eye on how filters affect your schema.
12
+ # Use `load_context:` and `visible?` to dump schemas under certain visibility constraints.
14
13
  #
15
14
  # @example Dump a Schema to .graphql + .json files
16
15
  # require "graphql/rake_task"
@@ -36,8 +35,6 @@ module GraphQL
36
35
  schema_name: nil,
37
36
  load_schema: ->(task) { Object.const_get(task.schema_name) },
38
37
  load_context: ->(task) { {} },
39
- only: nil,
40
- except: nil,
41
38
  directory: ".",
42
39
  idl_outfile: "schema.graphql",
43
40
  json_outfile: "schema.json",
@@ -68,12 +65,6 @@ module GraphQL
68
65
  # @return [<#call(task)>] A callable for loading the query context
69
66
  attr_accessor :load_context
70
67
 
71
- # @return [<#call(member, ctx)>, nil] A filter for this task
72
- attr_accessor :only
73
-
74
- # @return [<#call(member, ctx)>, nil] A filter for this task
75
- attr_accessor :except
76
-
77
68
  # @return [String] target for IDL task
78
69
  attr_accessor :idl_outfile
79
70
 
@@ -117,10 +108,10 @@ module GraphQL
117
108
  include_is_repeatable: include_is_repeatable,
118
109
  include_specified_by_url: include_specified_by_url,
119
110
  include_schema_description: include_schema_description,
120
- only: @only, except: @except, context: context
111
+ context: context
121
112
  )
122
113
  when :to_definition
123
- schema.to_definition(only: @only, except: @except, context: context)
114
+ schema.to_definition(context: context)
124
115
  else
125
116
  raise ArgumentError, "Unexpected schema dump method: #{method_name.inspect}"
126
117
  end
@@ -9,7 +9,7 @@ module GraphQL
9
9
 
10
10
  # Return the source of `send_node`, but without the keyword argument represented by `pair_node`
11
11
  def source_without_keyword_argument(send_node, pair_node)
12
- # work back to the preceeding comma
12
+ # work back to the preceding comma
13
13
  first_pos = pair_node.location.expression.begin_pos
14
14
  end_pos = pair_node.location.expression.end_pos
15
15
  node_source = send_node.source_range.source