It is tempting to just drop down to raw queries but then when I read about things like composable Ecto queries (https://medium.com/flatiron-labs/how-to-compose-queries-in-e...) it makes me want to stay at the higher abstraction level.
The final example in that post:
EctoCars.Car
|> EctoCars.Car.with_color("blue")
|> EctoCars.Car.with_transmission("automatic")
|> EctoCars.Car.with_engine_horse_power(200)
|> EctoCars.Repo.all()
generates very clean SQL: SELECT c0."id", c0."color", c0."vin_number", c0."specification_id"
FROM "cars" AS c0
LEFT OUTER JOIN "specifications" AS s1 ON c0."specification_id" = s1."id"
LEFT OUTER JOIN "transmissions" AS t2 ON s1."transmission_id" = t2."id"
LEFT OUTER JOIN "engines" AS e3 ON s1."engine_id" = e3."id"
WHERE (c0."color" = $1) AND (t2."type" = $2) AND (e3."horse_power" > $3)