graphql 1.12.8 → 1.12.9

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10ea46e2edf136b445de343ee1a58dd98b0a6c5800ef31923d7d184198ed58fd
4
- data.tar.gz: f2f6dff0bf020bfef04769deb3fd548317121f0e636d7a47a94baea862f341ac
3
+ metadata.gz: bcd53f90295f4a4444841bee25b0329ba993ea2ae3d10bb9ba807f262b9354ca
4
+ data.tar.gz: af7807ae411d7f50252758b64c2248fc3c640cc2930c22c0740bae25d567e7ef
5
5
  SHA512:
6
- metadata.gz: a79fde55cedcd391b7dfe7c141e22c51563aeefceb0fda494dd50f4281fefb0104f8663e688395268c95361ee10e01c7bfb69250368441ec8b8c9ad0d00ac279
7
- data.tar.gz: 49a7b0f5cdf9d3a64ff05b0898c7ef93c6cdfd210baf93affa25afe3f3d7b59187fe3e7727f467af9411a085c5f6e8e281fafd27352fe97128f98bd82ffde330
6
+ metadata.gz: 770c7bde4c17619f645d77829bb9ca78bed5f944a7609a31095d9e8e859adbf0728988a640ad98a3a10fbccc73f658a0906296d1d6bed5f0f6d77b53a9bf9c79
7
+ data.tar.gz: 9fee4b7cb3e63c07a702462c1b6ebc0a0bd2d1342a4d22803839b63a03d8a910ebd6189a748695ba75e2732e1af30e9a6b9587d72be602eee6b1db43822bb779
@@ -122,7 +122,7 @@ module Graphql
122
122
  if options.api?
123
123
  say("Skipped graphiql, as this rails project is API only")
124
124
  say(" You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app")
125
- elsif !options[:skip_graphiql]
125
+ elsif !options[:skip_graphiql] && !File.read(Rails.root.join("Gemfile")).include?("graphiql-rails")
126
126
  gem("graphiql-rails", group: :development)
127
127
 
128
128
  # This is a little cheat just to get cleaner shell output:
@@ -15,9 +15,9 @@ class GraphqlController < ApplicationController
15
15
  }
16
16
  result = <%= schema_name %>.execute(query, variables: variables, context: context, operation_name: operation_name)
17
17
  render json: result
18
- rescue => e
18
+ rescue StandardError => e
19
19
  raise e unless Rails.env.development?
20
- handle_error_in_development e
20
+ handle_error_in_development(e)
21
21
  end
22
22
 
23
23
  private
data/lib/graphql.rb CHANGED
@@ -81,10 +81,19 @@ end
81
81
  # Order matters for these:
82
82
 
83
83
  require "graphql/execution_error"
84
+ require "graphql/runtime_type_error"
85
+ require "graphql/unresolved_type_error"
86
+ require "graphql/invalid_null_error"
87
+ require "graphql/analysis_error"
88
+ require "graphql/coercion_error"
89
+ require "graphql/invalid_name_error"
90
+ require "graphql/integer_decoding_error"
91
+ require "graphql/integer_encoding_error"
92
+ require "graphql/string_encoding_error"
93
+
84
94
  require "graphql/define"
85
95
  require "graphql/base_type"
86
96
  require "graphql/object_type"
87
-
88
97
  require "graphql/enum_type"
89
98
  require "graphql/input_object_type"
90
99
  require "graphql/interface_type"
@@ -109,9 +118,6 @@ require "graphql/analysis"
109
118
  require "graphql/tracing"
110
119
  require "graphql/dig"
111
120
  require "graphql/execution"
112
- require "graphql/runtime_type_error"
113
- require "graphql/unresolved_type_error"
114
- require "graphql/invalid_null_error"
115
121
  require "graphql/pagination"
116
122
  require "graphql/schema"
117
123
  require "graphql/query"
@@ -133,12 +139,6 @@ require "graphql/static_validation"
133
139
  require "graphql/dataloader"
134
140
  require "graphql/introspection"
135
141
 
136
- require "graphql/analysis_error"
137
- require "graphql/coercion_error"
138
- require "graphql/invalid_name_error"
139
- require "graphql/integer_decoding_error"
140
- require "graphql/integer_encoding_error"
141
- require "graphql/string_encoding_error"
142
142
  require "graphql/version"
143
143
  require "graphql/compatibility"
144
144
  require "graphql/function"
@@ -29,7 +29,12 @@ module GraphQL
29
29
 
30
30
  def initialize
31
31
  @source_cache = Hash.new { |h, source_class| h[source_class] = Hash.new { |h2, batch_parameters|
32
- source = source_class.new(*batch_parameters)
32
+ source = if RUBY_VERSION < "3"
33
+ source_class.new(*batch_parameters)
34
+ else
35
+ batch_args, batch_kwargs = batch_parameters
36
+ source_class.new(*batch_args, **batch_kwargs)
37
+ end
33
38
  source.setup(self)
34
39
  h2[batch_parameters] = source
35
40
  }
@@ -43,8 +48,15 @@ module GraphQL
43
48
  # @param batch_parameters [Array<Object>]
44
49
  # @return [GraphQL::Dataloader::Source] An instance of {source_class}, initialized with `self, *batch_parameters`,
45
50
  # and cached for the lifetime of this {Multiplex}.
46
- def with(source_class, *batch_parameters)
47
- @source_cache[source_class][batch_parameters]
51
+ if RUBY_VERSION < "3"
52
+ def with(source_class, *batch_parameters)
53
+ @source_cache[source_class][batch_parameters]
54
+ end
55
+ else
56
+ def with(source_class, *batch_args, **batch_kwargs)
57
+ batch_parameters = [batch_args, batch_kwargs]
58
+ @source_cache[source_class][batch_parameters]
59
+ end
48
60
  end
49
61
 
50
62
  # Tell the dataloader that this fiber is waiting for data.
@@ -104,7 +116,7 @@ module GraphQL
104
116
  while @pending_jobs.any?
105
117
  # Create a Fiber to consume jobs until one of the jobs yields
106
118
  # or jobs run out
107
- f = Fiber.new {
119
+ f = spawn_fiber {
108
120
  while (job = @pending_jobs.shift)
109
121
  job.call
110
122
  end
@@ -191,7 +203,7 @@ module GraphQL
191
203
  #
192
204
  # This design could probably be improved by maintaining a `@pending_sources` queue which is shared by the fibers,
193
205
  # similar to `@pending_jobs`. That way, when a fiber is resumed, it would never pick up work that was finished by a different fiber.
194
- source_fiber = Fiber.new do
206
+ source_fiber = spawn_fiber do
195
207
  pending_sources.each(&:run_pending_keys)
196
208
  end
197
209
  end
@@ -204,5 +216,24 @@ module GraphQL
204
216
  rescue UncaughtThrowError => e
205
217
  throw e.tag, e.value
206
218
  end
219
+
220
+ # Copies the thread local vars into the fiber thread local vars. Many
221
+ # gems (such as RequestStore, MiniRacer, etc.) rely on thread local vars
222
+ # to keep track of execution context, and without this they do not
223
+ # behave as expected.
224
+ #
225
+ # @see https://github.com/rmosolgo/graphql-ruby/issues/3449
226
+ def spawn_fiber
227
+ fiber_locals = {}
228
+
229
+ Thread.current.keys.each do |fiber_var_key|
230
+ fiber_locals[fiber_var_key] = Thread.current[fiber_var_key]
231
+ end
232
+
233
+ Fiber.new do
234
+ fiber_locals.each { |k, v| Thread.current[k] = v }
235
+ yield
236
+ end
237
+ end
207
238
  end
208
239
  end
@@ -50,7 +50,7 @@ module GraphQL
50
50
  root_type = schema.root_type_for_operation(root_op_type)
51
51
  path = []
52
52
  set_all_interpreter_context(query.root_value, nil, nil, path)
53
- object_proxy = authorized_new(root_type, query.root_value, context, path)
53
+ object_proxy = authorized_new(root_type, query.root_value, context)
54
54
  object_proxy = schema.sync_lazy(object_proxy)
55
55
  if object_proxy.nil?
56
56
  # Root .authorized? returned false.
@@ -193,7 +193,7 @@ module GraphQL
193
193
  object = owner_object
194
194
 
195
195
  if is_introspection
196
- object = authorized_new(field_defn.owner, object, context, next_path)
196
+ object = authorized_new(field_defn.owner, object, context)
197
197
  end
198
198
 
199
199
  total_args_count = field_defn.arguments.size
@@ -246,11 +246,17 @@ module GraphQL
246
246
  # Use this flag to tell Interpreter::Arguments to add itself
247
247
  # to the keyword args hash _before_ freezing everything.
248
248
  extra_args[:argument_details] = :__arguments_add_self
249
+ when :irep_node
250
+ # This is used by `__typename` in order to support the legacy runtime,
251
+ # but it has no use here (and it's always `nil`).
252
+ # Stop adding it here to avoid the overhead of `.merge_extras` below.
249
253
  else
250
254
  extra_args[extra] = field_defn.fetch_extra(extra, context)
251
255
  end
252
256
  end
253
- resolved_arguments = resolved_arguments.merge_extras(extra_args)
257
+ if extra_args.any?
258
+ resolved_arguments = resolved_arguments.merge_extras(extra_args)
259
+ end
254
260
  resolved_arguments.keyword_arguments
255
261
  end
256
262
 
@@ -372,7 +378,7 @@ module GraphQL
372
378
  end
373
379
  when "OBJECT"
374
380
  object_proxy = begin
375
- authorized_new(current_type, value, context, path)
381
+ authorized_new(current_type, value, context)
376
382
  rescue GraphQL::ExecutionError => err
377
383
  err
378
384
  end
@@ -635,22 +641,8 @@ module GraphQL
635
641
  end
636
642
  end
637
643
 
638
- def authorized_new(type, value, context, path)
639
- trace_payload = { context: context, type: type, object: value, path: path }
640
-
641
- auth_val = context.query.trace("authorized", trace_payload) do
642
- type.authorized_new(value, context)
643
- end
644
-
645
- if context.schema.lazy?(auth_val)
646
- GraphQL::Execution::Lazy.new do
647
- context.query.trace("authorized_lazy", trace_payload) do
648
- context.schema.sync_lazy(auth_val)
649
- end
650
- end
651
- else
652
- auth_val
653
- end
644
+ def authorized_new(type, value, context)
645
+ type.authorized_new(value, context)
654
646
  end
655
647
  end
656
648
  end
@@ -79,7 +79,7 @@ module GraphQL
79
79
  context: context,
80
80
  parent: parent,
81
81
  field: field,
82
- max_page_size: field.max_page_size || context.schema.default_max_page_size,
82
+ max_page_size: field.has_max_page_size? ? field.max_page_size : context.schema.default_max_page_size,
83
83
  first: arguments[:first],
84
84
  after: arguments[:after],
85
85
  last: arguments[:last],
@@ -355,23 +355,6 @@ module GraphQL
355
355
  # For forwards-compatibility with Schema classes
356
356
  alias :graphql_definition :itself
357
357
 
358
- # Validate a query string according to this schema.
359
- # @param string_or_document [String, GraphQL::Language::Nodes::Document]
360
- # @return [Array<GraphQL::StaticValidation::Error >]
361
- def validate(string_or_document, rules: nil, context: nil)
362
- doc = if string_or_document.is_a?(String)
363
- GraphQL.parse(string_or_document)
364
- else
365
- string_or_document
366
- end
367
- query = GraphQL::Query.new(self, document: doc, context: context)
368
- validator_opts = { schema: self }
369
- rules && (validator_opts[:rules] = rules)
370
- validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
371
- res = validator.validate(query, timeout: validate_timeout)
372
- res[:errors]
373
- end
374
-
375
358
  def deprecated_define(**kwargs, &block)
376
359
  super
377
360
  ensure_defined
@@ -712,6 +695,7 @@ module GraphQL
712
695
  def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
713
696
  def_delegators :_schema_class, :directive
714
697
  def_delegators :_schema_class, :error_handler
698
+ def_delegators :_schema_class, :validate
715
699
 
716
700
 
717
701
  # Given this schema member, find the class-based definition object
@@ -861,7 +845,6 @@ module GraphQL
861
845
  def_delegators :graphql_definition,
862
846
  # Execution
863
847
  :execution_strategy_for_operation,
864
- :validate,
865
848
  # Configuration
866
849
  :metadata, :redefine,
867
850
  :id_from_object_proc, :object_from_id_proc,
@@ -1293,6 +1276,23 @@ module GraphQL
1293
1276
  end
1294
1277
  end
1295
1278
 
1279
+ # Validate a query string according to this schema.
1280
+ # @param string_or_document [String, GraphQL::Language::Nodes::Document]
1281
+ # @return [Array<GraphQL::StaticValidation::Error >]
1282
+ def validate(string_or_document, rules: nil, context: nil)
1283
+ doc = if string_or_document.is_a?(String)
1284
+ GraphQL.parse(string_or_document)
1285
+ else
1286
+ string_or_document
1287
+ end
1288
+ query = GraphQL::Query.new(self, document: doc, context: context)
1289
+ validator_opts = { schema: self }
1290
+ rules && (validator_opts[:rules] = rules)
1291
+ validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
1292
+ res = validator.validate(query, timeout: validate_timeout)
1293
+ res[:errors]
1294
+ end
1295
+
1296
1296
  attr_writer :max_complexity
1297
1297
 
1298
1298
  def max_complexity(max_complexity = nil)
@@ -226,8 +226,8 @@ module GraphQL
226
226
  # It's funny to think of a _result_ of an input object.
227
227
  # This is used for rendering the default value in introspection responses.
228
228
  def coerce_result(value, ctx)
229
- # Allow the application to provide values as :symbols, and convert them to the strings
230
- value = value.reduce({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
229
+ # Allow the application to provide values as :snake_symbols, and convert them to the camelStrings
230
+ value = value.reduce({}) { |memo, (k, v)| memo[Member::BuildType.camelize(k.to_s)] = v; memo }
231
231
 
232
232
  result = {}
233
233
 
@@ -113,27 +113,15 @@ module GraphQL
113
113
  end
114
114
 
115
115
  def visible?(context)
116
- if @mutation
117
- @mutation.visible?(context)
118
- else
119
- true
120
- end
116
+ true
121
117
  end
122
118
 
123
119
  def accessible?(context)
124
- if @mutation
125
- @mutation.accessible?(context)
126
- else
127
- true
128
- end
120
+ true
129
121
  end
130
122
 
131
123
  def authorized?(object, context)
132
- if @mutation
133
- @mutation.authorized?(object, context)
134
- else
135
- true
136
- end
124
+ true
137
125
  end
138
126
  end
139
127
  end
@@ -48,12 +48,26 @@ module GraphQL
48
48
  # @return [GraphQL::Schema::Object, GraphQL::Execution::Lazy]
49
49
  # @raise [GraphQL::UnauthorizedError] if the user-provided hook returns `false`
50
50
  def authorized_new(object, context)
51
- auth_val = context.query.with_error_handling do
52
- begin
53
- authorized?(object, context)
54
- rescue GraphQL::UnauthorizedError => err
55
- context.schema.unauthorized_object(err)
51
+ trace_payload = { context: context, type: self, object: object, path: context[:current_path] }
52
+
53
+ maybe_lazy_auth_val = context.query.trace("authorized", trace_payload) do
54
+ context.query.with_error_handling do
55
+ begin
56
+ authorized?(object, context)
57
+ rescue GraphQL::UnauthorizedError => err
58
+ context.schema.unauthorized_object(err)
59
+ end
60
+ end
61
+ end
62
+
63
+ auth_val = if context.schema.lazy?(maybe_lazy_auth_val)
64
+ GraphQL::Execution::Lazy.new do
65
+ context.query.trace("authorized_lazy", trace_payload) do
66
+ context.schema.sync_lazy(maybe_lazy_auth_val)
67
+ end
56
68
  end
69
+ else
70
+ maybe_lazy_auth_val
57
71
  end
58
72
 
59
73
  context.schema.after_lazy(auth_val) do |is_authorized|
@@ -4,7 +4,7 @@ module GraphQL
4
4
  module DirectivesAreDefined
5
5
  def initialize(*)
6
6
  super
7
- @directive_names = context.schema.directives.keys
7
+ @directive_names = context.warden.directives.map(&:graphql_name)
8
8
  end
9
9
 
10
10
  def on_directive(node, parent)
@@ -373,17 +373,26 @@ module GraphQL
373
373
  # In this context, `parents` represends the "self scope" of the field,
374
374
  # what types may be found at this point in the query.
375
375
  def mutually_exclusive?(parents1, parents2)
376
- parents1.each do |type1|
377
- parents2.each do |type2|
378
- # If the types we're comparing are both different object types,
379
- # they have to be mutually exclusive.
380
- if type1 != type2 && type1.kind.object? && type2.kind.object?
381
- return true
376
+ if parents1.empty? || parents2.empty?
377
+ false
378
+ elsif parents1.length == parents2.length
379
+ parents1.length.times.any? do |i|
380
+ type1 = parents1[i - 1]
381
+ type2 = parents2[i - 1]
382
+ if type1 == type2
383
+ # If the types we're comparing are the same type,
384
+ # then they aren't mutually exclusive
385
+ false
386
+ else
387
+ # Check if these two scopes have _any_ types in common.
388
+ possible_right_types = context.query.possible_types(type1)
389
+ possible_left_types = context.query.possible_types(type2)
390
+ (possible_right_types & possible_left_types).empty?
382
391
  end
383
392
  end
393
+ else
394
+ true
384
395
  end
385
-
386
- false
387
396
  end
388
397
  end
389
398
  end
@@ -34,12 +34,12 @@ module GraphQL
34
34
  # channel: self,
35
35
  # }
36
36
  #
37
- # result = MySchema.execute({
37
+ # result = MySchema.execute(
38
38
  # query: query,
39
39
  # context: context,
40
40
  # variables: variables,
41
41
  # operation_name: operation_name
42
- # })
42
+ # )
43
43
  #
44
44
  # payload = {
45
45
  # result: result.to_h,
@@ -146,14 +146,15 @@ module GraphQL
146
146
  def setup_stream(channel, initial_event)
147
147
  topic = initial_event.topic
148
148
  channel.stream_from(stream_event_name(initial_event), coder: @action_cable_coder) do |message|
149
- object = @serializer.load(message)
150
149
  events_by_fingerprint = @events[topic]
150
+ object = nil
151
151
  events_by_fingerprint.each do |_fingerprint, events|
152
152
  if events.any? && events.first == initial_event
153
153
  # The fingerprint has told us that this response should be shared by all subscribers,
154
154
  # so just run it once, then deliver the result to every subscriber
155
155
  first_event = events.first
156
156
  first_subscription_id = first_event.context.fetch(:subscription_id)
157
+ object ||= @serializer.load(message)
157
158
  result = execute_update(first_subscription_id, first_event, object)
158
159
  # Having calculated the result _once_, send the same payload to all subscribers
159
160
  events.each do |event|
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.12.8"
3
+ VERSION = "1.12.9"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.8
4
+ version: 1.12.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-12 00:00:00.000000000 Z
11
+ date: 2021-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips