Skip to content

Commit 2385763

Browse files
authored
Fix NOT precedence for in and is_nil (#753)
1 parent 7f7cd02 commit 2385763

2 files changed

Lines changed: 25 additions & 5 deletions

File tree

lib/ecto/adapters/postgres/connection.ex

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -953,23 +953,23 @@ if Code.ensure_loaded?(Postgrex) do
953953

954954
defp expr({:in, _, [left, right]}, sources, query) when is_list(right) do
955955
args = Enum.map_intersperse(right, ?,, &expr(&1, sources, query))
956-
[expr(left, sources, query), " IN (", args, ?)]
956+
[maybe_paren(left, sources, query), " IN (", args, ?)]
957957
end
958958

959959
defp expr({:in, _, [left, {:^, _, [ix, _]}]}, sources, query) do
960-
[expr(left, sources, query), " = ANY($", Integer.to_string(ix + 1), ?)]
960+
[maybe_paren(left, sources, query), " = ANY($", Integer.to_string(ix + 1), ?)]
961961
end
962962

963963
defp expr({:in, _, [left, %Ecto.SubQuery{} = subquery]}, sources, query) do
964-
[expr(left, sources, query), " IN ", expr(subquery, sources, query)]
964+
[maybe_paren(left, sources, query), " IN ", expr(subquery, sources, query)]
965965
end
966966

967967
defp expr({:in, _, [left, right]}, sources, query) do
968-
[expr(left, sources, query), " = ANY(", expr(right, sources, query), ?)]
968+
[maybe_paren(left, sources, query), " = ANY(", expr(right, sources, query), ?)]
969969
end
970970

971971
defp expr({:is_nil, _, [arg]}, sources, query) do
972-
[expr(arg, sources, query) | " IS NULL"]
972+
[maybe_paren(arg, sources, query) | " IS NULL"]
973973
end
974974

975975
defp expr({:not, _, [expr]}, sources, query) do

test/ecto/adapters/postgres_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,9 @@ defmodule Ecto.Adapters.PostgresTest do
831831

832832
query = "schema" |> select([r], r.x == is_nil(r.y)) |> plan()
833833
assert all(query) == ~s{SELECT s0."x" = (s0."y" IS NULL) FROM "schema" AS s0}
834+
835+
query = "schema" |> select([r], is_nil(not r.x)) |> plan()
836+
assert all(query) == ~s{SELECT (NOT (s0."x")) IS NULL FROM "schema" AS s0}
834837
end
835838

836839
test "fragments" do
@@ -1096,6 +1099,15 @@ defmodule Ecto.Adapters.PostgresTest do
10961099

10971100
assert all(query) ==
10981101
~s{SELECT ((s0."x" = $1) OR s0."x" = ANY($2)) OR (s0."x" = $3) FROM "schema" AS s0}
1102+
1103+
query = "schema" |> select([e], (not e.x) in [true, false]) |> plan()
1104+
assert all(query) == ~s{SELECT (NOT (s0."x")) IN (TRUE,FALSE) FROM "schema" AS s0}
1105+
1106+
query = "schema" |> select([e], (not e.x) in ^[true, false]) |> plan()
1107+
assert all(query) == ~s{SELECT (NOT (s0."x")) = ANY($1) FROM "schema" AS s0}
1108+
1109+
query = "schema" |> select([e], (not e.x) in e.w) |> plan()
1110+
assert all(query) == ~s{SELECT (NOT (s0."x")) = ANY(s0."w") FROM "schema" AS s0}
10991111
end
11001112

11011113
test "in subquery" do
@@ -1106,6 +1118,14 @@ defmodule Ecto.Adapters.PostgresTest do
11061118
~s{SELECT c0."x" FROM "comments" AS c0 } <>
11071119
~s{WHERE (c0."post_id" IN (SELECT sp0."id" FROM "posts" AS sp0 WHERE (sp0."title" = $1)))}
11081120

1121+
query =
1122+
"comments"
1123+
|> select([c], (not c.published) in subquery(from(p in "posts", select: p.published)))
1124+
|> plan()
1125+
1126+
assert all(query) ==
1127+
~s{SELECT (NOT (c0."published")) IN (SELECT sp0."published" AS "published" FROM "posts" AS sp0) FROM "comments" AS c0}
1128+
11091129
posts = subquery("posts" |> where(title: parent_as(:comment).subtitle) |> select([p], p.id))
11101130

11111131
query =

0 commit comments

Comments
 (0)