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 = "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!(u64); // unsupported by SQLx Sqlite
195                    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 = "mock")]
219            crate::QueryResultRow::Mock(row) => {
220                for (column, value) in row.clone().into_column_value_tuples() {
221                    let col = if !column.starts_with(pre) {
222                        continue;
223                    } else {
224                        column.replacen(pre, "", 1)
225                    };
226                    map.insert(col, sea_query::sea_value_to_json_value(&value));
227                }
228                Ok(JsonValue::Object(map))
229            }
230            #[cfg(feature = "proxy")]
231            crate::QueryResultRow::Proxy(row) => {
232                for (column, value) in row.clone().into_column_value_tuples() {
233                    let col = if !column.starts_with(pre) {
234                        continue;
235                    } else {
236                        column.replacen(pre, "", 1)
237                    };
238                    map.insert(col, sea_query::sea_value_to_json_value(&value));
239                }
240                Ok(JsonValue::Object(map))
241            }
242            #[allow(unreachable_patterns)]
243            _ => unreachable!(),
244        }
245    }
246}
247
248#[cfg(test)]
249#[cfg(feature = "mock")]
250mod tests {
251    use crate::tests_cfg::cake;
252    use crate::{entity::*, DbBackend, DbErr, MockDatabase};
253    use sea_query::Value;
254
255    #[smol_potat::test]
256    async fn to_json_1() -> Result<(), DbErr> {
257        let db = MockDatabase::new(DbBackend::Postgres)
258            .append_query_results([[maplit::btreemap! {
259                "id" => Into::<Value>::into(128), "name" => Into::<Value>::into("apple")
260            }]])
261            .into_connection();
262
263        assert_eq!(
264            cake::Entity::find().into_json().one(&db).await.unwrap(),
265            Some(serde_json::json!({
266                "id": 128,
267                "name": "apple"
268            }))
269        );
270
271        Ok(())
272    }
273}