Skip to content

Commit

Permalink
insert node (tree aware)
Browse files Browse the repository at this point in the history
  • Loading branch information
electronicbites committed Mar 12, 2024
1 parent 753891e commit a4cbff7
Show file tree
Hide file tree
Showing 2 changed files with 288 additions and 52 deletions.
98 changes: 90 additions & 8 deletions lib/radiator/outline.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ defmodule Radiator.Outline do
|> Repo.all()
end

@doc """
Returns the the number of nodes for an episode
## Examples
iex> count_nodes_by_episode(123)
3
"""
def count_nodes_by_episode(episode_id) do
episode_id
|> list_nodes_by_episode()
|> Enum.count()
end

@doc """
Gets a single node.
Expand Down Expand Up @@ -219,6 +234,74 @@ defmodule Radiator.Outline do
|> broadcast_node_action(:insert)
end

@doc """
Inserts a node.
## Examples
iex> insert_node(%{content: 'foo'}, %Node{} = parent_node, %Node{} = prev_node)
{:ok, %Node{}}
iex> insert_node(%{content: value}, %Node{} = parent_node, %Node{parent_id: nil} = prev_node)
{:error, :parent_and_prev_not_consistent}
"""
# creates a node and inserts it into the outline tree
# if a parent node is given, the new node will be inserted as a child of the parent node
# if a previous node is given, the new node will be inserted after the previous node
# if no parent is given, the new node will be inserted as a root node
# if no previous node is given, the new node will be inserted as the first child of the parent node
def insert_node(attrs, parent_node \\ nil, prev_node \\ nil) do
Repo.transaction(fn ->
prev_node_id = get_node_id(prev_node)
parent_node_id = get_node_id(parent_node)

# find Node which has been previously connected to prev_node
node_to_move =
Node
|> where_prev_node_equals(prev_node_id)
|> where_parent_node_equals(parent_node_id)
|> Repo.one()

with true <- parent_and_prev_consistent?(parent_node, prev_node),
{:ok, node} <- create_node(attrs),
{:ok, _node_to_move} <- move_node_(node_to_move, nil, node.uuid),
{:ok, node} <- move_node_(node, parent_node_id, prev_node_id) do
node
else
false ->
Repo.rollback("Insert node failed. Parent and prev node are not consistent.")

{:error, _} ->
Repo.rollback("Insert node failed. Unkown error")
end
end)
end

defp move_node_(nil, _parent_node_id, _prev_node_id), do: {:ok, nil}

defp move_node_(node, parent_node_id, prev_node_id) do
node
|> Node.move_node_changeset(%{
parent_id: parent_node_id,
prev_id: prev_node_id
})
|> Repo.update()
end

defp parent_and_prev_consistent?(_, nil), do: true
defp parent_and_prev_consistent?(nil, _), do: true

defp parent_and_prev_consistent?(parent, prev) do
parent.uuid == prev.parent_id
end

defp where_prev_node_equals(node, nil), do: where(node, [n], is_nil(n.prev_id))
defp where_prev_node_equals(node, prev_id), do: where(node, [n], n.prev_id == ^prev_id)

defp where_parent_node_equals(node, nil), do: where(node, [n], is_nil(n.parent_id))
defp where_parent_node_equals(node, parent_id), do: where(node, [n], n.parent_id == ^parent_id)

@doc """
Updates a nodes content.
Expand Down Expand Up @@ -258,16 +341,9 @@ defmodule Radiator.Outline do

prev_node = get_prev_node(node)

prev_uuid =
if prev_node do
prev_node.uuid
else
nil
end

if next_node do
next_node
|> Node.move_node_changeset(%{prev_id: prev_uuid})
|> Node.move_node_changeset(%{prev_id: get_node_id(prev_node)})
|> Repo.update()
end

Expand All @@ -283,6 +359,12 @@ defmodule Radiator.Outline do
|> broadcast_node_action(:delete)
end

defp get_node_id(nil), do: nil

defp get_node_id(%Node{} = node) do
node.uuid
end

defp broadcast_node_action({:ok, node}, action) do
PubSub.broadcast(Radiator.PubSub, @topic, {action, node})
{:ok, node}
Expand Down
Loading

0 comments on commit a4cbff7

Please sign in to comment.