use sqlx::sqlite::SqlitePool; use super::create::{self, Create}; use crate::{clock::DateTime, event::Broadcaster, login::Login, name::Name, password::Password}; pub struct Users<'a> { db: &'a SqlitePool, events: &'a Broadcaster, } impl<'a> Users<'a> { pub const fn new(db: &'a SqlitePool, events: &'a Broadcaster) -> Self { Self { db, events } } pub async fn create( &self, name: &Name, password: &Password, created_at: &DateTime, ) -> Result { let create = Create::begin(name, password, created_at); let validated = create.validate()?; let mut tx = self.db.begin().await?; let stored = validated.store(&mut tx).await?; tx.commit().await?; let login = stored.login().to_owned(); stored.publish(self.events); Ok(login) } } #[derive(Debug, thiserror::Error)] pub enum CreateError { #[error("invalid user name: {0}")] InvalidName(Name), #[error(transparent)] PasswordHash(#[from] password_hash::Error), #[error(transparent)] Database(#[from] sqlx::Error), } impl From for CreateError { fn from(error: create::Error) -> Self { match error { create::Error::InvalidName(name) => Self::InvalidName(name), create::Error::PasswordHash(error) => Self::PasswordHash(error), } } }