1defmodule Ecto.Query.Builder.OrderByTest do
2  use ExUnit.Case, async: true
3
4  import Ecto.Query.Builder.OrderBy
5  doctest Ecto.Query.Builder.OrderBy
6
7  import Ecto.Query
8
9  describe "escape" do
10    test "handles expressions and params" do
11      assert {Macro.escape(quote do [asc: &0.y] end), %{}} ==
12             escape(:order_by, quote do x.y end, [x: 0], __ENV__)
13
14      assert {Macro.escape(quote do [asc: &0.x, asc: &1.y] end), %{}} ==
15             escape(:order_by, quote do [x.x, y.y] end, [x: 0, y: 1], __ENV__)
16
17      assert {Macro.escape(quote do [asc: &0.x, desc: &1.y] end), %{}} ==
18             escape(:order_by, quote do [asc: x.x, desc: y.y] end, [x: 0, y: 1], __ENV__)
19
20      assert {Macro.escape(quote do [asc: &0.x, desc: &1.y] end), %{}} ==
21             escape(:order_by, quote do [x.x, desc: y.y] end, [x: 0, y: 1], __ENV__)
22
23      assert {Macro.escape(quote do [asc: &0.x] end), %{}} ==
24             escape(:order_by, quote do :x end, [x: 0], __ENV__)
25
26      assert {Macro.escape(quote do [asc: &0.x, desc: &0.y] end), %{}} ==
27             escape(:order_by, quote do [:x, desc: :y] end, [x: 0], __ENV__)
28
29      import Kernel, except: [>: 2]
30      assert {Macro.escape(quote do [asc: 1 > 2] end), %{}} ==
31             escape(:order_by, quote do 1 > 2 end, [], __ENV__)
32    end
33
34    test "raises on unbound variables" do
35      assert_raise Ecto.Query.CompileError, "unbound variable `x` in query", fn ->
36        escape(:order_by, quote do x.y end, [], __ENV__)
37      end
38    end
39
40    test "raises on unknown expression" do
41      message = "expected :asc, :desc or interpolated value in `order_by`, got: `:test`"
42      assert_raise Ecto.Query.CompileError, message, fn ->
43        escape(:order_by, quote do [test: x.y] end, [x: 0], __ENV__)
44      end
45    end
46  end
47
48  describe "at runtime" do
49    test "accepts fields, lists or keyword lists" do
50      key = :title
51      dir = :desc
52      assert order_by("q", [q], ^key).order_bys == order_by("q", [q], [asc: q.title]).order_bys
53      assert order_by("q", [q], [^key]).order_bys == order_by("q", [q], [asc: q.title]).order_bys
54      assert order_by("q", [q], [desc: ^key]).order_bys == order_by("q", [q], [desc: q.title]).order_bys
55      assert order_by("q", [q], [{^dir, ^key}]).order_bys == order_by("q", [q], [desc: q.title]).order_bys
56    end
57
58    test "raises on invalid direction" do
59      message = "expected :asc or :desc in `order_by`, got: `:temp`"
60      assert_raise Ecto.Query.CompileError, message, fn ->
61        temp = :temp
62        order_by("posts", [p], [{^var!(temp), p.y}])
63      end
64    end
65
66    test "raises on invalid field" do
67      message = "expected a field as an atom, a list or keyword list in `order_by`, got: `\"temp\"`"
68      assert_raise ArgumentError, message, fn ->
69        temp = "temp"
70        order_by("posts", [p], [asc: ^temp])
71      end
72    end
73
74    test "raises on invalid interpolation" do
75      message = "expected a field as an atom, a list or keyword list in `order_by`, got: `\"temp\"`"
76      assert_raise ArgumentError, message, fn ->
77        temp = "temp"
78        order_by("posts", [p], ^temp)
79      end
80    end
81  end
82end
83