EctoFlex
EctoFlex is a flexible way to query schemas.
It's in very early development and is not yet ready for production use, missing a lot of features that will be added hopefully fairly quickly.
PRs are welcome.
Installation
def deps do
[
{:ecto_flex, "~> 0.3.0"}
]
end
This function takes an Ecto.Queryable
, usually an Ecto.Schema
, as the first argument, and a map as a second argument, and returns an Ecto.Query
.
The second argument could take the following form:
%{
"field1" => %{"filter1" => value1},
"field2" => %{"filter2" => value2},
"@association" => %{"assoc_field1" => %{"filter3" => value3}},
}
The map must adhere to the following rules:
- Keys must be strings.
- Keys must map to schema fields, unless they have special meanings to EctoFlex (see below for more).
- Values are maps themselves.
- Each value map key must be one of the predefined "filters" (see below for more).
- Association keys start with
@
followed by the association name defined in the schema. - Association key values must adhere to this list (see point 1).
Sepcial Keys
Aside from schema fields, EctoFlex treats some keys in a special way. Currently only 1 special key is supported:
-
flex
- When EctoFlex finds the
flex
key, it looks in the value (a map) for some configurations. For example, the following will get the first 10 records ordered by name ascendingly:%{"flex" => %{"page" => 1, "per_page" => 10, "order" => "name"}}
- So far, there are only 3 supported
flex
configurations:page
,per_page
, andorder
. - To order descendingly, prefix the field name with a minus sign:
%{"order" => "-name"}
- When EctoFlex finds the
Filters
Supported filters are:
- is:
%{"age" => %{"is" => 35}}
- contains:
%{"name" => %{"contains" => "tina"}}
- greater_than:
%{"birthdate" => %{"greater_than" => yesterday}}
- less_than:
%{"age" => %{"less_than" => 21}}
Filter values could be either a single value or a list. If a list is provided, the values in the list will be OR
d together:
The filter
%{"age" => %{"is" => [20, 21]}}
means: Get me all records with "age" being either 20 or 21.
Associations
Assuming we have a %User{}
which has_many :addresses
, we could filter users by address:
%{"@addresses" => %{"city" => %{"is" => "Tokyo"}}}
This filter means: get me all users who have at least one address in Tokyo.
Complete example
alias EctoFlex.FlexQuery
alias MyApp.Schemas.User
alias MyApp.Repo
conditions = %{ # get me all users
"age" => %{"greater_than" => 20}, # who are older than 20 years old
"email" => %{"contains" => "@gmail.com"}, # who registered with their gmail account
"@posts" => %{"inserted_at" => %{"greater_than" => yesterday}}, # who created a post today
"flex" => %{"order" => "-age", "page" => 1, "per_page" => 10}, # the top 10, ordered by age, oldest to youngest.
}
FlexQuery.filter(User, conditions) |> Repo.all()