FatEcto: Supercharge Your Ecto Queries with Ease! ๐
View SourceDescription
FatEcto is an Elixir package designed to make your life easier when working with Ecto. It simplifies query building, filtering, sorting, pagination, and data sanitizationโso you can focus on what truly matters: building amazing applications. With FatEcto, writing complex queries becomes effortless, flexible, and powerful! ๐ช
Installation
Getting started is simple! 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.0.0"}
]
end
Then, run mix deps.get
to install the package.
Features & Modules
๐ FatEcto.Dynamics.FatBuildable โ Dynamic Filtering Made Easy
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. ๐
Usage
defmodule FatEcto.Dynamics.MyApp.HospitalFilter do
use FatEcto.Dynamics.FatBuildable,
filterable_fields: %{
"id" => ["$EQUAL", "$NOT_EQUAL"]
},
overrideable_fields: ["name", "phone"],
ignoreable_fields_values: %{
"name" => ["%%", "", [], nil],
"phone" => ["%%", "", [], nil]
}
import Ecto.Query
@impl true
# You can implement override_whereable for your custom filters
def override_whereable(_dynamics, "name", "$ILIKE", value) do
dynamic([r], ilike(fragment("(?)::TEXT", r.name), ^value))
end
def override_whereable(dynamics, _, _, _), do: dynamics
# You can do some custom processing if needed eg
def after_whereable(dynamics) do
if dynamics, do: dynamics, else: true
end
end
Example Usage
Here are some practical examples of how to use FatEcto.Dynamics.MyApp.HospitalFilter
to dynamically build queries:
Example 1: Basic Filtering by ID
# Filter hospitals with ID equal to 1
params = %{"id" => %{"$EQUAL" => 1}}
dynamics = FatEcto.Dynamics.MyApp.HospitalFilter.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)
Example 2: Case-Insensitive Name Search
# Filter hospitals with names containing "St. Mary"
params = %{"name" => %{"$ILIKE" => "%St. Mary%"}}
dynamics = FatEcto.Dynamics.MyApp.HospitalFilter.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%"))
Example 3: Combining Multiple Filters
# Filter hospitals with ID not equal to 2 AND name containing "General"
params = %{
"id" => %{"$NOT_EQUAL" => 2},
"name" => %{"$ILIKE" => "%General%"}
}
dynamics = FatEcto.Dynamics.MyApp.HospitalFilter.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%"))
Example 4: Ignoring Empty or Invalid Values
# Filter hospitals with a name, but ignore empty or invalid values
params = %{"name" => %{"$ILIKE" => "%%"}} # Empty value is ignored
dynamics = FatEcto.Dynamics.MyApp.HospitalFilter.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
Example 5: Even Complex Nested conditions
# 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 examples
๐ FatEcto.FatSortable โ Effortless Sorting
Sorting 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. ๐
Usage of FatSortable
defmodule Fat.SortQuery do
import Ecto.Query
use FatEcto.FatSortable,
sortable_fields: %{"id" => "$ASC", "name" => ["$ASC", "$DESC"]},
overrideable_fields: ["custom_field"]
@impl true
def override_sortable(query, field, operator) do
case {field, operator} do
{"custom_field", "$ASC"} ->
from(q in query, order_by: [asc: fragment("?::jsonb->>'custom_field'", q)])
_ ->
query
end
end
end
๐ FatEcto.FatPaginator โ Paginate Like a Pro
No more hassle with pagination! FatPaginator helps you paginate Ecto queries efficiently, keeping your APIs snappy and responsive.
Usage of FatPaginator
defmodule Fat.MyPaginator do
use FatEcto.FatPaginator, repo: Fat.Repo
# Add custom pagination functions here
end
๐ FatEcto.FatDataSanitizer โ Clean & Structured Data
Messy data? Not anymore! DataSanitizer
helps you sanitize records and transform them into structured, clean views effortlessly. Keep your data tidy and consistent. ๐ฏ
Usage of FatDataSanitizer
defmodule Fat.MySanitizer do
use FatEcto.FatDataSanitizer
# Define your custom sanitization functions here
end
โก FatEcto Utilities โ Small Helpers, Big Impact
FatEcto also comes with a set of handy utility functions to streamline your workflow:
# Check if a map contains all required keys
FatEcto.Utils.Map.has_all_keys?(%{a: 1, b: 2}, [:a, :b])
# Ensure a map contains only allowed keys
FatEcto.Utils.Map.contain_only_allowed_keys?(%{a: 1, c: 3}, [:a, :b])
๐ Contributing
We love contributions! If youโd like to improve FatEcto, submit an issue or pull request. Letโs build something amazing together! ๐ฅ
๐ License
FatEcto is released under the MIT License.
๐ See the full documentation at HexDocs for more details.