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