From a408a38ffb78c4f22820a505aa4d37c7fbcccaa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20B=C3=B6hme?= Date: Wed, 7 Aug 2024 00:09:00 +0200 Subject: [PATCH] feat: add database --- lib/todo/cache.ex | 3 +- lib/todo/database.ex | 51 +++++++++++++++++++++++++ lib/todo/server.ex | 90 ++++++++++++++++++++++---------------------- 3 files changed, 97 insertions(+), 47 deletions(-) create mode 100644 lib/todo/database.ex diff --git a/lib/todo/cache.ex b/lib/todo/cache.ex index 724b539..9e29fc6 100644 --- a/lib/todo/cache.ex +++ b/lib/todo/cache.ex @@ -3,6 +3,7 @@ defmodule Todo.Cache do @impl GenServer def init(_init_args) do + Todo.Database.start() {:ok, %{}} end @@ -13,7 +14,7 @@ defmodule Todo.Cache do {:reply, process, state} :error -> - new_process = Todo.Server.start() + {:ok, new_process} = Todo.Server.start(name) new_state = Map.put(state, name, new_process) diff --git a/lib/todo/database.ex b/lib/todo/database.ex new file mode 100644 index 0000000..07862fd --- /dev/null +++ b/lib/todo/database.ex @@ -0,0 +1,51 @@ +defmodule Todo.Database do + use GenServer + + @db_folder "./persist" + + def start do + GenServer.start(__MODULE__, nil, name: __MODULE__) + end + + def store(key, data) do + GenServer.cast(__MODULE__, {:store, key, data}) + end + + def get(key) do + GenServer.call(__MODULE__, {:get, key}) + end + + @impl GenServer + def init(_) do + File.mkdir_p!(@db_folder) + + {:ok, nil} + end + + @impl GenServer + def handle_cast({:store, key, data}, state) do + key + |> file_name() + |> File.write!(:erlang.term_to_binary(data)) + + {:noreply, state} + end + + @impl GenServer + def handle_call({:get, key}, _, state) do + data = + case File.read(file_name(key)) do + {:ok, contents} -> + :erlang.binary_to_term(contents) + + _ -> + nil + end + + {:reply, data, state} + end + + def file_name(key) do + Path.join(@db_folder, to_string(key)) + end +end diff --git a/lib/todo/server.ex b/lib/todo/server.ex index 09e75b7..2688873 100644 --- a/lib/todo/server.ex +++ b/lib/todo/server.ex @@ -1,52 +1,8 @@ defmodule Todo.Server do use GenServer - @impl GenServer - def init(%_{} = todo_list) do - {:ok, todo_list} - end - - @impl GenServer - def init(entries) do - {:ok, Todo.List.new(entries)} - end - - @impl GenServer - def handle_call({:entries, date}, _from, todo_list) do - entries = Todo.List.entries(todo_list, date) - - {:reply, entries, todo_list} - end - - @impl GenServer - def handle_cast({:add, entry}, todo_list) do - new_todo_list = Todo.List.add(todo_list, entry) - - {:noreply, new_todo_list} - end - - @impl GenServer - def handle_cast({:update, id, update_fun}, todo_list) do - new_todo_list = Todo.List.update(todo_list, id, update_fun) - - {:noreply, new_todo_list} - end - - @impl GenServer - def handle_cast({:delete, id}, todo_list) do - new_todo_list = Todo.List.delete(todo_list, id) - - {:noreply, new_todo_list} - end - - def start(entries \\ []) - - def start(%_{} = todo_list) do - GenServer.start(__MODULE__, todo_list) - end - - def start(entries) do - GenServer.start(__MODULE__, entries) + def start(name) do + GenServer.start(__MODULE__, name) end def add(pid, entry) do @@ -64,4 +20,46 @@ defmodule Todo.Server do def delete(pid, id) do GenServer.cast(pid, {:delete, id}) end + + @impl GenServer + def init(name) do + {:ok, {name, nil}, {:continue, :init}} + end + + @impl GenServer + def handle_continue(:init, {name, nil}) do + todo_list = Todo.Database.get(name) || Todo.List.new() + {:noreply, {name, todo_list}} + end + + @impl GenServer + def handle_call({:entries, date}, _from, {name, todo_list}) do + entries = Todo.List.entries(todo_list, date) + + {:reply, entries, {name, todo_list}} + end + + @impl GenServer + def handle_cast({:add, entry}, {name, todo_list}) do + new_todo_list = Todo.List.add(todo_list, entry) + Todo.Database.store(name, new_todo_list) + + {:noreply, {name, new_todo_list}} + end + + @impl GenServer + def handle_cast({:update, id, update_fun}, {name, todo_list}) do + new_todo_list = Todo.List.update(todo_list, id, update_fun) + Todo.Database.store(name, new_todo_list) + + {:noreply, {name, new_todo_list}} + end + + @impl GenServer + def handle_cast({:delete, id}, {name, todo_list}) do + new_todo_list = Todo.List.delete(todo_list, id) + Todo.Database.store(name, new_todo_list) + + {:noreply, {name, new_todo_list}} + end end