diff --git a/src/databases/database.rs b/src/databases/database.rs index 778c3dfe..43e6c533 100644 --- a/src/databases/database.rs +++ b/src/databases/database.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; -use crate::databases::mysql::MysqlDatabase; +use crate::databases::mysql::Mysql; use crate::databases::sqlite::SqliteDatabase; use crate::models::info_hash::InfoHash; use crate::models::response::TorrentsResponse; @@ -75,7 +75,7 @@ pub async fn connect(db_path: &str) -> Result, Error> { Ok(Box::new(db)) } ['m', 'y', 's', 'q', 'l', ..] => { - let db = MysqlDatabase::new(db_path).await; + let db = Mysql::new(db_path).await; Ok(Box::new(db)) } _ => Err(Error::UnrecognizedDatabaseDriver), diff --git a/src/databases/mysql.rs b/src/databases/mysql.rs index d4bf4789..6babecb2 100644 --- a/src/databases/mysql.rs +++ b/src/databases/mysql.rs @@ -14,11 +14,11 @@ use crate::models::user::{User, UserAuthentication, UserCompact, UserProfile}; use crate::utils::clock::current_time; use crate::utils::hex::bytes_to_hex; -pub struct MysqlDatabase { +pub struct Mysql { pub pool: MySqlPool, } -impl MysqlDatabase { +impl Mysql { pub async fn new(database_url: &str) -> Self { let db = MySqlPoolOptions::new() .connect(database_url) @@ -35,7 +35,7 @@ impl MysqlDatabase { } #[async_trait] -impl Database for MysqlDatabase { +impl Database for Mysql { fn get_database_driver(&self) -> Driver { Driver::Mysql } @@ -92,7 +92,7 @@ impl Database for MysqlDatabase { match insert_user_profile_result { Ok(_) => { let _ = tx.commit().await; - Ok(user_id as i64) + Ok(i64::overflowing_add_unsigned(0, user_id).0) } Err(e) => { let _ = tx.rollback().await; @@ -133,11 +133,16 @@ impl Database for MysqlDatabase { .map_err(|_| database::Error::UserNotFound) } + /// Gets User Tracker Key + /// + /// # Panics + /// + /// Will panic if the input time overflows the `u64` seconds overflows the `i64` type. + /// (this will naturally happen in 292.5 billion years) async fn get_user_tracker_key(&self, user_id: i64) -> Option { const HOUR_IN_SECONDS: i64 = 3600; - // casting current_time() to i64 will overflow in the year 2262 - let current_time_plus_hour = (current_time() as i64) + HOUR_IN_SECONDS; + let current_time_plus_hour = i64::try_from(current_time()).unwrap().saturating_add(HOUR_IN_SECONDS); // get tracker key that is valid for at least one hour from now query_as::<_, TrackerKey>("SELECT tracker_key AS 'key', date_expiry AS valid_until FROM torrust_tracker_keys WHERE user_id = ? AND date_expiry > ? ORDER BY date_expiry DESC") @@ -233,7 +238,7 @@ impl Database for MysqlDatabase { .bind(category_name) .execute(&self.pool) .await - .map(|v| v.last_insert_id() as i64) + .map(|v| i64::try_from(v.last_insert_id()).expect("last ID is larger than i64")) .map_err(|e| match e { sqlx::Error::Database(err) => { if err.message().contains("UNIQUE") { @@ -325,13 +330,13 @@ impl Database for MysqlDatabase { i += 1; } } - if !category_filters.is_empty() { + if category_filters.is_empty() { + String::new() + } else { format!( "INNER JOIN torrust_categories tc ON tt.category_id = tc.category_id AND ({}) ", category_filters ) - } else { - String::new() } } else { String::new() @@ -365,18 +370,19 @@ impl Database for MysqlDatabase { let res: Vec = sqlx::query_as::<_, TorrentListing>(&query_string) .bind(title) - .bind(offset as i64) + .bind(i64::saturating_add_unsigned(0, offset)) .bind(limit) .fetch_all(&self.pool) .await .map_err(|_| database::Error::Error)?; Ok(TorrentsResponse { - total: count as u32, + total: u32::try_from(count).expect("variable `count` is larger than u32"), results: res, }) } + #[allow(clippy::too_many_lines)] async fn insert_torrent_and_get_id( &self, torrent: &Torrent, @@ -416,7 +422,7 @@ impl Database for MysqlDatabase { .bind(root_hash) .execute(&self.pool) .await - .map(|v| v.last_insert_id() as i64) + .map(|v| i64::try_from(v.last_insert_id()).expect("last ID is larger than i64")) .map_err(|e| match e { sqlx::Error::Database(err) => { if err.message().contains("info_hash") {