diff options
Diffstat (limited to 'src/plugins/tell/database.rs')
| -rw-r--r-- | src/plugins/tell/database.rs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/plugins/tell/database.rs b/src/plugins/tell/database.rs new file mode 100644 index 0000000..98e9fb3 --- /dev/null +++ b/src/plugins/tell/database.rs @@ -0,0 +1,150 @@ +#[cfg(feature = "mysql")] +extern crate dotenv; + +#[cfg(feature = "mysql")] +use std::sync::Arc; +use std::collections::HashMap; + +#[cfg(feature = "mysql")] +use diesel::prelude::*; +#[cfg(feature = "mysql")] +use diesel::mysql::MysqlConnection; +#[cfg(feature = "mysql")] +use r2d2::Pool; +#[cfg(feature = "mysql")] +use r2d2_diesel::ConnectionManager; + +use chrono::NaiveDateTime; + +#[cfg(feature = "mysql")] +use failure::ResultExt; + +use super::error::*; + +#[cfg_attr(feature = "mysql", derive(Queryable))] +#[derive(PartialEq, Clone, Debug)] +pub struct TellMessage { + pub id: i64, + pub sender: String, + pub receiver: String, + pub time: NaiveDateTime, + pub message: String, +} + +#[cfg_attr(feature = "mysql", derive(Insertable))] +#[cfg_attr(feature = "mysql", table_name = "tells")] +pub struct NewTellMessage<'a> { + pub sender: &'a str, + pub receiver: &'a str, + pub time: NaiveDateTime, + pub message: &'a str, +} + +pub trait Database: Send { + fn insert_tell(&mut self, tell: &NewTellMessage) -> Result<(), TellError>; + fn get_tells(&self, receiver: &str) -> Result<Vec<TellMessage>, TellError>; + fn get_receivers(&self) -> Result<Vec<String>, TellError>; + fn delete_tells(&mut self, receiver: &str) -> Result<(), TellError>; +} + +// HashMap +impl Database for HashMap<String, Vec<TellMessage>> { + fn insert_tell(&mut self, tell: &NewTellMessage) -> Result<(), TellError> { + let tell = TellMessage { + id: 0, + sender: tell.sender.to_string(), + receiver: tell.receiver.to_string(), + time: tell.time, + message: tell.message.to_string(), + }; + + let receiver = tell.receiver.clone(); + let tell_messages = self.entry(receiver) + .or_insert_with(|| Vec::with_capacity(3)); + (*tell_messages).push(tell); + + Ok(()) + } + + fn get_tells(&self, receiver: &str) -> Result<Vec<TellMessage>, TellError> { + Ok(self.get(receiver).cloned().ok_or(ErrorKind::NotFound)?) + } + + fn get_receivers(&self) -> Result<Vec<String>, TellError> { + Ok(self.iter() + .map(|(receiver, _)| receiver.to_owned()) + .collect::<Vec<_>>()) + } + + fn delete_tells(&mut self, receiver: &str) -> Result<(), TellError> { + match self.remove(receiver) { + Some(_) => Ok(()), + None => Err(ErrorKind::NotFound)?, + } + } +} + +// Diesel automatically defines the tells module as public. +// We create a schema module to keep it private. +#[cfg(feature = "mysql")] +mod schema { + table! { + tells (id) { + id -> Bigint, + sender -> Varchar, + receiver -> Varchar, + time -> Timestamp, + message -> Varchar, + } + } +} + +#[cfg(feature = "mysql")] +use self::schema::tells; + +#[cfg(feature = "mysql")] +impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> { + fn insert_tell(&mut self, tell: &NewTellMessage) -> Result<(), TellError> { + use diesel; + + let conn = &*self.get().expect("Failed to get connection"); + diesel::insert_into(tells::table) + .values(tell) + .execute(conn) + .context(ErrorKind::MysqlError)?; + + Ok(()) + } + + fn get_tells(&self, receiver: &str) -> Result<Vec<TellMessage>, TellError> { + use self::tells::columns; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + Ok(tells::table + .filter(columns::receiver.eq(receiver)) + .order(columns::time.asc()) + .load::<TellMessage>(conn) + .context(ErrorKind::MysqlError)?) + } + + fn get_receivers(&self) -> Result<Vec<String>, TellError> { + use self::tells::columns; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + Ok(tells::table + .select(columns::receiver) + .load::<String>(conn) + .context(ErrorKind::MysqlError)?) + } + + fn delete_tells(&mut self, receiver: &str) -> Result<(), TellError> { + use diesel; + use self::tells::columns; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + diesel::delete(tells::table.filter(columns::receiver.eq(receiver))) + .execute(conn) + .context(ErrorKind::MysqlError)?; + Ok(()) + } +} |
