Skip to content

Commit 73358f8

Browse files
committed
Clean up code, support grouped one-of conditions
1 parent 7848952 commit 73358f8

2 files changed

Lines changed: 35 additions & 17 deletions

File tree

lib/graphql/schema/validator/required_validator.rb

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,42 +40,32 @@ class RequiredValidator < Validator
4040
# @param message [String]
4141
def initialize(one_of: nil, argument: nil, allow_all_hidden: nil, message: nil, **default_options)
4242
@one_of = if one_of
43-
@single_argument = false
4443
one_of
4544
elsif argument
46-
@single_argument = true
4745
[ argument ]
4846
else
4947
raise ArgumentError, "`one_of:` or `argument:` must be given in `validates required: {...}`"
5048
end
51-
@allow_all_hidden = allow_all_hidden.nil? ? @single_argument : allow_all_hidden
49+
@allow_all_hidden = allow_all_hidden.nil? ? !!argument : allow_all_hidden
5250
@message = message
5351
super(**default_options)
5452
end
5553

5654
def validate(_object, context, value)
5755
fully_matched_conditions = 0
5856
partially_matched_conditions = 0
59-
if @one_of
60-
visible_keywords = context.types.arguments(@validated).map(&:keyword)
61-
visible_one_ofs = @one_of & visible_keywords
62-
if visible_one_ofs.empty?
63-
if @allow_all_hidden
64-
return nil
65-
else
66-
raise GraphQL::Error, <<~ERR
67-
#{@validated.path} validates `required: ...` but all required arguments were hidden.
6857

69-
Update your schema definition to allow the client to see some fields or skip validation by adding `required: { ..., allow_all_hidden: true }`
70-
ERR
71-
end
72-
end
73-
end
58+
visible_keywords = context.types.arguments(@validated).map(&:keyword)
59+
no_visible_conditions = true
7460

7561
if !value.nil?
7662
@one_of.each do |one_of_condition|
7763
case one_of_condition
7864
when Symbol
65+
if no_visible_conditions && visible_keywords.include?(one_of_condition)
66+
no_visible_conditions = false
67+
end
68+
7969
if value.key?(one_of_condition)
8070
fully_matched_conditions += 1
8171
end
@@ -84,6 +74,9 @@ def validate(_object, context, value)
8474
full_match = true
8575

8676
one_of_condition.each do |k|
77+
if no_visible_conditions && visible_keywords.include?(k)
78+
no_visible_conditions = false
79+
end
8780
if value.key?(k)
8881
any_match = true
8982
else
@@ -106,6 +99,18 @@ def validate(_object, context, value)
10699
end
107100
end
108101

102+
if no_visible_conditions
103+
if @allow_all_hidden
104+
return nil
105+
else
106+
raise GraphQL::Error, <<~ERR
107+
#{@validated.path} validates `required: ...` but all required arguments were hidden.
108+
109+
Update your schema definition to allow the client to see some fields or skip validation by adding `required: { ..., allow_all_hidden: true }`
110+
ERR
111+
end
112+
end
113+
109114
if fully_matched_conditions == 1 && partially_matched_conditions == 0
110115
nil # OK
111116
else

spec/graphql/schema/validator/required_validator_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ class Query < GraphQL::Schema::Object
136136
argument :b, Int, required: false, always_hidden: true
137137
argument :c, Int
138138
end
139+
140+
field :four_arguments, Int, fallback_value: 4 do
141+
validates required: { one_of: [[:a, :b], :c, :d], allow_all_hidden: true}
142+
argument :a, Int, required: false, always_hidden: true
143+
argument :b, Int, required: false, always_hidden: true
144+
argument :c, Int, required: false, always_hidden: true
145+
argument :d, Int, required: false, always_hidden: true
146+
end
139147
end
140148

141149
query(Query)
@@ -157,6 +165,11 @@ class Query < GraphQL::Schema::Object
157165
assert_equal expected_message, err.message
158166
end
159167

168+
it "doesn't require hidden arguments when required as a group" do
169+
result = RequiredHiddenSchema.execute("{ fourArguments }")
170+
assert_equal 4, result["data"]["fourArguments"]
171+
end
172+
160173
it "Doesn't require hidden argument to be present" do
161174
result = RequiredHiddenSchema.execute("{ oneArgument }")
162175
assert_equal 1, result["data"]["oneArgument"]

0 commit comments

Comments
 (0)