FatEcto is an Elixir package designed to make your life easier when working with Ecto. It simplifies query building, filtering, sorting, and paginationβso you can focus on what truly matters: building amazing applications. With FatEcto, writing complex repeating queries becomes effortless, flexible, and powerful! πͺ
Add fat_ecto to your list of dependencies in mix.exs:
def deps do
[
# Check https://hexdocs.pm/fat_ecto for the latest version
{:fat_ecto, "~> 1.2"}
]
endThen, run mix deps.get to install the package.
Tired of writing repetitive query filters? The Whereable module lets you dynamically filter records using flexible conditions passed from your web or mobile clientsβwith little to no effort! And the best part? You stay in control. π
defmodule FatEcto.HospitalDynamicsBuilder do
use FatEcto.Query.Dynamics.Buildable,
filterable: [
id: ["$EQUAL", "$NOT_EQUAL"]
],
overrideable: ["name", "phone"],
ignoreable: [
name: ["%%", "", [], nil],
phone: ["%%", "", [], nil]
]
import Ecto.Query
@impl true
# You can implement override_buildable for your custom filters
def override_buildable("name", "$ILIKE", value) do
dynamic([r], ilike(fragment("(?)::TEXT", r.name), ^value))
end
def override_buildable(_field, _operator, _value), do: nil
endHere are some practical examples of how to use FatEcto.HospitalDynamicsBuilder to dynamically build queries:
# Filter hospitals with ID equal to 1
params = %{"id" => %{"$EQUAL" => 1}}
dynamics = FatEcto.HospitalDynamicsBuilder.build(params)
# Use the dynamics in a query
import Ecto.Query
query = where(FatEcto.FatHospital, ^dynamics)
# Resulting query:
# from(h in FatEcto.FatHospital, where: h.id == 1)# Filter hospitals with names containing "St. Mary"
params = %{"name" => %{"$ILIKE" => "%St. Mary%"}}
dynamics = FatEcto.HospitalDynamicsBuilder.build(params)
# Use the dynamics in a query
import Ecto.Query
query = where(FatEcto.FatHospital, ^dynamics)
# Resulting query:
# from(h in FatEcto.FatHospital, where: ilike(fragment("(?)::TEXT", h.name), ^"%St. Mary%"))# Filter hospitals with ID not equal to 2 AND name containing "General"
params = %{
"id" => %{"$NOT_EQUAL" => 2},
"name" => %{"$ILIKE" => "%General%"}
}
dynamics = FatEcto.HospitalDynamicsBuilder.build(params)
# Use the dynamics in a query
import Ecto.Query
query = where(FatEcto.FatHospital, ^dynamics)
# Resulting query:
# from(h in FatEcto.FatHospital, where: h.id != 2 and ilike(fragment("(?)::TEXT", h.name), ^"%General%"))# Filter hospitals with a name, but ignore empty or invalid values
params = %{"name" => %{"$ILIKE" => "%%"}} # Empty value is ignored
dynamics = FatEcto.HospitalDynamicsBuilder.build(params)
# Use the dynamics in a query
import Ecto.Query
query = where(FatEcto.FatHospital, ^dynamics)
# Resulting query:
# from(h in FatEcto.FatHospital) # No filtering applied for name# Filter hospitals with a name, but ignore empty or invalid values
params = %{
"$OR" => [
%{
"name" => %{"$ILIKE" => "%John%"},
"$OR" => %{"rating" => %{"$GT" => 18}, "location" => "New York"}
},
%{
"start_date" => "2023-01-01",
"$AND" => [
%{"rating" => %{"$GT" => 4}},
%{"email" => "fat_ecto@example.com"}
]
}
]
}
dynamics = DoctorFilter.build(params)
# Resulting dynamic:
dynamic(
[q],
((q.location == ^"New York" or q.rating > ^18) and ilike(fragment("(?)::TEXT", q.name), ^"%John%")) or
(q.rating > ^4 and q.email == ^"fat_ecto@example.com" and q.start_date == ^"2023-01-01")
)
# You can now apply the result on where just like above examplesConfigure FatEcto to return dynamic([q], true) instead of nil when no filters are applied:
# config/config.exs
config :fat_ecto, :default_dynamic, :return_true
# Now all Buildable modules return dynamic([q], true) when filters are empty
dynamics = FatEcto.HospitalBuilder.build(%{})
# Returns: dynamic([q], true) instead of nilSorting should be simpleβand with Sortable, it is! Your frontend can send sorting parameters, and FatEcto will seamlessly generate the right sorting queries, allowing you to build powerful, customizable sorting logic without breaking a sweat. π
defmodule Fat.SortQuery do
import Ecto.Query
use FatEcto.Sort.Sortable,
sortable: [id: "$ASC", email: "*", name: ["$ASC", "$DESC"]],
overrideable: ["custom_field"]
@impl true
def override_sortable("custom_field", "$DESC") do
{:desc, dynamic([u], fragment("?->>'custom_field'", u.metadata))}
end
def override_sortable(_field, _operator), do: nil
endNo more hassle with pagination! FatPaginator helps you paginate Ecto queries efficiently, keeping your APIs snappy and responsive.
defmodule Fat.MyPaginator do
use FatEcto.Pagination.V2Paginator,
default_limit: 10,
repo: FatEcto.Repo,
max_limit: 100
endWe love contributions! If youβd like to improve FatEcto, submit an issue or pull request. Letβs build something amazing together! π₯
FatEcto is released under the MIT License.
π See the full documentation at HexDocs for more details.