From f6077aa18a0dd1b88fd19604c51911c0572fe8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=B6ginger?= Date: Tue, 2 Jul 2024 21:30:01 +0200 Subject: [PATCH 1/7] WIP list episodes, rename event_id => uuid --- lib/radiator/event_store.ex | 20 ++++++++++++++++--- .../event/node_content_changed_event.ex | 2 +- .../outline/event/node_deleted_event.ex | 2 +- .../outline/event/node_inserted_event.ex | 2 +- .../outline/event/node_moved_event.ex | 2 +- lib/radiator/outline/event_consumer.ex | 8 ++++---- .../components/outline_components.ex | 17 +++++++++------- lib/radiator_web/live/episode_live/index.ex | 15 ++++++++++---- test/radiator/event_store_test.exs | 4 ++-- test/support/fixtures/event_store_fixtures.ex | 8 ++++---- 10 files changed, 52 insertions(+), 28 deletions(-) diff --git a/lib/radiator/event_store.ex b/lib/radiator/event_store.ex index 7a659948..a7a6eb8c 100644 --- a/lib/radiator/event_store.ex +++ b/lib/radiator/event_store.ex @@ -12,7 +12,7 @@ defmodule Radiator.EventStore do create_event_data(%{ data: AbstractEvent.payload(event), event_type: AbstractEvent.event_type(event), - uuid: convert_to_uuid(event.event_id), + uuid: convert_to_uuid(event.uuid), user_id: event.user_id }) @@ -23,11 +23,11 @@ defmodule Radiator.EventStore do defp convert_to_uuid(uuid), do: uuid @doc """ - Returns the list of foo_events. + Returns the list of all event_data. ## Examples - iex> list_events() + iex> list_event_data() [%Event{}, ...] """ @@ -35,6 +35,20 @@ defmodule Radiator.EventStore do Repo.all(EventData) end + @doc """ + Returns the list of event_data per episode. + + ## Examples + + iex> list_event_data_by_episode() + [%Event{}, ...] + + """ + # def list_event_data_by_episode(nil), do: nil + def list_event_data_by_episode(episode_id) do + Repo.all(EventData, where: [episode_id: episode_id], order_by: [desc: :inserted_at]) + end + @doc """ Gets a single event data. diff --git a/lib/radiator/outline/event/node_content_changed_event.ex b/lib/radiator/outline/event/node_content_changed_event.ex index 5c3b027b..9f170bd4 100644 --- a/lib/radiator/outline/event/node_content_changed_event.ex +++ b/lib/radiator/outline/event/node_content_changed_event.ex @@ -1,5 +1,5 @@ defmodule Radiator.Outline.Event.NodeContentChangedEvent do @moduledoc false - defstruct [:event_id, :node_id, :content, :user_id] + defstruct [:uuid, :node_id, :content, :user_id] end diff --git a/lib/radiator/outline/event/node_deleted_event.ex b/lib/radiator/outline/event/node_deleted_event.ex index 1bbf0f46..7d1c872b 100644 --- a/lib/radiator/outline/event/node_deleted_event.ex +++ b/lib/radiator/outline/event/node_deleted_event.ex @@ -1,4 +1,4 @@ defmodule Radiator.Outline.Event.NodeDeletedEvent do @moduledoc false - defstruct [:event_id, :node_id, :user_id, :children] + defstruct [:uuid, :node_id, :user_id, :children, :next_id] end diff --git a/lib/radiator/outline/event/node_inserted_event.ex b/lib/radiator/outline/event/node_inserted_event.ex index 783063aa..5220f6eb 100644 --- a/lib/radiator/outline/event/node_inserted_event.ex +++ b/lib/radiator/outline/event/node_inserted_event.ex @@ -1,5 +1,5 @@ defmodule Radiator.Outline.Event.NodeInsertedEvent do @moduledoc false - defstruct [:event_id, :node, :user_id, :next_id] + defstruct [:uuid, :node, :user_id, :next_id] end diff --git a/lib/radiator/outline/event/node_moved_event.ex b/lib/radiator/outline/event/node_moved_event.ex index 2e774cbc..bbcdd4d5 100644 --- a/lib/radiator/outline/event/node_moved_event.ex +++ b/lib/radiator/outline/event/node_moved_event.ex @@ -1,7 +1,7 @@ defmodule Radiator.Outline.Event.NodeMovedEvent do @moduledoc false defstruct [ - :event_id, + :uuid, :node_id, :parent_id, :prev_id, diff --git a/lib/radiator/outline/event_consumer.ex b/lib/radiator/outline/event_consumer.ex index 0af29e16..aeded465 100644 --- a/lib/radiator/outline/event_consumer.ex +++ b/lib/radiator/outline/event_consumer.ex @@ -74,7 +74,7 @@ defmodule Radiator.Outline.EventConsumer do node -> Outline.remove_node(node) end - %NodeDeletedEvent{node_id: node_id, event_id: command.event_id, user_id: command.user_id} + %NodeDeletedEvent{node_id: node_id, uuid: command.event_id, user_id: command.user_id} |> EventStore.persist_event() |> Dispatch.broadcast() @@ -84,7 +84,7 @@ defmodule Radiator.Outline.EventConsumer do defp handle_insert_node_result({:ok, %NodeRepoResult{node: node, next_id: next_id}}, command) do %NodeInsertedEvent{ node: node, - event_id: command.event_id, + uuid: command.event_id, user_id: command.user_id, next_id: next_id } @@ -108,7 +108,7 @@ defmodule Radiator.Outline.EventConsumer do parent_id: command.parent_id, prev_id: command.prev_id, user_id: command.user_id, - event_id: command.event_id, + uuid: command.event_id, next_id: result.next_id } |> EventStore.persist_event() @@ -127,7 +127,7 @@ defmodule Radiator.Outline.EventConsumer do node_id: node.uuid, content: node.content, user_id: command.user_id, - event_id: command.event_id + uuid: command.event_id } |> EventStore.persist_event() |> Dispatch.broadcast() diff --git a/lib/radiator_web/components/outline_components.ex b/lib/radiator_web/components/outline_components.ex index 16133f00..6ceb4d09 100644 --- a/lib/radiator_web/components/outline_components.ex +++ b/lib/radiator_web/components/outline_components.ex @@ -29,7 +29,7 @@ defmodule RadiatorWeb.OutlineComponents do ~H"""
- <%= @event.event_id %> + <%= @event.uuid %>
<%= @event.node_id %> - NodeContentChanged
@@ -42,11 +42,12 @@ defmodule RadiatorWeb.OutlineComponents do ~H"""
- <%= @event.event_id %> + <%= @event.uuid %>
<%= @event.node_id %> - NodeDeleted
-

moved nodes = ?

+

next node = ?

+

child nodes = ?

""" end @@ -55,14 +56,14 @@ defmodule RadiatorWeb.OutlineComponents do ~H"""
- <%= @event.event_id %> + <%= @event.uuid %>
<%= @event.node.uuid %> - NodeInserted

parent_id = <%= @event.node.parent_id %>

prev_id = <%= @event.node.prev_id %>

+

next_id = <%= @event.next_id %>

content = <%= @event.node.content %>

-

moved nodes = ?

""" end @@ -71,13 +72,15 @@ defmodule RadiatorWeb.OutlineComponents do ~H"""
- <%= @event.event_id %> + <%= @event.uuid %>
<%= @event.node_id %> - NodeMoved

parent_id = <%= @event.parent_id %>

prev_id = <%= @event.prev_id %>

-

moved nodes = ?

+

old_prev_id = <%= @event.old_prev_id %>

+

old_next_id = <%= @event.old_next_id %>

+

next_id = <%= @event.next_id %>

""" end diff --git a/lib/radiator_web/live/episode_live/index.ex b/lib/radiator_web/live/episode_live/index.ex index a0f31d4f..849c90da 100644 --- a/lib/radiator_web/live/episode_live/index.ex +++ b/lib/radiator_web/live/episode_live/index.ex @@ -10,14 +10,16 @@ defmodule RadiatorWeb.EpisodeLive.Index do NodeMovedEvent } + alias Radiator.EventStore alias Radiator.Podcast alias Radiator.Podcast.Episode alias RadiatorWeb.OutlineComponents @impl true - def mount(%{"show" => show_id}, _session, socket) do + def mount(%{"show" => show_id} = params, _session, socket) do show = Podcast.get_show!(show_id, preload: :episodes) + episode = get_selected_episode(params) socket |> assign(:page_title, show.title) @@ -25,8 +27,8 @@ defmodule RadiatorWeb.EpisodeLive.Index do |> assign(:show, show) |> assign(:episodes, show.episodes) |> assign(action: nil, episode: nil, form: nil) - |> stream_configure(:event_logs, dom_id: & &1.event_id) - |> stream(:event_logs, []) + |> stream_configure(:event_logs, dom_id: & &1.uuid) + |> stream(:event_logs, get_event_logs(episode)) |> reply(:ok) end @@ -149,7 +151,7 @@ defmodule RadiatorWeb.EpisodeLive.Index do end @impl true - def handle_info(%{event_id: <<_::binary-size(36)>> <> ":" <> id} = event, %{id: id} = socket) do + def handle_info(%{uuid: <<_::binary-size(36)>> <> ":" <> id} = event, %{id: id} = socket) do id = case event do %{node: %{uuid: id}} -> id @@ -218,6 +220,11 @@ defmodule RadiatorWeb.EpisodeLive.Index do Podcast.get_current_episode_for_show(show_id) end + def get_event_logs(nil), do: [] + def get_event_logs(episode) do + EventStore.list_event_data_by_episode(episode.id) + end + defp get_nodes(%{id: id}), do: NodeRepository.list_nodes_by_episode(id) defp get_nodes(_), do: [] diff --git a/test/radiator/event_store_test.exs b/test/radiator/event_store_test.exs index d6bcead0..d93078f3 100644 --- a/test/radiator/event_store_test.exs +++ b/test/radiator/event_store_test.exs @@ -22,7 +22,7 @@ defmodule Radiator.EventStoreTest do event = node_inserted_event_fixture(user_id: user.id) EventStore.persist_event(event) - stored_event = EventStore.get_event_data!(event.event_id) + stored_event = EventStore.get_event_data!(event.uuid) assert stored_event.data["next_id"] == event.next_id assert stored_event.user_id == event.user_id assert stored_event.event_type == "NodeInsertedEvent" @@ -65,7 +65,7 @@ defmodule Radiator.EventStoreTest do event = node_moved_event_fixture(user_id: user.id) EventStore.persist_event(event) - stored_event = EventStore.get_event_data!(event.event_id) + stored_event = EventStore.get_event_data!(event.uuid) assert stored_event.data["node_id"] == event.node_id assert stored_event.data["parent_id"] == event.parent_id assert stored_event.data["prev_id"] == event.prev_id diff --git a/test/support/fixtures/event_store_fixtures.ex b/test/support/fixtures/event_store_fixtures.ex index 3b0adbde..5c0cbe66 100644 --- a/test/support/fixtures/event_store_fixtures.ex +++ b/test/support/fixtures/event_store_fixtures.ex @@ -40,7 +40,7 @@ defmodule Radiator.EventStoreFixtures do %NodeInsertedEvent{ node: node, user_id: user_id, - event_id: Ecto.UUID.generate(), + uuid: Ecto.UUID.generate(), next_id: next.uuid } end @@ -52,7 +52,7 @@ defmodule Radiator.EventStoreFixtures do node_id: node.uuid, content: node.content, user_id: user_id, - event_id: Ecto.UUID.generate() + uuid: Ecto.UUID.generate() } end @@ -62,7 +62,7 @@ defmodule Radiator.EventStoreFixtures do %NodeDeletedEvent{ node_id: node.uuid, user_id: user_id, - event_id: Ecto.UUID.generate() + uuid: Ecto.UUID.generate() } end @@ -84,7 +84,7 @@ defmodule Radiator.EventStoreFixtures do next_id: next.uuid, old_next_id: old_next.uuid, old_prev_id: old_prev.uuid, - event_id: Ecto.UUID.generate() + uuid: Ecto.UUID.generate() } end end From 85ddc7c06e8ac76dae5ef1fdd6e77b78cfca3f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=B6ginger?= Date: Tue, 2 Jul 2024 21:39:14 +0200 Subject: [PATCH 2/7] WIP 2 list episodes, rename event_id => uuid --- lib/radiator/event_store.ex | 8 ++++++++ lib/radiator/outline/event/abstract_event.ex | 2 ++ lib/radiator_web/live/episode_live/index.ex | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/radiator/event_store.ex b/lib/radiator/event_store.ex index a7a6eb8c..b86cb675 100644 --- a/lib/radiator/event_store.ex +++ b/lib/radiator/event_store.ex @@ -19,6 +19,14 @@ defmodule Radiator.EventStore do event end + def list_events_by_episode(episode_id) do + episode_id + |> list_event_data_by_episode + |> Enum.map(&event_data_to_event/1) + end + + defp event_data_to_event(_event), do: nil + defp convert_to_uuid(<>), do: uuid defp convert_to_uuid(uuid), do: uuid diff --git a/lib/radiator/outline/event/abstract_event.ex b/lib/radiator/outline/event/abstract_event.ex index 9f8579c4..7d4904ec 100644 --- a/lib/radiator/outline/event/abstract_event.ex +++ b/lib/radiator/outline/event/abstract_event.ex @@ -3,6 +3,8 @@ defprotocol Radiator.Outline.Event.AbstractEvent do def event_type(event) end +# TODO remove protocol, rename to Event, move one hierarchy up + alias Radiator.Outline.Event.{ NodeContentChangedEvent, NodeInsertedEvent, diff --git a/lib/radiator_web/live/episode_live/index.ex b/lib/radiator_web/live/episode_live/index.ex index 849c90da..a6bbc9c7 100644 --- a/lib/radiator_web/live/episode_live/index.ex +++ b/lib/radiator_web/live/episode_live/index.ex @@ -222,7 +222,8 @@ defmodule RadiatorWeb.EpisodeLive.Index do def get_event_logs(nil), do: [] def get_event_logs(episode) do - EventStore.list_event_data_by_episode(episode.id) + # EventStore.list_event_data_by_episode(episode.id) + [] end defp get_nodes(%{id: id}), do: NodeRepository.list_nodes_by_episode(id) From c9820c23106a8000959857c0bdb056d023a8fcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20W=C3=B6ginger?= Date: Tue, 2 Jul 2024 22:26:28 +0200 Subject: [PATCH 3/7] WIP add virtual position field --- lib/radiator/outline/node.ex | 1 + test/radiator/outline_test.exs | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/lib/radiator/outline/node.ex b/lib/radiator/outline/node.ex index a11b50ef..0718b7a0 100644 --- a/lib/radiator/outline/node.ex +++ b/lib/radiator/outline/node.ex @@ -15,6 +15,7 @@ defmodule Radiator.Outline.Node do field :parent_id, Ecto.UUID field :prev_id, Ecto.UUID field :level, :integer, virtual: true + field :position, :integer, virtual: true belongs_to :episode, Episode diff --git a/test/radiator/outline_test.exs b/test/radiator/outline_test.exs index b2e79a50..03f4552c 100644 --- a/test/radiator/outline_test.exs +++ b/test/radiator/outline_test.exs @@ -678,6 +678,55 @@ defmodule Radiator.OutlineTest do end end + describe "get_node_postion/1" do + setup :complex_node_fixture + + test "with a given uuid we get all child nodes with positions",%{ + node_1: node_1, + node_2: node_2, + node_3: node_3, + node_4: node_4, + node_5: node_5, + node_6: node_6, + nested_node_1: nested_node_1, + nested_node_2: nested_node_2, + parent_node: parent_node + } do + # get_node_postion_for_level(parent_node.uuid) + parent_node = Outline.get_parent_node(node_4) + child_nodes = Outline.get_all_child_nodes(parent_node) + + # child_nodes + # sorted_child_nodes = [] + + # child_nodes.prev_id.nil? + + # child_nodes -- first + # sorted_child_nodes = [first] + + # child_nodes + # child_map %{ + # uuid: {node, position}, + + + # } + # sorted_child_nodes = [] + + temp_child_nodes = child_nodes + |> Enum.map(fn node -> {node.uuid, {node, nil}} end) + |> Map.new + + temp_child_nodes + |> Enum.map(fn {uuid, {node, _}} -> {node, get_position(node.prev_id, temp_child_nodes) end) + end + + end + + def get_position(uuid, %{uuid => {_node, nil}}), do: 1 + + def get_position(uuid, %{uuid => {_node, position}}), do: position + 1 + + defp assert_level_for_node(tree, node, level) do node = Enum.filter(tree, fn n -> n.uuid == node.uuid end) |> List.first() assert node.level == level From 6a9108f5a2982d891135445488e3016ac9a3169e Mon Sep 17 00:00:00 2001 From: sorax Date: Wed, 3 Jul 2024 08:10:14 +0200 Subject: [PATCH 4/7] disable unused --- lib/radiator_web/live/episode_live/index.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/radiator_web/live/episode_live/index.ex b/lib/radiator_web/live/episode_live/index.ex index a6bbc9c7..0fa1189a 100644 --- a/lib/radiator_web/live/episode_live/index.ex +++ b/lib/radiator_web/live/episode_live/index.ex @@ -10,7 +10,7 @@ defmodule RadiatorWeb.EpisodeLive.Index do NodeMovedEvent } - alias Radiator.EventStore + # alias Radiator.EventStore alias Radiator.Podcast alias Radiator.Podcast.Episode @@ -221,7 +221,8 @@ defmodule RadiatorWeb.EpisodeLive.Index do end def get_event_logs(nil), do: [] - def get_event_logs(episode) do + + def get_event_logs(_episode) do # EventStore.list_event_data_by_episode(episode.id) [] end From 162c67ebda8f12c1a24042d6ce1731b0c96e8664 Mon Sep 17 00:00:00 2001 From: sorax Date: Wed, 3 Jul 2024 08:10:29 +0200 Subject: [PATCH 5/7] fix: order nodes --- test/radiator/outline_test.exs | 61 ++++++++++------------------------ 1 file changed, 18 insertions(+), 43 deletions(-) diff --git a/test/radiator/outline_test.exs b/test/radiator/outline_test.exs index 03f4552c..978a74ab 100644 --- a/test/radiator/outline_test.exs +++ b/test/radiator/outline_test.exs @@ -679,53 +679,28 @@ defmodule Radiator.OutlineTest do end describe "get_node_postion/1" do - setup :complex_node_fixture - - test "with a given uuid we get all child nodes with positions",%{ - node_1: node_1, - node_2: node_2, - node_3: node_3, - node_4: node_4, - node_5: node_5, - node_6: node_6, - nested_node_1: nested_node_1, - nested_node_2: nested_node_2, - parent_node: parent_node - } do - # get_node_postion_for_level(parent_node.uuid) - parent_node = Outline.get_parent_node(node_4) - child_nodes = Outline.get_all_child_nodes(parent_node) - - # child_nodes - # sorted_child_nodes = [] - - # child_nodes.prev_id.nil? - - # child_nodes -- first - # sorted_child_nodes = [first] - - # child_nodes - # child_map %{ - # uuid: {node, position}, - - - # } - # sorted_child_nodes = [] - - temp_child_nodes = child_nodes - |> Enum.map(fn node -> {node.uuid, {node, nil}} end) - |> Map.new + setup :complex_node_fixture - temp_child_nodes - |> Enum.map(fn {uuid, {node, _}} -> {node, get_position(node.prev_id, temp_child_nodes) end) - end + test "with a given uuid we get all child nodes with positions", %{node_4: node_4} do + ordered_list = + node_4 + |> Outline.get_parent_node() + |> Outline.get_all_child_nodes() + |> Enum.map(fn node -> {node.prev_id, node} end) + |> Map.new() + |> order_nodes(nil, []) + assert ordered_list |> Enum.map(& &1.content) == + ["node_1", "node_2", "node_3", "node_4", "node_5", "node_6"] + end end - def get_position(uuid, %{uuid => {_node, nil}}), do: 1 - - def get_position(uuid, %{uuid => {_node, position}}), do: position + 1 - + defp order_nodes(index, prev_id, collection) do + case index[prev_id] do + %{uuid: uuid} = node -> order_nodes(index, uuid, [node | collection]) + _ -> Enum.reverse(collection) + end + end defp assert_level_for_node(tree, node, level) do node = Enum.filter(tree, fn n -> n.uuid == node.uuid end) |> List.first() From 4c3536cc5fa1723fe36b028dfcf9d602a950a219 Mon Sep 17 00:00:00 2001 From: sorax Date: Wed, 3 Jul 2024 15:05:00 +0200 Subject: [PATCH 6/7] removed todo (make credo happy) --- lib/radiator/outline/event/abstract_event.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/radiator/outline/event/abstract_event.ex b/lib/radiator/outline/event/abstract_event.ex index 7d4904ec..9f8579c4 100644 --- a/lib/radiator/outline/event/abstract_event.ex +++ b/lib/radiator/outline/event/abstract_event.ex @@ -3,8 +3,6 @@ defprotocol Radiator.Outline.Event.AbstractEvent do def event_type(event) end -# TODO remove protocol, rename to Event, move one hierarchy up - alias Radiator.Outline.Event.{ NodeContentChangedEvent, NodeInsertedEvent, From a0e5d8fc7bbc6635c558b64a90cfbef3735bce4d Mon Sep 17 00:00:00 2001 From: sorax Date: Sun, 7 Jul 2024 10:59:29 +0200 Subject: [PATCH 7/7] extract funtion to context --- lib/radiator/outline.ex | 19 +++++++++++++++++++ test/radiator/outline_test.exs | 21 +++------------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/radiator/outline.ex b/lib/radiator/outline.ex index 4acdc74c..62204e41 100644 --- a/lib/radiator/outline.ex +++ b/lib/radiator/outline.ex @@ -25,6 +25,25 @@ defmodule Radiator.Outline do require Logger + @doc """ + Returns a list of direct child nodes in correct order. + """ + + def order_child_nodes(%Node{} = node) do + node + |> get_all_child_nodes() + |> Enum.map(fn node -> {node.prev_id, node} end) + |> Map.new() + |> order_nodes(nil, []) + end + + defp order_nodes(index, prev_id, collection) do + case index[prev_id] do + %{uuid: uuid} = node -> order_nodes(index, uuid, [node | collection]) + _ -> Enum.reverse(collection) + end + end + @doc """ Inserts a node. diff --git a/test/radiator/outline_test.exs b/test/radiator/outline_test.exs index 978a74ab..685cffc1 100644 --- a/test/radiator/outline_test.exs +++ b/test/radiator/outline_test.exs @@ -678,30 +678,15 @@ defmodule Radiator.OutlineTest do end end - describe "get_node_postion/1" do + describe "order_child_nodes/1" do setup :complex_node_fixture - test "with a given uuid we get all child nodes with positions", %{node_4: node_4} do - ordered_list = - node_4 - |> Outline.get_parent_node() - |> Outline.get_all_child_nodes() - |> Enum.map(fn node -> {node.prev_id, node} end) - |> Map.new() - |> order_nodes(nil, []) - - assert ordered_list |> Enum.map(& &1.content) == + test "get child nodes in correct order", %{parent_node: parent_node} do + assert parent_node |> Outline.order_child_nodes() |> Enum.map(& &1.content) == ["node_1", "node_2", "node_3", "node_4", "node_5", "node_6"] end end - defp order_nodes(index, prev_id, collection) do - case index[prev_id] do - %{uuid: uuid} = node -> order_nodes(index, uuid, [node | collection]) - _ -> Enum.reverse(collection) - end - end - defp assert_level_for_node(tree, node, level) do node = Enum.filter(tree, fn n -> n.uuid == node.uuid end) |> List.first() assert node.level == level