1use serde::{Deserialize, Serialize};
4
5use crate::dbms::value::Value;
6use crate::memory::Encode;
7
8mod blob;
9mod boolean;
10mod date;
11mod datetime;
12mod decimal;
13mod integers;
14mod json;
15mod nullable;
16mod text;
17mod uuid;
18
19pub use self::blob::Blob;
20pub use self::boolean::Boolean;
21pub use self::date::Date;
22pub use self::datetime::DateTime;
23pub use self::decimal::Decimal;
24pub use self::integers::{Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64};
25pub use self::json::Json;
26pub use self::nullable::Nullable;
27pub use self::text::Text;
28pub use self::uuid::Uuid;
29
30pub trait DataType:
38 Clone
39 + std::fmt::Debug
40 + std::fmt::Display
41 + PartialEq
42 + Eq
43 + Default
44 + PartialOrd
45 + Ord
46 + std::hash::Hash
47 + Encode
48 + Serialize
49 + Into<Value>
50 + for<'de> Deserialize<'de>
51{
52}
53
54pub trait CustomDataType: DataType {
67 const TYPE_TAG: &'static str;
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
73pub enum DataTypeKind {
74 Blob,
75 Boolean,
76 Date,
77 DateTime,
78 Decimal,
79 Int8,
80 Int16,
81 Int32,
82 Int64,
83 Json,
84 Text,
85 Uint8,
86 Uint16,
87 Uint32,
88 Uint64,
89 Uuid,
90 Custom {
94 tag: &'static str,
95 wire_size: crate::dbms::table::WireSize,
96 },
97}
98
99#[cfg(test)]
100mod test {
101
102 use std::collections::HashSet;
103
104 use super::*;
105
106 #[test]
107 fn test_should_implement_data_type_for_every_builtin_and_nullable_builtin() {
108 fn assert_data_type<T>()
109 where
110 T: DataType,
111 {
112 }
113
114 assert_data_type::<Blob>();
115 assert_data_type::<Boolean>();
116 assert_data_type::<Date>();
117 assert_data_type::<DateTime>();
118 assert_data_type::<Decimal>();
119 assert_data_type::<Int8>();
120 assert_data_type::<Int16>();
121 assert_data_type::<Int32>();
122 assert_data_type::<Int64>();
123 assert_data_type::<Json>();
124 assert_data_type::<Text>();
125 assert_data_type::<Uint8>();
126 assert_data_type::<Uint16>();
127 assert_data_type::<Uint32>();
128 assert_data_type::<Uint64>();
129 assert_data_type::<Uuid>();
130
131 assert_data_type::<Nullable<Blob>>();
132 assert_data_type::<Nullable<Boolean>>();
133 assert_data_type::<Nullable<Date>>();
134 assert_data_type::<Nullable<DateTime>>();
135 assert_data_type::<Nullable<Decimal>>();
136 assert_data_type::<Nullable<Int8>>();
137 assert_data_type::<Nullable<Int16>>();
138 assert_data_type::<Nullable<Int32>>();
139 assert_data_type::<Nullable<Int64>>();
140 assert_data_type::<Nullable<Json>>();
141 assert_data_type::<Nullable<Text>>();
142 assert_data_type::<Nullable<Uint8>>();
143 assert_data_type::<Nullable<Uint16>>();
144 assert_data_type::<Nullable<Uint32>>();
145 assert_data_type::<Nullable<Uint64>>();
146 assert_data_type::<Nullable<Uuid>>();
147 }
148
149 #[test]
150 fn test_should_create_all_data_type_kind_variants() {
151 let kinds = [
152 DataTypeKind::Blob,
153 DataTypeKind::Boolean,
154 DataTypeKind::Date,
155 DataTypeKind::DateTime,
156 DataTypeKind::Decimal,
157 DataTypeKind::Int8,
158 DataTypeKind::Int16,
159 DataTypeKind::Int32,
160 DataTypeKind::Int64,
161 DataTypeKind::Json,
162 DataTypeKind::Text,
163 DataTypeKind::Uint8,
164 DataTypeKind::Uint16,
165 DataTypeKind::Uint32,
166 DataTypeKind::Uint64,
167 DataTypeKind::Uuid,
168 ];
169
170 assert_eq!(kinds.len(), 16);
171 }
172
173 #[test]
174 #[allow(clippy::clone_on_copy)]
175 fn test_should_clone_data_type_kind() {
176 let kind = DataTypeKind::Text;
177 let cloned = kind.clone();
178 assert_eq!(kind, cloned);
179 }
180
181 #[test]
182 fn test_should_copy_data_type_kind() {
183 let kind = DataTypeKind::Uint32;
184 let copied = kind;
185 assert_eq!(kind, copied);
186 }
187
188 #[test]
189 fn test_should_compare_data_type_kinds() {
190 assert_eq!(DataTypeKind::Blob, DataTypeKind::Blob);
191 assert_eq!(DataTypeKind::Boolean, DataTypeKind::Boolean);
192 assert_ne!(DataTypeKind::Blob, DataTypeKind::Boolean);
193 assert_ne!(DataTypeKind::Int32, DataTypeKind::Int64);
194 assert_ne!(DataTypeKind::Uint32, DataTypeKind::Uint64);
195 }
196
197 #[test]
198 fn test_should_hash_data_type_kind() {
199 let mut set = HashSet::new();
200 set.insert(DataTypeKind::Text);
201 set.insert(DataTypeKind::Uint32);
202 set.insert(DataTypeKind::Boolean);
203
204 assert!(set.contains(&DataTypeKind::Text));
205 assert!(set.contains(&DataTypeKind::Uint32));
206 assert!(set.contains(&DataTypeKind::Boolean));
207 assert!(!set.contains(&DataTypeKind::Blob));
208 }
209
210 #[test]
211 fn test_should_debug_data_type_kind() {
212 assert_eq!(format!("{:?}", DataTypeKind::Blob), "Blob");
213 assert_eq!(format!("{:?}", DataTypeKind::Boolean), "Boolean");
214 assert_eq!(format!("{:?}", DataTypeKind::Date), "Date");
215 assert_eq!(format!("{:?}", DataTypeKind::DateTime), "DateTime");
216 assert_eq!(format!("{:?}", DataTypeKind::Decimal), "Decimal");
217 assert_eq!(format!("{:?}", DataTypeKind::Int8), "Int8");
218 assert_eq!(format!("{:?}", DataTypeKind::Int16), "Int16");
219 assert_eq!(format!("{:?}", DataTypeKind::Int32), "Int32");
220 assert_eq!(format!("{:?}", DataTypeKind::Int64), "Int64");
221 assert_eq!(format!("{:?}", DataTypeKind::Json), "Json");
222 assert_eq!(format!("{:?}", DataTypeKind::Text), "Text");
223 assert_eq!(format!("{:?}", DataTypeKind::Uint8), "Uint8");
224 assert_eq!(format!("{:?}", DataTypeKind::Uint16), "Uint16");
225 assert_eq!(format!("{:?}", DataTypeKind::Uint32), "Uint32");
226 assert_eq!(format!("{:?}", DataTypeKind::Uint64), "Uint64");
227 assert_eq!(format!("{:?}", DataTypeKind::Uuid), "Uuid");
228 }
229
230 #[test]
231 fn test_should_use_data_type_kind_as_hashmap_key() {
232 use std::collections::HashMap;
233
234 let mut map = HashMap::new();
235 map.insert(DataTypeKind::Text, "String type");
236 map.insert(DataTypeKind::Uint32, "32-bit unsigned integer");
237
238 assert_eq!(map.get(&DataTypeKind::Text), Some(&"String type"));
239 assert_eq!(
240 map.get(&DataTypeKind::Uint32),
241 Some(&"32-bit unsigned integer")
242 );
243 assert_eq!(map.get(&DataTypeKind::Blob), None);
244 }
245
246 #[test]
247 fn test_should_create_custom_data_type_kind() {
248 use crate::dbms::table::WireSize;
249 let kind = DataTypeKind::Custom {
250 tag: "role",
251 wire_size: WireSize::Fixed(1),
252 };
253 assert_eq!(
254 kind,
255 DataTypeKind::Custom {
256 tag: "role",
257 wire_size: WireSize::Fixed(1)
258 }
259 );
260 assert_ne!(
261 kind,
262 DataTypeKind::Custom {
263 tag: "status",
264 wire_size: WireSize::Fixed(1)
265 }
266 );
267 assert_ne!(kind, DataTypeKind::Text);
268 }
269
270 #[test]
271 fn test_should_copy_custom_data_type_kind() {
272 use crate::dbms::table::WireSize;
273 let kind = DataTypeKind::Custom {
274 tag: "role",
275 wire_size: WireSize::LengthPrefixed,
276 };
277 let copied = kind;
278 assert_eq!(kind, copied);
279 }
280
281 #[test]
282 fn test_should_debug_custom_data_type_kind() {
283 use crate::dbms::table::WireSize;
284 let kind = DataTypeKind::Custom {
285 tag: "role",
286 wire_size: WireSize::Fixed(1),
287 };
288 let debug = format!("{kind:?}");
289 assert!(debug.contains("Custom"));
290 assert!(debug.contains("role"));
291 }
292}