lambda_appsync/
id.rs

1use serde::{Deserialize, Serialize};
2
3/// A custom UUID-based identifier type for AppSync GraphQL objects.
4///
5/// This type wraps a [Uuid](uuid::Uuid) (v4) to provide a standardized way of identifying objects
6/// in AppSync while ensuring type safety and validation. It implements serialization
7/// and deserialization as [String] as expected by GraphQL.
8///
9/// # Example
10/// ```
11/// use lambda_appsync::ID;
12///
13/// let id = ID::new();
14/// let id_str: String = id.into();
15/// ```
16#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
17#[serde(try_from = "String", into = "String")]
18pub struct ID(uuid::Uuid);
19impl ID {
20    /// Create a new random ID based on the UUIDv4 specification.
21    ///
22    /// # Example
23    /// ```
24    /// use lambda_appsync::ID;
25    ///
26    /// let id = ID::new();
27    /// ```
28    pub fn new() -> Self {
29        Self(uuid::Uuid::new_v4())
30    }
31}
32impl Default for ID {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37impl TryFrom<String> for ID {
38    type Error = uuid::Error;
39    /// Attempts to create an ID from a string representation of a UUID.
40    ///
41    /// # Example
42    /// ```
43    /// use lambda_appsync::ID;
44    ///
45    /// let id = ID::try_from("123e4567-e89b-12d3-a456-426614174000".to_string()).unwrap();
46    /// ```
47    ///
48    /// # Errors
49    /// Returns a `uuid::Error` if:
50    /// - The string is not a valid UUID format
51    /// - The string contains invalid characters
52    /// - The string is not of the correct length
53    fn try_from(value: String) -> Result<Self, Self::Error> {
54        value.parse()
55    }
56}
57
58impl core::str::FromStr for ID {
59    type Err = uuid::Error;
60
61    /// Attempts to create an ID from a string representation of a UUID.
62    ///
63    /// # Example
64    /// ```
65    /// use lambda_appsync::ID;
66    ///
67    /// let id: ID = "123e4567-e89b-12d3-a456-426614174000".parse().unwrap();
68    /// ```
69    ///
70    /// # Errors
71    /// Returns a `uuid::Error` if:
72    /// - The string is not a valid UUID format
73    /// - The string contains invalid characters
74    /// - The string is not of the correct length
75    fn from_str(s: &str) -> Result<Self, Self::Err> {
76        Ok(ID(uuid::Uuid::parse_str(s)?))
77    }
78}
79impl core::fmt::Display for ID {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        write!(f, "{}", self.0)
82    }
83}
84impl From<ID> for String {
85    fn from(value: ID) -> Self {
86        value.to_string()
87    }
88}
89impl core::ops::Deref for ID {
90    type Target = uuid::Uuid;
91
92    fn deref(&self) -> &Self::Target {
93        &self.0
94    }
95}
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use core::ops::Deref;
100
101    #[test]
102    fn test_id_creation() {
103        let id = ID::new();
104        let id_str: String = id.into();
105
106        // Test parsing back
107        let parsed = ID::try_from(id_str.clone()).unwrap();
108        assert_eq!(id, parsed);
109
110        // Test display
111        assert_eq!(id.to_string(), id_str);
112    }
113
114    #[test]
115    fn test_new_id() {
116        let id = ID::new();
117        assert!(uuid::Uuid::parse_str(&id.to_string()).is_ok());
118    }
119
120    #[test]
121    fn test_id_conversion() {
122        let id = ID::new();
123        let id_string = String::from(id);
124        let converted_id = ID::try_from(id_string.clone()).unwrap();
125        assert_eq!(id, converted_id);
126        assert_eq!(id.to_string(), id_string);
127    }
128
129    #[test]
130    fn test_invalid_id() {
131        let result = ID::try_from("not-a-uuid".to_string());
132        assert!(result.is_err());
133    }
134
135    #[test]
136    fn test_id_deref() {
137        let id = ID::new();
138        let uuid: &uuid::Uuid = id.deref();
139        assert_eq!(uuid.to_string(), id.to_string());
140    }
141
142    #[test]
143    fn test_id_display() {
144        let id = ID::new();
145        let uuid_string = id.0.to_string();
146        assert_eq!(id.to_string(), uuid_string);
147    }
148}