feat: category filter includes subcategories
This commit is contained in:
@@ -203,6 +203,27 @@ defmodule ComponentsElixir.Inventory do
|
||||
Category.changeset(category, attrs)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets all category IDs that are descendants of the given category ID, including the category itself.
|
||||
This is used for filtering components by category and all its subcategories.
|
||||
Returns an empty list if the category doesn't exist.
|
||||
|
||||
Note: This implementation loads all categories into memory for traversal, which is efficient
|
||||
for typical category tree sizes (hundreds of categories). For very large category trees,
|
||||
a recursive CTE query could be used instead.
|
||||
"""
|
||||
def get_category_and_descendant_ids(category_id) when is_integer(category_id) do
|
||||
categories = list_categories()
|
||||
|
||||
# Verify the category exists before getting descendants
|
||||
case Enum.find(categories, &(&1.id == category_id)) do
|
||||
nil -> []
|
||||
_category -> ComponentsElixir.Inventory.Hierarchical.descendant_ids(categories, category_id, &(&1.parent_id))
|
||||
end
|
||||
end
|
||||
|
||||
def get_category_and_descendant_ids(_), do: []
|
||||
|
||||
## Components
|
||||
|
||||
@doc """
|
||||
@@ -219,7 +240,9 @@ defmodule ComponentsElixir.Inventory do
|
||||
defp apply_component_filters(query, opts) do
|
||||
Enum.reduce(opts, query, fn
|
||||
{:category_id, category_id}, query when not is_nil(category_id) ->
|
||||
where(query, [c], c.category_id == ^category_id)
|
||||
# Get the category and all its descendant category IDs
|
||||
category_ids = get_category_and_descendant_ids(category_id)
|
||||
where(query, [c], c.category_id in ^category_ids)
|
||||
|
||||
{:storage_location_id, storage_location_id}, query when not is_nil(storage_location_id) ->
|
||||
where(query, [c], c.storage_location_id == ^storage_location_id)
|
||||
|
||||
@@ -143,6 +143,32 @@ defmodule ComponentsElixir.Inventory.Hierarchical do
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets all descendant IDs for a given entity ID, including the entity itself.
|
||||
This recursively finds all children, grandchildren, etc.
|
||||
|
||||
## Examples
|
||||
iex> categories = [
|
||||
...> %{id: 1, parent_id: nil},
|
||||
...> %{id: 2, parent_id: 1},
|
||||
...> %{id: 3, parent_id: 2},
|
||||
...> %{id: 4, parent_id: 1}
|
||||
...> ]
|
||||
iex> Hierarchical.descendant_ids(categories, 1, &(&1.parent_id))
|
||||
[1, 2, 3, 4]
|
||||
"""
|
||||
def descendant_ids(entities, entity_id, parent_id_accessor_fn) do
|
||||
[entity_id | get_descendant_ids_recursive(entities, entity_id, parent_id_accessor_fn)]
|
||||
end
|
||||
|
||||
defp get_descendant_ids_recursive(entities, parent_id, parent_id_accessor_fn) do
|
||||
children = child_entities(entities, parent_id, parent_id_accessor_fn)
|
||||
|
||||
Enum.flat_map(children, fn child ->
|
||||
[child.id | get_descendant_ids_recursive(entities, child.id, parent_id_accessor_fn)]
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Generates display name for entity including parent context.
|
||||
For dropdown displays: "Parent > Child"
|
||||
|
||||
Reference in New Issue
Block a user