@@ -19,11 +19,18 @@ defmodule Filtrex do
1919 defstruct type: nil , conditions: [ ] , sub_filters: [ ] , empty: false
2020
2121 @ whitelist [
22- :filter , :type , :conditions , :sub_filters ,
23- :column , :comparator , :value , :start , :end
22+ :filter ,
23+ :type ,
24+ :conditions ,
25+ :sub_filters ,
26+ :column ,
27+ :comparator ,
28+ :value ,
29+ :start ,
30+ :end
2431 ]
2532
26- @ type t :: Filtrex . t
33+ @ type t :: Filtrex . t ( )
2734
2835 @ doc """
2936 Parses a filter expression and returns an error or the parsed filter with
@@ -35,18 +42,18 @@ defmodule Filtrex do
3542 [%Filtrex.Type.Config{type: :text, keys: ~w(title comments)}]
3643 ```
3744 """
38- @ spec parse ( [ Filtrex.Type.Config . t ] , Map . t ) :: { :error , String . t } | { :ok , Filtrex . t }
45+ @ spec parse ( [ Filtrex.Type.Config . t ( ) ] , map ) :: { :error , String . t ( ) } | { :ok , Filtrex . t ( ) }
3946 def parse ( configs , map ) do
4047 with { :ok , sanitized } <- Filtrex.Params . sanitize ( map , @ whitelist ) ,
4148 { :ok , valid_structured_map } <- validate_structure ( sanitized ) ,
42- do: parse_validated_structure ( configs , valid_structured_map )
49+ do: parse_validated_structure ( configs , valid_structured_map )
4350 end
4451
4552 @ doc """
4653 Parses a filter expression, like `parse/2`. If any exception is raised when
4754 parsing the map, a `%Filtrex{empty: true}` struct will be returned.
4855 """
49- @ spec safe_parse ( [ Filtrex.Type.Config . t ] , Map . t ) :: Filtrex . t
56+ @ spec safe_parse ( [ Filtrex.Type.Config . t ( ) ] , map ) :: Filtrex . t ( )
5057 def safe_parse ( configs , map ) do
5158 try do
5259 { :ok , filter } = parse ( configs , map )
@@ -65,6 +72,7 @@ defmodule Filtrex do
6572 ```
6673 """
6774 def parse_params ( _configs , params ) when params == % { } , do: { :ok , % Filtrex { empty: true } }
75+
6876 def parse_params ( configs , params ) do
6977 with { :ok , { type , params } } <- parse_params_filter_union ( params ) ,
7078 { :ok , conditions } <- Filtrex.Params . parse_conditions ( configs , params ) ,
@@ -77,6 +85,7 @@ defmodule Filtrex do
7785 will be returned.
7886 """
7987 def safe_parse_params ( _configs , params ) when params == % { } , do: % Filtrex { empty: true }
88+
8089 def safe_parse_params ( configs , params ) do
8190 try do
8291 { :ok , filter } = parse_params ( configs , params )
@@ -98,8 +107,9 @@ defmodule Filtrex do
98107 Filtrex.query(query, filter, allow_empty: true)
99108 ```
100109 """
101- @ spec query ( Ecto.Queryable . t , Filtrex . t , Keyword . t ) :: Ecto.Query . t
110+ @ spec query ( Ecto.Queryable . t ( ) , Filtrex . t ( ) , Keyword . t ( ) ) :: Ecto.Query . t ( )
102111 def query ( queryable , filter , opts \\ [ allow_empty: true ] )
112+
103113 def query ( queryable , % Filtrex { empty: true } , opts ) do
104114 if opts [ :allow_empty ] do
105115 queryable
@@ -113,6 +123,7 @@ defmodule Filtrex do
113123 queryable
114124 |> Filtrex.AST . build_query ( filter )
115125 |> Code . eval_quoted ( [ ] , __ENV__ )
126+
116127 result
117128 end
118129
@@ -123,42 +134,53 @@ defmodule Filtrex do
123134 case map do
124135 % { filter: % { type: type } } when type not in ~w( all any none) ->
125136 { :error , "Invalid filter type '#{ type } '" }
137+
126138 % { filter: % { conditions: conditions } } when conditions == [ ] or not is_list ( conditions ) ->
127139 { :error , "One or more conditions required to filter" }
140+
128141 % { filter: % { sub_filters: sub_filters } } when not is_list ( sub_filters ) ->
129142 { :error , "Sub-filters must be a valid list of filters" }
143+
130144 validated = % { filter: params } ->
131145 sub_filters = Map . get ( params , :sub_filters , [ ] )
132- result = Enum . reduce_while ( sub_filters , { :ok , [ ] } , fn ( sub_map , { :ok , acc } ) ->
133- case validate_structure ( sub_map ) do
134- { :ok , sub_validated } -> { :cont , { :ok , acc ++ [ sub_validated ] } }
135- { :error , error } -> { :halt , { :error , error } }
136- end
137- end )
146+
147+ result =
148+ Enum . reduce_while ( sub_filters , { :ok , [ ] } , fn sub_map , { :ok , acc } ->
149+ case validate_structure ( sub_map ) do
150+ { :ok , sub_validated } -> { :cont , { :ok , acc ++ [ sub_validated ] } }
151+ { :error , error } -> { :halt , { :error , error } }
152+ end
153+ end )
154+
138155 with { :ok , validated_sub_filters } <- result ,
139- do: { :ok , put_in ( validated . filter [ :sub_filters ] , validated_sub_filters ) }
156+ do: { :ok , put_in ( validated . filter [ :sub_filters ] , validated_sub_filters ) }
157+
140158 _ ->
141159 { :error , "Invalid filter structure" }
142160 end
143161 end
144162
145163 defp parse_validated_structure ( configs , % { filter: params } ) do
146- parsed_filters = Enum . reduce_while ( params [ :sub_filters ] , { :ok , [ ] } , fn ( to_parse , { :ok , acc } ) ->
147- case parse ( configs , to_parse ) do
148- { :ok , filter } -> { :cont , { :ok , acc ++ [ filter ] } }
149- { :error , error } -> { :halt , { :error , error } }
150- end
151- end )
164+ parsed_filters =
165+ Enum . reduce_while ( params [ :sub_filters ] , { :ok , [ ] } , fn to_parse , { :ok , acc } ->
166+ case parse ( configs , to_parse ) do
167+ { :ok , filter } -> { :cont , { :ok , acc ++ [ filter ] } }
168+ { :error , error } -> { :halt , { :error , error } }
169+ end
170+ end )
171+
152172 with { :ok , filters } <- parsed_filters ,
153- do: parse_conditions ( configs , params [ :type ] , params [ :conditions ] )
154- |> parse_condition_results ( params [ :type ] , filters )
173+ do:
174+ parse_conditions ( configs , params [ :type ] , params [ :conditions ] )
175+ |> parse_condition_results ( params [ :type ] , filters )
155176 end
156177
157178 defp parse_conditions ( configs , type , conditions ) do
158- Enum . reduce ( conditions , % { errors: [ ] , conditions: [ ] } , fn ( map , acc ) ->
179+ Enum . reduce ( conditions , % { errors: [ ] , conditions: [ ] } , fn map , acc ->
159180 case Filtrex.Condition . parse ( configs , Map . put ( map , :inverse , inverse_for ( type ) ) ) do
160181 { :error , error } ->
161182 update_list_in_map ( acc , :errors , error )
183+
162184 { :ok , condition } ->
163185 update_list_in_map ( acc , :conditions , condition )
164186 end
@@ -168,6 +190,7 @@ defmodule Filtrex do
168190 defp parse_condition_results ( % { errors: [ ] , conditions: conditions } , type , parsed_filters ) do
169191 { :ok , % Filtrex { type: type , conditions: conditions , sub_filters: parsed_filters } }
170192 end
193+
171194 defp parse_condition_results ( % { errors: errors } , _ , _ ) do
172195 { :error , Enum . join ( errors , ", " ) }
173196 end
@@ -176,15 +199,17 @@ defmodule Filtrex do
176199 case Map . fetch ( params , "filter_union" ) do
177200 { :ok , type } when type in ~w( all any none) ->
178201 { :ok , { type , Map . delete ( params , "filter_union" ) } }
202+
179203 :error ->
180204 { :ok , { "all" , params } }
205+
181206 _ ->
182207 { :error , "Invalid filter union" }
183208 end
184209 end
185210
186211 defp inverse_for ( "none" ) , do: true
187- defp inverse_for ( _ ) , do: false
212+ defp inverse_for ( _ ) , do: false
188213
189214 defp update_list_in_map ( map , key , value ) do
190215 values = Map . get ( map , key )
0 commit comments