@@ -8,27 +8,10 @@ defmodule EpochtalkServerWeb.Helpers.Validate do
88
99 @ doc """
1010 Ensure that `keys` provided in list are mutually exclusive within `attrs` map.
11-
12- ## Example
13- iex> alias EpochtalkServerWeb.Helpers.Validate
14- iex> attrs = %{"page" => 1}
15- iex> Validate.mutually_exclusive!(attrs, ["page", "start"])
16- :ok
17- iex> attrs = %{"start" => 1}
18- iex> Validate.mutually_exclusive!(attrs, ["page", "start"])
19- :ok
20- iex> Validate.mutually_exclusive!(attrs, ["start"])
21- :ok
22- iex> attrs = %{"page" => 1, "start" => 1}
23- iex> Validate.mutually_exclusive!(attrs, ["page", "start"])
24- ** (EpochtalkServerWeb.CustomErrors.InvalidPayload) The following payload parameters cannot be passed at the same time: page, start
2511 """
2612 @ spec mutually_exclusive! ( attrs :: map , keys :: [ String . t ( ) ] ) :: :ok | no_return
2713 def mutually_exclusive! ( attrs , keys ) when is_map ( attrs ) and is_list ( keys ) do
28- contains_all_keys =
29- Enum . reduce ( keys , true , fn key , acc -> acc && Map . has_key? ( attrs , key ) end )
30-
31- if contains_all_keys && length ( keys ) > 1 ,
14+ if map_contains_any_two_keys_in_list? ( attrs , keys ) ,
3215 do:
3316 raise ( InvalidPayload ,
3417 message:
@@ -152,6 +135,29 @@ defmodule EpochtalkServerWeb.Helpers.Validate do
152135 end
153136 end
154137
138+ # entrypoint
139+ defp map_contains_any_two_keys_in_list? ( map , list ) ,
140+ do: map_contains_any_two_keys_in_list? ( map , list , false )
141+
142+ # if map is empty, return false
143+ defp map_contains_any_two_keys_in_list? ( map , _list , _key_found? ) when map == % { } , do: false
144+ # if list is empty, return false
145+ defp map_contains_any_two_keys_in_list? ( _map , [ ] , _key_found? ) , do: false
146+ # if key_found? is false
147+ defp map_contains_any_two_keys_in_list? ( map , [ key | keys ] = _list , false = _key_found? ) do
148+ # check next key with updated key_found?
149+ map_contains_any_two_keys_in_list? ( map , keys , Map . has_key? ( map , key ) )
150+ end
151+
152+ # if key_found? is true
153+ defp map_contains_any_two_keys_in_list? ( map , [ key | keys ] = _list , true = key_found? ) do
154+ # if current key is in map, return true
155+ if Map . has_key? ( map , key ) ,
156+ do: true ,
157+ # otherwise, check next key
158+ else: map_contains_any_two_keys_in_list? ( map , keys , key_found? )
159+ end
160+
155161 defp to_bool ( str , opts ) do
156162 case str do
157163 "true" -> true
0 commit comments