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