Refactor to delegate pattern

This commit is contained in:
mitchell 2020-10-05 18:45:56 -04:00
parent e212eee751
commit b492d338cd
5 changed files with 53 additions and 42 deletions

4
Vagrantfile vendored
View File

@ -14,7 +14,7 @@ Vagrant.configure('2') do |config| # rubocop:disable Metrics/BlockLength
dev.vm.network 'private_network', ip: '192.168.50.11' dev.vm.network 'private_network', ip: '192.168.50.11'
dev.vm.provider 'virtualbox' do |vb| dev.vm.provider 'virtualbox' do |vb|
vb.memory = '2048' vb.memory = '4096'
vb.cpus = 4 vb.cpus = 4
end end
@ -131,7 +131,7 @@ Vagrant.configure('2') do |config| # rubocop:disable Metrics/BlockLength
prod.vm.network 'private_network', ip: '192.168.50.10' prod.vm.network 'private_network', ip: '192.168.50.10'
prod.vm.provider 'virtualbox' do |vb| prod.vm.provider 'virtualbox' do |vb|
vb.memory = '2048' vb.memory = '4096'
vb.cpus = 4 vb.cpus = 4
end end

View File

@ -4,6 +4,7 @@ defmodule Shortnr.URL do
domain service. domain service.
""" """
alias Shortnr.Transport alias Shortnr.Transport
alias Shortnr.URL.Repo
defstruct id: "", defstruct id: "",
created_at: DateTime.utc_now(), created_at: DateTime.utc_now(),
@ -17,37 +18,39 @@ defmodule Shortnr.URL do
url: URI.t() url: URI.t()
} }
@spec create(String.t(), module()) :: {:ok, String.t()} | Transport.error() @spec create(String.t()) :: {:ok, String.t()} | Transport.error()
def create(url, repo) do def create(url) when is_binary(url) do
url_struct = %__MODULE__{id: generate_id(), url: URI.parse(url)} url_struct = %__MODULE__{id: generate_id(), url: URI.parse(url)}
{:ok, extant_url} = repo.get(url_struct.id) url_struct.id
|> Repo.get()
if extant_url do |> create_if_no_collision(url_struct, url)
create(url, repo)
else
:ok = repo.put(url_struct)
{:ok, url_struct.id}
end
end end
@spec get(String.t(), module()) :: {:ok, t()} | Transport.error() defp create_if_no_collision({:ok, nil}, %__MODULE__{id: id} = url, _url) do
def get(key, repo) do :ok = Repo.put(url)
case repo.get(key) do {:ok, id}
{:ok, nil} -> {:error, {:not_found, "url could not be found with the given id"}}
{:ok, url} -> {:ok, url}
end
end end
@spec list(module()) :: {:ok, list(t())} | Transport.error() defp create_if_no_collision({:ok, _}, _url_struct, url) when is_binary(url), do: create(url)
def list(repo) do
{:ok, _} = repo.list @spec get(String.t()) :: {:ok, t()} | Transport.error()
def get(key) do
key
|> Repo.get()
|> handle_errors
end end
@spec delete(String.t(), module()) :: {:ok, String.t()} | Transport.error() @spec list() :: {:ok, list(t())}
def delete(key, repo) do def list do
:ok = repo.delete(key) handle_errors(Repo.list())
{:ok, "Success"} end
@spec delete(String.t()) :: {:ok, String.t()}
def delete(key) do
key
|> Repo.delete()
|> handle_errors
end end
@id_chars String.codepoints("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXWYZ0123456789") @id_chars String.codepoints("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXWYZ0123456789")
@ -58,6 +61,13 @@ defmodule Shortnr.URL do
do: Enum.random(@id_chars) do: Enum.random(@id_chars)
end end
defp handle_errors({:ok, nil}),
do: {:error, {:not_found, "url could not be found with the given id"}}
defp handle_errors({:ok, _} = response), do: response
defp handle_errors(:ok), do: {:ok, "Success"}
defimpl Transport.Text.Encodable do defimpl Transport.Text.Encodable do
alias Shortnr.URL alias Shortnr.URL
@spec encode(URL.t()) :: String.t() @spec encode(URL.t()) :: String.t()

View File

@ -8,7 +8,7 @@ defmodule Shortnr.URL.Endpoints do
def list(conn) do def list(conn) do
conn conn
|> HTTP.wrap() |> HTTP.wrap()
|> HTTP.handle(fn -> URL.list(URL.Repo.ETS) end) |> HTTP.handle(&URL.list/0)
|> Text.encode() |> Text.encode()
|> HTTP.send(:ok) |> HTTP.send(:ok)
end end
@ -16,7 +16,7 @@ defmodule Shortnr.URL.Endpoints do
def create(conn, url) do def create(conn, url) do
conn conn
|> HTTP.wrap(url) |> HTTP.wrap(url)
|> HTTP.handle(&URL.create(&1, URL.Repo.ETS)) |> HTTP.handle(&URL.create(&1))
|> Text.encode() |> Text.encode()
|> HTTP.send(:created) |> HTTP.send(:created)
end end
@ -24,7 +24,7 @@ defmodule Shortnr.URL.Endpoints do
def get(conn, id) do def get(conn, id) do
conn conn
|> HTTP.wrap(id) |> HTTP.wrap(id)
|> HTTP.handle(&URL.get(&1, URL.Repo.ETS)) |> HTTP.handle(&URL.get(&1))
|> Text.encode() |> Text.encode()
|> HTTP.send(:found) |> HTTP.send(:found)
end end
@ -32,7 +32,7 @@ defmodule Shortnr.URL.Endpoints do
def delete(conn, id) do def delete(conn, id) do
conn conn
|> HTTP.wrap(id) |> HTTP.wrap(id)
|> HTTP.handle(&URL.delete(&1, URL.Repo.ETS)) |> HTTP.handle(&URL.delete(&1))
|> Text.encode() |> Text.encode()
|> HTTP.send(:ok) |> HTTP.send(:ok)
end end

View File

@ -7,9 +7,18 @@ defmodule Shortnr.URL.Repo do
alias Shortnr.Transport alias Shortnr.Transport
alias Shortnr.URL alias Shortnr.URL
@callback put(URL.t()) :: :ok | Transport.error() @spec put(URL.t()) :: :ok | Transport.error()
@callback get(String.t()) :: {:ok, URL.t()} | Transport.error() defdelegate put(url), to: Shortnr.URL.Repo.ETS
@callback delete(String.t()) :: :ok | Transport.error()
@callback list() :: {:ok, list(URL.t())} | Transport.error() @spec get(String.t()) :: {:ok, URL.t() | nil} | Transport.error()
@callback reset() :: :ok | Transport.error() defdelegate get(url), to: Shortnr.URL.Repo.ETS
@spec delete(String.t()) :: :ok | Transport.error()
defdelegate delete(url), to: Shortnr.URL.Repo.ETS
@spec list() :: {:ok, list(URL.t())} | Transport.error()
defdelegate list(), to: Shortnr.URL.Repo.ETS
@spec reset() :: :ok | Transport.error()
defdelegate reset(), to: Shortnr.URL.Repo.ETS
end end

View File

@ -2,11 +2,7 @@ defmodule Shortnr.URL.Repo.ETS do
@moduledoc """ @moduledoc """
This module is an implemention of the Repo behaviour using the Erlang ETS library. This module is an implemention of the Repo behaviour using the Erlang ETS library.
""" """
alias Shortnr.URL.Repo
@behaviour Repo
@impl true
def get(key) do def get(key) do
case ets().lookup(:urls, key) |> List.first() do case ets().lookup(:urls, key) |> List.first() do
{_, url} -> {:ok, url} {_, url} -> {:ok, url}
@ -14,25 +10,21 @@ defmodule Shortnr.URL.Repo.ETS do
end end
end end
@impl true
def put(url) do def put(url) do
:ok = ets().insert(:urls, {url.id, url}) :ok = ets().insert(:urls, {url.id, url})
:ok :ok
end end
@impl true
def list do def list do
resp = ets().select(:urls, [{:"$1", [], [:"$1"]}]) resp = ets().select(:urls, [{:"$1", [], [:"$1"]}])
{:ok, resp |> Enum.map(&elem(&1, 1))} {:ok, resp |> Enum.map(&elem(&1, 1))}
end end
@impl true
def delete(key) do def delete(key) do
:ok = ets().delete(:urls, key) :ok = ets().delete(:urls, key)
:ok :ok
end end
@impl true
def reset do def reset do
:ok = ets().delete_all_objects(:urls) :ok = ets().delete_all_objects(:urls)
end end