From a34aedc37528034fa7b0309f410bc44cd6b2c538 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 21 Dec 2022 01:52:27 -0500 Subject: [PATCH] move sqlx impls to reusable macro --- crates/types/enums/src/core/visibility.rs | 2 +- .../enums/src/files/media_upload_type.rs | 40 +---------------- crates/types/enums/src/macros.rs | 44 ++++++++++++++++++- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/crates/types/enums/src/core/visibility.rs b/crates/types/enums/src/core/visibility.rs index 7aa2c7e945..562b9d975b 100644 --- a/crates/types/enums/src/core/visibility.rs +++ b/crates/types/enums/src/core/visibility.rs @@ -37,7 +37,7 @@ pub enum Visibility { } -impl_enum_display_and_debug_for_to_str!(Visibility); +impl_enum_display_and_debug_using_to_str!(Visibility); // For reference, here's what the serde implementation might be if manually written. // This may be useful for designing composite types in the future: diff --git a/crates/types/enums/src/files/media_upload_type.rs b/crates/types/enums/src/files/media_upload_type.rs index d0b6c66237..7fd56e5c9f 100644 --- a/crates/types/enums/src/files/media_upload_type.rs +++ b/crates/types/enums/src/files/media_upload_type.rs @@ -1,12 +1,5 @@ use serde::Deserialize; use serde::Serialize; -use sqlx::Decode; -use sqlx::Encode; -use sqlx::Type; -use sqlx_core::database::HasArguments; -use sqlx_core::encode::IsNull; -use sqlx_core::error::BoxDynError; -use sqlx_core::mysql::{MySql, MySqlTypeInfo, MySqlValueRef}; #[cfg(test)] use strum::EnumCount; @@ -26,37 +19,8 @@ pub enum MediaUploadType { Video, } -// This overt approach is being taken because of the following error: -// `MySqlDatabaseError { code: Some("HY000"), number: 1210, message: "Incorrect arguments to mysqld_stmt_execute" }` -// Basically, sqlx can't turn our enum into a VARCHAR when using #[derive(sqlx::Type)]. -// We further lose the ability to `#[sqlx(rename_all="lowercase")]`, etc., so our encoder/decoder -// need to set the rules. -// Solution adapted from https://github.com/launchbadge/sqlx/discussions/1502 -impl Type for MediaUploadType { - fn type_info() -> MySqlTypeInfo { - String::type_info() - } -} - -impl<'q> Encode<'q, MySql> for MediaUploadType { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { - // NB: In the absence of `#[derive(sqlx::Type)]` and `#sqlx(rename_all="lowercase")]`, - // this controls the casing of the variants when sent to MySQL. - self.to_str().encode_by_ref(buf) - } -} - -impl<'r> Decode<'r, MySql> for MediaUploadType { - fn decode( - value: MySqlValueRef<'r>, - ) -> Result { - let string = String::decode(value)?; - let value = MediaUploadType::from_str(&string)?; - Ok(value) - } -} - -impl_enum_display_and_debug_for_to_str!(MediaUploadType); +impl_enum_display_and_debug_using_to_str!(MediaUploadType); +impl_enum_sqlx_coders!(MediaUploadType); /// NB: Legacy API for older code. impl MediaUploadType { diff --git a/crates/types/enums/src/macros.rs b/crates/types/enums/src/macros.rs index 79f7694e1d..ede7c6970a 100644 --- a/crates/types/enums/src/macros.rs +++ b/crates/types/enums/src/macros.rs @@ -1,7 +1,7 @@ /// Implement `Display` and `Debug` for enums that have a `.to_str()` method. /// This ensures that the casing follows whatever `.to_str()` specifies. -macro_rules! impl_enum_display_and_debug_for_to_str { +macro_rules! impl_enum_display_and_debug_using_to_str { ($t:ident) => { // Debug trait. @@ -42,3 +42,45 @@ macro_rules! impl_enum_display_and_debug_for_to_str { } } +/// This overt approach is being taken because of the following error: +/// +/// `MySqlDatabaseError { code: Some("HY000"), number: 1210, message: "Incorrect arguments to mysqld_stmt_execute" }` +/// +/// Basically, sqlx can't turn our enum into a VARCHAR when using #[derive(sqlx::Type)]. +/// Unfortunately, by not using this, we also lose the ability to `#[sqlx(rename_all="lowercase")]`, etc., +/// so our encoder/decoder need to set the rules. +/// +/// Solution adapted from https://github.com/launchbadge/sqlx/discussions/1502 +macro_rules! impl_enum_sqlx_coders { + ($t:ident) => { + + impl sqlx::Type for $t { + fn type_info() -> sqlx_core::mysql::MySqlTypeInfo { + String::type_info() + } + } + + impl<'q> sqlx::Encode<'q, sqlx_core::mysql::MySql> for $t { + fn encode_by_ref( + &self, + buf: &mut >::ArgumentBuffer + ) -> sqlx_core::encode::IsNull { + // NB: In the absence of `#[derive(sqlx::Type)]` and `#sqlx(rename_all="lowercase")]`, + // this controls the casing of the variants when sent to MySQL. + self.to_str().encode_by_ref(buf) + } + } + + impl<'r> sqlx::Decode<'r, sqlx_core::mysql::MySql> for $t { + fn decode( + value: sqlx_core::mysql::MySqlValueRef<'r>, + ) -> Result { + let string = String::decode(value)?; + let value = $t::from_str(&string)?; + Ok(value) + } + } + + } +} +