mybatis_core/mysql/
sqlx_value.rs

1use rbson::{to_bson, Binary, Bson};
2use sqlx_core::column::Column;
3use sqlx_core::decode::Decode;
4use sqlx_core::error::BoxDynError;
5use sqlx_core::mysql::{MySql, MySqlRow, MySqlValue, MySqlValueRef};
6use sqlx_core::row::Row;
7use sqlx_core::type_info::TypeInfo;
8use sqlx_core::types::{BigDecimal, Json};
9use sqlx_core::value::ValueRef;
10
11use crate::convert::{JsonCodec, RefJsonCodec, ResultCodec};
12use chrono::{DateTime, NaiveDate, Utc};
13
14use crate::db::db_adapter::DataDecoder;
15use crate::to_bson_macro;
16use rbson::bson;
17use rbson::spec::BinarySubtype;
18
19impl<'r> JsonCodec for sqlx_core::mysql::MySqlValueRef<'r> {
20    fn try_to_bson(self) -> crate::Result<Bson> {
21        match self.type_info().name() {
22            "NULL" => {
23                return Ok(Bson::Null);
24            }
25            "DECIMAL" => {
26                let r: Option<String> = Decode::<'_, MySql>::decode(self)?;
27                if let Some(date) = r {
28                    return Ok(Bson::String(date));
29                }
30                return Ok(Bson::Null);
31            }
32            "BIGINT UNSIGNED" => {
33                let r: Option<u64> = Decode::<'_, MySql>::decode(self)?;
34                if let Some(r) = r {
35                    return Ok(bson!(r));
36                }
37                return Ok(Bson::Null);
38            }
39            "BIGINT" => {
40                let r: Option<i64> = Decode::<'_, MySql>::decode(self)?;
41                return Ok(to_bson_macro!(r));
42            }
43            "INT UNSIGNED" | "MEDIUMINT UNSIGNED" => {
44                let r: Option<u32> = Decode::<'_, MySql>::decode(self)?;
45                return Ok(to_bson_macro!(r));
46            }
47            "INT" | "MEDIUMINT" => {
48                let r: Option<i32> = Decode::<'_, MySql>::decode(self)?;
49                return Ok(to_bson_macro!(r));
50            }
51            "SMALLINT" => {
52                let r: Option<i16> = Decode::<'_, MySql>::decode(self)?;
53                if let Some(r) = r {
54                    return Ok(bson!(r as i32));
55                }
56                return Ok(Bson::Null);
57            }
58            "SMALLINT UNSIGNED" => {
59                let r: Option<u16> = Decode::<'_, MySql>::decode(self)?;
60                if let Some(r) = r {
61                    return Ok(bson!(r as u32));
62                }
63                return Ok(Bson::Null);
64            }
65            "TINYINT UNSIGNED" => {
66                let r: Option<u8> = Decode::<'_, MySql>::decode(self)?;
67                if let Some(r) = r {
68                    return Ok(bson!(r as u32));
69                }
70                return Ok(Bson::Null);
71            }
72            "TINYINT" => {
73                let r: Option<i8> = Decode::<'_, MySql>::decode(self)?;
74                if let Some(r) = r {
75                    return Ok(bson!(r as i32));
76                }
77                return Ok(Bson::Null);
78            }
79            "FLOAT" => {
80                let r: Option<f32> = Decode::<'_, MySql>::decode(self)?;
81                return Ok(to_bson_macro!(r));
82            }
83            "DOUBLE" => {
84                let r: Option<f64> = Decode::<'_, MySql>::decode(self)?;
85                return Ok(to_bson_macro!(r));
86            }
87            "BINARY" | "VARBINARY" | "CHAR" | "VARCHAR" | "TEXT" | "ENUM" => {
88                let r: Option<String> = Decode::<'_, MySql>::decode(self)?;
89                return Ok(to_bson_macro!(r));
90            }
91            "BLOB" | "TINYBLOB" | "MEDIUMBLOB" | "LONGBLOB" | "TINYTEXT" | "MEDIUMTEXT"
92            | "LONGTEXT" => {
93                let r: Option<Vec<u8>> = Decode::<'_, MySql>::decode(self)?;
94                if let Some(r) = r {
95                    return Ok(Bson::Binary(rbson::Binary {
96                        subtype: BinarySubtype::Generic,
97                        bytes: r,
98                    }));
99                }
100                return Ok(Bson::Null);
101            }
102            "BIT" => {
103                let r: Option<u8> = Decode::<'_, MySql>::decode(self)?;
104                if let Some(r) = r {
105                    return Ok(bson!(r as i32));
106                }
107                return Ok(Bson::Null);
108            }
109            "BOOLEAN" => {
110                let r: Option<u8> = Decode::<'_, MySql>::decode(self)?;
111                if let Some(r) = r {
112                    let mut b = false;
113                    if r == 1 {
114                        b = true;
115                    }
116                    return Ok(bson!(b));
117                }
118                return Ok(Bson::Null);
119            }
120            "DATE" => {
121                let r: Option<chrono::NaiveDate> = Decode::<'_, MySql>::decode(self)?;
122                return Ok(to_bson(&r).unwrap_or_default());
123            }
124            "TIME" | "YEAR" => {
125                let r: Option<chrono::NaiveTime> = Decode::<'_, MySql>::decode(self)?;
126                return Ok(to_bson(&r).unwrap_or_default());
127            }
128            "DATETIME" => {
129                let r: Option<chrono::NaiveDateTime> = Decode::<'_, MySql>::decode(self)?;
130                if let Some(dt) = r {
131                    return Ok(Bson::String(dt.format("%Y-%m-%dT%H:%M:%S").to_string()));
132                }
133                return Ok(Bson::Null);
134            }
135            "TIMESTAMP" => {
136                let r: Option<chrono::NaiveDateTime> = Decode::<'_, MySql>::decode(self)?;
137                if let Some(dt) = r {
138                    return Ok(Bson::String(dt.format("%Y-%m-%dT%H:%M:%S").to_string()));
139                }
140                return Ok(Bson::Null);
141            }
142            "JSON" => {
143                let r: Option<Json<serde_json::Value>> = Decode::<'_, MySql>::decode(self)?;
144                if let Some(r) = r {
145                    return Ok(to_bson(&r.0).unwrap_or_default());
146                }
147                return Ok(Bson::Null);
148            }
149            _ => {
150                //TODO "GEOMETRY" support. for now you can use already supported types to decode this
151                let r: Option<Vec<u8>> = Decode::<'_, MySql>::decode(self)?;
152                if let Some(r) = r {
153                    return Ok(Bson::Binary(rbson::Binary {
154                        subtype: BinarySubtype::Generic,
155                        bytes: r,
156                    }));
157                }
158                return Ok(Bson::Null);
159            }
160        }
161    }
162}
163
164impl RefJsonCodec for Vec<MySqlRow> {
165    fn try_to_bson(&self, decoder: &dyn DataDecoder) -> crate::Result<rbson::Bson> {
166        let mut arr = Vec::with_capacity(self.len());
167        for row in self {
168            let mut m = rbson::Document::new();
169            let columns = row.columns();
170            for x in columns {
171                let key = x.name();
172                let v: MySqlValueRef = row.try_get_raw(key)?;
173                let mut bson = v.try_to_bson()?;
174                decoder.decode(key, &mut bson)?;
175                m.insert(key.to_owned(), bson);
176            }
177            arr.push(rbson::Bson::Document(m));
178        }
179        Ok(Bson::Array(arr))
180    }
181}