sea_orm/query/
json.rs

1use crate::{error::*, FromQueryResult, QueryResult};
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::{postgres::types::Oid, Column, Postgres, Row, Type};
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                    // match_postgres_type!(u8); // unsupported by SQLx Postgres
120                    // match_postgres_type!(u16); // unsupported by SQLx Postgres
121                    // Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
122                    // Instead, `u32` was wrapped by a `sqlx::Oid`.
123                    if <Oid as Type<Postgres>>::type_info().eq(col_type) {
124                        try_get_type!(u32, col)
125                    }
126                    // match_postgres_type!(u64); // unsupported by SQLx Postgres
127                    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 = "with-uuid")]
155                    try_get_type!(uuid::Uuid, col);
156                    #[cfg(all(feature = "with-uuid", feature = "postgres-array"))]
157                    try_get_type!(Vec<uuid::Uuid>, col);
158                    try_get_type!(Vec<u8>, col);
159                }
160                Ok(JsonValue::Object(map))
161            }
162            #[cfg(feature = "sqlx-sqlite")]
163            crate::QueryResultRow::SqlxSqlite(row) => {
164                use serde_json::json;
165                use sqlx::{Column, Row, Sqlite, Type};
166                for column in row.columns() {
167                    let col = if !column.name().starts_with(pre) {
168                        continue;
169                    } else {
170                        column.name().replacen(pre, "", 1)
171                    };
172                    let col_type = column.type_info();
173                    macro_rules! match_sqlite_type {
174                        ( $type: ty ) => {
175                            if <$type as Type<Sqlite>>::type_info().eq(col_type) {
176                                try_get_type!($type, col)
177                            }
178                        };
179                    }
180                    match_sqlite_type!(bool);
181                    match_sqlite_type!(i8);
182                    match_sqlite_type!(i16);
183                    match_sqlite_type!(i32);
184                    match_sqlite_type!(i64);
185                    match_sqlite_type!(u8);
186                    match_sqlite_type!(u16);
187                    match_sqlite_type!(u32);
188                    // match_sqlite_type!(u64); // unsupported by SQLx Sqlite
189                    match_sqlite_type!(f32);
190                    match_sqlite_type!(f64);
191                    #[cfg(feature = "with-chrono")]
192                    match_sqlite_type!(chrono::NaiveDate);
193                    #[cfg(feature = "with-chrono")]
194                    match_sqlite_type!(chrono::NaiveTime);
195                    #[cfg(feature = "with-chrono")]
196                    match_sqlite_type!(chrono::NaiveDateTime);
197                    #[cfg(feature = "with-time")]
198                    match_sqlite_type!(time::Date);
199                    #[cfg(feature = "with-time")]
200                    match_sqlite_type!(time::Time);
201                    #[cfg(feature = "with-time")]
202                    match_sqlite_type!(time::PrimitiveDateTime);
203                    #[cfg(feature = "with-time")]
204                    match_sqlite_type!(time::OffsetDateTime);
205                    try_get_type!(String, col);
206                    #[cfg(feature = "with-uuid")]
207                    try_get_type!(uuid::Uuid, col);
208                    try_get_type!(Vec<u8>, col);
209                }
210                Ok(JsonValue::Object(map))
211            }
212            #[cfg(feature = "mock")]
213            crate::QueryResultRow::Mock(row) => {
214                for (column, value) in row.clone().into_column_value_tuples() {
215                    let col = if !column.starts_with(pre) {
216                        continue;
217                    } else {
218                        column.replacen(pre, "", 1)
219                    };
220                    map.insert(col, sea_query::sea_value_to_json_value(&value));
221                }
222                Ok(JsonValue::Object(map))
223            }
224            #[cfg(feature = "proxy")]
225            crate::QueryResultRow::Proxy(row) => {
226                for (column, value) in row.clone().into_column_value_tuples() {
227                    let col = if !column.starts_with(pre) {
228                        continue;
229                    } else {
230                        column.replacen(pre, "", 1)
231                    };
232                    map.insert(col, sea_query::sea_value_to_json_value(&value));
233                }
234                Ok(JsonValue::Object(map))
235            }
236            #[allow(unreachable_patterns)]
237            _ => unreachable!(),
238        }
239    }
240}
241
242#[cfg(test)]
243#[cfg(feature = "mock")]
244mod tests {
245    use crate::tests_cfg::cake;
246    use crate::{entity::*, DbBackend, DbErr, MockDatabase};
247    use sea_query::Value;
248
249    #[smol_potat::test]
250    async fn to_json_1() -> Result<(), DbErr> {
251        let db = MockDatabase::new(DbBackend::Postgres)
252            .append_query_results([[maplit::btreemap! {
253                "id" => Into::<Value>::into(128), "name" => Into::<Value>::into("apple")
254            }]])
255            .into_connection();
256
257        assert_eq!(
258            cake::Entity::find().into_json().one(&db).await.unwrap(),
259            Some(serde_json::json!({
260                "id": 128,
261                "name": "apple"
262            }))
263        );
264
265        Ok(())
266    }
267}