Skip to main content

ic_dbms_api/dbms/
types.rs

1//! This module exposes the data types used in the DBMS canister.
2
3use candid::CandidType;
4use serde::{Deserialize, Serialize};
5
6use crate::dbms::value::Value;
7use crate::memory::Encode;
8
9mod blob;
10mod boolean;
11mod date;
12mod datetime;
13mod decimal;
14mod integers;
15mod json;
16mod nullable;
17mod principal;
18mod text;
19mod uuid;
20
21pub use self::blob::Blob;
22pub use self::boolean::Boolean;
23pub use self::date::Date;
24pub use self::datetime::DateTime;
25pub use self::decimal::Decimal;
26pub use self::integers::{Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64};
27pub use self::json::Json;
28pub use self::nullable::Nullable;
29pub use self::principal::Principal;
30pub use self::text::Text;
31pub use self::uuid::Uuid;
32
33/// A trait representing a data type that can be stored in the DBMS.
34///
35/// This is an umbrella trait that combines several other traits to ensure that
36/// any type implementing [`DataType`] can be cloned, compared, hashed, encoded,
37/// and serialized/deserialized using both Candid and Serde.
38///
39/// Also it is used by the DBMS to compare and sort values of different data types.
40pub trait DataType:
41    Clone
42    + std::fmt::Debug
43    + std::fmt::Display
44    + PartialEq
45    + Eq
46    + Default
47    + PartialOrd
48    + Ord
49    + std::hash::Hash
50    + Encode
51    + CandidType
52    + Serialize
53    + Into<Value>
54    + for<'de> Deserialize<'de>
55{
56}
57
58/// An enumeration of all supported data type kinds in the DBMS.
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60pub enum DataTypeKind {
61    Blob,
62    Boolean,
63    Date,
64    DateTime,
65    Decimal,
66    Int32,
67    Int64,
68    Json,
69    Principal,
70    Text,
71    Uint32,
72    Uint64,
73    Uuid,
74}
75
76#[cfg(test)]
77mod test {
78
79    use std::collections::HashSet;
80
81    use super::*;
82
83    #[test]
84    fn test_should_create_all_data_type_kind_variants() {
85        let kinds = [
86            DataTypeKind::Blob,
87            DataTypeKind::Boolean,
88            DataTypeKind::Date,
89            DataTypeKind::DateTime,
90            DataTypeKind::Decimal,
91            DataTypeKind::Int32,
92            DataTypeKind::Int64,
93            DataTypeKind::Json,
94            DataTypeKind::Principal,
95            DataTypeKind::Text,
96            DataTypeKind::Uint32,
97            DataTypeKind::Uint64,
98            DataTypeKind::Uuid,
99        ];
100
101        assert_eq!(kinds.len(), 13);
102    }
103
104    #[test]
105    #[allow(clippy::clone_on_copy)]
106    fn test_should_clone_data_type_kind() {
107        let kind = DataTypeKind::Text;
108        let cloned = kind.clone();
109        assert_eq!(kind, cloned);
110    }
111
112    #[test]
113    fn test_should_copy_data_type_kind() {
114        let kind = DataTypeKind::Uint32;
115        let copied = kind;
116        assert_eq!(kind, copied);
117    }
118
119    #[test]
120    fn test_should_compare_data_type_kinds() {
121        assert_eq!(DataTypeKind::Blob, DataTypeKind::Blob);
122        assert_eq!(DataTypeKind::Boolean, DataTypeKind::Boolean);
123        assert_ne!(DataTypeKind::Blob, DataTypeKind::Boolean);
124        assert_ne!(DataTypeKind::Int32, DataTypeKind::Int64);
125        assert_ne!(DataTypeKind::Uint32, DataTypeKind::Uint64);
126    }
127
128    #[test]
129    fn test_should_hash_data_type_kind() {
130        let mut set = HashSet::new();
131        set.insert(DataTypeKind::Text);
132        set.insert(DataTypeKind::Uint32);
133        set.insert(DataTypeKind::Boolean);
134
135        assert!(set.contains(&DataTypeKind::Text));
136        assert!(set.contains(&DataTypeKind::Uint32));
137        assert!(set.contains(&DataTypeKind::Boolean));
138        assert!(!set.contains(&DataTypeKind::Blob));
139    }
140
141    #[test]
142    fn test_should_debug_data_type_kind() {
143        assert_eq!(format!("{:?}", DataTypeKind::Blob), "Blob");
144        assert_eq!(format!("{:?}", DataTypeKind::Boolean), "Boolean");
145        assert_eq!(format!("{:?}", DataTypeKind::Date), "Date");
146        assert_eq!(format!("{:?}", DataTypeKind::DateTime), "DateTime");
147        assert_eq!(format!("{:?}", DataTypeKind::Decimal), "Decimal");
148        assert_eq!(format!("{:?}", DataTypeKind::Int32), "Int32");
149        assert_eq!(format!("{:?}", DataTypeKind::Int64), "Int64");
150        assert_eq!(format!("{:?}", DataTypeKind::Json), "Json");
151        assert_eq!(format!("{:?}", DataTypeKind::Principal), "Principal");
152        assert_eq!(format!("{:?}", DataTypeKind::Text), "Text");
153        assert_eq!(format!("{:?}", DataTypeKind::Uint32), "Uint32");
154        assert_eq!(format!("{:?}", DataTypeKind::Uint64), "Uint64");
155        assert_eq!(format!("{:?}", DataTypeKind::Uuid), "Uuid");
156    }
157
158    #[test]
159    fn test_should_use_data_type_kind_as_hashmap_key() {
160        use std::collections::HashMap;
161
162        let mut map = HashMap::new();
163        map.insert(DataTypeKind::Text, "String type");
164        map.insert(DataTypeKind::Uint32, "32-bit unsigned integer");
165
166        assert_eq!(map.get(&DataTypeKind::Text), Some(&"String type"));
167        assert_eq!(
168            map.get(&DataTypeKind::Uint32),
169            Some(&"32-bit unsigned integer")
170        );
171        assert_eq!(map.get(&DataTypeKind::Blob), None);
172    }
173}