theenglishway (time) 4 роки тому
батько
коміт
e3e0bf68c8

+ 1 - 0
lib/vaccins/application.ex

@@ -13,6 +13,7 @@ defmodule Vaccins.Application do
       {Phoenix.PubSub, name: Vaccins.PubSub},
       # Start the Endpoint (http/https)
       VaccinsWeb.Endpoint,
+      Vaccins.LocationStore,
       {Finch, name: Vaccins.Finch}
     ]
 

+ 62 - 26
lib/vaccins/location_store.ex

@@ -12,6 +12,9 @@ defmodule Vaccins.LocationStore do
       availability_query_params: []
     ]
 
+    def from_json(m = %{provider: "Elixir.Vaccins.Queries.Doctolib"}),
+      do: struct(Location, m) |> Map.replace(:provider, Vaccins.Queries.Doctolib)
+
     def set_id(l = %Location{name: name}), do: %{l | id: name |> String.to_atom()}
 
     def build_query(l = %Location{availability_query_params: params, provider: provider})
@@ -72,47 +75,80 @@ defmodule Vaccins.LocationStore do
     end
   end
 
+  use GenServer
   require Ex2ms
   import Ecto.Changeset
   alias Vaccins.Queries.Doctolib
   @name Vaccins.LocationStore
+  @file_path "./location_store.json"
+
+  def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: @name)
+
+  @impl true
+  def init(_opts) do
+    locations = read_file() |> Map.new(&{&1.id, &1})
+    {:ok, %{locations: locations}}
+  end
 
   def get_locations() do
-    select_all =
-      Ex2ms.fun do
-        x -> x
-      end
+    GenServer.call(@name, :get_locations)
+  end
 
-    :dets.select(@name, select_all) |> Enum.map(fn {_k, v} -> v end)
+  def add_location(params) do
+    GenServer.call(@name, {:add_location, params})
   end
 
-  def insert_all(locations) do
-    locations |> Enum.each(&:dets.insert(@name, {&1.id, &1}))
+  def delete_location(id) do
+    GenServer.call(@name, {:delete_location, id})
   end
 
-  def build_location(l = %Location{}), do: l |> Location.set_id() |> Location.build_query()
+  @impl true
+  def handle_call(:get_locations, _, state = %{locations: locations}),
+    do: {:reply, locations |> Map.values() |> Enum.map(&Location.build_query/1), state}
 
-  def add_location(params) do
+  @impl true
+  def handle_call({:add_location, params}, _, state = %{locations: locations}) do
     cs = params |> LocationRaw.changeset()
 
-    with {:ok, raw_location} <- cs |> apply_action(:insert),
-         processed <-
-           %Location{
-             name: raw_location.name,
-             booking_page: raw_location.booking_page,
-             availability_query_params: raw_location |> LocationRaw.to_query_params(),
-             provider: Doctolib
-           }
-           |> build_location,
-         true <- :dets.insert_new(@name, {processed.id, processed}) do
-      :ok
-    else
-      false -> cs |> add_error(:name, "error on insertion", []) |> apply_action(:insert)
-      e = {:error, _} -> e
-    end
+    resp =
+      with {:ok, raw_location} <- cs |> apply_action(:insert),
+           processed <-
+             %Location{
+               name: raw_location.name,
+               booking_page: raw_location.booking_page,
+               availability_query_params: raw_location |> LocationRaw.to_query_params(),
+               provider: Doctolib
+             }
+             |> Location.set_id(),
+           locations <- locations |> Map.put(processed.id, processed),
+           :ok <- locations |> Map.values() |> write_file() do
+        :ok
+        {:reply, :ok, %{locations: locations}}
+      else
+        e = {:error, _} -> {:reply, e, state}
+      end
   end
 
-  def delete_location(id) do
-    :dets.delete(@name, id)
+  @impl true
+  def handle_call({:delete_location, id}, _, state = %{locations: locations}) do
+    with locations <- locations |> Map.delete(id),
+         :ok <- locations |> Map.values() |> write_file(),
+         do: {:reply, :ok, %{locations: locations}}
   end
+
+  defp read_file(),
+    do:
+      with(
+        {:ok, content} <- File.read(@file_path),
+        {:ok, decoded} <- Jason.decode(content, keys: :atoms),
+        do: decoded |> Enum.map(&Location.from_json/1)
+      )
+
+  defp write_file(locations),
+    do:
+      with(
+        {:ok, encoded} <-
+          Jason.encode(locations |> Enum.map(&(&1 |> Map.from_struct())), pretty: true),
+        do: File.write(@file_path, encoded)
+      )
 end

+ 1 - 1
lib/vaccins_web/live/location_component.ex

@@ -40,7 +40,7 @@ defmodule VaccinsWeb.LocationComponent do
   end
 
   def handle_event("delete", _, socket = %{assigns: %{id: id}}) do
-    if LocationStore.delete_location(id), do: send(self(), {:location_deleted, id})
+    if :ok == LocationStore.delete_location(id), do: send(self(), {:location_deleted, id})
     {:noreply, socket}
   end