sqlx_rxqlite/
type_info.rs

1use std::fmt::{self, Display, Formatter};
2use std::str::FromStr;
3
4//use libsqlite3_sys::{SQLITE_BLOB, SQLITE_FLOAT, SQLITE_INTEGER, SQLITE_NULL, SQLITE_TEXT};
5
6use crate::error::BoxDynError;
7
8pub(crate) use sqlx_core::type_info::*;
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
12pub(crate) enum DataType {
13    Null,
14    Int,
15    Float,
16    Text,
17    Blob,
18
19    // TODO: Support NUMERIC
20    #[allow(dead_code)]
21    Numeric,
22
23    // non-standard extensions
24    Bool,
25    Int64,
26    Date,
27    Time,
28    Datetime,
29}
30
31/// Type information for a SQLite type.
32#[derive(Debug, Clone, Eq, PartialEq, Hash)]
33#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
34pub struct RXQLiteTypeInfo(pub(crate) DataType);
35
36impl Display for RXQLiteTypeInfo {
37    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
38        f.pad(self.name())
39    }
40}
41
42impl TypeInfo for RXQLiteTypeInfo {
43    fn is_null(&self) -> bool {
44        matches!(self.0, DataType::Null)
45    }
46
47    fn name(&self) -> &str {
48        match self.0 {
49            DataType::Null => "NULL",
50            DataType::Text => "TEXT",
51            DataType::Float => "REAL",
52            DataType::Blob => "BLOB",
53            DataType::Int | DataType::Int64 => "INTEGER",
54            DataType::Numeric => "NUMERIC",
55
56            // non-standard extensions
57            DataType::Bool => "BOOLEAN",
58            DataType::Date => "DATE",
59            DataType::Time => "TIME",
60            DataType::Datetime => "DATETIME",
61        }
62    }
63}
64
65// note: this implementation is particularly important as this is how the macros determine
66//       what Rust type maps to what *declared* SQL type
67// <https://www.sqlite.org/datatype3.html#affname>
68impl FromStr for DataType {
69    type Err = BoxDynError;
70
71    fn from_str(s: &str) -> Result<Self, Self::Err> {
72        let s = s.to_ascii_lowercase();
73        Ok(match &*s {
74            "int4" => DataType::Int,
75            "int8" => DataType::Int64,
76            "boolean" | "bool" => DataType::Bool,
77
78            "date" => DataType::Date,
79            "time" => DataType::Time,
80            "datetime" | "timestamp" => DataType::Datetime,
81
82            _ if s.contains("int") => DataType::Int64,
83
84            _ if s.contains("char") || s.contains("clob") || s.contains("text") => DataType::Text,
85
86            _ if s.contains("blob") => DataType::Blob,
87
88            _ if s.contains("real") || s.contains("floa") || s.contains("doub") => DataType::Float,
89
90            _ => {
91                return Err(format!("unknown type: `{s}`").into());
92            }
93        })
94    }
95}
96
97// #[cfg(feature = "any")]
98// impl From<RXQLiteTypeInfo> for crate::any::AnyTypeInfo {
99//     #[inline]
100//     fn from(ty: RXQLiteTypeInfo) -> Self {
101//         crate::any::AnyTypeInfo(crate::any::type_info::AnyTypeInfoKind::RXQLite(ty))
102//     }
103// }
104
105#[test]
106fn test_data_type_from_str() -> Result<(), BoxDynError> {
107    assert_eq!(DataType::Int, "INT4".parse()?);
108
109    assert_eq!(DataType::Int64, "INT".parse()?);
110    assert_eq!(DataType::Int64, "INTEGER".parse()?);
111    assert_eq!(DataType::Int64, "INTBIG".parse()?);
112    assert_eq!(DataType::Int64, "MEDIUMINT".parse()?);
113
114    assert_eq!(DataType::Int64, "BIGINT".parse()?);
115    assert_eq!(DataType::Int64, "UNSIGNED BIG INT".parse()?);
116    assert_eq!(DataType::Int64, "INT8".parse()?);
117
118    assert_eq!(DataType::Text, "CHARACTER(20)".parse()?);
119    assert_eq!(DataType::Text, "NCHAR(55)".parse()?);
120    assert_eq!(DataType::Text, "TEXT".parse()?);
121    assert_eq!(DataType::Text, "CLOB".parse()?);
122
123    assert_eq!(DataType::Blob, "BLOB".parse()?);
124
125    assert_eq!(DataType::Float, "REAL".parse()?);
126    assert_eq!(DataType::Float, "FLOAT".parse()?);
127    assert_eq!(DataType::Float, "DOUBLE PRECISION".parse()?);
128
129    assert_eq!(DataType::Bool, "BOOLEAN".parse()?);
130    assert_eq!(DataType::Bool, "BOOL".parse()?);
131
132    assert_eq!(DataType::Datetime, "DATETIME".parse()?);
133    assert_eq!(DataType::Time, "TIME".parse()?);
134    assert_eq!(DataType::Date, "DATE".parse()?);
135
136    Ok(())
137}