A very simple macro to implement scoped associations in your schemas.
The package can be installed by adding scoped_associations
to your list of dependencies in mix.exs
:
def deps do
[{:scoped_associations, github: "jgarcia/scoped_associations", app: false}]
end
Consider the following schema.
defmodule Customer do
...
schema "customers" do
...
has_many :purchases, Purchase
has_many :reviews, Review
...
end
end
Supose that in a page you want to display the customer's last purchase and first review.
Modifying your schema like this
defmodule Customer do
...
use ScopedAssociations
schema "customers" do
...
end
has_one_scoped :last_purchase, schema: Purchase, foreign_key: "customer_id", scope: :last_purchase
has_one_scoped :first_review, schema: Review, foreign_key: "customer_id", scope: :first_review
def last_purchase do
from p in Purchase,
join: f in fragment("SELECT MAX(id) AS id, customer_id FROM purchases GROUP BY customer_id"),
on: p.id == f.id
end
def first_review do
from r in Review,
join: f in fragment("SELECT MIN(id) AS id, customer_id FROM reviews GROUP BY customer_id"),
on: r.id == f.id
end
end
To load those relations you can use the include function along with list of relations to load
customers = Repo.all(Customer)
|> Customer.include([:last_purchase, :first_review])
Please keep in mind that this is a first draft, there is some code duplication that I will address in the near future as well as some improvements to the api.
- Add tests with ecto schemas
- Remove code duplication in favor of reusable functions to reduce the number functions defined by the macro
- Figure out some edge cases
- Publish in hex