@@ -273,20 +273,28 @@ pub fn update_library<E: Env + 'static>(
273273 ) ) if Some ( loading_auth_key) == auth_key => match result {
274274 Ok ( items) => {
275275 // send an event that the missing library is now present
276- let library_missing_effects = Effects :: msg ( Msg :: Event ( Event :: UserLibraryMissing {
276+ let pulled_events_effects = Effects :: msg ( Msg :: Event ( Event :: UserLibraryMissing {
277277 library_missing : false ,
278278 } ) )
279279 . unchanged ( ) ;
280280
281- library_missing_effects
282- . join ( Effects :: msg ( Msg :: Event ( Event :: LibraryItemsPulledFromAPI {
281+ let pulled_events_effects = pulled_events_effects . join (
282+ Effects :: msg ( Msg :: Event ( Event :: LibraryItemsPulledFromAPI {
283283 ids : ids. to_owned ( ) ,
284- } ) ) )
285- . join ( Effects :: one ( update_and_push_items_to_storage :: < E > (
286- library,
287- items. to_owned ( ) ,
288- ) ) )
289- . join ( Effects :: msg ( Msg :: Internal ( Internal :: LibraryChanged ( true ) ) ) )
284+ } ) )
285+ . unchanged ( ) ,
286+ ) ;
287+
288+ if should_update_library_with_items ( library, items) {
289+ pulled_events_effects
290+ . join ( Effects :: one ( update_and_push_items_to_storage :: < E > (
291+ library,
292+ items. to_owned ( ) ,
293+ ) ) )
294+ . join ( Effects :: msg ( Msg :: Internal ( Internal :: LibraryChanged ( true ) ) ) )
295+ } else {
296+ pulled_events_effects
297+ }
290298 }
291299 Err ( error) => Effects :: msg ( Msg :: Event ( Event :: Error {
292300 error : error. to_owned ( ) ,
@@ -300,6 +308,13 @@ pub fn update_library<E: Env + 'static>(
300308 }
301309}
302310
311+ fn should_update_library_with_items ( library : & LibraryBucket , items : & [ LibraryItem ] ) -> bool {
312+ items. iter ( ) . any ( |item| match library. items . get ( & item. id ) {
313+ Some ( current_item) => item. mtime >= current_item. mtime && item != current_item,
314+ None => true ,
315+ } )
316+ }
317+
303318fn update_and_push_items_to_storage < E : Env + ' static > (
304319 library : & mut LibraryBucket ,
305320 items : Vec < LibraryItem > ,
@@ -484,3 +499,105 @@ fn plan_sync_with_api<E: Env + 'static>(library: &LibraryBucket, auth_key: &Auth
484499 )
485500 . into ( )
486501}
502+
503+ #[ cfg( test) ]
504+ mod tests {
505+ use chrono:: { TimeZone , Utc } ;
506+
507+ use crate :: models:: ctx:: CtxStatus ;
508+ use crate :: runtime:: msg:: { Internal , Msg } ;
509+ use crate :: types:: api:: { DatastoreCommand , DatastoreRequest } ;
510+ use crate :: types:: library:: { LibraryBucket , LibraryItem } ;
511+ use crate :: types:: profile:: { Auth , AuthKey , GDPRConsent , Profile , User } ;
512+
513+ use super :: { should_update_library_with_items, update_library} ;
514+
515+ fn library_item ( id : & str ) -> LibraryItem {
516+ LibraryItem {
517+ id : id. to_owned ( ) ,
518+ r#type : "series" . to_owned ( ) ,
519+ name : "name" . to_owned ( ) ,
520+ poster : None ,
521+ poster_shape : Default :: default ( ) ,
522+ removed : false ,
523+ temp : false ,
524+ ctime : Some ( Utc . with_ymd_and_hms ( 2020 , 1 , 1 , 0 , 0 , 0 ) . unwrap ( ) ) ,
525+ mtime : Utc . with_ymd_and_hms ( 2020 , 1 , 1 , 0 , 0 , 0 ) . unwrap ( ) ,
526+ state : Default :: default ( ) ,
527+ behavior_hints : Default :: default ( ) ,
528+ }
529+ }
530+
531+ #[ test]
532+ fn should_update_library_with_items_only_when_merge_changes_library ( ) {
533+ let item = library_item ( "id" ) ;
534+ let library = LibraryBucket :: new ( None , vec ! [ item. to_owned( ) ] ) ;
535+
536+ assert ! ( !should_update_library_with_items(
537+ & library,
538+ & [ item. to_owned( ) ]
539+ ) ) ;
540+
541+ let mut newer_item = item. to_owned ( ) ;
542+ newer_item. name = "updated" . to_owned ( ) ;
543+ newer_item. mtime = Utc . with_ymd_and_hms ( 2020 , 1 , 2 , 0 , 0 , 0 ) . unwrap ( ) ;
544+ assert ! ( should_update_library_with_items( & library, & [ newer_item] ) ) ;
545+
546+ let mut older_item = item. to_owned ( ) ;
547+ older_item. name = "older" . to_owned ( ) ;
548+ older_item. mtime = Utc . with_ymd_and_hms ( 2019 , 12 , 31 , 0 , 0 , 0 ) . unwrap ( ) ;
549+ assert ! ( !should_update_library_with_items( & library, & [ older_item] ) ) ;
550+
551+ assert ! ( should_update_library_with_items(
552+ & library,
553+ & [ library_item( "missing" ) ]
554+ ) ) ;
555+ }
556+
557+ #[ test]
558+ fn library_pull_result_is_unchanged_when_items_match ( ) {
559+ let item = library_item ( "id" ) ;
560+ let auth_key = AuthKey ( "auth_key" . to_owned ( ) ) ;
561+ let profile = Profile {
562+ auth : Some ( Auth {
563+ key : auth_key. to_owned ( ) ,
564+ user : User {
565+ id : "user_id" . into ( ) ,
566+ email : "user_email" . to_owned ( ) ,
567+ last_modified : Utc . with_ymd_and_hms ( 2020 , 1 , 1 , 0 , 0 , 0 ) . unwrap ( ) ,
568+ date_registered : Utc . with_ymd_and_hms ( 2020 , 1 , 1 , 0 , 0 , 0 ) . unwrap ( ) ,
569+ gdpr_consent : GDPRConsent {
570+ tos : true ,
571+ privacy : true ,
572+ marketing : true ,
573+ from : Some ( "tests" . to_owned ( ) ) ,
574+ } ,
575+ ..Default :: default ( )
576+ } ,
577+ } ) ,
578+ ..Default :: default ( )
579+ } ;
580+ let request = DatastoreRequest {
581+ auth_key,
582+ collection : "libraryItem" . to_owned ( ) ,
583+ command : DatastoreCommand :: Get {
584+ ids : vec ! [ "id" . to_owned( ) ] ,
585+ all : false ,
586+ } ,
587+ } ;
588+ let msg = Msg :: Internal ( Internal :: LibraryPullResult (
589+ request,
590+ Ok ( vec ! [ item. to_owned( ) ] ) ,
591+ ) ) ;
592+ let mut library = LibraryBucket :: new ( Some ( "user_id" . into ( ) ) , vec ! [ item] ) ;
593+
594+ let effects = update_library :: < crate :: unit_tests:: TestEnv > (
595+ & mut library,
596+ & profile,
597+ & CtxStatus :: Ready ,
598+ & msg,
599+ ) ;
600+
601+ assert ! ( !effects. has_changed) ;
602+ }
603+ }
0 commit comments