@@ -447,21 +447,53 @@ public final class FilesDatabaseManager: Sendable {
447447 }
448448 }
449449
450+ ///
451+ /// Mark an item as deleted.
452+ ///
453+ /// This is a soft delete and does not actually delete data for which there is ``removeItemMetadata(ocId:)``.
454+ ///
455+ /// - Parameters:
456+ /// - ocId: The unique identifier of the item.
457+ ///
450458 @discardableResult public func deleteItemMetadata( ocId: String ) -> Bool {
451459 do {
452460 let results = itemMetadatas. where { $0. ocId == ocId }
453461 let database = ncDatabase ( )
462+
454463 try database. write {
455- logger. debug ( " Deleting item metadata. \( ocId) " )
456464 results. forEach { $0. deleted = true }
465+ logger. debug ( " Marked item as deleted. " , [ . item: ocId] )
457466 }
467+
458468 return true
459469 } catch {
460- logger. error ( " Could not delete item metadata with ocId \( ocId ) . " , [ . error: error] )
470+ logger. error ( " Could not mark item as deleted . " , [ . item : ocId , . error: error] )
461471 return false
462472 }
463473 }
464474
475+ ///
476+ /// Hard delete an item.
477+ ///
478+ /// Unlike ``deleteItemMetadata(ocId:)``, this actually deletes a data record.
479+ ///
480+ /// - Parameters:
481+ /// - ocId: The unique identifier of the item.
482+ ///
483+ public func removeItemMetadata( ocId: String ) {
484+ do {
485+ let database = ncDatabase ( )
486+ let results = itemMetadatas. where { $0. ocId == ocId }
487+
488+ try database. write {
489+ database. delete ( results)
490+ logger. debug ( " Removed item metadata from database. " , [ . item: ocId] )
491+ }
492+ } catch {
493+ logger. error ( " Could not remove item metadata. " , [ . item: ocId, . error: error] )
494+ }
495+ }
496+
465497 public func renameItemMetadata( ocId: String , newServerUrl: String , newFileName: String ) {
466498 guard let itemMetadata = itemMetadatas. where ( { $0. ocId == ocId } ) . first else {
467499 logger. error ( " Could not find an item with ocID \( ocId) to rename to \( newFileName) " )
@@ -538,13 +570,12 @@ public final class FilesDatabaseManager: Sendable {
538570 return NSFileProviderItemIdentifier ( parentMetadata. ocId)
539571 }
540572
541- private func managedMaterialisedItemMetadatas( account : String ) -> Results < RealmItemMetadata > {
573+ private func managedMaterialisedItemMetadatas( ) -> Results < RealmItemMetadata > {
542574 itemMetadatas. where { candidate in
543- let belongsToAccount = candidate. account == account
544575 let isVisitedDirectory = candidate. directory && candidate. visitedDirectory
545576 let isDownloadedFile = candidate. directory == false && candidate. downloaded
546577
547- return belongsToAccount && ( isVisitedDirectory || isDownloadedFile)
578+ return isVisitedDirectory || isDownloadedFile
548579 }
549580 }
550581
@@ -556,67 +587,97 @@ public final class FilesDatabaseManager: Sendable {
556587 ///
557588 /// - Returns: An array of sendable metadata objects.
558589 ///
559- public func materialisedItemMetadatas( account: String ) -> [ SendableItemMetadata ] {
560- managedMaterialisedItemMetadatas ( account : account ) . toUnmanagedResults ( )
590+ public func materialisedItemMetadatas( account _ : String ) -> [ SendableItemMetadata ] {
591+ managedMaterialisedItemMetadatas ( ) . toUnmanagedResults ( )
561592 }
562593
563- public func pendingWorkingSetChanges( account: Account , since date: Date ) -> ( updated: [ SendableItemMetadata ] , deleted: [ SendableItemMetadata ] ) {
564- let accId = account. ncKitAccount
565- let pending = managedMaterialisedItemMetadatas ( account: accId) . where { $0. syncTime > date }
566- var updated = pending. where { !$0. deleted } . toUnmanagedResults ( )
567- var deleted = pending. where { $0. deleted } . toUnmanagedResults ( )
568- var handledUpdateOcIds = Set ( updated. map ( \. ocId) )
594+ ///
595+ /// Look up the not yet synchronized changes and deletions in the materialized items since the last given synchronization time.
596+ ///
597+ /// - Parameters:
598+ /// - date: All items with a synchronization time later than this are considered.
599+ ///
600+ /// - Returns: Locally changed items in the working set grouped by "updated" and "deleted".
601+ ///
602+ public func pendingWorkingSetChanges( since date: Date ) -> ( updated: [ SendableItemMetadata ] , deleted: [ SendableItemMetadata ] ) {
603+ logger. debug ( " Gathering pending working set changes... " )
604+ let pendingChanges = managedMaterialisedItemMetadatas ( ) . where { $0. syncTime > date }
605+ var updatedItems = pendingChanges. where { !$0. deleted } . toUnmanagedResults ( )
606+ var deletedItems = pendingChanges. where { $0. deleted } . toUnmanagedResults ( )
607+
608+ for item in updatedItems {
609+ logger. debug ( " Found updated item. " , [ . item: item. ocId, . name: item. fileName] )
610+ }
569611
570- updated
571- . map { $0. remotePath ( ) }
572- . forEach { serverUrl in
573- logger. debug ( " Checking updated item... " , [ . url: serverUrl] )
612+ for item in deletedItems {
613+ logger. debug ( " Found deleted item. " , [ . item: item. ocId, . name: item. fileName] )
614+ }
574615
616+ var updatedItemIdentifiers = Set ( updatedItems. map ( \. ocId) )
617+ var deletedItemIdentifiers = Set ( deletedItems. map ( \. ocId) )
618+
619+ updatedItems // Look for changed children
620+ . filter {
621+ $0. directory // files do not have any children to look for
622+ }
623+ . map {
624+ $0. remotePath ( )
625+ }
626+ . forEach { serverUrl in
575627 itemMetadatas
576- . where { $0 . serverUrl == serverUrl && $0 . syncTime > date }
577- . forEach { metadata in
578- guard !handledUpdateOcIds . contains ( metadata . ocId ) else {
579- return
580- }
628+ . where {
629+ $0 . serverUrl == serverUrl && $0 . syncTime > date
630+ }
631+ . forEach { child in
632+ let sendableMetadata = SendableItemMetadata ( value : child )
581633
582- handledUpdateOcIds. insert ( metadata. ocId)
583- let sendableMetadata = SendableItemMetadata ( value: metadata)
634+ if child. deleted {
635+ guard deletedItemIdentifiers. contains ( child. ocId) == false else {
636+ return
637+ }
584638
585- if metadata . deleted {
586- deleted . append ( sendableMetadata)
587- logger. debug ( " Appended deleted item to working set changes. " , [ . item: metadata . ocId, . url: serverUrl] )
639+ deletedItemIdentifiers . insert ( child . ocId )
640+ deletedItems . append ( sendableMetadata)
641+ logger. debug ( " Appended deleted item to working set changes. " , [ . item: child . ocId, . url: serverUrl] )
588642 } else {
589- updated. append ( sendableMetadata)
590- logger. debug ( " Appended updated item to working set changes. " , [ . item: metadata. ocId, . url: serverUrl] )
643+ guard updatedItemIdentifiers. contains ( child. ocId) == false else {
644+ return
645+ }
646+
647+ updatedItemIdentifiers. insert ( child. ocId)
648+ updatedItems. append ( sendableMetadata)
649+ logger. debug ( " Appended updated item to working set changes. " , [ . item: child. ocId, . url: serverUrl] )
591650 }
592651 }
593652 }
594653
595- let handledDeleteOcIds = Set ( deleted. map ( \. ocId) )
596-
597- deleted
598- . map { $0. remotePath ( ) }
654+ deletedItems // Look for deleted children recursively
655+ . filter {
656+ $0. directory // files do not have any children to look for
657+ }
658+ . map {
659+ $0. remotePath ( )
660+ }
599661 . forEach { serverUrl in
600- logger. debug ( " Verifying deleted item... " , [ . url: serverUrl] )
601-
602662 itemMetadatas. where {
603663 $0. serverUrl. starts ( with: serverUrl) && $0. syncTime > date
604- } . forEach { metadata in
605- guard metadata . isLockFileOfLocalOrigin == false else {
606- logger. info ( " Excluding item from deletion because it is a lock file from local origin. " , [ . item: metadata . ocId] )
664+ } . forEach { child in
665+ guard child . isLockFileOfLocalOrigin == false else {
666+ logger. info ( " Excluding item from deletion because it is a lock file from local origin. " , [ . item: child . ocId, . name : child . fileName ] )
607667 return
608668 }
609669
610- guard !handledDeleteOcIds . contains ( metadata . ocId) else {
670+ guard !deletedItemIdentifiers . contains ( child . ocId) else {
611671 return
612672 }
613673
614- deleted. append ( SendableItemMetadata ( value: metadata) )
615- logger. debug ( " Appended deleted item to working set changes. " , [ . item: metadata. ocId, . url: serverUrl] )
674+ deletedItemIdentifiers. insert ( child. ocId)
675+ deletedItems. append ( SendableItemMetadata ( value: child) )
676+ logger. debug ( " Appended deleted item to working set changes. " , [ . item: child. ocId, . url: serverUrl] )
616677 }
617678 }
618679
619- return ( updated , deleted )
680+ return ( updatedItems , deletedItems )
620681 }
621682
622683 public func itemsMetadataByFileNameSuffix( suffix: String ) -> [ SendableItemMetadata ] {
0 commit comments