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 +4 -4
- data/lib/generators/graphql/install_generator.rb +1 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
- data/lib/graphql.rb +10 -10
- data/lib/graphql/dataloader.rb +36 -5
- data/lib/graphql/execution/interpreter/runtime.rb +12 -20
- data/lib/graphql/pagination/connections.rb +1 -1
- data/lib/graphql/schema.rb +18 -18
- data/lib/graphql/schema/input_object.rb +2 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +3 -15
- data/lib/graphql/schema/object.rb +19 -5
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +17 -8
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
- data/lib/graphql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcd53f90295f4a4444841bee25b0329ba993ea2ae3d10bb9ba807f262b9354ca
|
4
|
+
data.tar.gz: af7807ae411d7f50252758b64c2248fc3c640cc2930c22c0740bae25d567e7ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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"
|
data/lib/graphql/dataloader.rb
CHANGED
@@ -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 =
|
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
|
-
|
47
|
-
|
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 =
|
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 =
|
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
|
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
|
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
|
-
|
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
|
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
|
639
|
-
|
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
|
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],
|
data/lib/graphql/schema.rb
CHANGED
@@ -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 :
|
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
|
-
|
117
|
-
@mutation.visible?(context)
|
118
|
-
else
|
119
|
-
true
|
120
|
-
end
|
116
|
+
true
|
121
117
|
end
|
122
118
|
|
123
119
|
def accessible?(context)
|
124
|
-
|
125
|
-
@mutation.accessible?(context)
|
126
|
-
else
|
127
|
-
true
|
128
|
-
end
|
120
|
+
true
|
129
121
|
end
|
130
122
|
|
131
123
|
def authorized?(object, context)
|
132
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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|
|
@@ -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.
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
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|
|
data/lib/graphql/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2021-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|