Skip to main content

wasm_dbms_api/dbms/
types.rs

1//! This module exposes the data types used in the DBMS.
2
3use 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
30/// A trait representing a data type that can be stored in the DBMS.
31///
32/// This is an umbrella trait that combines several other traits to ensure that
33/// any type implementing [`DataType`] can be cloned, compared, hashed, encoded,
34/// and serialized/deserialized using Serde.
35///
36/// Also it is used by the DBMS to compare and sort values of different data types.
37pub 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
54/// A trait for user-defined custom data types.
55///
56/// Custom types are stored as type-erased [`CustomValue`](crate::dbms::custom_value::CustomValue)
57/// inside `Value::Custom`. The `TYPE_TAG` constant uniquely identifies the type
58/// and must be stable across versions.
59///
60/// # Ordering contract
61///
62/// For custom types used with range filters (`Gt`, `Lt`, `Ge`, `Le`) or `ORDER BY`,
63/// the [`Encode`](crate::memory::Encode) output must be order-preserving: if `a < b`,
64/// then `a.encode() < b.encode()` lexicographically.
65/// Equality filters (`Eq`, `Ne`, `In`) only require canonical encoding.
66pub trait CustomDataType: DataType {
67    /// Unique string identifier for this type (e.g., `"principal"`, `"role"`).
68    const TYPE_TAG: &'static str;
69}
70
71/// An enumeration of all supported data type kinds in the DBMS.
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
73pub enum DataTypeKind {
74    Blob,
75    Boolean,
76    Date,
77    DateTime,
78    Decimal,
79    Int32,
80    Int64,
81    Json,
82    Text,
83    Uint32,
84    Uint64,
85    Uuid,
86    Custom(&'static str),
87}
88
89#[cfg(test)]
90mod test {
91
92    use std::collections::HashSet;
93
94    use super::*;
95
96    #[test]
97    fn test_should_create_all_data_type_kind_variants() {
98        let kinds = [
99            DataTypeKind::Blob,
100            DataTypeKind::Boolean,
101            DataTypeKind::Date,
102            DataTypeKind::DateTime,
103            DataTypeKind::Decimal,
104            DataTypeKind::Int32,
105            DataTypeKind::Int64,
106            DataTypeKind::Json,
107            DataTypeKind::Text,
108            DataTypeKind::Uint32,
109            DataTypeKind::Uint64,
110            DataTypeKind::Uuid,
111        ];
112
113        assert_eq!(kinds.len(), 12);
114    }
115
116    #[test]
117    #[allow(clippy::clone_on_copy)]
118    fn test_should_clone_data_type_kind() {
119        let kind = DataTypeKind::Text;
120        let cloned = kind.clone();
121        assert_eq!(kind, cloned);
122    }
123
124    #[test]
125    fn test_should_copy_data_type_kind() {
126        let kind = DataTypeKind::Uint32;
127        let copied = kind;
128        assert_eq!(kind, copied);
129    }
130
131    #[test]
132    fn test_should_compare_data_type_kinds() {
133        assert_eq!(DataTypeKind::Blob, DataTypeKind::Blob);
134        assert_eq!(DataTypeKind::Boolean, DataTypeKind::Boolean);
135        assert_ne!(DataTypeKind::Blob, DataTypeKind::Boolean);
136        assert_ne!(DataTypeKind::Int32, DataTypeKind::Int64);
137        assert_ne!(DataTypeKind::Uint32, DataTypeKind::Uint64);
138    }
139
140    #[test]
141    fn test_should_hash_data_type_kind() {
142        let mut set = HashSet::new();
143        set.insert(DataTypeKind::Text);
144        set.insert(DataTypeKind::Uint32);
145        set.insert(DataTypeKind::Boolean);
146
147        assert!(set.contains(&DataTypeKind::Text));
148        assert!(set.contains(&DataTypeKind::Uint32));
149        assert!(set.contains(&DataTypeKind::Boolean));
150        assert!(!set.contains(&DataTypeKind::Blob));
151    }
152
153    #[test]
154    fn test_should_debug_data_type_kind() {
155        assert_eq!(format!("{:?}", DataTypeKind::Blob), "Blob");
156        assert_eq!(format!("{:?}", DataTypeKind::Boolean), "Boolean");
157        assert_eq!(format!("{:?}", DataTypeKind::Date), "Date");
158        assert_eq!(format!("{:?}", DataTypeKind::DateTime), "DateTime");
159        assert_eq!(format!("{:?}", DataTypeKind::Decimal), "Decimal");
160        assert_eq!(format!("{:?}", DataTypeKind::Int32), "Int32");
161        assert_eq!(format!("{:?}", DataTypeKind::Int64), "Int64");
162        assert_eq!(format!("{:?}", DataTypeKind::Json), "Json");
163        assert_eq!(format!("{:?}", DataTypeKind::Text), "Text");
164        assert_eq!(format!("{:?}", DataTypeKind::Uint32), "Uint32");
165        assert_eq!(format!("{:?}", DataTypeKind::Uint64), "Uint64");
166        assert_eq!(format!("{:?}", DataTypeKind::Uuid), "Uuid");
167    }
168
169    #[test]
170    fn test_should_use_data_type_kind_as_hashmap_key() {
171        use std::collections::HashMap;
172
173        let mut map = HashMap::new();
174        map.insert(DataTypeKind::Text, "String type");
175        map.insert(DataTypeKind::Uint32, "32-bit unsigned integer");
176
177        assert_eq!(map.get(&DataTypeKind::Text), Some(&"String type"));
178        assert_eq!(
179            map.get(&DataTypeKind::Uint32),
180            Some(&"32-bit unsigned integer")
181        );
182        assert_eq!(map.get(&DataTypeKind::Blob), None);
183    }
184
185    #[test]
186    fn test_should_create_custom_data_type_kind() {
187        let kind = DataTypeKind::Custom("role");
188        assert_eq!(kind, DataTypeKind::Custom("role"));
189        assert_ne!(kind, DataTypeKind::Custom("status"));
190        assert_ne!(kind, DataTypeKind::Text);
191    }
192
193    #[test]
194    fn test_should_copy_custom_data_type_kind() {
195        let kind = DataTypeKind::Custom("role");
196        let copied = kind;
197        assert_eq!(kind, copied);
198    }
199
200    #[test]
201    fn test_should_debug_custom_data_type_kind() {
202        let kind = DataTypeKind::Custom("role");
203        let debug = format!("{kind:?}");
204        assert!(debug.contains("Custom"));
205        assert!(debug.contains("role"));
206    }
207}