1use candid::CandidType;
2use serde::{Deserialize, Serialize};
3
4use super::types;
5
6#[derive(
8 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, CandidType, Serialize, Deserialize,
9)]
10pub enum Value {
11 Blob(types::Blob),
12 Boolean(types::Boolean),
13 Date(types::Date),
14 DateTime(types::DateTime),
15 Decimal(types::Decimal),
16 Int32(types::Int32),
17 Int64(types::Int64),
18 Null,
19 Principal(types::Principal),
20 Text(types::Text),
21 Uint32(types::Uint32),
22 Uint64(types::Uint64),
23 Uuid(types::Uuid),
24}
25
26macro_rules! impl_conv_for_value {
28 ($variant:ident, $ty:ty, $name:ident) => {
29 impl From<$ty> for Value {
30 fn from(value: $ty) -> Self {
31 Value::$variant(value)
32 }
33 }
34
35 impl Value {
36 pub fn $name(&self) -> Option<&$ty> {
38 if let Value::$variant(v) = self {
39 Some(v)
40 } else {
41 None
42 }
43 }
44 }
45 };
46}
47
48impl_conv_for_value!(Blob, types::Blob, as_blob);
49impl_conv_for_value!(Boolean, types::Boolean, as_boolean);
50impl_conv_for_value!(Date, types::Date, as_date);
51impl_conv_for_value!(DateTime, types::DateTime, as_datetime);
52impl_conv_for_value!(Decimal, types::Decimal, as_decimal);
53impl_conv_for_value!(Int32, types::Int32, as_int32);
54impl_conv_for_value!(Int64, types::Int64, as_int64);
55impl_conv_for_value!(Principal, types::Principal, as_principal);
56impl_conv_for_value!(Text, types::Text, as_text);
57impl_conv_for_value!(Uint32, types::Uint32, as_uint32);
58impl_conv_for_value!(Uint64, types::Uint64, as_uint64);
59impl_conv_for_value!(Uuid, types::Uuid, as_uuid);
60
61impl Value {
62 pub fn is_null(&self) -> bool {
64 matches!(self, Value::Null)
65 }
66
67 pub fn type_name(&self) -> &'static str {
69 match self {
70 Value::Blob(_) => "Blob",
71 Value::Boolean(_) => "Boolean",
72 Value::Date(_) => "Date",
73 Value::DateTime(_) => "DateTime",
74 Value::Decimal(_) => "Decimal",
75 Value::Int32(_) => "Int32",
76 Value::Int64(_) => "Int64",
77 Value::Null => "Null",
78 Value::Principal(_) => "Principal",
79 Value::Text(_) => "Text",
80 Value::Uint32(_) => "Uint32",
81 Value::Uint64(_) => "Uint64",
82 Value::Uuid(_) => "Uuid",
83 }
84 }
85}
86
87#[cfg(test)]
88mod tests {
89
90 use uuid::Uuid;
91
92 use super::*;
93
94 #[test]
95 fn test_null() {
96 let int_value: Value = types::Int32(42).into();
97 assert!(!int_value.is_null());
98
99 let null_value = Value::Null;
100 assert!(null_value.is_null());
101 }
102
103 #[test]
104 fn test_value_conversion_blob() {
105 let blob = types::Blob(vec![1, 2, 3]);
106 let value: Value = blob.clone().into();
107 assert_eq!(value.as_blob(), Some(&blob));
108 }
109
110 #[test]
111 fn test_value_conversion_boolean() {
112 let boolean = types::Boolean(true);
113 let value: Value = boolean.into();
114 assert_eq!(value.as_boolean(), Some(&boolean));
115 }
116
117 #[test]
118 fn test_value_conversion_date() {
119 let date = types::Date {
120 year: 2023,
121 month: 3,
122 day: 15,
123 }; let value: Value = date.into();
125 assert_eq!(value.as_date(), Some(&date));
126 }
127
128 #[test]
129 fn test_value_conversion_datetime() {
130 let datetime = types::DateTime {
131 year: 2023,
132 month: 3,
133 day: 15,
134 hour: 12,
135 minute: 30,
136 second: 45,
137 microsecond: 123456,
138 timezone_offset_minutes: 0,
139 }; let value: Value = datetime.into();
141 assert_eq!(value.as_datetime(), Some(&datetime));
142 }
143
144 #[test]
145 fn test_value_conversion_decimal() {
146 let decimal = types::Decimal(rust_decimal::Decimal::new(12345, 2)); let value: Value = decimal.into();
148 assert_eq!(value.as_decimal(), Some(&decimal));
149 }
150
151 #[test]
152 fn test_value_conversion_int32() {
153 let int32 = types::Int32(1234567890);
154 let value: Value = int32.into();
155 assert_eq!(value.as_int32(), Some(&int32));
156 }
157
158 #[test]
159 fn test_value_conversion_int64() {
160 let int64 = types::Int64(1234567890);
161 let value: Value = int64.into();
162 assert_eq!(value.as_int64(), Some(&int64));
163 }
164
165 #[test]
166 fn test_value_conversion_principal() {
167 let principal = types::Principal(candid::Principal::from_text("aaaaa-aa").unwrap());
168 let value: Value = principal.clone().into();
169 assert_eq!(value.as_principal(), Some(&principal));
170 }
171
172 #[test]
173 fn test_value_conversion_text() {
174 let text = types::Text("Hello, World!".to_string());
175 let value: Value = text.clone().into();
176 assert_eq!(value.as_text(), Some(&text));
177 }
178
179 #[test]
180 fn test_value_conversion_uint32() {
181 let uint32 = types::Uint32(123456);
182 let value: Value = uint32.into();
183 assert_eq!(value.as_uint32(), Some(&uint32));
184 }
185
186 #[test]
187 fn test_value_conversion_uint64() {
188 let uint64 = types::Uint64(12345678901234);
189 let value: Value = uint64.into();
190 assert_eq!(value.as_uint64(), Some(&uint64));
191 }
192
193 #[test]
194 fn test_value_conversion_uuid() {
195 let uuid = types::Uuid(
196 Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").expect("failed to parse uuid"),
197 );
198 let value: Value = uuid.clone().into();
199 assert_eq!(value.as_uuid(), Some(&uuid));
200 }
201
202 #[test]
203 fn test_value_type_name() {
204 let int_value: Value = types::Int32(42).into();
205 assert_eq!(int_value.type_name(), "Int32");
206
207 let text_value: Value = types::Text("Hello".to_string()).into();
208 assert_eq!(text_value.type_name(), "Text");
209
210 let null_value = Value::Null;
211 assert_eq!(null_value.type_name(), "Null");
212 }
213}