Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce elixir formatting #5

Merged
merged 1 commit into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading