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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2e4ec1acc9810683bb2628dc5403c74d729742612655f1be275267a89b107b3
4
- data.tar.gz: fb092108f803095aea29b325859fc810feaa8e5fdb6c873c431f9824428fbc15
3
+ metadata.gz: 170be4878ee16ebea26a272dde50923d35e624c87e1154b34de61a10f6a9fae0
4
+ data.tar.gz: 5ac223538670c8a24c2748e0819cab3b5e0627c14b4a4745559fdedfcd8440fb
5
5
  SHA512:
6
- metadata.gz: 603e3da13be680884399546074dae65f44635382e13311758e237f7973bbdd96f4a1a46f6b17476af77d88177f5e82f3c76b227633e2e15a9c909365a818f97e
7
- data.tar.gz: d631c5a9e1c91fb815d98e1981641405c344b589c6e823ae5609b25fd819a2d5dc9032f366c94a3da69c56a48aa7d8e9ee082cbfa217807e6cbf313d16cbd598
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-docs/#{GraphQL::VERSION}/Schema.html#complexity_cost_cacluation_mode-class_method
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
- @type_for_column = @model_class.type_for_attribute(@find_by)
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 load(requested_key)
14
- casted_key = @type_for_column.cast(requested_key)
15
- super(casted_key)
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
- records.each { |r| record_lookup[r.public_send(@find_by)] = r }
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
- "#<Query::Context ...>"
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
- [input, missing_required_inputs].each do |args_to_validate|
190
- args_to_validate.each do |argument_name, value|
191
- argument = types.argument(self, argument_name)
192
- # Items in the input that are unexpected
193
- if argument.nil?
194
- result ||= Query::InputValidationResult.new
195
- result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
196
- else
197
- # Items in the input that are expected, but have invalid values
198
- argument_result = argument.type.validate_input(value, ctx)
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
- if !argument_result.valid?
201
- result.merge_result!(argument_name, argument_result)
202
- end
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
- begin_notifications_event(prev_ev.name, prev_ev.payload)
140
+ if prev_ev
141
+ begin_notifications_event(prev_ev.name, prev_ev.payload)
142
+ end
141
143
  super
142
144
  end
143
145
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.5.3"
3
+ VERSION = "2.5.5"
4
4
  end
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.3
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-14 00:00:00.000000000 Z
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.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: []