EctoFilter v0.2.0 EctoFilter behaviour View Source
Aims in building database queries using data as filtering conditions.
Filtering conditions
Filtering conditions are represented as tuples consisting of field name, filtering rule
and value to filter by. For example, {:first_name, :equal, "Bob"}
will select all records
with the "Bob"
value of the :first_name
field.
You can use multiple conditions, in that case they will be combined in query.
Also, it is possible to build queries based on field values of associated models.
This can be achieved by condition nesting: {:organization, nil, [{:name, :like, "acme"}]}
will
select only records with the :name
field of their associated as the :organization
entity
matching with the "acme"
value.
Operators
Every filtering condition is handled by the corresponding operator — a function which takes the Ecto query and the filtering condition and returns the query with the filtering condition applied.
Usually operators are defined as apply/4
callback implementations in the filter module.
EctoFilter includes default operators for field value comparison, array inclusion checking, matching values with pattern and filtering by values of the associated entities' fields.
Also, operators for dealing with PostgreSQL JSON/JSONB fields are available.
Extending
It is possible to implement custom filtering logic by defining custom filter modules. See examples below for more information.
Examples:
Basic filtering
iex> Repo.insert!(%User{first_name: "Bob"})
iex> Repo.insert!(%User{first_name: "Alice"})
iex> result =
...> User
...> |> EctoFilter.filter([])
...> |> Repo.all()
iex> length(result)
2
iex> Repo.insert!(%User{email: "bob@example.com"})
iex> Repo.insert!(%User{email: "alice@example.com"})
iex> result =
...> User
...> |> EctoFilter.filter([{:email, :equal, "alice@example.com"}])
...> |> Repo.all()
iex> length(result)
1
iex> hd(result).email
"alice@example.com"
Building custom filter
iex> defmodule CustomFilter do
...> use EctoFilter
...>
...> def apply(query, {:name, :full_text_search, value}, _, User) do
...> where(
...> query,
...> [..., u],
...> fragment("to_tsvector(concat_ws(' ', ?, ?)) @@ plainto_tsquery(?)", u.first_name, u.last_name, ^value)
...> )
...> end
...>
...> def apply(query, condition, type, context), do: super(query, condition, type, context)
...> end
iex> Repo.insert!(%User{first_name: "Bob", last_name: "Doe"})
iex> Repo.insert!(%User{first_name: "Alice", last_name: "Roe"})
iex> result =
...> User
...> |> CustomFilter.filter([{:name, :full_text_search, "alice roe"}])
...> |> Repo.all()
iex> length(result)
1
iex> hd(result).first_name
"Alice"
Link to this section Summary
Functions
Adds filtering conditions to the query.
Link to this section Types
condition() View Source
field_type()
View Source
field_type() :: Ecto.Type.t() | Ecto.Embedded.t() | Ecto.Association.t()
field_type() :: Ecto.Type.t() | Ecto.Embedded.t() | Ecto.Association.t()
Link to this section Functions
filter(query, conditions)
View Source
filter(query :: Ecto.Query.t(), conditions :: [condition()]) :: Ecto.Query.t()
filter(query :: Ecto.Query.t(), conditions :: [condition()]) :: Ecto.Query.t()
Adds filtering conditions to the query.
introspect(queryable, field)
View Source
introspect(queryable :: Ecto.Queryable.t(), field :: atom()) :: field_type()
introspect(queryable :: Ecto.Queryable.t(), field :: atom()) :: field_type()
Link to this section Callbacks
apply(query, condition, type, context)
View Source
apply(
query :: Ecto.Query.t(),
condition :: condition(),
type :: field_type(),
context :: Ecto.Queriable.t()
) :: Ecto.Query.t()
apply( query :: Ecto.Query.t(), condition :: condition(), type :: field_type(), context :: Ecto.Queriable.t() ) :: Ecto.Query.t()