Current section
Files
Jump to
Current section
Files
lib/query/children.ex
defmodule Hierarch.Query.Children do
import Ecto.Query
@doc """
Return query expressions for children of a query
```elixir
import Ecto.Query
query = from t in Catelog, where: [..]
query
|> Hierarch.Query.Children.query()
|> Repo.all
"""
def query(%{from: %{source: {_table_name, schema}}} = queryable) do
path_column = schema.__hierarch__(:path_column)
[pk_column] = schema.__schema__(:primary_key)
uuids_query =
from(t in queryable,
select: %{
__ancestry__:
fragment(
"? || replace(text(?), '-', '_')",
field(t, ^path_column),
field(t, ^pk_column)
)
}
)
uuids_array_query =
from(t in subquery(uuids_query),
select: %{__ltrees__: fragment("array_agg(?)", t.__ancestry__)}
)
schema
|> join(:cross, [], a in subquery(uuids_array_query))
|> where([t, a], field(t, ^path_column) in a.__ltrees__)
end
@doc """
Return query expressions for children
## Options
* `:with_self` - when true to include itself. Defaults to false.
```elixir
%Catelog{
id: "06a84054-8827-42c2-9b75-25ed75e6d5f8",
name: "Top.Hobbies",
path: "a9ae8f40-b016-4bf9-8224-e2755466e699",
}
|> Hierarch.Query.Children.query()
|> Repo.all
# or
%Catelog{
id: "06a84054-8827-42c2-9b75-25ed75e6d5f8",
name: "Top.Hobbies",
path: "a9ae8f40-b016-4bf9-8224-e2755466e699",
}
|> Catelog.children()
|> Repo.all
```
"""
def query(%schema{} = struct, opts \\ []) do
with_self = Keyword.get(opts, :with_self, false)
path = Hierarch.Util.struct_path(struct)
[{pk_column, value}] = Ecto.primary_key(struct)
children_path = Hierarch.LTree.concat(path, value)
children_query =
from(
t in schema,
where: field(t, ^schema.__hierarch__(:path_column)) == ^children_path
)
case with_self do
true -> children_query |> or_where([t], field(t, ^pk_column) == ^value)
_ -> children_query
end
end
end