AccountRepository

Trait AccountRepository 

Source
pub trait AccountRepository<R, G>
where R: AccessHierarchy + Eq, G: Eq + Clone,
{ // Required methods fn store_account( &self, account: Account<R, G>, ) -> impl Future<Output = Result<Option<Account<R, G>>>>; fn delete_account( &self, user_id: &str, ) -> impl Future<Output = Result<Option<Account<R, G>>>>; fn update_account( &self, account: Account<R, G>, ) -> impl Future<Output = Result<Option<Account<R, G>>>>; fn query_account_by_user_id( &self, user_id: &str, ) -> impl Future<Output = Result<Option<Account<R, G>>>>; }
Expand description

Repository abstraction for persisting and retrieving Account entities.

This trait is implemented by storage backends (e.g. in‑memory, SurrealDB, SeaORM). It deliberately uses an Option<Account<..>> in results for operations where absence is a normal outcome (delete / update / query) so callers can distinguish “not found” from actual errors (Result::Err).

§Semantics

MethodSuccess (Ok) Return ValueTypical None MeaningError (Err) Meaning
store_accountSome(Account) if storedNone only if backend chooses (rare)Persistence / connectivity / constraint failure
delete_accountSome(Account) = deleted & returnedNone = no account with that user idBackend / IO failure
update_accountSome(Account) = updatedNone = no existing account to updateBackend / IO / optimistic concurrency failure
query_account_by_user_idSome(Account) = foundNone = not foundBackend / IO failure

Backends SHOULD:

  • Treat user_id as a logical unique key
  • Enforce uniqueness at storage level where possible
  • Return identical timing characteristics for “found” vs “not found” where feasible (helps upstream login logic resist user enumeration timing attacks)

§Concurrency & Consistency

This trait does not prescribe isolation semantics. Implementations should document:

  • Whether updates are last‑write‑wins
  • Whether optimistic locking / versioning is applied

§Example (generic usage)


use axum_gate::accounts::Account;
use axum_gate::prelude::{Role, Group};
use axum_gate::accounts::AccountRepository;
use axum_gate::repositories::memory::MemoryAccountRepository;

async fn load_or_create(
    repo: &MemoryAccountRepository<Role, Group>,
    template: Account<Role, Group>
) -> axum_gate::errors::Result<Account<Role, Group>> {
    if let Some(existing) = repo.query_account_by_user_id(&template.user_id).await? {
        Ok(existing)
    } else {
        Ok(repo.store_account(template).await?.expect("store returned None"))
    }
}

§Error Handling

Return Err only for exceptional backend failures (connectivity, serialization, constraint violation, etc.). Use Ok(None) for “not found” / “no-op” outcomes.

§Extensibility

If you add methods (e.g. pagination, search), prefer separate traits to avoid forcing all backends to implement optional features.

Required Methods§

Source

fn store_account( &self, account: Account<R, G>, ) -> impl Future<Output = Result<Option<Account<R, G>>>>

Persist a new account.

Implementations SHOULD enforce uniqueness of user_id. Returning Ok(Some(account)) indicates success. Returning Ok(None) is discouraged unless there is a documented race / conditional insert semantics the backend wishes to expose.

Source

fn delete_account( &self, user_id: &str, ) -> impl Future<Output = Result<Option<Account<R, G>>>>

Delete an account identified by its user_id.

Returns:

  • Ok(Some(account)) if the account existed and was removed
  • Ok(None) if no account matched user_id
  • Err(e) on backend error
Source

fn update_account( &self, account: Account<R, G>, ) -> impl Future<Output = Result<Option<Account<R, G>>>>

Update an existing account.

Implementations may perform either full replacement or partial persistence depending on backend capabilities (document if non‑standard). Returns:

  • Ok(Some(updated_account)) on success
  • Ok(None) if the account does not exist
  • Err(e) on failure
Source

fn query_account_by_user_id( &self, user_id: &str, ) -> impl Future<Output = Result<Option<Account<R, G>>>>

Fetch an account by its logical user identifier.

This must not leak timing differences exploitable for enumeration if used together with authentication flows relying on indistinguishable “not found”.

Returns:

  • Ok(Some(account)) if found
  • Ok(None) if not found
  • Err(e) on backend failure

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl<R, G> AccountRepository<R, G> for MemoryAccountRepository<R, G>
where Account<R, G>: Clone, R: AccessHierarchy + Eq, G: Eq + Clone,