|
|
@@ -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
|