diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index b4dc129..80f1a55 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -154,6 +154,36 @@ B52DD1CC1BE1F94D00949AFE /* CoreStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F03A53F19C5C6DA005002A5 /* CoreStoreTests.swift */; }; B52DD1CD1BE1F94D00949AFE /* TestEntity1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D372851A39CDDB00F583D9 /* TestEntity1.swift */; }; B52DD1CE1BE1F94D00949AFE /* TestEntity2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */; }; + B53FB9FE1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; }; + B53FB9FF1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; }; + B53FBA001CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; }; + B53FBA011CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; }; + B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */; }; + B53FBA041CAB300C00F0D40A /* CSMigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA031CAB300C00F0D40A /* CSMigrationType.swift */; }; + B53FBA051CAB300C00F0D40A /* CSMigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA031CAB300C00F0D40A /* CSMigrationType.swift */; }; + B53FBA061CAB300C00F0D40A /* CSMigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA031CAB300C00F0D40A /* CSMigrationType.swift */; }; + B53FBA071CAB300C00F0D40A /* CSMigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA031CAB300C00F0D40A /* CSMigrationType.swift */; }; + B53FBA081CAB300C00F0D40A /* CSMigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA031CAB300C00F0D40A /* CSMigrationType.swift */; }; + B53FBA0B1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA0A1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift */; }; + B53FBA0C1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA0A1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift */; }; + B53FBA0D1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA0A1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift */; }; + B53FBA0E1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA0A1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift */; }; + B53FBA0F1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA0A1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift */; }; + B53FBA121CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA111CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift */; }; + B53FBA131CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA111CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift */; }; + B53FBA141CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA111CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift */; }; + B53FBA151CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA111CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift */; }; + B53FBA161CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA111CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift */; }; + B53FBA181CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA171CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift */; }; + B53FBA191CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA171CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift */; }; + B53FBA1A1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA171CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift */; }; + B53FBA1B1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA171CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift */; }; + B53FBA1C1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA171CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift */; }; + B53FBA1E1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA1D1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift */; }; + B53FBA1F1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA1D1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift */; }; + B53FBA201CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA1D1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift */; }; + B53FBA211CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA1D1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift */; }; + B53FBA221CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FBA1D1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift */; }; B546F9581C99B17400D5AC55 /* CSCoreStore+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B546F9571C99B17400D5AC55 /* CSCoreStore+Setup.swift */; }; B546F9591C99B17400D5AC55 /* CSCoreStore+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B546F9571C99B17400D5AC55 /* CSCoreStore+Setup.swift */; }; B546F95A1C99B17400D5AC55 /* CSCoreStore+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B546F9571C99B17400D5AC55 /* CSCoreStore+Setup.swift */; }; @@ -588,6 +618,12 @@ B529C2031CA4A2DB007E7EBD /* CSSaveResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSaveResult.swift; sourceTree = ""; }; B52DD1741BE1F8CC00949AFE /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSMigrationResult.swift; sourceTree = ""; }; + B53FBA031CAB300C00F0D40A /* CSMigrationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSMigrationType.swift; sourceTree = ""; }; + B53FBA0A1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSCoreStore+Migrating.swift"; sourceTree = ""; }; + B53FBA111CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSProgress+ObjectiveC.swift"; sourceTree = ""; }; + B53FBA171CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+ObjectiveC.swift"; sourceTree = ""; }; + B53FBA1D1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+ObjectiveC.swift"; sourceTree = ""; }; B546F9571C99B17400D5AC55 /* CSCoreStore+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSCoreStore+Setup.swift"; sourceTree = ""; }; B546F95C1C9A12B800D5AC55 /* CSSQliteStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSQliteStore.swift; sourceTree = ""; }; B546F9681C9AF26D00D5AC55 /* CSInMemoryStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSInMemoryStore.swift; sourceTree = ""; }; @@ -902,6 +938,16 @@ name = Observing; sourceTree = ""; }; + B53FBA101CAB607000F0D40A /* Convenience Helpers */ = { + isa = PBXGroup; + children = ( + B53FBA171CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift */, + B53FBA111CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift */, + B53FBA1D1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift */, + ); + name = "Convenience Helpers"; + sourceTree = ""; + }; B546F9611C9A13F400D5AC55 /* Setup */ = { isa = PBXGroup; children = ( @@ -969,6 +1015,7 @@ B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */, B5DBE2CC1C9914A900B5CEFA /* CSCoreStore.swift */, B5519A491CA1F4FB002BEF78 /* CSError.swift */, + B53FBA101CAB607000F0D40A /* Convenience Helpers */, B546F9611C9A13F400D5AC55 /* Setup */, B5519A5D1CA20093002BEF78 /* Saving and Processing */, B5E2222F1CA5339200BA2E95 /* Fetching and Querying */, @@ -983,7 +1030,10 @@ isa = PBXGroup; children = ( B5E1B5A71CAA49E2007FD580 /* CSDataStack+Migrating.swift */, + B53FBA0A1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift */, B559CD421CAA8B6300E4D58B /* CSSetupResult.swift */, + B53FBA031CAB300C00F0D40A /* CSMigrationType.swift */, + B53FB9FD1CAB2D2F00F0D40A /* CSMigrationResult.swift */, ); name = Migrating; sourceTree = ""; @@ -1492,12 +1542,14 @@ B5519A5F1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */, B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */, B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */, + B53FBA0B1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B5E84F141AFF847B0064E85B /* DataStack+Querying.swift in Sources */, B5D7A5B61CA3BF8F005C752B /* CSInto.swift in Sources */, B56007141B3F6C2800A9A8F9 /* SectionBy.swift in Sources */, B5E84F371AFF85470064E85B /* NSManagedObjectContext+Transaction.swift in Sources */, B5ECDC1D1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */, B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */, + B53FBA121CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */, B5E1B5A81CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */, B56007161B4018AB00A9A8F9 /* MigrationChain.swift in Sources */, B5E1B59D1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */, @@ -1514,8 +1566,10 @@ B56007111B3F6BD500A9A8F9 /* Into.swift in Sources */, B5E84F111AFF847B0064E85B /* Select.swift in Sources */, B5FE4DA21C8481E100FA6A91 /* StorageInterface.swift in Sources */, + B53FB9FE1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */, B5DBE2D21C991B3E00B5CEFA /* CSDataStack.swift in Sources */, B50392F91C478FF3009900CA /* NSManagedObject+Transaction.swift in Sources */, + B53FBA181CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */, B5202CFA1C04688100DED140 /* NSFetchedResultsController+Convenience.swift in Sources */, B5519A591CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */, B5ECDBDF1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */, @@ -1563,12 +1617,14 @@ B5E84EF81AFF846E0064E85B /* CoreStore+Transaction.swift in Sources */, B5E84F301AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift in Sources */, B546F9691C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */, + B53FBA1E1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */, B5E84F211AFF84860064E85B /* CoreStore+Observing.swift in Sources */, B559CD431CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */, B5ECDBEC1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */, B5E84EE61AFF84610064E85B /* DefaultLogger.swift in Sources */, + B53FBA041CAB300C00F0D40A /* CSMigrationType.swift in Sources */, B5E84EF41AFF846E0064E85B /* AsynchronousDataTransaction.swift in Sources */, B5DBE2CD1C9914A900B5CEFA /* CSCoreStore.swift in Sources */, B546F95D1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, @@ -1613,12 +1669,14 @@ B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */, B5FE4DAD1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */, 82BA18C51C4BBD5300A0916E /* ListObserver.swift in Sources */, + B53FBA0D1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, 82BA18C21C4BBD5300A0916E /* ObjectMonitor.swift in Sources */, B5D7A5B81CA3BF8F005C752B /* CSInto.swift in Sources */, 82BA18A51C4BBD2200A0916E /* CoreStore+Setup.swift in Sources */, 82BA18BD1C4BBD4A00A0916E /* GroupBy.swift in Sources */, B5ECDC1F1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */, B5C976E41C6C9F9A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */, + B53FBA141CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */, B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */, B5D3F6461C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */, B5E1B59F1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */, @@ -1635,8 +1693,10 @@ 82BA18B11C4BBD3100A0916E /* SaveResult.swift in Sources */, 82BA18DD1C4BBE1400A0916E /* NSFetchedResultsController+Convenience.swift in Sources */, B5FE4DA81C84FB4400FA6A91 /* InMemoryStore.swift in Sources */, + B53FBA001CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */, B5DBE2D31C991B3E00B5CEFA /* CSDataStack.swift in Sources */, 82BA18B41C4BBD3900A0916E /* BaseDataTransaction+Importing.swift in Sources */, + B53FBA1A1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */, 82BA18CA1C4BBD5900A0916E /* MigrationResult.swift in Sources */, B5519A5A1CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */, B5ECDBE11CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */, @@ -1684,12 +1744,14 @@ 82BA18D31C4BBD7100A0916E /* NSManagedObjectContext+CoreStore.swift in Sources */, 82BA18AD1C4BBD3100A0916E /* UnsafeDataTransaction.swift in Sources */, B546F96A1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */, + B53FBA201CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */, 82BA18A81C4BBD2900A0916E /* CoreStoreLogger.swift in Sources */, B559CD451CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, 82BA18B81C4BBD4200A0916E /* ClauseTypes.swift in Sources */, B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */, 82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */, 82BA18B91C4BBD4A00A0916E /* From.swift in Sources */, + B53FBA061CAB300C00F0D40A /* CSMigrationType.swift in Sources */, 82BA18BE1C4BBD4A00A0916E /* Tweak.swift in Sources */, B5DBE2CE1C9914A900B5CEFA /* CSCoreStore.swift in Sources */, B546F95E1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, @@ -1723,6 +1785,7 @@ B52DD1BE1BE1F94300949AFE /* NSProgress+Convenience.swift in Sources */, B5ECDC151CA816E500C7F112 /* CSTweak.swift in Sources */, B546F9761C9C553300D5AC55 /* SetupResult.swift in Sources */, + B53FBA161CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */, B5ECDC271CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */, B52DD1951BE1F92500949AFE /* CoreStoreError.swift in Sources */, B546F9601C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, @@ -1750,6 +1813,7 @@ B5ECDBFD1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */, B52DD1BD1BE1F94300949AFE /* NSManagedObject+Convenience.swift in Sources */, B52DD1AD1BE1F93900949AFE /* Where.swift in Sources */, + B53FBA1C1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */, B5ECDBE31CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */, B5ECDC031CA80CBA00C7F112 /* CSWhere.swift in Sources */, B52DD1AC1BE1F93900949AFE /* Select.swift in Sources */, @@ -1782,6 +1846,7 @@ B52DD19F1BE1F92C00949AFE /* SynchronousDataTransaction.swift in Sources */, B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */, B52DD1C11BE1F94600949AFE /* Functions.swift in Sources */, + B53FBA0F1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B52DD19A1BE1F92800949AFE /* CoreStore+Logging.swift in Sources */, B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */, B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */, @@ -1794,12 +1859,15 @@ B52DD1C91BE1F94600949AFE /* NSManagedObjectContext+Transaction.swift in Sources */, B52DD19B1BE1F92800949AFE /* CoreStoreLogger.swift in Sources */, B52DD1991BE1F92800949AFE /* DefaultLogger.swift in Sources */, + B53FBA221CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */, + B53FBA081CAB300C00F0D40A /* CSMigrationType.swift in Sources */, B52DD1B91BE1F94000949AFE /* CoreStore+Migration.swift in Sources */, B5519A5C1CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */, B5DBE2D51C991B3E00B5CEFA /* CSDataStack.swift in Sources */, B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */, B52DD1AA1BE1F93500949AFE /* ClauseTypes.swift in Sources */, + B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1837,12 +1905,14 @@ B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */, B5FE4DAE1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */, B563218C1BD65216006C9394 /* DataStack+Transaction.swift in Sources */, + B53FBA0E1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B563219E1BD65216006C9394 /* CoreStore+Observing.swift in Sources */, B5D7A5B91CA3BF8F005C752B /* CSInto.swift in Sources */, B56321891BD65216006C9394 /* AsynchronousDataTransaction.swift in Sources */, B56321831BD65216006C9394 /* CoreStore+Setup.swift in Sources */, B5ECDC201CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */, B5C976E51C6C9F9B00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */, + B53FBA151CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */, B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */, B5D3F6471C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */, B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */, @@ -1859,8 +1929,10 @@ B56321981BD65216006C9394 /* Where.swift in Sources */, B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */, B5FE4DA91C84FB4400FA6A91 /* InMemoryStore.swift in Sources */, + B53FBA011CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */, B5DBE2D41C991B3E00B5CEFA /* CSDataStack.swift in Sources */, B50392FA1C47963F009900CA /* NSManagedObject+Transaction.swift in Sources */, + B53FBA1B1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */, B5519A5B1CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */, B5ECDBE21CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */, B56321971BD65216006C9394 /* Select.swift in Sources */, @@ -1908,12 +1980,14 @@ B56321B11BD6521C006C9394 /* NSManagedObjectContext+CoreStore.swift in Sources */, B563218D1BD65216006C9394 /* CoreStore+Transaction.swift in Sources */, B546F96B1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */, + B53FBA211CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */, B563218B1BD65216006C9394 /* UnsafeDataTransaction.swift in Sources */, B559CD461CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, B56321A61BD65216006C9394 /* MigrationType.swift in Sources */, B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */, B56321861BD65216006C9394 /* CoreStoreLogger.swift in Sources */, + B53FBA071CAB300C00F0D40A /* CSMigrationType.swift in Sources */, B56321841BD65216006C9394 /* DefaultLogger.swift in Sources */, B5DBE2CF1C9914A900B5CEFA /* CSCoreStore.swift in Sources */, B546F95F1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, @@ -1930,6 +2004,7 @@ files = ( B5ECDC0C1CA8161B00C7F112 /* CSGroupBy.swift in Sources */, B5EA11DD1CA3AFD9002282F8 /* NSPersistentStoreCoordinator+Setup.swift in Sources */, + B53FBA191CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */, B5ECDC3A1CA8369400C7F112 /* CSDataStack.swift in Sources */, B5D9E2EF1CA2C317007A9D52 /* ObjectMonitor.swift in Sources */, B5ECDC3B1CA836AD00C7F112 /* CoreStoreBridge.swift in Sources */, @@ -1968,15 +2043,20 @@ B5D9E3011CA2C317007A9D52 /* Into.swift in Sources */, B5ECDC301CA81CDC00C7F112 /* CSCoreStore+Transaction.swift in Sources */, B5D9E3021CA2C317007A9D52 /* Select.swift in Sources */, + B53FBA1F1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */, B5D7A5B41CA3BAE7005C752B /* NSPersistentStore+Setup.swift in Sources */, B5D9E3031CA2C317007A9D52 /* NSManagedObject+Transaction.swift in Sources */, + B53FBA0C1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B5D9E3041CA2C317007A9D52 /* NSFetchedResultsController+Convenience.swift in Sources */, B5D9E3051CA2C317007A9D52 /* (null) in Sources */, B5D9E3061CA2C317007A9D52 /* ObjectObserver.swift in Sources */, B5D9E3071CA2C317007A9D52 /* NotificationObserver.swift in Sources */, + B53FBA051CAB300C00F0D40A /* CSMigrationType.swift in Sources */, B5D9E3081CA2C317007A9D52 /* ImportableObject.swift in Sources */, + B53FBA131CAB63CB00F0D40A /* NSProgress+ObjectiveC.swift in Sources */, B5ECDC3C1CA836B600C7F112 /* CSCoreStore.swift in Sources */, B5D9E3091CA2C317007A9D52 /* MigrationResult.swift in Sources */, + B53FB9FF1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */, B5D9E30A1CA2C317007A9D52 /* CoreStore.swift in Sources */, B5D9E30B1CA2C317007A9D52 /* ClauseTypes.swift in Sources */, B5D9E30C1CA2C317007A9D52 /* BaseDataTransaction+Querying.swift in Sources */, diff --git a/Sources/Convenience Helpers/NSFetchedResultsController+Convenience.swift b/Sources/Convenience Helpers/NSFetchedResultsController+Convenience.swift index 474bdc6..cbadc3a 100644 --- a/Sources/Convenience Helpers/NSFetchedResultsController+Convenience.swift +++ b/Sources/Convenience Helpers/NSFetchedResultsController+Convenience.swift @@ -32,7 +32,7 @@ import CoreData public extension NSFetchedResultsController { /** - Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful to partially support Objective-C classes by passing an `NSFetchedResultsController` instance instead of a `ListMonitor`. + Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction. */ @nonobjc public static func createForStack(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController { diff --git a/Sources/Convenience Helpers/NSManagedObject+Convenience.swift b/Sources/Convenience Helpers/NSManagedObject+Convenience.swift index f1eb1dc..1e8e134 100644 --- a/Sources/Convenience Helpers/NSManagedObject+Convenience.swift +++ b/Sources/Convenience Helpers/NSManagedObject+Convenience.swift @@ -37,8 +37,8 @@ public extension NSManagedObject { - parameter KVCKey: the KVC key - returns: the primitive value for the KVC key */ - @warn_unused_result @nonobjc + @warn_unused_result public func accessValueForKVCKey(KVCKey: KeyPath) -> AnyObject? { self.willAccessValueForKey(KVCKey) diff --git a/Sources/Migrating/CoreStore+Migration.swift b/Sources/Migrating/CoreStore+Migration.swift index ae3f462..da03227 100644 --- a/Sources/Migrating/CoreStore+Migration.swift +++ b/Sources/Migrating/CoreStore+Migration.swift @@ -69,7 +69,7 @@ public extension CoreStore { } ) ``` - - parameter storage: the local storage + - parameter storage: the storage - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.Failure` result if an error occurs asynchronously. - returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required */ @@ -104,7 +104,7 @@ public extension CoreStore { Asynchronously adds a `LocalStorage` to the `defaultStack`. Migrations are also initiated by default. ``` try CoreStore.addStorage( - SQLiteStore(configuration: "Config1"), + SQLiteStore(fileName: "core_data.sqlite", configuration: "Config1"), completion: { result in switch result { case .Success(let storage): // ... diff --git a/Sources/Migrating/DataStack+Migration.swift b/Sources/Migrating/DataStack+Migration.swift index 6350526..01fad1a 100644 --- a/Sources/Migrating/DataStack+Migration.swift +++ b/Sources/Migrating/DataStack+Migration.swift @@ -69,7 +69,7 @@ public extension DataStack { } ) ``` - - parameter storage: the local storage + - parameter storage: the storage - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.Failure` result if an error occurs asynchronously. - returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required */ @@ -143,7 +143,7 @@ public extension DataStack { Asynchronously adds a `LocalStorage` to the stack. Migrations are also initiated by default. ``` try dataStack.addStorage( - SQLiteStore(configuration: "Config1"), + SQLiteStore(fileName: "core_data.sqlite", configuration: "Config1"), completion: { result in switch result { case .Success(let storage): // ... diff --git a/Sources/Migrating/MigrationResult.swift b/Sources/Migrating/MigrationResult.swift index 5450814..e2c18da 100644 --- a/Sources/Migrating/MigrationResult.swift +++ b/Sources/Migrating/MigrationResult.swift @@ -57,7 +57,7 @@ import Foundation } ``` */ -public enum MigrationResult { +public enum MigrationResult: BooleanType, Hashable { /** `MigrationResult.Success` indicates either the migration succeeded, or there were no migrations needed. The associated value is an array of `MigrationType`s reflecting the migration steps completed. @@ -70,6 +70,34 @@ public enum MigrationResult { case Failure(CoreStoreError) + // MARK: BooleanType + + public var boolValue: Bool { + + switch self { + + case .Success: return true + case .Failure: return false + } + } + + + // MARK: Hashable + + public var hashValue: Int { + + switch self { + + case .Success(let migrationTypes): + return self.boolValue.hashValue + ^ migrationTypes.map { $0.hashValue }.reduce(0, combine: ^).hashValue + + case .Failure(let error): + return self.boolValue.hashValue ^ error.hashValue + } + } + + // MARK: Internal internal init(_ migrationTypes: [MigrationType]) { @@ -89,16 +117,20 @@ public enum MigrationResult { } -// MARK: - MigrationResult: BooleanType +// MARK: - SetupResult: Equatable -extension MigrationResult: BooleanType { +@warn_unused_result +public func == (lhs: MigrationResult, rhs: MigrationResult) -> Bool { - public var boolValue: Bool { + switch (lhs, rhs) { - switch self { - - case .Success: return true - case .Failure: return false - } + case (.Success(let migrationTypes1), .Success(let migrationTypes2)): + return migrationTypes1 == migrationTypes2 + + case (.Failure(let error1), .Failure(let error2)): + return error1 == error2 + + default: + return false } } diff --git a/Sources/Migrating/MigrationType.swift b/Sources/Migrating/MigrationType.swift index 146f1d4..b9b3c65 100644 --- a/Sources/Migrating/MigrationType.swift +++ b/Sources/Migrating/MigrationType.swift @@ -31,7 +31,7 @@ import Foundation /** The `MigrationType` specifies the type of migration required for a store. */ -public enum MigrationType: BooleanType { +public enum MigrationType: BooleanType, Hashable { /** Indicates that the persistent store matches the latest model version and no migration is needed @@ -120,4 +120,45 @@ public enum MigrationType: BooleanType { case .Heavyweight: return true } } + + + // MARK: Hashable + + public var hashValue: Int { + + let preHash = self.boolValue.hashValue ^ self.isHeavyweightMigration.hashValue + switch self { + + case .None(let version): + return preHash ^ version.hashValue + + case .Lightweight(let sourceVersion, let destinationVersion): + return preHash ^ sourceVersion.hashValue ^ destinationVersion.hashValue + + case .Heavyweight(let sourceVersion, let destinationVersion): + return preHash ^ sourceVersion.hashValue ^ destinationVersion.hashValue + } + } +} + + +// MARK: - MigrationType: Equatable + +@warn_unused_result +public func == (lhs: MigrationType, rhs: MigrationType) -> Bool { + + switch (lhs, rhs) { + + case (.None(let version1), .None(let version2)): + return version1 == version2 + + case (.Lightweight(let source1, let destination1), .Lightweight(let source2, let destination2)): + return source1 == source2 && destination1 == destination2 + + case (.Heavyweight(let source1, let destination1), .Heavyweight(let source2, let destination2)): + return source1 == source2 && destination1 == destination2 + + default: + return false + } } diff --git a/Sources/ObjectiveC/CSCoreStore+Migrating.swift b/Sources/ObjectiveC/CSCoreStore+Migrating.swift new file mode 100644 index 0000000..bff4a9b --- /dev/null +++ b/Sources/ObjectiveC/CSCoreStore+Migrating.swift @@ -0,0 +1,105 @@ +// +// CSCoreStore+Migrating.swift +// CoreStore +// +// Copyright © 2016 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation +import CoreData + + +// MARK: - CSCoreStore + +public extension CSCoreStore { + + /** + Asynchronously adds a `CSInMemoryStore` to the `defaultStack`. Migrations are also initiated by default. + ``` + NSError *error; + NSProgress *migrationProgress = [dataStack + addInMemoryStorage:[CSInMemoryStore new] + completion:^(CSSetupResult *result) { + if (result.isSuccess) { + // ... + } + } + error: &error]; + ``` + - parameter storage: the `CSInMemoryStore` instance + - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. + - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. + */ + public static func addInMemoryStorage(storage: CSInMemoryStore, completion: (CSSetupResult) -> Void, error: NSErrorPointer) -> NSProgress? { + + return self.defaultStack.addInMemoryStorage(storage, completion: completion, error: error) + } + + /** + Asynchronously adds a `CSSQLiteStore` to the `defaultStack`. Migrations are also initiated by default. + ``` + NSError *error; + NSProgress *migrationProgress = [dataStack + addInMemoryStorage:[[CSSQLiteStore alloc] + initWithFileName:@"core_data.sqlite" + configuration:@"Config1"] + completion:^(CSSetupResult *result) { + if (result.isSuccess) { + // ... + } + } + error: &error]; + ``` + - parameter storage: the `CSSQLiteStore` instance + - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. Note that the `CSLocalStorage` associated to the `-[CSSetupResult storage]` may not always be the same instance as the parameter argument if a previous `CSLocalStorage` was already added at the same URL and with the same configuration. + - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. + */ + public static func addSQLiteStorage(storage: CSSQLiteStore, completion: (CSSetupResult) -> Void, error: NSErrorPointer) -> NSProgress? { + + return self.defaultStack.addSQLiteStorage(storage, completion: completion, error: error) + } + + /** + Migrates a `CSSQLiteStore` to match the `defaultStack`'s managed object model version. This method does NOT add the migrated store to the data stack. + + - parameter storage: the `CSSQLiteStore` instance + - parameter completion: the closure to be executed on the main queue when the migration completes, either due to success or failure. The closure's `CSMigrationResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. + - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. + */ + @objc + public static func upgradeStorageIfNeeded(storage: CSSQLiteStore, completion: (CSMigrationResult) -> Void, error: NSErrorPointer) -> NSProgress? { + + return self.defaultStack.upgradeStorageIfNeeded(storage, completion: completion, error: error) + } + + /** + Checks the migration steps required for the `CSSQLiteStore` to match the `defaultStack`'s managed object model version. + + - parameter storage: the `CSSQLiteStore` instance + - returns: a `CSMigrationType` array indicating the migration steps required for the store, or an empty array if the file does not exist yet. Otherwise, `nil` is returned and the `error` argument is set if either inspection of the store failed, or if no mapping model was found/inferred. + */ + @objc + @warn_unused_result + public static func requiredMigrationsForSQLiteStore(storage: CSSQLiteStore, error: NSErrorPointer) -> [CSMigrationType]? { + + return self.defaultStack.requiredMigrationsForSQLiteStore(storage, error: error) + } +} diff --git a/Sources/ObjectiveC/CSDataStack+Migrating.swift b/Sources/ObjectiveC/CSDataStack+Migrating.swift index 74ae3d9..9f99080 100644 --- a/Sources/ObjectiveC/CSDataStack+Migrating.swift +++ b/Sources/ObjectiveC/CSDataStack+Migrating.swift @@ -31,332 +31,98 @@ import CoreData public extension CSDataStack { -// /** -// Asynchronously adds a `StorageInterface` to the stack. Migrations are also initiated by default. -// ``` -// try dataStack.addStorage( -// InMemoryStore(configuration: "Config1"), -// completion: { result in -// switch result { -// case .Success(let storage): // ... -// case .Failure(let error): // ... -// } -// } -// ) -// ``` -// - parameter storage: the local storage -// - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.Failure` result if an error occurs asynchronously. -// - returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required -// */ -// public func addInMemoryStorage(storage: CSInMemoryStore, completion: (CSSetupResult) -> Void, error: NSErrorPointer) -> NSProgress? { -// -// self.coordinator.performAsynchronously { -// -// if let _ = self.persistentStoreForStorage(storage) { -// -// GCDQueue.Main.async { -// -// completion(SetupResult(storage)) -// } -// return -// } -// -// do { -// -// try self.createPersistentStoreFromStorage( -// storage, -// finalURL: nil, -// finalStoreOptions: storage.storeOptions -// ) -// -// GCDQueue.Main.async { -// -// completion(SetupResult(storage)) -// } -// } -// catch { -// -// let storeError = CoreStoreError(error) -// CoreStore.log( -// storeError, -// "Failed to add \(typeName(storage)) to the stack." -// ) -// -// GCDQueue.Main.async { -// -// completion(SetupResult(storeError)) -// } -// } -// } -// -// return nil -// } -// -// /** -// Asynchronously adds a `LocalStorage` with default settings to the stack. Migrations are also initiated by default. -// ``` -// try dataStack.addStorage( -// SQLiteStore.self, -// completion: { result in -// switch result { -// case .Success(let storage): // ... -// case .Failure(let error): // ... -// } -// } -// ) -// ``` -// - parameter storeType: the local storage type -// - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.Failure` result if an error occurs asynchronously. Note that the `LocalStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration. -// - returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required -// */ -// public func addStorage(storeType: T.Type, completion: (SetupResult) -> Void) throws -> NSProgress? { -// -// return try self.addStorage(storeType.init(), completion: completion) -// } -// -// /** -// Asynchronously adds a `LocalStorage` to the stack. Migrations are also initiated by default. -// ``` -// try dataStack.addStorage( -// SQLiteStore(configuration: "Config1"), -// completion: { result in -// switch result { -// case .Success(let storage): // ... -// case .Failure(let error): // ... -// } -// } -// ) -// ``` -// - parameter storage: the local storage -// - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.Failure` result if an error occurs asynchronously. Note that the `LocalStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration. -// - returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required -// */ -// public func addStorage(storage: T, completion: (SetupResult) -> Void) throws -> NSProgress? { -// -// let fileURL = storage.fileURL -// CoreStore.assert( -// fileURL.fileURL, -// "The specified URL for the \(typeName(storage)) is invalid: \"\(fileURL)\"" -// ) -// -// return try self.coordinator.performSynchronously { -// -// if let _ = self.persistentStoreForStorage(storage) { -// -// GCDQueue.Main.async { -// -// completion(SetupResult(storage)) -// } -// return nil -// } -// -// if let persistentStore = self.coordinator.persistentStoreForURL(fileURL) { -// -// if let existingStorage = persistentStore.storageInterface as? T -// where storage.matchesPersistentStore(persistentStore) { -// -// GCDQueue.Main.async { -// -// completion(SetupResult(existingStorage)) -// } -// return nil -// } -// -// let error = CoreStoreError.DifferentStorageExistsAtURL(existingPersistentStoreURL: fileURL) -// CoreStore.log( -// error, -// "Failed to add \(typeName(storage)) at \"\(fileURL)\" because a different \(typeName(NSPersistentStore)) at that URL already exists." -// ) -// throw error -// } -// -// do { -// -// try NSFileManager.defaultManager().createDirectoryAtURL( -// fileURL.URLByDeletingLastPathComponent!, -// withIntermediateDirectories: true, -// attributes: nil -// ) -// -// let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType( -// storage.dynamicType.storeType, -// URL: fileURL, -// options: storage.storeOptions -// ) -// -// return self.upgradeStorageIfNeeded( -// storage, -// metadata: metadata, -// completion: { (result) -> Void in -// -// if case .Failure(.InternalError(let error)) = result { -// -// if storage.localStorageOptions.contains(.RecreateStoreOnModelMismatch) && error.isCoreDataMigrationError { -// -// do { -// -// try _ = self.model[metadata].flatMap(storage.eraseStorageAndWait) -// try self.addStorageAndWait(storage) -// -// GCDQueue.Main.async { -// -// completion(SetupResult(storage)) -// } -// } -// catch { -// -// completion(SetupResult(error)) -// } -// return -// } -// -// completion(SetupResult(error)) -// return -// } -// -// do { -// -// try self.addStorageAndWait(storage) -// -// completion(SetupResult(storage)) -// } -// catch { -// -// completion(SetupResult(error)) -// } -// } -// ) -// } -// catch let error as NSError -// where error.code == NSFileReadNoSuchFileError && error.domain == NSCocoaErrorDomain { -// -// try self.addStorageAndWait(storage) -// -// GCDQueue.Main.async { -// -// completion(SetupResult(storage)) -// } -// return nil -// } -// catch { -// -// let storeError = CoreStoreError(error) -// CoreStore.log( -// storeError, -// "Failed to load SQLite \(typeName(NSPersistentStore)) metadata." -// ) -// throw storeError -// } -// } -// } -// -// /** -// Migrates a local storage to match the `DataStack`'s managed object model version. This method does NOT add the migrated store to the data stack. -// -// - parameter storage: the local storage -// - parameter completion: the closure to be executed on the main queue when the migration completes, either due to success or failure. The closure's `MigrationResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.Failure` result if an error occurs asynchronously. -// - returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required -// */ -// public func upgradeStorageIfNeeded(storage: T, completion: (MigrationResult) -> Void) throws -> NSProgress? { -// -// return try self.coordinator.performSynchronously { -// -// let fileURL = storage.fileURL -// do { -// -// CoreStore.assert( -// self.persistentStoreForStorage(storage) == nil, -// "Attempted to migrate an already added \(typeName(storage)) at URL \"\(fileURL)\"" -// ) -// -// let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType( -// storage.dynamicType.storeType, -// URL: fileURL, -// options: storage.storeOptions -// ) -// return self.upgradeStorageIfNeeded( -// storage, -// metadata: metadata, -// completion: completion -// ) -// } -// catch { -// -// let metadataError = CoreStoreError(error) -// CoreStore.log( -// metadataError, -// "Failed to load \(typeName(storage)) metadata from URL \"\(fileURL)\"." -// ) -// throw metadataError -// } -// } -// } -// -// /** -// Checks the migration steps required for the storage to match the `DataStack`'s managed object model version. -// -// - parameter storage: the local storage -// - returns: a `MigrationType` array indicating the migration steps required for the store, or an empty array if the file does not exist yet. Otherwise, an error is thrown if either inspection of the store failed, or if no mapping model was found/inferred. -// */ -// @warn_unused_result -// public func requiredMigrationsForStorage(storage: T) throws -> [MigrationType] { -// -// return try self.coordinator.performSynchronously { -// -// let fileURL = storage.fileURL -// -// CoreStore.assert( -// self.persistentStoreForStorage(storage) == nil, -// "Attempted to query required migrations for an already added \(typeName(storage)) at URL \"\(fileURL)\"" -// ) -// do { -// -// let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType( -// storage.dynamicType.storeType, -// URL: fileURL, -// options: storage.storeOptions -// ) -// -// guard let migrationSteps = self.computeMigrationFromStorage(storage, metadata: metadata) else { -// -// let error = CoreStoreError.MappingModelNotFound( -// localStoreURL: fileURL, -// targetModel: self.model, -// targetModelVersion: self.modelVersion -// ) -// CoreStore.log( -// error, -// "Failed to find migration steps from the \(typeName(storage)) at URL \"\(fileURL)\" to version model \"\(self.modelVersion)\"." -// ) -// throw error -// } -// -// if migrationSteps.count > 1 && storage.localStorageOptions.contains(.PreventProgressiveMigration) { -// -// let error = CoreStoreError.ProgressiveMigrationRequired(localStoreURL: fileURL) -// CoreStore.log( -// error, -// "Failed to find migration mapping from the \(typeName(storage)) at URL \"\(fileURL)\" to version model \"\(self.modelVersion)\" without requiring progessive migrations." -// ) -// throw error -// } -// -// return migrationSteps.map { $0.migrationType } -// } -// catch let error as NSError -// where error.code == NSFileReadNoSuchFileError && error.domain == NSCocoaErrorDomain { -// -// return [] -// } -// catch { -// -// let metadataError = CoreStoreError(error) -// CoreStore.log( -// metadataError, -// "Failed to load \(typeName(storage)) metadata from URL \"\(fileURL)\"." -// ) -// throw metadataError -// } -// } -// } + /** + Asynchronously adds a `CSInMemoryStore` to the stack. Migrations are also initiated by default. + ``` + NSError *error; + NSProgress *migrationProgress = [dataStack + addInMemoryStorage:[CSInMemoryStore new] + completion:^(CSSetupResult *result) { + if (result.isSuccess) { + // ... + } + } + error: &error]; + ``` + - parameter storage: the `CSInMemoryStore` instance + - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. + - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. + */ + @objc + public func addInMemoryStorage(storage: CSInMemoryStore, completion: (CSSetupResult) -> Void, error: NSErrorPointer) -> NSProgress? { + + return bridge(error) { + + try self.bridgeToSwift.addStorage( + storage.bridgeToSwift, + completion: { completion($0.bridgeToObjectiveC) } + ) + } + } + + /** + Asynchronously adds a `CSSQLiteStore` to the stack. Migrations are also initiated by default. + ``` + NSError *error; + NSProgress *migrationProgress = [dataStack + addInMemoryStorage:[[CSSQLiteStore alloc] + initWithFileName:@"core_data.sqlite" + configuration:@"Config1"] + completion:^(CSSetupResult *result) { + if (result.isSuccess) { + // ... + } + } + error: &error]; + ``` + - parameter storage: the `CSSQLiteStore` instance + - parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `CSSetupResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. Note that the `CSLocalStorage` associated to the `-[CSSetupResult storage]` may not always be the same instance as the parameter argument if a previous `CSLocalStorage` was already added at the same URL and with the same configuration. + - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. + */ + @objc + public func addSQLiteStorage(storage: CSSQLiteStore, completion: (CSSetupResult) -> Void, error: NSErrorPointer) -> NSProgress? { + + return bridge(error) { + + try self.bridgeToSwift.addStorage( + storage.bridgeToSwift, + completion: { completion($0.bridgeToObjectiveC) } + ) + } + } + + /** + Migrates a `CSSQLiteStore` to match the `CSDataStack`'s managed object model version. This method does NOT add the migrated store to the data stack. + + - parameter storage: the `CSSQLiteStore` instance + - parameter completion: the closure to be executed on the main queue when the migration completes, either due to success or failure. The closure's `CSMigrationResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a failure `CSSetupResult` result if an error occurs asynchronously. + - returns: an `NSProgress` instance if a migration has started. `nil` if no migrations are required or if `error` was set. + */ + @objc + public func upgradeStorageIfNeeded(storage: CSSQLiteStore, completion: (CSMigrationResult) -> Void, error: NSErrorPointer) -> NSProgress? { + + return bridge(error) { + + try self.bridgeToSwift.upgradeStorageIfNeeded( + storage.bridgeToSwift, + completion: { completion($0.bridgeToObjectiveC) } + ) + } + } + + /** + Checks the migration steps required for the `CSSQLiteStore` to match the `CSDataStack`'s managed object model version. + + - parameter storage: the `CSSQLiteStore` instance + - returns: a `CSMigrationType` array indicating the migration steps required for the store, or an empty array if the file does not exist yet. Otherwise, `nil` is returned and the `error` argument is set if either inspection of the store failed, or if no mapping model was found/inferred. + */ + @objc + @warn_unused_result + public func requiredMigrationsForSQLiteStore(storage: CSSQLiteStore, error: NSErrorPointer) -> [CSMigrationType]? { + + return bridge(error) { + + try self.bridgeToSwift.requiredMigrationsForStorage(storage.bridgeToSwift) + } + } } \ No newline at end of file diff --git a/Sources/ObjectiveC/CSMigrationResult.swift b/Sources/ObjectiveC/CSMigrationResult.swift new file mode 100644 index 0000000..727c4c7 --- /dev/null +++ b/Sources/ObjectiveC/CSMigrationResult.swift @@ -0,0 +1,174 @@ +// +// CSMigrationResult.swift +// CoreStore +// +// Copyright © 2016 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation +import CoreData + + +// MARK: - CSMigrationResult + +/** + The `CSMigrationResult` serves as the Objective-C bridging type for `MigrationResult`. + */ +@objc +public final class CSMigrationResult: NSObject, CoreStoreObjectiveCType { + + /** + `YES` if the migration succeeded, `NO` otherwise + */ + @objc + public var isSuccess: Bool { + + return self.bridgeToSwift.boolValue + } + + /** + `YES` if the migration failed, `NO` otherwise + */ + @objc + public var isFailure: Bool { + + return !self.bridgeToSwift.boolValue + } + + /** + `YES` if the migration succeeded, `NO` otherwise + */ + @objc + public var migrationTypes: [CSMigrationType]? { + + guard case .Success(let migrationTypes) = self.bridgeToSwift else { + + return nil + } + return migrationTypes.map { $0.bridgeToObjectiveC } + } + + /** + The `NSError` for a failed migration, or `nil` if the migration succeeded + */ + @objc + public var error: NSError? { + + guard case .Failure(let error) = self.bridgeToSwift else { + + return nil + } + return error.bridgeToObjectiveC + } + + /** + If the result was a success, the `success` block is executed with an array of `CSMigrationType`s that indicates the migration steps completed. If the result was a failure, the `failure` block is executed with an `NSError` argument pertaining to the actual error. + + The blocks are executed immediately as `@noescape` and will not be retained. + + - parameter success: the block to execute on success. The block passes an array of `CSMigrationType`s that indicates the migration steps completed. + - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. + */ + @objc + public func handleSuccess(@noescape success: (migrationTypes: [CSMigrationType]) -> Void, @noescape failure: (error: NSError) -> Void) { + + switch self.bridgeToSwift { + + case .Success(let migrationTypes): + success(migrationTypes: migrationTypes.map { $0.bridgeToObjectiveC }) + + case .Failure(let error): + failure(error: error.bridgeToObjectiveC) + } + } + + /** + If the result was a success, the `success` block is executed with an array of `CSMigrationType`s that indicates the migration steps completed. If the result was a failure, this method does nothing. + + The block is executed immediately as `@noescape` and will not be retained. + + - parameter success: the block to execute on success. The block passes an array of `CSMigrationType`s that indicates the migration steps completed. + */ + @objc + public func handleSuccess(@noescape success: (migrationTypes: [CSMigrationType]) -> Void) { + + guard case .Success(let migrationTypes) = self.bridgeToSwift else { + + return + } + success(migrationTypes: migrationTypes.map { $0.bridgeToObjectiveC }) + } + + /** + If the result was a failure, the `failure` block is executed with an `NSError` argument pertaining to the actual error. If the result was a success, this method does nothing. + + The block is executed immediately as `@noescape` and will not be retained. + + - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. + */ + @objc + public func handleFailure(@noescape failure: (error: NSError) -> Void) { + + guard case .Failure(let error) = self.bridgeToSwift else { + + return + } + failure(error: error.bridgeToObjectiveC) + } + + + // MARK: NSObject + + public override var hash: Int { + + return self.bridgeToSwift.hashValue + } + + public override func isEqual(object: AnyObject?) -> Bool { + + guard let object = object as? CSMigrationResult else { + + return false + } + return self.bridgeToSwift == object.bridgeToSwift + } + + + // MARK: CoreStoreObjectiveCType + + public let bridgeToSwift: MigrationResult + + public required init(_ swiftValue: MigrationResult) { + + self.bridgeToSwift = swiftValue + super.init() + } +} + + +// MARK: - MigrationResult + +extension MigrationResult: CoreStoreSwiftType { + + // MARK: CoreStoreSwiftType + + public typealias ObjectiveCType = CSMigrationResult +} diff --git a/Sources/ObjectiveC/CSMigrationType.swift b/Sources/ObjectiveC/CSMigrationType.swift new file mode 100644 index 0000000..4790566 --- /dev/null +++ b/Sources/ObjectiveC/CSMigrationType.swift @@ -0,0 +1,120 @@ +// +// CSMigrationType.swift +// CoreStore +// +// Copyright © 2016 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation +import CoreData + + +// MARK: - CSMigrationType + +/** + The `CSMigrationType` serves as the Objective-C bridging type for `MigrationType`. + */ +@objc +public final class CSMigrationType: NSObject, CoreStoreObjectiveCType { + + /** + Returns `YES` if the `CSMigrationType`'s `sourceVersion` and `destinationVersion` do not match. Returns `NO` otherwise. + */ + @objc + public var needsMigration: Bool { + + return self.bridgeToSwift.boolValue + } + + /** + Returns the source model version for the migration type. If no migration is required, `sourceVersion` will be equal to the `destinationVersion`. + */ + @objc + public var sourceVersion: String { + + return self.bridgeToSwift.sourceVersion + } + + /** + Returns the destination model version for the migration type. If no migration is required, `destinationVersion` will be equal to the `sourceVersion`. + */ + @objc + public var destinationVersion: String { + + return self.bridgeToSwift.destinationVersion + } + + /** + Returns `YES` if the `CSMigrationType` is a lightweight migration. Used as syntactic sugar. + */ + @objc + public var isLightweightMigration: Bool { + + return self.bridgeToSwift.isLightweightMigration + } + + /** + Returns `YES` if the `CSMigrationType` is a heavyweight migration. Used as syntactic sugar. + */ + @objc + public var isHeavyweightMigration: Bool { + + return self.bridgeToSwift.isHeavyweightMigration + } + + + // MARK: NSObject + + public override var hash: Int { + + return self.bridgeToSwift.hashValue + } + + public override func isEqual(object: AnyObject?) -> Bool { + + guard let object = object as? CSMigrationType else { + + return false + } + return self.bridgeToSwift == object.bridgeToSwift + } + + + // MARK: CoreStoreObjectiveCType + + public let bridgeToSwift: MigrationType + + public required init(_ swiftValue: MigrationType) { + + self.bridgeToSwift = swiftValue + super.init() + } +} + + +// MARK: - MigrationType + +extension MigrationType: CoreStoreSwiftType { + + // MARK: CoreStoreSwiftType + + public typealias ObjectiveCType = CSMigrationType +} diff --git a/Sources/ObjectiveC/CSSaveResult.swift b/Sources/ObjectiveC/CSSaveResult.swift index 5eea4b2..28d03e0 100644 --- a/Sources/ObjectiveC/CSSaveResult.swift +++ b/Sources/ObjectiveC/CSSaveResult.swift @@ -85,10 +85,10 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType { The blocks are executed immediately as `@noescape` and will not be retained. - parameter success: the block to execute on success. The block passes a `BOOL` argument that indicates if there were any changes made. - - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actuall error. + - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. */ @objc - public func handleSuccess(@noescape success: (hasChanges: Bool) -> Void, @noescape failure: (error: NSError) -> Void) { + public func handleSuccess(@noescape success: (hasChanges: Bool) -> Void, @noescape failure: (error: NSError) -> Void) { switch self.bridgeToSwift { @@ -122,7 +122,7 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType { The block is executed immediately as `@noescape` and will not be retained. - - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actuall error. + - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. */ @objc public func handleFailure(@noescape failure: (error: NSError) -> Void) { diff --git a/Sources/ObjectiveC/CSSetupResult.swift b/Sources/ObjectiveC/CSSetupResult.swift index ec6de8e..9766f0c 100644 --- a/Sources/ObjectiveC/CSSetupResult.swift +++ b/Sources/ObjectiveC/CSSetupResult.swift @@ -36,67 +36,53 @@ import CoreData public final class CSSetupResult: NSObject { /** - `YES` if the `commit` operation for the transaction succeeded, either because the save succeeded or because there were no changes to save. Returns `NO` to indicate failure. + `YES` if adding the `CSStorageInterface` to the `CSDataStack` succeeded, `NO` otherwise. */ @objc public var isSuccess: Bool { - return self.bridgeToSwift.boolValue + return self.storage != nil } /** - `YES` if the `commit` operation for the transaction failed, or `NO` otherwise. When `YES`, the `error` property returns the actual `NSError` for the failure. + `YES` if adding the `CSStorageInterface` to the `CSDataStack` failed, `NO` otherwise. When `YES`, the `error` property returns the actual `NSError` for the failure. */ @objc public var isFailure: Bool { - return !self.bridgeToSwift.boolValue + return self.storage == nil } /** A `CSStorageInterface` instance if the `commit` operation for the transaction succeeded. Returns `NO` otherwise. */ @objc - public var storage: CSStorageInterface? { - - guard case .Success(let storage as CoreStoreSwiftType) = self.bridgeToSwift else { - - return nil - } - return storage.bridgeToObjectiveC - } + public let storage: CSStorageInterface? /** The `NSError` for a failed `commit` operation, or `nil` if the `commit` succeeded */ @objc - public var error: NSError? { - - guard case .Failure(let error) = self.bridgeToSwift else { - - return nil - } - return error.bridgeToObjectiveC - } + public let error: NSError? /** - If the result was a success, the `success` block is executed with a `BOOL` argument that indicates if there were any changes made. If the result was a failure, the `failure` block is executed with an `NSError` argument pertaining to the actual error. + If the result was a success, the `success` block is executed with the `CSStorageInterface` instance that was added to the `CSDataStack`. If the result was a failure, the `failure` block is executed with an `NSError` argument pertaining to the actual error. The blocks are executed immediately as `@noescape` and will not be retained. - - parameter success: the block to execute on success. The block passes a `BOOL` argument that indicates if there were any changes made. - - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actuall error. + - parameter success: the block to execute on success. The block passes a `CSStorageInterface` instance that was added to the `CSDataStack`. + - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. */ @objc public func handleSuccess(@noescape success: (storage: CSStorageInterface) -> Void, @noescape failure: (error: NSError) -> Void) { - switch self.bridgeToSwift { + if let storage = self.storage { - case .Success(let storage): - success(storage: storage.bridgeToObjectiveC) + success(storage: storage) + } + else { - case .Failure(let error): - failure(error: error.bridgeToObjectiveC) + failure(error: self.error!) } } @@ -110,7 +96,7 @@ public final class CSSetupResult: NSObject { @objc public func handleSuccess(@noescape success: (storage: CSStorageInterface) -> Void) { - guard let storageInterface = self.storageInterface else { + guard let storage = self.storage else { return } @@ -122,16 +108,16 @@ public final class CSSetupResult: NSObject { The block is executed immediately as `@noescape` and will not be retained. - - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actuall error. + - parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error. */ @objc public func handleFailure(@noescape failure: (error: NSError) -> Void) { - guard let coreStoreError = self.coreStoreError else { + guard let error = self.error else { return } - failure(error: coreStoreError.bridgeToObjectiveC) + failure(error: error) } @@ -139,11 +125,11 @@ public final class CSSetupResult: NSObject { public override var hash: Int { - if let storageInterface = self.storageInterface { + if let storage = self.storage { - return self.isSuccess.hashValue ^ ObjectIdentifier(storageInterface).hashValue + return self.isSuccess.hashValue ^ ObjectIdentifier(storage).hashValue } - return self.isSuccess.hashValue ^ self.coreStoreError!.hashValue + return self.isSuccess.hashValue ^ self.error!.hashValue } public override func isEqual(object: AnyObject?) -> Bool { @@ -152,37 +138,38 @@ public final class CSSetupResult: NSObject { return false } - return self.storageInterface === object.storageInterface - && self.coreStoreError == object.coreStoreError + return self.storage === object.storage + && self.error == object.error } // MARK: CoreStoreObjectiveCType - public required init(_ swiftValue: SetupResult) { + public required init(_ swiftValue: SetupResult) { switch swiftValue { case .Success(let storage): - self.storageInterface = storage + self.storage = storage.bridgeToObjectiveC + self.error = nil case .Failure(let error): - self.coreStoreError = error + self.storage = nil + self.error = error.bridgeToObjectiveC } super.init() } - - private var storageInterface: StorageInterface? - private var coreStoreError: CoreStoreError? } // MARK: - SetupResult -extension SetupResult { +extension SetupResult where T: CoreStoreSwiftType, T.ObjectiveCType: CSStorageInterface { // MARK: CoreStoreSwiftType + public typealias ObjectiveCType = CSSetupResult + public var bridgeToObjectiveC: CSSetupResult { return CSSetupResult(self) diff --git a/Sources/ObjectiveC/CoreStoreBridge.swift b/Sources/ObjectiveC/CoreStoreBridge.swift index 337ad9b..40718fb 100644 --- a/Sources/ObjectiveC/CoreStoreBridge.swift +++ b/Sources/ObjectiveC/CoreStoreBridge.swift @@ -42,12 +42,12 @@ public protocol CoreStoreObjectiveCType: class, AnyObject { public protocol CoreStoreSwiftType { - associatedtype ObjectiveCType: CoreStoreObjectiveCType + associatedtype ObjectiveCType var bridgeToObjectiveC: ObjectiveCType { get } } -public extension CoreStoreSwiftType where Self == ObjectiveCType.SwiftType { +public extension CoreStoreSwiftType where ObjectiveCType: CoreStoreObjectiveCType, Self == ObjectiveCType.SwiftType { public var bridgeToObjectiveC: ObjectiveCType { @@ -58,17 +58,17 @@ public extension CoreStoreSwiftType where Self == ObjectiveCType.SwiftType { // MARK: - Internal -internal func bridge(@noescape closure: () -> T) -> T.ObjectiveCType { +internal func bridge(@noescape closure: () -> T) -> T.ObjectiveCType { return closure().bridgeToObjectiveC } -internal func bridge(@noescape closure: () -> T?) -> T.ObjectiveCType? { +internal func bridge(@noescape closure: () -> T?) -> T.ObjectiveCType? { return closure()?.bridgeToObjectiveC } -internal func bridge(@noescape closure: () throws -> T) throws -> T.ObjectiveCType { +internal func bridge(@noescape closure: () throws -> T) throws -> T.ObjectiveCType { do { @@ -107,4 +107,34 @@ internal func bridge(error: NSErrorPointer, @noescape _ c } } +internal func bridge(error: NSErrorPointer, @noescape _ closure: () throws -> T?) -> T? { + + do { + + let result = try closure() + error.memory = nil + return result + } + catch let swiftError { + + error.memory = swiftError.bridgeToObjectiveC + return nil + } +} + +internal func bridge(error: NSErrorPointer, @noescape _ closure: () throws -> [T]) -> [T.ObjectiveCType]? { + + do { + + let result = try closure() + error.memory = nil + return result.map { $0.bridgeToObjectiveC } + } + catch let swiftError { + + error.memory = swiftError.bridgeToObjectiveC + return nil + } +} + diff --git a/Sources/ObjectiveC/NSFetchedResultsController+ObjectiveC.swift b/Sources/ObjectiveC/NSFetchedResultsController+ObjectiveC.swift new file mode 100644 index 0000000..6f2725b --- /dev/null +++ b/Sources/ObjectiveC/NSFetchedResultsController+ObjectiveC.swift @@ -0,0 +1,52 @@ +// +// NSFetchedResultsController+ObjectiveC.swift +// CoreStore +// +// Copyright © 2016 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation +import CoreData + + +// MARK: - NSFetchedResultsController + +@available(OSX, unavailable) +public extension NSFetchedResultsController { + + /** + Utility for creating an `NSFetchedResultsController` from a `CSDataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `CSListMonitor`s abstraction. + */ + @objc + public static func cs_createForStack(dataStack: CSDataStack, fetchRequest: NSFetchRequest, from: CSFrom?, sectionBy: CSSectionBy?, fetchClauses: [CSFetchClause]) -> NSFetchedResultsController { + + return CoreStoreFetchedResultsController( + context: dataStack.bridgeToSwift.mainContext, + fetchRequest: fetchRequest, + from: from?.bridgeToSwift, + sectionBy: sectionBy?.bridgeToSwift, + applyFetchClauses: { fetchRequest in + + fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) } + } + ) + } +} diff --git a/Sources/ObjectiveC/NSManagedObject+ObjectiveC.swift b/Sources/ObjectiveC/NSManagedObject+ObjectiveC.swift new file mode 100644 index 0000000..dc6ef8b --- /dev/null +++ b/Sources/ObjectiveC/NSManagedObject+ObjectiveC.swift @@ -0,0 +1,76 @@ +// +// NSManagedObject+ObjectiveC.swift +// CoreStore +// +// Copyright © 2016 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation +import CoreData + + +// MARK: - NSManagedObject + +public extension NSManagedObject { + + /** + Provides a convenience wrapper for accessing `-primitiveValueForKey:` with proper calls to `-willAccessValueForKey:` and `-didAccessValueForKey:`. This is useful when implementing accessor methods for transient attributes. + + - parameter KVCKey: the KVC key + - returns: the primitive value for the KVC key + */ + @objc + @warn_unused_result + public func cs_accessValueForKVCKey(KVCKey: KeyPath) -> AnyObject? { + + return self.accessValueForKVCKey(KVCKey) + } + + /** + Provides a convenience wrapper for setting `-setPrimitiveValue:` with proper calls to `-willChangeValueForKey:` and `-didChangeValueForKey:`. This is useful when implementing mutator methods for transient attributes. + + - parameter value: the value to set the KVC key with + - parameter KVCKey: the KVC key + */ + @objc + public func cs_setValue(value: AnyObject?, forKVCKey KVCKey: KeyPath) { + + self.setValue(value, forKVCKey: KVCKey) + } + + /** + Re-faults the object to use the latest values from the persistent store + */ + @objc + public func cs_refreshAsFault() { + + self.refreshAsFault() + } + + /** + Re-faults the object to use the latest values from the persistent store and merges previously pending changes back + */ + @nonobjc + public func cs_refreshAndMerge() { + + self.refreshAndMerge() + } +} diff --git a/Sources/ObjectiveC/NSProgress+ObjectiveC.swift b/Sources/ObjectiveC/NSProgress+ObjectiveC.swift new file mode 100644 index 0000000..d09ae10 --- /dev/null +++ b/Sources/ObjectiveC/NSProgress+ObjectiveC.swift @@ -0,0 +1,42 @@ +// +// NSProgress+ObjectiveC.swift +// CoreStore +// +// Copyright © 2016 John Rommel Estropia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import Foundation + + +// MARK: - NSProgress + +public extension NSProgress { + + /** + Sets a closure that the `NSProgress` calls whenever its `fractionCompleted` changes. You can use this instead of setting up KVO. + - parameter closure: the closure to execute on progress change + */ + @objc + public func cs_setProgressHandler(closure: ((progress: NSProgress) -> Void)?) { + + self.setProgressHandler(closure) + } +}