use std::{fmt, string::String as StdString}; use sqlx::{ encode::{Encode, IsNull}, Database, Decode, Type, }; use unicode_normalization::UnicodeNormalization as _; #[derive(Clone, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(from = "StdString", into = "StdString")] pub struct String(StdString); impl fmt::Display for String { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self(value) = self; value.fmt(f) } } impl From for String { fn from(value: StdString) -> Self { let value = value.nfc().collect(); Self(value) } } impl From for StdString { fn from(value: String) -> Self { let String(value) = value; value } } impl std::ops::Deref for String { type Target = StdString; fn deref(&self) -> &Self::Target { let Self(value) = self; value } } // Type is manually implemented so that we can implement Decode to do // normalization on read. Implementation is otherwise based on // `#[derive(sqlx::Type)]` with the `#[sqlx(transparent)]` attribute. impl Type for String where DB: Database, StdString: Type, { fn type_info() -> ::TypeInfo { >::type_info() } fn compatible(ty: &::TypeInfo) -> bool { >::compatible(ty) } } impl<'r, DB> Decode<'r, DB> for String where DB: Database, StdString: Decode<'r, DB>, { fn decode(value: ::ValueRef<'r>) -> Result { let value = StdString::decode(value)?; let value = value.nfc().collect(); Ok(Self(value)) } } impl<'q, DB> Encode<'q, DB> for String where DB: Database, StdString: Encode<'q, DB>, { fn encode_by_ref( &self, buf: &mut ::ArgumentBuffer<'q>, ) -> Result { let Self(value) = self; value.encode_by_ref(buf) } fn encode( self, buf: &mut ::ArgumentBuffer<'q>, ) -> Result { let Self(value) = self; value.encode(buf) } fn produces(&self) -> Option<::TypeInfo> { let Self(value) = self; value.produces() } fn size_hint(&self) -> usize { let Self(value) = self; value.size_hint() } }