1use crate::{FromQueryResult, QueryResult, error::*};
2use serde_json::Map;
3pub use serde_json::Value as JsonValue;
4
5impl FromQueryResult for JsonValue {
6 #[allow(unused_variables, unused_mut)]
7 fn from_query_result(res: &QueryResult, pre: &str) -> Result<Self, DbErr> {
8 let mut map = Map::new();
9 #[allow(unused_macros)]
10 macro_rules! try_get_type {
11 ( $type: ty, $col: ident ) => {
12 if let Ok(v) = res.try_get::<Option<$type>>(pre, &$col) {
13 map.insert($col.to_owned(), json!(v));
14 continue;
15 }
16 };
17 }
18 match &res.row {
19 #[cfg(feature = "sqlx-mysql")]
20 crate::QueryResultRow::SqlxMySql(row) => {
21 use serde_json::json;
22 use sqlx::{Column, MySql, Row, Type, TypeInfo};
23 for column in row.columns() {
24 let col = if !column.name().starts_with(pre) {
25 continue;
26 } else {
27 column.name().replacen(pre, "", 1)
28 };
29 let col_type = column.type_info();
30 macro_rules! match_mysql_type {
31 ( $type: ty ) => {
32 if <$type as Type<MySql>>::type_info().eq(col_type) {
33 try_get_type!($type, col)
34 }
35 };
36 }
37 macro_rules! match_mysql_compatible_type {
38 ( $type: ty ) => {
39 if <$type as Type<MySql>>::compatible(col_type) {
40 try_get_type!($type, col)
41 }
42 };
43 }
44 match_mysql_type!(bool);
45 match_mysql_type!(i8);
46 match_mysql_type!(i16);
47 match_mysql_type!(i32);
48 match_mysql_type!(i64);
49 match_mysql_type!(u8);
50 match_mysql_type!(u16);
51 match_mysql_type!(u32);
52 match_mysql_type!(u64);
53 match_mysql_type!(f32);
54 match_mysql_type!(f64);
55 #[cfg(feature = "with-json")]
56 if col_type.name().eq_ignore_ascii_case("JSON")
58 || (col_type.name().eq_ignore_ascii_case("BLOB")
59 && <String as Type<MySql>>::compatible(col_type))
60 {
61 try_get_type!(serde_json::Value, col);
62 }
63 match_mysql_type!(String);
64 #[cfg(feature = "with-chrono")]
65 match_mysql_type!(chrono::NaiveDate);
66 #[cfg(feature = "with-chrono")]
67 match_mysql_type!(chrono::NaiveTime);
68 #[cfg(feature = "with-chrono")]
69 match_mysql_type!(chrono::NaiveDateTime);
70 #[cfg(feature = "with-chrono")]
71 match_mysql_type!(chrono::DateTime<chrono::Utc>);
72 #[cfg(feature = "with-time")]
73 match_mysql_type!(time::Date);
74 #[cfg(feature = "with-time")]
75 match_mysql_type!(time::Time);
76 #[cfg(feature = "with-time")]
77 match_mysql_type!(time::PrimitiveDateTime);
78 #[cfg(feature = "with-time")]
79 match_mysql_type!(time::OffsetDateTime);
80 #[cfg(feature = "with-rust_decimal")]
81 match_mysql_type!(rust_decimal::Decimal);
82 match_mysql_compatible_type!(String);
83 #[cfg(feature = "with-uuid")]
84 try_get_type!(uuid::Uuid, col);
85 try_get_type!(Vec<u8>, col);
86 }
87 Ok(JsonValue::Object(map))
88 }
89 #[cfg(feature = "sqlx-postgres")]
90 crate::QueryResultRow::SqlxPostgres(row) => {
91 use serde_json::json;
92 use sqlx::{Column, Postgres, Row, Type, postgres::types::Oid};
93
94 for column in row.columns() {
95 let col = if !column.name().starts_with(pre) {
96 continue;
97 } else {
98 column.name().replacen(pre, "", 1)
99 };
100 let col_type = column.type_info();
101
102 macro_rules! match_postgres_type {
103 ( $type: ty ) => {
104 match col_type.kind() {
105 #[cfg(feature = "postgres-array")]
106 sqlx::postgres::PgTypeKind::Array(_) => {
107 if <Vec<$type> as Type<Postgres>>::type_info().eq(col_type) {
108 try_get_type!(Vec<$type>, col);
109 }
110 }
111 _ => {
112 if <$type as Type<Postgres>>::type_info().eq(col_type) {
113 try_get_type!($type, col);
114 }
115 }
116 }
117 };
118 }
119
120 match_postgres_type!(bool);
121 match_postgres_type!(i8);
122 match_postgres_type!(i16);
123 match_postgres_type!(i32);
124 match_postgres_type!(i64);
125 if <Oid as Type<Postgres>>::type_info().eq(col_type) {
130 try_get_type!(u32, col)
131 }
132 match_postgres_type!(f32);
134 match_postgres_type!(f64);
135 #[cfg(feature = "with-chrono")]
136 match_postgres_type!(chrono::NaiveDate);
137 #[cfg(feature = "with-chrono")]
138 match_postgres_type!(chrono::NaiveTime);
139 #[cfg(feature = "with-chrono")]
140 match_postgres_type!(chrono::NaiveDateTime);
141 #[cfg(feature = "with-chrono")]
142 match_postgres_type!(chrono::DateTime<chrono::FixedOffset>);
143 #[cfg(feature = "with-time")]
144 match_postgres_type!(time::Date);
145 #[cfg(feature = "with-time")]
146 match_postgres_type!(time::Time);
147 #[cfg(feature = "with-time")]
148 match_postgres_type!(time::PrimitiveDateTime);
149 #[cfg(feature = "with-time")]
150 match_postgres_type!(time::OffsetDateTime);
151 #[cfg(feature = "with-rust_decimal")]
152 match_postgres_type!(rust_decimal::Decimal);
153 #[cfg(feature = "with-json")]
154 try_get_type!(serde_json::Value, col);
155 #[cfg(all(feature = "with-json", feature = "postgres-array"))]
156 try_get_type!(Vec<serde_json::Value>, col);
157 try_get_type!(String, col);
158 #[cfg(feature = "postgres-array")]
159 try_get_type!(Vec<String>, col);
160 #[cfg(feature = "postgres-vector")]
161 try_get_type!(pgvector::Vector, col);
162 #[cfg(feature = "with-uuid")]
163 try_get_type!(uuid::Uuid, col);
164 #[cfg(all(feature = "with-uuid", feature = "postgres-array"))]
165 try_get_type!(Vec<uuid::Uuid>, col);
166 #[cfg(feature = "with-ipnetwork")]
167 try_get_type!(ipnetwork::IpNetwork, col);
168 #[cfg(all(feature = "with-ipnetwork", feature = "postgres-array"))]
169 try_get_type!(Vec<ipnetwork::IpNetwork>, col);
170 try_get_type!(Vec<u8>, col);
171 }
172 Ok(JsonValue::Object(map))
173 }
174 #[cfg(feature = "sqlx-sqlite")]
175 crate::QueryResultRow::SqlxSqlite(row) => {
176 use serde_json::json;
177 use sqlx::{Column, Row, Sqlite, Type};
178 for column in row.columns() {
179 let col = if !column.name().starts_with(pre) {
180 continue;
181 } else {
182 column.name().replacen(pre, "", 1)
183 };
184 let col_type = column.type_info();
185 macro_rules! match_sqlite_type {
186 ( $type: ty ) => {
187 if <$type as Type<Sqlite>>::type_info().eq(col_type) {
188 try_get_type!($type, col)
189 }
190 };
191 }
192 match_sqlite_type!(bool);
193 match_sqlite_type!(i8);
194 match_sqlite_type!(i16);
195 match_sqlite_type!(i32);
196 match_sqlite_type!(i64);
197 match_sqlite_type!(u8);
198 match_sqlite_type!(u16);
199 match_sqlite_type!(u32);
200 match_sqlite_type!(f32);
202 match_sqlite_type!(f64);
203 #[cfg(feature = "with-chrono")]
204 match_sqlite_type!(chrono::NaiveDate);
205 #[cfg(feature = "with-chrono")]
206 match_sqlite_type!(chrono::NaiveTime);
207 #[cfg(feature = "with-chrono")]
208 match_sqlite_type!(chrono::NaiveDateTime);
209 #[cfg(feature = "with-time")]
210 match_sqlite_type!(time::Date);
211 #[cfg(feature = "with-time")]
212 match_sqlite_type!(time::Time);
213 #[cfg(feature = "with-time")]
214 match_sqlite_type!(time::PrimitiveDateTime);
215 #[cfg(feature = "with-time")]
216 match_sqlite_type!(time::OffsetDateTime);
217 try_get_type!(String, col);
218 #[cfg(feature = "with-uuid")]
219 try_get_type!(uuid::Uuid, col);
220 try_get_type!(Vec<u8>, col);
221 }
222 Ok(JsonValue::Object(map))
223 }
224 #[cfg(feature = "rusqlite")]
225 crate::QueryResultRow::Rusqlite(row) => {
226 use crate::driver::rusqlite::RusqliteOwnedValue;
227 use serde_json::json;
228
229 for (i, column) in row.columns.iter().enumerate() {
230 let column = if !column.starts_with(pre) {
231 continue;
232 } else {
233 column.replacen(pre, "", 1)
234 };
235 map.insert(
236 column,
237 match &row.values[i] {
238 RusqliteOwnedValue::Integer(v) => json!(v),
239 RusqliteOwnedValue::Real(v) => json!(v),
240 RusqliteOwnedValue::Text(v) => json!(v),
241 RusqliteOwnedValue::Blob(v) => json!(v),
242 RusqliteOwnedValue::Null => json!(null),
243 },
244 );
245 }
246 Ok(JsonValue::Object(map))
247 }
248 #[cfg(feature = "mock")]
249 crate::QueryResultRow::Mock(row) => {
250 for (column, value) in row.clone().into_column_value_tuples() {
251 let col = if !column.starts_with(pre) {
252 continue;
253 } else {
254 column.replacen(pre, "", 1)
255 };
256 map.insert(col, sea_query::sea_value_to_json_value(&value));
257 }
258 Ok(JsonValue::Object(map))
259 }
260 #[cfg(feature = "proxy")]
261 crate::QueryResultRow::Proxy(row) => {
262 for (column, value) in row.clone().into_column_value_tuples() {
263 let col = if !column.starts_with(pre) {
264 continue;
265 } else {
266 column.replacen(pre, "", 1)
267 };
268 map.insert(col, sea_query::sea_value_to_json_value(&value));
269 }
270 Ok(JsonValue::Object(map))
271 }
272 #[allow(unreachable_patterns)]
273 _ => unreachable!(),
274 }
275 }
276}
277
278#[cfg(test)]
279#[cfg(feature = "mock")]
280mod tests {
281 use crate::tests_cfg::cake;
282 use crate::{DbBackend, DbErr, MockDatabase, entity::*};
283 use sea_query::Value;
284
285 #[test]
286 fn to_json_1() -> Result<(), DbErr> {
287 let db = MockDatabase::new(DbBackend::Postgres)
288 .append_query_results([[maplit::btreemap! {
289 "id" => Into::<Value>::into(128), "name" => Into::<Value>::into("apple")
290 }]])
291 .into_connection();
292
293 assert_eq!(
294 cake::Entity::find().into_json().one(&db).unwrap(),
295 Some(serde_json::json!({
296 "id": 128,
297 "name": "apple"
298 }))
299 );
300
301 Ok(())
302 }
303}