From e9799560e033c3de59a99946ad3811dff47c8819 Mon Sep 17 00:00:00 2001 From: Jokler Date: Mon, 14 May 2018 20:46:59 +0200 Subject: Remind: Add Mysql as a possible database The bot also responds with the id and time of a reminder after creation to allow the creator to delete them. Furthermore the InvalidCommand message was fixed and the unnecessary dotenv dependency was removed. --- src/plugins/remind/database.rs | 128 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 9 deletions(-) (limited to 'src/plugins/remind/database.rs') diff --git a/src/plugins/remind/database.rs b/src/plugins/remind/database.rs index c0c127e..e434ec0 100644 --- a/src/plugins/remind/database.rs +++ b/src/plugins/remind/database.rs @@ -1,14 +1,30 @@ -#[cfg(feature = "mysql")] -extern crate dotenv; - use std::collections::HashMap; use std::collections::hash_map::Entry; use std::fmt; +#[cfg(feature = "mysql")] +use std::sync::Arc; + +#[cfg(feature = "mysql")] +use diesel::mysql::MysqlConnection; +#[cfg(feature = "mysql")] +use diesel::prelude::*; +#[cfg(feature = "mysql")] +use r2d2::Pool; +#[cfg(feature = "mysql")] +use r2d2_diesel::ConnectionManager; + +#[cfg(feature = "mysql")] +use failure::ResultExt; + use chrono::NaiveDateTime; use super::error::*; +#[cfg(feature = "mysql")] +static LAST_ID_SQL: &'static str = "SELECT LAST_INSERT_ID()"; + +#[cfg_attr(feature = "mysql", derive(Queryable))] #[derive(Clone, Debug)] pub struct Event { pub id: i64, @@ -16,7 +32,7 @@ pub struct Event { pub content: String, pub author: String, pub time: NaiveDateTime, - pub repeat: Option, + pub repeat: Option, } impl fmt::Display for Event { @@ -29,18 +45,20 @@ impl fmt::Display for Event { } } +#[cfg_attr(feature = "mysql", derive(Insertable))] +#[cfg_attr(feature = "mysql", table_name = "events")] #[derive(Debug)] pub struct NewEvent<'a> { pub receiver: &'a str, pub content: &'a str, pub author: &'a str, pub time: &'a NaiveDateTime, - pub repeat: Option, + pub repeat: Option, } pub trait Database: Send + Sync { - fn insert_event(&mut self, event: &NewEvent) -> Result<(), RemindError>; - fn update_event_time(&mut self, id: i64, &NaiveDateTime) -> Result<(), RemindError>; + fn insert_event(&mut self, event: &NewEvent) -> Result; + fn update_event_time(&mut self, id: i64, time: &NaiveDateTime) -> Result<(), RemindError>; fn get_events_before(&self, time: &NaiveDateTime) -> Result, RemindError>; fn get_user_events(&self, user: &str) -> Result, RemindError>; fn get_event(&self, id: i64) -> Result; @@ -49,7 +67,7 @@ pub trait Database: Send + Sync { // HashMap impl Database for HashMap { - fn insert_event(&mut self, event: &NewEvent) -> Result<(), RemindError> { + fn insert_event(&mut self, event: &NewEvent) -> Result { let mut id = 0; while self.contains_key(&id) { id += 1; @@ -65,7 +83,7 @@ impl Database for HashMap { }; match self.insert(id, event) { - None => Ok(()), + None => Ok(id), Some(_) => Err(ErrorKind::Duplicate)?, } } @@ -126,3 +144,95 @@ impl Database for HashMap { } } } + +#[cfg(feature = "mysql")] +mod schema { + table! { + events (id) { + id -> Bigint, + receiver -> Varchar, + content -> Text, + author -> Varchar, + time -> Timestamp, + repeat -> Nullable, + } + } +} + +#[cfg(feature = "mysql")] +use self::schema::events; + +#[cfg(feature = "mysql")] +impl Database for Arc>> { + fn insert_event(&mut self, event: &NewEvent) -> Result { + use diesel::{self, dsl::sql, types::Bigint}; + let conn = &*self.get().context(ErrorKind::NoConnection)?; + + diesel::insert_into(events::table) + .values(event) + .execute(conn) + .context(ErrorKind::MysqlError)?; + + let id = sql::(LAST_ID_SQL) + .get_result(conn) + .context(ErrorKind::MysqlError)?; + + Ok(id) + } + + fn update_event_time(&mut self, id: i64, time: &NaiveDateTime) -> Result<(), RemindError> { + use self::events::columns; + use diesel; + let conn = &*self.get().context(ErrorKind::NoConnection)?; + + match diesel::update(events::table.filter(columns::id.eq(id))) + .set(columns::time.eq(time)) + .execute(conn) + { + Ok(0) => Err(ErrorKind::NotFound)?, + Ok(_) => Ok(()), + Err(e) => Err(e).context(ErrorKind::MysqlError)?, + } + } + + fn get_events_before(&self, time: &NaiveDateTime) -> Result, RemindError> { + use self::events::columns; + let conn = &*self.get().context(ErrorKind::NoConnection)?; + + Ok(events::table + .filter(columns::time.lt(time)) + .load::(conn) + .context(ErrorKind::MysqlError)?) + } + + fn get_user_events(&self, user: &str) -> Result, RemindError> { + use self::events::columns; + let conn = &*self.get().context(ErrorKind::NoConnection)?; + + Ok(events::table + .filter(columns::receiver.eq(user)) + .load::(conn) + .context(ErrorKind::MysqlError)?) + } + + fn get_event(&self, id: i64) -> Result { + let conn = &*self.get().context(ErrorKind::NoConnection)?; + + Ok(events::table + .find(id) + .first(conn) + .context(ErrorKind::MysqlError)?) + } + + fn delete_event(&mut self, id: i64) -> Result<(), RemindError> { + use self::events::columns; + use diesel; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + match diesel::delete(events::table.filter(columns::id.eq(id))).execute(conn) { + Ok(0) => Err(ErrorKind::NotFound)?, + Ok(_) => Ok(()), + Err(e) => Err(e).context(ErrorKind::MysqlError)?, + } + } +} -- cgit v1.2.3-70-g09d2