@@ -4,7 +4,7 @@ defmodule Composite do
44
55 It allows getting rid of some boilerplate when building a query based on input parameters.
66
7- params = %{query_string : "John Doe"}
7+ params = %{search_query : "John Doe"}
88
99 User
1010 |> where(active: true)
@@ -21,7 +21,12 @@ defmodule Composite do
2121 You're able to use Composite with any Elixir term, as it is just an advanced wrapper around `Enum.reduce/3`.
2222 """
2323 import Kernel , except: [ apply: 3 ]
24- defstruct param_definitions: [ ] , dep_definitions: % { } , params: nil , input_query: nil
24+
25+ defstruct param_definitions: [ ] ,
26+ dep_definitions: % { } ,
27+ params: nil ,
28+ input_query: nil ,
29+ required_deps: [ ]
2530
2631 @ type dependency_name :: atom ( )
2732 @ type dependencies ::
@@ -36,14 +41,15 @@ defmodule Composite do
3641 @ type dependency_option :: { :requires , dependencies ( ) }
3742 @ type param_path_item :: any ( )
3843 @ type apply_fun ( query ) :: ( query , value :: any ( ) -> query ) | ( query -> query )
39- @ type load_dependency ( query ) :: ( query -> query )
44+ @ type load_dependency ( query ) :: ( query -> query ) | ( query , params ( ) -> query )
4045 @ type params :: Access . t ( )
4146 @ type t ( query ) :: % __MODULE__ {
4247 param_definitions: [ { [ param_path_item ( ) ] , apply_fun ( query ) , [ param_option ( query ) ] } ] ,
4348 dep_definitions: % {
4449 optional ( dependency_name ( ) ) => [ { load_dependency ( query ) , [ dependency_option ( ) ] } ]
4550 } ,
46- params: params ( ) ,
51+ required_deps: [ dependency_name ( ) ] ,
52+ params: params ( ) | nil ,
4753 input_query: query
4854 }
4955
@@ -176,7 +182,7 @@ defmodule Composite do
176182 |> Composite.param(
177183 :search,
178184 fn
179- query, "+" <> _ = phone_number -> where(query, [phones: phones] phones.number == ^phone_number)
185+ query, "+" <> _ = phone_number -> where(query, [phones: phones], phones.number == ^phone_number)
180186 query, query_string -> where(query, [records], ilike(records.text, ^query_string))
181187 end,
182188 requires: fn
@@ -186,6 +192,8 @@ defmodule Composite do
186192 )
187193 |> Composite.dependency(:phone, &join(&1, :inner, [records], phones in assoc(records, :phone), as: :phones))
188194
195+ When `loader` function has arity 2, then all parameters are passed in the second argument.
196+
189197 ### Options
190198
191199 * `:requires` - allows to set dependencies for current dependency.
@@ -199,7 +207,7 @@ defmodule Composite do
199207 func ,
200208 opts \\ [ ]
201209 )
202- when is_function ( func , 1 ) do
210+ when is_function ( func , 1 ) or is_function ( func , 2 ) do
203211 ensure_unknown_opts_absent! ( opts , [ :requires ] )
204212 % { composite | dep_definitions: Map . put ( dep_definitions , dependency , { func , opts } ) }
205213 end
@@ -233,11 +241,19 @@ defmodule Composite do
233241 |> set_once! ( :input_query , input_query )
234242 |> set_once! ( :params , params )
235243
244+ { query , loaded_deps } =
245+ load_dependencies (
246+ composite . input_query ,
247+ composite . params ,
248+ composite . dep_definitions ,
249+ MapSet . new ( ) ,
250+ composite . required_deps
251+ )
252+
236253 { query , _loaded_deps } =
237254 composite . param_definitions
238255 |> Enum . reverse ( )
239- |> Enum . reduce ( { composite . input_query , MapSet . new ( ) } , fn { path , func , opts } ,
240- { query , loaded_deps } ->
256+ |> Enum . reduce ( { query , loaded_deps } , fn { path , func , opts } , { query , loaded_deps } ->
241257 value = get_in ( composite . params , path )
242258
243259 ignore? = Keyword . get ( opts , :ignore? , & empty_value? / 1 )
@@ -252,7 +268,13 @@ defmodule Composite do
252268 required_deps = opts |> Keyword . get ( :ignore_requires ) |> List . wrap ( )
253269
254270 { query , loaded_deps } =
255- load_dependencies ( query , composite . dep_definitions , loaded_deps , required_deps )
271+ load_dependencies (
272+ query ,
273+ composite . params ,
274+ composite . dep_definitions ,
275+ loaded_deps ,
276+ required_deps
277+ )
256278
257279 { on_ignore . ( query ) , loaded_deps }
258280 else
@@ -266,7 +288,13 @@ defmodule Composite do
266288 |> List . wrap ( )
267289
268290 { query , loaded_deps } =
269- load_dependencies ( query , composite . dep_definitions , loaded_deps , required_deps )
291+ load_dependencies (
292+ query ,
293+ composite . params ,
294+ composite . dep_definitions ,
295+ loaded_deps ,
296+ required_deps
297+ )
270298
271299 case func do
272300 func when is_function ( func , 1 ) -> { func . ( query ) , loaded_deps }
@@ -278,6 +306,19 @@ defmodule Composite do
278306 query
279307 end
280308
309+ @ doc """
310+ Forces loading dependency even if it is not required by `params`.
311+ """
312+ @ spec force_require ( t ( query ) , dependency_name ( ) | [ dependency_name ( ) ] ) :: t ( query )
313+ when query: any ( )
314+ def force_require (
315+ % __MODULE__ { required_deps: required_deps } = composite ,
316+ dependency_or_dependencies
317+ ) do
318+ dependencies = List . wrap ( dependency_or_dependencies )
319+ % __MODULE__ { composite | required_deps: dependencies ++ required_deps }
320+ end
321+
281322 defp empty_value? ( value ) do
282323 value in [ nil , "" , [ ] , % { } ]
283324 end
@@ -306,11 +347,11 @@ defmodule Composite do
306347 end
307348 end
308349
309- defp load_dependencies ( query , _deps_definitions , loaded_deps , [ ] = _required_deps ) do
350+ defp load_dependencies ( query , _params , _deps_definitions , loaded_deps , [ ] = _required_deps ) do
310351 { query , loaded_deps }
311352 end
312353
313- defp load_dependencies ( query , deps_definitions , loaded_deps , required_deps ) do
354+ defp load_dependencies ( query , params , deps_definitions , loaded_deps , required_deps ) do
314355 deps_to_load = required_deps |> MapSet . new ( ) |> MapSet . difference ( loaded_deps )
315356
316357 { query , loaded_deps } =
@@ -327,9 +368,15 @@ defmodule Composite do
327368 required_deps = opts |> Keyword . get ( :requires ) |> List . wrap ( )
328369
329370 { query , loaded_deps } =
330- query |> load_dependencies ( deps_definitions , loaded_deps , required_deps )
371+ load_dependencies ( query , params , deps_definitions , loaded_deps , required_deps )
372+
373+ query =
374+ case loader do
375+ loader when is_function ( loader , 1 ) -> loader . ( query )
376+ loader when is_function ( loader , 2 ) -> loader . ( query , params )
377+ end
331378
332- { loader . ( query ) , loaded_deps }
379+ { query , loaded_deps }
333380 end )
334381
335382 { query , MapSet . union ( loaded_deps , deps_to_load ) }
0 commit comments