Skip to main content

sea_orm/value/
text_uuid.rs

1use std::{
2    fmt,
3    ops::{Deref, DerefMut},
4    str::FromStr,
5};
6
7use sea_query::{ValueType, ValueTypeErr};
8
9use crate::TryGetable;
10use crate::{self as sea_orm, TryFromU64};
11use crate::{DbErr, TryGetError};
12
13/// Newtype making sure that UUIDs will be stored as `TEXT` columns,
14/// instead of `BLOB` (which is the default).
15/// Advantages:
16/// - TEXT makes it easier to interact with the SQLite DB directly
17/// - Allows for queries like `WHERE id IN (<uuid>, <uuid>, ...)` which are
18///   impossible to write with `BLOB` values
19#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash)]
20pub struct TextUuid(pub uuid::Uuid);
21
22impl fmt::Display for TextUuid {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        self.0.fmt(f)
25    }
26}
27
28impl FromStr for TextUuid {
29    type Err = uuid::Error;
30
31    fn from_str(s: &str) -> Result<Self, Self::Err> {
32        uuid::Uuid::parse_str(s).map(TextUuid)
33    }
34}
35
36super::impl_serde_with_str!(TextUuid);
37
38impl From<TextUuid> for sea_query::Value {
39    fn from(value: TextUuid) -> Self {
40        value.0.to_string().into()
41    }
42}
43
44impl TryGetable for TextUuid {
45    fn try_get_by<I: sea_orm::ColIdx>(
46        res: &sea_orm::QueryResult,
47        index: I,
48    ) -> Result<Self, sea_orm::TryGetError> {
49        let uuid_str: String = res.try_get_by(index)?;
50        let uuid = uuid::Uuid::parse_str(&uuid_str).map_err(|e| {
51            TryGetError::DbErr(DbErr::Type(format!("Failed to parse string as UUID: {e}")))
52        })?;
53        Ok(TextUuid(uuid))
54    }
55}
56
57impl ValueType for TextUuid {
58    fn try_from(v: sea_orm::Value) -> Result<Self, ValueTypeErr> {
59        match v {
60            sea_orm::Value::String(Some(s)) => {
61                let uuid = uuid::Uuid::parse_str(&s).map_err(|_| ValueTypeErr)?;
62                Ok(TextUuid(uuid))
63            }
64            _ => Err(ValueTypeErr),
65        }
66    }
67
68    fn type_name() -> String {
69        "TextUuid".to_string()
70    }
71
72    fn array_type() -> sea_query::ArrayType {
73        <String as sea_query::ValueType>::array_type()
74    }
75
76    fn column_type() -> sea_orm::ColumnType {
77        <String as sea_query::ValueType>::column_type()
78    }
79}
80
81// This seems to be required when using TextUuid as a primary key
82impl TryFromU64 for TextUuid {
83    fn try_from_u64(_n: u64) -> Result<Self, sea_orm::DbErr> {
84        Err(sea_orm::DbErr::ConvertFromU64("TextUuid"))
85    }
86}
87
88impl sea_query::Nullable for TextUuid {
89    fn null() -> sea_orm::Value {
90        <String as sea_query::Nullable>::null()
91    }
92}
93
94impl sea_orm::IntoActiveValue<TextUuid> for TextUuid {
95    fn into_active_value(self) -> crate::ActiveValue<TextUuid> {
96        sea_orm::ActiveValue::Set(self)
97    }
98}
99
100impl Deref for TextUuid {
101    type Target = uuid::Uuid;
102
103    fn deref(&self) -> &uuid::Uuid {
104        &self.0
105    }
106}
107
108impl DerefMut for TextUuid {
109    fn deref_mut(&mut self) -> &mut uuid::Uuid {
110        &mut self.0
111    }
112}
113
114impl From<uuid::Uuid> for TextUuid {
115    fn from(value: uuid::Uuid) -> Self {
116        TextUuid(value)
117    }
118}
119
120impl From<TextUuid> for uuid::Uuid {
121    fn from(value: TextUuid) -> Self {
122        value.0
123    }
124}