-
-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
3,229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import Foundation | ||
import CoreData | ||
|
||
/** | ||
Helps you filter insertions, deletions and updates by comparing your JSON dictionary with your Core Data local objects. | ||
It also provides uniquing for you locally stored objects and automatic removal of not found ones. | ||
*/ | ||
class DataFilter: NSObject { | ||
struct Operation: OptionSet { | ||
let rawValue: Int | ||
|
||
init(rawValue: Int) { | ||
self.rawValue = rawValue | ||
} | ||
|
||
static let insert = Operation(rawValue: 1 << 0) | ||
static let update = Operation(rawValue: 1 << 1) | ||
static let delete = Operation(rawValue: 1 << 2) | ||
static let all: Operation = [.insert, .update, .delete] | ||
} | ||
|
||
class func changes(_ changes: [[String: Any]], | ||
inEntityNamed entityName: String, | ||
localPrimaryKey: String, | ||
remotePrimaryKey: String, | ||
context: NSManagedObjectContext, | ||
inserted: (_ json: [String: Any]) -> Void, | ||
updated: (_ json: [String: Any], _ updatedObject: NSManagedObject) -> Void) { | ||
self.changes(changes, inEntityNamed: entityName, predicate: nil, operations: .all, localPrimaryKey: localPrimaryKey, remotePrimaryKey: remotePrimaryKey, context: context, inserted: inserted, updated: updated) | ||
} | ||
|
||
class func changes(_ changes: [[String: Any]], | ||
inEntityNamed entityName: String, | ||
predicate: NSPredicate?, | ||
operations: Operation, | ||
localPrimaryKey: String, | ||
remotePrimaryKey: String, | ||
context: NSManagedObjectContext, | ||
inserted: (_ json: [String: Any]) -> Void, | ||
updated: (_ json: [String: Any], _ updatedObject: NSManagedObject) -> Void) { | ||
// `DataObjectIDs.objectIDsInEntityNamed` also deletes all objects that don't have a primary key or that have the same primary key already found in the context | ||
let primaryKeysAndObjectIDs = context.managedObjectIDs(in: entityName, usingAsKey: localPrimaryKey, predicate: predicate) as [NSObject: NSManagedObjectID] | ||
let localPrimaryKeys = Array(primaryKeysAndObjectIDs.keys) | ||
let remotePrimaryKeys = changes.map { $0[remotePrimaryKey] } | ||
let remotePrimaryKeysWithoutNils = (remotePrimaryKeys.filter { (($0 as? NSObject) != NSNull()) && ($0 != nil) } as! [NSObject?]) as! [NSObject] | ||
|
||
var remotePrimaryKeysAndChanges = [NSObject: [String: Any]]() | ||
for (primaryKey, change) in zip(remotePrimaryKeysWithoutNils, changes) { | ||
remotePrimaryKeysAndChanges[primaryKey] = change | ||
} | ||
|
||
var intersection = Set(remotePrimaryKeysWithoutNils) | ||
intersection.formIntersection(Set(localPrimaryKeys)) | ||
let updatedObjectIDs = Array(intersection) | ||
|
||
var deletedObjectIDs = localPrimaryKeys | ||
deletedObjectIDs = deletedObjectIDs.filter { value in | ||
!remotePrimaryKeysWithoutNils.contains { $0.isEqual(value) } | ||
} | ||
|
||
var insertedObjectIDs = remotePrimaryKeysWithoutNils | ||
insertedObjectIDs = insertedObjectIDs.filter { value in | ||
!localPrimaryKeys.contains { $0.isEqual(value) } | ||
} | ||
|
||
if operations.contains(.delete) { | ||
for fetchedID in deletedObjectIDs { | ||
let objectID = primaryKeysAndObjectIDs[fetchedID]! | ||
let object = context.object(with: objectID) | ||
context.delete(object) | ||
} | ||
} | ||
|
||
if operations.contains(.insert) { | ||
for fetchedID in insertedObjectIDs { | ||
let objectDictionary = remotePrimaryKeysAndChanges[fetchedID]! | ||
inserted(objectDictionary) | ||
} | ||
} | ||
|
||
if operations.contains(.update) { | ||
for fetchedID in updatedObjectIDs { | ||
let JSON = remotePrimaryKeysAndChanges[fetchedID]! | ||
let objectID = primaryKeysAndObjectIDs[fetchedID]! | ||
let object = context.object(with: objectID) | ||
updated(JSON, object) | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.