lib/documents/session/supervisor.ex

defmodule Ravix.Documents.Session.Supervisor do
  @moduledoc """
  Supervisor for RavenDB Sessions
  """
  alias Ravix.Documents.Session
  alias Ravix.Documents.Session.State, as: SessionState

  @spec start_link(any) :: :ignore | {:error, any} | {:ok, pid}
  def start_link(store) do
    children = [
      {PartitionSupervisor, child_spec: DynamicSupervisor, name: supervisor_name(store)}
    ]

    Supervisor.start_link(children, strategy: :one_for_one)
  end

  @doc """
  Creates a session with the informed initial state
  """
  @spec create_session(SessionState.t()) :: :ignore | {:error, any} | {:ok, pid} | {:ok, pid, any}
  def create_session(%SessionState{} = session_state) do
    session_state = session_state |> SessionState.update_last_session_call()

    DynamicSupervisor.start_child(
      {:via, PartitionSupervisor,
       {supervisor_name(session_state.store), session_state.session_id}},
      {Session, session_state}
    )
  end

  @doc """
  Closes a session for the informed store using the session pid or session_id
  """
  @spec close_session(atom(), bitstring()) :: :ok | {:error, :not_found}
  def close_session(store, session_id) do
    case Registry.lookup(:sessions, session_id) do
      [] ->
        {:error, :not_found}

      sessions ->
        {pid, _} = sessions |> Enum.at(0)

        DynamicSupervisor.terminate_child(
          {:via, PartitionSupervisor, {supervisor_name(store), session_id}},
          pid
        )
    end
  end

  defp supervisor_name(store) do
    :"#{store}.Sessions"
  end
end