From 5547403200cf0c3be336c2597071f3094da25397 Mon Sep 17 00:00:00 2001 From: silverpill Date: Fri, 19 Nov 2021 17:32:51 +0000 Subject: [PATCH] Use macros to create FromSql/ToSql implementations for int enums --- src/config.rs | 4 ++-- src/database/int_enum.rs | 36 +++++++++++++++++++++++++++++ src/database/mod.rs | 1 + src/models/markers/types.rs | 32 ++++--------------------- src/models/notifications/queries.rs | 2 +- src/models/notifications/types.rs | 13 +++++++---- src/models/posts/types.rs | 32 ++++--------------------- src/models/relationships/queries.rs | 26 +++++++-------------- src/models/relationships/types.rs | 19 +++++++-------- 9 files changed, 73 insertions(+), 92 deletions(-) create mode 100644 src/database/int_enum.rs diff --git a/src/config.rs b/src/config.rs index 6679664..b3126c7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,7 @@ use crate::activitypub::views::get_instance_actor_url; use crate::errors::ConversionError; use crate::utils::crypto::deserialize_private_key; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub enum Environment { Development, Production, @@ -126,7 +126,7 @@ impl Config { Instance { _url: self.try_instance_url().unwrap(), actor_key: self.try_instance_rsa_key().unwrap(), - is_private: self.environment == Environment::Development, + is_private: matches!(self.environment, Environment::Development), } } diff --git a/src/database/int_enum.rs b/src/database/int_enum.rs new file mode 100644 index 0000000..c2e063e --- /dev/null +++ b/src/database/int_enum.rs @@ -0,0 +1,36 @@ +macro_rules! int_enum_from_sql { + ($t:ty) => { + impl<'a> postgres_types::FromSql<'a> for $t { + fn from_sql( + _: &postgres_types::Type, + raw: &'a [u8], + ) -> Result<$t, Box> { + let int_value = postgres_protocol::types::int2_from_sql(raw)?; + let value = <$t>::try_from(int_value)?; + Ok(value) + } + + postgres_types::accepts!(INT2); + } + } +} + +macro_rules! int_enum_to_sql { + ($t:ty) => { + impl postgres_types::ToSql for $t { + fn to_sql( + &self, _: &postgres_types::Type, + out: &mut postgres_types::private::BytesMut, + ) -> Result> { + let int_value: i16 = self.into(); + postgres_protocol::types::int2_to_sql(int_value, out); + Ok(postgres_types::IsNull::No) + } + + postgres_types::accepts!(INT2); + postgres_types::to_sql_checked!(); + } + } +} + +pub(crate) use {int_enum_from_sql, int_enum_to_sql}; diff --git a/src/database/mod.rs b/src/database/mod.rs index 1b93a15..bf3620e 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,3 +1,4 @@ +pub mod int_enum; pub mod migrate; pub type Pool = deadpool_postgres::Pool; diff --git a/src/models/markers/types.rs b/src/models/markers/types.rs index 84cfc52..53f5c9b 100644 --- a/src/models/markers/types.rs +++ b/src/models/markers/types.rs @@ -1,14 +1,10 @@ use std::convert::TryFrom; use chrono::{DateTime, Utc}; -use postgres_protocol::types::{int2_from_sql, int2_to_sql}; -use postgres_types::{ - FromSql, ToSql, IsNull, Type, - accepts, to_sql_checked, - private::BytesMut, -}; +use postgres_types::FromSql; use uuid::Uuid; +use crate::database::int_enum::{int_enum_from_sql, int_enum_to_sql}; use crate::errors::ConversionError; #[derive(Debug)] @@ -39,28 +35,8 @@ impl TryFrom for Timeline { } } -type SqlError = Box; - -impl<'a> FromSql<'a> for Timeline { - fn from_sql(_: &Type, raw: &'a [u8]) -> Result { - let int_value = int2_from_sql(raw)?; - let timeline = Timeline::try_from(int_value)?; - Ok(timeline) - } - - accepts!(INT2); -} - -impl ToSql for Timeline { - fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result { - let int_value: i16 = self.into(); - int2_to_sql(int_value, out); - Ok(IsNull::No) - } - - accepts!(INT2); - to_sql_checked!(); -} +int_enum_from_sql!(Timeline); +int_enum_to_sql!(Timeline); #[allow(dead_code)] #[derive(FromSql)] diff --git a/src/models/notifications/queries.rs b/src/models/notifications/queries.rs index 26af265..9a47652 100644 --- a/src/models/notifications/queries.rs +++ b/src/models/notifications/queries.rs @@ -25,7 +25,7 @@ async fn create_notification( ) VALUES ($1, $2, $3, $4) ", - &[&sender_id, &recipient_id, &post_id, &i16::from(event_type)], + &[&sender_id, &recipient_id, &post_id, &event_type], ).await?; Ok(()) } diff --git a/src/models/notifications/types.rs b/src/models/notifications/types.rs index 33d6e34..4a83614 100644 --- a/src/models/notifications/types.rs +++ b/src/models/notifications/types.rs @@ -5,6 +5,7 @@ use postgres_types::FromSql; use tokio_postgres::Row; use uuid::Uuid; +use crate::database::int_enum::{int_enum_from_sql, int_enum_to_sql}; use crate::errors::{ConversionError, DatabaseError}; use crate::models::attachments::types::DbMediaAttachment; use crate::models::posts::types::{DbPost, Post}; @@ -18,10 +19,11 @@ struct DbNotification { sender_id: Uuid, recipient_id: Uuid, post_id: Option, - event_type: i16, + event_type: EventType, created_at: DateTime, } +#[derive(Debug)] pub enum EventType { Follow, FollowRequest, @@ -29,8 +31,8 @@ pub enum EventType { Reaction, } -impl From for i16 { - fn from(value: EventType) -> i16 { +impl From<&EventType> for i16 { + fn from(value: &EventType) -> i16 { match value { EventType::Follow => 1, EventType::FollowRequest => 2, @@ -55,6 +57,9 @@ impl TryFrom for EventType { } } +int_enum_from_sql!(EventType); +int_enum_to_sql!(EventType); + pub struct Notification { pub id: i32, pub sender: DbActorProfile, @@ -84,7 +89,7 @@ impl TryFrom<&Row> for Notification { id: db_notification.id, sender: db_sender, post: maybe_post, - event_type: EventType::try_from(db_notification.event_type)?, + event_type: db_notification.event_type, created_at: db_notification.created_at, }; Ok(notification) diff --git a/src/models/posts/types.rs b/src/models/posts/types.rs index 27891c3..26aaf29 100644 --- a/src/models/posts/types.rs +++ b/src/models/posts/types.rs @@ -1,15 +1,11 @@ use std::convert::TryFrom; use chrono::{DateTime, Utc}; -use postgres_protocol::types::{int2_from_sql, int2_to_sql}; -use postgres_types::{ - FromSql, ToSql, IsNull, Type, - accepts, to_sql_checked, - private::BytesMut, -}; +use postgres_types::FromSql; use tokio_postgres::Row; use uuid::Uuid; +use crate::database::int_enum::{int_enum_from_sql, int_enum_to_sql}; use crate::errors::{ConversionError, ValidationError}; use crate::models::attachments::types::DbMediaAttachment; use crate::models::profiles::types::DbActorProfile; @@ -43,28 +39,8 @@ impl TryFrom for Visibility { } } -type SqlError = Box; - -impl<'a> FromSql<'a> for Visibility { - fn from_sql(_: &Type, raw: &'a [u8]) -> Result { - let int_value = int2_from_sql(raw)?; - let visibility = Visibility::try_from(int_value)?; - Ok(visibility) - } - - accepts!(INT2); -} - -impl ToSql for Visibility { - fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result { - let int_value: i16 = self.into(); - int2_to_sql(int_value, out); - Ok(IsNull::No) - } - - accepts!(INT2); - to_sql_checked!(); -} +int_enum_from_sql!(Visibility); +int_enum_to_sql!(Visibility); #[derive(FromSql)] #[postgres(name = "post")] diff --git a/src/models/relationships/queries.rs b/src/models/relationships/queries.rs index ccbb6e6..865016b 100644 --- a/src/models/relationships/queries.rs +++ b/src/models/relationships/queries.rs @@ -12,7 +12,6 @@ use crate::models::profiles::queries::{ }; use super::types::{ DbFollowRequest, - FollowRequest, FollowRequestStatus, Relationship, }; @@ -142,12 +141,12 @@ pub async fn create_follow_request( db_client: &impl GenericClient, source_id: &Uuid, target_id: &Uuid, -) -> Result { - let request = FollowRequest { +) -> Result { + let request = DbFollowRequest { id: Uuid::new_v4(), source_id: source_id.to_owned(), target_id: target_id.to_owned(), - status: FollowRequestStatus::Pending, + request_status: FollowRequestStatus::Pending, }; db_client.execute( " @@ -160,7 +159,7 @@ pub async fn create_follow_request( &request.id, &request.source_id, &request.target_id, - &i16::from(request.status.clone()), + &request.request_status, ], ).await?; Ok(request) @@ -171,7 +170,6 @@ pub async fn follow_request_accepted( request_id: &Uuid, ) -> Result<(), DatabaseError> { let mut transaction = db_client.transaction().await?; - let status_sql = i16::from(FollowRequestStatus::Accepted); let maybe_row = transaction.query_opt( " UPDATE follow_request @@ -179,7 +177,7 @@ pub async fn follow_request_accepted( WHERE id = $2 RETURNING source_id, target_id ", - &[&status_sql, &request_id], + &[&FollowRequestStatus::Accepted, &request_id], ).await?; let row = maybe_row.ok_or(DatabaseError::NotFound("follow request"))?; let source_id: Uuid = row.try_get("source_id")?; @@ -193,14 +191,13 @@ pub async fn follow_request_rejected( db_client: &impl GenericClient, request_id: &Uuid, ) -> Result<(), DatabaseError> { - let status_sql: i16 = FollowRequestStatus::Rejected.into(); let updated_count = db_client.execute( " UPDATE follow_request SET request_status = $1 WHERE id = $2 ", - &[&status_sql, &request_id], + &[&FollowRequestStatus::Rejected, &request_id], ).await?; if updated_count == 0 { return Err(DatabaseError::NotFound("follow request")); @@ -228,7 +225,7 @@ pub async fn get_follow_request_by_path( db_client: &impl GenericClient, source_id: &Uuid, target_id: &Uuid, -) -> Result { +) -> Result { let maybe_row = db_client.query_opt( " SELECT follow_request @@ -238,13 +235,6 @@ pub async fn get_follow_request_by_path( &[&source_id, &target_id], ).await?; let row = maybe_row.ok_or(DatabaseError::NotFound("follow request"))?; - let db_request: DbFollowRequest = row.try_get("follow_request")?; - let request_status = FollowRequestStatus::try_from(db_request.request_status)?; - let request = FollowRequest { - id: db_request.id, - source_id: db_request.source_id, - target_id: db_request.target_id, - status: request_status, - }; + let request: DbFollowRequest = row.try_get("follow_request")?; Ok(request) } diff --git a/src/models/relationships/types.rs b/src/models/relationships/types.rs index 65b7fd1..64dbfba 100644 --- a/src/models/relationships/types.rs +++ b/src/models/relationships/types.rs @@ -5,6 +5,7 @@ use serde::Serialize; use tokio_postgres::Row; use uuid::Uuid; +use crate::database::int_enum::{int_enum_from_sql, int_enum_to_sql}; use crate::errors::ConversionError; #[derive(Serialize)] @@ -30,15 +31,15 @@ impl TryFrom<&Row> for Relationship { } } -#[derive(Clone, PartialEq)] +#[derive(Debug)] pub enum FollowRequestStatus { Pending, Accepted, Rejected, } -impl From for i16 { - fn from(value: FollowRequestStatus) -> i16 { +impl From<&FollowRequestStatus> for i16 { + fn from(value: &FollowRequestStatus) -> i16 { match value { FollowRequestStatus::Pending => 1, FollowRequestStatus::Accepted => 2, @@ -61,18 +62,14 @@ impl TryFrom for FollowRequestStatus { } } +int_enum_from_sql!(FollowRequestStatus); +int_enum_to_sql!(FollowRequestStatus); + #[derive(FromSql)] #[postgres(name = "follow_request")] pub struct DbFollowRequest { pub id: Uuid, pub source_id: Uuid, pub target_id: Uuid, - pub request_status: i16, -} - -pub struct FollowRequest { - pub id: Uuid, - pub source_id: Uuid, - pub target_id: Uuid, - pub status: FollowRequestStatus, + pub request_status: FollowRequestStatus, }