diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex index 13cc10e5..c281184c 100644 --- a/lib/ecto/adapters/postgres/connection.ex +++ b/lib/ecto/adapters/postgres/connection.ex @@ -533,6 +533,22 @@ if Code.ensure_loaded?(Postgrex) do do: "TRUE" defp select_fields(fields, sources, query) do + # NB: append order_by fields if distinct: true specified + fields = + case query.distinct do + %Ecto.Query.ByExpr{expr: true} -> + order_by_fields = + Enum.map(query.order_bys, &Keyword.values(&1.expr)) |> List.flatten() + + Enum.reduce(order_by_fields, fields, fn + {{:., _, [{:&, [], [idx]}, _]}, _, _} = field, acc when idx > 0 -> acc ++ [field] + _field, acc -> acc + end) + + _ -> + fields + end + Enum.map_intersperse(fields, ", ", fn {:&, _, [idx]} -> case elem(sources, idx) do diff --git a/test/ecto/adapters/postgres_test.exs b/test/ecto/adapters/postgres_test.exs index 9bb21a61..b3d8b7c3 100644 --- a/test/ecto/adapters/postgres_test.exs +++ b/test/ecto/adapters/postgres_test.exs @@ -579,6 +579,52 @@ defmodule Ecto.Adapters.PostgresTest do ~s{SELECT DISTINCT ON (s0."x") s0."x" FROM "schema" AS s0 ORDER BY s0."x" DESC} end + test "distinct true with assocs" do + query = + Schema + |> join(:inner, [r], assoc(r, :permalink)) + |> order_by([r, p], [p.id]) + |> distinct([r], true) + |> select([r], r.x) + |> plan() + + assert all(query) == + ~s{SELECT DISTINCT s0."x", s1."id" FROM "schema" AS s0 INNER JOIN "schema3" AS s1 ON s1."id" = s0."y" ORDER BY s1."id"} + + query = + Schema + |> join(:inner, [r], assoc(r, :permalink)) + |> order_by([r, p], [p.id]) + |> distinct([r], true) + |> select([r], struct(r, [:x])) + |> plan() + + assert all(query) == + ~s{SELECT DISTINCT s0."x", s1."id" FROM "schema" AS s0 INNER JOIN "schema3" AS s1 ON s1."id" = s0."y" ORDER BY s1."id"} + + query = + Schema + |> join(:inner, [r], subquery(from p in Schema3, where: not is_nil(p.binary)), on: true) + |> order_by([r, p], [p.id]) + |> distinct([r], true) + |> select([r], struct(r, [:x])) + |> plan() + + assert all(query) == + ~s{SELECT DISTINCT s0."x", s1."id" FROM "schema" AS s0 INNER JOIN (SELECT ss0."id" AS "id", ss0."list1" AS "list1", ss0."list2" AS "list2", ss0."binary" AS "binary" FROM "schema3" AS ss0 WHERE (NOT (ss0."binary" IS NULL))) AS s1 ON TRUE ORDER BY s1."id"} + + query = + Schema + |> join(:inner, [r], assoc(r, :permalink)) + |> order_by([r], [r.id]) + |> distinct([r], true) + |> select([r], r.x) + |> plan() + + assert all(query) == + ~s{SELECT DISTINCT s0."x" FROM "schema" AS s0 INNER JOIN "schema3" AS s1 ON s1."id" = s0."y" ORDER BY s0."id"} + end + test "coalesce" do query = Schema |> select([s], coalesce(s.x, 5)) |> plan() assert all(query) == ~s{SELECT coalesce(s0."x", 5) FROM "schema" AS s0}