Repository: elixir-ecto/ecto
Pull request #2445 (2018-02-23 16:22:36)

Include `:as` in inspected queries
Refs #2389 

I have (re)introduced `:as` attribute in `JoinExpr` struct for convenience of converting expressions on inspect. I'm not too happy with the way the `as` expression is put in the list in `Inspect.join` but couldn't think of a better way ATM that wouldn't hinder the readability even further.


Patch:
diff --git a/lib/ecto/query.ex b/lib/ecto/query.ex
index a3b93f77..6e363adc 100644
--- a/lib/ecto/query.ex
+++ b/lib/ecto/query.ex
@@ -332,7 +332,7 @@ defmodule Ecto.Query do
 
   defmodule JoinExpr do
     @moduledoc false
-    defstruct [:qual, :source, :on, :file, :line, :assoc, :ix, params: []]
+    defstruct [:qual, :source, :on, :file, :line, :assoc, :as, :ix, params: []]
   end
 
   defmodule Tagged do
diff --git a/lib/ecto/query/builder/join.ex b/lib/ecto/query/builder/join.ex
index 255473b7..734c5da3 100644
--- a/lib/ecto/query/builder/join.ex
+++ b/lib/ecto/query/builder/join.ex
@@ -178,7 +178,7 @@ defmodule Ecto.Query.Builder.Join do
     join =
       quote do
         %JoinExpr{qual: unquote(join_qual), source: unquote(join_source),
-                  assoc: unquote(join_assoc), file: unquote(env.file),
+                  assoc: unquote(join_assoc), as: unquote(as), file: unquote(env.file),
                   line: unquote(env.line), params: unquote(join_params),
                   on: %QueryExpr{expr: unquote(on_expr), params: unquote(on_params),
                                  line: unquote(env.line), file: unquote(env.file)}}
@@ -219,7 +219,7 @@ defmodule Ecto.Query.Builder.Join do
     {on_expr, on_params, on_file, on_line} =
       Ecto.Query.Builder.Filter.filter!(:on, query, expr, count_bind, file, line)
 
-    join = %JoinExpr{qual: join_qual, source: join_source, assoc: join_assoc,
+    join = %JoinExpr{qual: join_qual, source: join_source, assoc: join_assoc, as: as,
                      file: file, line: line, params: join_params,
                      on: %QueryExpr{expr: on_expr, params: on_params,
                                     line: on_line, file: on_file}}
diff --git a/lib/ecto/query/inspect.ex b/lib/ecto/query/inspect.ex
index 307690ac..4c7e3144 100644
--- a/lib/ecto/query/inspect.ex
+++ b/lib/ecto/query/inspect.ex
@@ -89,19 +89,19 @@ defimpl Inspect, for: Ecto.Query do
     |> Enum.flat_map(fn {expr, ix} -> join(expr, elem(names, expr.ix || ix + 1), names) end)
   end
 
-  defp join(%JoinExpr{qual: qual, assoc: {ix, right}}, name, names) do
+  defp join(%JoinExpr{qual: qual, assoc: {ix, right}, as: as}, name, names) do
     string = "#{name} in assoc(#{elem(names, ix)}, #{inspect right})"
-    [{join_qual(qual), string}]
+    [{join_qual(qual), string}] ++ kw_inspect(:as, as)
   end
 
-  defp join(%JoinExpr{qual: qual, source: {:fragment, _, _} = source, on: on} = part, name, names) do
+  defp join(%JoinExpr{qual: qual, source: {:fragment, _, _} = source, on: on, as: as} = part, name, names) do
     string = "#{name} in #{expr(source, names, part)}"
-    [{join_qual(qual), string}, on: expr(on, names)]
+    [{join_qual(qual), string}] ++ kw_inspect(:as, as) ++ [on: expr(on, names)]
   end
 
-  defp join(%JoinExpr{qual: qual, source: source, on: on}, name, names) do
+  defp join(%JoinExpr{qual: qual, source: source, on: on, as: as}, name, names) do
     string = "#{name} in #{unbound_from source}"
-    [{join_qual(qual), string}, on: expr(on, names)]
+    [{join_qual(qual), string}] ++ kw_inspect(:as, as) ++ [on: expr(on, names)]
   end
 
   defp preloads([]),       do: []


Test patch:
diff --git a/test/ecto/query/inspect_test.exs b/test/ecto/query/inspect_test.exs
index e91f53e0..256af560 100644
--- a/test/ecto/query/inspect_test.exs
+++ b/test/ecto/query/inspect_test.exs
@@ -90,6 +90,17 @@ defmodule Ecto.Query.InspectTest do
            ~s{from p in Inspect.Post, join: c in ^#Ecto.Query<from c in Inspect.Comment, where: true>, on: p.id == c.id}
   end
 
+  test "as" do
+    assert i(from(x in Post, join: y in Comment, as: :comment, on: x.id == y.id)) ==
+      ~s{from p in Inspect.Post, join: c in Inspect.Comment, as: :comment, on: p.id == c.id}
+
+    assert i(from(x in Post, inner_join: y in fragment("foo ? and ?", x.id, ^1), as: :foo, on: y.id == x.id)) ==
+      ~s{from p in Inspect.Post, join: f in fragment("foo ? and ?", p.id, ^1), as: :foo, on: f.id == p.id}
+
+    assert i(from(x in Post, join: y in subquery(Comment), as: :comment, on: x.id == y.id)) ==
+      ~s{from p in Inspect.Post, join: c in subquery(from c in Inspect.Comment), as: :comment, on: p.id == c.id}
+  end
+
   test "where" do
     assert i(from(x in Post, where: x.foo == x.bar, where: true)) ==
            ~s{from p in Inspect.Post, where: p.foo == p.bar, where: true}
diff --git a/test/ecto/query_test.exs b/test/ecto/query_test.exs
index cfb5eb26..83b4cbfd 100644
--- a/test/ecto/query_test.exs
+++ b/test/ecto/query_test.exs
@@ -256,7 +256,7 @@ defmodule Ecto.QueryTest do
         |> where([comment: c], c.id == 0)
 
       assert inspect(query) ==
-        ~s[#Ecto.Query<from p in \"posts\", join: c in \"comments\", on: true, where: c.id == 0>]
+        ~s[#Ecto.Query<from p in \"posts\", join: c in \"comments\", as: :comment, on: true, where: c.id == 0>]
     end
 
     test "match on binding by name with ... in the middle" do
@@ -267,7 +267,7 @@ defmodule Ecto.QueryTest do
         |> where([p, ..., authors: a], a.id == 0)
 
       assert inspect(query) ==
-        ~s[#Ecto.Query<from p in \"posts\", join: c in \"comments\", on: true, join: a in \"authors\", on: true, where: a.id == 0>]
+        ~s[#Ecto.Query<from p in \"posts\", join: c in \"comments\", on: true, join: a in \"authors\", as: :authors, on: true, where: a.id == 0>]
     end
 
     test "referring to non-existing binding" do