Another emoji reaction bot(this one is for Discord)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

123 lines
2.7 KiB

use crate::models::NewUserProgram;
use crate::schema::user_programs::columns;
use crate::schema::user_programs::columns::discord_user_id;
use crate::schema::user_programs::dsl::user_programs;
use bigdecimal::{BigDecimal, FromPrimitive};
use diesel::{BoolExpressionMethods, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
use serenity::model::id::UserId;
use std::collections::HashMap;
pub(crate) struct Program {
pub(crate) code: HashMap<u32, String>,
}
impl Program {
pub fn new() -> Self {
Self {
code: HashMap::new(),
}
}
pub fn stringify(&self) -> String {
let mut code: Vec<(u32, String)> =
self.code.iter().map(|(a, b)| (*a, b.to_owned())).collect();
code.sort_by(|a, b| a.0.cmp(&b.0));
code.into_iter()
.map(|a| a.1)
.collect::<Vec<String>>()
.join("\n")
}
pub fn stringy_line_nums(&self) -> String {
let mut code: Vec<(u32, String)> =
self.code.iter().map(|(a, b)| (*a, b.to_owned())).collect();
code.sort_by(|a, b| a.0.cmp(&b.0));
code.into_iter()
.map(|a| format!("{}\t{}", a.0, a.1))
.collect::<Vec<String>>()
.join("\n")
}
pub fn save_program(&self, conn: &PgConnection, user_id: UserId, name: &str) -> Option<()> {
let code = self.stringy_line_nums();
let new_program = NewUserProgram {
discord_user_id: BigDecimal::from_u64(*user_id.as_u64()).unwrap(),
name,
code: code.as_str(),
};
diesel::insert_into(user_programs)
.values(&new_program)
.on_conflict((discord_user_id, columns::name))
.do_update()
.set(columns::code.eq(&code))
.execute(conn)
.ok()?;
Some(())
}
pub fn load_program(&mut self, conn: &PgConnection, user_id: UserId, name: &str) -> Option<()> {
let code: Vec<String> = user_programs
.filter(
columns::discord_user_id
.eq(BigDecimal::from_u64(*user_id.as_u64()).unwrap())
.and(columns::name.eq(name)),
)
.limit(1)
.select(columns::code)
.get_results(conn)
.ok()?;
if code.is_empty() {
return None;
}
let code = &code[0];
self.parse_string(code)?;
Some(())
}
fn parse_string(&mut self, code: &str) -> Option<()> {
let mut valid = true;
let code: HashMap<u32, String> = code
.split('\n')
.map(|line| {
let mut iter = line.splitn(2, &[' ', '\t'][..]);
// This unwrap_or_else thing is pretty ugly
// Is there a better way?
let line_num: u32 = iter
.next()
.unwrap_or_else(|| {
valid = false;
"0"
})
.parse()
.unwrap_or_else(|_| {
valid = false;
0
});
let line_code = iter
.next()
.unwrap_or_else(|| {
valid = false;
""
})
.to_owned();
(line_num, line_code)
})
.collect();
if valid {
self.code = code;
Some(())
} else {
None
}
}
}