Skip to content

Commit

Permalink
support subqueries in order_by, group_by, distinct, windows
Browse files Browse the repository at this point in the history
ecto_sql support for elixir-ecto#607
  • Loading branch information
zachdaniel committed May 23, 2024
1 parent 8e19684 commit 487b45f
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 18 deletions.
12 changes: 6 additions & 6 deletions lib/ecto/adapters/myxql/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ if Code.ensure_loaded?(MyXQL) do
## Query

@parent_as __MODULE__
alias Ecto.Query.{BooleanExpr, JoinExpr, QueryExpr, WithExpr}
alias Ecto.Query.{BooleanExpr, ByExpr, JoinExpr, QueryExpr, WithExpr}

@impl true
def all(query, as_prefix \\ []) do
Expand Down Expand Up @@ -319,10 +319,10 @@ if Code.ensure_loaded?(MyXQL) do
end

defp distinct(nil, _sources, _query), do: []
defp distinct(%QueryExpr{expr: true}, _sources, _query), do: "DISTINCT "
defp distinct(%QueryExpr{expr: false}, _sources, _query), do: []
defp distinct(%ByExpr{expr: true}, _sources, _query), do: "DISTINCT "
defp distinct(%ByExpr{expr: false}, _sources, _query), do: []

defp distinct(%QueryExpr{expr: exprs}, _sources, query) when is_list(exprs) do
defp distinct(%ByExpr{expr: exprs}, _sources, query) when is_list(exprs) do
error!(query, "DISTINCT with multiple columns is not supported by MySQL")
end

Expand Down Expand Up @@ -511,7 +511,7 @@ if Code.ensure_loaded?(MyXQL) do
defp group_by(%{group_bys: group_bys} = query, sources) do
[
" GROUP BY "
| Enum.map_intersperse(group_bys, ", ", fn %QueryExpr{expr: expr} ->
| Enum.map_intersperse(group_bys, ", ", fn %ByExpr{expr: expr} ->
Enum.map_intersperse(expr, ", ", &expr(&1, sources, query))
end)
]
Expand Down Expand Up @@ -549,7 +549,7 @@ if Code.ensure_loaded?(MyXQL) do
defp order_by(%{order_bys: order_bys} = query, sources) do
[
" ORDER BY "
| Enum.map_intersperse(order_bys, ", ", fn %QueryExpr{expr: expr} ->
| Enum.map_intersperse(order_bys, ", ", fn %ByExpr{expr: expr} ->
Enum.map_intersperse(expr, ", ", &order_by_expr(&1, sources, query))
end)
]
Expand Down
12 changes: 6 additions & 6 deletions lib/ecto/adapters/postgres/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ if Code.ensure_loaded?(Postgrex) do
end

@parent_as __MODULE__
alias Ecto.Query.{BooleanExpr, JoinExpr, QueryExpr, WithExpr}
alias Ecto.Query.{BooleanExpr, ByExpr, JoinExpr, QueryExpr, WithExpr}

@impl true
def all(query, as_prefix \\ []) do
Expand Down Expand Up @@ -551,11 +551,11 @@ if Code.ensure_loaded?(Postgrex) do
end

defp distinct(nil, _, _), do: {[], []}
defp distinct(%QueryExpr{expr: []}, _, _), do: {[], []}
defp distinct(%QueryExpr{expr: true}, _, _), do: {" DISTINCT", []}
defp distinct(%QueryExpr{expr: false}, _, _), do: {[], []}
defp distinct(%ByExpr{expr: []}, _, _), do: {[], []}
defp distinct(%ByExpr{expr: true}, _, _), do: {" DISTINCT", []}
defp distinct(%ByExpr{expr: false}, _, _), do: {[], []}

defp distinct(%QueryExpr{expr: exprs}, sources, query) do
defp distinct(%ByExpr{expr: exprs}, sources, query) do
{[
" DISTINCT ON (",
Enum.map_intersperse(exprs, ", ", fn {_, expr} -> expr(expr, sources, query) end),
Expand Down Expand Up @@ -772,7 +772,7 @@ if Code.ensure_loaded?(Postgrex) do
[
" GROUP BY "
| Enum.map_intersperse(group_bys, ", ", fn
%QueryExpr{expr: expr} ->
%ByExpr{expr: expr} ->
Enum.map_intersperse(expr, ", ", &expr(&1, sources, query))
end)
]
Expand Down
12 changes: 6 additions & 6 deletions lib/ecto/adapters/tds/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ if Code.ensure_loaded?(Tds) do

@parent_as __MODULE__
alias Ecto.Query
alias Ecto.Query.{BooleanExpr, JoinExpr, QueryExpr, WithExpr}
alias Ecto.Query.{BooleanExpr, ByExpr, JoinExpr, QueryExpr, WithExpr}

@impl true
def all(query, as_prefix \\ []) do
Expand Down Expand Up @@ -390,10 +390,10 @@ if Code.ensure_loaded?(Tds) do
end

defp distinct(nil, _sources, _query), do: []
defp distinct(%QueryExpr{expr: true}, _sources, _query), do: "DISTINCT "
defp distinct(%QueryExpr{expr: false}, _sources, _query), do: []
defp distinct(%ByExpr{expr: true}, _sources, _query), do: "DISTINCT "
defp distinct(%ByExpr{expr: false}, _sources, _query), do: []

defp distinct(%QueryExpr{expr: exprs}, _sources, query) when is_list(exprs) do
defp distinct(%ByExpr{expr: exprs}, _sources, query) when is_list(exprs) do
error!(
query,
"DISTINCT with multiple columns is not supported by MsSQL. " <>
Expand Down Expand Up @@ -584,7 +584,7 @@ if Code.ensure_loaded?(Tds) do
defp group_by(%{group_bys: group_bys} = query, sources) do
[
" GROUP BY "
| Enum.map_intersperse(group_bys, ", ", fn %QueryExpr{expr: expr} ->
| Enum.map_intersperse(group_bys, ", ", fn %ByExpr{expr: expr} ->
Enum.map_intersperse(expr, ", ", &expr(&1, sources, query))
end)
]
Expand All @@ -595,7 +595,7 @@ if Code.ensure_loaded?(Tds) do
defp order_by(%{order_bys: order_bys} = query, sources) do
[
" ORDER BY "
| Enum.map_intersperse(order_bys, ", ", fn %QueryExpr{expr: expr} ->
| Enum.map_intersperse(order_bys, ", ", fn %ByExpr{expr: expr} ->
Enum.map_intersperse(expr, ", ", &order_by_expr(&1, sources, query))
end)
]
Expand Down
27 changes: 27 additions & 0 deletions test/ecto/adapters/postgres_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,10 @@ defmodule Ecto.Adapters.PostgresTest do

query = Schema |> distinct(false) |> select([r], {r.x, r.y}) |> plan()
assert all(query) == ~s{SELECT s0."x", s0."y" FROM "schema" AS s0}

query = (from row in Schema, as: :r, select: row.x) |> distinct(exists(from other_schema in "schema", where: other_schema.x == parent_as(:r).x, select: [other_schema.x])) |> plan()

assert all(query) == ~s{SELECT DISTINCT ON (exists((SELECT ss0."x" AS "result" FROM "schema" AS ss0 WHERE (ss0."x" = s0."x")))) s0."x" FROM "schema" AS s0}
end

test "distinct with order by" do
Expand Down Expand Up @@ -618,6 +622,14 @@ defmodule Ecto.Adapters.PostgresTest do
assert all(query) ==
~s{SELECT s0."x" FROM "schema" AS s0 ORDER BY s0."x" ASC NULLS FIRST, s0."y" DESC NULLS FIRST}

query =
(from row in Schema, as: :r)
|> order_by(asc: exists(from other_schema in "schema", where: other_schema.x == parent_as(:r).x, select: [other_schema.x]))
|> select([r], r.x)
|> plan()

assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 ORDER BY exists((SELECT ss0."x" AS "result" FROM "schema" AS ss0 WHERE (ss0."x" = s0."x")))}

query =
Schema
|> order_by([r], asc_nulls_last: r.x, desc_nulls_last: r.y)
Expand Down Expand Up @@ -1057,6 +1069,10 @@ defmodule Ecto.Adapters.PostgresTest do

query = Schema |> group_by([r], []) |> select([r], r.x) |> plan()
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0}

query = (from row in Schema, as: :r, select: row.x) |> group_by([r], exists(from other_schema in "schema", where: other_schema.x == parent_as(:r).x, select: [other_schema.x])) |> plan()

assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 GROUP BY exists((SELECT ss0."x" AS "result" FROM "schema" AS ss0 WHERE (ss0."x" = s0."x")))}
end

test "arrays and sigils" do
Expand Down Expand Up @@ -1364,6 +1380,17 @@ defmodule Ecto.Adapters.PostgresTest do
~s{SELECT s0."x" FROM "schema" AS s0 WINDOW "w" AS (PARTITION BY s0."x")}
end

test "window with subquery" do
query =
(from row in Schema, as: :r)
|> select([r], r.x)
|> windows([r], w: [order_by: exists(from other_schema in "schema", where: other_schema.x == parent_as(:r).x, select: [other_schema.x])])
|> plan

assert all(query) ==
~s{SELECT s0."x" FROM "schema" AS s0 WINDOW "w" AS (ORDER BY exists((SELECT ss0."x" AS "result" FROM "schema" AS ss0 WHERE (ss0."x" = s0."x"))))}
end

test "two windows" do
query =
Schema
Expand Down

0 comments on commit 487b45f

Please sign in to comment.