Skip to content

Commit

Permalink
add tree node function
Browse files Browse the repository at this point in the history
  • Loading branch information
electronicbites committed Feb 17, 2024
1 parent 9c8e96d commit 0fa5da4
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 16 deletions.
48 changes: 38 additions & 10 deletions lib/radiator/outline.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,37 @@ defmodule Radiator.Outline do

@doc """
Gets all nodes of an episode as a tree.
Uses a Common Table Expression (CTE) to recursively query the database.
## Examples
iex> get_node_tree(123)
[%Node{}, %Node{}, ..]
"""
def get_node_tree(episode_id) do

node_tree_initial_query =
Node
|> where([n], is_nil(n.parent_id))
|> where([n], n.episode_id == ^episode_id)
|> select([n], %{uuid: n.uuid, content: n.content, parent_id: n.parent_id, prev_id: n.prev_id, level: 0})

node_tree_recursion_query = from outline_node in "outline_nodes",
join: node_tree in "node_tree", on: outline_node.parent_id == node_tree.uuid,
select: [outline_node.uuid, outline_node.content, outline_node.parent_id, outline_node.prev_id, node_tree.level + 1]
|> select([n], %{
uuid: n.uuid,
content: n.content,
parent_id: n.parent_id,
prev_id: n.prev_id,
level: 0
})

node_tree_recursion_query =
from outline_node in "outline_nodes",
join: node_tree in "node_tree",
on: outline_node.parent_id == node_tree.uuid,
select: [
outline_node.uuid,
outline_node.content,
outline_node.parent_id,
outline_node.prev_id,
node_tree.level + 1
]

node_tree_query =
node_tree_initial_query
Expand All @@ -90,17 +104,30 @@ defmodule Radiator.Outline do
"node_tree"
|> recursive_ctes(true)
|> with_cte("node_tree", as: ^node_tree_query)
|> select([n], %{uuid: n.uuid, content: n.content, parent_id: n.parent_id, prev_id: n.prev_id, level: n.level})
|> select([n], %{
uuid: n.uuid,
content: n.content,
parent_id: n.parent_id,
prev_id: n.prev_id,
level: n.level
})
|> Repo.all()
|> Enum.map(fn %{uuid: uuid, content: content, parent_id: parent_id, prev_id: prev_id, level: level} ->
|> Enum.map(fn %{
uuid: uuid,
content: content,
parent_id: parent_id,
prev_id: prev_id,
level: level
} ->
%Node{
uuid: binaray_uuid_to_ecto_uuid(uuid),
content: content,
parent_id: binaray_uuid_to_ecto_uuid(parent_id),
prev_id: binaray_uuid_to_ecto_uuid(prev_id),
parent_id: binaray_uuid_to_ecto_uuid(parent_id),
prev_id: binaray_uuid_to_ecto_uuid(prev_id),
level: level
}
end)

{:ok, tree}
end

Expand Down Expand Up @@ -175,6 +202,7 @@ defmodule Radiator.Outline do
defp broadcast_node_action({:error, error}, _action), do: {:error, error}

defp binaray_uuid_to_ecto_uuid(nil), do: nil

defp binaray_uuid_to_ecto_uuid(uuid) do
Ecto.UUID.load!(uuid)
end
Expand Down
5 changes: 2 additions & 3 deletions priv/repo/seeds.exs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,5 @@ alias Radiator.{Accounts, Outline, Podcast}
prev_id: node211.uuid
})


{:ok, past_parent_node} =
Outline.create_node(%{content: "Old Content", episode_id: past_episode.id})
{:ok, past_parent_node} =
Outline.create_node(%{content: "Old Content", episode_id: past_episode.id})
11 changes: 8 additions & 3 deletions test/radiator/outline_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,17 @@ defmodule Radiator.OutlineTest do
Node
|> where([n], n.episode_id == ^episode_id)
|> Repo.all()

assert Enum.count(tree) == Enum.count(all_nodes)

Enum.each(tree, fn node ->
assert node.uuid == List.first(Enum.filter(all_nodes, fn n -> n.uuid == node.uuid end)).uuid
assert node.uuid ==
List.first(Enum.filter(all_nodes, fn n -> n.uuid == node.uuid end)).uuid
end)
end

test "does not return a node not in this episode", %{
parent: parent
parent: parent
} do
episode_id = parent.episode_id
other_node = node_fixture(parent_id: nil, prev_id: nil, content: "other content")
Expand All @@ -120,7 +123,9 @@ defmodule Radiator.OutlineTest do
node_6 = node_fixture(episode_id: episode.id, parent_id: parent.uuid, prev_id: node_5.uuid)

nested_node_1 = node_fixture(episode_id: episode.id, parent_id: node_3.uuid, prev_id: nil)
nested_node_2 = node_fixture(episode_id: episode.id, parent_id: node_3.uuid, prev_id: nested_node_1.uuid)

nested_node_2 =
node_fixture(episode_id: episode.id, parent_id: node_3.uuid, prev_id: nested_node_1.uuid)

%{
node_1: node_1,
Expand Down

0 comments on commit 0fa5da4

Please sign in to comment.