I would like to understand how to simple inject a sort function into my module.
for key <- @query_keys, direction <- [asc: "asc", desc: "desc"] do
{atom_dir, str_dir} = direction
arg_name = "#{key}_#{str_dir}"
def unquote(:sort)(q, arg_name) do
# I can't get atom_dir or direction or key here!!
order_by(q, [{^var!(atom_dir), :s}])
end
defmodule Example do
defmacro __before_compile__(_opts) do
schema = parse_module_schema(__CALLER__.module)
quote bind_quoted: [schema: schema] do
import Ecto.Query, only: [from: 2, order_by: 2]
@query_keys Enum.map(@ecto_fields, &elem(&1, 0))
@spec init_query() :: Ecto.Query.t()
def init_query, do: from(__MODULE__, as: unquote(schema))
defoverridable(init_query: 0)
for key <- @query_keys, direction <- [:asc, :desc] do
arg_name = "#{key}_#{direction}"
def unquote(:sort)(queryable, unquote(arg_name)) do
order_by(queryable, [{unquote(direction), unquote(key)}])
end
end
if :updated_at in @query_keys do
def sort(queryable, _), do: order_by(queryable, desc: :updated_at)
end
end
end
defp parse_module_schema(module) do
module |> Module.split() |> List.last() |> Macro.underscore() |> String.to_atom()
end
end
defmodule Post do
use Ecto.Schema
@before_compile Example
schema "posts" do
field :author
field :content
end
end
iex> Post.sort(Post.init_query(), "content_desc")
#Ecto.Query<from p0 in Post, as: :post, order_by: [desc: p0.content]>
Hint
Any Elixir expression is valid inside the interpolation. If a string is given, the string is interpolated as is. If any other value is given, Elixir will attempt to convert it to a string using the String.Chars protocol.