11use crate :: webserver:: ErrorWithStatus ;
22use crate :: webserver:: database:: SupportedDatabase ;
33use crate :: webserver:: { Database , StatusCodeResultExt , make_placeholder} ;
4+ use crate :: webserver:: database:: { DbParam , driver:: DbValue } ;
45use crate :: { AppState , TEMPLATES_DIR } ;
56use anyhow:: Context ;
67use chrono:: { DateTime , Utc } ;
7- use sqlx:: any:: { AnyStatement , AnyTypeInfo } ;
8- use sqlx:: postgres:: types:: PgTimeTz ;
9- use sqlx:: { Executor , Postgres , Statement , Type } ;
108use std:: fmt:: Write ;
119use std:: io:: ErrorKind ;
1210use std:: path:: { Component , Path , PathBuf } ;
@@ -241,9 +239,9 @@ async fn file_modified_since_local(path: &Path, since: DateTime<Utc>) -> tokio::
241239}
242240
243241pub struct DbFsQueries {
244- was_modified : AnyStatement < ' static > ,
245- read_file : AnyStatement < ' static > ,
246- exists : AnyStatement < ' static > ,
242+ was_modified : String ,
243+ read_file : String ,
244+ exists : String ,
247245}
248246
249247impl DbFsQueries {
@@ -277,44 +275,40 @@ impl DbFsQueries {
277275
278276 async fn check_table_available ( db : & Database ) -> anyhow:: Result < ( ) > {
279277 db. connection
280- . execute ( "SELECT 1 FROM sqlpage_files WHERE 1 = 0" )
278+ . acquire ( )
279+ . await
280+ . context ( "Unable to acquire database connection" ) ?
281+ . execute_command ( "SELECT 1 FROM sqlpage_files WHERE 1 = 0" , & [ ] )
281282 . await
282- . map ( |_| ( ) )
283283 . context ( "Unable to access sqlpage_files" ) ?;
284284 Ok ( ( ) )
285285 }
286286
287- async fn make_was_modified_query ( db : & Database ) -> anyhow:: Result < AnyStatement < ' static > > {
287+ async fn make_was_modified_query ( db : & Database ) -> anyhow:: Result < String > {
288288 let was_modified_query = format ! (
289289 "SELECT 1 from sqlpage_files WHERE last_modified >= {} AND path = {}" ,
290290 make_placeholder( db. info. kind, 1 ) ,
291291 make_placeholder( db. info. kind, 2 )
292292 ) ;
293- let param_types: & [ AnyTypeInfo ; 2 ] = & [
294- PgTimeTz :: type_info ( ) . into ( ) ,
295- <str as Type < Postgres > >:: type_info ( ) . into ( ) ,
296- ] ;
297293 log:: debug!( "Preparing the database filesystem was_modified_query: {was_modified_query}" ) ;
298- db . prepare_with ( & was_modified_query, param_types ) . await
294+ Ok ( was_modified_query)
299295 }
300296
301- async fn make_read_file_query ( db : & Database ) -> anyhow:: Result < AnyStatement < ' static > > {
297+ async fn make_read_file_query ( db : & Database ) -> anyhow:: Result < String > {
302298 let read_file_query = format ! (
303299 "SELECT contents from sqlpage_files WHERE path = {}" ,
304300 make_placeholder( db. info. kind, 1 ) ,
305301 ) ;
306- let param_types: & [ AnyTypeInfo ; 1 ] = & [ <str as Type < Postgres > >:: type_info ( ) . into ( ) ] ;
307302 log:: debug!( "Preparing the database filesystem read_file_query: {read_file_query}" ) ;
308- db . prepare_with ( & read_file_query, param_types ) . await
303+ Ok ( read_file_query)
309304 }
310305
311- async fn make_exists_query ( db : & Database ) -> anyhow:: Result < AnyStatement < ' static > > {
306+ async fn make_exists_query ( db : & Database ) -> anyhow:: Result < String > {
312307 let exists_query = format ! (
313308 "SELECT 1 from sqlpage_files WHERE path = {}" ,
314309 make_placeholder( db. info. kind, 1 ) ,
315310 ) ;
316- let param_types: & [ AnyTypeInfo ; 1 ] = & [ <str as Type < Postgres > >:: type_info ( ) . into ( ) ] ;
317- db. prepare_with ( & exists_query, param_types) . await
311+ Ok ( exists_query)
318312 }
319313
320314 async fn file_modified_since_in_db (
@@ -323,22 +317,22 @@ impl DbFsQueries {
323317 path : & Path ,
324318 since : DateTime < Utc > ,
325319 ) -> anyhow:: Result < bool > {
326- let query = self
327- . was_modified
328- . query_as :: < ( i32 , ) > ( )
329- . bind ( since)
330- . bind ( path. display ( ) . to_string ( ) ) ;
320+ let params = [
321+ DbParam :: Timestamp ( since) ,
322+ DbParam :: Text ( path. display ( ) . to_string ( ) ) ,
323+ ] ;
331324 log:: trace!(
332325 "Checking if file {} was modified since {} by executing query: \n \
333326 {}\n \
334327 with parameters: {:?}",
335328 path. display( ) ,
336329 since,
337- self . was_modified. sql ( ) ,
330+ self . was_modified,
338331 ( since, path)
339332 ) ;
340- let was_modified_i32 = query
341- . fetch_optional ( & app_state. db . connection )
333+ let mut conn = app_state. db . connection . acquire ( ) . await ?;
334+ let was_modified_i32 = conn
335+ . fetch_optional ( & self . was_modified , & params)
342336 . await
343337 . with_context ( || {
344338 format ! (
@@ -350,20 +344,25 @@ impl DbFsQueries {
350344 "DB File {} was modified result: {was_modified_i32:?}" ,
351345 path. display( )
352346 ) ;
353- Ok ( was_modified_i32 == Some ( ( 1 , ) ) )
347+ Ok ( was_modified_i32. is_some ( ) )
354348 }
355349
356350 async fn read_file ( & self , app_state : & AppState , path : & Path ) -> anyhow:: Result < Vec < u8 > > {
357351 log:: debug!( "Reading file {} from the database" , path. display( ) ) ;
358- self . read_file
359- . query_as :: < ( Vec < u8 > , ) > ( )
360- . bind ( path. display ( ) . to_string ( ) )
361- . fetch_optional ( & app_state. db . connection )
352+ let mut conn = app_state. db . connection . acquire ( ) . await ?;
353+ conn. fetch_optional (
354+ & self . read_file ,
355+ & [ DbParam :: Text ( path. display ( ) . to_string ( ) ) ] ,
356+ )
362357 . await
363358 . map_err ( anyhow:: Error :: from)
364- . and_then ( |modified| {
365- if let Some ( ( modified, ) ) = modified {
366- Ok ( modified)
359+ . and_then ( |row| {
360+ if let Some ( row) = row {
361+ match row. values . first ( ) {
362+ Some ( DbValue :: Bytes ( bytes) ) => Ok ( bytes. clone ( ) ) ,
363+ Some ( DbValue :: Text ( text) ) => Ok ( text. as_bytes ( ) . to_vec ( ) ) ,
364+ _ => Ok ( Vec :: new ( ) ) ,
365+ }
367366 } else {
368367 Err ( ErrorWithStatus {
369368 status : actix_web:: http:: StatusCode :: NOT_FOUND ,
@@ -375,19 +374,17 @@ impl DbFsQueries {
375374 }
376375
377376 async fn file_exists ( & self , app_state : & AppState , path : & Path ) -> anyhow:: Result < bool > {
378- let query = self
379- . exists
380- . query_as :: < ( i32 , ) > ( )
381- . bind ( path. display ( ) . to_string ( ) ) ;
377+ let params = [ DbParam :: Text ( path. display ( ) . to_string ( ) ) ] ;
382378 log:: trace!(
383379 "Checking if file {} exists by executing query: \n \
384380 {}\n \
385381 with parameters: {:?}",
386382 path. display( ) ,
387- self . exists. sql ( ) ,
383+ self . exists,
388384 ( path, )
389385 ) ;
390- let result = query. fetch_optional ( & app_state. db . connection ) . await ;
386+ let mut conn = app_state. db . connection . acquire ( ) . await ?;
387+ let result = conn. fetch_optional ( & self . exists , & params) . await ;
391388 log:: debug!( "DB File exists result: {result:?}" ) ;
392389 result. map ( |result| result. is_some ( ) ) . with_context ( || {
393390 format ! (
@@ -401,7 +398,6 @@ impl DbFsQueries {
401398#[ actix_web:: test]
402399async fn test_sql_file_read_utf8 ( ) -> anyhow:: Result < ( ) > {
403400 use crate :: app_config;
404- use sqlx:: Executor ;
405401 let config = app_config:: tests:: test_config ( ) ;
406402 let state = AppState :: init ( & config) . await ?;
407403
@@ -417,20 +413,24 @@ async fn test_sql_file_read_utf8() -> anyhow::Result<()> {
417413 let create_table_sql = DbFsQueries :: get_create_table_sql ( state. db . info . database_type ) ;
418414 let db = & state. db ;
419415 let conn = & db. connection ;
420- conn. execute ( "DROP TABLE IF EXISTS sqlpage_files" ) . await ?;
416+ let mut conn = db. connection . acquire ( ) . await ?;
417+ conn. execute_command ( "DROP TABLE IF EXISTS sqlpage_files" , & [ ] ) . await ?;
421418 log:: debug!( "Creating table sqlpage_files: {create_table_sql}" ) ;
422- conn. execute ( create_table_sql) . await ?;
419+ conn. execute_command ( create_table_sql, & [ ] ) . await ?;
423420
424421 let dbms = db. info . kind ;
425422 let insert_sql = format ! (
426423 "INSERT INTO sqlpage_files(path, contents) VALUES ({}, {})" ,
427424 make_placeholder( dbms, 1 ) ,
428425 make_placeholder( dbms, 2 )
429426 ) ;
430- sqlx:: query ( & insert_sql)
431- . bind ( "unit test file.txt" )
432- . bind ( "Héllö world! 😀" . as_bytes ( ) )
433- . execute ( conn)
427+ conn. execute_command (
428+ & insert_sql,
429+ & [
430+ DbParam :: Text ( "unit test file.txt" . into ( ) ) ,
431+ DbParam :: Bytes ( "Héllö world! 😀" . as_bytes ( ) . to_vec ( ) ) ,
432+ ] ,
433+ )
434434 . await ?;
435435
436436 let fs = FileSystem :: init ( "/" , db) . await ;
0 commit comments