Current section
Files
Jump to
Current section
Files
lib/trubo_ecto.ex
defmodule Trubo.Ecto do
@moduledoc """
Elixir Search compoment, support single table search, sort and paginate.
"""
alias Trubo.Ecto.Hooks.{Paginate, Sort, Search}
alias Trubo.Ecto.Config, as: TConfig
@doc """
Returns a result and pageinate info.
## Example
iex> params = %{"q" => %{"title_like" => "q"}, "s" => "updated_at+asc", "per_page" => 5, "page" => 1}
iex> run(Product, params)
%{
paginate: %{total_pages: 2, current_page: 1, per_page: 5, total_count: 8, prev_page: 0, next_page: 2},
result: [Prudct]
}
"""
@spec trubo(Ecto.Query.t(), Map.t(), Keyword.t()) :: Map.t()
def trubo(queryable, params, opts \\ []) do
queryable = truboq(queryable, params)
%{
datas: handle_query(queryable, opts),
paginate: get_paginate(queryable, params, opts)
}
end
@doc """
Returns processed queryable.
"""
@spec truboq(Ecto.Query.t(), Map.t()) :: Ecto.Query.t()
def truboq(queryable, params) do
[Search, Sort, Paginate]
|> Enum.reduce(queryable, &run_hook(&1, &2, params))
end
@doc """
Returns searching result.
## Example
iex> search(Product, %{"q" => %{"title_like" => "q"}})
[Product]
"""
@spec search(Ecto.Query.t(), Map.t(), Keyword.t()) :: any
def search(queryable, params, opts \\ []) do
queryable
|> searchq(params)
|> handle_query(opts)
end
@doc """
Returns searching queryable.
## Example
iex> searchq(Product, %{"q" => %{"title_like" => "q"}})
#Ecto.Query<from t in Product, where: like(t.title, ^"%q%")>
"""
@spec search(Ecto.Query.t(), Map.t()) :: Ecto.Query.t()
def searchq(queryable, params), do: Search.run(queryable, params)
@doc """
Returns sorting result.
"""
@spec sort(Ecto.Query.t(), Map.t(), Keyword.t()) :: any
def sort(queryable, params, opts \\ []) do
queryable
|> sortq(params)
|> handle_query(opts)
end
@doc """
Returns sorting queryable.
"""
@spec sortq(Ecto.Query.t(), Map.t()) :: Ecto.Query.t()
def sortq(queryable, params), do: Sort.run(queryable, params)
@doc """
Returns Paginate result.
"""
@spec paginate(Ecto.Query.t(), Map.t(), Keyword.t()) :: Map.t()
def paginate(queryable, params, opts \\ []) do
queryable = paginateq(queryable, params)
%{
dates: handle_query(queryable, opts),
paginate: get_paginate(queryable, params, opts)
}
end
@doc """
Returns Paginate queryable.
## Example
iex> params = %{"per_page" => 5, "page" => 2}
iex> paginateq(Product, params)
#Ecto.Query<from t in Product, limit: ^5, offset: ^5>
"""
@spec paginateq(Ecto.Query.t(), Map.t()) :: Ecto.Query.t()
def paginateq(queryable, params), do: Paginate.run(queryable, params)
@doc """
Gets paginate info.
## Example
iex> get_paginate(queryable, params)
%{total_pages: 2, current_page: 1, per_page: 5, total_count: 8, prev_page: 0, next_page: 2}
"""
# @spec get_paginate(Ecto.Query.t(), Map.t(), Keyword.t()) :: Map.t()
def get_paginate(queryable, params, opts \\ []) do
build_opts = Keyword.put_new(opts, :repo, TConfig.repo)
Paginate.get_paginate(queryable, params, build_opts)
end
# invoke hook runq
defp run_hook(hook, queryable, params), do: apply(hook, :run, [queryable, params])
defp handle_query(queryable, opts) do
build_opts = Keyword.put_new(opts, :repo, TConfig.repo)
case Keyword.get(build_opts, :repo) do
nil -> raise "Expected key `repo` in `opts`, got #{inspect(opts)}"
repo -> apply(repo, :all, [queryable])
end
end
defmacro __using__(opts) do
quote do
alias Trubo.Ecto.Config, as: TConfig
@doc """
Returns result
"""
@spec trubo(Ecto.Query.t(), map(), Keyword.t()) :: any()
def trubo(queryable, params, opts \\ []) do
Trubo.Ecto.trubo(queryable, params, uniq_merge(opts, defaults()))
end
@doc """
Returns queryable
"""
@spec truboq(Ecto.Query.t(), map(), Keyword.t()) :: Ecto.Query.t()
def truboq(queryable, params, opts \\ []) do
Trubo.Ecto.truboq(queryable, params)
end
@doc """
Returns search result.
"""
@spec search(Ecto.Query.t(), map(), Keyword.t()) :: any()
def search(queryable, params, opts \\ []) do
Trubo.Ecto.search(queryable, params, uniq_merge(opts, defaults()))
end
@doc """
Returns search queryable.
"""
@spec searchq(Ecto.Query.t(), map(), Keyword.t()) :: Ecto.Query.t()
def searchq(queryable, params, opts \\ []) do
Trubo.Ecto.searchq(queryable, params)
end
@doc """
Returns sort data result.
"""
@spec sort(Ecto.Query.t(), map(), Keyword.t()) :: any()
def sort(queryable, params, opts \\ []) do
Trubo.Ecto.sort(queryable, params, uniq_merge(opts, defaults()))
end
@doc """
Returns sort queryable.
"""
@spec sortq(Ecto.Query.t(), map(), Keyword.t()) :: Ecto.Query.t()
def sortq(queryable, params, opts \\ []) do
Trubo.Ecto.sortq(queryable, params)
end
@doc """
Return paginate result.
"""
@spec paginate(Ecto.Query.t(), map(), Keyword.t()) :: any()
def paginate(queryable, params, opts \\ []) do
Trubo.Ecto.paginate(queryable, params, uniq_merge(opts, defaults()))
end
@doc """
Return paginate queryable.
"""
@spec paginateq(Ecto.Query.t(), map(), Keyword.t()) :: Ecto.Query.t()
def paginateq(queryable, params, opts \\ []) do
Trubo.Ecto.paginateq(queryable, params)
end
defp defaults() do
keys = ~w(repo per_page)a
Enum.map(keys, &get_defs/1)
end
defp get_defs(key) do
app = Application.get_application(__MODULE__)
{key, Keyword.get(unquote(opts), key, apply(TConfig, key, [app]))}
end
defp uniq_merge(keyword1, keyword2) do
keyword2
|> Keyword.merge(keyword1)
|> Keyword.new()
end
end
end
end