use std::{
collections::HashMap,
sync::{Arc, Mutex, PoisonError},
};
#[derive(Debug, Clone, Default)]
pub struct User{
pub id: String,
pub name: String,
}
pub trait UserRepo: Clone + Send + Sync {
fn insert(
&self,
user: User,
) -> impl std::future::Future<Output = Result<Option<User>, UserRepoError>>
+ std::marker::Send
+ std::marker::Sized;
fn get(
&self,
user_id: &str,
) -> impl std::future::Future<Output = Result<User, UserRepoError>>
+ std::marker::Send
+ std::marker::Sized;
fn remove(
&self,
user_id: &str,
) -> impl std::future::Future<Output = Result<User, UserRepoError>>
+ std::marker::Send
+ std::marker::Sized;
}
#[derive(Debug, Clone)]
pub enum UserRepoError {
RepoAccessFailed,
NotFound(String),
}
impl<T> From<PoisonError<T>> for UserRepoError {
fn from(_value: PoisonError<T>) -> Self {
Self::RepoAccessFailed
}
}
#[derive(Debug, Clone, Default)]
pub struct InMemoryUserRepo {
map: Arc<Mutex<HashMap<String, User>>>,
}
impl UserRepo for InMemoryUserRepo {
async fn insert(&self, user: User) -> Result<Option<User>, UserRepoError> {
Ok(self
.map
.lock()
.unwrap()
.insert(user.id.clone(), user))
}
async fn get(
&self,
user_id: &str,
) -> Result<User, UserRepoError> {
self
.map
.lock()?
.get(user_id).cloned()
.ok_or(UserRepoError::NotFound(user_id.to_string()))
}
async fn remove(&self, user_id: &str) -> Result<User, UserRepoError> {
self
.map
.lock()?
.remove(user_id)
.ok_or(UserRepoError::NotFound(user_id.to_string()))
}
}