graphql 2.6.2 → 2.6.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/field_extractor.rb +17 -1
  3. data/lib/graphql/analysis/query_complexity.rb +31 -15
  4. data/lib/graphql/backtrace/table.rb +10 -1
  5. data/lib/graphql/current.rb +7 -1
  6. data/lib/graphql/dataloader/async_dataloader.rb +310 -60
  7. data/lib/graphql/dataloader/source.rb +18 -10
  8. data/lib/graphql/dataloader.rb +1 -1
  9. data/lib/graphql/execution/directive_checks.rb +2 -0
  10. data/lib/graphql/execution/field_resolve_step.rb +84 -18
  11. data/lib/graphql/execution/finalize.rb +10 -9
  12. data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -0
  13. data/lib/graphql/execution/interpreter/runtime.rb +0 -6
  14. data/lib/graphql/execution/load_argument_step.rb +6 -0
  15. data/lib/graphql/execution/prepare_object_step.rb +14 -4
  16. data/lib/graphql/execution/runner.rb +7 -1
  17. data/lib/graphql/execution/selections_step.rb +6 -2
  18. data/lib/graphql/execution_error.rb +4 -0
  19. data/lib/graphql/language.rb +8 -2
  20. data/lib/graphql/schema/argument.rb +1 -1
  21. data/lib/graphql/schema/interface.rb +1 -1
  22. data/lib/graphql/schema/introspection_system.rb +6 -21
  23. data/lib/graphql/schema/printer.rb +1 -1
  24. data/lib/graphql/schema/validator/allow_blank_validator.rb +3 -3
  25. data/lib/graphql/schema/validator/allow_null_validator.rb +3 -3
  26. data/lib/graphql/schema/validator/exclusion_validator.rb +2 -2
  27. data/lib/graphql/schema/validator/format_validator.rb +3 -3
  28. data/lib/graphql/schema/validator/inclusion_validator.rb +2 -2
  29. data/lib/graphql/schema/validator/length_validator.rb +6 -6
  30. data/lib/graphql/schema/validator/numericality_validator.rb +19 -19
  31. data/lib/graphql/schema/validator/required_validator.rb +6 -4
  32. data/lib/graphql/schema/validator.rb +9 -0
  33. data/lib/graphql/schema/visibility/profile.rb +6 -4
  34. data/lib/graphql/schema/visibility.rb +30 -22
  35. data/lib/graphql/schema.rb +1 -1
  36. data/lib/graphql/version.rb +1 -1
  37. metadata +2 -2
@@ -37,9 +37,9 @@ module GraphQL
37
37
  if permitted_empty_value?(value)
38
38
  # Do nothing
39
39
  elsif value.nil? ||
40
- (@with_pattern && !value.match?(@with_pattern)) ||
41
- (@without_pattern && value.match?(@without_pattern))
42
- @message
40
+ (@with_pattern && !value.match?(validation_parameter(@with_pattern))) ||
41
+ (@without_pattern && value.match?(validation_parameter(@without_pattern)))
42
+ validation_parameter(@message)
43
43
  end
44
44
  end
45
45
  end
@@ -25,8 +25,8 @@ module GraphQL
25
25
  def validate(_object, _context, value)
26
26
  if permitted_empty_value?(value)
27
27
  # pass
28
- elsif !@in_list.include?(value)
29
- @message
28
+ elsif !validation_parameter(@in_list).include?(value)
29
+ validation_parameter(@message)
30
30
  end
31
31
  end
32
32
  end
@@ -45,12 +45,12 @@ module GraphQL
45
45
  def validate(_object, _context, value)
46
46
  return if permitted_empty_value?(value) # pass in this case
47
47
  length = value.nil? ? 0 : value.length
48
- if @maximum && length > @maximum
49
- partial_format(@too_long, { count: @maximum })
50
- elsif @minimum && length < @minimum
51
- partial_format(@too_short, { count: @minimum })
52
- elsif @is && length != @is
53
- partial_format(@wrong_length, { count: @is })
48
+ if (current_max = validation_parameter(@maximum)) && length > current_max
49
+ partial_format(validation_parameter(@too_long), { count: current_max })
50
+ elsif (current_min = validation_parameter(@minimum)) && length < current_min
51
+ partial_format(validation_parameter(@too_short), { count: current_min })
52
+ elsif (current_is = validation_parameter(@is)) && length != current_is
53
+ partial_format(validation_parameter(@wrong_length), { count: current_is })
54
54
  end
55
55
  end
56
56
  end
@@ -55,25 +55,25 @@ module GraphQL
55
55
  if permitted_empty_value?(value)
56
56
  # pass in this case
57
57
  elsif value.nil? # @allow_null is handled in the parent class
58
- @null_message
59
- elsif @greater_than && value <= @greater_than
60
- partial_format(@message, { comparison: "greater than", target: @greater_than })
61
- elsif @greater_than_or_equal_to && value < @greater_than_or_equal_to
62
- partial_format(@message, { comparison: "greater than or equal to", target: @greater_than_or_equal_to })
63
- elsif @less_than && value >= @less_than
64
- partial_format(@message, { comparison: "less than", target: @less_than })
65
- elsif @less_than_or_equal_to && value > @less_than_or_equal_to
66
- partial_format(@message, { comparison: "less than or equal to", target: @less_than_or_equal_to })
67
- elsif @equal_to && value != @equal_to
68
- partial_format(@message, { comparison: "equal to", target: @equal_to })
69
- elsif @other_than && value == @other_than
70
- partial_format(@message, { comparison: "something other than", target: @other_than })
71
- elsif @even && !value.even?
72
- (partial_format(@message, { comparison: "even", target: "" })).strip
73
- elsif @odd && !value.odd?
74
- (partial_format(@message, { comparison: "odd", target: "" })).strip
75
- elsif @within && !@within.include?(value)
76
- partial_format(@message, { comparison: "within", target: @within })
58
+ validation_parameter(@null_message)
59
+ elsif (current_greater_than = validation_parameter(@greater_than)) && value <= current_greater_than
60
+ partial_format(validation_parameter(@message), { comparison: "greater than", target: current_greater_than })
61
+ elsif (current_greater_than_or_equal_to = validation_parameter(@greater_than_or_equal_to)) && value < current_greater_than_or_equal_to
62
+ partial_format(validation_parameter(@message), { comparison: "greater than or equal to", target: current_greater_than_or_equal_to })
63
+ elsif (current_less_than = validation_parameter(@less_than)) && value >= current_less_than
64
+ partial_format(validation_parameter(@message), { comparison: "less than", target: current_less_than })
65
+ elsif (current_less_than_or_equal_to = validation_parameter(@less_than_or_equal_to)) && value > current_less_than_or_equal_to
66
+ partial_format(validation_parameter(@message), { comparison: "less than or equal to", target: current_less_than_or_equal_to })
67
+ elsif (current_equal_to = validation_parameter(@equal_to)) && value != current_equal_to
68
+ partial_format(validation_parameter(@message), { comparison: "equal to", target: current_equal_to })
69
+ elsif (current_other_than = validation_parameter(@other_than)) && value == current_other_than
70
+ partial_format(validation_parameter(@message), { comparison: "something other than", target: current_other_than })
71
+ elsif validation_parameter(@even) && !value.even?
72
+ (partial_format(validation_parameter(@message), { comparison: "even", target: "" })).strip
73
+ elsif validation_parameter(@odd) && !value.odd?
74
+ (partial_format(validation_parameter(@message), { comparison: "odd", target: "" })).strip
75
+ elsif (current_within = validation_parameter(@within)) && !current_within.include?(value)
76
+ partial_format(validation_parameter(@message), { comparison: "within", target: current_within })
77
77
  end
78
78
  end
79
79
  end
@@ -67,7 +67,8 @@ module GraphQL
67
67
  no_visible_conditions = true
68
68
 
69
69
  if !value.nil?
70
- @one_of.each do |one_of_condition|
70
+ validation_parameter(@one_of).each do |one_of_condition|
71
+ one_of_condition = validation_parameter(one_of_condition)
71
72
  case one_of_condition
72
73
  when Symbol
73
74
  if no_visible_conditions && visible_keywords.include?(one_of_condition)
@@ -108,7 +109,7 @@ module GraphQL
108
109
  end
109
110
 
110
111
  if no_visible_conditions
111
- if @allow_all_hidden
112
+ if validation_parameter(@allow_all_hidden)
112
113
  return nil
113
114
  else
114
115
  raise GraphQL::Error, <<~ERR
@@ -122,7 +123,7 @@ module GraphQL
122
123
  if fully_matched_conditions == 1 && partially_matched_conditions == 0
123
124
  nil # OK
124
125
  else
125
- @message || build_message(context)
126
+ validation_parameter(@message) || build_message(context)
126
127
  end
127
128
  end
128
129
 
@@ -130,8 +131,9 @@ module GraphQL
130
131
  argument_definitions = context.types.arguments(@validated)
131
132
 
132
133
  required_names = @one_of.map do |arg_keyword|
134
+ arg_keyword = validation_parameter(arg_keyword)
133
135
  if arg_keyword.is_a?(Array)
134
- names = arg_keyword.map { |arg| arg_keyword_to_graphql_name(argument_definitions, arg) }
136
+ names = arg_keyword.map { |arg| arg_keyword_to_graphql_name(argument_definitions, validation_parameter(arg)) }
135
137
  names.compact! # hidden arguments are `nil`
136
138
  "(" + names.join(" and ") + ")"
137
139
  else
@@ -34,6 +34,15 @@ module GraphQL
34
34
  string
35
35
  end
36
36
 
37
+ # @return [Object] The current value to use for validation, based on `config_value` from configuration time. If a Proc is given, this calls it and returns it.
38
+ def validation_parameter(config_value)
39
+ if config_value.is_a?(Proc)
40
+ config_value.call
41
+ else
42
+ config_value
43
+ end
44
+ end
45
+
37
46
  # @return [Boolean] `true` if `value` is `nil` and this validator has `allow_null: true` or if value is `.blank?` and this validator has `allow_blank: true`
38
47
  def permitted_empty_value?(value)
39
48
  (value.nil? && @allow_null) ||
@@ -290,11 +290,13 @@ module GraphQL
290
290
  end
291
291
  # Lots more to do here
292
292
  end
293
- @schema.introspection_system.entry_points.each do |f|
294
- arguments(f).each do |arg|
295
- argument(f, arg.graphql_name)
293
+ if @schema.query
294
+ @schema.introspection_system.entry_points.each do |f|
295
+ arguments(f).each do |arg|
296
+ argument(f, arg.graphql_name)
297
+ end
298
+ field(@schema.query, f.graphql_name)
296
299
  end
297
- field(@schema.query, f.graphql_name)
298
300
  end
299
301
  @schema.introspection_system.dynamic_fields.each do |f|
300
302
  arguments(f).each do |arg|
@@ -8,11 +8,17 @@ module GraphQL
8
8
  # Use this plugin to make some parts of your schema hidden from some viewers.
9
9
  #
10
10
  class Visibility
11
+ class TypeConfigurationError < GraphQL::Error
12
+ def initialize(config_message, config_str)
13
+ message = "GraphQL::Schema::Visibility already preloaded, but #{config_message} added to the schema. Move this `#{config_str}` configuration above `use(GraphQL::Schema::Visibility)"
14
+ super(message)
15
+ end
16
+ end
11
17
  # @param schema [Class<GraphQL::Schema>]
12
18
  # @param profiles [Hash<Symbol => Hash>] A hash of `name => context` pairs for preloading visibility profiles
13
19
  # @param preload [Boolean] if `true`, load the default schema profile and all named profiles immediately (defaults to `true` for `Rails.env.production?` and `Rails.env.staging?`)
14
20
  # @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.env) ? (Rails.env.production? || Rails.env.staging?) : nil), migration_errors: false)
21
+ def self.use(schema, dynamic: false, profiles: EmptyObjects::EMPTY_HASH, preload: (defined?(Rails.env) ? (Rails.env.production? || Rails.env.staging? || nil) : false), migration_errors: false)
16
22
  profiles&.each { |name, ctx|
17
23
  ctx[:visibility_profile] = name
18
24
  ctx.freeze
@@ -20,7 +26,7 @@ module GraphQL
20
26
  schema.visibility = self.new(schema, dynamic: dynamic, preload: preload, profiles: profiles, migration_errors: migration_errors)
21
27
  end
22
28
 
23
- def initialize(schema, dynamic:, preload:, profiles:, migration_errors:)
29
+ def initialize(schema, dynamic:, preload:, profiles:, migration_errors:, configuration_inherited: false)
24
30
  @schema = schema
25
31
  schema.use_visibility_profile = true
26
32
  schema.visibility_profile_class = if migration_errors
@@ -40,6 +46,7 @@ module GraphQL
40
46
  @types = nil
41
47
  @all_references = nil
42
48
  @loaded_all = false
49
+ @configuration_inherited = configuration_inherited
43
50
  if preload
44
51
  self.preload
45
52
  end
@@ -94,6 +101,7 @@ module GraphQL
94
101
  # Root types may have been nil:
95
102
  types_to_visit.compact!
96
103
  ensure_all_loaded(types_to_visit)
104
+ @cached_profiles.clear
97
105
  @profiles.each do |profile_name, example_ctx|
98
106
  prof = profile_for(example_ctx)
99
107
  prof.preload
@@ -102,41 +110,27 @@ module GraphQL
102
110
 
103
111
  # @api private
104
112
  def query_configured(query_type)
105
- if @preload
106
- ensure_all_loaded([query_type])
107
- end
113
+ require_if_preloaded("a query type was", "query(...)")
108
114
  end
109
115
 
110
116
  # @api private
111
117
  def mutation_configured(mutation_type)
112
- if @preload
113
- ensure_all_loaded([mutation_type])
114
- end
118
+ require_if_preloaded("a mutation type was", "mutation(...)")
115
119
  end
116
120
 
117
121
  # @api private
118
122
  def subscription_configured(subscription_type)
119
- if @preload
120
- ensure_all_loaded([subscription_type])
121
- end
123
+ require_if_preloaded("a mutation type was", "subscription(...)")
122
124
  end
123
125
 
124
126
  # @api private
125
127
  def orphan_types_configured(orphan_types)
126
- if @preload
127
- ensure_all_loaded(orphan_types)
128
- end
128
+ require_if_preloaded("orphan types were", "orphan_types(...)")
129
129
  end
130
130
 
131
131
  # @api private
132
132
  def introspection_system_configured(introspection_system)
133
- if @preload
134
- introspection_types = [
135
- *@schema.introspection_system.types.values,
136
- *@schema.introspection_system.entry_points.map { |ep| ep.type.unwrap },
137
- ]
138
- ensure_all_loaded(introspection_types)
139
- end
133
+ require_if_preloaded("custom introspection was", "introspection(...)")
140
134
  end
141
135
 
142
136
  # Make another Visibility for `schema` based on this one
@@ -148,7 +142,8 @@ module GraphQL
148
142
  dynamic: @dynamic,
149
143
  preload: @preload,
150
144
  profiles: @profiles,
151
- migration_errors: @migration_errors
145
+ migration_errors: @migration_errors,
146
+ configuration_inherited: true,
152
147
  )
153
148
  end
154
149
 
@@ -196,6 +191,19 @@ module GraphQL
196
191
 
197
192
  private
198
193
 
194
+ def require_if_preloaded(config_message, config_code)
195
+ case @preload
196
+ when false
197
+ # Rails.env wasn't defined, so this won't try to preload unless manually set to true
198
+ when true, nil
199
+ if @configuration_inherited
200
+ preload
201
+ else
202
+ raise TypeConfigurationError.new(config_message, config_code)
203
+ end
204
+ end
205
+ end
206
+
199
207
  def ensure_all_loaded(types_to_visit)
200
208
  while (type = types_to_visit.shift)
201
209
  if type.kind.fields? && @preloaded_types.add?(type)
@@ -757,6 +757,7 @@ module GraphQL
757
757
  # reset this cached value:
758
758
  @introspection_system = nil
759
759
  introspection_system
760
+ self.visibility&.introspection_system_configured(introspection_system)
760
761
  @introspection
761
762
  else
762
763
  @introspection || find_inherited_value(:introspection)
@@ -768,7 +769,6 @@ module GraphQL
768
769
  if !@introspection_system
769
770
  @introspection_system = Schema::IntrospectionSystem.new(self)
770
771
  @introspection_system.resolve_late_bindings
771
- self.visibility&.introspection_system_configured(@introspection_system)
772
772
  end
773
773
  @introspection_system
774
774
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.6.2"
3
+ VERSION = "2.6.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.6.2
4
+ version: 2.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-05-12 00:00:00.000000000 Z
10
+ date: 2026-07-06 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64