Current section
Files
Jump to
Current section
Files
src/nm_node.erl
-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}.