-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduced ability to convert params into custom queries and apply them to accumulator query using: * query builder functions at context level * custom query functions from schema
- Loading branch information
Showing
7 changed files
with
204 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
defmodule EctoShorts.Actions.Filters do | ||
@moduledoc """ | ||
Converts parameters into filters and applies them to the query using the query builder. | ||
""" | ||
require Logger | ||
|
||
@type query :: Ecto.Query.t() | ||
@type params :: map() | keyword() | ||
@type query_builder :: module() | ||
|
||
@doc """ | ||
Applies filters to the query based on the provided parameters. | ||
""" | ||
@spec convert_params_to_filter(query, params, query_builder) :: query | ||
def convert_params_to_filter(query, _params, nil), do: query | ||
|
||
def convert_params_to_filter(query, params, _query_builder) | ||
when not (is_map(params) or is_list(params)), | ||
do: query | ||
|
||
def convert_params_to_filter(query, params, _query_builder) | ||
when params === %{} or params === [], | ||
do: query | ||
|
||
def convert_params_to_filter(query, params, query_builder) do | ||
if supports_query_building(query_builder) do | ||
schema = EctoShorts.QueryHelpers.get_queryable(query) | ||
|
||
Enum.reduce(params, query, &reduce_filter(query_builder, schema, &1, &2)) | ||
else | ||
query | ||
end | ||
end | ||
|
||
defp reduce_filter(query_builder, schema, {filter_key, filter_value}, current_query) do | ||
if filter_key in query_builder.filters() do | ||
query_builder.build_query(schema, %{filter_key => filter_value}, current_query) | ||
else | ||
Logger.debug( | ||
"[EctoShorts] #{inspect(filter_key)} is not defined among filters in the #{inspect(query_builder)} context module" | ||
) | ||
|
||
current_query | ||
end | ||
end | ||
|
||
defp supports_query_building(query_builder) do | ||
Code.ensure_loaded?(query_builder) and | ||
function_exported?(query_builder, :build_query, 3) and | ||
function_exported?(query_builder, :filters, 0) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
defmodule EctoShorts.Actions.QueryBuilder do | ||
@moduledoc """ | ||
Behaviour for query building from a filter map. | ||
Allows calling custom query functions in schemas | ||
by defining the callback in a context. | ||
In other words, the query builder decides how and when to apply | ||
a schema's query function. | ||
Example of implementing the `build_query/3` callback in a context: | ||
```elixir | ||
defmodule YourApp.Context do | ||
@behaviour EctoShorts.Actions.QueryBuilder | ||
@impl EctoShorts.Actions.QueryBuilder | ||
def build_query(YourApp.Context.Schema, {:custom_filter, val}, queryable) do | ||
YourApp.Context.Schema.by_custom_filter(queryable, val) | ||
end | ||
end | ||
``` | ||
""" | ||
|
||
@type filter :: %{(filter_key :: atom) => filter_value :: any} | ||
@type queryable :: Ecto.Queryable.t() | ||
@type schema :: module() | ||
|
||
@doc "Adds condition to accumulator Ecto query by calling schema's function" | ||
@callback build_query(schema, filter, queryable) :: queryable | ||
@callback filters() :: list(atom) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
defmodule EctoShorts.Actions.FiltersTest do | ||
use ExUnit.Case, async: true | ||
doctest EctoShorts.Actions.Filters | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.