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