diff options
Diffstat (limited to 'src/channel/repo/broadcast.rs')
| -rw-r--r-- | src/channel/repo/broadcast.rs | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/src/channel/repo/broadcast.rs b/src/channel/repo/broadcast.rs new file mode 100644 index 0000000..3ca7396 --- /dev/null +++ b/src/channel/repo/broadcast.rs @@ -0,0 +1,112 @@ +use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction}; + +use crate::{ + clock::DateTime, + repo::{ + channel, + login::{self, Login, Logins}, + message, + }, +}; + +pub trait Provider { + fn broadcast(&mut self) -> Broadcast; +} + +impl<'c> Provider for Transaction<'c, Sqlite> { + fn broadcast(&mut self) -> Broadcast { + Broadcast(self) + } +} + +pub struct Broadcast<'t>(&'t mut SqliteConnection); + +#[derive(Clone, Debug, serde::Serialize)] +pub struct Message { + pub id: message::Id, + pub sender: Login, + pub body: String, + pub sent_at: DateTime, +} + +impl<'c> Broadcast<'c> { + pub async fn create( + &mut self, + sender: &login::Id, + channel: &channel::Id, + body: &str, + sent_at: &DateTime, + ) -> Result<Message, sqlx::Error> { + let id = message::Id::generate(); + + let sender = Logins::from(&mut *self.0).by_id(sender).await?; + + let message = sqlx::query!( + r#" + insert into message + (id, sender, channel, body, sent_at) + values ($1, $2, $3, $4, $5) + returning + id as "id: message::Id", + sender as "sender: login::Id", + body, + sent_at as "sent_at: DateTime" + "#, + id, + sender.id, + channel, + body, + sent_at, + ) + .map(|row| { + debug_assert!(row.sender == sender.id); + Message { + id: row.id, + sender: sender.clone(), + body: row.body, + sent_at: row.sent_at, + } + }) + .fetch_one(&mut *self.0) + .await?; + + Ok(message) + } + + pub async fn replay( + &mut self, + channel: &channel::Id, + resume_at: Option<&DateTime>, + ) -> Result<Vec<Message>, sqlx::Error> { + let messages = sqlx::query!( + r#" + select + message.id as "id: message::Id", + login.id as "sender_id: login::Id", + login.name as sender_name, + message.body, + message.sent_at as "sent_at: DateTime" + from message + join login on message.sender = login.id + where channel = $1 + and coalesce(sent_at > $2, true) + order by sent_at asc + "#, + channel, + resume_at, + ) + .map(|row| Message { + id: row.id, + sender: Login { + id: row.sender_id, + name: row.sender_name, + }, + body: row.body, + sent_at: row.sent_at, + }) + .fetch_all(&mut *self.0) + .await?; + + Ok(messages) + } +} |
