graphql 1.12.16 → 1.12.17
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/graphql/dataloader/source.rb +18 -0
- data/lib/graphql/dataloader.rb +26 -16
- data/lib/graphql/define/instance_definable.rb +1 -1
- data/lib/graphql/execution/interpreter/runtime.rb +10 -6
- data/lib/graphql/introspection/input_value_type.rb +6 -0
- data/lib/graphql/query.rb +4 -0
- data/lib/graphql/schema/argument.rb +16 -2
- data/lib/graphql/schema/input_object.rb +4 -4
- data/lib/graphql/schema/resolver.rb +4 -2
- data/lib/graphql/schema/subscription.rb +2 -4
- data/lib/graphql/schema/validator/numericality_validator.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +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: 6c9089e4578454f473996553a4771e4086e51b2b2db17fc31a579ab28019bd39
|
4
|
+
data.tar.gz: f45a70c81394f35c86d1610491f106e39899bc2c927a6a6d13e9e6533bc3bc85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7231b5e00a336439d15d469a383cd7e211e305961d4a4b431e8a97f5e483819bbd87de3d7cfffc9b6677b8175f700e012cd9ee4a0c92fa47005455a14893d3c
|
7
|
+
data.tar.gz: 98495c2b24d65ef90d7f5e1036956349ea79d03ea192de6ed06e517657f49b4e0e9c748c8a28d54aac24e96b42f52eea5d4cbfbca801a4389b1515804296831a
|
@@ -89,6 +89,24 @@ module GraphQL
|
|
89
89
|
nil
|
90
90
|
end
|
91
91
|
|
92
|
+
# These arguments are given to `dataloader.with(source_class, ...)`. The object
|
93
|
+
# returned from this method is used to de-duplicate batch loads under the hood
|
94
|
+
# by using it as a Hash key.
|
95
|
+
#
|
96
|
+
# By default, the arguments are all put in an Array. To customize how this source's
|
97
|
+
# batches are merged, override this method to return something else.
|
98
|
+
#
|
99
|
+
# For example, if you pass `ActiveRecord::Relation`s to `.with(...)`, you could override
|
100
|
+
# this method to call `.to_sql` on them, thus merging `.load(...)` calls when they apply
|
101
|
+
# to equivalent relations.
|
102
|
+
#
|
103
|
+
# @param batch_args [Array<Object>]
|
104
|
+
# @param batch_kwargs [Hash]
|
105
|
+
# @return [Object]
|
106
|
+
def self.batch_key_for(*batch_args, **batch_kwargs)
|
107
|
+
[*batch_args, **batch_kwargs]
|
108
|
+
end
|
109
|
+
|
92
110
|
private
|
93
111
|
|
94
112
|
# Reads and returns the result for the key from the internal cache, or raises an error if the result was an error
|
data/lib/graphql/dataloader.rb
CHANGED
@@ -27,18 +27,20 @@ module GraphQL
|
|
27
27
|
schema.dataloader_class = self
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
source.setup(self)
|
39
|
-
h2[batch_parameters] = source
|
40
|
-
}
|
30
|
+
# Call the block with a Dataloader instance,
|
31
|
+
# then run all enqueued jobs and return the result of the block.
|
32
|
+
def self.with_dataloading(&block)
|
33
|
+
dataloader = self.new
|
34
|
+
result = nil
|
35
|
+
dataloader.append_job {
|
36
|
+
result = block.call(dataloader)
|
41
37
|
}
|
38
|
+
dataloader.run
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize
|
43
|
+
@source_cache = Hash.new { |h, k| h[k] = {} }
|
42
44
|
@pending_jobs = []
|
43
45
|
end
|
44
46
|
|
@@ -49,16 +51,24 @@ module GraphQL
|
|
49
51
|
# @return [GraphQL::Dataloader::Source] An instance of {source_class}, initialized with `self, *batch_parameters`,
|
50
52
|
# and cached for the lifetime of this {Multiplex}.
|
51
53
|
if RUBY_VERSION < "3"
|
52
|
-
def with(source_class, *
|
53
|
-
|
54
|
+
def with(source_class, *batch_args)
|
55
|
+
batch_key = source_class.batch_key_for(*batch_args)
|
56
|
+
@source_cache[source_class][batch_key] ||= begin
|
57
|
+
source = source_class.new(*batch_args)
|
58
|
+
source.setup(self)
|
59
|
+
source
|
60
|
+
end
|
54
61
|
end
|
55
62
|
else
|
56
63
|
def with(source_class, *batch_args, **batch_kwargs)
|
57
|
-
|
58
|
-
@source_cache[source_class][
|
64
|
+
batch_key = source_class.batch_key_for(*batch_args, **batch_kwargs)
|
65
|
+
@source_cache[source_class][batch_key] ||= begin
|
66
|
+
source = source_class.new(*batch_args, **batch_kwargs)
|
67
|
+
source.setup(self)
|
68
|
+
source
|
69
|
+
end
|
59
70
|
end
|
60
71
|
end
|
61
|
-
|
62
72
|
# Tell the dataloader that this fiber is waiting for data.
|
63
73
|
#
|
64
74
|
# Dataloader will resume the fiber after the requested data has been loaded (by another Fiber).
|
@@ -76,7 +76,7 @@ ERR
|
|
76
76
|
# Apply definition from `define(...)` kwargs
|
77
77
|
defn.define_keywords.each do |keyword, value|
|
78
78
|
# Don't splat string hashes, which blows up on Rubies before 2.7
|
79
|
-
if value.is_a?(Hash) && value.each_key.all? { |k| k.is_a?(Symbol) }
|
79
|
+
if value.is_a?(Hash) && !value.empty? && value.each_key.all? { |k| k.is_a?(Symbol) }
|
80
80
|
defn_proxy.public_send(keyword, **value)
|
81
81
|
else
|
82
82
|
defn_proxy.public_send(keyword, value)
|
@@ -236,6 +236,7 @@ module GraphQL
|
|
236
236
|
selections,
|
237
237
|
selection_response,
|
238
238
|
final_response,
|
239
|
+
nil,
|
239
240
|
)
|
240
241
|
end
|
241
242
|
}
|
@@ -347,7 +348,7 @@ module GraphQL
|
|
347
348
|
NO_ARGS = {}.freeze
|
348
349
|
|
349
350
|
# @return [void]
|
350
|
-
def evaluate_selections(path, scoped_context, owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result) # rubocop:disable Metrics/ParameterLists
|
351
|
+
def evaluate_selections(path, scoped_context, owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result, parent_object) # rubocop:disable Metrics/ParameterLists
|
351
352
|
set_all_interpreter_context(owner_object, nil, nil, path)
|
352
353
|
|
353
354
|
finished_jobs = 0
|
@@ -355,7 +356,7 @@ module GraphQL
|
|
355
356
|
gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
|
356
357
|
@dataloader.append_job {
|
357
358
|
evaluate_selection(
|
358
|
-
path, result_name, field_ast_nodes_or_ast_node, scoped_context, owner_object, owner_type, is_eager_selection, selections_result
|
359
|
+
path, result_name, field_ast_nodes_or_ast_node, scoped_context, owner_object, owner_type, is_eager_selection, selections_result, parent_object
|
359
360
|
)
|
360
361
|
finished_jobs += 1
|
361
362
|
if target_result && finished_jobs == enqueued_jobs
|
@@ -370,7 +371,7 @@ module GraphQL
|
|
370
371
|
attr_reader :progress_path
|
371
372
|
|
372
373
|
# @return [void]
|
373
|
-
def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, scoped_context, owner_object, owner_type, is_eager_field, selections_result) # rubocop:disable Metrics/ParameterLists
|
374
|
+
def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, scoped_context, owner_object, owner_type, is_eager_field, selections_result, parent_object) # rubocop:disable Metrics/ParameterLists
|
374
375
|
return if dead_result?(selections_result)
|
375
376
|
# As a performance optimization, the hash key will be a `Node` if
|
376
377
|
# there's only one selection of the field. But if there are multiple
|
@@ -421,16 +422,16 @@ module GraphQL
|
|
421
422
|
total_args_count = field_defn.arguments.size
|
422
423
|
if total_args_count == 0
|
423
424
|
kwarg_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
424
|
-
evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result)
|
425
|
+
evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
|
425
426
|
else
|
426
427
|
# TODO remove all arguments(...) usages?
|
427
428
|
@query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
|
428
|
-
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result)
|
429
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
|
429
430
|
end
|
430
431
|
end
|
431
432
|
end
|
432
433
|
|
433
|
-
def evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
|
434
|
+
def evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
|
434
435
|
context.scoped_context = scoped_context
|
435
436
|
return_type = field_defn.type
|
436
437
|
after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
|
@@ -472,6 +473,8 @@ module GraphQL
|
|
472
473
|
# This is used by `__typename` in order to support the legacy runtime,
|
473
474
|
# but it has no use here (and it's always `nil`).
|
474
475
|
# Stop adding it here to avoid the overhead of `.merge_extras` below.
|
476
|
+
when :parent
|
477
|
+
extra_args[:parent] = parent_object
|
475
478
|
else
|
476
479
|
extra_args[extra] = field_defn.fetch_extra(extra, context)
|
477
480
|
end
|
@@ -733,6 +736,7 @@ module GraphQL
|
|
733
736
|
selections,
|
734
737
|
this_result,
|
735
738
|
final_result,
|
739
|
+
owner_object.object,
|
736
740
|
)
|
737
741
|
this_result
|
738
742
|
end
|
@@ -23,6 +23,12 @@ module GraphQL
|
|
23
23
|
if value.nil?
|
24
24
|
'null'
|
25
25
|
else
|
26
|
+
if (@object.type.kind.list? || (@object.type.kind.non_null? && @object.type.of_type.kind.list?)) && !value.respond_to?(:map)
|
27
|
+
# This is a bit odd -- we expect the default value to be an application-style value, so we use coerce result below.
|
28
|
+
# But coerce_result doesn't wrap single-item lists, which are valid inputs to list types.
|
29
|
+
# So, apply that wrapper here if needed.
|
30
|
+
value = [value]
|
31
|
+
end
|
26
32
|
coerced_default_value = @object.type.coerce_result(value, @context)
|
27
33
|
serialize_default_value(coerced_default_value, @object.type)
|
28
34
|
end
|
data/lib/graphql/query.rb
CHANGED
@@ -117,6 +117,10 @@ module GraphQL
|
|
117
117
|
raise ArgumentError, "Query should only be provided a query string or a document, not both."
|
118
118
|
end
|
119
119
|
|
120
|
+
if @query_string && !@query_string.is_a?(String)
|
121
|
+
raise ArgumentError, "Query string argument should be a String, got #{@query_string.class.name} instead."
|
122
|
+
end
|
123
|
+
|
120
124
|
# A two-layer cache of type resolution:
|
121
125
|
# { abstract_type => { value => resolved_type } }
|
122
126
|
@resolved_types_cache = Hash.new do |h1, k1|
|
@@ -151,7 +151,7 @@ module GraphQL
|
|
151
151
|
input_obj_arg = input_obj_arg.type_class
|
152
152
|
# TODO: this skips input objects whose values were alread replaced with application objects.
|
153
153
|
# See: https://github.com/rmosolgo/graphql-ruby/issues/2633
|
154
|
-
if value.
|
154
|
+
if value.is_a?(InputObject) && value.key?(input_obj_arg.keyword) && !input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
|
155
155
|
return false
|
156
156
|
end
|
157
157
|
end
|
@@ -298,7 +298,21 @@ module GraphQL
|
|
298
298
|
# @api private
|
299
299
|
def validate_default_value
|
300
300
|
coerced_default_value = begin
|
301
|
-
type
|
301
|
+
# This is weird, but we should accept single-item default values for list-type arguments.
|
302
|
+
# If we used `coerce_isolated_input` below, it would do this for us, but it's not really
|
303
|
+
# the right thing here because we expect default values in application format (Ruby values)
|
304
|
+
# not GraphQL format (scalar values).
|
305
|
+
#
|
306
|
+
# But I don't think Schema::List#coerce_result should apply wrapping to single-item lists.
|
307
|
+
prepped_default_value = if default_value.nil?
|
308
|
+
nil
|
309
|
+
elsif (type.kind.list? || (type.kind.non_null? && type.of_type.list?)) && !default_value.respond_to?(:map)
|
310
|
+
[default_value]
|
311
|
+
else
|
312
|
+
default_value
|
313
|
+
end
|
314
|
+
|
315
|
+
type.coerce_isolated_result(prepped_default_value) unless prepped_default_value.nil?
|
302
316
|
rescue GraphQL::Schema::Enum::UnresolvedValueError
|
303
317
|
# It raises this, which is helpful at runtime, but not here...
|
304
318
|
default_value
|
@@ -71,11 +71,11 @@ module GraphQL
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def prepare
|
74
|
-
if context
|
75
|
-
context.schema.after_any_lazies(@maybe_lazies) do
|
76
|
-
object = context[:current_object]
|
74
|
+
if @context
|
75
|
+
@context.schema.after_any_lazies(@maybe_lazies) do
|
76
|
+
object = @context[:current_object]
|
77
77
|
# Pass this object's class with `as` so that messages are rendered correctly from inherited validators
|
78
|
-
Schema::Validator.validate!(self.class.validators, object, context, @ruby_style_hash, as: self.class)
|
78
|
+
Schema::Validator.validate!(self.class.validators, object, @context, @ruby_style_hash, as: self.class)
|
79
79
|
self
|
80
80
|
end
|
81
81
|
else
|
@@ -218,8 +218,10 @@ module GraphQL
|
|
218
218
|
own_extras + (superclass.respond_to?(:extras) ? superclass.extras : [])
|
219
219
|
end
|
220
220
|
|
221
|
-
#
|
222
|
-
#
|
221
|
+
# If `true` (default), then the return type for this resolver will be nullable.
|
222
|
+
# If `false`, then the return type is non-null.
|
223
|
+
#
|
224
|
+
# @see #type which sets the return type of this field and accepts a `null:` option
|
223
225
|
# @param allow_null [Boolean] Whether or not the response can be null
|
224
226
|
def null(allow_null = nil)
|
225
227
|
if !allow_null.nil?
|
@@ -58,11 +58,9 @@ module GraphQL
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
#
|
61
|
+
# The default implementation returns nothing on subscribe.
|
62
62
|
# Override it to return an object or
|
63
|
-
# `:no_response` to return nothing.
|
64
|
-
#
|
65
|
-
# The default is `:no_response`.
|
63
|
+
# `:no_response` to (explicitly) return nothing.
|
66
64
|
def subscribe(args = {})
|
67
65
|
:no_response
|
68
66
|
end
|
@@ -24,12 +24,13 @@ module GraphQL
|
|
24
24
|
# @param other_than [Integer]
|
25
25
|
# @param odd [Boolean]
|
26
26
|
# @param even [Boolean]
|
27
|
+
# @param within [Range]
|
27
28
|
# @param message [String] used for all validation failures
|
28
29
|
def initialize(
|
29
30
|
greater_than: nil, greater_than_or_equal_to: nil,
|
30
31
|
less_than: nil, less_than_or_equal_to: nil,
|
31
32
|
equal_to: nil, other_than: nil,
|
32
|
-
odd: nil, even: nil,
|
33
|
+
odd: nil, even: nil, within: nil,
|
33
34
|
message: "%{validated} must be %{comparison} %{target}",
|
34
35
|
**default_options
|
35
36
|
)
|
@@ -42,6 +43,7 @@ module GraphQL
|
|
42
43
|
@other_than = other_than
|
43
44
|
@odd = odd
|
44
45
|
@even = even
|
46
|
+
@within = within
|
45
47
|
@message = message
|
46
48
|
super(**default_options)
|
47
49
|
end
|
@@ -63,6 +65,8 @@ module GraphQL
|
|
63
65
|
(partial_format(@message, { comparison: "even", target: "" })).strip
|
64
66
|
elsif @odd && !value.odd?
|
65
67
|
(partial_format(@message, { comparison: "odd", target: "" })).strip
|
68
|
+
elsif @within && !@within.include?(value)
|
69
|
+
partial_format(@message, { comparison: "within", target: @within })
|
66
70
|
end
|
67
71
|
end
|
68
72
|
end
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -44,6 +44,6 @@ I also sell [GraphQL::Pro](https://graphql.pro) which provides several features
|
|
44
44
|
|
45
45
|
## Getting Involved
|
46
46
|
|
47
|
-
- __Say hi & ask questions__ in the
|
47
|
+
- __Say hi & ask questions__ in the #graphql-ruby channel on [Discord](https://discord.com/invite/xud7bH9) or [on Twitter](https://twitter.com/rmosolgo)!
|
48
48
|
- __Report bugs__ by posting a description, full stack trace, and all relevant code in a [GitHub issue](https://github.com/rmosolgo/graphql-ruby/issues).
|
49
49
|
- __Start hacking__ with the [Development guide](https://graphql-ruby.org/development).
|
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.17
|
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-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|