From 380edb3d79d6127dd90d66868a27ac3ba0058c8b Mon Sep 17 00:00:00 2001 From: Tomas Kohout Date: Sat, 16 Jul 2016 20:31:13 +0200 Subject: [PATCH 1/2] Fixed boxing of optional collections --- CoreValue.xcodeproj/project.pbxproj | 2 +- CoreValue/CoreValue.swift | 39 +++++++++++++----- CoreValueMacTests/CoreValueTests.swift | 40 ++++++++++++++++++- .../CoreValueTests.xcdatamodel/contents | 13 ++++-- 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/CoreValue.xcodeproj/project.pbxproj b/CoreValue.xcodeproj/project.pbxproj index 1e47ec6..c8e68f4 100644 --- a/CoreValue.xcodeproj/project.pbxproj +++ b/CoreValue.xcodeproj/project.pbxproj @@ -153,8 +153,8 @@ 4D59125A1B4989FB0022506E /* CoreValue */ = { isa = PBXGroup; children = ( - 4D5912721B498A170022506E /* CoreValue.swift */, 4D6AEB981B4DEAE100DDD5E1 /* curry.swift */, + 4D5912721B498A170022506E /* CoreValue.swift */, 4D391F291B5404FE00C66C90 /* Frameworks */, ); path = CoreValue; diff --git a/CoreValue/CoreValue.swift b/CoreValue/CoreValue.swift index a658cf0..758436a 100644 --- a/CoreValue/CoreValue.swift +++ b/CoreValue/CoreValue.swift @@ -612,19 +612,22 @@ private func internalToObject(context: NSManagedObjectContext?, // Optional with Value case (.Optional?, let child?): result.setValue(child.value as? AnyObject, forKey: label) - // A collection of objects - case (.Collection?, _): - var objects: [NSManagedObject] = [] - for (_, value) in valueMirror.children { - if let boxedValue = value as? BoxingStruct { - objects.append(try boxedValue.toObject(context)) - } - } + let optionalMirror: Mirror = Mirror(reflecting: child.value) - if objects.count > 0 { - let mutableValue = result.mutableOrderedSetValueForKey(label) - mutableValue.addObjectsFromArray(objects) + switch (optionalMirror.displayStyle, optionalMirror.children.first) { + case (.Collection?, _): + try internalCollectionToSet(context, result: result, label: label, mirror: optionalMirror) + default: + if let value = child.value as? Boxing { + try value.box(result, withKey: label) + }else { + result.setValue(child.value as? AnyObject, forKey: label) + } + break } + // A collection of objects + case (.Collection?, _): + try internalCollectionToSet(context, result: result, label: label, mirror: valueMirror) default: // If we end up here, we were unable to decode it throw CVManagedStructError.StructValueError(message: "Could not decode value for field '\(label)' obj \(valueMaybe)") @@ -637,3 +640,17 @@ private func internalToObject(context: NSManagedObjectContext?, throw CVManagedStructError.StructConversionError(message: "Object is not a struct: \(entity)") } +private func internalCollectionToSet(context: NSManagedObjectContext?, result: NSManagedObject, label: String, mirror: Mirror) throws { + var objects: [NSManagedObject] = [] + for (_, value) in mirror.children { + if let boxedValue = value as? BoxingStruct { + objects.append(try boxedValue.toObject(context)) + } + } + + if objects.count > 0 { + let mutableValue = result.mutableOrderedSetValueForKey(label) + mutableValue.addObjectsFromArray(objects) + } +} + diff --git a/CoreValueMacTests/CoreValueTests.swift b/CoreValueMacTests/CoreValueTests.swift index e234612..5ba8a1f 100644 --- a/CoreValueMacTests/CoreValueTests.swift +++ b/CoreValueMacTests/CoreValueTests.swift @@ -34,11 +34,26 @@ struct Shop: CVManagedStruct { var name: String var owner: Employee + var products: Array? static func fromObject(o: NSManagedObject) throws -> Shop { return try curry(self.init) <^> o <| "name" <^> o <| "owner" + <^> o <|| "products" + } +} + +struct Product: CVManagedStruct { + static let EntityName = "Product" + + var name: String + var color: String + + static func fromObject(o: NSManagedObject) throws -> Product { + return try curry(self.init) + <^> o <| "name" + <^> o <| "color" } } @@ -161,7 +176,7 @@ class CoreValueMacTests: XCTestCase { var nsEmployee2: NSManagedObject! let shop = { - return Shop(name: "Carl's Household Items", owner: Employee(name: "Carl", age: 66, position: nil, department: "Register", job: "Owner")) + return Shop(name: "Carl's Household Items", owner: Employee(name: "Carl", age: 66, position: nil, department: "Register", job: "Owner"), products: nil) }() var nsShop: NSManagedObject! @@ -421,6 +436,29 @@ class CoreValueMacTests: XCTestCase { XCTAssert(false, "\(e)") } } + + func testOptionalCollectionToCoreData() { + // create two shops + let s1 = Shop(name: "shop_with_products1", owner: Employee(name: "a", age: 4, position: nil, department: "", job: ""), products: [Product(name: "Pancake", color:"golden")]) + do { + try s1.toObject(self.context) + } catch let e { + XCTAssert(false, "\(e)") + } + + let s2 = Shop(name: "shop_with_products2", owner: Employee(name: "a", age: 4, position: nil, department: "", job: ""), products: [Product(name: "Unicorn", color: "sparkling")]) + testTry { + try s2.toObject(self.context) + } + + // And query the count + testTry { + let predicate = NSPredicate(format: "self.name=='shop_with_products1'", argumentArray: []) + let results: [Shop] = try Shop.query(self.context, predicate: predicate) + XCTAssert(results.count == 1, "Wrong amount of objects, update did insert: \(results.count)") + XCTAssert(results.first?.products?.count == 1, "Wrong amount of products, actual amount: \(results.first?.products?.count ?? 0)") + } + } } diff --git a/CoreValueMacTests/CoreValueTests.xcdatamodel/contents b/CoreValueMacTests/CoreValueTests.xcdatamodel/contents index 5c28ece..43d9851 100644 --- a/CoreValueMacTests/CoreValueTests.xcdatamodel/contents +++ b/CoreValueMacTests/CoreValueTests.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -26,15 +26,22 @@ + + + + + + + - - + + \ No newline at end of file From d203e3cac93ea056312214efbe3f0f9572e4ca25 Mon Sep 17 00:00:00 2001 From: Tomas Kohout Date: Sat, 16 Jul 2016 20:56:26 +0200 Subject: [PATCH 2/2] Changed internalCollectionToSet to include updated code --- CoreValue/CoreValue.swift | 12 ++++++++---- .../CoreValueTests.xcdatamodel/contents | 11 +++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CoreValue/CoreValue.swift b/CoreValue/CoreValue.swift index fab0e09..56de815 100644 --- a/CoreValue/CoreValue.swift +++ b/CoreValue/CoreValue.swift @@ -642,7 +642,6 @@ private func internalToObject(context: NSManagedObjectContext?, result.setValue(nil, forKey: label) // Optional with Value case (.Optional?, let child?): - result.setValue(child.value as? AnyObject, forKey: label) let optionalMirror: Mirror = Mirror(reflecting: child.value) switch (optionalMirror.displayStyle, optionalMirror.children.first) { @@ -679,9 +678,14 @@ private func internalCollectionToSet(context: NSManagedObjectContext?, result: N } } - if objects.count > 0 { - let mutableValue = result.mutableOrderedSetValueForKey(label) - mutableValue.addObjectsFromArray(objects) + let orderedSet = NSOrderedSet(array: objects) + + let mutableValue = result.mutableOrderedSetValueForKey(label) + if objects.count == 0 { + mutableValue.removeAllObjects() + } else { + mutableValue.intersectOrderedSet(orderedSet) // removes objects that are not in new array + mutableValue.unionOrderedSet(orderedSet) // adds new objects } } diff --git a/CoreValueMacTests/CoreValueTests.xcdatamodel/contents b/CoreValueMacTests/CoreValueTests.xcdatamodel/contents index 2a113c9..6500cd8 100644 --- a/CoreValueMacTests/CoreValueTests.xcdatamodel/contents +++ b/CoreValueMacTests/CoreValueTests.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -27,16 +27,23 @@ + + + + + + - + + \ No newline at end of file