It looks like you might be doing a lot of data access.
You might get a huge boost in simplicity and performance by using maps instead of lists.
If you were willing to separate storing and sorting of children, you could store a map of children
and an order
list that has ordered child ids:
elements = %{
children: %{
"62197198-e3a1-46de-8f18-f2c6843f646f" => %{
children: %{
"b2a6b171-26e1-4e8a-8cd3-c41f388de6e8" => %{
children: [],
class: ["text-black", "w-full", "p-2"],
id: "b2a6b171-26e1-4e8a-8cd3-c41f388de6e8",
# index: 1,
parent: "section",
parent_id: "62197198-e3a1-46de-8f18-f2c6843f646f",
type: "text"
},
"c9ea0fff-1ee0-407e-8b2a-64afc954c40b" => %{
children: [],
class: ["text-black", "w-full", "p-2"],
id: "c9ea0fff-1ee0-407e-8b2a-64afc954c40b",
# index: 0,
parent: "section",
parent_id: "62197198-e3a1-46de-8f18-f2c6843f646f",
type: "text"
}
},
class: ["flex", "flex-col", "justify-between", "items-stretch",
"min-h-[200px]", "w-full", "border", "border-dashed", "border-gray-400",
"p-1"],
id: "62197198-e3a1-46de-8f18-f2c6843f646f",
# index: 0,
order: ["c9ea0fff-1ee0-407e-8b2a-64afc954c40b",
"b2a6b171-26e1-4e8a-8cd3-c41f388de6e8"],
parent: "layout",
parent_id: "64a2c3f2-d71f-464a-8318-be072d7b6624",
type: "section"
}
},
order: ["62197198-e3a1-46de-8f18-f2c6843f646f"],
class: ["flex", "flex-row", "justify-start", "items-center", "w-full",
"space-x-3", "px-3", "py-10"],
id: "64a2c3f2-d71f-464a-8318-be072d7b6624",
# index: 0,
order: "62197198-e3a1-46de-8f18-f2c6843f646f",
parent: "dragLocation",
parent_id: "dragLocation",
type: "layout"
}
Once you do that, you can use @codeanpeace’s Access module functions at a cost of O(n)
instead of O(n^3)
:
Look up would be:
def find(elements, id, parent_id, layout_id) do
get_in(elements, [:children, layout_id,:children, parent_id, :children, id])
end
Updating an element
def add_tag(elements, id, parent_id, layout_id, tag, type) when type in @elements do
update_in(elements, [:children, layout_id,:children, parent_id, :children, id], fn selected_element ->
if selected_element.type == type do
Map.merge(selected_element, %{tag: tag})
end
end)
end
Removing an element:
def delete(elements, id, parent_id, layout_id) do
# Remove the child
{_,elements} = pop_in(elements, [:children, layout_id,:children, parent_id, :children, id])
# Remove it from the order
elements = update_in(elements, [:children, layout_id,:children, parent_id, :order], fn order ->
Enum.reject(order, &(&1 == id))
end)
elements
end
Adding is similar to deleting