From 43c890b27c9dbc779de59fcb4df93170b7be7841 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 20 Dec 2022 21:52:43 -0500 Subject: [PATCH] Hack for sqlx to insert enums into varchar, but case still wrong --- .../media_uploads/insert_media_upload.rs | 4 +- .../endpoints/media_uploads/upload_audio.rs | 2 +- crates/types/enums/src/core/visibility.rs | 43 +++++++++ .../enums/src/files/media_upload_type.rs | 93 +++++++++++++++++++ crates/types/enums/src/files/mod.rs | 1 + crates/types/enums/src/lib.rs | 4 + crates/types/enums/src/macros.rs | 30 ++++++ .../src/db/enums/media_upload_type.rs | 53 ----------- .../types/reusable_types/src/db/enums/mod.rs | 1 - 9 files changed, 174 insertions(+), 57 deletions(-) create mode 100644 crates/types/enums/src/files/media_upload_type.rs create mode 100644 crates/types/enums/src/files/mod.rs create mode 100644 crates/types/enums/src/macros.rs delete mode 100644 crates/types/reusable_types/src/db/enums/media_upload_type.rs diff --git a/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs b/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs index 1206b5b5e1..3fbd1ba57c 100644 --- a/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs +++ b/crates/lib/database_queries/src/queries/media_uploads/insert_media_upload.rs @@ -1,7 +1,7 @@ use anyhow::anyhow; use container_common::anyhow_result::AnyhowResult; use enums::core::visibility::Visibility; -use reusable_types::db::enums::media_upload_type::MediaUploadType; +use enums::files::media_upload_type::MediaUploadType; use reusable_types::db::payloads::MediaUploadDetails; use sqlx::MySqlPool; use tokens::files::media_upload::MediaUploadToken; @@ -86,7 +86,7 @@ SET args.token, args.uuid_idempotency_token, - "audio", // TODO: args.media_type, + args.media_type, /*args.maybe_original_filename, args.original_file_size_bytes, args.original_duration_millis, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs index 4043bfdf9c..47d2ac18f2 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/upload_audio.rs @@ -19,7 +19,7 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use log::{info, warn, log}; use regex::Regex; use reusable_types::db::enums::generic_download_type::GenericDownloadType; -use reusable_types::db::enums::media_upload_type::MediaUploadType; +use enums::files::media_upload_type::MediaUploadType; use reusable_types::db::payloads::MediaUploadDetails; use sqlx::error::DatabaseError; use sqlx::error::Error::Database; diff --git a/crates/types/enums/src/core/visibility.rs b/crates/types/enums/src/core/visibility.rs index 6689fe9b94..2160927f27 100644 --- a/crates/types/enums/src/core/visibility.rs +++ b/crates/types/enums/src/core/visibility.rs @@ -30,6 +30,33 @@ pub enum Visibility { // have not yet been migrated to this scheme. } + +impl_string_enum!(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: +// +// use serde::{Deserializer, Serializer}; +// +// impl serde::Serialize for UserToken { +// fn serialize(&self, serializer: S) -> Result { +// serializer.serialize_str(&self.0) +// } +// } +// +// impl<'de> serde::Deserialize<'de> for UserToken { +// fn deserialize>(d: D) -> Result { +// let s = String::deserialize(d)?; +// Ok(UserToken(s)) +// } +// } + +//impl sqlx::Type for Visibility { +// fn type_info() -> sqlx_core::database::TypeInfo { +// todo!() +// } +//} + impl Default for Visibility { fn default() -> Self { Self::Public } } @@ -87,6 +114,22 @@ mod tests { assert!(Visibility::from_str("foo").is_err()); } + mod traits { + use crate::core::visibility::Visibility; + + #[test] + fn display() { + let visibility = Visibility::Hidden; + assert_eq!(format!("{}", visibility), "hidden".to_string()); + } + + #[test] + fn debug() { + let visibility = Visibility::Private; + assert_eq!(format!("{:?}", visibility), "private".to_string()); + } + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] struct CompositeType { visibility: Visibility, diff --git a/crates/types/enums/src/files/media_upload_type.rs b/crates/types/enums/src/files/media_upload_type.rs new file mode 100644 index 0000000000..93157a3771 --- /dev/null +++ b/crates/types/enums/src/files/media_upload_type.rs @@ -0,0 +1,93 @@ +use sqlx::Type; +use serde::Deserialize; +use serde::Serialize; +use sqlx_core::database::HasArguments; +use sqlx_core::encode::IsNull; +use sqlx_core::mysql::MySql; + +/// Used in the `media_uploads` table in a `VARCHAR` field. +/// +/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY. +//#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize, sqlx::Type)] +#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +//#[sqlx(rename_all = "lowercase")] +pub enum MediaUploadType { + #[serde(rename = "audio")] + //#[sqlx(rename = "audio")] + Audio, + #[serde(rename = "video")] + //#[sqlx(rename = "video")] + Video, +} + +// Solution adapted from https://github.com/launchbadge/sqlx/discussions/1502 +impl Type for MediaUploadType { + fn type_info() -> sqlx::mysql::MySqlTypeInfo { + String::type_info() + } +} + + +impl<'q> sqlx::Encode<'q, sqlx::MySql> for MediaUploadType { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { + self.to_string().encode_by_ref(buf) + } +} + +impl<'r> sqlx::Decode<'r, sqlx::MySql> for MediaUploadType { + fn decode( + value: sqlx::mysql::MySqlValueRef<'r>, + ) -> Result { + let string = String::decode(value)?; + let value = MediaUploadType::from_str(&string)?; + //let value = string.parse()?; + Ok(value) + } +} + + +impl_string_enum!(MediaUploadType); + +/// NB: Legacy API for older code. +impl MediaUploadType { + pub fn to_str(&self) -> &'static str { + match self { + Self::Audio => "audio", + Self::Video => "video", + } + } + + pub fn from_str(value: &str) -> Result { + match value { + "audio" => Ok(Self::Audio), + "video" => Ok(Self::Video), + _ => Err(format!("invalid value: {:?}", value)), + } + } +} + +#[cfg(test)] +mod tests { + use crate::files::media_upload_type::MediaUploadType; + use crate::test_helpers::assert_serialization; + + #[test] + fn test_serialization() { + assert_serialization(MediaUploadType::Audio, "audio"); + assert_serialization(MediaUploadType::Video, "video"); + } + + #[test] + fn test_to_str() { + assert_eq!(MediaUploadType::Audio.to_str(), "audio"); + assert_eq!(MediaUploadType::Video.to_str(), "video"); + } + + #[test] + fn test_from_str() { + assert_eq!(MediaUploadType::from_str("audio").unwrap(), MediaUploadType::Audio); + assert_eq!(MediaUploadType::from_str("video").unwrap(), MediaUploadType::Video); + assert!(MediaUploadType::from_str("foo").is_err()); + } +} diff --git a/crates/types/enums/src/files/mod.rs b/crates/types/enums/src/files/mod.rs new file mode 100644 index 0000000000..8c653cf6ad --- /dev/null +++ b/crates/types/enums/src/files/mod.rs @@ -0,0 +1 @@ +pub mod media_upload_type; diff --git a/crates/types/enums/src/lib.rs b/crates/types/enums/src/lib.rs index 7f35b53561..f9cd1566e8 100644 --- a/crates/types/enums/src/lib.rs +++ b/crates/types/enums/src/lib.rs @@ -21,6 +21,10 @@ #[macro_use] extern crate serde_derive; +#[macro_use] +mod macros; + #[cfg(test)] pub mod test_helpers; pub mod core; +pub mod files; diff --git a/crates/types/enums/src/macros.rs b/crates/types/enums/src/macros.rs new file mode 100644 index 0000000000..089031a94d --- /dev/null +++ b/crates/types/enums/src/macros.rs @@ -0,0 +1,30 @@ + +// Default methods for string enum types. +macro_rules! impl_string_enum { + ($t:ident) => { +// // Constructors and accessors. +// impl $t { +// #[inline] +// pub fn new(value: String) -> Self { +// $t(value) +// } +// +// #[inline] +// pub fn new_from_str(value: &str) -> Self { +// $t(value.to_string()) +// } +// +// #[inline] +// pub fn as_str(&self) -> &str { +// &self.0 +// } +// } + + // Display trait. + impl std::fmt::Display for $t { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } + } + } +} diff --git a/crates/types/reusable_types/src/db/enums/media_upload_type.rs b/crates/types/reusable_types/src/db/enums/media_upload_type.rs deleted file mode 100644 index c16c49e9a1..0000000000 --- a/crates/types/reusable_types/src/db/enums/media_upload_type.rs +++ /dev/null @@ -1,53 +0,0 @@ -/// Used in the `media_uploads` table. -/// -/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY. -#[derive(Clone, Copy, Eq, PartialEq, Debug, Deserialize, Serialize, sqlx::Type)] -#[serde(rename_all = "lowercase")] -#[sqlx(rename_all = "lowercase")] -pub enum MediaUploadType { - Audio, - Video, -} - -/// NB: Legacy API for older code. -impl MediaUploadType { - pub fn to_str(&self) -> &'static str { - match self { - Self::Audio => "audio", - Self::Video => "video", - } - } - - pub fn from_str(value: &str) -> Result { - match value { - "audio" => Ok(Self::Audio), - "video" => Ok(Self::Video), - _ => Err(format!("invalid value: {:?}", value)), - } - } -} - -#[cfg(test)] -mod tests { - use crate::db::enums::media_upload_type::MediaUploadType; - use crate::test_helpers::assert_serialization; - - #[test] - fn test_serialization() { - assert_serialization(MediaUploadType::Audio, "audio"); - assert_serialization(MediaUploadType::Video, "video"); - } - - #[test] - fn test_to_str() { - assert_eq!(MediaUploadType::Audio.to_str(), "audio"); - assert_eq!(MediaUploadType::Video.to_str(), "video"); - } - - #[test] - fn test_from_str() { - assert_eq!(MediaUploadType::from_str("audio").unwrap(), MediaUploadType::Audio); - assert_eq!(MediaUploadType::from_str("video").unwrap(), MediaUploadType::Video); - assert!(MediaUploadType::from_str("foo").is_err()); - } -} diff --git a/crates/types/reusable_types/src/db/enums/mod.rs b/crates/types/reusable_types/src/db/enums/mod.rs index 226cd89c3c..21cc5a7616 100644 --- a/crates/types/reusable_types/src/db/enums/mod.rs +++ b/crates/types/reusable_types/src/db/enums/mod.rs @@ -3,5 +3,4 @@ pub mod generic_download_type; pub mod generic_inference_type; -pub mod media_upload_type; pub mod vocoder_type;