I am making a search/filter feature for my app. I have a schema called Initiatives that I want to filter. I want to filter Initiative by organization and then a search query on the Initiative. What’s the best practice to do this from the context layer? Where should I define functions that only return queries?
def list_initiatives do
Repo.all(Initiative)
end
All of the generated functions in the context layer call directly into the repo, so by the time the function returns, I can’t modify the query without executing another one.
I’d like to do something like below, but the standard seems to be not to expose ecto queries directly to the web layer. It would be easy if I could define a few functions that return a query and accept a query and then execute it with Repo.all in the liveview. How do I do this idiomatically?
And have all of the logic inside the context. This allows the LiveView to focus on UI concerns and makes it easier to test the different search keywords.
In any case, you may still want to compose. You can still have your original code in the context:
Ah I see. I went back through some code from a book I read, and they are keeping queries in a module “after” the schema module. What do you think of this approach?
It would be something like “lib/app/initiatives/initiative/query.ex” and the contents would have a bunch of queries:
defmodule App.Initiatives.Initiative.Query do
def base, do: App.Initiatives.Initiative
def by_organization(query \\ base(), organization) do
from i in query, where: ^organization.id == i.organization_id
end
end
It really doesn’t matter as far as running the code goes. Structure it in the way that you and your team find intuitive. These things are mostly preferences and rarely carry any real weight.