Skip to content

Commit

Permalink
add move node function
Browse files Browse the repository at this point in the history
  • Loading branch information
electronicbites committed Jan 30, 2024
1 parent e2e4332 commit a44abaf
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 16 deletions.
19 changes: 19 additions & 0 deletions lib/radiator/outline.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ defmodule Radiator.Outline do
|> broadcast_node_action(:update)
end

@doc """
Moves a nodes to another parent.
## Examples
iex> move_node(node, %Node{uuid: new_parent_id})
{:ok, %Node{}}
iex> move_node(node, nil)
{:error, %Ecto.Changeset{}}
"""
def move_node(%Node{} = node, %Node{} = parent_node) do
node
|> Node.move_changeset(parent_node)
|> Repo.update()
|> broadcast_node_action(:update)
end

@doc """
Deletes a node.
Expand Down
23 changes: 21 additions & 2 deletions lib/radiator/outline/node.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ defmodule Radiator.Outline.Node do
Changeset for moving a node
Only the parent_id is allowed and expected to be changed
"""
def move_changeset(node, attrs) do
def move_changeset(node, new_parent_node) do
node
|> cast(attrs, [:parent_id])
|> cast(%{parent_id: new_parent_node.uuid}, [:parent_id])
|> validate_parent(new_parent_node)
end

@doc """
Expand All @@ -58,4 +59,22 @@ defmodule Radiator.Outline.Node do

defp trim(content) when is_binary(content), do: String.trim(content)
defp trim(content), do: content

defp validate_parent(changeset, nil), do: add_error(changeset, :parent_id, "must not be nil")

defp validate_parent(changeset, parent_node) do
cond do
parent_node.uuid == changeset.data.uuid ->
add_error(changeset, :parent_id, "must not be the same as the node itself")

parent_node.parent_id == changeset.data.uuid ->
add_error(changeset, :parent_id, "node is already parent of the parent node")

parent_node.episode_id != changeset.data.episode_id ->
add_error(changeset, :parent_id, "nodes must be in the same episode")

true ->
changeset
end
end
end
55 changes: 41 additions & 14 deletions test/radiator/outline_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,45 @@ defmodule Radiator.OutlineTest do

alias Radiator.Outline

describe "outline_nodes" do
alias Radiator.Outline.Node
alias Radiator.Outline.Node

import Radiator.OutlineFixtures
alias Radiator.PodcastFixtures
import Radiator.OutlineFixtures
alias Radiator.PodcastFixtures

@invalid_attrs %{content: nil}
@invalid_attrs %{content: nil}

test "list_nodes/0 returns all nodes" do
describe "list_nodes/0" do
test "returns all nodes" do
node = node_fixture()
assert Outline.list_nodes() == [node]
end
end

test "get_node!/1 returns the node with given id" do
describe "get_node!/1" do
test "returns the node with given id" do
node = node_fixture()
assert Outline.get_node!(node.uuid) == node
end
end

test "create_node/1 with valid data creates a node" do
describe "create_node/1" do
test "with valid data creates a node" do
episode = PodcastFixtures.episode_fixture()
valid_attrs = %{content: "some content", episode_id: episode.id}

assert {:ok, %Node{} = node} = Outline.create_node(valid_attrs)
assert node.content == "some content"
end

test "create_node/1 trims whitespace from content" do
test "trims whitespace from content" do
episode = PodcastFixtures.episode_fixture()
valid_attrs = %{content: " some content ", episode_id: episode.id}

assert {:ok, %Node{} = node} = Outline.create_node(valid_attrs)
assert node.content == "some content"
end

test "create_node/1 can have a creator" do
test "can have a creator" do
episode = PodcastFixtures.episode_fixture()
user = %{id: 2}
valid_attrs = %{content: "some content", episode_id: episode.id}
Expand All @@ -47,25 +51,48 @@ defmodule Radiator.OutlineTest do
assert node.creator_id == user.id
end

test "create_node/1 with invalid data returns error changeset" do
test "with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Outline.create_node(@invalid_attrs)
end
end

test "update_node_content/2 with valid data updates the node" do
describe "update_node_content/2" do
test "with valid data updates the node" do
node = node_fixture()
update_attrs = %{content: "some updated content"}

assert {:ok, %Node{} = node} = Outline.update_node_content(node, update_attrs)
assert node.content == "some updated content"
end

test "update_node_content/2 with invalid data returns error changeset" do
test "with invalid data returns error changeset" do
node = node_fixture()
assert {:error, %Ecto.Changeset{}} = Outline.update_node_content(node, @invalid_attrs)
assert node == Outline.get_node!(node.uuid)
end
end

describe "move_node/2" do
test "moves node to another parent" do
node = node_fixture()
new_parent = node_fixture(episode_id: node.episode_id)

assert {:ok, %Node{} = node} = Outline.move_node(node, new_parent)
assert node.parent_id == new_parent.uuid
end

test "update_node_content/2 with parent from another episode returns error changeset" do
node = node_fixture()
new_bad_parent = node_fixture()
assert node.episode_id != new_bad_parent.episode_id

assert {:error, %Ecto.Changeset{}} = Outline.move_node(node, new_bad_parent)
assert node == Outline.get_node!(node.uuid)
end
end

test "delete_node/1 deletes the node" do
describe "delete_node/1" do
test "deletes the node" do
node = node_fixture()
assert {:ok, %Node{}} = Outline.delete_node(node)
assert_raise Ecto.NoResultsError, fn -> Outline.get_node!(node.uuid) end
Expand Down

0 comments on commit a44abaf

Please sign in to comment.