-module(nm_node). -moduledoc false. -export([ delete/2, fast_delete/2, fast_update/3, get_node/2, get_value/2, id/0, node/3, ref/1, update/3 ]). delete(NestedTable, root) -> ets:delete(NestedTable), ok; delete(NestedTable, Id) -> case get_node(NestedTable, Id) of {ok, #{parent := ParentId}} -> remove_in_parent(NestedTable, ParentId, Id), remove_children(NestedTable, Id), ets:delete(NestedTable, Id), ok; Error -> Error end. fast_delete(NestedTable, root) -> ets:delete(NestedTable), ok; fast_delete(NestedTable, Id) -> case get_node(NestedTable, Id) of {ok, #{parent := ParentId}} -> remove_in_parent(NestedTable, ParentId, Id), ets:delete(NestedTable, Id), ok; Error -> Error end. remove_in_parent(NestedTable, ParentId, Id) -> case get_value(NestedTable, ParentId) of {ok, Value0} when is_list(Value0) -> Value1 = lists:delete({'$nm_ref', Id}, Value0), ets:update_element(NestedTable, ParentId, {3, Value1}), ok; {ok, Value0} when is_map(Value0) -> Fun = fun (_Key, {'$nm_ref', Ref}) -> Ref /= Id; (_Key, _Value) -> true end, Value1 = maps:filter(Fun, Value0), ets:update_element(NestedTable, ParentId, {3, Value1}), ok; Error -> Error end. remove_children(NestedTable, Id) -> Fun = fun(CurrentId) -> remove_children(NestedTable, CurrentId), ets:delete(NestedTable, CurrentId), ok end, Children = lists:flatten(ets:match(NestedTable, {'$1', Id, '_'})), lists:foreach(Fun, Children). update(NestedTable, Id, Data0) -> remove_children(NestedTable, Id), Data1 = nm_nesting:unnest(NestedTable, Data0, Id), ets:update_element(NestedTable, Id, {3, Data1}), ok. fast_update(NestedTable, Id, Data) -> ets:update_element(NestedTable, Id, {3, Data}), ok. get_node(NestedTable, Id) -> case ets:lookup(NestedTable, Id) of {badkey, Id} -> {error, no_reference}; [{Id, Parent, Value}] -> {ok, node(Id, Parent, Value)} end. get_value(NestedTable, Id) -> case ets:lookup(NestedTable, Id) of {badkey, Id} -> {error, no_reference}; [{Id, _Parent, Value}] -> {ok, Value} end. id() -> P1 = erlang:system_time(millisecond), P2 = erlang:unique_integer([positive]), Str = io_lib:format("~9.32.0b~3.32.0b", [P1, P2]), binary:list_to_bin("$nm" ++ Str). node(Self, Parent, Value) -> #{ref => Self, parent => Parent, value => Value}. ref(Id) -> {'$nm_ref', Id}.