graphql 2.5.3 → 2.5.5
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.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/query_complexity.rb +2 -2
- data/lib/graphql/dataloader/active_record_association_source.rb +15 -7
- data/lib/graphql/dataloader/active_record_source.rb +26 -5
- data/lib/graphql/dataloader/source.rb +16 -4
- data/lib/graphql/execution/interpreter.rb +0 -7
- data/lib/graphql/query/context.rb +1 -7
- data/lib/graphql/schema/input_object.rb +24 -21
- data/lib/graphql/schema/visibility.rb +1 -1
- data/lib/graphql/tracing/notifications_trace.rb +3 -1
- data/lib/graphql/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 170be4878ee16ebea26a272dde50923d35e624c87e1154b34de61a10f6a9fae0
|
4
|
+
data.tar.gz: 5ac223538670c8a24c2748e0819cab3b5e0627c14b4a4745559fdedfcd8440fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 272a8d48f0ec1d0ad1a79021dc103aede933d34a35829512bf0d46bcbcbc3bafe3b3484cbd38c26ba8193144f3a4024c1c69bd732c9e4cf472307fd15c1d1a33
|
7
|
+
data.tar.gz: b1a66e945b02251b72410c792a91ba5d28cbe82e3eba3891bd3a708382076c2da9e6cf1349c3b688a0f7f87ba06d9bb1b83d06e4c3282e47c0c9724d76cb187b
|
@@ -28,14 +28,14 @@ module GraphQL
|
|
28
28
|
end
|
29
29
|
when nil
|
30
30
|
subject.logger.warn <<~GRAPHQL
|
31
|
-
GraphQL-Ruby's complexity cost system is getting some "breaking fixes" in a future version. See the migration notes at https://graphql-ruby.org/api-
|
31
|
+
GraphQL-Ruby's complexity cost system is getting some "breaking fixes" in a future version. See the migration notes at https://graphql-ruby.org/api-doc/#{GraphQL::VERSION}/GraphQL/Schema.html#complexity_cost_calculation_mode_for-class_method
|
32
32
|
|
33
33
|
To opt into the future behavior, configure your schema (#{subject.schema.name ? subject.schema.name : subject.schema.ancestors}) with:
|
34
34
|
|
35
35
|
complexity_cost_calculation_mode(:future) # or `:legacy`, `:compare`
|
36
36
|
|
37
37
|
GRAPHQL
|
38
|
-
max_possible_complexity
|
38
|
+
max_possible_complexity(mode: :legacy)
|
39
39
|
else
|
40
40
|
raise ArgumentError, "Expected `:future`, `:legacy`, `:compare`, or `nil` from `#{query.schema}.complexity_cost_calculation_mode_for` but got: #{query.schema.complexity_cost_calculation_mode.inspect}"
|
41
41
|
end
|
@@ -12,6 +12,14 @@ module GraphQL
|
|
12
12
|
@scope = scope
|
13
13
|
end
|
14
14
|
|
15
|
+
def self.batch_key_for(association, scope = nil)
|
16
|
+
if scope
|
17
|
+
[association, scope.to_sql]
|
18
|
+
else
|
19
|
+
[association]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
15
23
|
def load(record)
|
16
24
|
if (assoc = record.association(@association)).loaded?
|
17
25
|
assoc.target
|
@@ -41,17 +49,17 @@ module GraphQL
|
|
41
49
|
::ActiveRecord::Associations::Preloader.new(records: records, associations: @association, available_records: available_records, scope: @scope).call
|
42
50
|
|
43
51
|
loaded_associated_records = records.map { |r| r.public_send(@association) }
|
44
|
-
records_by_model = {}
|
45
|
-
loaded_associated_records.each do |record|
|
46
|
-
if record
|
47
|
-
updates = records_by_model[record.class] ||= {}
|
48
|
-
updates[record.id] = record
|
49
|
-
end
|
50
|
-
end
|
51
52
|
|
52
53
|
if @scope.nil?
|
53
54
|
# Don't cache records loaded via scope because they might have reduced `SELECT`s
|
54
55
|
# Could check .select_values here?
|
56
|
+
records_by_model = {}
|
57
|
+
loaded_associated_records.flatten.each do |record|
|
58
|
+
if record
|
59
|
+
updates = records_by_model[record.class] ||= {}
|
60
|
+
updates[record.id] = record
|
61
|
+
end
|
62
|
+
end
|
55
63
|
records_by_model.each do |model_class, updates|
|
56
64
|
dataloader.with(RECORD_SOURCE_CLASS, model_class).merge(updates)
|
57
65
|
end
|
@@ -7,18 +7,39 @@ module GraphQL
|
|
7
7
|
def initialize(model_class, find_by: model_class.primary_key)
|
8
8
|
@model_class = model_class
|
9
9
|
@find_by = find_by
|
10
|
-
@
|
10
|
+
@find_by_many = find_by.is_a?(Array)
|
11
|
+
if @find_by_many
|
12
|
+
@type_for_column = @find_by.map { |fb| @model_class.type_for_attribute(fb) }
|
13
|
+
else
|
14
|
+
@type_for_column = @model_class.type_for_attribute(@find_by)
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
18
|
+
def result_key_for(requested_key)
|
19
|
+
normalize_fetch_key(requested_key)
|
20
|
+
end
|
21
|
+
|
22
|
+
def normalize_fetch_key(requested_key)
|
23
|
+
if @find_by_many
|
24
|
+
requested_key.each_with_index.map do |k, idx|
|
25
|
+
@type_for_column[idx].cast(k)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
@type_for_column.cast(requested_key)
|
29
|
+
end
|
16
30
|
end
|
17
31
|
|
18
32
|
def fetch(record_ids)
|
19
33
|
records = @model_class.where(@find_by => record_ids)
|
20
34
|
record_lookup = {}
|
21
|
-
|
35
|
+
if @find_by_many
|
36
|
+
records.each do |r|
|
37
|
+
key = @find_by.map { |fb| r.public_send(fb) }
|
38
|
+
record_lookup[key] = r
|
39
|
+
end
|
40
|
+
else
|
41
|
+
records.each { |r| record_lookup[r.public_send(@find_by)] = r }
|
42
|
+
end
|
22
43
|
record_ids.map { |id| record_lookup[id] }
|
23
44
|
end
|
24
45
|
end
|
@@ -21,7 +21,7 @@ module GraphQL
|
|
21
21
|
def request(value)
|
22
22
|
res_key = result_key_for(value)
|
23
23
|
if !@results.key?(res_key)
|
24
|
-
@pending[res_key] ||= value
|
24
|
+
@pending[res_key] ||= normalize_fetch_key(value)
|
25
25
|
end
|
26
26
|
Dataloader::Request.new(self, value)
|
27
27
|
end
|
@@ -35,12 +35,24 @@ module GraphQL
|
|
35
35
|
value
|
36
36
|
end
|
37
37
|
|
38
|
+
# Implement this method if varying values given to {load} (etc) should be consolidated
|
39
|
+
# or normalized before being handed off to your {fetch} implementation.
|
40
|
+
#
|
41
|
+
# This is different than {result_key_for} because _that_ method handles unification inside Dataloader's cache,
|
42
|
+
# but this method changes the value passed into {fetch}.
|
43
|
+
#
|
44
|
+
# @param value [Object] The value passed to {load}, {load_all}, {request}, or {request_all}
|
45
|
+
# @return [Object] The value given to {fetch}
|
46
|
+
def normalize_fetch_key(value)
|
47
|
+
value
|
48
|
+
end
|
49
|
+
|
38
50
|
# @return [Dataloader::Request] a pending request for a values from `keys`. Call `.load` on that object to wait for the results.
|
39
51
|
def request_all(values)
|
40
52
|
values.each do |v|
|
41
53
|
res_key = result_key_for(v)
|
42
54
|
if !@results.key?(res_key)
|
43
|
-
@pending[res_key] ||= v
|
55
|
+
@pending[res_key] ||= normalize_fetch_key(v)
|
44
56
|
end
|
45
57
|
end
|
46
58
|
Dataloader::RequestAll.new(self, values)
|
@@ -53,7 +65,7 @@ module GraphQL
|
|
53
65
|
if @results.key?(result_key)
|
54
66
|
result_for(result_key)
|
55
67
|
else
|
56
|
-
@pending[result_key] ||= value
|
68
|
+
@pending[result_key] ||= normalize_fetch_key(value)
|
57
69
|
sync([result_key])
|
58
70
|
result_for(result_key)
|
59
71
|
end
|
@@ -68,7 +80,7 @@ module GraphQL
|
|
68
80
|
k = result_key_for(v)
|
69
81
|
result_keys << k
|
70
82
|
if !@results.key?(k)
|
71
|
-
@pending[k] ||= v
|
83
|
+
@pending[k] ||= normalize_fetch_key(v)
|
72
84
|
pending_keys << k
|
73
85
|
end
|
74
86
|
}
|
@@ -93,13 +93,6 @@ module GraphQL
|
|
93
93
|
# Then, work through lazy results in a breadth-first way
|
94
94
|
multiplex.dataloader.append_job {
|
95
95
|
query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
|
96
|
-
queries = multiplex ? multiplex.queries : [query]
|
97
|
-
final_values = queries.map do |query|
|
98
|
-
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
99
|
-
# it might not be present if the query has an error
|
100
|
-
runtime ? runtime.final_result : nil
|
101
|
-
end
|
102
|
-
final_values.compact!
|
103
96
|
multiplex.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
|
104
97
|
Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
|
105
98
|
end
|
@@ -39,9 +39,6 @@ module GraphQL
|
|
39
39
|
# @return [GraphQL::Schema]
|
40
40
|
attr_reader :schema
|
41
41
|
|
42
|
-
# @return [Array<String, Integer>] The current position in the result
|
43
|
-
attr_reader :path
|
44
|
-
|
45
42
|
# Make a new context which delegates key lookup to `values`
|
46
43
|
# @param query [GraphQL::Query] the query who owns this context
|
47
44
|
# @param values [Hash] A hash of arbitrary values which will be accessible at query-time
|
@@ -53,9 +50,6 @@ module GraphQL
|
|
53
50
|
@storage = Hash.new { |h, k| h[k] = {} }
|
54
51
|
@storage[nil] = @provided_values
|
55
52
|
@errors = []
|
56
|
-
@path = []
|
57
|
-
@value = nil
|
58
|
-
@context = self # for SharedMethods TODO delete sharedmethods
|
59
53
|
@scoped_context = ScopedContext.new(self)
|
60
54
|
end
|
61
55
|
|
@@ -245,7 +239,7 @@ module GraphQL
|
|
245
239
|
end
|
246
240
|
|
247
241
|
def inspect
|
248
|
-
"
|
242
|
+
"#<#{self.class} ...>"
|
249
243
|
end
|
250
244
|
|
251
245
|
def scoped_merge!(hash)
|
@@ -176,30 +176,33 @@ module GraphQL
|
|
176
176
|
return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
177
177
|
end
|
178
178
|
|
179
|
-
# Inject missing required arguments
|
180
|
-
missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
|
181
|
-
if !input.key?(argument.graphql_name) && argument.type.non_null? && !argument.default_value? && types.argument(self, argument.graphql_name)
|
182
|
-
m[argument.graphql_name] = nil
|
183
|
-
end
|
184
|
-
|
185
|
-
m
|
186
|
-
end
|
187
179
|
|
188
180
|
result = nil
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
181
|
+
|
182
|
+
|
183
|
+
input.each do |argument_name, value|
|
184
|
+
argument = types.argument(self, argument_name)
|
185
|
+
# Items in the input that are unexpected
|
186
|
+
if argument.nil?
|
187
|
+
result ||= Query::InputValidationResult.new
|
188
|
+
result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
|
189
|
+
else
|
190
|
+
# Items in the input that are expected, but have invalid values
|
191
|
+
argument_result = argument.type.validate_input(value, ctx)
|
192
|
+
if !argument_result.valid?
|
199
193
|
result ||= Query::InputValidationResult.new
|
200
|
-
|
201
|
-
|
202
|
-
|
194
|
+
result.merge_result!(argument_name, argument_result)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Check for missing non-null arguments
|
200
|
+
ctx.types.arguments(self).each do |argument|
|
201
|
+
if !input.key?(argument.graphql_name) && argument.type.non_null? && !argument.default_value?
|
202
|
+
result ||= Query::InputValidationResult.new
|
203
|
+
argument_result = argument.type.validate_input(nil, ctx)
|
204
|
+
if !argument_result.valid?
|
205
|
+
result.merge_result!(argument.graphql_name, argument_result)
|
203
206
|
end
|
204
207
|
end
|
205
208
|
end
|
@@ -12,7 +12,7 @@ module GraphQL
|
|
12
12
|
# @param profiles [Hash<Symbol => Hash>] A hash of `name => context` pairs for preloading visibility profiles
|
13
13
|
# @param preload [Boolean] if `true`, load the default schema profile and all named profiles immediately (defaults to `true` for `Rails.env.production?`)
|
14
14
|
# @param migration_errors [Boolean] if `true`, raise an error when `Visibility` and `Warden` return different results
|
15
|
-
def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails) ? Rails.env.production? : nil), migration_errors: false)
|
15
|
+
def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails.env) ? Rails.env.production? : nil), migration_errors: false)
|
16
16
|
profiles&.each { |name, ctx|
|
17
17
|
ctx[:visibility_profile] = name
|
18
18
|
ctx.freeze
|
@@ -137,7 +137,9 @@ module GraphQL
|
|
137
137
|
|
138
138
|
def dataloader_fiber_resume(source)
|
139
139
|
prev_ev = Fiber[PREVIOUS_EV_KEY]
|
140
|
-
|
140
|
+
if prev_ev
|
141
|
+
begin_notifications_event(prev_ev.name, prev_ev.payload)
|
142
|
+
end
|
141
143
|
super
|
142
144
|
end
|
143
145
|
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-29 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: base64
|
@@ -163,6 +163,20 @@ dependencies:
|
|
163
163
|
- - ">="
|
164
164
|
- !ruby/object:Gem::Version
|
165
165
|
version: '0'
|
166
|
+
- !ruby/object:Gem::Dependency
|
167
|
+
name: ostruct
|
168
|
+
requirement: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
type: :development
|
174
|
+
prerelease: false
|
175
|
+
version_requirements: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
166
180
|
- !ruby/object:Gem::Dependency
|
167
181
|
name: rake
|
168
182
|
requirement: !ruby/object:Gem::Requirement
|
@@ -801,7 +815,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
801
815
|
- !ruby/object:Gem::Version
|
802
816
|
version: '0'
|
803
817
|
requirements: []
|
804
|
-
rubygems_version: 3.6.
|
818
|
+
rubygems_version: 3.6.8
|
805
819
|
specification_version: 4
|
806
820
|
summary: A GraphQL language and runtime for Ruby
|
807
821
|
test_files: []
|