1
1
mod sql;
2
2
mod sql_pseudofunctions;
3
+ mod sql_to_json;
3
4
4
5
use anyhow:: { anyhow, Context } ;
5
6
use futures_util:: stream:: Stream ;
6
7
use futures_util:: StreamExt ;
7
- use serde_json:: { Map , Value } ;
8
+ use serde_json:: Value ;
8
9
use std:: borrow:: Cow ;
9
10
use std:: fmt:: { Display , Formatter } ;
10
11
use std:: path:: Path ;
11
12
use std:: time:: Duration ;
12
13
13
14
use crate :: app_config:: AppConfig ;
14
15
pub use crate :: file_cache:: FileCache ;
15
- use crate :: utils :: add_value_to_map ;
16
+
16
17
use crate :: webserver:: database:: sql_pseudofunctions:: extract_req_param;
17
18
use crate :: webserver:: http:: RequestInfo ;
18
19
use crate :: MIGRATIONS_DIR ;
@@ -24,10 +25,7 @@ use sqlx::any::{
24
25
use sqlx:: migrate:: Migrator ;
25
26
use sqlx:: pool:: { PoolConnection , PoolOptions } ;
26
27
use sqlx:: query:: Query ;
27
- use sqlx:: {
28
- Any , AnyConnection , AnyPool , Arguments , Column , ConnectOptions , Decode , Either , Executor , Row ,
29
- Statement , TypeInfo , ValueRef ,
30
- } ;
28
+ use sqlx:: { Any , AnyConnection , AnyPool , Arguments , ConnectOptions , Either , Executor , Statement } ;
31
29
32
30
use self :: sql:: ParsedSQLStatement ;
33
31
@@ -160,7 +158,7 @@ async fn take_connection<'a, 'b>(
160
158
#[ inline]
161
159
fn parse_single_sql_result ( res : sqlx:: Result < Either < AnyQueryResult , AnyRow > > ) -> DbItem {
162
160
match res {
163
- Ok ( Either :: Right ( r) ) => DbItem :: Row ( row_to_json ( & r) ) ,
161
+ Ok ( Either :: Right ( r) ) => DbItem :: Row ( sql_to_json :: row_to_json ( & r) ) ,
164
162
Ok ( Either :: Left ( res) ) => {
165
163
log:: debug!( "Finished query with result: {:?}" , res) ;
166
164
DbItem :: FinishedQuery
@@ -202,105 +200,6 @@ pub enum DbItem {
202
200
Error ( anyhow:: Error ) ,
203
201
}
204
202
205
- macro_rules! try_decode_with {
206
- ( $raw_value: expr, [ $ty0: ty] , $fn: expr) => {
207
- <$ty0 as Decode <sqlx:: any:: Any >>:: decode( $raw_value) . map( $fn)
208
- } ;
209
- ( $raw_value: expr, [ $ty0: ty, $( $ty: ty) ,+] , $fn: expr) => {
210
- match try_decode_with!( $raw_value, [ $ty0] , $fn) {
211
- Ok ( value) => Ok ( value) ,
212
- Err ( _) => try_decode_with!( $raw_value, [ $( $ty) ,+] , $fn) ,
213
- }
214
- } ;
215
- }
216
-
217
- fn row_to_json ( row : & AnyRow ) -> Value {
218
- use Value :: Object ;
219
-
220
- let columns = row. columns ( ) ;
221
- let mut map = Map :: new ( ) ;
222
- for col in columns {
223
- let key = col. name ( ) . to_string ( ) ;
224
- let value: Value = sql_to_json ( row, col) ;
225
- map = add_value_to_map ( map, ( key, value) ) ;
226
- }
227
- Object ( map)
228
- }
229
-
230
- fn sql_to_json ( row : & AnyRow , col : & sqlx:: any:: AnyColumn ) -> Value {
231
- let raw_value_result = row. try_get_raw ( col. ordinal ( ) ) ;
232
- match raw_value_result {
233
- Ok ( raw_value) if !raw_value. is_null ( ) => {
234
- let mut raw_value = Some ( raw_value) ;
235
- log:: trace!( "Decoding a value of type {:?}" , col. type_info( ) . name( ) ) ;
236
- let decoded = sql_nonnull_to_json ( || {
237
- raw_value
238
- . take ( )
239
- . unwrap_or_else ( || row. try_get_raw ( col. ordinal ( ) ) . unwrap ( ) )
240
- } ) ;
241
- log:: trace!( "Decoded value: {:?}" , decoded) ;
242
- decoded
243
- }
244
- Ok ( _null) => Value :: Null ,
245
- Err ( e) => {
246
- log:: warn!( "Unable to extract value from row: {:?}" , e) ;
247
- Value :: Null
248
- }
249
- }
250
- }
251
-
252
- fn sql_nonnull_to_json < ' r > ( mut get_ref : impl FnMut ( ) -> sqlx:: any:: AnyValueRef < ' r > ) -> Value {
253
- let raw_value = get_ref ( ) ;
254
- match raw_value. type_info ( ) . name ( ) {
255
- "REAL" | "FLOAT" | "NUMERIC" | "DECIMAL" | "FLOAT4" | "FLOAT8" | "DOUBLE" => {
256
- <f64 as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
257
- . unwrap_or ( f64:: NAN )
258
- . into ( )
259
- }
260
- "INT8" | "BIGINT" | "INTEGER" => <i64 as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
261
- . unwrap_or_default ( )
262
- . into ( ) ,
263
- "INT" | "INT4" => <i32 as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
264
- . unwrap_or_default ( )
265
- . into ( ) ,
266
- "INT2" | "SMALLINT" => <i16 as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
267
- . unwrap_or_default ( )
268
- . into ( ) ,
269
- "BOOL" | "BOOLEAN" => <bool as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
270
- . unwrap_or_default ( )
271
- . into ( ) ,
272
- "DATE" => <chrono:: NaiveDate as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
273
- . as_ref ( )
274
- . map_or_else ( std:: string:: ToString :: to_string, ToString :: to_string)
275
- . into ( ) ,
276
- "TIME" => <chrono:: NaiveTime as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
277
- . as_ref ( )
278
- . map_or_else ( ToString :: to_string, ToString :: to_string)
279
- . into ( ) ,
280
- "DATETIME" | "DATETIME2" | "DATETIMEOFFSET" | "TIMESTAMP" | "TIMESTAMPTZ" => {
281
- try_decode_with ! (
282
- get_ref( ) ,
283
- [ chrono:: NaiveDateTime , chrono:: DateTime <chrono:: Utc >] ,
284
- |v| dbg!( v) . to_string( )
285
- )
286
- . unwrap_or_else ( |e| format ! ( "Unable to decode date: {e:?}" ) )
287
- . into ( )
288
- }
289
- "JSON" | "JSON[]" | "JSONB" | "JSONB[]" => {
290
- <& [ u8 ] as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
291
- . and_then ( |rv| {
292
- serde_json:: from_slice :: < Value > ( rv)
293
- . map_err ( |e| Box :: new ( e) as Box < dyn std:: error:: Error + Sync + Send > )
294
- } )
295
- . unwrap_or_default ( )
296
- }
297
- // Deserialize as a string by default
298
- _ => <String as Decode < sqlx:: any:: Any > >:: decode ( raw_value)
299
- . unwrap_or_default ( )
300
- . into ( ) ,
301
- }
302
- }
303
-
304
203
impl Database {
305
204
pub async fn init ( config : & AppConfig ) -> anyhow:: Result < Self > {
306
205
let database_url = & config. database_url ;
@@ -380,30 +279,3 @@ impl Display for PreparedStatement {
380
279
write ! ( f, "{}" , self . statement. sql( ) )
381
280
}
382
281
}
383
-
384
- #[ actix_web:: test]
385
- async fn test_row_to_json ( ) -> anyhow:: Result < ( ) > {
386
- use sqlx:: Connection ;
387
- let mut c = sqlx:: AnyConnection :: connect ( "sqlite://:memory:" ) . await ?;
388
- let row = sqlx:: query (
389
- "SELECT \
390
- 123.456 as one_value, \
391
- 1 as two_values, \
392
- 2 as two_values, \
393
- 'x' as three_values, \
394
- 'y' as three_values, \
395
- 'z' as three_values \
396
- ",
397
- )
398
- . fetch_one ( & mut c)
399
- . await ?;
400
- assert_eq ! (
401
- row_to_json( & row) ,
402
- serde_json:: json!( {
403
- "one_value" : 123.456 ,
404
- "two_values" : [ 1 , 2 ] ,
405
- "three_values" : [ "x" , "y" , "z" ] ,
406
- } )
407
- ) ;
408
- Ok ( ( ) )
409
- }
0 commit comments