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.provider 'virtualbox' do |vb|
vb.memory = '2048'
vb.memory = '4096'
vb.cpus = 4
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.provider 'virtualbox' do |vb|
vb.memory = '2048'
vb.memory = '4096'
vb.cpus = 4
end

View File

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

View File

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

View File

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

View File

@ -2,11 +2,7 @@ defmodule Shortnr.URL.Repo.ETS do
@moduledoc """
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
case ets().lookup(:urls, key) |> List.first() do
{_, url} -> {:ok, url}
@ -14,25 +10,21 @@ defmodule Shortnr.URL.Repo.ETS do
end
end
@impl true
def put(url) do
:ok = ets().insert(:urls, {url.id, url})
:ok
end
@impl true
def list do
resp = ets().select(:urls, [{:"$1", [], [:"$1"]}])
{:ok, resp |> Enum.map(&elem(&1, 1))}
end
@impl true
def delete(key) do
:ok = ets().delete(:urls, key)
:ok
end
@impl true
def reset do
:ok = ets().delete_all_objects(:urls)
end