Change database operations to be async

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/2/head
trivernis 3 years ago
parent 0d43e8294e
commit 2d980111bc
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

13
Cargo.lock generated

@ -379,6 +379,7 @@ dependencies = [
"log 0.4.14", "log 0.4.14",
"r2d2", "r2d2",
"thiserror", "thiserror",
"tokio-diesel",
] ]
[[package]] [[package]]
@ -2161,6 +2162,18 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "tokio-diesel"
version = "0.3.0"
source = "git+https://github.com/Trivernis/tokio-diesel#f4af42558246ab323600622ba8d08803d3c18842"
dependencies = [
"async-trait",
"diesel",
"futures",
"r2d2",
"tokio",
]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.1.0" version = "1.1.0"

127
database/Cargo.lock generated

@ -1,5 +1,16 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "async-trait"
version = "0.1.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36ea56748e10732c49404c153638a15ec3d6211ec5ff35d9bb20e13b93576adf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.0.1"
@ -48,6 +59,7 @@ dependencies = [
"log", "log",
"r2d2", "r2d2",
"thiserror", "thiserror",
"tokio-diesel",
] ]
[[package]] [[package]]
@ -91,6 +103,76 @@ version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "futures"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815"
[[package]]
name = "futures-io"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04"
[[package]]
name = "futures-sink"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23"
[[package]]
name = "futures-task"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc"
[[package]]
name = "futures-util"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025"
dependencies = [
"futures-core",
"futures-sink",
"futures-task",
"pin-project-lite",
"pin-utils",
]
[[package]]
name = "hermit-abi"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.9" version = "0.1.9"
@ -164,6 +246,16 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.1" version = "0.11.1"
@ -189,6 +281,18 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "pin-project-lite"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pq-sys" name = "pq-sys"
version = "0.4.6" version = "0.4.6"
@ -299,6 +403,29 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "tokio"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134af885d758d645f0f0505c9a8b3f9bf8a348fd822e112ab5248138348f1722"
dependencies = [
"autocfg",
"num_cpus",
"pin-project-lite",
]
[[package]]
name = "tokio-diesel"
version = "0.3.0"
source = "git+https://github.com/Trivernis/tokio-diesel#f4af42558246ab323600622ba8d08803d3c18842"
dependencies = [
"async-trait",
"diesel",
"futures",
"r2d2",
"tokio",
]
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.1" version = "0.2.1"

@ -13,4 +13,5 @@ thiserror = "1.0.24"
diesel = {version="1.4.6", features=["postgres", "r2d2", "chrono"]} diesel = {version="1.4.6", features=["postgres", "r2d2", "chrono"]}
log = "0.4.14" log = "0.4.14"
diesel_migrations = "1.4.0" diesel_migrations = "1.4.0"
r2d2 = "0.8.9" r2d2 = "0.8.9"
tokio-diesel = {git = "https://github.com/Trivernis/tokio-diesel"}

@ -7,6 +7,7 @@ use diesel::{delete, insert_into};
use std::any; use std::any;
use std::fmt::Debug; use std::fmt::Debug;
use std::str::FromStr; use std::str::FromStr;
use tokio_diesel::*;
#[derive(Clone)] #[derive(Clone)]
pub struct Database { pub struct Database {
@ -22,22 +23,22 @@ impl Database {
} }
/// Returns a guild setting from the database /// Returns a guild setting from the database
pub fn get_guild_setting<T: 'static>( pub async fn get_guild_setting<T: 'static>(
&self, &self,
guild_id: u64, guild_id: u64,
key: &str, key: String,
) -> DatabaseResult<Option<T>> ) -> DatabaseResult<Option<T>>
where where
T: FromStr, T: FromStr,
{ {
use guild_settings::dsl; use guild_settings::dsl;
log::debug!("Retrieving setting '{}' for guild {}", key, guild_id); log::debug!("Retrieving setting '{}' for guild {}", key, guild_id);
let connection = self.pool.get()?;
let entries: Vec<GuildSetting> = dsl::guild_settings let entries: Vec<GuildSetting> = dsl::guild_settings
.filter(dsl::guild_id.eq(guild_id as i64)) .filter(dsl::guild_id.eq(guild_id as i64))
.filter(dsl::key.eq(key)) .filter(dsl::key.eq(key))
.load::<GuildSetting>(&connection)?; .load_async::<GuildSetting>(&self.pool)
.await?;
log::trace!("Result is {:?}", entries); log::trace!("Result is {:?}", entries);
if let Some(first) = entries.first() { if let Some(first) = entries.first() {
@ -57,16 +58,20 @@ impl Database {
} }
/// Upserting a guild setting /// Upserting a guild setting
pub fn set_guild_setting<T>(&self, guild_id: u64, key: &str, value: T) -> DatabaseResult<()> pub async fn set_guild_setting<T>(
&self,
guild_id: u64,
key: String,
value: T,
) -> DatabaseResult<()>
where where
T: ToString + Debug, T: ToString + Debug,
{ {
use guild_settings::dsl; use guild_settings::dsl;
log::debug!("Setting '{}' to '{:?}' for guild {}", key, value, guild_id); log::debug!("Setting '{}' to '{:?}' for guild {}", key, value, guild_id);
let connection = self.pool.get()?;
insert_into(dsl::guild_settings) insert_into(dsl::guild_settings)
.values(&GuildSettingInsert { .values(GuildSettingInsert {
guild_id: guild_id as i64, guild_id: guild_id as i64,
key: key.to_string(), key: key.to_string(),
value: value.to_string(), value: value.to_string(),
@ -74,69 +79,76 @@ impl Database {
.on_conflict((dsl::guild_id, dsl::key)) .on_conflict((dsl::guild_id, dsl::key))
.do_update() .do_update()
.set(dsl::value.eq(value.to_string())) .set(dsl::value.eq(value.to_string()))
.execute(&connection)?; .execute_async(&self.pool)
.await?;
Ok(()) Ok(())
} }
/// Deletes a guild setting /// Deletes a guild setting
pub fn delete_guild_setting(&self, guild_id: u64, key: &str) -> DatabaseResult<()> { pub async fn delete_guild_setting(&self, guild_id: u64, key: String) -> DatabaseResult<()> {
use guild_settings::dsl; use guild_settings::dsl;
log::debug!("Deleting '{}' for guild {}", key, guild_id);
let connection = self.pool.get()?;
delete(dsl::guild_settings) delete(dsl::guild_settings)
.filter(dsl::guild_id.eq(guild_id as i64)) .filter(dsl::guild_id.eq(guild_id as i64))
.filter(dsl::key.eq(key)) .filter(dsl::key.eq(key))
.execute(&connection)?; .execute_async(&self.pool)
.await?;
Ok(()) Ok(())
} }
/// Returns a list of all guild playlists /// Returns a list of all guild playlists
pub fn get_guild_playlists(&self, guild_id: u64) -> DatabaseResult<Vec<GuildPlaylist>> { pub async fn get_guild_playlists(&self, guild_id: u64) -> DatabaseResult<Vec<GuildPlaylist>> {
use guild_playlists::dsl; use guild_playlists::dsl;
log::debug!("Retrieving guild playlists for guild {}", guild_id); log::debug!("Retrieving guild playlists for guild {}", guild_id);
let connection = self.pool.get()?;
let playlists: Vec<GuildPlaylist> = dsl::guild_playlists let playlists: Vec<GuildPlaylist> = dsl::guild_playlists
.filter(dsl::guild_id.eq(guild_id as i64)) .filter(dsl::guild_id.eq(guild_id as i64))
.load::<GuildPlaylist>(&connection)?; .load_async::<GuildPlaylist>(&self.pool)
.await?;
Ok(playlists) Ok(playlists)
} }
/// Returns a guild playlist by name /// Returns a guild playlist by name
pub fn get_guild_playlist( pub async fn get_guild_playlist(
&self, &self,
guild_id: u64, guild_id: u64,
name: &str, name: String,
) -> DatabaseResult<Option<GuildPlaylist>> { ) -> DatabaseResult<Option<GuildPlaylist>> {
use guild_playlists::dsl; use guild_playlists::dsl;
log::debug!("Retriving guild playlist '{}' for guild {}", name, guild_id); log::debug!("Retriving guild playlist '{}' for guild {}", name, guild_id);
let connection = self.pool.get()?;
let playlists: Vec<GuildPlaylist> = dsl::guild_playlists let playlists: Vec<GuildPlaylist> = dsl::guild_playlists
.filter(dsl::guild_id.eq(guild_id as i64)) .filter(dsl::guild_id.eq(guild_id as i64))
.filter(dsl::name.eq(name)) .filter(dsl::name.eq(name))
.load::<GuildPlaylist>(&connection)?; .load_async::<GuildPlaylist>(&self.pool)
.await?;
Ok(playlists.into_iter().next()) Ok(playlists.into_iter().next())
} }
/// Adds a new playlist to the database overwriting the old one /// Adds a new playlist to the database overwriting the old one
pub fn add_guild_playlist(&self, guild_id: u64, name: &str, url: &str) -> DatabaseResult<()> { pub async fn add_guild_playlist(
&self,
guild_id: u64,
name: String,
url: String,
) -> DatabaseResult<()> {
use guild_playlists::dsl; use guild_playlists::dsl;
log::debug!("Inserting guild playlist '{}' for guild {}", name, guild_id); log::debug!("Inserting guild playlist '{}' for guild {}", name, guild_id);
let connection = self.pool.get()?;
insert_into(dsl::guild_playlists) insert_into(dsl::guild_playlists)
.values(GuildPlaylistInsert { .values(GuildPlaylistInsert {
guild_id: guild_id as i64, guild_id: guild_id as i64,
name: name.to_string(), name: name.clone(),
url: url.to_string(), url: url.clone(),
}) })
.on_conflict((dsl::guild_id, dsl::name)) .on_conflict((dsl::guild_id, dsl::name))
.do_update() .do_update()
.set(dsl::url.eq(url.to_string())) .set(dsl::url.eq(url))
.execute(&connection)?; .execute_async(&self.pool)
.await?;
Ok(()) Ok(())
} }

@ -18,4 +18,7 @@ pub enum DatabaseError {
#[error("Result Error: {0}")] #[error("Result Error: {0}")]
ResultError(#[from] diesel::result::Error), ResultError(#[from] diesel::result::Error),
#[error("AsyncError: {0}")]
AsyncError(#[from] tokio_diesel::AsyncError),
} }

@ -286,7 +286,9 @@ async fn get_songs_for_query(ctx: &Context, msg: &Message, query: &str) -> BotRe
log::debug!("Query is a saved playlist"); log::debug!("Query is a saved playlist");
let pl_name: &str = captures.get(1).unwrap().as_str(); let pl_name: &str = captures.get(1).unwrap().as_str();
log::trace!("Playlist name is {}", pl_name); log::trace!("Playlist name is {}", pl_name);
let playlist_opt = database.get_guild_playlist(guild_id.0, pl_name)?; let playlist_opt = database
.get_guild_playlist(guild_id.0, pl_name.to_string())
.await?;
log::trace!("Playlist is {:?}", playlist_opt); log::trace!("Playlist is {:?}", playlist_opt);
if let Some(playlist) = playlist_opt { if let Some(playlist) = playlist_opt {

@ -14,7 +14,7 @@ async fn playlists(ctx: &Context, msg: &Message) -> CommandResult {
log::debug!("Displaying playlists for guild {}", guild.id); log::debug!("Displaying playlists for guild {}", guild.id);
let database = get_database_from_context(ctx).await; let database = get_database_from_context(ctx).await;
let playlists = database.get_guild_playlists(guild.id.0)?; let playlists = database.get_guild_playlists(guild.id.0).await?;
msg.channel_id msg.channel_id
.send_message(ctx, |m| { .send_message(ctx, |m| {
m.embed(|e| { m.embed(|e| {

@ -29,7 +29,9 @@ async fn save_playlist(ctx: &Context, msg: &Message, mut args: Args) -> CommandR
); );
let database = get_database_from_context(ctx).await; let database = get_database_from_context(ctx).await;
database.add_guild_playlist(guild.id.0, &*name, url)?; database
.add_guild_playlist(guild.id.0, name.clone(), url.to_string())
.await?;
msg.channel_id msg.channel_id
.say(ctx, format!("Playlist **{}** saved", name)) .say(ctx, format!("Playlist **{}** saved", name))

@ -21,7 +21,9 @@ async fn get(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
if let Some(key) = args.single::<String>().ok() { if let Some(key) = args.single::<String>().ok() {
log::debug!("Displaying guild setting of '{}'", key); log::debug!("Displaying guild setting of '{}'", key);
let setting = database.get_guild_setting::<String>(guild.id.0, &key)?; let setting = database
.get_guild_setting::<String>(guild.id.0, key.clone())
.await?;
match setting { match setting {
Some(value) => { Some(value) => {
@ -43,7 +45,10 @@ async fn get(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let key = key.to_string(); let key = key.to_string();
{ {
match database.get_guild_setting::<String>(guild.id.0, &key)? { match database
.get_guild_setting::<String>(guild.id.0, key.clone())
.await?
{
Some(value) => kv_pairs.push(format!("`{}` = `{}`", key, value)), Some(value) => kv_pairs.push(format!("`{}` = `{}`", key, value)),
None => kv_pairs.push(format!("`{}` not set", key)), None => kv_pairs.push(format!("`{}` not set", key)),
} }

@ -30,12 +30,16 @@ async fn set(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let guild = msg.guild(&ctx.cache).await.unwrap(); let guild = msg.guild(&ctx.cache).await.unwrap();
if let Ok(value) = args.single::<String>() { if let Ok(value) = args.single::<String>() {
database.set_guild_setting(guild.id.0, &key, value.clone())?; database
.set_guild_setting(guild.id.0, key.clone(), value.clone())
.await?;
msg.channel_id msg.channel_id
.say(ctx, format!("Set `{}` to `{}`", key, value)) .say(ctx, format!("Set `{}` to `{}`", key, value))
.await?; .await?;
} else { } else {
database.delete_guild_setting(guild.id.0, &key)?; database
.delete_guild_setting(guild.id.0, key.clone())
.await?;
msg.channel_id msg.channel_id
.say(ctx, format!("Setting `{}` reset to default", key)) .say(ctx, format!("Setting `{}` reset to default", key))
.await?; .await?;

@ -36,6 +36,7 @@ pub async fn get_setting<T: 'static + FromStr>(
let data = ctx.data.read().await; let data = ctx.data.read().await;
let database = data.get::<DatabaseContainer>().unwrap(); let database = data.get::<DatabaseContainer>().unwrap();
database database
.get_guild_setting::<T>(guild_id.0, &setting.to_string()) .get_guild_setting::<T>(guild_id.0, setting.to_string())
.await
.map_err(BotError::from) .map_err(BotError::from)
} }

Loading…
Cancel
Save