diff --git a/CoreStore.xcodeproj/project.pbxproj b/CoreStore.xcodeproj/project.pbxproj index 56633b4..1228450 100644 --- a/CoreStore.xcodeproj/project.pbxproj +++ b/CoreStore.xcodeproj/project.pbxproj @@ -413,13 +413,37 @@ B5C976E81C6E3A5D00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; }; B5C976E91C6E3A5E00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; }; B5D1E22C19FA9FBC003B2874 /* CoreStoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */; }; - B5D339AF1E925BF200C880DE /* Prototype.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* Prototype.swift */; }; - B5D339B01E925BF200C880DE /* Prototype.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* Prototype.swift */; }; - B5D339B11E925BF200C880DE /* Prototype.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* Prototype.swift */; }; - B5D339B21E925BF200C880DE /* Prototype.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* Prototype.swift */; }; + B5D339AF1E925BF200C880DE /* ObjectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* ObjectModel.swift */; }; + B5D339B01E925BF200C880DE /* ObjectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* ObjectModel.swift */; }; + B5D339B11E925BF200C880DE /* ObjectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* ObjectModel.swift */; }; + B5D339B21E925BF200C880DE /* ObjectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* ObjectModel.swift */; }; B5D339B41E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; }; B5D339B51E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; }; B5D339B61E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; }; + B5D339D81E9489AB00C880DE /* ManagedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339D71E9489AB00C880DE /* ManagedObject.swift */; }; + B5D339D91E9489AB00C880DE /* ManagedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339D71E9489AB00C880DE /* ManagedObject.swift */; }; + B5D339DA1E9489AB00C880DE /* ManagedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339D71E9489AB00C880DE /* ManagedObject.swift */; }; + B5D339DB1E9489AB00C880DE /* ManagedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339D71E9489AB00C880DE /* ManagedObject.swift */; }; + B5D339DD1E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339DC1E9489C700C880DE /* ManagedObjectProtocol.swift */; }; + B5D339DE1E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339DC1E9489C700C880DE /* ManagedObjectProtocol.swift */; }; + B5D339DF1E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339DC1E9489C700C880DE /* ManagedObjectProtocol.swift */; }; + B5D339E01E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339DC1E9489C700C880DE /* ManagedObjectProtocol.swift */; }; + B5D339E21E948C3600C880DE /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E11E948C3600C880DE /* Attribute.swift */; }; + B5D339E31E948C3600C880DE /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E11E948C3600C880DE /* Attribute.swift */; }; + B5D339E41E948C3600C880DE /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E11E948C3600C880DE /* Attribute.swift */; }; + B5D339E51E948C3600C880DE /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E11E948C3600C880DE /* Attribute.swift */; }; + B5D339E71E9493A500C880DE /* Entity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E61E9493A500C880DE /* Entity.swift */; }; + B5D339E81E9493A500C880DE /* Entity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E61E9493A500C880DE /* Entity.swift */; }; + B5D339E91E9493A500C880DE /* Entity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E61E9493A500C880DE /* Entity.swift */; }; + B5D339EA1E9493A500C880DE /* Entity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339E61E9493A500C880DE /* Entity.swift */; }; + B5D339EC1E9495E500C880DE /* Attribute+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339EB1E9495E500C880DE /* Attribute+Querying.swift */; }; + B5D339ED1E9495E500C880DE /* Attribute+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339EB1E9495E500C880DE /* Attribute+Querying.swift */; }; + B5D339EE1E9495E500C880DE /* Attribute+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339EB1E9495E500C880DE /* Attribute+Querying.swift */; }; + B5D339EF1E9495E500C880DE /* Attribute+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339EB1E9495E500C880DE /* Attribute+Querying.swift */; }; + B5D339F11E94AF5800C880DE /* CoreStoreStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */; }; + B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */; }; + B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */; }; + B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */; }; B5D372841A39CD6900F583D9 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5D372821A39CD6900F583D9 /* Model.xcdatamodeld */; }; B5D39A0219FD00C9000E91BB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D39A0119FD00C9000E91BB /* Foundation.framework */; }; B5D3F6451C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */; }; @@ -700,8 +724,14 @@ B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafeDataTransaction+Observing.swift"; sourceTree = ""; }; B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreFetchedResultsController.swift; sourceTree = ""; }; B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreError.swift; sourceTree = ""; }; - B5D339AE1E925BF200C880DE /* Prototype.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Prototype.swift; sourceTree = ""; }; + B5D339AE1E925BF200C880DE /* ObjectModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectModel.swift; sourceTree = ""; }; B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicModelTests.swift; sourceTree = ""; }; + B5D339D71E9489AB00C880DE /* ManagedObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObject.swift; sourceTree = ""; }; + B5D339DC1E9489C700C880DE /* ManagedObjectProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObjectProtocol.swift; sourceTree = ""; }; + B5D339E11E948C3600C880DE /* Attribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Attribute.swift; sourceTree = ""; }; + B5D339E61E9493A500C880DE /* Entity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Entity.swift; sourceTree = ""; }; + B5D339EB1E9495E500C880DE /* Attribute+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Attribute+Querying.swift"; sourceTree = ""; }; + B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreStrings.swift; sourceTree = ""; }; B5D372831A39CD6900F583D9 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = ""; }; B5D39A0119FD00C9000E91BB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacySQLiteStore.swift; sourceTree = ""; }; @@ -1051,7 +1081,11 @@ B57358D71E5A7F9B0094B50A /* Dynamic Models */ = { isa = PBXGroup; children = ( - B5D339AE1E925BF200C880DE /* Prototype.swift */, + B5D339E11E948C3600C880DE /* Attribute.swift */, + B5D339D71E9489AB00C880DE /* ManagedObject.swift */, + B5D339E61E9493A500C880DE /* Entity.swift */, + B5D339DC1E9489C700C880DE /* ManagedObjectProtocol.swift */, + B5D339AE1E925BF200C880DE /* ObjectModel.swift */, ); path = "Dynamic Models"; sourceTree = ""; @@ -1062,6 +1096,7 @@ 2F291E2619C6D3CF007AF63F /* CoreStore.swift */, B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */, B549F6721E56A92800FBAB2D /* CoreDataNativeType.swift */, + B5D339F01E94AF5800C880DE /* CoreStoreStrings.swift */, B5E84EDA1AFF84500064E85B /* Setup */, B5E84EE21AFF84610064E85B /* Logging */, B5E84EE91AFF846E0064E85B /* Transactions */, @@ -1178,6 +1213,7 @@ B5E84EFD1AFF847B0064E85B /* Fetching and Querying */ = { isa = PBXGroup; children = ( + B5D339EB1E9495E500C880DE /* Attribute+Querying.swift */, B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */, B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */, B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */, @@ -1589,6 +1625,7 @@ B529C2041CA4A2DB007E7EBD /* CSSaveResult.swift in Sources */, B5D1E22C19FA9FBC003B2874 /* CoreStoreError.swift in Sources */, B5E84F131AFF847B0064E85B /* Where.swift in Sources */, + B5D339D81E9489AB00C880DE /* ManagedObject.swift in Sources */, B5D3F6451C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */, B596BBBB1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B5ECDBFF1CA80CBA00C7F112 /* CSWhere.swift in Sources */, @@ -1598,6 +1635,7 @@ B52FD3AA1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */, + B5D339E21E948C3600C880DE /* Attribute.swift in Sources */, B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */, B53FBA0B1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B5E84F141AFF847B0064E85B /* DataStack+Querying.swift in Sources */, @@ -1608,6 +1646,7 @@ B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */, B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */, B5E1B5A81CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */, + B5D339F11E94AF5800C880DE /* CoreStoreStrings.swift in Sources */, B56007161B4018AB00A9A8F9 /* MigrationChain.swift in Sources */, B5E1B59D1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */, B5ECDC231CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */, @@ -1656,18 +1695,20 @@ B5E84F231AFF84860064E85B /* ListMonitor.swift in Sources */, B5E84EF71AFF846E0064E85B /* UnsafeDataTransaction.swift in Sources */, B56964D41B22FFAD0075EE4A /* DataStack+Migration.swift in Sources */, + B5D339DD1E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */, B5A5F2661CAEC50F004AB9AF /* CSSelect.swift in Sources */, B5ECDBE51CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */, B5519A4A1CA1F4FB002BEF78 /* CSError.swift in Sources */, B5E84EF51AFF846E0064E85B /* BaseDataTransaction.swift in Sources */, B5E84EFB1AFF846E0064E85B /* SaveResult.swift in Sources */, + B5D339EC1E9495E500C880DE /* Attribute+Querying.swift in Sources */, B5E84F0F1AFF847B0064E85B /* From.swift in Sources */, B5FAD6A91B50A4B400714891 /* Progress+Convenience.swift in Sources */, B5E84EFC1AFF846E0064E85B /* SynchronousDataTransaction.swift in Sources */, B5E222231CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */, B5E84F281AFF84920064E85B /* NSManagedObject+Convenience.swift in Sources */, B51BE06A1B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift in Sources */, - B5D339AF1E925BF200C880DE /* Prototype.swift in Sources */, + B5D339AF1E925BF200C880DE /* ObjectModel.swift in Sources */, B5AEFAB51C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, B5E2222A1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */, B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */, @@ -1696,6 +1737,7 @@ B5E84EF41AFF846E0064E85B /* AsynchronousDataTransaction.swift in Sources */, B5DBE2CD1C9914A900B5CEFA /* CSCoreStore.swift in Sources */, B546F95D1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, + B5D339E71E9493A500C880DE /* Entity.swift in Sources */, B5ECDC0B1CA8161B00C7F112 /* CSGroupBy.swift in Sources */, B5E84F151AFF847B0064E85B /* CoreStore+Querying.swift in Sources */, B5E84F241AFF84860064E85B /* ListObserver.swift in Sources */, @@ -1747,6 +1789,7 @@ B529C2061CA4A2DB007E7EBD /* CSSaveResult.swift in Sources */, 82BA18AE1C4BBD3100A0916E /* DataStack+Transaction.swift in Sources */, 82BA18AB1C4BBD3100A0916E /* AsynchronousDataTransaction.swift in Sources */, + B5D339D91E9489AB00C880DE /* ManagedObject.swift in Sources */, 82BA18CE1C4BBD7100A0916E /* FetchedResultsControllerDelegate.swift in Sources */, B596BBBC1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B5ECDC011CA80CBA00C7F112 /* CSWhere.swift in Sources */, @@ -1756,6 +1799,7 @@ B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, B5FE4DAD1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */, + B5D339E31E948C3600C880DE /* Attribute.swift in Sources */, 82BA18C51C4BBD5300A0916E /* ListObserver.swift in Sources */, B53FBA0D1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, 82BA18C21C4BBD5300A0916E /* ObjectMonitor.swift in Sources */, @@ -1766,6 +1810,7 @@ B5C976E41C6C9F9A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */, B53FBA141CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */, B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */, + B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */, B5D3F6461C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */, B5E1B59F1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */, B5ECDC251CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */, @@ -1814,18 +1859,20 @@ 82BA18D11C4BBD7100A0916E /* NotificationObserver.swift in Sources */, 82BA18BB1C4BBD4A00A0916E /* Where.swift in Sources */, B5A5F2681CAEC50F004AB9AF /* CSSelect.swift in Sources */, + B5D339DE1E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */, B5ECDBE71CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */, B5519A4B1CA1F4FB002BEF78 /* CSError.swift in Sources */, 82BA18D71C4BBD7100A0916E /* NSManagedObjectModel+Setup.swift in Sources */, 82BA18C31C4BBD5300A0916E /* ObjectObserver.swift in Sources */, 82BA18BF1C4BBD5300A0916E /* SectionBy.swift in Sources */, + B5D339ED1E9495E500C880DE /* Attribute+Querying.swift in Sources */, 82BA18AC1C4BBD3100A0916E /* SynchronousDataTransaction.swift in Sources */, 82BA18C71C4BBD5900A0916E /* CoreStore+Migration.swift in Sources */, B5E222251CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */, 82BA18C41C4BBD5300A0916E /* ListMonitor.swift in Sources */, 82BA18BA1C4BBD4A00A0916E /* Select.swift in Sources */, B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, - B5D339B01E925BF200C880DE /* Prototype.swift in Sources */, + B5D339B01E925BF200C880DE /* ObjectModel.swift in Sources */, B5E2222C1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */, 82BA18A71C4BBD2900A0916E /* CoreStore+Logging.swift in Sources */, 82BA18D81C4BBD7100A0916E /* WeakObject.swift in Sources */, @@ -1854,6 +1901,7 @@ B5DBE2CE1C9914A900B5CEFA /* CSCoreStore.swift in Sources */, B546F95E1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, B5ECDC0D1CA8161B00C7F112 /* CSGroupBy.swift in Sources */, + B5D339E81E9493A500C880DE /* Entity.swift in Sources */, 82BA18CC1C4BBD6400A0916E /* Progress+Convenience.swift in Sources */, 82BA18C01C4BBD5300A0916E /* DataStack+Observing.swift in Sources */, 82BA18A61C4BBD2900A0916E /* DefaultLogger.swift in Sources */, @@ -1905,6 +1953,7 @@ B546F9761C9C553300D5AC55 /* SetupResult.swift in Sources */, B53FBA161CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */, B5ECDC271CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */, + B5D339DB1E9489AB00C880DE /* ManagedObject.swift in Sources */, B52DD1951BE1F92500949AFE /* CoreStoreError.swift in Sources */, B596BBBE1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B546F9601C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, @@ -1914,6 +1963,7 @@ B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B5ECDC2D1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */, B5D7A5BA1CA3BF8F005C752B /* CSInto.swift in Sources */, + B5D339E51E948C3600C880DE /* Attribute.swift in Sources */, B5A5F26A1CAEC50F004AB9AF /* CSSelect.swift in Sources */, B5220E1B1D13079B009BC71E /* CSCoreStore+Observing.swift in Sources */, B5FEC1911C9166E700532541 /* NSPersistentStore+Setup.swift in Sources */, @@ -1924,6 +1974,7 @@ B5220E1C1D130801009BC71E /* FetchedResultsControllerDelegate.swift in Sources */, B52DD19E1BE1F92C00949AFE /* AsynchronousDataTransaction.swift in Sources */, B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */, + B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */, B5220E241D13085E009BC71E /* NSFetchedResultsController+Convenience.swift in Sources */, B559CD471CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, B5ECDBF01CA6BF2000C7F112 /* CSFrom.swift in Sources */, @@ -1972,18 +2023,20 @@ B52DD1CA1BE1F94600949AFE /* NSManagedObjectModel+Setup.swift in Sources */, B52DD1A41BE1F92F00949AFE /* ImportableObject.swift in Sources */, B5220E161D13067C009BC71E /* ObjectMonitor.swift in Sources */, + B5D339E01E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */, B52DD1AE1BE1F93900949AFE /* OrderBy.swift in Sources */, B52DD1BA1BE1F94000949AFE /* MigrationChain.swift in Sources */, B50392FB1C479640009900CA /* NSManagedObject+Transaction.swift in Sources */, B52DD1A31BE1F92C00949AFE /* SaveResult.swift in Sources */, B5220E211D130816009BC71E /* CSObjectObserver.swift in Sources */, + B5D339EF1E9495E500C880DE /* Attribute+Querying.swift in Sources */, B52DD19F1BE1F92C00949AFE /* SynchronousDataTransaction.swift in Sources */, B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */, B52DD1C11BE1F94600949AFE /* Functions.swift in Sources */, B5220E1A1D130791009BC71E /* CoreStoreFetchedResultsController.swift in Sources */, B53FBA0F1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */, - B5D339B21E925BF200C880DE /* Prototype.swift in Sources */, + B5D339B21E925BF200C880DE /* ObjectModel.swift in Sources */, B52DD19A1BE1F92800949AFE /* CoreStore+Logging.swift in Sources */, B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */, B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */, @@ -2012,6 +2065,7 @@ B5DBE2D51C991B3E00B5CEFA /* CSDataStack.swift in Sources */, B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */, + B5D339EA1E9493A500C880DE /* Entity.swift in Sources */, B52DD1AA1BE1F93500949AFE /* ClauseTypes.swift in Sources */, B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */, B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, @@ -2063,6 +2117,7 @@ B529C2071CA4A2DC007E7EBD /* CSSaveResult.swift in Sources */, B563219D1BD65216006C9394 /* DataStack+Observing.swift in Sources */, B56321961BD65216006C9394 /* From.swift in Sources */, + B5D339DA1E9489AB00C880DE /* ManagedObject.swift in Sources */, B5ECDC021CA80CBA00C7F112 /* CSWhere.swift in Sources */, B596BBBD1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B5ECDC081CA8138100C7F112 /* CSOrderBy.swift in Sources */, @@ -2072,6 +2127,7 @@ B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, B563218C1BD65216006C9394 /* DataStack+Transaction.swift in Sources */, + B5D339E41E948C3600C880DE /* Attribute.swift in Sources */, B53FBA0E1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B563219E1BD65216006C9394 /* CoreStore+Observing.swift in Sources */, B5D7A5B91CA3BF8F005C752B /* CSInto.swift in Sources */, @@ -2082,6 +2138,7 @@ B53FBA151CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */, B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */, B5D3F6471C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */, + B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */, B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */, B5ECDC261CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */, B563217F1BD65216006C9394 /* CoreStore.swift in Sources */, @@ -2130,18 +2187,20 @@ B563219A1BD65216006C9394 /* GroupBy.swift in Sources */, B5ECDBE81CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */, B5A5F2691CAEC50F004AB9AF /* CSSelect.swift in Sources */, + B5D339DF1E9489C700C880DE /* ManagedObjectProtocol.swift in Sources */, B5519A4C1CA1F4FB002BEF78 /* CSError.swift in Sources */, B563219B1BD65216006C9394 /* Tweak.swift in Sources */, B56321B51BD6521C006C9394 /* NSManagedObjectModel+Setup.swift in Sources */, B563218F1BD65216006C9394 /* ImportableObject.swift in Sources */, B56321991BD65216006C9394 /* OrderBy.swift in Sources */, + B5D339EE1E9495E500C880DE /* Attribute+Querying.swift in Sources */, B56321A51BD65216006C9394 /* MigrationChain.swift in Sources */, B563218E1BD65216006C9394 /* SaveResult.swift in Sources */, B5E222261CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */, B56321A21BD65216006C9394 /* ListObserver.swift in Sources */, B563218A1BD65216006C9394 /* SynchronousDataTransaction.swift in Sources */, B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, - B5D339B11E925BF200C880DE /* Prototype.swift in Sources */, + B5D339B11E925BF200C880DE /* ObjectModel.swift in Sources */, B5E2222D1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */, B563219F1BD65216006C9394 /* ObjectMonitor.swift in Sources */, B56321B61BD6521C006C9394 /* WeakObject.swift in Sources */, @@ -2170,6 +2229,7 @@ B5DBE2CF1C9914A900B5CEFA /* CSCoreStore.swift in Sources */, B546F95F1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, B5ECDC0E1CA8161B00C7F112 /* CSGroupBy.swift in Sources */, + B5D339E91E9493A500C880DE /* Entity.swift in Sources */, B56321A41BD65216006C9394 /* CoreStore+Migration.swift in Sources */, B56321A01BD65216006C9394 /* ObjectObserver.swift in Sources */, B56321951BD65216006C9394 /* ClauseTypes.swift in Sources */, diff --git a/CoreStoreTests/BaseTests/BaseTestCase.swift b/CoreStoreTests/BaseTests/BaseTestCase.swift index 76eeaff..5f79f40 100644 --- a/CoreStoreTests/BaseTests/BaseTestCase.swift +++ b/CoreStoreTests/BaseTests/BaseTestCase.swift @@ -37,7 +37,7 @@ class BaseTestCase: XCTestCase { @nonobjc @discardableResult - func prepareStack(configurations: [String?] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T { + func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T { let stack = DataStack( modelName: "Model", diff --git a/CoreStoreTests/BaseTests/BaseTestDataTestCase.swift b/CoreStoreTests/BaseTests/BaseTestDataTestCase.swift index a1055c1..513ed02 100644 --- a/CoreStoreTests/BaseTests/BaseTestDataTestCase.swift +++ b/CoreStoreTests/BaseTests/BaseTestDataTestCase.swift @@ -28,7 +28,7 @@ class BaseTestDataTestCase: BaseTestCase { }() @nonobjc - func prepareTestDataForStack(_ stack: DataStack, configurations: [String?] = [nil]) { + func prepareTestDataForStack(_ stack: DataStack, configurations: [ModelConfiguration] = [nil]) { try! stack.perform( synchronous: { (transaction) in diff --git a/CoreStoreTests/DynamicModelTests.swift b/CoreStoreTests/DynamicModelTests.swift index 1b73f5c..55b7625 100644 --- a/CoreStoreTests/DynamicModelTests.swift +++ b/CoreStoreTests/DynamicModelTests.swift @@ -13,7 +13,7 @@ import CoreData @testable import CoreStore -class Bird: CoreStoreManagedObject { +class Bird: ManagedObject { let species = Attribute.Required("species", default: "Swift") } @@ -28,10 +28,8 @@ class DynamicModelTests: BaseTestDataTestCase { func testDynamicModels_CanBeDeclaredCorrectly() { - let birdEntity = Entity("Bird") - let mascotEntity = Entity("Mascot") let dataStack = DataStack( - dynamicModel: ModelVersion( + dynamicModel: ObjectModel( version: "V1", entities: [ Entity("Bird"), @@ -54,14 +52,14 @@ class DynamicModelTests: BaseTestDataTestCase { stack.perform( asynchronous: { (transaction) in - let bird = Bird(transaction.create(Into(birdEntity.dynamicClass))) + let bird = transaction.create(Into()) XCTAssertEqual(bird.species*, "Swift") XCTAssertTrue(type(of: bird.species*) == String.self) bird.species .= "Sparrow" XCTAssertEqual(bird.species*, "Sparrow") - let mascot = Mascot(transaction.create(Into(mascotEntity.dynamicClass))) + let mascot = transaction.create(Into()) XCTAssertEqual(mascot.species*, "Swift") XCTAssertEqual(mascot.nickname*, nil) @@ -83,20 +81,16 @@ class DynamicModelTests: BaseTestDataTestCase { let p1 = Bird.where({ $0.species == "Sparrow" }) XCTAssertEqual(p1.predicate, Where("%K == %@", "species", "Sparrow").predicate) - let rawBird = transaction.fetchOne(From(birdEntity.dynamicClass), p1) - XCTAssertNotNil(rawBird) - - let bird = Bird(rawBird) - XCTAssertEqual(bird.species*, "Sparrow") + let bird = transaction.fetchOne(From()) + XCTAssertNotNil(bird) + XCTAssertEqual(bird!.species*, "Sparrow") let p2 = Mascot.where({ $0.nickname == "Riko" }) XCTAssertEqual(p2.predicate, Where("%K == %@", "nickname", "Riko").predicate) - let rawMascot = transaction.fetchOne(From(mascotEntity.dynamicClass), p2) - XCTAssertNotNil(rawMascot) - - let mascot = Mascot(rawMascot) - XCTAssertEqual(mascot.nickname*, "Riko") + let mascot = transaction.fetchOne(From()) + XCTAssertNotNil(mascot) + XCTAssertEqual(mascot!.nickname*, "Riko") let p3 = Mascot.where({ $0.year == 2016 }) XCTAssertEqual(p3.predicate, Where("%K == %@", "year", 2016).predicate) @@ -116,7 +110,7 @@ class DynamicModelTests: BaseTestDataTestCase { } @nonobjc - func prepareStack(_ dataStack: DataStack, configurations: [String?] = [nil], _ closure: (_ dataStack: DataStack) -> Void) { + func prepareStack(_ dataStack: DataStack, configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> Void) { do { diff --git a/CoreStoreTests/FetchTests.swift b/CoreStoreTests/FetchTests.swift index 31e56ef..92c1b5e 100644 --- a/CoreStoreTests/FetchTests.swift +++ b/CoreStoreTests/FetchTests.swift @@ -36,7 +36,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacksAndTransactions_CanFetchOneExisting() { - let configurations: [String?] = ["Config1"] + let configurations: [ModelConfiguration] = ["Config1"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -139,7 +139,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacksAndTransactions_CanFetchAllExisting() { - let configurations: [String?] = ["Config1"] + let configurations: [ModelConfiguration] = ["Config1"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -274,7 +274,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchOneFromDefaultConfiguration() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -413,7 +413,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchOneFromSingleConfiguration() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -596,7 +596,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchOneFromMultipleConfigurations() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -739,7 +739,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchAllFromDefaultConfiguration() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -948,7 +948,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchAllFromSingleConfiguration() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1185,7 +1185,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchAllFromMultipleConfigurations() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1384,7 +1384,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchCountFromDefaultConfiguration() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1507,7 +1507,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchCountFromSingleConfiguration() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1666,7 +1666,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanFetchCountFromMultipleConfigurations() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1785,7 +1785,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchOneFromDefaultConfiguration() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1932,7 +1932,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchOneFromSingleConfiguration() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -2126,7 +2126,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchOneFromMultipleConfigurations() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -2277,7 +2277,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchAllFromDefaultConfiguration() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -2494,7 +2494,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchAllFromSingleConfiguration() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -2754,7 +2754,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchAllFromMultipleConfigurations() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -2973,7 +2973,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchCountFromDefaultConfiguration() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -3104,7 +3104,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchCountFromSingleConfiguration() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -3274,7 +3274,7 @@ final class FetchTests: BaseTestDataTestCase { @objc dynamic func test_ThatTransactions_CanFetchCountFromMultipleConfigurations() { - let configurations: [String?] = [nil, "Config1", "Config2"] + let configurations: [ModelConfiguration] = [nil, "Config1", "Config2"] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) diff --git a/CoreStoreTests/FromTests.swift b/CoreStoreTests/FromTests.swift index 6a0a740..b43c979 100644 --- a/CoreStoreTests/FromTests.swift +++ b/CoreStoreTests/FromTests.swift @@ -38,7 +38,7 @@ final class FromTests: BaseTestCase { do { - let from = From() + let from = From() XCTAssert(from.entityClass === NSManagedObject.self) XCTAssertNil(from.configurations) } diff --git a/CoreStoreTests/IntoTests.swift b/CoreStoreTests/IntoTests.swift index d101476..3f5f2be 100644 --- a/CoreStoreTests/IntoTests.swift +++ b/CoreStoreTests/IntoTests.swift @@ -36,7 +36,7 @@ final class IntoTests: XCTestCase { @objc dynamic func test_ThatIntoClauseConstants_AreCorrect() { - XCTAssertEqual(Into.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME") + XCTAssertEqual(DataStack.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME") } @objc @@ -44,7 +44,7 @@ final class IntoTests: XCTestCase { do { - let into = Into() + let into = Into() XCTAssert(into.entityClass === NSManagedObject.self) XCTAssertNil(into.configuration) XCTAssertTrue(into.inferStoreIfPossible) @@ -58,14 +58,7 @@ final class IntoTests: XCTestCase { } do { - let into = Into() - XCTAssert(into.entityClass === TestEntity1.self) - XCTAssertNil(into.configuration) - XCTAssertTrue(into.inferStoreIfPossible) - } - do { - - let into = Into(TestEntity1.self as AnyClass) + let into = Into(TestEntity1.self) XCTAssert(into.entityClass === TestEntity1.self) XCTAssertNil(into.configuration) XCTAssertTrue(into.inferStoreIfPossible) @@ -84,13 +77,6 @@ final class IntoTests: XCTestCase { XCTAssertEqual(into.configuration, "Config1") XCTAssertFalse(into.inferStoreIfPossible) } - do { - - let into = Into(TestEntity1.self as AnyClass, "Config1") - XCTAssert(into.entityClass === TestEntity1.self) - XCTAssertEqual(into.configuration, "Config1") - XCTAssertFalse(into.inferStoreIfPossible) - } } @objc @@ -98,43 +84,30 @@ final class IntoTests: XCTestCase { do { - let into = Into() - XCTAssertEqual(into, Into()) + let into = Into() XCTAssertEqual(into, Into()) - XCTAssertEqual(into, Into(NSManagedObject.self as AnyClass)) - XCTAssertFalse(into == Into()) + XCTAssertEqual(into, Into(NSManagedObject.self)) + XCTAssertNotEqual(into, Into(TestEntity1.self)) XCTAssertNotEqual(into, Into("Config1")) } do { let into = Into() XCTAssertEqual(into, Into()) - XCTAssertEqual(into, Into(TestEntity1.self as AnyClass)) - XCTAssertFalse(into == Into()) + XCTAssertEqual(into, Into(TestEntity1.self)) XCTAssertNotEqual(into, Into("Config1")) } do { - let into = Into() - XCTAssertEqual(into, Into()) - XCTAssertEqual(into, Into(TestEntity1.self as AnyClass)) - XCTAssertFalse(into == Into()) - XCTAssertNotEqual(into, Into("Config1")) - } - do { - - let into = Into(TestEntity1.self as AnyClass) + let into = Into(TestEntity1.self) XCTAssert(into == Into()) XCTAssertEqual(into, Into(TestEntity1.self)) - XCTAssertFalse(into == Into()) XCTAssertFalse(into == Into("Config1")) } do { let into = Into("Config1") XCTAssertEqual(into, Into(TestEntity1.self, "Config1")) - XCTAssertEqual(into, Into(TestEntity1.self as AnyClass, "Config1")) - XCTAssertFalse(into == Into("Config1")) XCTAssertNotEqual(into, Into("Config2")) } do { @@ -142,16 +115,14 @@ final class IntoTests: XCTestCase { let into = Into(TestEntity1.self, "Config1") XCTAssertEqual(into, Into(TestEntity1.self, "Config1")) XCTAssertEqual(into, Into("Config1")) - XCTAssertFalse(into == Into("Config1")) XCTAssertNotEqual(into, Into("Config2")) } do { - let into = Into(TestEntity1.self as AnyClass, "Config1") - XCTAssert(into == Into("Config1")) + let into = Into(TestEntity1.self, "Config1") + XCTAssertEqual(into, Into("Config1")) XCTAssertEqual(into, Into(TestEntity1.self, "Config1")) - XCTAssertFalse(into == Into("Config1")) - XCTAssertFalse(into == Into("Config2")) + XCTAssertNotEqual(into, Into("Config2")) } } @@ -160,45 +131,9 @@ final class IntoTests: XCTestCase { do { - let into = Into() + let into = Into() let objcInto = into.bridgeToObjectiveC XCTAssertEqual(into, objcInto.bridgeToSwift) } - do { - - let into = Into() - let objcInto = into.bridgeToObjectiveC - XCTAssertTrue(into == objcInto.bridgeToSwift) - } - do { - - let into = Into(TestEntity1.self as AnyClass) - let objcInto = into.bridgeToObjectiveC - XCTAssertEqual(into, objcInto.bridgeToSwift) - } - do { - - let into = Into(TestEntity1.self as AnyClass) - let objcInto = into.bridgeToObjectiveC - XCTAssertEqual(into, objcInto.bridgeToSwift) - } - do { - - let into = Into("Config1") - let objcInto = into.bridgeToObjectiveC - XCTAssertTrue(into == objcInto.bridgeToSwift) - } - do { - - let into = Into(TestEntity1.self, "Config1") - let objcInto = into.bridgeToObjectiveC - XCTAssertTrue(into == objcInto.bridgeToSwift) - } - do { - - let into = Into(TestEntity1.self as AnyClass, "Config1") - let objcInto = into.bridgeToObjectiveC - XCTAssertTrue(into == objcInto.bridgeToSwift) - } } } diff --git a/CoreStoreTests/QueryTests.swift b/CoreStoreTests/QueryTests.swift index d77b86c..215061d 100644 --- a/CoreStoreTests/QueryTests.swift +++ b/CoreStoreTests/QueryTests.swift @@ -36,7 +36,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryAttributeValue() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -220,7 +220,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryAverageValue() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -399,7 +399,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryCountValue() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -576,7 +576,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryMaximumValue() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -760,7 +760,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryMinimumValue() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -944,7 +944,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQuerySumValue() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1122,7 +1122,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryObjectIDValue() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1290,7 +1290,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryAttributes() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) @@ -1344,7 +1344,7 @@ class QueryTests: BaseTestDataTestCase { @objc dynamic func test_ThatDataStacks_CanQueryAggregates() { - let configurations: [String?] = [nil] + let configurations: [ModelConfiguration] = [nil] self.prepareStack(configurations: configurations) { (stack) in self.prepareTestDataForStack(stack, configurations: configurations) diff --git a/Sources/CoreStoreStrings.swift b/Sources/CoreStoreStrings.swift new file mode 100644 index 0000000..5dbc3db --- /dev/null +++ b/Sources/CoreStoreStrings.swift @@ -0,0 +1,66 @@ +// +// CoreStoreStrings.swift +// CoreStore +// +// Copyright © 2017 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: - XcdatamodelFilename + +/** + A `String` that pertains to the name of an *.xcdatamodeld file (without the file extension). + */ +public typealias XcdatamodelFilename = String + + +// MARK: - ModelConfiguration + +/** + An `Optional` that pertains to the name of a "Configuration" which particular groups of entities may belong to. When `nil`, pertains to the default configuration which includes all entities. + */ +public typealias ModelConfiguration = String? + + +// MARK: - ModelVersion + +/** + An `String` that pertains to the name of a versioned *.xcdatamodeld file (without the file extension). + */ +public typealias ModelVersion = String + + +// MARK: - EntityName + +/** + An `String` that pertains to an Entity name. + */ +public typealias EntityName = String + + +// MARK: - ClassName + +/** + An `String` that pertains to a dynamically-accessable class name (usable with NSClassFromString(...)). + */ +public typealias ClassName = String diff --git a/Sources/Fetching and Querying/Attribute+Querying.swift b/Sources/Fetching and Querying/Attribute+Querying.swift new file mode 100644 index 0000000..2fc367d --- /dev/null +++ b/Sources/Fetching and Querying/Attribute+Querying.swift @@ -0,0 +1,69 @@ +// +// Attribute+Querying.swift +// CoreStore +// +// Copyright © 2017 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 CoreData +import Foundation + + +// MARK: - AttributeContainer.Required + +public extension AttributeContainer.Required where V: CVarArg { + + public static func == (_ attribute: AttributeContainer.Required, _ value: V) -> Where { + + return Where(attribute.keyPath, isEqualTo: value) + } + public static func < (_ attribute: AttributeContainer.Required, _ value: V) -> Where { + + return Where("%K < %@", attribute.keyPath, value) + } + public static func > (_ attribute: AttributeContainer.Required, _ value: V) -> Where { + + return Where("%K > %@", attribute.keyPath, value) + } + public static func <= (_ attribute: AttributeContainer.Required, _ value: V) -> Where { + + return Where("%K <= %@", attribute.keyPath, value) + } + public static func >= (_ attribute: AttributeContainer.Required, _ value: V) -> Where { + + return Where("%K >= %@", attribute.keyPath, value) + } + public static func != (_ attribute: AttributeContainer.Required, _ value: V) -> Where { + + return Where("%K != %@", attribute.keyPath, value) + } +} + + +// MARK: - AttributeContainer.Optional + +public extension AttributeContainer.Optional where V: CVarArg { + + public static func == (_ attribute: AttributeContainer.Optional, _ value: V?) -> Where { + + return Where(attribute.keyPath, isEqualTo: value) + } +} diff --git a/Sources/Fetching and Querying/BaseDataTransaction+Querying.swift b/Sources/Fetching and Querying/BaseDataTransaction+Querying.swift index a658e83..5e07541 100644 --- a/Sources/Fetching and Querying/BaseDataTransaction+Querying.swift +++ b/Sources/Fetching and Querying/BaseDataTransaction+Querying.swift @@ -121,7 +121,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s */ - public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> T? { + public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> T? { CoreStore.assert( self.isRunningInAllowedQueue(), @@ -137,7 +137,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource { - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s */ - public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> T? { + public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> T? { CoreStore.assert( self.isRunningInAllowedQueue(), diff --git a/Sources/Fetching and Querying/Concrete Clauses/From.swift b/Sources/Fetching and Querying/Concrete Clauses/From.swift index c294958..e9fa23b 100644 --- a/Sources/Fetching and Querying/Concrete Clauses/From.swift +++ b/Sources/Fetching and Querying/Concrete Clauses/From.swift @@ -39,18 +39,18 @@ import CoreData let person = transaction.fetchOne(From("Configuration1")) ``` */ -public struct From { +public struct From { /** - The associated `NSManagedObject` entity class + The associated `NSManagedObject` or `ManagedObject` entity class */ - public let entityClass: AnyClass + public let entityClass: T.Type /** The `NSPersistentStore` configuration names to associate objects from. May contain `String`s to pertain to named configurations, or `nil` to pertain to the default configuration */ - public let configurations: [String?]? + public let configurations: [ModelConfiguration]? /** Initializes a `From` clause. @@ -68,38 +68,22 @@ public struct From { ``` let people = transaction.fetchAll(From()) ``` - - parameter entity: the associated `NSManagedObject` type + - parameter entity: the associated `NSManagedObject` or `ManagedObject` type */ public init(_ entity: T.Type) { self.init(entityClass: entity, configurations: nil) } - /** - Initializes a `From` clause with the specified entity class. - ``` - let people = transaction.fetchAll(From()) - ``` - - parameter entityClass: the associated `NSManagedObject` entity class - */ - public init(_ entityClass: AnyClass) { - - CoreStore.assert( - entityClass is T.Type, - "Attempted to create generic type \(cs_typeName(From.self)) with entity class \(cs_typeName(entityClass))" - ) - self.init(entityClass: entityClass, configurations: nil) - } - /** Initializes a `From` clause with the specified configurations. ``` let people = transaction.fetchAll(From(nil, "Configuration1")) ``` - - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. + - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `ManagedObject`'s entity type. Set to `nil` to use the default configuration. - parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter) */ - public init(_ configuration: String?, _ otherConfigurations: String?...) { + public init(_ configuration: ModelConfiguration, _ otherConfigurations: ModelConfiguration...) { self.init(entityClass: T.self, configurations: [configuration] + otherConfigurations) } @@ -109,9 +93,9 @@ public struct From { ``` let people = transaction.fetchAll(From(["Configuration1", "Configuration2"])) ``` - - parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. + - parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `ManagedObject`'s entity type. Set to `nil` to use the default configuration. */ - public init(_ configurations: [String?]) { + public init(_ configurations: [ModelConfiguration]) { self.init(entityClass: T.self, configurations: configurations) } @@ -121,11 +105,11 @@ public struct From { ``` let people = transaction.fetchAll(From(MyPersonEntity.self, nil, "Configuration1")) ``` - - parameter entity: the associated `NSManagedObject` type - - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. + - parameter entity: the associated `NSManagedObject` or `ManagedObject` type + - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `ManagedObject`'s entity type. Set to `nil` to use the default configuration. - parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter) */ - public init(_ entity: T.Type, _ configuration: String?, _ otherConfigurations: String?...) { + public init(_ entity: T.Type, _ configuration: ModelConfiguration, _ otherConfigurations: ModelConfiguration...) { self.init(entityClass: entity, configurations: [configuration] + otherConfigurations) } @@ -135,55 +119,29 @@ public struct From { ``` let people = transaction.fetchAll(From(MyPersonEntity.self, ["Configuration1", "Configuration1"])) ``` - - parameter entity: the associated `NSManagedObject` type - - parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. + - parameter entity: the associated `NSManagedObject` or `ManagedObject` type + - parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `ManagedObject`'s entity type. Set to `nil` to use the default configuration. */ - public init(_ entity: T.Type, _ configurations: [String?]) { + public init(_ entity: T.Type, _ configurations: [ModelConfiguration]) { self.init(entityClass: entity, configurations: configurations) } - /** - Initializes a `From` clause with the specified configurations. - ``` - let people = transaction.fetchAll(From(MyPersonEntity.self, nil, "Configuration1")) - ``` - - parameter entity: the associated `NSManagedObject` entity class - - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. - - parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter) - */ - public init(_ entityClass: AnyClass, _ configuration: String?, _ otherConfigurations: String?...) { - - CoreStore.assert( - entityClass is T.Type, - "Attempted to create generic type \(cs_typeName(From.self)) with entity class \(cs_typeName(entityClass))" - ) - self.init(entityClass: entityClass, configurations: [configuration] + otherConfigurations) - } - - /** - Initializes a `From` clause with the specified configurations. - ``` - let people = transaction.fetchAll(From(MyPersonEntity.self, ["Configuration1", "Configuration1"])) - ``` - - parameter entity: the associated `NSManagedObject` entity class - - parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. - */ - public init(_ entityClass: AnyClass, _ configurations: [String?]) { - - CoreStore.assert( - entityClass is T.Type, - "Attempted to create generic type \(cs_typeName(From.self)) with entity class \(cs_typeName(entityClass))" - ) - self.init(entityClass: entityClass, configurations: configurations) - } - // MARK: Internal + internal let findPersistentStores: (_ context: NSManagedObjectContext) -> [NSPersistentStore]? + + internal init(entityClass: T.Type, configurations: [ModelConfiguration]?, findPersistentStores: @escaping (_ context: NSManagedObjectContext) -> [NSPersistentStore]?) { + + self.entityClass = entityClass + self.configurations = configurations + self.findPersistentStores = findPersistentStores + } + internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest, context: NSManagedObjectContext, applyAffectedStores: Bool = true) -> Bool { - fetchRequest.entity = context.entityDescriptionForEntityClass(self.entityClass) + fetchRequest.entity = context.parentStack!.entityDescription(for: EntityIdentifier(self.entityClass))! guard applyAffectedStores else { return true @@ -206,30 +164,21 @@ public struct From { return stores?.isEmpty == false } - internal func downcast() -> From { - - return From( - entityClass: self.entityClass, - configurations: self.configurations, - findPersistentStores: self.findPersistentStores - ) - } - // MARK: Private - private let findPersistentStores: (_ context: NSManagedObjectContext) -> [NSPersistentStore]? - - private init(entityClass: AnyClass, configurations: [String?]?) { + private init(entityClass: T.Type, configurations: [ModelConfiguration]?) { self.entityClass = entityClass self.configurations = configurations + + let entityIdentifier = EntityIdentifier(entityClass) if let configurations = configurations { - let configurationsSet = Set(configurations.map { $0 ?? Into.defaultConfigurationName }) + let configurationsSet = Set(configurations.map({ $0 ?? DataStack.defaultConfigurationName })) self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in - return context.parentStack?.persistentStoresForEntityClass(entityClass)?.filter { + return context.parentStack?.persistentStores(for: entityIdentifier)?.filter { return configurationsSet.contains($0.configurationName) } @@ -239,15 +188,8 @@ public struct From { self.findPersistentStores = { (context: NSManagedObjectContext) -> [NSPersistentStore]? in - return context.parentStack?.persistentStoresForEntityClass(entityClass) + return context.parentStack?.persistentStores(for: entityIdentifier) } } } - - private init(entityClass: AnyClass, configurations: [String?]?, findPersistentStores: @escaping (_ context: NSManagedObjectContext) -> [NSPersistentStore]?) { - - self.entityClass = entityClass - self.configurations = configurations - self.findPersistentStores = findPersistentStores - } } diff --git a/Sources/Importing/BaseDataTransaction+Importing.swift b/Sources/Importing/BaseDataTransaction+Importing.swift index 45ccdf4..2fda999 100644 --- a/Sources/Importing/BaseDataTransaction+Importing.swift +++ b/Sources/Importing/BaseDataTransaction+Importing.swift @@ -50,8 +50,7 @@ public extension BaseDataTransaction { return try autoreleasepool { - let entityType = into.entityClass as! T.Type - + let entityType = into.entityClass guard entityType.shouldInsert(from: source, in: self) else { return nil @@ -111,7 +110,7 @@ public extension BaseDataTransaction { return try sourceArray.flatMap { (source) -> T? in - let entityType = into.entityClass as! T.Type + let entityType = into.entityClass guard entityType.shouldInsert(from: source, in: self) else { return nil @@ -145,7 +144,7 @@ public extension BaseDataTransaction { return try autoreleasepool { - let entityType = into.entityClass as! T.Type + let entityType = into.entityClass let uniqueIDKeyPath = entityType.uniqueIDKeyPath guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else { @@ -198,7 +197,7 @@ public extension BaseDataTransaction { return try autoreleasepool { - let entityType = into.entityClass as! T.Type + let entityType = into.entityClass var importSourceByID = Dictionary() let sortedIDs = try autoreleasepool { diff --git a/Sources/Internal/CoreStoreFetchedResultsController.swift b/Sources/Internal/CoreStoreFetchedResultsController.swift index 251ddd0..87f376b 100644 --- a/Sources/Internal/CoreStoreFetchedResultsController.swift +++ b/Sources/Internal/CoreStoreFetchedResultsController.swift @@ -66,7 +66,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll } else { - guard let from = (fetchRequest.entity.flatMap { $0.managedObjectClassName }).flatMap(NSClassFromString).flatMap(From.init) else { + guard let from = (fetchRequest.entity.flatMap { $0.managedObjectClassName }).flatMap(NSClassFromString).flatMap({ From($0 as! T.Type) }) else { CoreStore.abort("Attempted to create a \(CoreStoreFetchedResultsController.self) without a \(cs_typeName(From.self)) clause or an \(cs_typeName(NSEntityDescription.self)).") } diff --git a/Sources/Internal/NSManagedObjectContext+CoreStore.swift b/Sources/Internal/NSManagedObjectContext+CoreStore.swift index d461551..680bd3c 100644 --- a/Sources/Internal/NSManagedObjectContext+CoreStore.swift +++ b/Sources/Internal/NSManagedObjectContext+CoreStore.swift @@ -54,25 +54,6 @@ internal extension NSManagedObjectContext { } } - @nonobjc - internal func entityDescriptionForEntityType(_ entity: NSManagedObject.Type) -> NSEntityDescription? { - - return self.entityDescriptionForEntityClass(entity) - } - - @nonobjc - internal func entityDescriptionForEntityClass(_ entity: AnyClass) -> NSEntityDescription? { - - guard let entityName = self.parentStack?.entityNameForEntityClass(entity) else { - - return nil - } - return NSEntityDescription.entity( - forEntityName: entityName, - in: self - ) - } - @nonobjc internal func setupForCoreStoreWithContextName(_ contextName: String) { diff --git a/Sources/Internal/NSManagedObjectContext+Querying.swift b/Sources/Internal/NSManagedObjectContext+Querying.swift index 7fe0c2c..9778914 100644 --- a/Sources/Internal/NSManagedObjectContext+Querying.swift +++ b/Sources/Internal/NSManagedObjectContext+Querying.swift @@ -95,14 +95,13 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource { } @nonobjc - public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> T? { - + public func fetchOne(_ from: From, _ fetchClauses: FetchClause...) -> T? { return self.fetchOne(from, fetchClauses) } @nonobjc - public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> T? { + public func fetchOne(_ from: From, _ fetchClauses: [FetchClause]) -> T? { let fetchRequest = CoreStoreFetchRequest() let storeFound = from.applyToFetchRequest(fetchRequest, context: self) @@ -116,6 +115,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource { return nil } return self.fetchOne(fetchRequest.dynamicCast()) + .flatMap(from.entityClass.cs_from) } @nonobjc diff --git a/Sources/Internal/NSManagedObjectModel+Setup.swift b/Sources/Internal/NSManagedObjectModel+Setup.swift index 3fe06dd..b5e9c17 100644 --- a/Sources/Internal/NSManagedObjectModel+Setup.swift +++ b/Sources/Internal/NSManagedObjectModel+Setup.swift @@ -157,22 +157,50 @@ internal extension NSManagedObjectModel { } @nonobjc - internal func entityNameForClass(_ entityClass: AnyClass) -> String { + internal var entityDescriptionsByEntityIdentifier: [EntityIdentifier: NSEntityDescription] { - return self.entityNameMapping[NSStringFromClass(entityClass)]! - } - - @nonobjc - internal func entityTypesMapping() -> [String: NSManagedObject.Type] { - - var mapping = [String: NSManagedObject.Type]() - self.entityNameMapping.forEach { (className, entityName) in + if let mapping: NSDictionary = cs_getAssociatedObjectForKey(&PropertyKeys.objectClassNamesByEntityName, inObject: self) { - mapping[entityName] = (NSClassFromString(className)! as! NSManagedObject.Type) + return mapping as! [EntityIdentifier: NSEntityDescription] } + + var mapping: [EntityIdentifier: NSEntityDescription] = [:] + self.entities.forEach { (entityDescription) in + + let entityIdentifier = EntityIdentifier(entityDescription) + mapping[entityIdentifier] = entityDescription + } + cs_setAssociatedCopiedObject( + mapping as NSDictionary, + forKey: &PropertyKeys.objectClassNamesByEntityName, + inObject: self + ) return mapping } + // TODO: remove +// @nonobjc +// internal func entityNames(for type: NSManagedObject.Type) -> Set { +// +// let className = NSStringFromClass(type) +// return Set( +// self.objectClassNamesByEntityName +// .filter({ $0.value == className }) +// .map({ $0.key }) +// ) +// } +// +// @nonobjc +// internal func entityTypesMapping() -> [EntityName: NSManagedObject.Type] { +// +// var mapping = [EntityName: NSManagedObject.Type]() +// self.objectClassNamesByEntityName.forEach { (entityName, className) in +// +// mapping[entityName] = (NSClassFromString(className)! as! NSManagedObject.Type) +// } +// return mapping +// } + @nonobjc internal func mergedModels() -> [NSManagedObjectModel] { @@ -256,39 +284,9 @@ internal extension NSManagedObjectModel { } } - @nonobjc - private var entityNameMapping: [String: String] { - - get { - - if let mapping: NSDictionary = cs_getAssociatedObjectForKey(&PropertyKeys.entityNameMapping, inObject: self) { - - return mapping as! [String: String] - } - - var mapping = [String: String]() - self.entities.forEach { // TODO: use AnyEntity as mapping key - - guard let entityName = $0.name else { - - return - } - - let className = $0.managedObjectClassName - mapping[className!] = entityName - } - cs_setAssociatedCopiedObject( - mapping as NSDictionary, - forKey: &PropertyKeys.entityNameMapping, - inObject: self - ) - return mapping - } - } - private struct PropertyKeys { - static var entityNameMapping: Void? + static var objectClassNamesByEntityName: Void? static var modelVersionFileURL: Void? static var modelVersions: Void? diff --git a/Sources/Internal/NSPersistentStoreCoordinator+Setup.swift b/Sources/Internal/NSPersistentStoreCoordinator+Setup.swift index 04e79b2..8bba039 100644 --- a/Sources/Internal/NSPersistentStoreCoordinator+Setup.swift +++ b/Sources/Internal/NSPersistentStoreCoordinator+Setup.swift @@ -72,7 +72,7 @@ internal extension NSPersistentStoreCoordinator { } @nonobjc - internal func addPersistentStoreSynchronously(_ storeType: String, configuration: String?, URL storeURL: URL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore { + internal func addPersistentStoreSynchronously(_ storeType: String, configuration: ModelConfiguration, URL storeURL: URL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore { var store: NSPersistentStore? var storeError: NSError? diff --git a/Sources/ObjectiveC/CSCoreStore+Setup.swift b/Sources/ObjectiveC/CSCoreStore+Setup.swift index 1fb3627..7774516 100644 --- a/Sources/ObjectiveC/CSCoreStore+Setup.swift +++ b/Sources/ObjectiveC/CSCoreStore+Setup.swift @@ -44,21 +44,9 @@ public extension CSCoreStore { Returns the entity name-to-class type mapping from the `defaultStack`'s model. */ @objc - public static var entityClassesByName: [String: NSManagedObject.Type] { + public static func entityTypesByNameForType(_ type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] { - return CoreStore.entityTypesByName - } - - /** - Returns the entity class for the given entity name from the `defaultStack`'s model. - - - parameter name: the entity name - - returns: the `NSManagedObject` class for the given entity name, or `nil` if not found - */ - @objc - public static func entityClassWithName(_ name: String) -> NSManagedObject.Type? { - - return CoreStore.entityTypesByName[name] + return CoreStore.entityTypesByName(for: type) } /** @@ -137,4 +125,30 @@ public extension CSCoreStore { return self.defaultStack.addSQLiteStorageAndWait(storage, error: error) } + + + // MARK: Deprecated + + /** + Returns the entity name-to-class type mapping from the `defaultStack`'s model. + */ + @available(*, deprecated: 3.1, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.") + @objc + public static var entityClassesByName: [EntityName: NSManagedObject.Type] { + + return CoreStore.entityTypesByName + } + + /** + Returns the entity class for the given entity name from the `defaultStack`'s model. + + - parameter name: the entity name + - returns: the `NSManagedObject` class for the given entity name, or `nil` if not found + */ + @available(*, deprecated: 3.1, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.") + @objc + public static func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? { + + return CoreStore.entityTypesByName[name] + } } diff --git a/Sources/ObjectiveC/CSDataStack.swift b/Sources/ObjectiveC/CSDataStack.swift index 386dd27..f8bacdc 100644 --- a/Sources/ObjectiveC/CSDataStack.swift +++ b/Sources/ObjectiveC/CSDataStack.swift @@ -54,7 +54,7 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType { - parameter versionChain: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. */ @objc - public convenience init(modelName: String?, bundle: Bundle?, versionChain: [String]?) { + public convenience init(modelName: XcdatamodelFilename?, bundle: Bundle?, versionChain: [String]?) { self.init( DataStack( @@ -73,7 +73,7 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType { - parameter versionTree: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. */ @objc - public convenience init(modelName: String?, bundle: Bundle?, versionTree: [String: String]?) { + public convenience init(modelName: XcdatamodelFilename?, bundle: Bundle?, versionTree: [String: String]?) { self.init( DataStack( @@ -128,23 +128,12 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType { } /** - Returns the entity name-to-class type mapping from the stack's model. + Returns the entity name-to-class type mapping from the `CSDataStack`'s model. */ @objc - public var entityClassesByName: [String: NSManagedObject.Type] { + public func entityTypesByNameForType(_ type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] { - return self.bridgeToSwift.entityTypesByName - } - - /** - Returns the entity class for the given entity name from the stack's's model. - - parameter name: the entity name - - returns: the `NSManagedObject` class for the given entity name, or `nil` if not found - */ - @objc - public func entityClassWithName(_ name: String) -> NSManagedObject.Type? { - - return self.bridgeToSwift.entityTypesByName[name] + return self.bridgeToSwift.entityTypesByName(for: type) } /** @@ -268,6 +257,31 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType { self.bridgeToSwift = swiftValue super.init() } + + + // MARK: Deprecated + + /** + Returns the entity name-to-class type mapping from the stack's model. + */ + @available(*, deprecated: 3.1, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.") + @objc + public var entityClassesByName: [EntityName: NSManagedObject.Type] { + + return self.bridgeToSwift.entityTypesByName + } + + /** + Returns the entity class for the given entity name from the stack's's model. + - parameter name: the entity name + - returns: the `NSManagedObject` class for the given entity name, or `nil` if not found + */ + @available(*, deprecated: 3.1, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.") + @objc + public func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? { + + return self.bridgeToSwift.entityTypesByName[name] + } } diff --git a/Sources/ObjectiveC/CSFrom.swift b/Sources/ObjectiveC/CSFrom.swift index 66677aa..0c913ec 100644 --- a/Sources/ObjectiveC/CSFrom.swift +++ b/Sources/ObjectiveC/CSFrom.swift @@ -35,7 +35,7 @@ import CoreData - SeeAlso: `From` */ @objc -public final class CSFrom: NSObject, CoreStoreObjectiveCType { +public final class CSFrom: NSObject { /** The associated `NSManagedObject` entity class @@ -71,7 +71,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType { - parameter entityClass: the `NSManagedObject` class type to be created */ @objc - public convenience init(entityClass: AnyClass) { + public convenience init(entityClass: NSManagedObject.Type) { self.init(From(entityClass)) } @@ -85,7 +85,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType { - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. */ @objc - public convenience init(entityClass: AnyClass, configuration: Any) { + public convenience init(entityClass: NSManagedObject.Type, configuration: Any) { switch configuration { @@ -111,9 +111,9 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType { - parameter configurations: an array of the `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. */ @objc - public convenience init(entityClass: AnyClass, configurations: [Any]) { + public convenience init(entityClass: NSManagedObject.Type, configurations: [Any]) { - var arguments = [String?]() + var arguments = [ModelConfiguration]() for configuration in configurations { switch configuration { @@ -154,7 +154,7 @@ public final class CSFrom: NSObject, CoreStoreObjectiveCType { // MARK: - From -extension From: CoreStoreSwiftType { +extension From where T: NSManagedObject { // MARK: CoreStoreSwiftType @@ -162,4 +162,16 @@ extension From: CoreStoreSwiftType { return CSFrom(self) } + + + // MARK: FilePrivate + + fileprivate func downcast() -> From { + + return From( + entityClass: self.entityClass, + configurations: self.configurations, + findPersistentStores: self.findPersistentStores + ) + } } diff --git a/Sources/ObjectiveC/CSInMemoryStore.swift b/Sources/ObjectiveC/CSInMemoryStore.swift index 1efc847..d98c4ad 100644 --- a/Sources/ObjectiveC/CSInMemoryStore.swift +++ b/Sources/ObjectiveC/CSInMemoryStore.swift @@ -43,7 +43,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. */ @objc - public convenience init(configuration: String?) { + public convenience init(configuration: ModelConfiguration) { self.init(InMemoryStore(configuration: configuration)) } @@ -70,7 +70,7 @@ public final class CSInMemoryStore: NSObject, CSStorageInterface, CoreStoreObjec The configuration name in the model file */ @objc - public var configuration: String? { + public var configuration: ModelConfiguration { return self.bridgeToSwift.configuration } diff --git a/Sources/ObjectiveC/CSInto.swift b/Sources/ObjectiveC/CSInto.swift index 4e783bb..0510b32 100644 --- a/Sources/ObjectiveC/CSInto.swift +++ b/Sources/ObjectiveC/CSInto.swift @@ -35,13 +35,13 @@ import CoreData - SeeAlso: `Into` */ @objc -public final class CSInto: NSObject, CoreStoreObjectiveCType { +public final class CSInto: NSObject { /** The associated `NSManagedObject` entity class */ @objc - public var entityClass: AnyClass { + public var entityClass: NSManagedObject.Type { return self.bridgeToSwift.entityClass } @@ -51,7 +51,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType { May contain a `String` to pertain to a named configuration, or `nil` to pertain to the default configuration */ @objc - public var configuration: String? { + public var configuration: ModelConfiguration { return self.bridgeToSwift.configuration } @@ -65,7 +65,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType { - parameter entityClass: the `NSManagedObject` class type to be created */ @objc - public convenience init(entityClass: AnyClass) { + public convenience init(entityClass: NSManagedObject.Type) { self.init(Into(entityClass)) } @@ -80,7 +80,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType { - parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. */ @objc - public convenience init(entityClass: AnyClass, configuration: String?) { + public convenience init(entityClass: NSManagedObject.Type, configuration: ModelConfiguration) { self.init(Into(entityClass, configuration)) } @@ -122,7 +122,7 @@ public final class CSInto: NSObject, CoreStoreObjectiveCType { // MARK: - Into -extension Into: CoreStoreSwiftType { +extension Into where T: NSManagedObject { // MARK: CoreStoreSwiftType @@ -130,4 +130,16 @@ extension Into: CoreStoreSwiftType { return CSInto(self) } + + + // MARK: FilePrivate + + fileprivate func downcast() -> Into { + + return Into( + entityClass: self.entityClass, + configuration: self.configuration, + inferStoreIfPossible: self.inferStoreIfPossible + ) + } } diff --git a/Sources/ObjectiveC/CSSQliteStore.swift b/Sources/ObjectiveC/CSSQliteStore.swift index 6ef96c9..5bb5164 100644 --- a/Sources/ObjectiveC/CSSQliteStore.swift +++ b/Sources/ObjectiveC/CSSQliteStore.swift @@ -46,7 +46,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT - parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `CSLocalStorageOptionsNone`. */ @objc - public convenience init(fileURL: URL, configuration: String?, mappingModelBundles: [Bundle]?, localStorageOptions: Int) { + public convenience init(fileURL: URL, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) { self.init( SQLiteStore( @@ -68,7 +68,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT - parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `[CSLocalStorageOptions none]`. */ @objc - public convenience init(fileName: String, configuration: String?, mappingModelBundles: [Bundle]?, localStorageOptions: Int) { + public convenience init(fileName: String, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) { self.init( SQLiteStore( @@ -133,7 +133,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT /** The configuration name in the model file */ - public var configuration: String? { + public var configuration: ModelConfiguration { return self.bridgeToSwift.configuration } diff --git a/Sources/ObjectiveC/CSStorageInterface.swift b/Sources/ObjectiveC/CSStorageInterface.swift index 44681f3..a18cb74 100644 --- a/Sources/ObjectiveC/CSStorageInterface.swift +++ b/Sources/ObjectiveC/CSStorageInterface.swift @@ -47,7 +47,7 @@ public protocol CSStorageInterface { The configuration name in the model file */ @objc - var configuration: String? { get } + var configuration: ModelConfiguration { get } /** The options dictionary for the `NSPersistentStore` diff --git a/Sources/ObjectiveC/NSFetchedResultsController+ObjectiveC.swift b/Sources/ObjectiveC/NSFetchedResultsController+ObjectiveC.swift index ed7de1f..bd81d1f 100644 --- a/Sources/ObjectiveC/NSFetchedResultsController+ObjectiveC.swift +++ b/Sources/ObjectiveC/NSFetchedResultsController+ObjectiveC.swift @@ -88,7 +88,7 @@ fileprivate func createFRC(fromContext context: NSManagedObjectContext, from: CS let controller = CoreStoreFetchedResultsController( context: context, fetchRequest: CoreStoreFetchRequest().dynamicCast(), - from: from?.bridgeToSwift.downcast(), + from: from?.bridgeToSwift, sectionBy: sectionBy?.bridgeToSwift, applyFetchClauses: { (fetchRequest) in diff --git a/Sources/Setup/CoreStore+Setup.swift b/Sources/Setup/CoreStore+Setup.swift index d1c57ef..a30ad63 100644 --- a/Sources/Setup/CoreStore+Setup.swift +++ b/Sources/Setup/CoreStore+Setup.swift @@ -42,9 +42,17 @@ public extension CoreStore { /** Returns the entity name-to-class type mapping from the `defaultStack`'s model. */ - public static var entityTypesByName: [String: NSManagedObject.Type] { + public static func entityTypesByName(for type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] { - return self.defaultStack.entityTypesByName + return self.defaultStack.entityTypesByName(for: type) + } + + /** + Returns the entity name-to-class type mapping from the `defaultStack`'s model. + */ + public static func entityTypesByName(for type: ManagedObject.Type) -> [EntityName: ManagedObject.Type] { + + return self.defaultStack.entityTypesByName(for: type) } /** @@ -55,6 +63,14 @@ public extension CoreStore { return self.defaultStack.entityDescription(for: type) } + /** + Returns the `NSEntityDescription` for the specified `ManagedObject` subclass from `defaultStack`'s model. + */ + public static func entityDescription(for type: ManagedObject.Type) -> NSEntityDescription? { + + return self.defaultStack.entityDescription(for: type) + } + /** Creates an `SQLiteStore` with default parameters and adds it to the `defaultStack`. This method blocks until completion. ``` @@ -155,6 +171,18 @@ public extension CoreStore { } + // MARK: Deprecated + + /** + Returns the entity name-to-class type mapping from the `defaultStack`'s model. + */ + @available(*, deprecated: 3.1, message: "Use the new CoreStore.entityTypesByName(for:) method passing `NSManagedObject.self` as argument.") + public static var entityTypesByName: [EntityName: NSManagedObject.Type] { + + return self.defaultStack.entityTypesByName + } + + // MARK: Obsolete @available(*, obsoleted: 3.0.0, renamed: "entityDescription(for:)") diff --git a/Sources/Setup/DataStack.swift b/Sources/Setup/DataStack.swift index 8cf3eb0..9812b72 100644 --- a/Sources/Setup/DataStack.swift +++ b/Sources/Setup/DataStack.swift @@ -41,7 +41,7 @@ public final class DataStack: Equatable { - parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used. - parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. */ - public convenience init(modelName: String = DataStack.applicationName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) { + public convenience init(modelName: XcdatamodelFilename = DataStack.applicationName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) { let model = NSManagedObjectModel.fromBundle( bundle, @@ -51,12 +51,12 @@ public final class DataStack: Equatable { self.init(model: model, migrationChain: migrationChain) } - public convenience init(dynamicModel: ModelVersion) { + public convenience init(dynamicModel: ObjectModel) { self.init(model: dynamicModel.createModel()) } - public convenience init(dynamicModels: [ModelVersion], migrationChain: MigrationChain = nil) { + public convenience init(dynamicModels: [ObjectModel], migrationChain: MigrationChain = nil) { CoreStore.assert( migrationChain.valid, @@ -106,9 +106,49 @@ public final class DataStack: Equatable { /** Returns the entity name-to-class type mapping from the `DataStack`'s model. */ - public var entityTypesByName: [String: NSManagedObject.Type] { + public func entityTypesByName(for type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] { - return self.model.entityTypesMapping() + var entityTypesByName: [EntityName: NSManagedObject.Type] = [:] + for (entityIdentifier, entityDescription) in self.model.entityDescriptionsByEntityIdentifier { + + switch entityIdentifier.category { + + case .coreData: + let actualType = NSClassFromString(entityDescription.managedObjectClassName!)! as! NSManagedObject.Type + if (actualType as AnyClass).isSubclass(of: type) { + + entityTypesByName[entityDescription.name!] = actualType + } + + case .coreStore: + continue + } + } + return entityTypesByName + } + + /** + Returns the entity name-to-class type mapping from the `DataStack`'s model. + */ + public func entityTypesByName(for type: ManagedObject.Type) -> [EntityName: ManagedObject.Type] { + + var entityTypesByName: [EntityName: ManagedObject.Type] = [:] + for (entityIdentifier, entityDescription) in self.model.entityDescriptionsByEntityIdentifier { + + switch entityIdentifier.category { + + case .coreData: + continue + + case .coreStore: + let actualType = NSClassFromString(entityDescription.managedObjectClassName!)! as! ManagedObject.Type + if (actualType as AnyClass).isSubclass(of: type) { + + entityTypesByName[entityDescription.name!] = actualType + } + } + } + return entityTypesByName } /** @@ -116,10 +156,15 @@ public final class DataStack: Equatable { */ public func entityDescription(for type: NSManagedObject.Type) -> NSEntityDescription? { - return NSEntityDescription.entity( - forEntityName: self.model.entityNameForClass(type), - in: self.mainContext - ) + return self.entityDescription(for: EntityIdentifier(type)) + } + + /** + Returns the `NSEntityDescription` for the specified `ManagedObject` subclass. + */ + public func entityDescription(for type: ManagedObject.Type) -> NSEntityDescription? { + + return self.entityDescription(for: EntityIdentifier(type)) } /** @@ -408,6 +453,8 @@ public final class DataStack: Equatable { // MARK: Internal + internal static var defaultConfigurationName = "PF_DEFAULT_CONFIGURATION_NAME" + internal static let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData" internal let coordinator: NSPersistentStoreCoordinator @@ -434,34 +481,27 @@ public final class DataStack: Equatable { .first } - internal func entityNameForEntityClass(_ entityClass: AnyClass) -> String? { - - return self.model.entityNameForClass(entityClass) - } - - internal func persistentStoresForEntityClass(_ entityClass: AnyClass) -> [NSPersistentStore]? { + internal func persistentStores(for entityIdentifier: EntityIdentifier) -> [NSPersistentStore]? { var returnValue: [NSPersistentStore]? = nil self.storeMetadataUpdateQueue.sync(flags: .barrier) { - returnValue = self.entityConfigurationsMapping[NSStringFromClass(entityClass)]?.map { - - return self.configurationStoreMapping[$0]! - } ?? [] + returnValue = self.finalConfigurationsByEntityIdentifier[entityIdentifier]? + .map({ self.persistentStoresByFinalConfiguration[$0]! }) ?? [] } return returnValue } - internal func persistentStoreForEntityClass(_ entityClass: AnyClass, configuration: String?, inferStoreIfPossible: Bool) -> (store: NSPersistentStore?, isAmbiguous: Bool) { + internal func persistentStore(for entityIdentifier: EntityIdentifier, configuration: ModelConfiguration, inferStoreIfPossible: Bool) -> (store: NSPersistentStore?, isAmbiguous: Bool) { return self.storeMetadataUpdateQueue.sync(flags: .barrier) { () -> (store: NSPersistentStore?, isAmbiguous: Bool) in - let configurationsForEntity = self.entityConfigurationsMapping[NSStringFromClass(entityClass)] ?? [] + let configurationsForEntity = self.finalConfigurationsByEntityIdentifier[entityIdentifier] ?? [] if let configuration = configuration { if configurationsForEntity.contains(configuration) { - return (store: self.configurationStoreMapping[configuration], isAmbiguous: false) + return (store: self.persistentStoresByFinalConfiguration[configuration], isAmbiguous: false) } else if !inferStoreIfPossible { @@ -475,7 +515,7 @@ public final class DataStack: Equatable { return (store: nil, isAmbiguous: false) case 1 where inferStoreIfPossible: - return (store: self.configurationStoreMapping[configurationsForEntity.first!], isAmbiguous: false) + return (store: self.persistentStoresByFinalConfiguration[configurationsForEntity.first!], isAmbiguous: false) default: return (store: nil, isAmbiguous: true) @@ -496,7 +536,7 @@ public final class DataStack: Equatable { self.storeMetadataUpdateQueue.async(flags: .barrier) { let configurationName = persistentStore.configurationName - self.configurationStoreMapping[configurationName] = persistentStore + self.persistentStoresByFinalConfiguration[configurationName] = persistentStore for entityDescription in (self.coordinator.managedObjectModel.entities(forConfigurationName: configurationName) ?? []) { let managedObjectClassName = entityDescription.managedObjectClassName! @@ -504,18 +544,23 @@ public final class DataStack: Equatable { NSClassFromString(managedObjectClassName) != nil, "The class \(cs_typeName(managedObjectClassName)) for the entity \(cs_typeName(entityDescription.name)) does not exist. Check if the subclass type and module name are properly configured." ) - - if self.entityConfigurationsMapping[managedObjectClassName] == nil { + let entityIdentifier = EntityIdentifier(entityDescription) + if self.finalConfigurationsByEntityIdentifier[entityIdentifier] == nil { - self.entityConfigurationsMapping[managedObjectClassName] = [] + self.finalConfigurationsByEntityIdentifier[entityIdentifier] = [] } - self.entityConfigurationsMapping[managedObjectClassName]?.insert(configurationName) + self.finalConfigurationsByEntityIdentifier[entityIdentifier]?.insert(configurationName) } } storage.didAddToDataStack(self) return persistentStore } + internal func entityDescription(for entityIdentifier: EntityIdentifier) -> NSEntityDescription? { + + return self.model.entityDescriptionsByEntityIdentifier[entityIdentifier] + } + // MARK: Private @@ -526,8 +571,8 @@ public final class DataStack: Equatable { // return true // }() - private var configurationStoreMapping = [String: NSPersistentStore]() - private var entityConfigurationsMapping = [String: Set]() // TODO: change key to AnyEntity + private var persistentStoresByFinalConfiguration = [String: NSPersistentStore]() + private var finalConfigurationsByEntityIdentifier = [EntityIdentifier: Set]() deinit { @@ -545,6 +590,18 @@ public final class DataStack: Equatable { } + // MARK: Deprecated + + /** + Returns the entity name-to-class type mapping from the `DataStack`'s model. + */ + @available(*, deprecated: 3.1, message: "Use the new DataStack.entityTypesByName(for:) method passing `NSManagedObject.self` as argument.") + public var entityTypesByName: [EntityName: NSManagedObject.Type] { + + return self.entityTypesByName(for: NSManagedObject.self) + } + + // MARK: Obsolete @available(*, obsoleted: 3.0.0, renamed: "entityDescription(for:)") diff --git a/Sources/Setup/Dynamic Models/Attribute.swift b/Sources/Setup/Dynamic Models/Attribute.swift new file mode 100644 index 0000000..46f9a11 --- /dev/null +++ b/Sources/Setup/Dynamic Models/Attribute.swift @@ -0,0 +1,166 @@ +// +// Attribute.swift +// CoreStore +// +// Copyright © 2017 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 CoreData +import Foundation + + +// MARK: Operators + +infix operator .= : AssignmentPrecedence +postfix operator * + + +// MARK: - AttributeContainer + +public enum AttributeContainer { + + // MARK: - Required + + public final class Required: AttributeProtocol { + + public static func .= (_ attribute: AttributeContainer.Required, _ value: V) { + + attribute.value = value + } + + public static postfix func * (_ attribute: AttributeContainer.Required) -> V { + + return attribute.value + } + + public let keyPath: String + + public init(_ keyPath: String, `default`: V = V.cs_emptyValue()) { + + self.keyPath = keyPath + self.defaultValue = `default`.cs_toImportableNativeType() + } + + public var value: V { + + get { + + let object = self.accessRawObject() + let key = self.keyPath + let value = object.value(forKey: key)! as! V.ImportableNativeType + return V.cs_fromImportableNativeType(value)! + } + set { + + let object = self.accessRawObject() + let key = self.keyPath + object.setValue(newValue.cs_toImportableNativeType(), forKey: key) + } + } + + // MARK: Internal + + internal static var attributeType: NSAttributeType { + + return V.cs_rawAttributeType + } + + internal let defaultValue: Any? + internal let isOptional = false + + internal var accessRawObject: () -> NSManagedObject = { + + fatalError("\(O.self) property values should not be accessed") + } + } + + + // MARK: - Optional + + public final class Optional: AttributeProtocol { + + public static func .= (_ attribute: AttributeContainer.Optional, _ value: V?) { + + attribute.value = value + } + + public static postfix func * (_ attribute: AttributeContainer.Optional) -> V? { + + return attribute.value + } + + public let keyPath: String + + public init(_ keyPath: String, `default`: V? = nil) { + + self.keyPath = keyPath + self.defaultValue = `default`?.cs_toImportableNativeType() + } + + public var value: V? { + + get { + + let object = self.accessRawObject() + let key = self.keyPath + guard let value = object.value(forKey: key) as! V.ImportableNativeType? else { + + return nil + } + return V.cs_fromImportableNativeType(value) + } + set { + + let object = self.accessRawObject() + let key = self.keyPath + object.setValue(newValue?.cs_toImportableNativeType(), forKey: key) + } + } + + + // MARK: Internal + + internal static var attributeType: NSAttributeType { + + return V.cs_rawAttributeType + } + + internal let defaultValue: Any? + internal let isOptional = true + internal var accessRawObject: () -> NSManagedObject = { + + fatalError("\(O.self) property values should not be accessed") + } + } +} + + +// MARK: - AttributeProtocol + +internal protocol AttributeProtocol: class { + + static var attributeType: NSAttributeType { get } + + var keyPath: String { get } + var isOptional: Bool { get } + var defaultValue: Any? { get } + var accessRawObject: () -> NSManagedObject { get set } +} diff --git a/Sources/Setup/Dynamic Models/Entity.swift b/Sources/Setup/Dynamic Models/Entity.swift new file mode 100644 index 0000000..d9e45d7 --- /dev/null +++ b/Sources/Setup/Dynamic Models/Entity.swift @@ -0,0 +1,198 @@ +// +// Entity.swift +// CoreStore +// +// Copyright © 2017 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 CoreData +import Foundation +import ObjectiveC + + +// MARK: - EntityProtocol + +public protocol EntityProtocol { + + var entityDescription: NSEntityDescription { get } +} + + +// MARK: Entity + +public struct Entity: EntityProtocol { + + public let entityDescription: NSEntityDescription + internal var dynamicClass: AnyClass { + + return NSClassFromString(self.entityDescription.managedObjectClassName!)! + } + + public init(_ entityName: String) { + + let dynamicClassName = String(reflecting: O.self) + .appending("__\(entityName)") + .replacingOccurrences(of: ".", with: "_") + .replacingOccurrences(of: "<", with: "_") + .replacingOccurrences(of: ">", with: "_") + // TODO: assign entityName through ModelVersion and + // TODO: set NSEntityDescription.userInfo AnyEntity + let newClass: AnyClass? + + if NSClassFromString(dynamicClassName) == nil { + + newClass = objc_allocateClassPair(NSManagedObject.self, dynamicClassName, 0) + } + else { + + newClass = nil + } + + defer { + + if let newClass = newClass { + + objc_registerClassPair(newClass) + } + } + + let entityDescription = NSEntityDescription() + entityDescription.userInfo = [ + EntityIdentifier.UserInfoKey.CoreStoreManagedObjectName: String(reflecting: O.self) + ] + entityDescription.name = entityName + entityDescription.managedObjectClassName = NSStringFromClass(NSManagedObject.self) +// entityDescription.managedObjectClassName = dynamicClassName // TODO: return to NSManagedObject + entityDescription.properties = type(of: self).initializeAttributes(Mirror(reflecting: O.meta)) + + self.entityDescription = entityDescription + } + + private static func initializeAttributes(_ mirror: Mirror) -> [NSAttributeDescription] { + + var attributeDescriptions: [NSAttributeDescription] = [] + for child in mirror.children { + + guard case let property as AttributeProtocol = child.value else { + + continue + } + let attributeDescription = NSAttributeDescription() + attributeDescription.name = property.keyPath + attributeDescription.attributeType = type(of: property).attributeType + attributeDescription.isOptional = property.isOptional + attributeDescription.defaultValue = property.defaultValue + attributeDescriptions.append(attributeDescription) + } + if let baseEntityAttributeDescriptions = mirror.superclassMirror.flatMap(self.initializeAttributes) { + + attributeDescriptions.append(contentsOf: baseEntityAttributeDescriptions) + } + return attributeDescriptions + } +} + + +// MARK: - EntityIdentifier + +internal struct EntityIdentifier: Hashable { + + // MARK: - Category + + internal enum Category: Int { + + case coreData + case coreStore + } + + + // MARK: - + + internal let category: Category + internal let interfacedClassName: String + + internal init(_ type: NSManagedObject.Type) { + + self.category = .coreData + self.interfacedClassName = String(reflecting: type) + } + + internal init(_ type: ManagedObject.Type) { + + self.category = .coreStore + self.interfacedClassName = String(reflecting: type) + } + + internal init(_ type: ManagedObjectProtocol.Type) { + + switch type { + + case let type as NSManagedObject.Type: + self.init(type) + + case let type as ManagedObject.Type: + self.init(type) + + default: + CoreStore.abort("\(cs_typeName(ManagedObjectProtocol.self)) is not meant to be implemented by external types.") + } + } + + internal init(_ entityDescription: NSEntityDescription) { + + if let coreStoreManagedObjectName = entityDescription.userInfo?[EntityIdentifier.UserInfoKey.CoreStoreManagedObjectName] as! String? { + + self.category = .coreStore + self.interfacedClassName = coreStoreManagedObjectName + } + else { + + self.category = .coreData + self.interfacedClassName = entityDescription.managedObjectClassName! + } + } + + + // MARK: Equatable + + static func == (lhs: EntityIdentifier, rhs: EntityIdentifier) -> Bool { + + return lhs.category == rhs.category + && lhs.interfacedClassName == rhs.interfacedClassName + } + + + // MARK: Hashable + + var hashValue: Int { + + return self.category.hashValue + ^ self.interfacedClassName.hashValue + } + + + // MARK: FilePrivate + + fileprivate enum UserInfoKey { + + fileprivate static let CoreStoreManagedObjectName = "CoreStoreManagedObjectName" + } +} diff --git a/Sources/Setup/Dynamic Models/ManagedObject.swift b/Sources/Setup/Dynamic Models/ManagedObject.swift new file mode 100644 index 0000000..700aced --- /dev/null +++ b/Sources/Setup/Dynamic Models/ManagedObject.swift @@ -0,0 +1,68 @@ +// +// ManagedObject.swift +// CoreStore +// +// Copyright © 2017 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 CoreData +import Foundation + + +// MARK: - ManagedObject + +open class ManagedObject: ManagedObjectProtocol { + + public required init(_ object: NSManagedObject) { + + self.isMeta = false + self.rawObject = object + self.initializeAttributes(Mirror(reflecting: self), { [unowned object] in object }) + } + + public required init(asMeta: Void) { + + self.isMeta = true + self.rawObject = nil + } + + + // MARK: Internal + + internal let rawObject: NSManagedObject? + internal let isMeta: Bool + + + // MARK: Private + + private func initializeAttributes(_ mirror: Mirror, _ accessRawObject: @escaping () -> NSManagedObject) { + + _ = mirror.superclassMirror.flatMap({ self.initializeAttributes($0, accessRawObject) }) + for child in mirror.children { + + guard case let property as AttributeProtocol = child.value else { + + continue + } + property.accessRawObject = accessRawObject + } + } +} diff --git a/Sources/Setup/Dynamic Models/ManagedObjectProtocol.swift b/Sources/Setup/Dynamic Models/ManagedObjectProtocol.swift new file mode 100644 index 0000000..29bc548 --- /dev/null +++ b/Sources/Setup/Dynamic Models/ManagedObjectProtocol.swift @@ -0,0 +1,119 @@ +// +// ManagedObjectProtocol.swift +// CoreStore +// +// Copyright © 2017 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: - ManagedObjectProtocol + +public protocol ManagedObjectProtocol: class { + + static func cs_forceCreate(entityDescription: NSEntityDescription, into context: NSManagedObjectContext, assignTo store: NSPersistentStore) -> Self + + static func cs_from(object: NSManagedObject) -> Self +} + +public extension ManagedObjectProtocol where Self: ManagedObject { + + public typealias Attribute = AttributeContainer + + @inline(__always) + public static func keyPath(_ attribute: (Self) -> AttributeContainer.Required) -> String { + + return attribute(self.meta).keyPath + } + + @inline(__always) + public static func keyPath(_ attribute: (Self) -> AttributeContainer.Optional) -> String { + + return attribute(self.meta).keyPath + } + + @inline(__always) + public static func `where`(_ condition: (Self) -> Where) -> Where { + + return condition(self.meta) + } + + + // MARK: Internal + + internal static var meta: Self { + + return self.init(asMeta: ()) + } +} + + +// MARK: - NSManagedObject + +extension NSManagedObject: ManagedObjectProtocol { + + // MARK: ManagedObjectProtocol + + public static func cs_from(object: NSManagedObject) -> Self { + + @inline(__always) + func forceCast(_ value: Any) -> T { + + return value as! T + } + return forceCast(object) + } + + public static func cs_forceCreate(entityDescription: NSEntityDescription, into context: NSManagedObjectContext, assignTo store: NSPersistentStore) -> Self { + + let object = self.init(entity: entityDescription, insertInto: context) + defer { + + context.assign(object, to: store) + } + return object + } +} + + +// MARK: - ManagedObject + +extension ManagedObject { + + // MARK: ManagedObjectProtocol + + public static func cs_from(object: NSManagedObject) -> Self { + + return self.init(object) + } + + public static func cs_forceCreate(entityDescription: NSEntityDescription, into context: NSManagedObjectContext, assignTo store: NSPersistentStore) -> Self { + + let type = NSClassFromString(entityDescription.managedObjectClassName!)! as! NSManagedObject.Type + let object = type.init(entity: entityDescription, insertInto: context) + defer { + + context.assign(object, to: store) + } + return self.init(object) + } +} diff --git a/Sources/Setup/Dynamic Models/ObjectModel.swift b/Sources/Setup/Dynamic Models/ObjectModel.swift new file mode 100644 index 0000000..692f276 --- /dev/null +++ b/Sources/Setup/Dynamic Models/ObjectModel.swift @@ -0,0 +1,76 @@ +// +// ObjectModel.swift +// CoreStore +// +// Copyright © 2017 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 CoreGraphics +import Foundation + + +// MARK: - ObjectModel + +public final class ObjectModel { + + public let version: String + + public convenience init(version: String, entities: [EntityProtocol]) { + + self.init(version: version, configurationEntities: [DataStack.defaultConfigurationName: entities]) + } + + public required init(version: String, configurationEntities: [String: [EntityProtocol]]) { + + self.version = version + + var entityConfigurations: [String: Set] = [:] + for (configuration, entities) in configurationEntities { + + entityConfigurations[configuration] = Set(entities.map({ $0.entityDescription })) + } + let allEntities = Set(entityConfigurations.map({ $0.value }).joined()) + entityConfigurations[DataStack.defaultConfigurationName] = allEntities + + self.entityConfigurations = entityConfigurations + self.entities = allEntities + } + + + // MARK: Internal + + internal let entities: Set + internal let entityConfigurations: [String: Set] + + internal func createModel() -> NSManagedObjectModel { + + let model = NSManagedObjectModel() + model.entities = self.entities.sorted(by: { $0.name! < $1.name! }) + for (configuration, entities) in self.entityConfigurations { + + model.setEntities( + entities.sorted(by: { $0.name! < $1.name! }), + forConfigurationName: configuration + ) + } + return model + } +} diff --git a/Sources/Setup/Dynamic Models/Prototype.swift b/Sources/Setup/Dynamic Models/Prototype.swift deleted file mode 100644 index 8d77453..0000000 --- a/Sources/Setup/Dynamic Models/Prototype.swift +++ /dev/null @@ -1,324 +0,0 @@ -// -// Prototype.swift -// CoreStore -// -// Created by John Estropia on 2017/04/03. -// Copyright © 2017 John Rommel Estropia. All rights reserved. -// - -import CoreGraphics -import Foundation -import ObjectiveC - - -public protocol ManagedObjectProtocol: class {} - -public protocol EntityProtocol { - - var entityDescription: NSEntityDescription { get } -} - -internal protocol AttributeProtocol: class { - - static var attributeType: NSAttributeType { get } - var keyPath: String { get } - var defaultValue: Any? { get } - var accessRawObject: () -> NSManagedObject { get set } -} - -open class CoreStoreManagedObject: ManagedObjectProtocol { - - internal let rawObject: NSManagedObject? - internal let isMeta: Bool - - public required init(_ object: NSManagedObject?) { - - self.isMeta = object == nil - self.rawObject = object - - guard let object = object else { - - return - } - self.initializeAttributes(Mirror(reflecting: self), { [unowned object] in object }) - } - - private func initializeAttributes(_ mirror: Mirror, _ accessRawObject: @escaping () -> NSManagedObject) { - - _ = mirror.superclassMirror.flatMap({ self.initializeAttributes($0, accessRawObject) }) - for child in mirror.children { - - guard case let property as AttributeProtocol = child.value else { - - continue - } - property.accessRawObject = accessRawObject - } - } -} - -public struct Entity: EntityProtocol { - - public let entityDescription: NSEntityDescription - internal var dynamicClass: AnyClass { - - return NSClassFromString(self.entityDescription.managedObjectClassName!)! - } - - public init(_ entityName: String) { - - let dynamicClassName = String(reflecting: O.self) - .appending("__\(entityName)") - .replacingOccurrences(of: ".", with: "_") - .replacingOccurrences(of: "<", with: "_") - .replacingOccurrences(of: ">", with: "_") - // TODO: assign entityName through ModelVersion and - // TODO: set NSEntityDescription.userInfo AnyEntity - let newClass: AnyClass? - - if NSClassFromString(dynamicClassName) == nil { - - newClass = objc_allocateClassPair(NSManagedObject.self, dynamicClassName, 0) - } - else { - - newClass = nil - } - - defer { - - if let newClass = newClass { - - objc_registerClassPair(newClass) - } - } - - let entityDescription = NSEntityDescription() - entityDescription.name = entityName - entityDescription.managedObjectClassName = dynamicClassName // TODO: return to NSManagedObject - entityDescription.properties = type(of: self).initializeAttributes(Mirror(reflecting: O.meta)) - - self.entityDescription = entityDescription - } - - private static func initializeAttributes(_ mirror: Mirror) -> [NSAttributeDescription] { - - var attributeDescriptions: [NSAttributeDescription] = [] - for child in mirror.children { - - guard case let property as AttributeProtocol = child.value else { - - continue - } - let attributeDescription = NSAttributeDescription() - attributeDescription.name = property.keyPath - attributeDescription.attributeType = type(of: property).attributeType - attributeDescription.isOptional = false - attributeDescription.defaultValue = property.defaultValue - attributeDescriptions.append(attributeDescription) - } - if let baseEntityAttributeDescriptions = mirror.superclassMirror.flatMap(self.initializeAttributes) { - - attributeDescriptions.append(contentsOf: baseEntityAttributeDescriptions) - } - return attributeDescriptions - } -} - -public enum AttributeContainer { - - public final class Required: AttributeProtocol { - - static var attributeType: NSAttributeType { return V.cs_rawAttributeType } - - let keyPath: String - let defaultValue: Any? - var accessRawObject: () -> NSManagedObject = { fatalError("\(O.self) property values should not be accessed") } - - var value: V { - - get { - - let object = self.accessRawObject() - let key = self.keyPath - let value = object.value(forKey: key)! as! V.ImportableNativeType - return V.cs_fromImportableNativeType(value)! - } - set { - - let object = self.accessRawObject() - let key = self.keyPath - object.setValue(newValue.cs_toImportableNativeType(), forKey: key) - } - } - - public init(_ keyPath: String, `default`: V = V.cs_emptyValue()) { - - self.keyPath = keyPath - self.defaultValue = `default` - } - } - - public final class Optional: AttributeProtocol { - - static var attributeType: NSAttributeType { return V.cs_rawAttributeType } - - let keyPath: String - let defaultValue: Any? - var accessRawObject: () -> NSManagedObject = { fatalError("\(O.self) property values should not be accessed") } - - var value: V? { - - get { - - let object = self.accessRawObject() - let key = self.keyPath - guard let value = object.value(forKey: key) as! V.ImportableNativeType? else { - - return nil - } - return V.cs_fromImportableNativeType(value) - } - set { - - let object = self.accessRawObject() - let key = self.keyPath - object.setValue(newValue?.cs_toImportableNativeType(), forKey: key) - } - } - - public init(_ keyPath: String, `default`: V? = nil) { - - self.keyPath = keyPath - self.defaultValue = `default` - } - } -} - -public extension ManagedObjectProtocol where Self: CoreStoreManagedObject { - - public typealias Attribute = AttributeContainer - - internal static var meta: Self { - - return self.init(nil) - } - - @inline(__always) - public static func keyPath(_ attribute: (Self) -> AttributeContainer.Required) -> String { - - return attribute(self.meta).keyPath - } - - @inline(__always) - public static func keyPath(_ attribute: (Self) -> AttributeContainer.Optional) -> String { - - return attribute(self.meta).keyPath - } - - @inline(__always) - public static func `where`(_ condition: (Self) -> Where) -> Where { - - return condition(self.meta) - } -} - - -//: ### Convenience Operators - -infix operator .= : AssignmentPrecedence -public func .= (_ attribute: AttributeContainer.Required, _ value: V) { - - attribute.value = value -} -public func .= (_ attribute: AttributeContainer.Optional, _ value: V?) { - - attribute.value = value -} - -postfix operator * -public postfix func * (_ attribute: AttributeContainer.Required) -> V { - - return attribute.value -} -public postfix func * (_ attribute: AttributeContainer.Optional) -> V? { - - return attribute.value -} - -public extension AttributeContainer.Required where V: CVarArg { - - public static func == (_ attribute: AttributeContainer.Required, _ value: V) -> Where { - - return Where(attribute.keyPath, isEqualTo: value) - } - public static func < (_ attribute: AttributeContainer.Required, _ value: V) -> Where { - - return Where("%K < %@", attribute.keyPath, value) - } - public static func > (_ attribute: AttributeContainer.Required, _ value: V) -> Where { - - return Where("%K > %@", attribute.keyPath, value) - } - public static func <= (_ attribute: AttributeContainer.Required, _ value: V) -> Where { - - return Where("%K <= %@", attribute.keyPath, value) - } - public static func >= (_ attribute: AttributeContainer.Required, _ value: V) -> Where { - - return Where("%K >= %@", attribute.keyPath, value) - } - public static func != (_ attribute: AttributeContainer.Required, _ value: V) -> Where { - - return Where("%K != %@", attribute.keyPath, value) - } -} -public extension AttributeContainer.Optional where V: CVarArg { - - public static func == (_ attribute: AttributeContainer.Optional, _ value: V?) -> Where { - - return Where(attribute.keyPath, isEqualTo: value) - } -} - -public final class ModelVersion { - - public let version: String - internal let entities: Set - internal let entityConfigurations: [String: Set] - - public convenience init(version: String, entities: [EntityProtocol]) { - - self.init(version: version, configurationEntities: [Into.defaultConfigurationName: entities]) - } - - public required init(version: String, configurationEntities: [String: [EntityProtocol]]) { - - self.version = version - - var entityConfigurations: [String: Set] = [:] - for (configuration, entities) in configurationEntities { - - entityConfigurations[configuration] = Set(entities.map({ $0.entityDescription })) - } - let allEntities = Set(entityConfigurations.map({ $0.value }).joined()) - entityConfigurations[Into.defaultConfigurationName] = allEntities - - self.entityConfigurations = entityConfigurations - self.entities = allEntities - } - - internal func createModel() -> NSManagedObjectModel { - - let model = NSManagedObjectModel() - model.entities = self.entities.sorted(by: { $0.name! < $1.name! }) - for (configuration, entities) in self.entityConfigurations { - - model.setEntities( - entities.sorted(by: { $0.name! < $1.name! }), - forConfigurationName: configuration - ) - } - return model - } -} diff --git a/Sources/Setup/StorageInterfaces/ICloudStore.swift b/Sources/Setup/StorageInterfaces/ICloudStore.swift index a454a95..0582350 100644 --- a/Sources/Setup/StorageInterfaces/ICloudStore.swift +++ b/Sources/Setup/StorageInterfaces/ICloudStore.swift @@ -65,7 +65,7 @@ public final class ICloudStore: CloudStorage { - parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration. - parameter cloudStorageOptions: When the `ICloudStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. */ - public required init?(ubiquitousContentName: String, ubiquitousContentTransactionLogsSubdirectory: String, ubiquitousContainerID: String? = nil, ubiquitousPeerToken: String? = nil, configuration: String? = nil, cloudStorageOptions: CloudStorageOptions = nil) { + public required init?(ubiquitousContentName: String, ubiquitousContentTransactionLogsSubdirectory: String, ubiquitousContainerID: String? = nil, ubiquitousPeerToken: String? = nil, configuration: ModelConfiguration = nil, cloudStorageOptions: CloudStorageOptions = nil) { CoreStore.assert( !ubiquitousContentName.isEmpty, @@ -258,7 +258,7 @@ public final class ICloudStore: CloudStorage { /** The configuration name in the model file */ - public let configuration: String? + public let configuration: ModelConfiguration /** The options dictionary for the `NSPersistentStore`. For `SQLiteStore`s, this is always set to diff --git a/Sources/Setup/StorageInterfaces/InMemoryStore.swift b/Sources/Setup/StorageInterfaces/InMemoryStore.swift index 8829773..67f6874 100644 --- a/Sources/Setup/StorageInterfaces/InMemoryStore.swift +++ b/Sources/Setup/StorageInterfaces/InMemoryStore.swift @@ -37,7 +37,7 @@ public final class InMemoryStore: StorageInterface, DefaultInitializableStore { Initializes an `InMemoryStore` for the specified configuration - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. */ - public init(configuration: String?) { + public init(configuration: ModelConfiguration) { self.configuration = configuration } @@ -64,7 +64,7 @@ public final class InMemoryStore: StorageInterface, DefaultInitializableStore { /** The configuration name in the model file */ - public let configuration: String? + public let configuration: ModelConfiguration /** The options dictionary for the `NSPersistentStore`. For `InMemoryStore`s, this is always set to `nil`. diff --git a/Sources/Setup/StorageInterfaces/LegacySQLiteStore.swift b/Sources/Setup/StorageInterfaces/LegacySQLiteStore.swift index e0e1c0a..f6b4c70 100644 --- a/Sources/Setup/StorageInterfaces/LegacySQLiteStore.swift +++ b/Sources/Setup/StorageInterfaces/LegacySQLiteStore.swift @@ -44,7 +44,7 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore { - parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration. - parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. */ - public init(fileURL: URL, configuration: String? = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { + public init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { self.fileURL = fileURL self.configuration = configuration @@ -61,7 +61,7 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore { - parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration. - parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. */ - public init(fileName: String, configuration: String? = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { + public init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { self.fileURL = LegacySQLiteStore.defaultRootDirectory.appendingPathComponent( fileName, @@ -118,7 +118,7 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore { /** The configuration name in the model file */ - public let configuration: String? + public let configuration: ModelConfiguration /** The options dictionary for the `NSPersistentStore`. For `SQLiteStore`s, this is always set to diff --git a/Sources/Setup/StorageInterfaces/SQLiteStore.swift b/Sources/Setup/StorageInterfaces/SQLiteStore.swift index 815b9d7..510d95f 100644 --- a/Sources/Setup/StorageInterfaces/SQLiteStore.swift +++ b/Sources/Setup/StorageInterfaces/SQLiteStore.swift @@ -43,7 +43,7 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore { - parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration. - parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. */ - public init(fileURL: URL, configuration: String? = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { + public init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { self.fileURL = fileURL self.configuration = configuration @@ -60,7 +60,7 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore { - parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration - parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. */ - public init(fileName: String, configuration: String? = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { + public init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { self.fileURL = SQLiteStore.defaultRootDirectory .appendingPathComponent(fileName, isDirectory: false) @@ -96,7 +96,7 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore { /** The configuration name in the model file */ - public let configuration: String? + public let configuration: ModelConfiguration /** The options dictionary for the `NSPersistentStore`. For `SQLiteStore`s, this is always set to diff --git a/Sources/Setup/StorageInterfaces/StorageInterface.swift b/Sources/Setup/StorageInterfaces/StorageInterface.swift index 28444bb..6775d99 100644 --- a/Sources/Setup/StorageInterfaces/StorageInterface.swift +++ b/Sources/Setup/StorageInterfaces/StorageInterface.swift @@ -41,7 +41,7 @@ public protocol StorageInterface: class { /** The configuration name in the model file */ - var configuration: String? { get } + var configuration: ModelConfiguration { get } /** The options dictionary for the `NSPersistentStore` @@ -166,7 +166,7 @@ internal extension LocalStorage { internal func matchesPersistentStore(_ persistentStore: NSPersistentStore) -> Bool { return persistentStore.type == type(of: self).storeType - && persistentStore.configurationName == (self.configuration ?? Into.defaultConfigurationName) + && persistentStore.configurationName == (self.configuration ?? DataStack.defaultConfigurationName) && persistentStore.url == self.fileURL } } @@ -250,7 +250,7 @@ internal extension CloudStorage { internal func matchesPersistentStore(_ persistentStore: NSPersistentStore) -> Bool { guard persistentStore.type == type(of: self).storeType - && persistentStore.configurationName == (self.configuration ?? Into.defaultConfigurationName) else { + && persistentStore.configurationName == (self.configuration ?? DataStack.defaultConfigurationName) else { return false } diff --git a/Sources/Transactions/AsynchronousDataTransaction.swift b/Sources/Transactions/AsynchronousDataTransaction.swift index b3eaac3..b08c691 100644 --- a/Sources/Transactions/AsynchronousDataTransaction.swift +++ b/Sources/Transactions/AsynchronousDataTransaction.swift @@ -83,12 +83,12 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { // MARK: BaseDataTransaction /** - Creates a new `NSManagedObject` with the specified entity type. + Creates a new `NSManagedObject` or `ManagedObject` with the specified entity type. - - parameter into: the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration - - returns: a new `NSManagedObject` instance of the specified entity type. + - parameter into: the `Into` clause indicating the destination `NSManagedObject` or `ManagedObject` entity type and the destination configuration + - returns: a new `NSManagedObject` or `ManagedObject` instance of the specified entity type. */ - public override func create(_ into: Into) -> T { + public override func create(_ into: Into) -> T { CoreStore.assert( !self.isCommitted, diff --git a/Sources/Transactions/BaseDataTransaction.swift b/Sources/Transactions/BaseDataTransaction.swift index dc626d7..b640833 100644 --- a/Sources/Transactions/BaseDataTransaction.swift +++ b/Sources/Transactions/BaseDataTransaction.swift @@ -45,32 +45,36 @@ public /*abstract*/ class BaseDataTransaction { } /** - Creates a new `NSManagedObject` with the specified entity type. + Creates a new `NSManagedObject` or `ManagedObject` with the specified entity type. - - parameter into: the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration - - returns: a new `NSManagedObject` instance of the specified entity type. + - parameter into: the `Into` clause indicating the destination `NSManagedObject` or `ManagedObject` entity type and the destination configuration + - returns: a new `NSManagedObject` or `ManagedObject` instance of the specified entity type. */ - public func create(_ into: Into) -> T { + public func create(_ into: Into) -> T { - let entityClass = (into.entityClass as! T.Type) + let entityClass = into.entityClass CoreStore.assert( self.isRunningInAllowedQueue(), "Attempted to create an entity of type \(cs_typeName(entityClass)) outside its designated queue." ) let context = self.context + let dataStack = context.parentStack! + let entityIdentifier = EntityIdentifier(entityClass) if into.inferStoreIfPossible { - switch context.parentStack!.persistentStoreForEntityClass( - entityClass, + switch dataStack.persistentStore( + for: entityIdentifier, configuration: nil, inferStoreIfPossible: true ) { case (let persistentStore?, _): - let object = entityClass.createInContext(context) - context.assign(object, to: persistentStore) - return object + return entityClass.cs_forceCreate( + entityDescription: dataStack.entityDescription(for: entityIdentifier)!, + into: context, + assignTo: persistentStore + ) case (nil, true): CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.") @@ -81,17 +85,19 @@ public /*abstract*/ class BaseDataTransaction { } else { - switch context.parentStack!.persistentStoreForEntityClass( - entityClass, + switch dataStack.persistentStore( + for: entityIdentifier, configuration: into.configuration - ?? type(of: into).defaultConfigurationName, + ?? DataStack.defaultConfigurationName, inferStoreIfPossible: false ) { case (let persistentStore?, _): - let object = entityClass.createInContext(context) - context.assign(object, to: persistentStore) - return object + return entityClass.cs_forceCreate( + entityDescription: dataStack.entityDescription(for: entityIdentifier)!, + into: context, + assignTo: persistentStore + ) case (nil, true): CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.") @@ -143,7 +149,7 @@ public /*abstract*/ class BaseDataTransaction { ) CoreStore.assert( into.inferStoreIfPossible - || (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName, + || (into.configuration ?? DataStack.defaultConfigurationName) == objectID.persistentStore?.configurationName, "Attempted to update an entity of type \(cs_typeName(into.entityClass)) but the specified persistent store do not match the `NSManagedObjectID`." ) return self.fetchExisting(objectID) as? T @@ -160,11 +166,10 @@ public /*abstract*/ class BaseDataTransaction { self.isRunningInAllowedQueue(), "Attempted to delete an entity outside its designated queue." ) - guard let object = object else { - - return - } - self.context.fetchExisting(object)?.deleteFromContext() + let context = self.context + object + .flatMap(context.fetchExisting) + .flatMap(context.delete) } /** @@ -192,7 +197,7 @@ public /*abstract*/ class BaseDataTransaction { ) let context = self.context - objects.forEach { context.fetchExisting($0)?.deleteFromContext() } + objects.forEach { context.fetchExisting($0).flatMap(context.delete) } } /** diff --git a/Sources/Transactions/Into.swift b/Sources/Transactions/Into.swift index 45e273a..1c922eb 100644 --- a/Sources/Transactions/Into.swift +++ b/Sources/Transactions/Into.swift @@ -39,18 +39,18 @@ import CoreData let person = transaction.create(Into("Configuration1")) ``` */ -public struct Into: Hashable { +public struct Into: Hashable { /** - The associated `NSManagedObject` entity class + The associated `NSManagedObject` or `ManagedObject` entity class */ - public let entityClass: AnyClass + public let entityClass: T.Type /** The `NSPersistentStore` configuration name to associate objects from. May contain a `String` to pertain to a named configuration, or `nil` to pertain to the default configuration */ - public let configuration: String? + public let configuration: ModelConfiguration /** Initializes an `Into` clause. @@ -58,7 +58,7 @@ public struct Into: Hashable { let person = transaction.create(Into()) ``` */ - public init(){ + public init() { self.init(entityClass: T.self, configuration: nil, inferStoreIfPossible: true) } @@ -75,22 +75,6 @@ public struct Into: Hashable { self.init(entityClass: entity, configuration: nil, inferStoreIfPossible: true) } - /** - Initializes an `Into` clause with the specified entity class. - ``` - let person = transaction.create(Into(MyPersonEntity.self)) - ``` - - parameter entityClass: the `NSManagedObject` class type to be created - */ - public init(_ entityClass: AnyClass) { - - CoreStore.assert( - entityClass is T.Type, - "Attempted to create generic type \(cs_typeName(Into.self)) with entity class \(cs_typeName(entityClass))" - ) - self.init(entityClass: entityClass, configuration: nil, inferStoreIfPossible: true) - } - /** Initializes an `Into` clause with the specified configuration. ``` @@ -98,7 +82,7 @@ public struct Into: Hashable { ``` - parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. */ - public init(_ configuration: String?) { + public init(_ configuration: ModelConfiguration) { self.init(entityClass: T.self, configuration: configuration, inferStoreIfPossible: false) } @@ -111,32 +95,15 @@ public struct Into: Hashable { - parameter entity: the `NSManagedObject` type to be created - parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. */ - public init(_ entity: T.Type, _ configuration: String?) { + public init(_ entity: T.Type, _ configuration: ModelConfiguration) { self.init(entityClass: entity, configuration: configuration, inferStoreIfPossible: false) } - /** - Initializes an `Into` clause with the specified entity class and configuration. - ``` - let person = transaction.create(Into(MyPersonEntity.self, "Configuration1")) - ``` - - parameter entityClass: the `NSManagedObject` class type to be created - - parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. - */ - public init(_ entityClass: AnyClass, _ configuration: String?) { - - CoreStore.assert( - entityClass is T.Type, - "Attempted to create generic type \(cs_typeName(Into.self)) with entity class \(cs_typeName(entityClass))" - ) - self.init(entityClass: entityClass, configuration: configuration, inferStoreIfPossible: false) - } - // MARK: Equatable - public static func == (lhs: Into, rhs: Into) -> Bool { + public static func == (lhs: Into, rhs: Into) -> Bool { return lhs.entityClass == rhs.entityClass && lhs.configuration == rhs.configuration @@ -156,26 +123,9 @@ public struct Into: Hashable { // MARK: Internal - internal static var defaultConfigurationName: String { - - return "PF_DEFAULT_CONFIGURATION_NAME" - } - internal let inferStoreIfPossible: Bool - internal func downcast() -> Into { - - return Into( - entityClass: self.entityClass, - configuration: self.configuration, - inferStoreIfPossible: self.inferStoreIfPossible - ) - } - - - // MARK: Private - - private init(entityClass: AnyClass, configuration: String?, inferStoreIfPossible: Bool) { + internal init(entityClass: T.Type, configuration: ModelConfiguration, inferStoreIfPossible: Bool) { self.entityClass = entityClass self.configuration = configuration diff --git a/Sources/Transactions/NSManagedObject+Transaction.swift b/Sources/Transactions/NSManagedObject+Transaction.swift index 2ebcd73..efd255c 100644 --- a/Sources/Transactions/NSManagedObject+Transaction.swift +++ b/Sources/Transactions/NSManagedObject+Transaction.swift @@ -43,22 +43,4 @@ public extension NSManagedObject { return self.managedObjectContext?.parentTransaction as? UnsafeDataTransaction } - - - // MARK: Internal - - @nonobjc - internal class func createInContext(_ context: NSManagedObjectContext) -> Self { - - return self.init( - entity: context.entityDescriptionForEntityType(self)!, - insertInto: context - ) - } - - @nonobjc - internal func deleteFromContext() { - - self.managedObjectContext?.delete(self) - } } diff --git a/Sources/Transactions/SynchronousDataTransaction.swift b/Sources/Transactions/SynchronousDataTransaction.swift index d390c69..552391e 100644 --- a/Sources/Transactions/SynchronousDataTransaction.swift +++ b/Sources/Transactions/SynchronousDataTransaction.swift @@ -50,12 +50,12 @@ public final class SynchronousDataTransaction: BaseDataTransaction { // MARK: BaseDataTransaction /** - Creates a new `NSManagedObject` with the specified entity type. + Creates a new `NSManagedObject` or `ManagedObject` with the specified entity type. - - parameter into: the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration - - returns: a new `NSManagedObject` instance of the specified entity type. + - parameter into: the `Into` clause indicating the destination `NSManagedObject` or `ManagedObject` entity type and the destination configuration + - returns: a new `NSManagedObject` or `ManagedObject` instance of the specified entity type. */ - public override func create(_ into: Into) -> T { + public override func create(_ into: Into) -> T { CoreStore.assert( !self.isCommitted,