Skip to content

Commit

Permalink
Enforce elixir formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
danschultzer committed Jan 4, 2024
1 parent e68821b commit b6329f0
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 236 deletions.
17 changes: 16 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ on:
workflow_call:

jobs:
lint:
runs-on: ubuntu-latest
name: Linter
env:
MIX_ENV: test
steps:
- uses: actions/checkout@v3
- uses: erlef/setup-beam@v1
with:
otp-version: 26.0
elixir-version: 1.15
- run: mix deps.get
- run: mix compile --warnings-as-errors
- run: mix credo --strict --ignore design.alias
- run: mix format --check-formatted

test:
services:
postgres:
Expand Down Expand Up @@ -40,5 +56,4 @@ jobs:
elixir-version: ${{matrix.version.elixir}}
- run: mix deps.get mix compile --warnings-as-errors
- run: mix test
- run: mix credo

74 changes: 43 additions & 31 deletions lib/idempotency_plug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,28 @@ defmodule IdempotencyPlug do
There's no Idempotency-Key request headers.
"""

defexception [
message: "No idempotency key found. You need to set the `Idempotency-Key` header for all POST requests: 'Idempotency-Key: KEY'",
plug_status: :bad_request
]
defexception message:
"No idempotency key found. You need to set the `Idempotency-Key` header for all POST requests: 'Idempotency-Key: KEY'",
plug_status: :bad_request
end

defmodule MultipleHeadersError do
@moduledoc """
There are multiple Idempotency-Key request headers.
"""

defexception [
message: "Only one `Idempotency-Key` header can be sent",
plug_status: :bad_request
]
defexception message: "Only one `Idempotency-Key` header can be sent",
plug_status: :bad_request
end

defmodule ConcurrentRequestError do
@moduledoc """
There's another request currently being processed for this ID.
"""

defexception [
message: "A request with the same `Idempotency-Key` is currently being processed",
plug_status: :conflict
]
defexception message:
"A request with the same `Idempotency-Key` is currently being processed",
plug_status: :conflict
end

defmodule RequestPayloadFingerprintMismatchError do
Expand All @@ -51,18 +47,20 @@ defmodule IdempotencyPlug do

defexception [
:reason,
message: "The original request was interrupted and can't be recovered as it's in an unknown state",
message:
"The original request was interrupted and can't be recovered as it's in an unknown state",
plug_status: :internal_server_error
]
end

defimpl Plug.Exception, for: [
NoHeadersError,
MultipleHeadersError,
ConcurrentRequestError,
RequestPayloadFingerprintMismatchError,
HaltedResponseError
] do
defimpl Plug.Exception,
for: [
NoHeadersError,
MultipleHeadersError,
ConcurrentRequestError,
RequestPayloadFingerprintMismatchError,
HaltedResponseError
] do
def status(%{plug_status: status}), do: Plug.Conn.Status.code(status)
def actions(_), do: []
end
Expand Down Expand Up @@ -173,7 +171,7 @@ defmodule IdempotencyPlug do

other ->
raise ArgumentError,
"option :tracker must be one of PID or Atom, got: #{inspect(other)}"
"option :tracker must be one of PID or Atom, got: #{inspect(other)}"
end

opts
Expand Down Expand Up @@ -208,7 +206,7 @@ defmodule IdempotencyPlug do
other ->
# credo:disable-for-next-line Credo.Check.Warning.RaiseInsideRescue
raise ArgumentError,
"option :with should be one of :exception or MFA, got: #{inspect(other)}"
"option :with should be one of :exception or MFA, got: #{inspect(other)}"
end
end

Expand Down Expand Up @@ -254,9 +252,14 @@ defmodule IdempotencyPlug do

processed_key =
case Keyword.get(opts, :idempotency_key, {__MODULE__, :idempotency_key}) do
{mod, fun} -> apply(mod, fun, [conn, key])
{mod, fun, args} -> apply(mod, fun, [conn, key | args])
other -> raise ArgumentError, "option :idempotency_key must be a MFA, got: #{inspect(other)}"
{mod, fun} ->
apply(mod, fun, [conn, key])

{mod, fun, args} ->
apply(mod, fun, [conn, key | args])

other ->
raise ArgumentError, "option :idempotency_key must be a MFA, got: #{inspect(other)}"
end

hash(:idempotency_key, processed_key, opts)
Expand All @@ -275,9 +278,15 @@ defmodule IdempotencyPlug do
defp hash_request_payload(conn, opts) do
payload =
case Keyword.get(opts, :request_payload, {__MODULE__, :request_payload}) do
{mod, fun} -> apply(mod, fun, [conn])
{mod, fun, args} -> apply(mod, fun, [conn | args])
other -> raise ArgumentError, "option :request_payload must be a MFA tuple, got: #{inspect(other)}"
{mod, fun} ->
apply(mod, fun, [conn])

{mod, fun, args} ->
apply(mod, fun, [conn | args])

other ->
raise ArgumentError,
"option :request_payload must be a MFA tuple, got: #{inspect(other)}"
end

hash(:request_payload, payload, opts)
Expand Down Expand Up @@ -308,7 +317,7 @@ defmodule IdempotencyPlug do
Conn.register_before_send(conn, fn conn ->
case RequestTracker.put_response(tracker, key, conn_to_response(conn)) do
{:ok, expires} -> put_expires_header(conn, expires)
{:error, error} -> raise "failed to put response in cache store, got: #{inspect error}"
{:error, error} -> raise "failed to put response in cache store, got: #{inspect(error)}"
end
end)
end
Expand Down Expand Up @@ -338,8 +347,11 @@ defmodule IdempotencyPlug do
mod
|> apply(fun, [conn, error | args])
|> case do
%Conn{halted: true} = conn -> conn
other -> raise ArgumentError, "option :with MUST return a halted conn, got: #{inspect(other)}"
%Conn{halted: true} = conn ->
conn

other ->
raise ArgumentError, "option :with MUST return a halted conn, got: #{inspect(other)}"
end
end
end
16 changes: 8 additions & 8 deletions lib/idempotency_plug/request_tracker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ defmodule IdempotencyPlug.RequestTracker do
fingerprint differs from what was stored, an error is returned.
"""
@spec track(atom() | pid(), binary(), binary()) ::
{:error, term()} |
{:init, binary(), DateTime.t()} |
{:mismatch, {:fingerprint, binary()}, DateTime.t()} |
{:processing, {atom(), pid()}, DateTime.t()} |
{:cache, {:ok, any()}, DateTime.t()} |
{:cache, {:halted, term()}, DateTime.t()}
{:error, term()}
| {:init, binary(), DateTime.t()}
| {:mismatch, {:fingerprint, binary()}, DateTime.t()}
| {:processing, {atom(), pid()}, DateTime.t()}
| {:cache, {:ok, any()}, DateTime.t()}
| {:cache, {:halted, term()}, DateTime.t()}
def track(name_or_pid, request_id, fingerprint) do
GenServer.call(name_or_pid, {:track, request_id, fingerprint})
end
Expand Down Expand Up @@ -162,7 +162,7 @@ defmodule IdempotencyPlug.RequestTracker do

def handle_call({:put_response, request_id, response}, _from, state) do
{store, store_opts} = fetch_store(state.options)
{_finished, state} = pop_monitored(state, &elem(&1, 0) == request_id)
{_finished, state} = pop_monitored(state, &(elem(&1, 0) == request_id))
data = {:ok, response}
expires_at = expires_at(state.options)

Expand All @@ -189,7 +189,7 @@ defmodule IdempotencyPlug.RequestTracker do
@impl true
def handle_info({:DOWN, _ref, :process, pid, reason}, state) do
{store, store_opts} = fetch_store(state.options)
{finished, state} = pop_monitored(state, &elem(&1, 1) == pid)
{finished, state} = pop_monitored(state, &(elem(&1, 1) == pid))
data = {:halted, reason}
expires_at = expires_at(state.options)

Expand Down
3 changes: 2 additions & 1 deletion lib/idempotency_plug/store.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ defmodule IdempotencyPlug.Store do

@callback setup(options()) :: :ok | {:error, term()}
@callback lookup(request_id(), options()) :: {data(), fingerprint(), expires_at()} | :not_found
@callback insert(request_id(), data(), fingerprint(), expires_at(), options()) :: :ok | {:error, term()}
@callback insert(request_id(), data(), fingerprint(), expires_at(), options()) ::
:ok | {:error, term()}
@callback update(request_id(), data(), expires_at(), options()) :: :ok | {:error, term()}
@callback prune(options()) :: :ok
end
Loading

0 comments on commit b6329f0

Please sign in to comment.