uberbot/src/database.rs

93 lines
3 KiB
Rust
Raw Normal View History

2022-01-02 14:58:54 -06:00
use rusqlite::{params, OptionalExtension};
use tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
oneshot,
};
2022-01-26 17:58:00 -06:00
use serde::Serialize;
2022-01-01 15:35:27 -06:00
#[derive(Debug)]
enum Task {
2022-01-26 17:58:00 -06:00
AddQuote(oneshot::Sender<bool>, Quote),
GetQuote(oneshot::Sender<Option<Quote>>, Option<String>),
2022-01-01 15:35:27 -06:00
// implement search WITH PAGINATION
}
pub struct DbExecutor {
rx: UnboundedReceiver<Task>,
db: rusqlite::Connection,
}
2022-01-26 17:58:00 -06:00
#[derive(Serialize, Debug)]
pub struct Quote {
pub author: String,
pub quote: String
}
2022-01-01 15:35:27 -06:00
impl DbExecutor {
pub fn create(dbpath: &str) -> rusqlite::Result<(Self, ExecutorConnection)> {
let (tx, rx) = unbounded_channel();
let db = rusqlite::Connection::open(dbpath)?;
2022-01-02 14:58:54 -06:00
db.execute(
"create table if not exists quotes(id integer primary key,\
username text not null, quote text not null)",
[],
)?;
2022-01-01 15:35:27 -06:00
tracing::debug!("Database connected ({})", dbpath);
Ok((Self { rx, db }, ExecutorConnection { tx }))
}
pub fn run(mut self) {
while let Some(task) = self.rx.blocking_recv() {
match task {
2022-01-26 17:58:00 -06:00
Task::AddQuote(tx, quote) => {
2022-01-01 15:35:27 -06:00
if let Err(e) = self.db.execute(
2022-01-02 14:58:54 -06:00
"insert into quotes(quote,username) values(?,?)",
2022-01-26 17:58:00 -06:00
params![quote.quote, quote.author],
2022-01-02 14:58:54 -06:00
) {
2022-01-01 15:35:27 -06:00
tracing::error!("A database error has occurred: {}", e);
tx.send(false).unwrap();
} else {
tx.send(true).unwrap();
}
}
Task::GetQuote(tx, author) => {
let quote = if let Some(ref author) = author {
2022-01-26 17:58:00 -06:00
self.db.query_row("select quote,username from quotes where username=? order by random() limit 1", params![author], |v| Ok(Quote {quote:v.get(0)?, author:v.get(1)?}))
2022-01-01 15:35:27 -06:00
} else {
2022-01-26 17:58:00 -06:00
self.db.query_row("select quote,username from quotes order by random() limit 1", params![], |v| Ok(Quote {quote:v.get(0)?, author:v.get(1)?}))
2022-01-01 15:35:27 -06:00
}.optional().unwrap_or_else(|e| {
tracing::error!("A database error has occurred: {}", e);
None
});
tx.send(quote).unwrap();
}
}
}
}
}
pub struct ExecutorConnection {
tx: UnboundedSender<Task>,
}
impl Clone for ExecutorConnection {
fn clone(&self) -> Self {
2022-01-02 14:58:54 -06:00
Self {
tx: self.tx.clone(),
}
2022-01-01 15:35:27 -06:00
}
}
impl ExecutorConnection {
2022-01-26 17:58:00 -06:00
pub async fn add_quote(&self, quote: Quote) -> bool {
2022-01-01 15:35:27 -06:00
let (otx, orx) = oneshot::channel();
2022-01-26 17:58:00 -06:00
self.tx.send(Task::AddQuote(otx, quote)).unwrap();
2022-01-01 15:35:27 -06:00
orx.await.unwrap()
}
2022-01-26 17:58:00 -06:00
pub async fn get_quote(&self, author: Option<String>) -> Option<Quote> {
2022-01-01 15:35:27 -06:00
let (otx, orx) = oneshot::channel();
self.tx.send(Task::GetQuote(otx, author)).unwrap();
orx.await.unwrap()
}
}