defmodule NavEx.Adapters.Session do
@moduledoc """
NavEx.Adapters.Session is adapter for keeping user's navigation history
utilizing Plug.Conn session.
## Adapter config
config NavEx.Adapters.Session,
history_key: "nav_ex_history" # name of the key in session where navigation history is saved
"""
@behaviour NavEx.Adapter
import Plug.Conn
@session_key Application.compile_env(NavEx.Adapters.Session, :history_key) || "nav_ex_history"
@history_length (Application.compile_env(:nav_ex, :history_length) || 10) + 1
@impl NavEx.Adapter
def children, do: []
@impl NavEx.Adapter
def insert(%Plug.Conn{request_path: request_path} = conn) do
case get_session(conn, @session_key) do
nil ->
{:ok, put_session(conn, @session_key, [request_path])}
history ->
{:ok, handle_history(conn, history, request_path)}
end
end
@impl NavEx.Adapter
def list(%Plug.Conn{} = conn) do
case get_session(conn, @session_key) do
nil ->
{:error, :not_found}
history ->
{:ok, history}
end
end
@impl NavEx.Adapter
def last_path(%Plug.Conn{} = conn) do
case get_session(conn, @session_key) do
nil ->
{:error, :not_found}
history when length(history) > 1 ->
{:ok, Enum.at(history, 1)}
_history ->
{:ok, nil}
end
end
@impl NavEx.Adapter
def path_at(%Plug.Conn{} = conn, n) do
case get_session(conn, @session_key) do
nil ->
{:error, :not_found}
history ->
{:ok, Enum.at(history, n)}
end
end
###
defp handle_history(conn, history, path) do
if length(history) < @history_length do
put_session(conn, @session_key, [path | history])
else
cut_history =
history
|> Enum.reverse()
|> tl()
|> Enum.reverse()
put_session(conn, @session_key, [path | cut_history])
end
end
end