use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite}; use super::{Id, Invite, Summary}; use crate::{ clock::DateTime, normalize::nfc, user::{self, User}, }; pub trait Provider { fn invites(&mut self) -> Invites; } impl Provider for Transaction<'_, Sqlite> { fn invites(&mut self) -> Invites { Invites(self) } } pub struct Invites<'t>(&'t mut SqliteConnection); impl Invites<'_> { pub async fn create( &mut self, issuer: &User, issued_at: &DateTime, ) -> Result { let id = Id::generate(); let invite = sqlx::query_as!( Invite, r#" insert into invite (id, issuer, issued_at) values ($1, $2, $3) returning id as "id: Id", issuer as "issuer: user::Id", issued_at as "issued_at: DateTime" "#, id, issuer.id, issued_at ) .fetch_one(&mut *self.0) .await?; Ok(invite) } pub async fn by_id(&mut self, invite: &Id) -> Result { let invite = sqlx::query_as!( Invite, r#" select id as "id: Id", issuer as "issuer: user::Id", issued_at as "issued_at: DateTime" from invite where id = $1 "#, invite, ) .fetch_one(&mut *self.0) .await?; Ok(invite) } pub async fn summary(&mut self, invite: &Id) -> Result { let invite = sqlx::query!( r#" select invite.id as "invite_id: Id", issuer.id as "issuer_id: user::Id", issuer.display_name as "issuer_name: nfc::String", invite.issued_at as "invite_issued_at: DateTime" from invite join user as issuer on (invite.issuer = issuer.id) where invite.id = $1 "#, invite, ) .map(|row| Summary { id: row.invite_id, issuer: row.issuer_name, issued_at: row.invite_issued_at, }) .fetch_one(&mut *self.0) .await?; Ok(invite) } pub async fn accept(&mut self, invite: &Invite) -> Result<(), sqlx::Error> { sqlx::query_scalar!( r#" delete from invite where id = $1 returning 1 as "deleted: bool" "#, invite.id, ) .fetch_one(&mut *self.0) .await?; Ok(()) } pub async fn expire(&mut self, expire_at: &DateTime) -> Result<(), sqlx::Error> { sqlx::query!( r#" delete from invite where issued_at < $1 "#, expire_at, ) .execute(&mut *self.0) .await?; Ok(()) } }