legendary-doc-site/apps/admin/kaffy/lib/kaffy/resource_query.ex
2020-07-27 20:28:41 +00:00

153 lines
4.3 KiB
Elixir

defmodule Kaffy.ResourceQuery do
@moduledoc false
import Ecto.Query
def list_resource(conn, resource, params \\ %{}) do
per_page = Map.get(params, "limit", "100") |> String.to_integer()
page = Map.get(params, "page", "1") |> String.to_integer()
search = Map.get(params, "search", "") |> String.trim()
search_fields = Kaffy.ResourceAdmin.search_fields(resource)
filtered_fields = get_filter_fields(params, resource)
ordering = get_ordering(resource, params)
current_offset = (page - 1) * per_page
schema = resource[:schema]
{all, paged} =
build_query(
schema,
search_fields,
filtered_fields,
search,
per_page,
ordering,
current_offset
)
custom_query = Kaffy.ResourceAdmin.custom_index_query(conn, resource, paged)
current_page = Kaffy.Utils.repo().all(custom_query)
do_cache = if search == "" and Enum.empty?(filtered_fields), do: true, else: false
all_count = cached_total_count(schema, do_cache, all)
{all_count, current_page}
end
def get_ordering(resource, params) do
default_ordering = Kaffy.ResourceAdmin.ordering(resource)
default_order_field = Map.get(params, "_of", "nil") |> String.to_existing_atom()
default_order_way = Map.get(params, "_ow", "nil") |> String.to_existing_atom()
case is_nil(default_order_field) or is_nil(default_order_way) do
true -> default_ordering
false -> [{default_order_way, default_order_field}]
end
end
def fetch_resource(conn, resource, id) do
schema = resource[:schema]
id_column = resource[:id_column] || :id
query = from(s in schema, where: ^[{id_column, id}])
custom_query = Kaffy.ResourceAdmin.custom_show_query(conn, resource, query)
Kaffy.Utils.repo().one(custom_query)
end
def fetch_list(_, [""]), do: []
def fetch_list(resource, ids) do
schema = resource[:schema]
from(s in schema, where: s.id in ^ids)
|> Kaffy.Utils.repo().all()
end
def total_count(schema, do_cache, query) do
result =
from(s in query, select: fragment("count(*)"))
|> Kaffy.Utils.repo().one()
if do_cache and result > 100_000 do
Kaffy.Cache.Client.add_cache(schema, "count", result, 600)
end
result
end
def cached_total_count(schema, false, query), do: total_count(schema, false, query)
def cached_total_count(schema, do_cache, query) do
Kaffy.Cache.Client.get_cache(schema, "count") || total_count(schema, do_cache, query)
end
defp get_filter_fields(params, resource) do
schema_fields =
Kaffy.ResourceSchema.fields(resource[:schema]) |> Enum.map(fn {k, _} -> to_string(k) end)
filtered_fields = Enum.filter(params, fn {k, v} -> k in schema_fields and v != "" end)
Enum.map(filtered_fields, fn {name, value} ->
%{name: name, value: value}
end)
end
defp build_query(
schema,
search_fields,
filtered_fields,
search,
per_page,
ordering,
current_offset
) do
query = from(s in schema)
query =
cond do
(is_nil(search_fields) || Enum.empty?(search_fields)) && search == "" ->
query
true ->
term =
search
|> String.replace("%", "\%")
|> String.replace("_", "\_")
term = "%#{term}%"
Enum.reduce(search_fields, query, fn
{association, fields}, q ->
query = from(s in q, join: a in assoc(s, ^association))
Enum.reduce(fields, query, fn f, current_query ->
from([..., r] in current_query, or_where: ilike(field(r, ^f), ^term))
end)
f, q ->
from(s in q, or_where: ilike(field(s, ^f), ^term))
end)
end
query = build_filtered_fields_query(query, filtered_fields)
limited_query =
from(s in query, limit: ^per_page, offset: ^current_offset, order_by: ^ordering)
{query, limited_query}
end
defp build_filtered_fields_query(query, []), do: query
defp build_filtered_fields_query(query, [filter | rest]) do
query =
case filter.value == "" do
true ->
query
false ->
field_name = String.to_existing_atom(filter.name)
from(s in query, where: field(s, ^field_name) == ^filter.value)
end
build_filtered_fields_query(query, rest)
end
end