graphql 1.12.18 → 1.12.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d1cfa93dc97adf13e461a45a00899f5ecc3e27d66c54c33d1a319b027665b78
4
- data.tar.gz: 5d8cf2b669619dd15058400e15342ff225ba02716c5d8c9959c74260d4f51b32
3
+ metadata.gz: 92aba0a1935a0022b97ea1630cde64884a727ce714fae6a2bca543666c73bde0
4
+ data.tar.gz: 5db896ad77a52ec4a025f526bab4f3c4b3d18206e009c2d8c3e14dd434f12ae6
5
5
  SHA512:
6
- metadata.gz: d7ff04a88e0ae883c382aa6559b52c38dbbc7d513537aaf506e89dd7880c227b6b032f7329c1c9e7b0fb9692b3e0e6fdbaac9df9fc82e536fb1e12b9cff2f65c
7
- data.tar.gz: 3276674be3f8b0eb05d5c8904cad3ef20697bf5b9efcb133bd7c283d7bd704d52cd75f87a46f6c1fd988faf6c439c796d186280f4e397f8dc5184ae7d17c333b
6
+ metadata.gz: 2985936af9bba4d0feec8263dd4a6c60c09110e39aba1a97359e4d02900732f02900e30d798074932bb6fe2a5ed0e00441be859bb3035ab0c819ccec3c9a0f66
7
+ data.tar.gz: e8e961e540b54a5c54d6d78c444eef422bd55264ee8ffc9c3a231f2614c570ee75de5c2888f3b13974304c48f60072e04bb0d0444ea6e1a13f4a37652dbd2f0b
@@ -12,9 +12,25 @@ module GraphQL
12
12
  # The value which couldn't be encoded
13
13
  attr_reader :integer_value
14
14
 
15
- def initialize(value)
15
+ # @return [GraphQL::Schema::Field] The field that returned a too-big integer
16
+ attr_reader :field
17
+
18
+ # @return [Array<String, Integer>] Where the field appeared in the GraphQL response
19
+ attr_reader :path
20
+
21
+ def initialize(value, context:)
16
22
  @integer_value = value
17
- super("Integer out of bounds: #{value}. \nConsider using ID or GraphQL::Types::BigInt instead.")
23
+ @field = context[:current_field]
24
+ @path = context[:current_path]
25
+ message = "Integer out of bounds: #{value}".dup
26
+ if @path
27
+ message << " @ #{@path.join(".")}"
28
+ end
29
+ if @field
30
+ message << " (#{@field.path})"
31
+ end
32
+ message << ". Consider using ID or GraphQL::Types::BigInt instead."
33
+ super(message)
18
34
  end
19
35
  end
20
36
  end
@@ -72,7 +72,7 @@ module GraphQL
72
72
  elsif @operation_name_error
73
73
  @validation_errors << @operation_name_error
74
74
  else
75
- validation_result = @schema.static_validator.validate(@query, validate: @validate, timeout: @schema.validate_timeout)
75
+ validation_result = @schema.static_validator.validate(@query, validate: @validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
76
76
  @validation_errors.concat(validation_result[:errors])
77
77
  @internal_representation = validation_result[:irep]
78
78
 
@@ -254,11 +254,17 @@ module GraphQL
254
254
  if authed
255
255
  application_object
256
256
  else
257
- raise GraphQL::UnauthorizedError.new(
257
+ err = GraphQL::UnauthorizedError.new(
258
258
  object: application_object,
259
259
  type: class_based_type,
260
260
  context: context,
261
261
  )
262
+ if self.respond_to?(:unauthorized_object)
263
+ err.set_backtrace(caller)
264
+ unauthorized_object(err)
265
+ else
266
+ raise err
267
+ end
262
268
  end
263
269
  end
264
270
  else
@@ -160,6 +160,16 @@ module GraphQL
160
160
  end
161
161
  end
162
162
 
163
+ # Called when an object loaded by `loads:` fails the `.authorized?` check for its resolved GraphQL object type.
164
+ #
165
+ # By default, the error is re-raised and passed along to {{Schema.unauthorized_object}}.
166
+ #
167
+ # Any value returned here will be used _instead of_ of the loaded object.
168
+ # @param err [GraphQL::UnauthorizedError]
169
+ def unauthorized_object(err)
170
+ raise err
171
+ end
172
+
163
173
  private
164
174
 
165
175
  def load_arguments(args)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Validator
6
+ # Use this to specifically reject values that respond to `.blank?` and respond truthy for that method.
7
+ #
8
+ # @example Require a non-empty string for an argument
9
+ # argument :name, String, required: true, validate: { allow_blank: false }
10
+ class AllowBlankValidator < Validator
11
+ def initialize(allow_blank_positional, allow_blank: nil, message: "%{validated} can't be blank", **default_options)
12
+ @message = message
13
+ super(**default_options)
14
+ @allow_blank = allow_blank.nil? ? allow_blank_positional : allow_blank
15
+ end
16
+
17
+ def validate(_object, _context, value)
18
+ if value.respond_to?(:blank?) && value.blank?
19
+ if (value.nil? && @allow_null) || @allow_blank
20
+ # pass
21
+ else
22
+ @message
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Validator
6
+ # Use this to specifically reject or permit `nil` values (given as `null` from GraphQL).
7
+ #
8
+ # @example require a non-null value for an argument if it is provided
9
+ # argument :name, String, required: false, validates: { allow_null: false }
10
+ class AllowNullValidator < Validator
11
+ MESSAGE = "%{validated} can't be null"
12
+ def initialize(allow_null_positional, allow_null: nil, message: MESSAGE, **default_options)
13
+ @message = message
14
+ super(**default_options)
15
+ @allow_null = allow_null.nil? ? allow_null_positional : allow_null
16
+ end
17
+
18
+ def validate(_object, _context, value)
19
+ if value.nil? && !@allow_null
20
+ @message
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -21,7 +21,9 @@ module GraphQL
21
21
  end
22
22
 
23
23
  def validate(_object, _context, value)
24
- if @in_list.include?(value)
24
+ if permitted_empty_value?(value)
25
+ # pass
26
+ elsif @in_list.include?(value)
25
27
  @message
26
28
  end
27
29
  end
@@ -38,7 +38,8 @@ module GraphQL
38
38
  end
39
39
 
40
40
  def validate(_object, _context, value)
41
- if (@with_pattern && !value.match?(@with_pattern)) ||
41
+ if value.nil? ||
42
+ (@with_pattern && !value.match?(@with_pattern)) ||
42
43
  (@without_pattern && value.match?(@without_pattern))
43
44
  @message
44
45
  end
@@ -23,7 +23,9 @@ module GraphQL
23
23
  end
24
24
 
25
25
  def validate(_object, _context, value)
26
- if !@in_list.include?(value)
26
+ if permitted_empty_value?(value)
27
+ # pass
28
+ elsif !@in_list.include?(value)
27
29
  @message
28
30
  end
29
31
  end
@@ -43,11 +43,13 @@ module GraphQL
43
43
  end
44
44
 
45
45
  def validate(_object, _context, value)
46
- if @maximum && value.length > @maximum
46
+ return if permitted_empty_value?(value) # pass in this case
47
+ length = value.nil? ? 0 : value.length
48
+ if @maximum && length > @maximum
47
49
  partial_format(@too_long, { count: @maximum })
48
- elsif @minimum && value.length < @minimum
50
+ elsif @minimum && length < @minimum
49
51
  partial_format(@too_short, { count: @minimum })
50
- elsif @is && value.length != @is
52
+ elsif @is && length != @is
51
53
  partial_format(@wrong_length, { count: @is })
52
54
  end
53
55
  end
@@ -32,6 +32,7 @@ module GraphQL
32
32
  equal_to: nil, other_than: nil,
33
33
  odd: nil, even: nil, within: nil,
34
34
  message: "%{validated} must be %{comparison} %{target}",
35
+ null_message: Validator::AllowNullValidator::MESSAGE,
35
36
  **default_options
36
37
  )
37
38
 
@@ -45,11 +46,16 @@ module GraphQL
45
46
  @even = even
46
47
  @within = within
47
48
  @message = message
49
+ @null_message = null_message
48
50
  super(**default_options)
49
51
  end
50
52
 
51
53
  def validate(object, context, value)
52
- if @greater_than && value <= @greater_than
54
+ if permitted_empty_value?(value)
55
+ # pass in this case
56
+ elsif value.nil? # @allow_null is handled in the parent class
57
+ @null_message
58
+ elsif @greater_than && value <= @greater_than
53
59
  partial_format(@message, { comparison: "greater than", target: @greater_than })
54
60
  elsif @greater_than_or_equal_to && value < @greater_than_or_equal_to
55
61
  partial_format(@message, { comparison: "greater than or equal to", target: @greater_than_or_equal_to })
@@ -7,7 +7,6 @@ module GraphQL
7
7
  # @return [GraphQL::Schema::Argument, GraphQL::Schema::Field, GraphQL::Schema::Resolver, Class<GraphQL::Schema::InputObject>]
8
8
  attr_reader :validated
9
9
 
10
- # TODO should this implement `if:` and `unless:` ?
11
10
  # @param validated [GraphQL::Schema::Argument, GraphQL::Schema::Field, GraphQL::Schema::Resolver, Class<GraphQL::Schema::InputObject>] The argument or argument owner this validator is attached to
12
11
  # @param allow_blank [Boolean] if `true`, then objects that respond to `.blank?` and return true for `.blank?` will skip this validation
13
12
  # @param allow_null [Boolean] if `true`, then incoming `null`s will skip this validation
@@ -25,26 +24,6 @@ module GraphQL
25
24
  raise GraphQL::RequiredImplementationMissingError, "Validator classes should implement #validate"
26
25
  end
27
26
 
28
- # This is called by the validation system and eventually calls {#validate}.
29
- # @api private
30
- def apply(object, context, value)
31
- if value.nil?
32
- if @allow_null
33
- nil # skip this
34
- else
35
- "%{validated} can't be null"
36
- end
37
- elsif value.respond_to?(:blank?) && value.blank?
38
- if @allow_blank
39
- nil # skip this
40
- else
41
- "%{validated} can't be blank"
42
- end
43
- else
44
- validate(object, context, value)
45
- end
46
- end
47
-
48
27
  # This is like `String#%`, but it supports the case that only some of `string`'s
49
28
  # values are present in `substitutions`
50
29
  def partial_format(string, substitutions)
@@ -55,6 +34,12 @@ module GraphQL
55
34
  string
56
35
  end
57
36
 
37
+ # @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
+ def permitted_empty_value?(value)
39
+ (value.nil? && @allow_null) ||
40
+ (@allow_blank && value.respond_to?(:blank?) && value.blank?)
41
+ end
42
+
58
43
  # @param schema_member [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class<GraphQL::Schema::InputObject>]
59
44
  # @param validates_hash [Hash{Symbol => Hash}, Hash{Class => Hash} nil] A configuration passed as `validates:`
60
45
  # @return [Array<Validator>]
@@ -62,6 +47,24 @@ module GraphQL
62
47
  if validates_hash.nil? || validates_hash.empty?
63
48
  EMPTY_ARRAY
64
49
  else
50
+ validates_hash = validates_hash.dup
51
+ allow_null = validates_hash.delete(:allow_null)
52
+ allow_blank = validates_hash.delete(:allow_blank)
53
+
54
+ # This could be {...}.compact on Ruby 2.4+
55
+ default_options = {}
56
+ if !allow_null.nil?
57
+ default_options[:allow_null] = allow_null
58
+ end
59
+ if !allow_blank.nil?
60
+ default_options[:allow_blank] = allow_blank
61
+ end
62
+
63
+ # allow_nil or allow_blank are the _only_ validations:
64
+ if validates_hash.empty?
65
+ validates_hash = default_options
66
+ end
67
+
65
68
  validates_hash.map do |validator_name, options|
66
69
  validator_class = case validator_name
67
70
  when Class
@@ -69,7 +72,11 @@ module GraphQL
69
72
  else
70
73
  all_validators[validator_name] || raise(ArgumentError, "unknown validation: #{validator_name.inspect}")
71
74
  end
72
- validator_class.new(validated: schema_member, **options)
75
+ if options.is_a?(Hash)
76
+ validator_class.new(validated: schema_member, **(default_options.merge(options)))
77
+ else
78
+ validator_class.new(options, validated: schema_member, **default_options)
79
+ end
73
80
  end
74
81
  end
75
82
  end
@@ -122,10 +129,10 @@ module GraphQL
122
129
 
123
130
  validators.each do |validator|
124
131
  validated = as || validator.validated
125
- errors = validator.apply(object, context, value)
132
+ errors = validator.validate(object, context, value)
126
133
  if errors &&
127
- (errors.is_a?(Array) && errors != EMPTY_ARRAY) ||
128
- (errors.is_a?(String))
134
+ (errors.is_a?(Array) && errors != EMPTY_ARRAY) ||
135
+ (errors.is_a?(String))
129
136
  if all_errors.frozen? # It's empty
130
137
  all_errors = []
131
138
  end
@@ -161,3 +168,7 @@ require "graphql/schema/validator/exclusion_validator"
161
168
  GraphQL::Schema::Validator.install(:exclusion, GraphQL::Schema::Validator::ExclusionValidator)
162
169
  require "graphql/schema/validator/required_validator"
163
170
  GraphQL::Schema::Validator.install(:required, GraphQL::Schema::Validator::RequiredValidator)
171
+ require "graphql/schema/validator/allow_null_validator"
172
+ GraphQL::Schema::Validator.install(:allow_null, GraphQL::Schema::Validator::AllowNullValidator)
173
+ require "graphql/schema/validator/allow_blank_validator"
174
+ GraphQL::Schema::Validator.install(:allow_blank, GraphQL::Schema::Validator::AllowBlankValidator)
@@ -1,10 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  class StringEncodingError < GraphQL::RuntimeTypeError
4
- attr_reader :string
5
- def initialize(str)
4
+ attr_reader :string, :field, :path
5
+ def initialize(str, context:)
6
6
  @string = str
7
- super("String \"#{str}\" was encoded as #{str.encoding}! GraphQL requires an encoding compatible with UTF-8.")
7
+ @field = context[:current_field]
8
+ @path = context[:current_path]
9
+ message = "String #{str.inspect} was encoded as #{str.encoding}".dup
10
+ if @path
11
+ message << " @ #{@path.join(".")}"
12
+ end
13
+ if @field
14
+ message << " (#{@field.path})"
15
+ end
16
+ message << ". GraphQL requires an encoding compatible with UTF-8."
17
+ super(message)
8
18
  end
9
19
  end
10
20
  end
@@ -25,7 +25,7 @@ module GraphQL
25
25
  if value >= MIN && value <= MAX
26
26
  value
27
27
  else
28
- err = GraphQL::IntegerEncodingError.new(value)
28
+ err = GraphQL::IntegerEncodingError.new(value, context: ctx)
29
29
  ctx.schema.type_error(err, ctx)
30
30
  end
31
31
  end
@@ -15,7 +15,7 @@ module GraphQL
15
15
  str.encode!(Encoding::UTF_8)
16
16
  end
17
17
  rescue EncodingError
18
- err = GraphQL::StringEncodingError.new(str)
18
+ err = GraphQL::StringEncodingError.new(str, context: ctx)
19
19
  ctx.schema.type_error(err, ctx)
20
20
  end
21
21
 
@@ -12,7 +12,7 @@ module GraphQL
12
12
  attr_reader :type
13
13
 
14
14
  # @return [GraphQL::Query::Context] the context for the current query
15
- attr_reader :context
15
+ attr_accessor :context
16
16
 
17
17
  def initialize(message = nil, object: nil, type: nil, context: nil)
18
18
  if message.nil? && object.nil? && type.nil?
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.12.18"
3
+ VERSION = "1.12.19"
4
4
  end
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.18
4
+ version: 1.12.19
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-02 00:00:00.000000000 Z
11
+ date: 2021-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -544,6 +544,8 @@ files:
544
544
  - lib/graphql/schema/unique_within_type.rb
545
545
  - lib/graphql/schema/validation.rb
546
546
  - lib/graphql/schema/validator.rb
547
+ - lib/graphql/schema/validator/allow_blank_validator.rb
548
+ - lib/graphql/schema/validator/allow_null_validator.rb
547
549
  - lib/graphql/schema/validator/exclusion_validator.rb
548
550
  - lib/graphql/schema/validator/format_validator.rb
549
551
  - lib/graphql/schema/validator/inclusion_validator.rb