Просмотр исходного кода

Refactor CoreDataObserver to be able to perform different operations based on the CRUD operation

polscm32 1 год назад
Родитель
Сommit
881a0e1639
1 измененных файлов с 87 добавлено и 16 удалено
  1. 87 16
      Model/CoreDataObserver.swift

+ 87 - 16
Model/CoreDataObserver.swift

@@ -2,34 +2,105 @@ import Combine
 import CoreData
 import Foundation
 
-func changedObjectsOnManagedObjectContextDidSavePublisher() -> some Publisher<Set<NSManagedObjectID>, Never> {
+/// Represents the types of Core Data changes that can be observed
+/// Use as an option set to specify which types of changes to monitor
+public struct CoreDataChangeTypes: OptionSet {
+    /// The raw integer value used to store the option set bits
+    public let rawValue: Int
+
+    /// Required initializer for OptionSet conformance
+    public init(rawValue: Int) {
+        self.rawValue = rawValue
+    }
+
+    /// Represents newly created/inserted objects in Core Data
+    /// Binary: 001 (1 << 0)
+    public static let inserted = CoreDataChangeTypes(rawValue: 1 << 0)
+
+    /// Represents modified/updated objects in Core Data
+    /// Binary: 010 (1 << 1)
+    public static let updated = CoreDataChangeTypes(rawValue: 1 << 1)
+
+    /// Represents removed/deleted objects in Core Data
+    /// Binary: 100 (1 << 2)
+    public static let deleted = CoreDataChangeTypes(rawValue: 1 << 2)
+
+    /// Convenience option that includes all possible change types
+    /// This combines inserted, updated, and deleted into a single option
+    public static let all: CoreDataChangeTypes = [.inserted, .updated, .deleted]
+}
+
+/// Creates a publisher that emits sets of NSManagedObjectIDs when Core Data changes occur
+/// - Parameter changeTypes: The types of changes to observe (defaults to .all)
+/// - Returns: A publisher that emits Sets of NSManagedObjectIDs for the specified change types
+func changedObjectsOnManagedObjectContextDidSavePublisher(
+    observing changeTypes: CoreDataChangeTypes = .all
+) -> some Publisher<Set<NSManagedObjectID>, Never> {
     Foundation.NotificationCenter.default
-        .publisher(for: NSNotification.Name.NSManagedObjectContextDidSave)
-        .map { notification in
-            guard let userInfo = notification.userInfo else { return Set<NSManagedObjectID>() }
+        .publisher(for: .NSManagedObjectContextDidSave)
+        .compactMap { notification -> Set<NSManagedObjectID>? in
 
             var objectIDs = Set<NSManagedObjectID>()
 
-            if let inserted = userInfo[NSInsertedObjectsKey] as? Set<NSManagedObject> {
-                objectIDs.formUnion(inserted.map(\.objectID))
+            // Process inserted objects if requested
+            if changeTypes.contains(.inserted) {
+                objectIDs.formUnion(notification.insertedObjectIDs)
             }
-            if let updated = userInfo[NSUpdatedObjectsKey] as? Set<NSManagedObject> {
-                objectIDs.formUnion(updated.map(\.objectID))
+
+            // Process updated objects if requested
+            if changeTypes.contains(.updated) {
+                objectIDs.formUnion(notification.updatedObjectIDs)
             }
-            if let deleted = userInfo[NSDeletedObjectsKey] as? Set<NSManagedObject> {
-                objectIDs.formUnion(deleted.map(\.objectID))
+
+            // Process deleted objects if requested
+            if changeTypes.contains(.deleted) {
+                objectIDs.formUnion(notification.deletedObjectIDs)
             }
 
-            return objectIDs
+            // Only emit non-empty sets
+            return objectIDs.isEmpty ? nil : objectIDs
         }
 }
 
 extension Publisher where Output == Set<NSManagedObjectID> {
-    func filterByEntityName(_ name: String) -> some Publisher<Self.Output, Self.Failure> {
-        filter { objectIDs in
-            objectIDs.contains { objectID in
-                objectID.entity.name == name
-            }
+    /// Filters Core Data changes by entity name
+    ///
+    /// This method allows filtering Core Data changes by entity name.
+    ///
+    /// Example usage:
+    /// ```swift
+    /// // Filter changes for "GlucoseStored" entity
+    /// publisher.filterByEntityName("GlucoseStored")
+    /// ```
+    ///
+    /// - Parameters:
+    ///   - name: The name of the Core Data entity to filter for
+    /// - Returns: A publisher emitting filtered sets of NSManagedObjectIDs
+    func filterByEntityName(
+        _ name: String
+    ) -> some Publisher<Set<NSManagedObjectID>, Self.Failure> {
+        compactMap { objectIDs -> Set<NSManagedObjectID>? in
+            // Early exit for empty sets
+            guard !objectIDs.isEmpty else { return nil }
+
+            // Use lazy evaluation for better performance
+            let filtered = objectIDs.lazy.filter { $0.entity.name == name }
+            let result = Set(filtered)
+            return result.isEmpty ? nil : result
         }
     }
 }
+
+extension Notification {
+    var insertedObjectIDs: Set<NSManagedObjectID> {
+        userInfo?[NSInsertedObjectIDsKey] as? Set<NSManagedObjectID> ?? []
+    }
+
+    var updatedObjectIDs: Set<NSManagedObjectID> {
+        userInfo?[NSUpdatedObjectIDsKey] as? Set<NSManagedObjectID> ?? []
+    }
+
+    var deletedObjectIDs: Set<NSManagedObjectID> {
+        userInfo?[NSDeletedObjectIDsKey] as? Set<NSManagedObjectID> ?? []
+    }
+}