oparl_types/
email_address.rs

1// SPDX-FileCopyrightText: Politik im Blick developers
2// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later OR EUPL-1.2
5
6#[derive(
7    Debug,
8    Clone,
9    PartialEq,
10    Eq,
11    Hash,
12    derive_more::AsRef,
13    derive_more::Display,
14    derive_more::From,
15    derive_more::FromStr,
16    derive_more::Into,
17    serde::Serialize,
18    serde::Deserialize,
19)]
20pub struct EmailAddress(email_address::EmailAddress);
21
22impl EmailAddress {
23    pub fn as_str(&self) -> &str {
24        self.0.as_str()
25    }
26}
27
28impl PartialOrd for EmailAddress {
29    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
30        Some(self.cmp(other))
31    }
32}
33
34impl Ord for EmailAddress {
35    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
36        self.as_str().cmp(other.as_str())
37    }
38}
39
40impl TryFrom<String> for EmailAddress {
41    type Error = email_address::Error;
42
43    fn try_from(value: String) -> Result<Self, Self::Error> {
44        value.parse()
45    }
46}
47
48#[cfg(feature = "sea-orm")]
49mod sea_orm_impls {
50    use sea_orm::{
51        sea_query::{ArrayType, Nullable, ValueType, ValueTypeErr},
52        ColumnType, DbErr, TryGetError, TryGetable, Value,
53    };
54
55    use super::EmailAddress;
56
57    impl From<EmailAddress> for Value {
58        fn from(value: EmailAddress) -> Self {
59            value.as_str().into()
60        }
61    }
62
63    impl TryGetable for EmailAddress {
64        fn try_get_by<I: sea_orm::ColIdx>(
65            res: &sea_orm::QueryResult,
66            index: I,
67        ) -> Result<Self, TryGetError> {
68            let s = <String as TryGetable>::try_get_by(res, index)?;
69            s.try_into().map_err(|e| {
70                DbErr::TryIntoErr {
71                    from: "String",
72                    into: "EmailAddress",
73                    source: Box::new(e),
74                }
75                .into()
76            })
77        }
78    }
79
80    impl ValueType for EmailAddress {
81        fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
82            let s = <String as ValueType>::try_from(v)?;
83            s.try_into().map_err(|_| ValueTypeErr)
84        }
85
86        fn type_name() -> String {
87            stringify!(String).to_owned()
88        }
89
90        fn array_type() -> ArrayType {
91            <String as ValueType>::array_type()
92        }
93
94        fn column_type() -> ColumnType {
95            <String as ValueType>::column_type()
96        }
97    }
98
99    impl Nullable for EmailAddress {
100        fn null() -> Value {
101            Value::String(None)
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::EmailAddress;
109
110    use pretty_assertions::assert_eq;
111
112    #[test]
113    fn from_str() {
114        assert_eq!(
115            EmailAddress(
116                "hello@example.com"
117                    .parse()
118                    .expect("value must be a parseable EmailAddress")
119            ),
120            "hello@example.com"
121                .parse()
122                .expect("value must be a parseable EmailAddress")
123        );
124    }
125}
126
127#[cfg(test)]
128mod serde_tests {
129    use super::EmailAddress;
130    use pretty_assertions::assert_eq;
131    use serde_json::json;
132
133    #[test]
134    fn serialize() {
135        assert_eq!(
136            json!(EmailAddress(
137                "hello@example.com"
138                    .parse()
139                    .expect("value must be a parseable EmailAddress")
140            )),
141            json!("hello@example.com")
142        );
143    }
144
145    #[test]
146    fn deserialize_good() {
147        let deserialized: EmailAddress = serde_json::from_value(json!("hello@example.com"))
148            .expect("value must be deserializable as EmailAddress");
149        assert_eq!(
150            deserialized,
151            EmailAddress(
152                "hello@example.com"
153                    .parse()
154                    .expect("value must be a parseable EmailAddress")
155            )
156        );
157    }
158
159    #[test]
160    fn deserialize_bad() {
161        assert!(serde_json::from_value::<EmailAddress>(json!("xyzabcd")).is_err());
162        assert!(serde_json::from_value::<EmailAddress>(json!(true)).is_err());
163        assert!(serde_json::from_value::<EmailAddress>(json!(123)).is_err());
164    }
165}