use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; use crate::{ clock::DateTime, event::{Instant, ResumePoint, Sequence}, login::{password::StoredHash, History, Id, Login}, }; pub trait Provider { fn logins(&mut self) -> Logins; } impl<'c> Provider for Transaction<'c, Sqlite> { fn logins(&mut self) -> Logins { Logins(self) } } pub struct Logins<'t>(&'t mut SqliteConnection); impl<'c> Logins<'c> { pub async fn create( &mut self, name: &str, password_hash: &StoredHash, created: &Instant, ) -> Result { let id = Id::generate(); let login = sqlx::query!( r#" insert into login (id, name, password_hash, created_sequence, created_at) values ($1, $2, $3, $4, $5) returning id as "id: Id", name, created_sequence as "created_sequence: Sequence", created_at as "created_at: DateTime" "#, id, name, password_hash, created.sequence, created.at, ) .map(|row| History { login: Login { id: row.id, name: row.name, }, created: Instant { at: row.created_at, sequence: row.created_sequence, }, }) .fetch_one(&mut *self.0) .await?; Ok(login) } pub async fn all(&mut self, resume_at: ResumePoint) -> Result, sqlx::Error> { let channels = sqlx::query!( r#" select id as "id: Id", name, created_sequence as "created_sequence: Sequence", created_at as "created_at: DateTime" from login where coalesce(created_sequence <= $1, true) order by created_sequence "#, resume_at, ) .map(|row| History { login: Login { id: row.id, name: row.name, }, created: Instant { at: row.created_at, sequence: row.created_sequence, }, }) .fetch_all(&mut *self.0) .await?; Ok(channels) } pub async fn replay(&mut self, resume_at: ResumePoint) -> Result, sqlx::Error> { let messages = sqlx::query!( r#" select id as "id: Id", name, created_sequence as "created_sequence: Sequence", created_at as "created_at: DateTime" from login where coalesce(login.created_sequence > $1, true) "#, resume_at, ) .map(|row| History { login: Login { id: row.id, name: row.name, }, created: Instant { at: row.created_at, sequence: row.created_sequence, }, }) .fetch_all(&mut *self.0) .await?; Ok(messages) } } impl<'t> From<&'t mut SqliteConnection> for Logins<'t> { fn from(tx: &'t mut SqliteConnection) -> Self { Self(tx) } }