From 625ca41cf54bac0268f7bde9d7ad9017c03d5919 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 21 Sep 2018 00:21:43 +0200 Subject: Quote: Add initial quote plugin --- src/plugins/quote/database.rs | 136 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/plugins/quote/database.rs (limited to 'src/plugins/quote/database.rs') diff --git a/src/plugins/quote/database.rs b/src/plugins/quote/database.rs new file mode 100644 index 0000000..6ad08a0 --- /dev/null +++ b/src/plugins/quote/database.rs @@ -0,0 +1,136 @@ +use std::collections::HashMap; +#[cfg(feature = "mysql")] +use std::sync::Arc; + +#[cfg(feature = "mysql")] +use diesel::mysql::MysqlConnection; +#[cfg(feature = "mysql")] +use diesel::prelude::*; +#[cfg(feature = "mysql")] +use failure::ResultExt; +#[cfg(feature = "mysql")] +use r2d2::Pool; +#[cfg(feature = "mysql")] +use r2d2_diesel::ConnectionManager; + +use chrono::NaiveDateTime; + +use super::error::*; + +#[cfg_attr(feature = "mysql", derive(Queryable))] +#[derive(Clone, Debug)] +pub struct Quote { + pub quotee: String, + pub channel: String, + pub idx: i32, + pub content: String, + pub author: String, + pub created: NaiveDateTime, +} + +#[cfg_attr(feature = "mysql", derive(Insertable))] +#[cfg_attr(feature = "mysql", table_name = "quotes")] +pub struct NewQuote<'a> { + pub quotee: &'a str, + pub channel: &'a str, + pub idx: i32, + pub content: &'a str, + pub author: &'a str, + pub created: NaiveDateTime, +} + +pub trait Database: Send + Sync { + fn insert_quote(&mut self, quote: &NewQuote) -> Result<(), QuoteError>; + fn get_quote(&self, quotee: &str, channel: &str, idx: i32) -> Result; + fn count_quotes(&self, quotee: &str, channel: &str) -> Result; +} + +// HashMap +impl Database for HashMap<(String, String, i32), Quote, S> { + fn insert_quote(&mut self, quote: &NewQuote) -> Result<(), QuoteError> { + let quote = Quote { + quotee: quote.quotee.to_owned(), + channel: quote.channel.to_owned(), + idx: quote.idx, + content: quote.content.to_owned(), + author: quote.author.to_owned(), + created: quote.created, + }; + + let quotee = quote.quotee.clone(); + let channel = quote.channel.clone(); + match self.insert((quotee, channel, quote.idx), quote) { + None => Ok(()), + Some(_) => Err(ErrorKind::Duplicate)?, + } + } + + fn get_quote(&self, quotee: &str, channel: &str, idx: i32) -> Result { + Ok(self.get(&(quotee.to_owned(), channel.to_owned(), idx)) + .cloned() + .ok_or(ErrorKind::NotFound)?) + } + + fn count_quotes(&self, quotee: &str, channel: &str) -> Result { + Ok(self.iter().filter(|&(&(ref n, ref c, _), _)| n == quotee && c == channel).count() as i32) + } +} + +// Diesel automatically defines the quotes module as public. +// We create a schema module to keep it private. +#[cfg(feature = "mysql")] +mod schema { + table! { + quotes (quotee, channel, idx) { + quotee -> Varchar, + channel -> Varchar, + idx -> Integer, + content -> Text, + author -> Varchar, + created -> Timestamp, + } + } +} + +#[cfg(feature = "mysql")] +use self::schema::quotes; + +#[cfg(feature = "mysql")] +impl Database for Arc>> { + fn insert_quote(&mut self, quote: &NewQuote) -> Result<(), QuoteError> { + use diesel; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + diesel::insert_into(quotes::table) + .values(quote) + .execute(conn) + .context(ErrorKind::MysqlError)?; + + Ok(()) + } + + fn get_quote(&self, quotee: &str, channel: &str, idx: i32) -> Result { + let conn = &*self.get().context(ErrorKind::NoConnection)?; + Ok(quotes::table + .find((quotee, channel, idx)) + .first(conn) + .context(ErrorKind::MysqlError)?) + } + + fn count_quotes(&self, quotee: &str, channel: &str) -> Result { + use diesel; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + let count: Result = quotes::table + .filter(quotes::columns::quotee.eq(quotee)) + .filter(quotes::columns::channel.eq(channel)) + .count() + .get_result(conn); + + match count { + Ok(c) => Ok(c as i32), + Err(diesel::NotFound) => Ok(0), + Err(e) => Err(e).context(ErrorKind::MysqlError)?, + } + } +} -- cgit v1.2.3-70-g09d2 From 9401a62004f3ac7313f6bf12d2649d5af61835c5 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 21 Sep 2018 00:59:44 +0200 Subject: Quote: Ignore trailing space when no index was specified --- src/plugins/quote/database.rs | 12 +++++++++--- src/plugins/quote/mod.rs | 20 +++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'src/plugins/quote/database.rs') diff --git a/src/plugins/quote/database.rs b/src/plugins/quote/database.rs index 6ad08a0..49d6058 100644 --- a/src/plugins/quote/database.rs +++ b/src/plugins/quote/database.rs @@ -46,7 +46,9 @@ pub trait Database: Send + Sync { } // HashMap -impl Database for HashMap<(String, String, i32), Quote, S> { +impl Database + for HashMap<(String, String, i32), Quote, S> +{ fn insert_quote(&mut self, quote: &NewQuote) -> Result<(), QuoteError> { let quote = Quote { quotee: quote.quotee.to_owned(), @@ -66,13 +68,17 @@ impl Database for HashMap<(String, St } fn get_quote(&self, quotee: &str, channel: &str, idx: i32) -> Result { - Ok(self.get(&(quotee.to_owned(), channel.to_owned(), idx)) + Ok(self + .get(&(quotee.to_owned(), channel.to_owned(), idx)) .cloned() .ok_or(ErrorKind::NotFound)?) } fn count_quotes(&self, quotee: &str, channel: &str) -> Result { - Ok(self.iter().filter(|&(&(ref n, ref c, _), _)| n == quotee && c == channel).count() as i32) + Ok(self + .iter() + .filter(|&(&(ref n, ref c, _), _)| n == quotee && c == channel) + .count() as i32) } } diff --git a/src/plugins/quote/mod.rs b/src/plugins/quote/mod.rs index 43333e7..9f8a29e 100644 --- a/src/plugins/quote/mod.rs +++ b/src/plugins/quote/mod.rs @@ -3,9 +3,9 @@ use std::marker::PhantomData; use std::str::FromStr; use antidote::RwLock; +use chrono::NaiveDateTime; use irc::client::prelude::*; use rand::{thread_rng, Rng}; -use chrono::NaiveDateTime; use time; use plugin::*; @@ -56,7 +56,8 @@ impl Quote { created: NaiveDateTime::from_timestamp(tm.sec, 0u32), }; - Ok(self.quotes + Ok(self + .quotes .write() .insert_quote("e) .map(|()| "Successfully added!")?) @@ -92,9 +93,11 @@ impl Quote { } let idx = match command.tokens.len() { - 1 => thread_rng().gen_range(1, count + 1), + 1 | _ if command.tokens[1].is_empty() => thread_rng().gen_range(1, count + 1), _ => { - let idx = match i32::from_str(&command.tokens[1]) { + let idx_string = &command.tokens[1]; + + let idx = match i32::from_str(idx_string) { Ok(i) => i, Err(_) => Err(ErrorKind::InvalidIndex)?, }; @@ -107,13 +110,16 @@ impl Quote { } }; - let quote = self.quotes + let quote = self + .quotes .read() .get_quote(quotee, channel, idx) .context(ErrorKind::NotFound)?; - - Ok(format!("\"{}\" - {}[{}/{}]", quote.content, quote.quotee, idx, count)) + Ok(format!( + "\"{}\" - {}[{}/{}]", + quote.content, quote.quotee, idx, count + )) } fn info(&self, command: &PluginCommand) -> Result { -- cgit v1.2.3-70-g09d2