taos_query/common/
ty.rs

1use std::{
2    fmt::{self, Display},
3    str::FromStr,
4};
5
6use serde::de::Visitor;
7
8/// TDengine data type enumeration.
9///
10/// | enum       | int | sql name         | rust type |
11/// | ----       |:---:| --------         |:---------:|
12/// | Null       | 0   | NULL             | None      |
13/// | Bool       | 1   | BOOL             | bool      |
14/// | TinyInt    | 2   | TINYINT          | i8        |
15/// | SmallInt   | 3   | SMALLINT         | i16       |
16/// | Int        | 4   | INT              | i32       |
17/// | BitInt     | 5   | BIGINT           | i64       |
18/// | Float      | 6   | FLOAT            | f32       |
19/// | Double     | 7   | DOUBLE           | f64       |
20/// | VarChar    | 8   | BINARY/VARCHAR   | str/String        |
21/// | Timestamp  | 9   | TIMESTAMP        | i64               |
22/// | NChar      | 10  | NCHAR            | str/String        |
23/// | UTinyInt   | 11  | TINYINT UNSIGNED | u8                |
24/// | USmallInt  | 12  | SMALLINT UNSIGNED| u16               |
25/// | UInt       | 13  | INT UNSIGNED     | u32               |
26/// | UBigInt    | 14  | BIGINT UNSIGNED  | u64               |
27/// | Json       | 15  | JSON             | serde_json::Value |
28/// | VarBinary  | 16  | VARBINARY        | Vec<u8>           |
29/// | Geometry   | 20  | GEOMETRY         | Vec<u8>           |
30///
31/// Note:
32/// - VarChar sql name is BINARY in v2, and VARCHAR in v3.
33/// - Decimal/Blob/MediumBlob is not supported in 2.0/3.0 .
34#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, serde_repr::Serialize_repr)]
35#[repr(u8)]
36#[non_exhaustive]
37#[derive(Default)]
38pub enum Ty {
39    /// Null is only a value, not a *real* type, a nullable data type could be represented as [`Option<T>`] in Rust.
40    ///
41    /// A data type should never be Null.
42    #[doc(hidden)]
43    #[default]
44    Null = 0,
45    /// The `BOOL` type in sql, will be represented as [bool] in Rust.
46    Bool = 1,
47    /// `TINYINT` type in sql, will be represented in Rust as [i8].
48    TinyInt = 2,
49    /// `SMALLINT` type in sql, will be represented in Rust as [i16].
50    SmallInt = 3,
51    /// `INT` type in sql, will be represented in Rust as [i32].
52    Int = 4,
53    /// `BIGINT` type in sql, will be represented in Rust as [i64].
54    BigInt = 5, // 5
55    /// UTinyInt, `tinyint unsigned` in sql, [u8] in Rust.
56    UTinyInt = 11, // 11
57    /// 12: USmallInt, `smallint unsigned` in sql, [u16] in Rust.
58    USmallInt = 12, // 12
59    /// 13: UInt, `int unsigned` in sql, [u32] in Rust.
60    UInt = 13, // 13
61    /// 14: UBigInt, `bigint unsigned` in sql, [u64] in Rust.
62    UBigInt = 14, // 14
63    /// 6: Float, `float` type in sql, will be represented in Rust as [f32].
64    Float = 6, // 6
65    /// 7: Double, `tinyint` type in sql, will be represented in Rust as [f64].
66    Double = 7, // 7
67    /// 9: Timestamp, `timestamp` type in sql, will be represented as [i64] in Rust.
68    /// But can be deserialized to [chrono::naive::NaiveDateTime] or [String].
69    Timestamp = 9, // 9
70    /// 8: VarChar, `binary` type in sql for TDengine 2.x, `varchar` for TDengine 3.x,
71    ///  will be represented in Rust as [&str] or [String]. This type of data be deserialized to [`Vec<u8>`].
72    VarChar = 8,
73    /// 10: NChar, `nchar` type in sql, the recommended way in TDengine to store utf-8 [String].
74    NChar = 10, // 10
75    /// 15: Json, `json` tag in sql, will be represented as [serde_json::value::Value] in Rust.
76    Json = 15, // 15
77
78    /// 16, VarBinary, `varbinary` in sql, [`Vec<u8>`] in Rust.
79    VarBinary = 16, // 16
80    /// 17, Not supported now.
81    #[doc(hidden)]
82    Decimal, // 17
83    /// 18, Not supported now.
84    #[doc(hidden)]
85    Blob, // 18
86    /// 19, Not supported now.
87    #[doc(hidden)]
88    MediumBlob, // 19
89
90    /// 20, Geometry, `geometry` in sql, [`Vec<u8>`] in Rust.
91    Geometry, // 20
92}
93
94impl<'de> serde::Deserialize<'de> for Ty {
95    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
96    where
97        D: serde::Deserializer<'de>,
98    {
99        struct TyVisitor;
100
101        impl<'de> Visitor<'de> for TyVisitor {
102            type Value = Ty;
103
104            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
105                formatter.write_str("invalid TDengine type")
106            }
107            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
108            where
109                E: serde::de::Error,
110            {
111                Ok(Ty::from_u8(v as u8))
112            }
113
114            fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
115            where
116                E: serde::de::Error,
117            {
118                Ok(Ty::from_u8(v))
119            }
120
121            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
122            where
123                E: serde::de::Error,
124            {
125                Ok(Ty::from_u8(v as u8))
126            }
127
128            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
129            where
130                E: serde::de::Error,
131            {
132                Ty::from_str(v).map_err(<E as serde::de::Error>::custom)
133            }
134
135            fn visit_none<E>(self) -> Result<Self::Value, E>
136            where
137                E: serde::de::Error,
138            {
139                Ok(Ty::Null)
140            }
141
142            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
143            where
144                D: serde::Deserializer<'de>,
145            {
146                deserializer.deserialize_any(self)
147            }
148
149            fn visit_unit<E>(self) -> Result<Self::Value, E>
150            where
151                E: serde::de::Error,
152            {
153                Ok(Ty::Null)
154            }
155        }
156
157        deserializer.deserialize_any(TyVisitor)
158    }
159}
160
161impl FromStr for Ty {
162    type Err = &'static str;
163    fn from_str(s: &str) -> Result<Self, Self::Err> {
164        match s.to_lowercase().as_str() {
165            "timestamp" => Ok(Ty::Timestamp),
166            "bool" => Ok(Ty::Bool),
167            "tinyint" => Ok(Ty::TinyInt),
168            "smallint" => Ok(Ty::SmallInt),
169            "int" => Ok(Ty::Int),
170            "bigint" => Ok(Ty::BigInt),
171            "tinyint unsigned" => Ok(Ty::UTinyInt),
172            "smallint unsigned" => Ok(Ty::USmallInt),
173            "int unsigned" => Ok(Ty::UInt),
174            "bigint unsigned" => Ok(Ty::UBigInt),
175            "float" => Ok(Ty::Float),
176            "double" => Ok(Ty::Double),
177            "binary" | "varchar" => Ok(Ty::VarChar),
178            "nchar" => Ok(Ty::NChar),
179            "json" => Ok(Ty::Json),
180            "varbinary" => Ok(Ty::VarBinary),
181            "decimal" => Ok(Ty::Decimal),
182            "blob" => Ok(Ty::Blob),
183            "mediumblob" => Ok(Ty::MediumBlob),
184            "geometry" => Ok(Ty::Geometry),
185            _ => Err("not a valid data type string"),
186        }
187    }
188}
189
190impl Ty {
191    /// Check if the data type is null or not.
192    pub const fn is_null(&self) -> bool {
193        matches!(self, Ty::Null)
194    }
195
196    /// Var type is one of [Ty::VarChar], [Ty::VarBinary], [Ty::NChar], [Ty::Geometry].
197    pub const fn is_var_type(&self) -> bool {
198        use Ty::*;
199        matches!(self, VarChar | VarBinary | NChar | Geometry)
200    }
201
202    // /// Check if the data type need quotes, means one of [Ty::VarChar], [Ty::NChar], [Ty::Json].
203    // pub const fn is_quote(&self) -> bool {
204    //     use Ty::*;
205    //     matches!(self, Json)
206    // }
207
208    pub const fn is_json(&self) -> bool {
209        matches!(self, Ty::Json)
210    }
211
212    /// Is one of boolean/integers/float/double/decimal
213    pub const fn is_primitive(&self) -> bool {
214        use Ty::*;
215        matches!(
216            self,
217            Bool | TinyInt
218                | SmallInt
219                | Int
220                | BigInt
221                | UTinyInt
222                | USmallInt
223                | UInt
224                | UBigInt
225                | Float
226                | Double
227                | Timestamp
228                | Decimal
229        )
230    }
231
232    /// Get fixed length if the type is primitive.
233    pub const fn fixed_length(&self) -> usize {
234        use Ty::*;
235        match self {
236            Bool => 1,
237            TinyInt => 1,
238            SmallInt => 2,
239            Int => 4,
240            BigInt => 8,
241            Float => 4,
242            Double => 8,
243            Timestamp => 8,
244            UTinyInt => 1,
245            USmallInt => 2,
246            UInt => 4,
247            UBigInt => 8,
248            Decimal => 16,
249            _ => 0,
250        }
251    }
252
253    /// The sql name of type.
254    pub const fn name(&self) -> &'static str {
255        use Ty::*;
256        match self {
257            Null => "NULL",
258            Bool => "BOOL",
259            TinyInt => "TINYINT",
260            SmallInt => "SMALLINT",
261            Int => "INT",
262            BigInt => "BIGINT",
263            Float => "FLOAT",
264            Double => "DOUBLE",
265            VarChar => "BINARY",
266            Timestamp => "TIMESTAMP",
267            NChar => "NCHAR",
268            UTinyInt => "TINYINT UNSIGNED",
269            USmallInt => "SMALLINT UNSIGNED",
270            UInt => "INT UNSIGNED",
271            UBigInt => "BIGINT UNSIGNED",
272            Json => "JSON",
273            VarBinary => "VARBINARY",
274            Decimal => "DECIMAL",
275            Blob => "BLOB",
276            MediumBlob => "MEDIUMBLOB",
277            Geometry => "GEOMETRY",
278        }
279    }
280
281    pub const fn lowercase_name(&self) -> &'static str {
282        use Ty::*;
283        match self {
284            Null => "null",
285            Bool => "bool",
286            TinyInt => "tinyint",
287            SmallInt => "smallint",
288            Int => "int",
289            BigInt => "bigint",
290            Float => "float",
291            Double => "double",
292            VarChar => "binary",
293            Timestamp => "timestamp",
294            NChar => "nchar",
295            UTinyInt => "tinyint unsigned",
296            USmallInt => "smallint unsigned",
297            UInt => "int unsigned",
298            UBigInt => "bigint unsigned",
299            Json => "json",
300            VarBinary => "varbinary",
301            Decimal => "decimal",
302            Blob => "blob",
303            MediumBlob => "mediumblob",
304            Geometry => "geometry",
305        }
306    }
307
308    /// The enum constants directly to str.
309    #[inline]
310    pub(crate) const fn as_variant_str(&self) -> &'static str {
311        use Ty::*;
312        macro_rules! _var_str {
313          ($($v:ident) *) => {
314              match self {
315                $($v => stringify!($v),) *
316              }
317          }
318        }
319        _var_str!(
320            Null Bool TinyInt SmallInt Int BigInt UTinyInt USmallInt UInt UBigInt
321            Float Double VarChar NChar Timestamp Json VarBinary Decimal Blob MediumBlob Geometry
322        )
323    }
324
325    #[inline]
326    const fn from_u8(v: u8) -> Self {
327        use Ty::*;
328        match v {
329            0 => Null,
330            1 => Bool,
331            2 => TinyInt,
332            3 => SmallInt,
333            4 => Int,
334            5 => BigInt,
335            6 => Float,
336            7 => Double,
337            8 => VarChar,
338            9 => Timestamp,
339            10 => NChar,
340            11 => UTinyInt,
341            12 => USmallInt,
342            13 => UInt,
343            14 => UBigInt,
344            15 => Json,
345            16 => VarBinary,
346            17 => Decimal,
347            18 => Blob,
348            19 => MediumBlob,
349            20 => Geometry,
350            _ => panic!("unknown data type"),
351        }
352    }
353}
354impl From<u8> for Ty {
355    #[inline]
356    fn from(v: u8) -> Self {
357        unsafe { std::mem::transmute(v) }
358    }
359}
360
361impl Display for Ty {
362    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363        write!(f, "{}", self.name())
364    }
365}
366macro_rules! _impl_from_primitive {
367    ($($ty:ty) *) => {
368      $(
369         impl From<$ty> for Ty {
370            #[inline]
371           fn from(v: $ty) -> Self {
372             Self::from_u8(v as _)
373           }
374         }
375      )*
376    }
377}
378
379_impl_from_primitive!(i8 i16 i32 i64 u16 u32 u64);