/
macros.ex
90 lines (76 loc) · 2.41 KB
/
macros.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
defmodule PhoenixDatatables.Query.Macros do
@moduledoc false
# make a simple AST representing blank Ecto table bindings so that
# 'name' is bound to num(th) position (0 base)
# e.g. bind_number(3, :t) = [_, _, _, t]
defp bind_number(num, name \\ :t) do
blanks =
for _ <- 0..num do
{:_, [], Elixir}
end
Enum.drop(blanks, 1) ++ [{name, [], Elixir}]
end
defp def_order_relation(num) do
bindings = bind_number(num)
quote do
defp order_relation(queryable, unquote(num), dir, column, nil) do
order_by(queryable, unquote(bindings), [{^dir, field(t, ^column)}])
end
defp order_relation(queryable, unquote(num), dir, column, options) when is_list(options) do
if dir == :desc && options[:nulls_last] do
order_by(queryable, unquote(bindings), [
fragment("? DESC NULLS LAST", field(t, ^column))
])
else
order_relation(queryable, unquote(num), dir, column, nil)
end
end
end
end
defp def_search_relation(num) do
bindings = bind_number(num)
quote do
defp search_relation(dynamic, unquote(num), attribute, search_term) do
dynamic(
unquote(bindings),
fragment("CAST(? AS TEXT) ILIKE ?", field(t, ^attribute), ^search_term) or ^dynamic
)
end
end
end
defp def_search_relation_and(num) do
bindings = bind_number(num)
quote do
defp search_relation_and(dynamic, unquote(num), attribute, search_term) do
dynamic(
unquote(bindings),
fragment("CAST(? AS TEXT) ILIKE ?", field(t, ^attribute), ^search_term) and ^dynamic
)
end
end
end
defmacro __using__(arg) do
defines_count =
case arg do
[] ->
25
num when is_integer(num) ->
num
arg ->
raise """
unknown args #{inspect(arg)} for
PhoenixDatatables.Query.Macros.__using__,
provide a number or nothing"
"""
end
order_relations = Enum.map(0..defines_count, &def_order_relation/1)
search_relations = Enum.map(0..defines_count, &def_search_relation/1)
search_relations_and = Enum.map(0..defines_count, &def_search_relation_and/1)
quote do
unquote(order_relations)
defp search_relation(queryable, nil, _, _), do: queryable
unquote(search_relations)
unquote(search_relations_and)
end
end
end