Select_merge with dynamic fields on a left outer join

Are translated_fields really dynamic?
If no, then I’d recommend to use simpler select expression:

|> select([product: p, translation: t], %{p | name: coalesce(t.name, p.name)})

actually, multiple select_merge can be composed:

translated_fields
|> Enum.reduce(query, fn
  # it would be great to have something like this:
  # field, query ->
  #   query |> select_merge([product: p, translation:t], %{^field => coalesce(field(t, ^field), field(p, ^field))})
  # but dynamic atoms are not supported as a field key
  :name, query ->
    query
    |> select_merge([product: p, translation: t], %{name: coalesce(t.name, p.name)})
  :description, query ->
    query
    |> select_merge([product: p, translation: t], %{description: coalesce(t.description, p.description)})
end)