diff options
| author | Nathan Perry <np@nathanperry.dev> | 2024-05-10 20:17:31 -0400 |
|---|---|---|
| committer | Nathan Perry <np@nathanperry.dev> | 2024-05-10 20:17:31 -0400 |
| commit | 833f2bed24ab49f1c6242762b6d1e0be9192e870 (patch) | |
| tree | 6addb09b277a3559a0049b31d602b80cd977bdbc | |
| parent | c56dea4fbd53fde13efaf742ab9ee9d56575128a (diff) | |
wip
| -rw-r--r-- | Cargo.lock | 266 | ||||
| -rw-r--r-- | Cargo.toml | 22 | ||||
| -rw-r--r-- | build.rs | 2 | ||||
| -rw-r--r-- | src/commands/meme/create.rs | 8 | ||||
| -rw-r--r-- | src/commands/meme/history.rs | 14 | ||||
| -rw-r--r-- | src/commands/meme/mod.rs | 4 | ||||
| -rw-r--r-- | src/db/mod.rs | 129 | ||||
| -rw-r--r-- | src/db/models.rs | 56 |
8 files changed, 238 insertions, 263 deletions
@@ -197,12 +197,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - -[[package]] name = "chrono" version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -334,16 +328,6 @@ dependencies = [ ] [[package]] -name = "ctrlc" -version = "3.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" -dependencies = [ - "nix", - "windows-sys 0.52.0", -] - -[[package]] name = "dashmap" version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -364,6 +348,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] +name = "deadpool" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" +dependencies = [ + "async-trait", + "deadpool-runtime", + "num_cpus", + "retain_mut", + "tokio", +] + +[[package]] +name = "deadpool" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6541a3916932fe57768d4be0b1ffb5ec7cbf74ca8c903fdfd5c0fe8aa958f0ed" +dependencies = [ + "deadpool-runtime", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-postgres" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19be9da496d60d03ec3ab45d960d80a3afb285b787394b83614a79942f467e7f" +dependencies = [ + "deadpool 0.12.1", + "getrandom", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + +[[package]] name = "deranged" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -395,31 +425,56 @@ dependencies = [ "chrono", "diesel_derives", "itoa", - "pq-sys", - "r2d2", ] [[package]] -name = "diesel_derives" -version = "2.1.4" +name = "diesel-async" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14701062d6bed917b5c7103bdffaee1e4609279e240488ad24e7bd979ca6866c" +checksum = "acada1517534c92d3f382217b485db8a8638f111b0e3f2a2a8e26165050f77be" +dependencies = [ + "async-trait", + "deadpool 0.9.5", + "diesel", + "futures-util", + "scoped-futures", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "diesel_async_migrations" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a700d6b83a17973b94d3065970fd2b36f1036c3fe08adcbdce1c9beb8fb25553" +dependencies = [ + "diesel", + "diesel-async", + "diesel_async_migrations_macros", + "scoped-futures", + "tracing", +] + +[[package]] +name = "diesel_async_migrations_macros" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05de210f31e6ac18162501b03c37f839af9f9fd6dd6de2bb4031ae6691c47679" dependencies = [ - "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.61", ] [[package]] -name = "diesel_migrations" -version = "2.1.0" +name = "diesel_derives" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac" +checksum = "14701062d6bed917b5c7103bdffaee1e4609279e240488ad24e7bd979ca6866c" dependencies = [ - "diesel", - "migrations_internals", - "migrations_macros", + "diesel_table_macro_syntax", + "proc-macro2", + "quote", + "syn 2.0.61", ] [[package]] @@ -1071,27 +1126,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] -name = "migrations_internals" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada" -dependencies = [ - "serde", - "toml", -] - -[[package]] -name = "migrations_macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", -] - -[[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1184,18 +1218,6 @@ dependencies = [ ] [[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] name = "no-std-net" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1529,20 +1551,6 @@ dependencies = [ ] [[package]] -name = "postgres" -version = "0.19.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7915b33ed60abc46040cbcaa25ffa1c7ec240668e0477c4f3070786f5916d451" -dependencies = [ - "bytes", - "fallible-iterator", - "futures-util", - "log", - "tokio", - "tokio-postgres", -] - -[[package]] name = "postgres-protocol" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1567,7 +1575,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" dependencies = [ "bytes", - "chrono", "fallible-iterator", "postgres-protocol", ] @@ -1585,15 +1592,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] -name = "pq-sys" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0052426df997c0cbd30789eb44ca097e3541717a7b8fa36b1c464ee7edebd" -dependencies = [ - "vcpkg", -] - -[[package]] name = "primal-check" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1621,27 +1619,6 @@ dependencies = [ ] [[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] - -[[package]] -name = "r2d2_postgres" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7029c56be658cb54f321e0bee597810ee16796b735fa2559d7056bf06b12230b" -dependencies = [ - "postgres", - "r2d2", -] - -[[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1806,6 +1783,12 @@ dependencies = [ ] [[package]] +name = "retain_mut" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" + +[[package]] name = "ring" version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2029,12 +2012,13 @@ dependencies = [ ] [[package]] -name = "scheduled-thread-pool" -version = "0.2.7" +name = "scoped-futures" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" dependencies = [ - "parking_lot", + "cfg-if", + "pin-utils", ] [[package]] @@ -2156,15 +2140,6 @@ dependencies = [ ] [[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - -[[package]] name = "serde_urlencoded" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2717,9 +2692,10 @@ version = "0.2.0" dependencies = [ "anyhow", "chrono", - "ctrlc", + "deadpool-postgres", "diesel", - "diesel_migrations", + "diesel-async", + "diesel_async_migrations", "dotenv", "either", "envconfig", @@ -2731,8 +2707,6 @@ dependencies = [ "log", "pest", "pest_derive", - "postgres", - "r2d2_postgres", "rand", "regex", "reqwest", @@ -2748,6 +2722,7 @@ dependencies = [ "time", "timeago", "tokio", + "tokio-postgres", "typemap", "url", ] @@ -2952,40 +2927,6 @@ dependencies = [ ] [[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] name = "tower-service" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3645,15 +3586,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] name = "winreg" version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6,7 +6,7 @@ edition = "2021" [features] default = ["db", "games"] -db = ["diesel", "postgres", "r2d2_postgres", "diesel_migrations"] +db = ["dep:diesel", "dep:diesel-async", "dep:diesel_async_migrations", "dep:tokio-postgres", "dep:deadpool-postgres"] games = [] [dependencies] @@ -20,8 +20,6 @@ dotenv = "0.15" chrono = "0.4" time = "0.3" fern = { version = "0.6", features = ["colored"] } -diesel = { version = "2.1", features = ["postgres", "chrono", "r2d2"], optional = true } -ctrlc = { version = "3.4", features = ["termination"] } rand = "0.8" either = "1.10" reqwest = { version = "0.11", features = ["json"] } @@ -33,17 +31,25 @@ serde_json = "1.0" timeago = "0.4" statrs = "0.16" fnv = "1.0" + pest = "2.7" pest_derive = "2.7" -postgres = { version = "0.19", optional = true, features = ["with-chrono-0_4"] } -r2d2_postgres = { version = "0.18", optional = true } -diesel_migrations = { version = "2.1", optional = true } + envconfig = "0.10" envconfig_derive = "0.10" + tap = "1.0" + +tokio = { version = "1.37", features = ["full"] } + songbird = { version = "0.4", features = ["builtin-queue"] } -tokio = { version = "1.37", features = ["full"]} -symphonia = { version = "0.5", features = ["all"]} +symphonia = { version = "0.5", features = ["all"] } + +diesel = { version = "2.1", features = ["chrono"], optional = true } +diesel-async = { version = "0.4", optional = true, features = ["deadpool", "postgres"] } +diesel_async_migrations = { version = "0.12", optional = true } +tokio-postgres = { version = "0.7", optional = true } +deadpool-postgres = { version = "0.13", optional = true } [dependencies.serenity] version = "0.12" @@ -1,3 +1,3 @@ fn main() { - println!("cargo:rerun-if-changed=path/to/your/migration/dir/relative/to/your/Cargo.toml"); + println!("cargo:rerun-if-changed=migrations"); } diff --git a/src/commands/meme/create.rs b/src/commands/meme/create.rs index 2cd9465..160de7b 100644 --- a/src/commands/meme/create.rs +++ b/src/commands/meme/create.rs @@ -72,7 +72,7 @@ pub async fn addmeme(ctx: &Context, msg: &Message, args: Args) -> CommandResult if let Some(att) = image { let data = att.download().await?; - image_id = Some(Image::create(&mut conn, &att.filename, data, msg.author.id.get())?); + image_id = Some(Image::create(&mut conn, &att.filename, data, msg.author.id.get()).await?); }; let save_result = NewMeme { @@ -83,6 +83,7 @@ pub async fn addmeme(ctx: &Context, msg: &Message, args: Args) -> CommandResult metadata_id: 0, } .save(&mut conn, msg.author.id.get()) + .await .map(|_| {}); use diesel::result::DatabaseErrorKind; @@ -182,7 +183,7 @@ pub async fn addaudiomeme(ctx: &Context, msg: &Message, args: Args) -> CommandRe if let Ok(att) = image_att { let data = att.download().await?; - image_id = Image::create(&mut conn, &att.filename, data, msg.author.id.get())?.pipe(Some); + image_id = Image::create(&mut conn, &att.filename, data, msg.author.id.get())?.await.pipe(Some); } let mut audio_data = Vec::new(); @@ -196,7 +197,7 @@ pub async fn addaudiomeme(ctx: &Context, msg: &Message, args: Args) -> CommandRe .await; } - let audio_id = Audio::create(&mut conn, audio_data, msg.author.id.get())?; + let audio_id = Audio::create(&mut conn, audio_data, msg.author.id.get()).await?; let save_result = NewMeme { title, @@ -206,6 +207,7 @@ pub async fn addaudiomeme(ctx: &Context, msg: &Message, args: Args) -> CommandRe metadata_id: 0, } .save(&mut conn, msg.author.id.get()) + .await .map(|_| {}); use diesel::result::DatabaseErrorKind; diff --git a/src/commands/meme/history.rs b/src/commands/meme/history.rs index e2953d1..e5b3d33 100644 --- a/src/commands/meme/history.rs +++ b/src/commands/meme/history.rs @@ -60,7 +60,7 @@ static CLEAN_DATE_FORMAT: &str = "%b %-e %Y"; pub async fn wat(ctx: &Context, msg: &Message, _: Args) -> CommandResult { let mut conn = connection()?; - let record = match InvocationRecord::last(&mut conn) { + let record = match InvocationRecord::last(&mut conn).await { Ok(x) => x, Err(e) => { if let Some(NotFound) = e.downcast_ref::<DieselError>() { @@ -75,11 +75,11 @@ pub async fn wat(ctx: &Context, msg: &Message, _: Args) -> CommandResult { }, }; - let meme = Meme::find(&mut conn, record.meme_id); + let meme = Meme::find(&mut conn, record.meme_id).await; match meme { Ok(ref meme) => { - let metadata = Metadata::find(&mut conn, meme.metadata_id)?; + let metadata = Metadata::find(&mut conn, meme.metadata_id).await?; let author = CONFIG.discord.guild().member(&ctx, metadata.created_by as u64).await?; util::send( @@ -125,7 +125,7 @@ pub async fn history(ctx: &Context, msg: &Message, mut args: Args) -> CommandRes let records = { let mut conn = connection()?; - InvocationRecord::last_n(&mut conn, n)? + InvocationRecord::last_n(&mut conn, n).await? }; if records.is_empty() { @@ -150,7 +150,9 @@ pub async fn history(ctx: &Context, msg: &Message, mut args: Args) -> CommandRes "" }; - let meme = Meme::find(&mut conn, rec.meme_id).and_then(|meme| { + let meme = Meme::find(&mut conn, rec.meme_id).await; + + .and_then(|meme| { Metadata::find(&mut conn, meme.metadata_id).map(|metadata| (metadata, meme)) }); @@ -214,7 +216,7 @@ pub async fn stats(ctx: &Context, msg: &Message, _: Args) -> CommandResult { }; let mut conn = connection()?; - let stats = db::stats(&mut conn)?; + let stats = db::stats(&mut conn).await?; debug!("reporting stats"); diff --git a/src/commands/meme/mod.rs b/src/commands/meme/mod.rs index c40e80a..b5a3c98 100644 --- a/src/commands/meme/mod.rs +++ b/src/commands/meme/mod.rs @@ -1,4 +1,4 @@ -use diesel::PgConnection; +use diesel_async::AsyncPgConnection; use log::debug; use rand::random; use serenity::{ @@ -70,7 +70,7 @@ struct Memes; async fn send_meme( ctx: &Context, t: &Meme, - conn: &mut PgConnection, + conn: &mut AsyncPgConnection, msg: &Message, ) -> CommandResult { let should_tts = diff --git a/src/db/mod.rs b/src/db/mod.rs index e7ff17f..04f2239 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -11,24 +11,13 @@ use chrono::{ }; use diesel::{ prelude::*, - r2d2::{ - ConnectionManager, - ManageConnection, - }, NotFound, }; - -use postgres::Client as RawPgConn; -use r2d2_postgres::{ - postgres::{ - Config, - NoTls, - }, - PostgresConnectionManager as RawPgConnMgr, -}; - +use diesel_async::pooled_connection::AsyncDieselConnectionManager; +use tokio_postgres::Client as RawPgConn; use anyhow::anyhow; -use diesel_migrations::MigrationHarness; +use diesel_async::pooled_connection::deadpool::Pool; +use deadpool_postgres::{Pool as RawPgConnMgr, PoolConfig}; use lazy_static::lazy_static; use crate::{ @@ -42,47 +31,62 @@ use self::schema::*; mod models; mod schema; -const MIGRATIONS: diesel_migrations::EmbeddedMigrations = diesel_migrations::embed_migrations!(); -static MIGRATE: std::sync::Once = std::sync::Once::new(); +const MIGRATIONS: diesel_async_migrations::EmbeddedMigrations = diesel_async_migrations::embed_migrations!(); +static MIGRATE: tokio::sync::OnceCell<()> = tokio::sync::OnceCell::new(); lazy_static! { static ref DB_URL: String = env::var("DATABASE_URL").expect("no database url in environment"); static ref DB_CONFIG: Config = Config::from_str(&DB_URL).expect("parsing db url as config"); - static ref CONN_MGR: ConnectionManager<PgConnection> = ConnectionManager::new(DB_URL.clone()); - static ref RAW_CONN_MGR: RawPgConnMgr<NoTls> = RawPgConnMgr::new(DB_CONFIG.clone(), NoTls); + + static ref POOL: diesel_async::pooled_connection::deadpool::Pool<AsyncDieselConnectionManager<AsyncPgConnection>> = { + let cfg = AsyncDieselConnectionManager::new(DB_URL.clone()); + let pool = Pool::builder(cfg).build().unwrap(); + + pool + }; + + static ref RAW_CONN_MGR: RawPgConnMgr = { + deadpool_postgres::Config::builder(tokio_postgres::NoTls).expect("failed to init config") + .config(PoolConfig::new(8)) + .build().expect("failed to build pool") + }; } #[inline] -pub fn connection() -> Result<PgConnection> { - CONN_MGR - .connect() - .map(|mut conn| { - MIGRATE.call_once(|| { - log::info!("running migrations"); - conn.run_pending_migrations(MIGRATIONS).expect("failed running migrations"); - log::info!("migrations complete"); - }); +pub async fn connection() -> Result<AsyncPgConnection> { + let pool: &Pool<AsyncDieselConnectionManager<_>> = POOL; + + pool.get() + .then(|mut conn| async move { + if let Ok(conn) = conn { + MIGRATE.get_or_init(|| async move { + log::info!("running migrations"); + MIGRATIONS.run_pending_migrations(&mut conn).await.expect("failed running migrations"); + log::info!("migrations complete"); + }).await; + } conn }) + .await .map_err(Error::from) } #[inline] -fn raw_connection() -> Result<RawPgConn> { +async fn raw_connection() -> Result<tokio_postgres::Client> { // HACK - if !MIGRATE.is_completed() { - connection()?; + if !MIGRATE.initialized() { + connection().await?; } RAW_CONN_MGR.connect().map_err(Error::from) } -pub fn find_meme<T: AsRef<str>>(conn: &mut PgConnection, search: T) -> Result<Meme> { +pub async fn find_meme<T: AsRef<str>>(conn: &mut AsyncPgConnection, search: T) -> Result<Meme> { let search = search.as_ref(); - let mut meme = memes::table.filter(memes::title.eq(search)).limit(1).first::<Meme>(conn); + let mut meme = memes::table.filter(memes::title.eq(search)).limit(1).first::<Meme>(conn).await; if let Err(NotFound) = meme { let format_search = format!("%{}%", search); @@ -90,18 +94,18 @@ pub fn find_meme<T: AsRef<str>>(conn: &mut PgConnection, search: T) -> Result<Me meme = memes::table .filter(memes::title.ilike(&format_search).or(memes::content.ilike(&format_search))) .limit(1) - .first::<Meme>(conn); + .first::<Meme>(conn).await; } meme.map_err(Error::from) } -pub fn query_meme<T: AsRef<str>>( +pub async fn query_meme<T: AsRef<str>>( search: T, user_id: Option<u64>, age_desc: bool, ) -> Result<Vec<(Meme, Metadata)>> { - let mut raw_conn = raw_connection()?; + let mut raw_conn = raw_connection().await?; let search = format!("%{}%", search.as_ref()); @@ -123,7 +127,7 @@ pub fn query_meme<T: AsRef<str>>( }, ), &[&search, &(user_id.unwrap_or(0) as i64), &user_id.is_none()], - )?; + ).await?; let result = rows .iter() @@ -150,21 +154,21 @@ pub fn query_meme<T: AsRef<str>>( Ok(result) } -pub fn delete_meme<T: AsRef<str>>( - conn: &mut PgConnection, +pub async fn delete_meme<T: AsRef<str>>( + conn: &mut AsyncPgConnection, search: T, deleted_by: u64, ) -> Result<()> { conn.transaction::<(), Error, _>(|tx| { - let deleted = memes::table.filter(memes::title.eq(search.as_ref())).first::<Meme>(tx)?; + let deleted = memes::table.filter(memes::title.eq(search.as_ref())).first::<Meme>(tx).await?; - diesel::delete(memes::table).filter(memes::id.eq(deleted.id)).execute(tx)?; + diesel::delete(memes::table).filter(memes::id.eq(deleted.id)).execute(tx).await?; if let Some(image_id) = deleted.image_id { - let count = memes::table.filter(memes::image_id.eq(image_id)).count().execute(tx)?; + let count = memes::table.filter(memes::image_id.eq(image_id)).count().execute(tx).await?; if count == 0 { - diesel::delete(images::table).filter(images::id.eq(image_id)).execute(tx)?; + diesel::delete(images::table).filter(images::id.eq(image_id)).execute(tx).await?; } } @@ -172,10 +176,10 @@ pub fn delete_meme<T: AsRef<str>>( let count = memes::table .select(::diesel::dsl::count_star()) .filter(memes::audio_id.eq(audio_id)) - .execute(tx)?; + .execute(tx).await?; if count == 0 { - diesel::delete(audio::table).filter(audio::id.eq(audio_id)).execute(tx)?; + diesel::delete(audio::table).filter(audio::id.eq(audio_id)).execute(tx).await?; } } @@ -185,16 +189,16 @@ pub fn delete_meme<T: AsRef<str>>( meme_id: deleted.id, }; - let _ = diesel::insert_into(tombstones::table).values(&tombstone).execute(tx)?; + let _ = diesel::insert_into(tombstones::table).values(&tombstone).execute(tx).await?; Ok(()) }) } -pub fn rare_meme(conn: &mut PgConnection, audio: bool) -> Result<Meme> { +pub async fn rare_meme(conn: &mut AsyncPgConnection, audio: bool) -> Result<Meme> { use rand::prelude::*; - let mut raw_conn = raw_connection()?; + let mut raw_conn = raw_connection().await?; let rows = raw_conn.query( r#" @@ -229,7 +233,7 @@ pub fn rare_meme(conn: &mut PgConnection, audio: bool) -> Result<Meme> { LIMIT 100; "#, &[&!audio, &audio], - )?; + ).await?; let elems = rows .iter() @@ -249,10 +253,10 @@ pub fn rare_meme(conn: &mut PgConnection, audio: bool) -> Result<Meme> { .ok_or_else(|| anyhow!("couldn't locate meme satisfying target probability"))? .0; - Meme::find(conn, meme_id) + Meme::find(conn, meme_id).await } -pub fn rand_meme(conn: &mut PgConnection, audio: bool) -> Result<Meme> { +pub async fn rand_meme(conn: &mut AsyncPgConnection, audio: bool) -> Result<Meme> { use rand::{ seq::SliceRandom, thread_rng, @@ -268,21 +272,23 @@ pub fn rand_meme(conn: &mut PgConnection, audio: bool) -> Result<Meme> { .or(memes::audio_id.is_not_null()), ) .load(conn) + .await .map_err(Error::from)? } else { memes::table .select(memes::id) .filter(memes::content.is_not_null().or(memes::image_id.is_not_null())) .load(conn) + .await .map_err(Error::from)? }; let id = ids.choose(&mut thread_rng()).ok_or_else(|| anyhow!("couldn't load meme"))?; - memes::table.find(id).first::<Meme>(conn).map_err(Error::from) + memes::table.find(id).first::<Meme>(conn).await.map_err(Error::from) } -pub fn rand_audio_meme(conn: &mut PgConnection) -> Result<Meme> { +pub async fn rand_audio_meme(conn: &mut AsyncPgConnection) -> Result<Meme> { use rand::{ seq::SliceRandom, thread_rng, @@ -292,14 +298,15 @@ pub fn rand_audio_meme(conn: &mut PgConnection) -> Result<Meme> { .select(memes::id) .filter(memes::audio_id.is_not_null()) .load(conn) + .await .map_err(Error::from)?; let id = ids.choose(&mut thread_rng()).ok_or_else(|| anyhow!("couldn't load audio meme"))?; - memes::table.find(id).first::<Meme>(conn).map_err(Error::from) + memes::table.find(id).first::<Meme>(conn).await.map_err(Error::from) } -pub fn rand_silent_meme(conn: &mut PgConnection) -> Result<Meme> { +pub async fn rand_silent_meme(conn: &mut AsyncPgConnection) -> Result<Meme> { use rand::{ seq::SliceRandom, thread_rng, @@ -309,11 +316,12 @@ pub fn rand_silent_meme(conn: &mut PgConnection) -> Result<Meme> { .select(memes::id) .filter(memes::audio_id.is_null()) .load(conn) + .await .map_err(Error::from)?; let id = ids.choose(&mut thread_rng()).ok_or_else(|| anyhow!("couldn't load audio meme"))?; - memes::table.find(id).first::<Meme>(conn).map_err(Error::from) + memes::table.find(id).first::<Meme>(conn).await.map_err(Error::from) } #[derive(Debug, Clone)] @@ -347,7 +355,7 @@ pub struct Stats { pub most_popular_meme_overall_count: usize, } -pub fn stats(conn: &mut PgConnection) -> Result<Stats> { +pub async fn stats(conn: &mut AsyncPgConnection) -> Result<Stats> { use chrono::{ NaiveDate, NaiveDateTime, @@ -373,36 +381,41 @@ pub fn stats(conn: &mut PgConnection) -> Result<Stats> { .select(count(memes::image_id)) .filter(memes::image_id.is_not_null()) .first(conn) + .await .map_err(Error::from)?; let audio_count: i64 = memes::table .select(count(memes::audio_id)) .filter(memes::audio_id.is_not_null()) .first(conn) + .await .map_err(Error::from)?; let started_recording: NaiveDateTime = invocation_records::table .select(invocation_records::time) .order(invocation_records::time) .first(conn) + .await .map_err(Error::from)?; let started_recording = to_utc(started_recording); let total_meme_invocations: i64 = - invocation_records::table.select(count_star()).first(conn).map_err(Error::from)?; + invocation_records::table.select(count_star()).first(conn).await.map_err(Error::from)?; let audio_meme_invocations: i64 = invocation_records::table .inner_join(memes::table) .select(count_star()) .filter(memes::audio_id.is_not_null()) .first(conn) + .await .map_err(Error::from)?; let random_meme_invocations: i64 = invocation_records::table .select(count_star()) .filter(invocation_records::random.eq(true)) .first(conn) + .await .map_err(Error::from)?; let mut raw_conn = raw_connection()?; diff --git a/src/db/models.rs b/src/db/models.rs index bba25a2..f7bbf8e 100644 --- a/src/db/models.rs +++ b/src/db/models.rs @@ -5,6 +5,7 @@ use diesel::{ Insertable, Queryable, }; +use diesel_async::{AsyncPgConnection, RunQueryDsl}; use sha1::Digest; use crate::{ @@ -25,18 +26,27 @@ pub struct Meme { } impl Meme { - pub fn image(&self, conn: &mut PgConnection) -> Option<Result<Image>> { + pub async fn image(&self, conn: &mut AsyncPgConnection) -> Option<Result<Image>> { self.image_id - .map(|x: i32| images::table.filter(images::id.eq(x)).first(conn).map_err(Error::from)) + .map(|x: i32| images::table.filter(images::id.eq(x)) + .first(conn) + .await + .map_err(Error::from)) } - pub fn audio(&self, conn: &mut PgConnection) -> Option<Result<Audio>> { + pub async fn audio(&self, conn: &mut AsyncPgConnection) -> Option<Result<Audio>> { self.audio_id - .map(|x: i32| audio::table.filter(audio::id.eq(x)).first(conn).map_err(Error::from)) + .map(|x: i32| audio::table.filter(audio::id.eq(x)) + .first(conn) + .await + .map_err(Error::from)) } - pub fn find(conn: &mut PgConnection, id: i32) -> Result<Meme> { - memes::table.find(id).get_result(conn).map_err(Error::from) + pub async fn find(conn: &mut AsyncPgConnection, id: i32) -> Result<Meme> { + memes::table.find(id) + .get_result(conn) + .await + .map_err(Error::from) } } @@ -51,7 +61,7 @@ pub struct NewMeme { } impl NewMeme { - pub fn save(mut self, conn: &mut PgConnection, by_user: u64) -> Result<Meme> { + pub async fn save(mut self, conn: &mut AsyncPgConnection, by_user: u64) -> Result<Meme> { let metadata = Metadata::create(conn, by_user)?; self.metadata_id = metadata.id; @@ -59,6 +69,7 @@ impl NewMeme { diesel::insert_into(memes::table) .values(&self) .get_result::<Meme>(conn) + .await .map_err(Error::from) } } @@ -73,7 +84,7 @@ pub struct Audio { } impl Audio { - pub fn create(conn: &mut PgConnection, data: Vec<u8>, by_user: u64) -> Result<i32> { + pub fn create(conn: &mut AsyncPgConnection, data: Vec<u8>, by_user: u64) -> Result<i32> { let mut data_hash = ::sha1::Sha1::new(); data_hash.update(&data); let data_hash = data_hash.finalize().to_vec(); @@ -81,7 +92,8 @@ impl Audio { let id = audio::table .select(audio::id) .filter(audio::data_hash.eq(&data_hash)) - .get_results::<i32>(conn)?; + .get_results::<i32>(conn) + .await?; if let Some(id) = id.first() { return Ok(*id); @@ -99,6 +111,7 @@ impl Audio { .values(&new_audio) .returning(audio::id) .get_result(conn) + .await .map_err(Error::from) } } @@ -123,7 +136,7 @@ pub struct Image { impl Image { pub fn create( - conn: &mut PgConnection, + conn: &mut AsyncPgConnection, filename: &str, data: Vec<u8>, by_user: u64, @@ -135,7 +148,8 @@ impl Image { let id = images::table .select(images::id) .filter(images::data_hash.eq(&data_hash)) - .get_results::<i32>(conn)?; + .get_results::<i32>(conn) + .await?; if let Some(id) = id.first() { return Ok(*id); @@ -154,6 +168,7 @@ impl Image { .values(&new_image) .returning(images::id) .get_result(conn) + .await .map_err(Error::from) } } @@ -176,17 +191,18 @@ pub struct Metadata { } impl Metadata { - pub fn create(conn: &mut PgConnection, by_user: u64) -> Result<Metadata> { + pub fn create(conn: &mut AsyncPgConnection, by_user: u64) -> Result<Metadata> { diesel::insert_into(metadata::table) .values(&NewMetadata { created_by: by_user as i64, }) .get_result::<Metadata>(conn) + .await .map_err(Error::from) } - pub fn find(conn: &mut PgConnection, id: i32) -> Result<Metadata> { - metadata::table.find(id).get_result::<Metadata>(conn).map_err(Error::from) + pub fn find(conn: &mut AsyncPgConnection, id: i32) -> Result<Metadata> { + metadata::table.find(id).get_result::<Metadata>(conn).await.map_err(Error::from) } } @@ -206,13 +222,14 @@ pub struct AuditRecord { } impl AuditRecord { - pub fn create(conn: &mut PgConnection, metadata: i32, by_user: u64) -> Result<AuditRecord> { + pub fn create(conn: &mut AsyncPgConnection, metadata: i32, by_user: u64) -> Result<AuditRecord> { diesel::insert_into(audit_records::table) .values(&NewAuditRecord { updated_by: by_user as i64, metadata_id: metadata, }) .get_result::<AuditRecord>(conn) + .await .map_err(Error::from) } } @@ -264,7 +281,7 @@ pub struct NewInvocationRecord { impl InvocationRecord { pub fn create( - conn: &mut PgConnection, + conn: &mut AsyncPgConnection, user_id: u64, message_id: u64, meme_id: i32, @@ -278,21 +295,24 @@ impl InvocationRecord { random, }) .get_result::<InvocationRecord>(conn) + .await .map_err(Error::from) } - pub fn last(conn: &mut PgConnection) -> Result<Self> { + pub fn last(conn: &mut AsyncPgConnection) -> Result<Self> { invocation_records::table .order(invocation_records::time.desc()) .first(conn) + .await .map_err(Error::from) } - pub fn last_n(conn: &mut PgConnection, n: usize) -> Result<Vec<Self>> { + pub fn last_n(conn: &mut AsyncPgConnection, n: usize) -> Result<Vec<Self>> { invocation_records::table .order(invocation_records::time.desc()) .limit(n as i64) .load(conn) + .await .map_err(Error::from) } } |
