Nadia.SessionStore behaviour (nadia v1.5.0)

View Source

Behaviour and helpers for optional bot session storage.

Session storage is deliberately explicit. Nadia does not start or name a global session store for you; applications supervise a store backend and pass that store to their handlers when they need state.

children = [
  {Nadia.SessionStore.ETS, name: MyApp.BotSessions}
]

store = {Nadia.SessionStore.ETS, MyApp.BotSessions}
{:ok, key} = Nadia.SessionStore.chat_key(context)
{:ok, session} = Nadia.SessionStore.update(store, key, fn session ->
  Map.update(session, :seen, 1, &(&1 + 1))
end)

The built-in ETS backend is intended for local development and single-node bots. Production applications can implement this behaviour with their own storage when they need persistence, cross-node consistency, or stronger concurrency guarantees.

Summary

Types

Session keys used by Nadia helper functions.

A session value.

A concrete store reference.

Functions

Builds a chat-scoped session key from a context or update.

Builds a combined chat/user session key from a context or update.

Deletes a session from a store.

Reads a session from a store.

Writes a complete session map to a store.

Atomically updates a session in a store when the backend supports it.

Builds a user-scoped session key from a context or update.

Types

key()

@type key() ::
  {:chat, integer() | binary()}
  | {:user, integer()}
  | {:chat_user, integer() | binary(), integer()}

Session keys used by Nadia helper functions.

session()

@type session() :: map()

A session value.

Nadia keeps sessions as maps so backends can store arbitrary application state without Nadia prescribing a schema.

store()

@type store() :: {module(), term()}

A concrete store reference.

The first element is the backend module implementing this behaviour. The second element is backend-specific state, such as a pid or registered process name for Nadia.SessionStore.ETS.

update_or_context()

@type update_or_context() :: Nadia.Model.Update.t() | Nadia.Context.t()

Callbacks

delete(store_state, key)

@callback delete(store_state :: term(), key()) :: :ok | {:error, term()}

get(store_state, key)

@callback get(store_state :: term(), key()) :: {:ok, session()} | {:error, term()}

put(store_state, key, session)

@callback put(store_state :: term(), key(), session()) :: :ok | {:error, term()}

update(store_state, key, function)

@callback update(store_state :: term(), key(), (session() ->
                                        session()
                                        | {:ok, session()}
                                        | {:error, term()})) ::
  {:ok, session()} | {:error, term()}

Functions

chat_key(update_or_context)

@spec chat_key(update_or_context()) :: {:ok, key()} | {:error, :missing_chat_id}

Builds a chat-scoped session key from a context or update.

chat_user_key(update_or_context)

@spec chat_user_key(update_or_context()) ::
  {:ok, key()} | {:error, :missing_chat_id | :missing_user_id}

Builds a combined chat/user session key from a context or update.

delete(arg1, key)

@spec delete(store(), key()) :: :ok | {:error, term()}

Deletes a session from a store.

get(arg1, key)

@spec get(store(), key()) :: {:ok, session()} | {:error, term()}

Reads a session from a store.

Missing sessions return {:ok, %{}}.

put(arg1, key, session)

@spec put(store(), key(), session()) :: :ok | {:error, term()}

Writes a complete session map to a store.

update(arg1, key, fun)

@spec update(store(), key(), (session() ->
                          session() | {:ok, session()} | {:error, term()})) ::
  {:ok, session()} | {:error, term()}

Atomically updates a session in a store when the backend supports it.

The update function receives the current session map, or %{} when the session is missing. It may return a new session map, {:ok, session}, or {:error, reason}. Error returns do not write a new value.

user_key(update_or_context)

@spec user_key(update_or_context()) :: {:ok, key()} | {:error, :missing_user_id}

Builds a user-scoped session key from a context or update.