@@ -36,6 +36,32 @@ impl FileSystem {
3636 }
3737 }
3838
39+ pub async fn last_modified (
40+ & self ,
41+ app_state : & AppState ,
42+ path : & Path ,
43+ priviledged : bool ,
44+ ) -> anyhow:: Result < DateTime < Utc > > {
45+ let local_path = self . safe_local_path ( app_state, path, priviledged) ?;
46+ let local_result = tokio:: fs:: metadata ( & local_path)
47+ . await
48+ . and_then ( |metadata| metadata. modified ( ) )
49+ . map ( DateTime :: < Utc > :: from) ;
50+ match ( local_result, & self . db_fs_queries ) {
51+ ( Ok ( last_modified) , _) => Ok ( last_modified) ,
52+ ( Err ( e) , Some ( db_fs) ) if is_path_missing_error ( & e) => {
53+ db_fs. last_modified_in_db ( app_state, path) . await
54+ }
55+ ( Err ( e) , _) => {
56+ let status = io_error_status ( & e)
57+ . unwrap_or ( actix_web:: http:: StatusCode :: INTERNAL_SERVER_ERROR ) ;
58+ Err ( e) . with_status ( status) . with_context ( || {
59+ format ! ( "Unable to read local file metadata for {}" , path. display( ) )
60+ } )
61+ }
62+ }
63+ }
64+
3965 pub async fn modified_since (
4066 & self ,
4167 app_state : & AppState ,
@@ -258,6 +284,7 @@ pub struct DbFsQueries {
258284 was_modified : AnyStatement < ' static > ,
259285 read_file : AnyStatement < ' static > ,
260286 exists : AnyStatement < ' static > ,
287+ last_modified : AnyStatement < ' static > ,
261288}
262289
263290impl DbFsQueries {
@@ -286,6 +313,7 @@ impl DbFsQueries {
286313 was_modified : Self :: make_was_modified_query ( db) . await ?,
287314 read_file : Self :: make_read_file_query ( db) . await ?,
288315 exists : Self :: make_exists_query ( db) . await ?,
316+ last_modified : Self :: make_last_modified_query ( db) . await ?,
289317 } )
290318 }
291319
@@ -300,7 +328,7 @@ impl DbFsQueries {
300328
301329 async fn make_was_modified_query ( db : & Database ) -> anyhow:: Result < AnyStatement < ' static > > {
302330 let was_modified_query = format ! (
303- "SELECT 1 from sqlpage_files WHERE last_modified >= {} AND path = {}" ,
331+ "SELECT 1 from sqlpage_files WHERE last_modified > {} AND path = {}" ,
304332 make_placeholder( db. info. kind, 1 ) ,
305333 make_placeholder( db. info. kind, 2 )
306334 ) ;
@@ -331,6 +359,39 @@ impl DbFsQueries {
331359 db. prepare_with ( & exists_query, param_types) . await
332360 }
333361
362+ async fn make_last_modified_query ( db : & Database ) -> anyhow:: Result < AnyStatement < ' static > > {
363+ let last_modified_query = format ! (
364+ "SELECT last_modified from sqlpage_files WHERE path = {}" ,
365+ make_placeholder( db. info. kind, 1 ) ,
366+ ) ;
367+ let param_types: & [ AnyTypeInfo ; 1 ] = & [ <str as Type < Postgres > >:: type_info ( ) . into ( ) ] ;
368+ db. prepare_with ( & last_modified_query, param_types) . await
369+ }
370+
371+ async fn last_modified_in_db (
372+ & self ,
373+ app_state : & AppState ,
374+ path : & Path ,
375+ ) -> anyhow:: Result < DateTime < Utc > > {
376+ self . last_modified
377+ . query_as :: < ( DateTime < Utc > , ) > ( )
378+ . bind ( path. display ( ) . to_string ( ) )
379+ . fetch_optional ( & app_state. db . connection )
380+ . await
381+ . map_err ( anyhow:: Error :: from)
382+ . and_then ( |last_modified| {
383+ last_modified
384+ . map ( |( last_modified, ) | last_modified)
385+ . ok_or_else ( || {
386+ ErrorWithStatus {
387+ status : actix_web:: http:: StatusCode :: NOT_FOUND ,
388+ }
389+ . into ( )
390+ } )
391+ } )
392+ . with_context ( || format ! ( "Unable to get the modification time of {}" , path. display( ) ) )
393+ }
394+
334395 async fn file_modified_since_in_db (
335396 & self ,
336397 app_state : & AppState ,
@@ -475,5 +536,16 @@ async fn test_sql_file_read_utf8() -> anyhow::Result<()> {
475536 "File should not be modified since one hour in the future"
476537 ) ;
477538
539+ let last_modified = fs
540+ . last_modified ( & state, "unit test file.txt" . as_ref ( ) , false )
541+ . await ?;
542+ let was_modified = fs
543+ . modified_since ( & state, "unit test file.txt" . as_ref ( ) , last_modified, false )
544+ . await ?;
545+ assert ! (
546+ !was_modified,
547+ "A file should not be considered modified since its exact modification time"
548+ ) ;
549+
478550 Ok ( ( ) )
479551}
0 commit comments