mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-13 13:55:58 +01:00
WIP: allow migrations for CoreStoreObjects
This commit is contained in:
@@ -63,7 +63,6 @@
|
||||
82BA18D41C4BBD7100A0916E /* NSManagedObjectContext+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */; };
|
||||
82BA18D51C4BBD7100A0916E /* NSManagedObjectContext+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */; };
|
||||
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
|
||||
82BA18D71C4BBD7100A0916E /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
|
||||
82BA18D81C4BBD7100A0916E /* WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* WeakObject.swift */; };
|
||||
82BA18DC1C4BBD9C00A0916E /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5D372821A39CD6900F583D9 /* Model.xcdatamodeld */; };
|
||||
82BA18DD1C4BBE1400A0916E /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
|
||||
@@ -88,7 +87,14 @@
|
||||
B51260801E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B512607E1E97A18000402229 /* CoreStoreObject+Convenience.swift */; };
|
||||
B51260811E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B512607E1E97A18000402229 /* CoreStoreObject+Convenience.swift */; };
|
||||
B51260821E97A18000402229 /* CoreStoreObject+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B512607E1E97A18000402229 /* CoreStoreObject+Convenience.swift */; };
|
||||
B51BE06A1B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
|
||||
B51260891E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260881E9B252B00402229 /* NSEntityDescription+DynamicModel.swift */; };
|
||||
B512608A1E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260881E9B252B00402229 /* NSEntityDescription+DynamicModel.swift */; };
|
||||
B512608B1E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260881E9B252B00402229 /* NSEntityDescription+DynamicModel.swift */; };
|
||||
B512608C1E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260881E9B252B00402229 /* NSEntityDescription+DynamicModel.swift */; };
|
||||
B51260931E9B28F100402229 /* EntityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260921E9B28F100402229 /* EntityIdentifier.swift */; };
|
||||
B51260941E9B28F100402229 /* EntityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260921E9B28F100402229 /* EntityIdentifier.swift */; };
|
||||
B51260951E9B28F100402229 /* EntityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260921E9B28F100402229 /* EntityIdentifier.swift */; };
|
||||
B51260961E9B28F100402229 /* EntityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51260921E9B28F100402229 /* EntityIdentifier.swift */; };
|
||||
B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; };
|
||||
B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; };
|
||||
B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; };
|
||||
@@ -199,8 +205,27 @@
|
||||
B52DD1C71BE1F94600949AFE /* NSManagedObjectContext+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */; };
|
||||
B52DD1C81BE1F94600949AFE /* NSManagedObjectContext+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */; };
|
||||
B52DD1C91BE1F94600949AFE /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
|
||||
B52DD1CA1BE1F94600949AFE /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
|
||||
B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* WeakObject.swift */; };
|
||||
B52F742F1E9B50D0005F3DAC /* SchemaHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */; };
|
||||
B52F74301E9B50D0005F3DAC /* SchemaHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */; };
|
||||
B52F74311E9B50D0005F3DAC /* SchemaHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */; };
|
||||
B52F74321E9B50D0005F3DAC /* SchemaHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */; };
|
||||
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; };
|
||||
B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; };
|
||||
B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; };
|
||||
B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; };
|
||||
B52F74411E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModel.swift */; };
|
||||
B52F74421E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModel.swift */; };
|
||||
B52F74431E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModel.swift */; };
|
||||
B52F74441E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModel.swift */; };
|
||||
B52F74451E9B8724005F3DAC /* XcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModel.swift */; };
|
||||
B52F74461E9B8724005F3DAC /* XcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModel.swift */; };
|
||||
B52F74471E9B8724005F3DAC /* XcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModel.swift */; };
|
||||
B52F74481E9B8724005F3DAC /* XcodeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModel.swift */; };
|
||||
B52F744A1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */; };
|
||||
B52F744B1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */; };
|
||||
B52F744C1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */; };
|
||||
B52F744D1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */; };
|
||||
B52FD3AA1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||
@@ -358,7 +383,6 @@
|
||||
B56321B21BD6521C006C9394 /* NSManagedObjectContext+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */; };
|
||||
B56321B31BD6521C006C9394 /* NSManagedObjectContext+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */; };
|
||||
B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
|
||||
B56321B51BD6521C006C9394 /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
|
||||
B56321B61BD6521C006C9394 /* WeakObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F2D1AFF849C0064E85B /* WeakObject.swift */; };
|
||||
B56507941D3930BC000596DA /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56507931D3930BC000596DA /* CoreData.framework */; };
|
||||
B56507961D3930C1000596DA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56507951D3930C1000596DA /* Foundation.framework */; };
|
||||
@@ -417,10 +441,6 @@
|
||||
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 /* DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* DynamicModel.swift */; };
|
||||
B5D339B01E925BF200C880DE /* DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* DynamicModel.swift */; };
|
||||
B5D339B11E925BF200C880DE /* DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* DynamicModel.swift */; };
|
||||
B5D339B21E925BF200C880DE /* DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339AE1E925BF200C880DE /* DynamicModel.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 */; };
|
||||
@@ -653,7 +673,8 @@
|
||||
B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+Setup.swift"; sourceTree = "<group>"; };
|
||||
B509C7F31E54511B0061C547 /* ImportableAttributeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportableAttributeType.swift; sourceTree = "<group>"; };
|
||||
B512607E1E97A18000402229 /* CoreStoreObject+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStoreObject+Convenience.swift"; sourceTree = "<group>"; };
|
||||
B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectModel+Setup.swift"; sourceTree = "<group>"; };
|
||||
B51260881E9B252B00402229 /* NSEntityDescription+DynamicModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSEntityDescription+DynamicModel.swift"; sourceTree = "<group>"; };
|
||||
B51260921E9B28F100402229 /* EntityIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityIdentifier.swift; sourceTree = "<group>"; };
|
||||
B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+CustomDebugStringConvertible.swift"; sourceTree = "<group>"; };
|
||||
B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+Convenience.swift"; sourceTree = "<group>"; };
|
||||
B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectObserverTests.swift; sourceTree = "<group>"; };
|
||||
@@ -671,6 +692,11 @@
|
||||
B529C2031CA4A2DB007E7EBD /* CSSaveResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSaveResult.swift; sourceTree = "<group>"; };
|
||||
B52DD1741BE1F8CC00949AFE /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaHistory.swift; sourceTree = "<group>"; };
|
||||
B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicSchema.swift; sourceTree = "<group>"; };
|
||||
B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyXcodeDataModel.swift; sourceTree = "<group>"; };
|
||||
B52F743C1E9B8724005F3DAC /* XcodeDataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeDataModel.swift; sourceTree = "<group>"; };
|
||||
B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreSchema.swift; sourceTree = "<group>"; };
|
||||
B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Logging.swift"; sourceTree = "<group>"; };
|
||||
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+CoreStore.swift"; sourceTree = "<group>"; };
|
||||
B538BA701D15B3E30003A766 /* CoreStoreBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreStoreBridge.m; sourceTree = "<group>"; };
|
||||
@@ -733,7 +759,6 @@
|
||||
B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafeDataTransaction+Observing.swift"; sourceTree = "<group>"; };
|
||||
B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreFetchedResultsController.swift; sourceTree = "<group>"; };
|
||||
B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreError.swift; sourceTree = "<group>"; };
|
||||
B5D339AE1E925BF200C880DE /* DynamicModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicModel.swift; sourceTree = "<group>"; };
|
||||
B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicModelTests.swift; sourceTree = "<group>"; };
|
||||
B5D339D71E9489AB00C880DE /* CoreStoreObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreObject.swift; sourceTree = "<group>"; };
|
||||
B5D339DC1E9489C700C880DE /* DynamicObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicObject.swift; sourceTree = "<group>"; };
|
||||
@@ -1012,6 +1037,17 @@
|
||||
name = Observing;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B52F74391E9B8724005F3DAC /* Dynamic Schema */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */,
|
||||
B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */,
|
||||
B52F743C1E9B8724005F3DAC /* XcodeDataModel.swift */,
|
||||
B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModel.swift */,
|
||||
);
|
||||
path = "Dynamic Schema";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B53FBA101CAB607000F0D40A /* Convenience */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1092,8 +1128,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5D339D71E9489AB00C880DE /* CoreStoreObject.swift */,
|
||||
B5D339AE1E925BF200C880DE /* DynamicModel.swift */,
|
||||
B52F74391E9B8724005F3DAC /* Dynamic Schema */,
|
||||
B5D339DC1E9489C700C880DE /* DynamicObject.swift */,
|
||||
B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */,
|
||||
B5D339E61E9493A500C880DE /* Entity.swift */,
|
||||
B5D33A001E96012400C880DE /* Relationship.swift */,
|
||||
B5D339E11E948C3600C880DE /* Value.swift */,
|
||||
@@ -1289,6 +1326,8 @@
|
||||
children = (
|
||||
B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */,
|
||||
B526613F1CADD585007B85D9 /* CoreStoreFetchRequest+CoreStore.swift */,
|
||||
B51260881E9B252B00402229 /* NSEntityDescription+DynamicModel.swift */,
|
||||
B51260921E9B28F100402229 /* EntityIdentifier.swift */,
|
||||
B54A6A541BA15F2A007870FD /* FetchedResultsControllerDelegate.swift */,
|
||||
B5E834BA1B7691F3001D3D50 /* Functions.swift */,
|
||||
B5FAD6AB1B51285300714891 /* MigrationManager.swift */,
|
||||
@@ -1299,7 +1338,6 @@
|
||||
B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */,
|
||||
B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */,
|
||||
B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */,
|
||||
B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */,
|
||||
B5FEC18D1C9166E200532541 /* NSPersistentStore+Setup.swift */,
|
||||
B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */,
|
||||
B5E84F2D1AFF849C0064E85B /* WeakObject.swift */,
|
||||
@@ -1633,6 +1671,7 @@
|
||||
B5ECDBF91CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
|
||||
B5C976E71C6E3A5A00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */,
|
||||
B5F1DA901B9AA991007C5CBB /* ImportableUniqueObject.swift in Sources */,
|
||||
B51260891E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */,
|
||||
B504D0D61B02362500B2BBB1 /* CoreStore+Setup.swift in Sources */,
|
||||
B529C2041CA4A2DB007E7EBD /* CSSaveResult.swift in Sources */,
|
||||
B5D1E22C19FA9FBC003B2874 /* CoreStoreError.swift in Sources */,
|
||||
@@ -1645,6 +1684,7 @@
|
||||
B5E1B5981CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
||||
B5519A5F1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
||||
B52FD3AA1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||
B52F74411E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */,
|
||||
B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||
B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */,
|
||||
B5D339E21E948C3600C880DE /* Value.swift in Sources */,
|
||||
@@ -1676,6 +1716,7 @@
|
||||
B546F9731C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
||||
B56007111B3F6BD500A9A8F9 /* Into.swift in Sources */,
|
||||
B5E84F111AFF847B0064E85B /* Select.swift in Sources */,
|
||||
B51260931E9B28F100402229 /* EntityIdentifier.swift in Sources */,
|
||||
B5FE4DA21C8481E100FA6A91 /* StorageInterface.swift in Sources */,
|
||||
B53FB9FE1CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||
B5DBE2D21C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
||||
@@ -1696,6 +1737,7 @@
|
||||
B5ECDC111CA816E500C7F112 /* CSTweak.swift in Sources */,
|
||||
B5E84F411AFF8CCD0064E85B /* ClauseTypes.swift in Sources */,
|
||||
B5E84F0D1AFF847B0064E85B /* BaseDataTransaction+Querying.swift in Sources */,
|
||||
B52F74451E9B8724005F3DAC /* XcodeDataModel.swift in Sources */,
|
||||
B5FAD6AC1B51285300714891 /* MigrationManager.swift in Sources */,
|
||||
B5E84EF61AFF846E0064E85B /* DataStack+Transaction.swift in Sources */,
|
||||
B5FEC18E1C9166E200532541 /* NSPersistentStore+Setup.swift in Sources */,
|
||||
@@ -1711,6 +1753,7 @@
|
||||
B5A5F2661CAEC50F004AB9AF /* CSSelect.swift in Sources */,
|
||||
B5ECDBE51CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */,
|
||||
B5519A4A1CA1F4FB002BEF78 /* CSError.swift in Sources */,
|
||||
B52F742F1E9B50D0005F3DAC /* SchemaHistory.swift in Sources */,
|
||||
B5E84EF51AFF846E0064E85B /* BaseDataTransaction.swift in Sources */,
|
||||
B5E84EFB1AFF846E0064E85B /* SaveResult.swift in Sources */,
|
||||
B5D339EC1E9495E500C880DE /* Attribute+Querying.swift in Sources */,
|
||||
@@ -1719,8 +1762,7 @@
|
||||
B5E84EFC1AFF846E0064E85B /* SynchronousDataTransaction.swift in Sources */,
|
||||
B5E222231CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
|
||||
B5E84F281AFF84920064E85B /* NSManagedObject+Convenience.swift in Sources */,
|
||||
B51BE06A1B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift in Sources */,
|
||||
B5D339AF1E925BF200C880DE /* DynamicModel.swift in Sources */,
|
||||
B52F744A1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||
B5AEFAB51C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
||||
B5E2222A1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
||||
B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */,
|
||||
@@ -1744,6 +1786,7 @@
|
||||
B5E84F211AFF84860064E85B /* CoreStore+Observing.swift in Sources */,
|
||||
B559CD431CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
|
||||
B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
||||
B5ECDBEC1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
|
||||
B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */,
|
||||
B5E84EE61AFF84610064E85B /* DefaultLogger.swift in Sources */,
|
||||
@@ -1799,6 +1842,7 @@
|
||||
B5ECDBFB1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
|
||||
B5C976E81C6E3A5D00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */,
|
||||
82BA18A21C4BBD1D00A0916E /* CoreStoreError.swift in Sources */,
|
||||
B512608A1E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */,
|
||||
82BA18B21C4BBD3900A0916E /* ImportableObject.swift in Sources */,
|
||||
B529C2061CA4A2DB007E7EBD /* CSSaveResult.swift in Sources */,
|
||||
82BA18AE1C4BBD3100A0916E /* DataStack+Transaction.swift in Sources */,
|
||||
@@ -1811,6 +1855,7 @@
|
||||
B5E1B59A1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
|
||||
B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
||||
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||
B52F74421E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */,
|
||||
B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||
B5FE4DAD1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
|
||||
B5D339E31E948C3600C880DE /* Value.swift in Sources */,
|
||||
@@ -1842,6 +1887,7 @@
|
||||
B546F9741C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
||||
82BA18B11C4BBD3100A0916E /* SaveResult.swift in Sources */,
|
||||
82BA18DD1C4BBE1400A0916E /* NSFetchedResultsController+Convenience.swift in Sources */,
|
||||
B51260941E9B28F100402229 /* EntityIdentifier.swift in Sources */,
|
||||
B5FE4DA81C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||
B53FBA001CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||
B5DBE2D31C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
||||
@@ -1862,6 +1908,7 @@
|
||||
B5ECDC131CA816E500C7F112 /* CSTweak.swift in Sources */,
|
||||
82BA18C91C4BBD5900A0916E /* MigrationType.swift in Sources */,
|
||||
82BA18D01C4BBD7100A0916E /* MigrationManager.swift in Sources */,
|
||||
B52F74461E9B8724005F3DAC /* XcodeDataModel.swift in Sources */,
|
||||
82BA18C61C4BBD5900A0916E /* DataStack+Migration.swift in Sources */,
|
||||
B59851491C90289D00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||
B5E1B5A41CAA4365007FD580 /* CSCoreStore+Observing.swift in Sources */,
|
||||
@@ -1876,7 +1923,7 @@
|
||||
B5D339DE1E9489C700C880DE /* DynamicObject.swift in Sources */,
|
||||
B5ECDBE71CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */,
|
||||
B5519A4B1CA1F4FB002BEF78 /* CSError.swift in Sources */,
|
||||
82BA18D71C4BBD7100A0916E /* NSManagedObjectModel+Setup.swift in Sources */,
|
||||
B52F74301E9B50D0005F3DAC /* SchemaHistory.swift in Sources */,
|
||||
82BA18C31C4BBD5300A0916E /* ObjectObserver.swift in Sources */,
|
||||
82BA18BF1C4BBD5300A0916E /* SectionBy.swift in Sources */,
|
||||
B5D339ED1E9495E500C880DE /* Attribute+Querying.swift in Sources */,
|
||||
@@ -1885,8 +1932,8 @@
|
||||
B5E222251CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
|
||||
82BA18C41C4BBD5300A0916E /* ListMonitor.swift in Sources */,
|
||||
82BA18BA1C4BBD4A00A0916E /* Select.swift in Sources */,
|
||||
B52F744B1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||
B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
||||
B5D339B01E925BF200C880DE /* DynamicModel.swift in Sources */,
|
||||
B5E2222C1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
||||
82BA18A71C4BBD2900A0916E /* CoreStore+Logging.swift in Sources */,
|
||||
82BA18D81C4BBD7100A0916E /* WeakObject.swift in Sources */,
|
||||
@@ -1910,6 +1957,7 @@
|
||||
B559CD451CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
|
||||
82BA18B81C4BBD4200A0916E /* ClauseTypes.swift in Sources */,
|
||||
B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
|
||||
B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
||||
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */,
|
||||
82BA18B91C4BBD4A00A0916E /* From.swift in Sources */,
|
||||
B53FBA061CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
||||
@@ -1965,6 +2013,7 @@
|
||||
B5DBE2D01C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
||||
B5677D411CD3B1E400322BFC /* ICloudStoreObserver.swift in Sources */,
|
||||
B52DD1BE1BE1F94300949AFE /* Progress+Convenience.swift in Sources */,
|
||||
B512608C1E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */,
|
||||
B5ECDC151CA816E500C7F112 /* CSTweak.swift in Sources */,
|
||||
B546F9761C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
||||
B53FBA161CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||
@@ -1977,6 +2026,7 @@
|
||||
B5ECDC211CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
||||
B52DD1C21BE1F94600949AFE /* MigrationManager.swift in Sources */,
|
||||
B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||
B52F74441E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */,
|
||||
B5ECDC2D1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
||||
B5D7A5BA1CA3BF8F005C752B /* CSInto.swift in Sources */,
|
||||
B5D339E51E948C3600C880DE /* Value.swift in Sources */,
|
||||
@@ -2008,6 +2058,7 @@
|
||||
B52DD1BD1BE1F94300949AFE /* NSManagedObject+Convenience.swift in Sources */,
|
||||
B52DD1AD1BE1F93900949AFE /* Where.swift in Sources */,
|
||||
B53FBA1C1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */,
|
||||
B51260961E9B28F100402229 /* EntityIdentifier.swift in Sources */,
|
||||
B5ECDBE31CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */,
|
||||
B5ECDC031CA80CBA00C7F112 /* CSWhere.swift in Sources */,
|
||||
B52DD1AC1BE1F93900949AFE /* Select.swift in Sources */,
|
||||
@@ -2028,6 +2079,7 @@
|
||||
B5ECDC091CA8138100C7F112 /* CSOrderBy.swift in Sources */,
|
||||
B52DD1A51BE1F92F00949AFE /* ImportableUniqueObject.swift in Sources */,
|
||||
B5E222271CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
|
||||
B52F74481E9B8724005F3DAC /* XcodeDataModel.swift in Sources */,
|
||||
B5519A621CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
||||
B52DD19C1BE1F92C00949AFE /* Into.swift in Sources */,
|
||||
B5FE4DA51C8481E100FA6A91 /* StorageInterface.swift in Sources */,
|
||||
@@ -2036,13 +2088,13 @@
|
||||
B5FE4DAA1C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||
B52DD1AF1BE1F93900949AFE /* GroupBy.swift in Sources */,
|
||||
B52DD1B01BE1F93900949AFE /* Tweak.swift in Sources */,
|
||||
B52DD1CA1BE1F94600949AFE /* NSManagedObjectModel+Setup.swift in Sources */,
|
||||
B52DD1A41BE1F92F00949AFE /* ImportableObject.swift in Sources */,
|
||||
B5220E161D13067C009BC71E /* ObjectMonitor.swift in Sources */,
|
||||
B5D339E01E9489C700C880DE /* DynamicObject.swift in Sources */,
|
||||
B52DD1AE1BE1F93900949AFE /* OrderBy.swift in Sources */,
|
||||
B52DD1BA1BE1F94000949AFE /* MigrationChain.swift in Sources */,
|
||||
B50392FB1C479640009900CA /* NSManagedObject+Transaction.swift in Sources */,
|
||||
B52F74321E9B50D0005F3DAC /* SchemaHistory.swift in Sources */,
|
||||
B52DD1A31BE1F92C00949AFE /* SaveResult.swift in Sources */,
|
||||
B5220E211D130816009BC71E /* CSObjectObserver.swift in Sources */,
|
||||
B5D339EF1E9495E500C880DE /* Attribute+Querying.swift in Sources */,
|
||||
@@ -2051,8 +2103,8 @@
|
||||
B52DD1C11BE1F94600949AFE /* Functions.swift in Sources */,
|
||||
B5220E1A1D130791009BC71E /* CoreStoreFetchedResultsController.swift in Sources */,
|
||||
B53FBA0F1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */,
|
||||
B52F744D1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||
B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */,
|
||||
B5D339B21E925BF200C880DE /* DynamicModel.swift in Sources */,
|
||||
B52DD19A1BE1F92800949AFE /* CoreStore+Logging.swift in Sources */,
|
||||
B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */,
|
||||
B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
||||
@@ -2076,6 +2128,7 @@
|
||||
B52DD19B1BE1F92800949AFE /* CoreStoreLogger.swift in Sources */,
|
||||
B52DD1991BE1F92800949AFE /* DefaultLogger.swift in Sources */,
|
||||
B5220E201D130813009BC71E /* CSObjectMonitor.swift in Sources */,
|
||||
B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
||||
B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */,
|
||||
B53FBA081CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
||||
B52DD1B91BE1F94000949AFE /* CoreStore+Migration.swift in Sources */,
|
||||
@@ -2131,6 +2184,7 @@
|
||||
B5ECDBFC1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
|
||||
B5C976E91C6E3A5E00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */,
|
||||
B56321801BD65216006C9394 /* CoreStoreError.swift in Sources */,
|
||||
B512608B1E9B252B00402229 /* NSEntityDescription+DynamicModel.swift in Sources */,
|
||||
B56321AD1BD6521C006C9394 /* MigrationManager.swift in Sources */,
|
||||
B529C2071CA4A2DC007E7EBD /* CSSaveResult.swift in Sources */,
|
||||
B563219D1BD65216006C9394 /* DataStack+Observing.swift in Sources */,
|
||||
@@ -2143,6 +2197,7 @@
|
||||
B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
|
||||
B5FE4DAE1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
|
||||
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
|
||||
B52F74431E9B8724005F3DAC /* LegacyXcodeDataModel.swift in Sources */,
|
||||
B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||
B563218C1BD65216006C9394 /* DataStack+Transaction.swift in Sources */,
|
||||
B5D339E41E948C3600C880DE /* Value.swift in Sources */,
|
||||
@@ -2174,6 +2229,7 @@
|
||||
B56321981BD65216006C9394 /* Where.swift in Sources */,
|
||||
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */,
|
||||
B5FE4DA91C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||
B51260951E9B28F100402229 /* EntityIdentifier.swift in Sources */,
|
||||
B53FBA011CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||
B5DBE2D41C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
||||
B50392FA1C47963F009900CA /* NSManagedObject+Transaction.swift in Sources */,
|
||||
@@ -2194,6 +2250,7 @@
|
||||
B56321931BD65216006C9394 /* DataStack+Querying.swift in Sources */,
|
||||
B56321A71BD65216006C9394 /* MigrationResult.swift in Sources */,
|
||||
B598514A1C90289E00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||
B52F74471E9B8724005F3DAC /* XcodeDataModel.swift in Sources */,
|
||||
B5FEC1901C9166E700532541 /* NSPersistentStore+Setup.swift in Sources */,
|
||||
B56321A11BD65216006C9394 /* ListMonitor.swift in Sources */,
|
||||
B5E1B5A51CAA4365007FD580 /* CSCoreStore+Observing.swift in Sources */,
|
||||
@@ -2208,7 +2265,7 @@
|
||||
B5D339DF1E9489C700C880DE /* DynamicObject.swift in Sources */,
|
||||
B5519A4C1CA1F4FB002BEF78 /* CSError.swift in Sources */,
|
||||
B563219B1BD65216006C9394 /* Tweak.swift in Sources */,
|
||||
B56321B51BD6521C006C9394 /* NSManagedObjectModel+Setup.swift in Sources */,
|
||||
B52F74311E9B50D0005F3DAC /* SchemaHistory.swift in Sources */,
|
||||
B563218F1BD65216006C9394 /* ImportableObject.swift in Sources */,
|
||||
B56321991BD65216006C9394 /* OrderBy.swift in Sources */,
|
||||
B5D339EE1E9495E500C880DE /* Attribute+Querying.swift in Sources */,
|
||||
@@ -2217,8 +2274,8 @@
|
||||
B5E222261CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
|
||||
B56321A21BD65216006C9394 /* ListObserver.swift in Sources */,
|
||||
B563218A1BD65216006C9394 /* SynchronousDataTransaction.swift in Sources */,
|
||||
B52F744C1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||
B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
||||
B5D339B11E925BF200C880DE /* DynamicModel.swift in Sources */,
|
||||
B5E2222D1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
||||
B563219F1BD65216006C9394 /* ObjectMonitor.swift in Sources */,
|
||||
B56321B61BD6521C006C9394 /* WeakObject.swift in Sources */,
|
||||
@@ -2242,6 +2299,7 @@
|
||||
B559CD461CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
|
||||
B56321A61BD65216006C9394 /* MigrationType.swift in Sources */,
|
||||
B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
|
||||
B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
||||
B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */,
|
||||
B56321861BD65216006C9394 /* CoreStoreLogger.swift in Sources */,
|
||||
B53FBA071CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
||||
|
||||
@@ -60,7 +60,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
}
|
||||
for model in models {
|
||||
|
||||
if model.version == storeVersion {
|
||||
if model.schemaHistory.currentModelVersion == storeVersion {
|
||||
|
||||
return model
|
||||
}
|
||||
@@ -141,29 +141,35 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private typealias ModelMetadata = (label: String, version: String, entityType: NSManagedObject.Type, migrationChain: MigrationChain)
|
||||
private typealias ModelMetadata = (label: String, entityType: NSManagedObject.Type, schemaHistory: SchemaHistory)
|
||||
|
||||
private let models: [ModelMetadata] = [
|
||||
(
|
||||
label: "Model V1",
|
||||
version: "MigrationDemo",
|
||||
entityType: OrganismV1.self,
|
||||
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
|
||||
schemaHistory: SchemaHistory(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
|
||||
)
|
||||
),
|
||||
(
|
||||
label: "Model V2",
|
||||
version: "MigrationDemoV2",
|
||||
entityType: OrganismV2.self,
|
||||
migrationChain: [
|
||||
"MigrationDemo": "MigrationDemoV2",
|
||||
"MigrationDemoV3": "MigrationDemoV2"
|
||||
]
|
||||
schemaHistory: SchemaHistory(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: [
|
||||
"MigrationDemo": "MigrationDemoV2",
|
||||
"MigrationDemoV3": "MigrationDemoV2"
|
||||
]
|
||||
)
|
||||
),
|
||||
(
|
||||
label: "Model V3",
|
||||
version: "MigrationDemoV3",
|
||||
entityType: OrganismV3.self,
|
||||
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
|
||||
schemaHistory: SchemaHistory(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
@@ -210,17 +216,14 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
|
||||
private func selectModelVersion(_ model: ModelMetadata) {
|
||||
|
||||
if self.dataStack?.modelVersion == model.version {
|
||||
if self.dataStack?.modelVersion == model.schemaHistory.currentModelVersion {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.set(dataStack: nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
|
||||
|
||||
let dataStack = DataStack(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: model.migrationChain
|
||||
)
|
||||
let dataStack = DataStack(schemaHistory: model.schemaHistory)
|
||||
|
||||
self.setEnabled(false)
|
||||
let progress = dataStack.addStorage(
|
||||
@@ -313,7 +316,13 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
|
||||
if let dataStack = dataStack, let model = model {
|
||||
|
||||
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.index(of: model.version)!
|
||||
self.segmentedControl?.selectedSegmentIndex = self.models
|
||||
.index(
|
||||
where: { (_, _, schemaHistory) -> Bool in
|
||||
|
||||
schemaHistory.currentModelVersion == model.schemaHistory.currentModelVersion
|
||||
}
|
||||
)!
|
||||
|
||||
self._dataStack = dataStack
|
||||
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.descending("dna")))
|
||||
|
||||
@@ -17,7 +17,7 @@ import CoreStore
|
||||
class BaseTestDataTestCase: BaseTestCase {
|
||||
|
||||
@nonobjc
|
||||
let dateFormatter: DateFormatter = {
|
||||
let dateFormatter: DateFormatter = cs_lazy {
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
@@ -25,7 +25,7 @@ class BaseTestDataTestCase: BaseTestCase {
|
||||
formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
|
||||
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
|
||||
return formatter
|
||||
}()
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func prepareTestDataForStack(_ stack: DataStack, configurations: [ModelConfiguration] = [nil]) {
|
||||
|
||||
@@ -57,8 +57,8 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
func testDynamicModels_CanBeDeclaredCorrectly() {
|
||||
|
||||
let dataStack = DataStack(
|
||||
dynamicModel: DynamicModel(
|
||||
version: "V1",
|
||||
CoreStoreSchema(
|
||||
modelVersion: "V1",
|
||||
entities: [
|
||||
Entity<Animal>("Animal"),
|
||||
Entity<Dog>("Dog"),
|
||||
|
||||
@@ -85,16 +85,19 @@ final class ErrorTests: XCTestCase {
|
||||
|
||||
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
|
||||
|
||||
let model = NSManagedObjectModel.fromBundle(Bundle(for: type(of: self)), modelName: "Model")
|
||||
let schemaHistory = SchemaHistory(
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
let version = "1.0.0"
|
||||
|
||||
let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: model, targetModelVersion: version)
|
||||
let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: schemaHistory.rawModel, targetModelVersion: version)
|
||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
|
||||
|
||||
let userInfo: NSDictionary = [
|
||||
"localStoreURL": dummyURL,
|
||||
"targetModel": model,
|
||||
"targetModel": schemaHistory.rawModel,
|
||||
"targetModelVersion": version
|
||||
]
|
||||
let objcError = error.bridgeToObjectiveC
|
||||
|
||||
@@ -37,8 +37,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
dynamic func test_ThatNilMigrationChains_HaveNoVersions() {
|
||||
|
||||
let chain: MigrationChain = nil
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertTrue(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertTrue(chain.isEmpty)
|
||||
|
||||
XCTAssertFalse(chain.contains("version1"))
|
||||
XCTAssertNil(chain.nextVersionFrom("version1"))
|
||||
@@ -48,8 +48,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
dynamic func test_ThatStringMigrationChains_HaveOneVersion() {
|
||||
|
||||
let chain: MigrationChain = "version1"
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertTrue(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertTrue(chain.isEmpty)
|
||||
|
||||
XCTAssertTrue(chain.contains("version1"))
|
||||
XCTAssertFalse(chain.contains("version2"))
|
||||
@@ -62,8 +62,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
dynamic func test_ThatArrayMigrationChains_HaveLinearVersions() {
|
||||
|
||||
let chain: MigrationChain = ["version1", "version2", "version3", "version4"]
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertFalse(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertFalse(chain.isEmpty)
|
||||
|
||||
XCTAssertTrue(chain.contains("version1"))
|
||||
XCTAssertTrue(chain.contains("version2"))
|
||||
@@ -86,8 +86,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
"version2": "version3",
|
||||
"version3": "version4"
|
||||
]
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertFalse(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertFalse(chain.isEmpty)
|
||||
|
||||
XCTAssertTrue(chain.contains("version1"))
|
||||
XCTAssertTrue(chain.contains("version2"))
|
||||
|
||||
@@ -36,10 +36,13 @@ class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let model = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!
|
||||
|
||||
let stack = DataStack(model: model, migrationChain: nil)
|
||||
XCTAssertEqual(stack.coordinator.managedObjectModel, model)
|
||||
let schemaHistory = SchemaHistory(
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self)),
|
||||
migrationChain: nil
|
||||
)
|
||||
let stack = DataStack(schemaHistory: schemaHistory)
|
||||
XCTAssertEqual(stack.coordinator.managedObjectModel, schemaHistory.rawModel)
|
||||
XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator)
|
||||
XCTAssertNil(stack.rootSavingContext.parent)
|
||||
XCTAssertFalse(stack.rootSavingContext.isDataStackContext)
|
||||
@@ -47,18 +50,18 @@ class SetupTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
|
||||
XCTAssertTrue(stack.mainContext.isDataStackContext)
|
||||
XCTAssertFalse(stack.mainContext.isTransactionContext)
|
||||
XCTAssertEqual(stack.model, model)
|
||||
XCTAssertTrue(stack.migrationChain.valid)
|
||||
XCTAssertTrue(stack.migrationChain.empty)
|
||||
XCTAssertTrue(stack.migrationChain.rootVersions.isEmpty)
|
||||
XCTAssertTrue(stack.migrationChain.leafVersions.isEmpty)
|
||||
XCTAssertEqual(stack.schemaHistory.rawModel, schemaHistory.rawModel)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.isValid)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.isEmpty)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.rootVersions.isEmpty)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.leafVersions.isEmpty)
|
||||
|
||||
CoreStore.defaultStack = stack
|
||||
XCTAssertEqual(CoreStore.defaultStack, stack)
|
||||
}
|
||||
do {
|
||||
|
||||
let migrationChain: MigrationChain = ["version1", "version2", "version3"]
|
||||
let migrationChain: MigrationChain = ["version1", "version2", "version3", "Model"]
|
||||
|
||||
let stack = self.expectLogger([.logWarning]) {
|
||||
|
||||
@@ -69,7 +72,7 @@ class SetupTests: BaseTestDataTestCase {
|
||||
)
|
||||
}
|
||||
XCTAssertEqual(stack.modelVersion, "Model")
|
||||
XCTAssertEqual(stack.migrationChain, migrationChain)
|
||||
XCTAssertEqual(stack.schemaHistory.migrationChain, migrationChain)
|
||||
|
||||
CoreStore.defaultStack = stack
|
||||
XCTAssertEqual(CoreStore.defaultStack, stack)
|
||||
@@ -226,7 +229,10 @@ class SetupTests: BaseTestDataTestCase {
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: stack.model[metadata])
|
||||
try sqliteStore.eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
|
||||
)
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
@@ -344,7 +350,10 @@ class SetupTests: BaseTestDataTestCase {
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: stack.model[metadata])
|
||||
try sqliteStore.eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
|
||||
)
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
|
||||
@@ -222,7 +222,7 @@ public enum CoreStoreError: Error, CustomNSError, Hashable {
|
||||
|
||||
internal init(_ error: Error?) {
|
||||
|
||||
self = error.flatMap { $0.bridgeToSwift } ?? .unknown
|
||||
self = error.flatMap({ $0.bridgeToSwift }) ?? .unknown
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: - XcdatamodelFilename
|
||||
// MARK: - XcodeDataModelFileName
|
||||
|
||||
/**
|
||||
A `String` that pertains to the name of an *.xcdatamodeld file (without the file extension).
|
||||
*/
|
||||
public typealias XcdatamodelFilename = String
|
||||
public typealias XcodeDataModelFileName = String
|
||||
|
||||
|
||||
// MARK: - ModelConfiguration
|
||||
|
||||
@@ -580,11 +580,11 @@ extension UUID: ImportableAttributeType {
|
||||
|
||||
enum Static {
|
||||
|
||||
static let empty: UUID = {
|
||||
static let empty: UUID = cs_lazy {
|
||||
|
||||
var zero = Array<UInt8>(repeating: 0, count: 16)
|
||||
return NSUUID(uuidBytes: &zero) as UUID
|
||||
}()
|
||||
}
|
||||
}
|
||||
return Static.empty
|
||||
}
|
||||
|
||||
106
Sources/Internal/EntityIdentifier.swift
Normal file
106
Sources/Internal/EntityIdentifier.swift
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// EntityIdentifier.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: - 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: CoreStoreObject.Type) {
|
||||
|
||||
self.category = .coreStore
|
||||
self.interfacedClassName = String(reflecting: type)
|
||||
}
|
||||
|
||||
internal init(_ type: DynamicObject.Type) {
|
||||
|
||||
switch type {
|
||||
|
||||
case let type as NSManagedObject.Type:
|
||||
self.init(type)
|
||||
|
||||
case let type as CoreStoreObject.Type:
|
||||
self.init(type)
|
||||
|
||||
default:
|
||||
CoreStore.abort("\(cs_typeName(DynamicObject.self)) is not meant to be implemented by external types.")
|
||||
}
|
||||
}
|
||||
|
||||
internal init(_ entityDescription: NSEntityDescription) {
|
||||
|
||||
if let anyEntity = entityDescription.anyEntity {
|
||||
|
||||
self.category = .coreStore
|
||||
self.interfacedClassName = NSStringFromClass(anyEntity.type)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -100,3 +100,12 @@ internal func cs_typeName(_ name: String?) -> String {
|
||||
|
||||
return "<\(name ?? "unknown")>"
|
||||
}
|
||||
|
||||
|
||||
// MARK: Functional
|
||||
|
||||
@inline(__always)
|
||||
internal func cs_lazy<T>(_ closure: () -> T) -> T {
|
||||
|
||||
return closure()
|
||||
}
|
||||
|
||||
76
Sources/Internal/NSEntityDescription+DynamicModel.swift
Normal file
76
Sources/Internal/NSEntityDescription+DynamicModel.swift
Normal file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// NSEntityDescription+DynamicModel.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: - NSEntityDescription
|
||||
|
||||
internal extension NSEntityDescription {
|
||||
|
||||
@nonobjc
|
||||
internal var anyEntity: CoreStoreSchema.AnyEntity? {
|
||||
|
||||
get {
|
||||
|
||||
guard let userInfo = self.userInfo,
|
||||
let typeName = userInfo[UserInfoKey.CoreStoreManagedObjectTypeName] as! String?,
|
||||
let entityName = userInfo[UserInfoKey.CoreStoreManagedObjectEntityName] as! String? else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return CoreStoreSchema.AnyEntity(
|
||||
type: NSClassFromString(typeName) as! CoreStoreObject.Type,
|
||||
entityName: entityName
|
||||
)
|
||||
}
|
||||
set {
|
||||
|
||||
if let newValue = newValue {
|
||||
|
||||
self.userInfo = [
|
||||
UserInfoKey.CoreStoreManagedObjectTypeName: NSStringFromClass(newValue.type),
|
||||
UserInfoKey.CoreStoreManagedObjectEntityName: newValue.entityName
|
||||
]
|
||||
}
|
||||
else {
|
||||
|
||||
self.userInfo = [:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
// MARK: - UserInfoKey
|
||||
|
||||
fileprivate enum UserInfoKey {
|
||||
|
||||
fileprivate static let CoreStoreManagedObjectTypeName = "CoreStoreManagedObjectTypeName"
|
||||
fileprivate static let CoreStoreManagedObjectEntityName = "CoreStoreManagedObjectEntityName"
|
||||
}
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
//
|
||||
// NSManagedObjectModel+Setup.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - NSManagedObjectModel
|
||||
|
||||
internal extension NSManagedObjectModel {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
@nonobjc
|
||||
internal static func fromBundle(_ bundle: Bundle, modelName: String, modelVersionHints: Set<String> = []) -> NSManagedObjectModel {
|
||||
|
||||
guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else {
|
||||
|
||||
// For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model.
|
||||
let foundModels = bundle
|
||||
.paths(forResourcesOfType: "momd", inDirectory: nil)
|
||||
.map({ ($0 as NSString).lastPathComponent })
|
||||
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle \"\(bundle.bundleIdentifier ?? "<nil>")\". Other model files in bundle: \(foundModels.coreStoreDumpString)")
|
||||
}
|
||||
|
||||
let modelFileURL = URL(fileURLWithPath: modelFilePath)
|
||||
let versionInfoPlistURL = modelFileURL.appendingPathComponent("VersionInfo.plist", isDirectory: false)
|
||||
|
||||
guard let versionInfo = NSDictionary(contentsOf: versionInfoPlistURL),
|
||||
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
|
||||
|
||||
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel.self)) metadata from path \"\(versionInfoPlistURL)\".")
|
||||
}
|
||||
|
||||
let modelVersions = Set(versionHashes.keys)
|
||||
let currentModelVersion: String
|
||||
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String,
|
||||
modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
|
||||
|
||||
currentModelVersion = plistModelVersion
|
||||
}
|
||||
else if let resolvedVersion = modelVersions.intersection(modelVersionHints).first {
|
||||
|
||||
CoreStore.log(
|
||||
.warning,
|
||||
message: "The MigrationChain leaf versions do not include the model file's current version. Resolving to version \"\(resolvedVersion)\"."
|
||||
)
|
||||
currentModelVersion = resolvedVersion
|
||||
}
|
||||
else if let resolvedVersion = modelVersions.first ?? modelVersionHints.first {
|
||||
|
||||
if !modelVersionHints.isEmpty {
|
||||
|
||||
CoreStore.log(
|
||||
.warning,
|
||||
message: "The MigrationChain leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"."
|
||||
)
|
||||
}
|
||||
currentModelVersion = resolvedVersion
|
||||
}
|
||||
else {
|
||||
|
||||
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
|
||||
}
|
||||
|
||||
var modelVersionFileURL: URL?
|
||||
for modelVersion in modelVersions {
|
||||
|
||||
let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
|
||||
|
||||
if modelVersion == currentModelVersion {
|
||||
|
||||
modelVersionFileURL = fileURL
|
||||
continue
|
||||
}
|
||||
|
||||
precondition(
|
||||
NSManagedObjectModel(contentsOf: fileURL) != nil,
|
||||
"Could not find the \"\(modelVersion).mom\" version file for the model at URL \"\(modelFileURL)\"."
|
||||
)
|
||||
}
|
||||
|
||||
if let modelVersionFileURL = modelVersionFileURL,
|
||||
let rootModel = NSManagedObjectModel(contentsOf: modelVersionFileURL) {
|
||||
|
||||
// TODO: apply to DynamicModel as well
|
||||
rootModel.modelVersionFileURL = modelVersionFileURL
|
||||
rootModel.modelVersions = modelVersions
|
||||
rootModel.currentModelVersion = currentModelVersion
|
||||
return rootModel
|
||||
}
|
||||
|
||||
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel.self)) from the model at URL \"\(modelFileURL)\".")
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal private(set) var currentModelVersion: String? {
|
||||
|
||||
get {
|
||||
|
||||
let value: NSString? = cs_getAssociatedObjectForKey(
|
||||
&PropertyKeys.currentModelVersion,
|
||||
inObject: self
|
||||
)
|
||||
return value as String?
|
||||
}
|
||||
set {
|
||||
|
||||
cs_setAssociatedCopiedObject(
|
||||
newValue == nil ? nil : (newValue! as NSString),
|
||||
forKey: &PropertyKeys.currentModelVersion,
|
||||
inObject: self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal private(set) var modelVersions: Set<String>? {
|
||||
|
||||
get {
|
||||
|
||||
let value: NSSet? = cs_getAssociatedObjectForKey(
|
||||
&PropertyKeys.modelVersions,
|
||||
inObject: self
|
||||
)
|
||||
return value as? Set<String>
|
||||
}
|
||||
set {
|
||||
|
||||
cs_setAssociatedCopiedObject(
|
||||
newValue == nil ? nil : (newValue! as NSSet),
|
||||
forKey: &PropertyKeys.modelVersions,
|
||||
inObject: self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal var entityDescriptionsByEntityIdentifier: [EntityIdentifier: NSEntityDescription] {
|
||||
|
||||
if let mapping: NSDictionary = cs_getAssociatedObjectForKey(&PropertyKeys.objectClassNamesByEntityName, inObject: self) {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal func mergedModels() -> [NSManagedObjectModel] {
|
||||
|
||||
return self.modelVersions?.map { self[$0] }.flatMap { $0 == nil ? [] : [$0!] } ?? [self]
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal subscript(modelVersion: String) -> NSManagedObjectModel? {
|
||||
|
||||
if modelVersion == self.currentModelVersion {
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
guard let modelFileURL = self.modelFileURL,
|
||||
let modelVersions = self.modelVersions,
|
||||
modelVersions.contains(modelVersion) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: apply to DynamicModel as well
|
||||
let versionModelFileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
|
||||
guard let model = NSManagedObjectModel(contentsOf: versionModelFileURL) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
model.currentModelVersion = modelVersion
|
||||
model.modelVersionFileURL = versionModelFileURL
|
||||
model.modelVersions = modelVersions
|
||||
return model
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
internal subscript(metadata: [String: Any]) -> NSManagedObjectModel? {
|
||||
|
||||
guard let modelHashes = metadata[NSStoreModelVersionHashesKey] as? [String : Data] else {
|
||||
|
||||
return nil
|
||||
}
|
||||
for modelVersion in self.modelVersions ?? [] {
|
||||
|
||||
if let versionModel = self[modelVersion], modelHashes == versionModel.entityVersionHashesByName {
|
||||
|
||||
return versionModel
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@nonobjc
|
||||
private var modelFileURL: URL? {
|
||||
|
||||
get {
|
||||
|
||||
return self.modelVersionFileURL?.deletingLastPathComponent()
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
private var modelVersionFileURL: URL? {
|
||||
|
||||
get {
|
||||
|
||||
let value: NSURL? = cs_getAssociatedObjectForKey(
|
||||
&PropertyKeys.modelVersionFileURL,
|
||||
inObject: self
|
||||
)
|
||||
return value as URL?
|
||||
}
|
||||
set {
|
||||
|
||||
cs_setAssociatedCopiedObject(
|
||||
newValue as NSURL?,
|
||||
forKey: &PropertyKeys.modelVersionFileURL,
|
||||
inObject: self
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private struct PropertyKeys {
|
||||
|
||||
static var objectClassNamesByEntityName: Void?
|
||||
|
||||
static var modelVersionFileURL: Void?
|
||||
static var modelVersions: Void?
|
||||
static var currentModelVersion: Void?
|
||||
}
|
||||
}
|
||||
@@ -158,6 +158,32 @@ extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConv
|
||||
}
|
||||
|
||||
|
||||
// MARK: - CoreStoreSchema
|
||||
|
||||
extension CoreStoreSchema: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
|
||||
// MARK: CustomDebugStringConvertible
|
||||
|
||||
public var debugDescription: String {
|
||||
|
||||
return formattedDebugDescription(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreDebugStringConvertible
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
return createFormattedString(
|
||||
"(", ")",
|
||||
("modelVersion", self.modelVersion),
|
||||
("entitiesByConfiguration", self.entitiesByConfiguration),
|
||||
("rawModel", self.rawModel())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
extension DataStack: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
@@ -179,14 +205,38 @@ extension DataStack: CustomDebugStringConvertible, CoreStoreDebugStringConvertib
|
||||
("coordinator", self.coordinator),
|
||||
("rootSavingContext", self.rootSavingContext),
|
||||
("mainContext", self.mainContext),
|
||||
("model", self.model),
|
||||
("migrationChain", self.migrationChain),
|
||||
("schemaHistory", self.schemaHistory),
|
||||
("coordinator.persistentStores", self.coordinator.persistentStores)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Entity
|
||||
|
||||
extension Entity: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
|
||||
// MARK: CustomDebugStringConvertible
|
||||
|
||||
public var debugDescription: String {
|
||||
|
||||
return formattedDebugDescription(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreDebugStringConvertible
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
return createFormattedString(
|
||||
"(", ")",
|
||||
("type", self.type),
|
||||
("entityName", self.entityName)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - From
|
||||
|
||||
extension From: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
@@ -350,6 +400,31 @@ extension LegacySQLiteStore: CustomDebugStringConvertible, CoreStoreDebugStringC
|
||||
}
|
||||
|
||||
|
||||
// MARK: - LegacyXcodeDataModel
|
||||
|
||||
extension LegacyXcodeDataModel: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
|
||||
// MARK: CustomDebugStringConvertible
|
||||
|
||||
public var debugDescription: String {
|
||||
|
||||
return formattedDebugDescription(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreDebugStringConvertible
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
return createFormattedString(
|
||||
"(", ")",
|
||||
("modelVersion", self.modelVersion),
|
||||
("rawModel", self.rawModel())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ListMonitor
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@@ -456,7 +531,7 @@ extension MigrationChain: CustomDebugStringConvertible, CoreStoreDebugStringConv
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
guard self.valid else {
|
||||
guard self.isValid else {
|
||||
|
||||
return "<invalid migration chain>"
|
||||
}
|
||||
@@ -669,6 +744,32 @@ extension SectionBy: CustomDebugStringConvertible, CoreStoreDebugStringConvertib
|
||||
}
|
||||
|
||||
|
||||
// MARK: - SchemaHistory
|
||||
|
||||
extension SchemaHistory: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
|
||||
// MARK: CustomDebugStringConvertible
|
||||
|
||||
public var debugDescription: String {
|
||||
|
||||
return formattedDebugDescription(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreDebugStringConvertible
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
return createFormattedString(
|
||||
"(", ")",
|
||||
("currentModelVersion", self.currentModelVersion),
|
||||
("migrationChain", self.migrationChain),
|
||||
("schemaByVersion", self.schemaByVersion)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Select
|
||||
|
||||
extension Select: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
@@ -896,6 +997,32 @@ extension Where: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
}
|
||||
|
||||
|
||||
// MARK: - XcodeDataModel
|
||||
|
||||
extension XcodeDataModel: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||
|
||||
// MARK: CustomDebugStringConvertible
|
||||
|
||||
public var debugDescription: String {
|
||||
|
||||
return formattedDebugDescription(self)
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreDebugStringConvertible
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
return createFormattedString(
|
||||
"(", ")",
|
||||
("modelVersion", self.modelVersion),
|
||||
("modelVersionFileURL", self.modelVersionFileURL),
|
||||
("rawModel", self.rawModel())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private: Utilities
|
||||
|
||||
private typealias DumpInfo = [(key: String, value: Any)]
|
||||
@@ -972,7 +1099,7 @@ public protocol CoreStoreDebugStringConvertible {
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private:
|
||||
// MARK: - Standard Types:
|
||||
|
||||
extension Array: CoreStoreDebugStringConvertible {
|
||||
|
||||
@@ -1214,7 +1341,15 @@ extension NSSortDescriptor: CoreStoreDebugStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
extension URL: CoreStoreDebugStringConvertible {
|
||||
extension NSString: CoreStoreDebugStringConvertible {
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
return "\"\(self)\""
|
||||
}
|
||||
}
|
||||
|
||||
extension NSURL: CoreStoreDebugStringConvertible {
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
@@ -1249,3 +1384,11 @@ extension String: CoreStoreDebugStringConvertible {
|
||||
return "\"\(self)\""
|
||||
}
|
||||
}
|
||||
|
||||
extension URL: CoreStoreDebugStringConvertible {
|
||||
|
||||
public var coreStoreDumpString: String {
|
||||
|
||||
return "\"\(self)\""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ public extension DataStack {
|
||||
|
||||
try storage.eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
soureModelHint: self.model[metadata]
|
||||
soureModelHint: self.schemaHistory.schema(for: metadata)?.rawModel()
|
||||
)
|
||||
_ = try self.addStorageAndWait(storage)
|
||||
|
||||
@@ -382,7 +382,9 @@ public extension DataStack {
|
||||
at: cacheFileURL,
|
||||
options: storeOptions
|
||||
)
|
||||
_ = try self.model[metadata].flatMap(storage.eraseStorageAndWait)
|
||||
_ = try self.schemaHistory
|
||||
.schema(for: metadata)
|
||||
.flatMap({ try storage.eraseStorageAndWait(soureModel: $0.rawModel()) })
|
||||
_ = try self.createPersistentStoreFromStorage(
|
||||
storage,
|
||||
finalURL: cacheFileURL,
|
||||
@@ -497,7 +499,7 @@ public extension DataStack {
|
||||
|
||||
let error = CoreStoreError.mappingModelNotFound(
|
||||
localStoreURL: fileURL,
|
||||
targetModel: self.model,
|
||||
targetModel: self.schemaHistory.rawModel,
|
||||
targetModelVersion: self.modelVersion
|
||||
)
|
||||
CoreStore.log(
|
||||
@@ -545,12 +547,12 @@ public extension DataStack {
|
||||
|
||||
let error = CoreStoreError.mappingModelNotFound(
|
||||
localStoreURL: storage.fileURL,
|
||||
targetModel: self.model,
|
||||
targetModel: self.schemaHistory.rawModel,
|
||||
targetModelVersion: self.modelVersion
|
||||
)
|
||||
CoreStore.log(
|
||||
error,
|
||||
"Failed to find migration steps from \(cs_typeName(storage)) at URL \"\(storage.fileURL)\" to version model \"\(self.model)\"."
|
||||
"Failed to find migration steps from \(cs_typeName(storage)) at URL \"\(storage.fileURL)\" to version model \"\(self.schemaHistory.rawModel)\"."
|
||||
)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
@@ -592,7 +594,7 @@ public extension DataStack {
|
||||
let progress = Progress(parent: nil, userInfo: nil)
|
||||
progress.totalUnitCount = numberOfMigrations
|
||||
|
||||
for (sourceModel, destinationModel, mappingModel, _) in migrationSteps {
|
||||
for (sourceModel, destinationModel, mappingModel, migrationType) in migrationSteps {
|
||||
|
||||
progress.becomeCurrent(withPendingUnitCount: 1)
|
||||
|
||||
@@ -620,8 +622,13 @@ public extension DataStack {
|
||||
)
|
||||
}
|
||||
catch {
|
||||
|
||||
migrationResult = MigrationResult(error)
|
||||
|
||||
let migrationError = CoreStoreError(error)
|
||||
CoreStore.log(
|
||||
migrationError,
|
||||
"Failed to migrate version model \"\(migrationType.sourceVersion)\" to version \"\(migrationType.destinationVersion)\"."
|
||||
)
|
||||
migrationResult = MigrationResult(migrationError)
|
||||
cancelled = true
|
||||
}
|
||||
}
|
||||
@@ -658,28 +665,27 @@ public extension DataStack {
|
||||
|
||||
private func computeMigrationFromStorage<T: LocalStorage>(_ storage: T, metadata: [String: Any]) -> [(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType)]? {
|
||||
|
||||
let model = self.model
|
||||
if model.isConfiguration(withName: storage.configuration, compatibleWithStoreMetadata: metadata) {
|
||||
let schemaHistory = self.schemaHistory
|
||||
if schemaHistory.rawModel.isConfiguration(withName: storage.configuration, compatibleWithStoreMetadata: metadata) {
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
guard let initialModel = model[metadata],
|
||||
var currentVersion = initialModel.currentModelVersion else {
|
||||
|
||||
return nil
|
||||
guard let initialSchema = schemaHistory.schema(for: metadata) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
let migrationChain: MigrationChain = self.migrationChain.empty
|
||||
? [currentVersion: model.currentModelVersion!]
|
||||
: self.migrationChain
|
||||
var currentVersion = initialSchema.modelVersion
|
||||
let migrationChain: MigrationChain = schemaHistory.migrationChain.isEmpty
|
||||
? [currentVersion: schemaHistory.currentModelVersion]
|
||||
: schemaHistory.migrationChain
|
||||
|
||||
var migrationSteps = [(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType)]()
|
||||
|
||||
while let nextVersion = migrationChain.nextVersionFrom(currentVersion),
|
||||
let sourceModel = model[currentVersion],
|
||||
sourceModel != model,
|
||||
let destinationModel = model[nextVersion] {
|
||||
let sourceModel = schemaHistory.rawModel(for: currentVersion),
|
||||
sourceModel != schemaHistory.rawModel,
|
||||
let destinationModel = schemaHistory.rawModel(for: nextVersion) {
|
||||
|
||||
if let mappingModel = NSMappingModel(
|
||||
from: storage.mappingModelBundles,
|
||||
@@ -727,7 +733,7 @@ public extension DataStack {
|
||||
currentVersion = nextVersion
|
||||
}
|
||||
|
||||
if migrationSteps.last?.destinationModel == model {
|
||||
if migrationSteps.last?.destinationModel == schemaHistory.rawModel {
|
||||
|
||||
return migrationSteps
|
||||
}
|
||||
@@ -775,21 +781,8 @@ public extension DataStack {
|
||||
}
|
||||
catch {
|
||||
|
||||
do {
|
||||
|
||||
try fileManager.removeItem(at: temporaryFileURL)
|
||||
}
|
||||
catch _ { }
|
||||
|
||||
let sourceVersion = migrationManager.sourceModel.currentModelVersion ?? "???"
|
||||
let destinationVersion = migrationManager.destinationModel.currentModelVersion ?? "???"
|
||||
let migrationError = CoreStoreError(error)
|
||||
CoreStore.log(
|
||||
migrationError,
|
||||
"Failed to migrate from version model \"\(sourceVersion)\" to version model \"\(destinationVersion)\"."
|
||||
)
|
||||
|
||||
throw migrationError
|
||||
_ = try? fileManager.removeItem(at: temporaryFileURL)
|
||||
throw CoreStoreError(error)
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -806,21 +799,8 @@ public extension DataStack {
|
||||
}
|
||||
catch {
|
||||
|
||||
do {
|
||||
|
||||
try fileManager.removeItem(at: temporaryFileURL)
|
||||
}
|
||||
catch _ { }
|
||||
|
||||
let sourceVersion = migrationManager.sourceModel.currentModelVersion ?? "???"
|
||||
let destinationVersion = migrationManager.destinationModel.currentModelVersion ?? "???"
|
||||
let fileError = CoreStoreError(error)
|
||||
CoreStore.log(
|
||||
fileError,
|
||||
"Failed to save store after migrating from version model \"\(sourceVersion)\" to version model \"\(destinationVersion)\"."
|
||||
)
|
||||
|
||||
throw fileError
|
||||
_ = try? fileManager.removeItem(at: temporaryFileURL)
|
||||
throw CoreStoreError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
self.versionTree = [:]
|
||||
self.rootVersions = []
|
||||
self.leafVersions = []
|
||||
self.valid = true
|
||||
self.isValid = true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +81,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
self.versionTree = [:]
|
||||
self.rootVersions = [value]
|
||||
self.leafVersions = [value]
|
||||
self.valid = true
|
||||
self.isValid = true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,13 +93,13 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
|
||||
var lastVersion: String?
|
||||
var versionTree = [String: String]()
|
||||
var valid = true
|
||||
var isValid = true
|
||||
for version in elements {
|
||||
|
||||
if let lastVersion = lastVersion,
|
||||
let _ = versionTree.updateValue(version, forKey: lastVersion) {
|
||||
|
||||
valid = false
|
||||
isValid = false
|
||||
}
|
||||
lastVersion = version
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
self.versionTree = versionTree
|
||||
self.rootVersions = Set(elements.prefix(1))
|
||||
self.leafVersions = Set(elements.suffix(1))
|
||||
self.valid = valid
|
||||
self.isValid = isValid
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,7 +115,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
*/
|
||||
public init(_ elements: [(String, String)]) {
|
||||
|
||||
var valid = true
|
||||
var isValid = true
|
||||
var versionTree = [String: String]()
|
||||
elements.forEach { (sourceVersion, destinationVersion) in
|
||||
|
||||
@@ -126,7 +126,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
|
||||
CoreStore.assert(false, "\(cs_typeName(MigrationChain.self))'s migration chain could not be created due to ambiguous version paths.")
|
||||
|
||||
valid = false
|
||||
isValid = false
|
||||
}
|
||||
let leafVersions = Set(
|
||||
elements
|
||||
@@ -156,7 +156,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
self.versionTree = versionTree
|
||||
self.rootVersions = Set(versionTree.keys).subtracting(versionTree.values)
|
||||
self.leafVersions = leafVersions
|
||||
self.valid = valid && Set(versionTree.keys).union(versionTree.values).filter { isVersionAmbiguous($0) }.count <= 0
|
||||
self.isValid = isValid && Set(versionTree.keys).union(versionTree.values).filter { isVersionAmbiguous($0) }.count <= 0
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +223,7 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
return lhs.versionTree == rhs.versionTree
|
||||
&& lhs.rootVersions == rhs.rootVersions
|
||||
&& lhs.leafVersions == rhs.leafVersions
|
||||
&& lhs.valid == rhs.valid
|
||||
&& lhs.isValid == rhs.isValid
|
||||
}
|
||||
|
||||
|
||||
@@ -231,9 +231,9 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
|
||||
|
||||
internal let rootVersions: Set<String>
|
||||
internal let leafVersions: Set<String>
|
||||
internal let valid: Bool
|
||||
internal let isValid: Bool
|
||||
|
||||
internal var empty: Bool {
|
||||
internal var isEmpty: Bool {
|
||||
|
||||
return self.versionTree.count <= 0
|
||||
}
|
||||
|
||||
@@ -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: XcdatamodelFilename?, bundle: Bundle?, versionChain: [String]?) {
|
||||
public convenience init(modelName: XcodeDataModelFileName?, 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: XcdatamodelFilename?, bundle: Bundle?, versionTree: [String: String]?) {
|
||||
public convenience init(modelName: XcodeDataModelFileName?, bundle: Bundle?, versionTree: [String: String]?) {
|
||||
|
||||
self.init(
|
||||
DataStack(
|
||||
@@ -84,40 +84,6 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from an `NSManagedObjectModel`.
|
||||
|
||||
- parameter model: the `NSManagedObjectModel` for the stack
|
||||
- parameter versionChain: 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.
|
||||
*/
|
||||
@objc
|
||||
public convenience init(model: NSManagedObjectModel, versionChain: [String]?) {
|
||||
|
||||
self.init(
|
||||
DataStack(
|
||||
model: model,
|
||||
migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from an `NSManagedObjectModel`.
|
||||
|
||||
- parameter model: the `NSManagedObjectModel` for the stack
|
||||
- parameter versionTree: 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.
|
||||
*/
|
||||
@objc
|
||||
public convenience init(model: NSManagedObjectModel, versionTree: [String]?) {
|
||||
|
||||
self.init(
|
||||
DataStack(
|
||||
model: model,
|
||||
migrationChain: versionTree.flatMap { MigrationChain($0) } ?? nil
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the stack's model version. The version string is the same as the name of the version-specific .xcdatamodeld file.
|
||||
*/
|
||||
@@ -261,6 +227,42 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from an `NSManagedObjectModel`.
|
||||
|
||||
- parameter model: the `NSManagedObjectModel` for the stack
|
||||
- parameter versionChain: 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.
|
||||
*/
|
||||
@available(*, deprecated: 3.1, message: "Use the -[initWithModelName:bundle:versionChain:] initializer.")
|
||||
@objc
|
||||
public convenience init(model: NSManagedObjectModel, versionChain: [String]?) {
|
||||
|
||||
self.init(
|
||||
DataStack(
|
||||
model: model,
|
||||
migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from an `NSManagedObjectModel`.
|
||||
|
||||
- parameter model: the `NSManagedObjectModel` for the stack
|
||||
- parameter versionTree: 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.
|
||||
*/
|
||||
@available(*, deprecated: 3.1, message: "Use the -[initWithModelName:bundle:versionTree:] initializer.")
|
||||
@objc
|
||||
public convenience init(model: NSManagedObjectModel, versionTree: [String]?) {
|
||||
|
||||
self.init(
|
||||
DataStack(
|
||||
model: model,
|
||||
migrationChain: versionTree.flatMap { MigrationChain($0) } ?? nil
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the entity name-to-class type mapping from the stack's model.
|
||||
*/
|
||||
|
||||
@@ -41,30 +41,24 @@ 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: XcdatamodelFilename = DataStack.applicationName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) {
|
||||
public convenience init(modelName: XcodeDataModelFileName = DataStack.applicationName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) {
|
||||
|
||||
let model = NSManagedObjectModel.fromBundle(
|
||||
bundle,
|
||||
modelName: modelName,
|
||||
modelVersionHints: migrationChain.leafVersions
|
||||
)
|
||||
self.init(model: model, migrationChain: migrationChain)
|
||||
}
|
||||
|
||||
public convenience init(dynamicModel: DynamicModel) {
|
||||
|
||||
self.init(model: dynamicModel.createModel())
|
||||
}
|
||||
|
||||
public convenience init(dynamicModels: [DynamicModel], migrationChain: MigrationChain = nil) {
|
||||
|
||||
CoreStore.assert(
|
||||
migrationChain.valid,
|
||||
"Invalid migration chain passed to the \(cs_typeName(DataStack.self)). Check that the model versions' order is correct and that no repetitions or ambiguities exist."
|
||||
)
|
||||
self.init(
|
||||
model: NSManagedObjectModel(byMerging: dynamicModels.map({ $0.createModel() }))!,
|
||||
migrationChain: migrationChain
|
||||
schemaHistory: SchemaHistory(
|
||||
modelName: modelName,
|
||||
bundle: bundle,
|
||||
migrationChain: migrationChain
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
public convenience init(_ schema: DynamicSchema, _ otherSchema: DynamicSchema..., migrationChain: MigrationChain = nil) {
|
||||
|
||||
self.init(
|
||||
schemaHistory: SchemaHistory(
|
||||
allSchema: [schema] + otherSchema,
|
||||
migrationChain: migrationChain
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -74,21 +68,20 @@ public final class DataStack: Equatable {
|
||||
- parameter model: the `NSManagedObjectModel` for the stack
|
||||
- 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 required init(model: NSManagedObjectModel, migrationChain: MigrationChain = nil) {
|
||||
public required init(schemaHistory: SchemaHistory) {
|
||||
|
||||
// TODO: test before release (rolled back)
|
||||
// _ = DataStack.isGloballyInitialized
|
||||
|
||||
CoreStore.assert(
|
||||
migrationChain.valid,
|
||||
schemaHistory.migrationChain.isValid,
|
||||
"Invalid migration chain passed to the \(cs_typeName(DataStack.self)). Check that the model versions' order is correct and that no repetitions or ambiguities exist."
|
||||
)
|
||||
|
||||
self.coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
|
||||
self.coordinator = NSPersistentStoreCoordinator(managedObjectModel: schemaHistory.rawModel)
|
||||
self.rootSavingContext = NSManagedObjectContext.rootSavingContextForCoordinator(self.coordinator)
|
||||
self.mainContext = NSManagedObjectContext.mainContextForRootContext(self.rootSavingContext)
|
||||
self.model = model
|
||||
self.migrationChain = migrationChain
|
||||
self.schemaHistory = schemaHistory
|
||||
|
||||
self.rootSavingContext.parentStack = self
|
||||
|
||||
@@ -100,7 +93,7 @@ public final class DataStack: Equatable {
|
||||
*/
|
||||
public var modelVersion: String {
|
||||
|
||||
return self.model.currentModelVersion!
|
||||
return self.schemaHistory.currentModelVersion
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +102,7 @@ public final class DataStack: Equatable {
|
||||
public func entityTypesByName(for type: NSManagedObject.Type) -> [EntityName: NSManagedObject.Type] {
|
||||
|
||||
var entityTypesByName: [EntityName: NSManagedObject.Type] = [:]
|
||||
for (entityIdentifier, entityDescription) in self.model.entityDescriptionsByEntityIdentifier {
|
||||
for (entityIdentifier, entityDescription) in self.schemaHistory.entityDescriptionsByEntityIdentifier {
|
||||
|
||||
switch entityIdentifier.category {
|
||||
|
||||
@@ -133,7 +126,7 @@ public final class DataStack: Equatable {
|
||||
public func entityTypesByName(for type: CoreStoreObject.Type) -> [EntityName: CoreStoreObject.Type] {
|
||||
|
||||
var entityTypesByName: [EntityName: CoreStoreObject.Type] = [:]
|
||||
for (entityIdentifier, entityDescription) in self.model.entityDescriptionsByEntityIdentifier {
|
||||
for (entityIdentifier, entityDescription) in self.schemaHistory.entityDescriptionsByEntityIdentifier {
|
||||
|
||||
switch entityIdentifier.category {
|
||||
|
||||
@@ -332,7 +325,7 @@ public final class DataStack: Equatable {
|
||||
)
|
||||
try storage.eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
soureModelHint: self.model[metadata]
|
||||
soureModelHint: self.schemaHistory.schema(for: metadata)?.rawModel()
|
||||
)
|
||||
let finalStoreOptions = storage.dictionary(forOptions: storage.localStorageOptions)
|
||||
_ = try self.createPersistentStoreFromStorage(
|
||||
@@ -425,7 +418,9 @@ public final class DataStack: Equatable {
|
||||
at: cacheFileURL,
|
||||
options: storeOptions
|
||||
)
|
||||
_ = try self.model[metadata].flatMap(storage.eraseStorageAndWait)
|
||||
_ = try self.schemaHistory
|
||||
.schema(for: metadata)
|
||||
.flatMap({ try storage.eraseStorageAndWait(soureModel: $0.rawModel()) })
|
||||
_ = try self.createPersistentStoreFromStorage(
|
||||
storage,
|
||||
finalURL: cacheFileURL,
|
||||
@@ -464,11 +459,10 @@ public final class DataStack: Equatable {
|
||||
internal let coordinator: NSPersistentStoreCoordinator
|
||||
internal let rootSavingContext: NSManagedObjectContext
|
||||
internal let mainContext: NSManagedObjectContext
|
||||
internal let model: NSManagedObjectModel
|
||||
internal let migrationChain: MigrationChain
|
||||
internal let schemaHistory: SchemaHistory
|
||||
internal let childTransactionQueue = DispatchQueue.serial("com.coreStore.dataStack.childTransactionQueue")
|
||||
internal let storeMetadataUpdateQueue = DispatchQueue.concurrent("com.coreStore.persistentStoreBarrierQueue")
|
||||
internal let migrationQueue: OperationQueue = {
|
||||
internal let migrationQueue: OperationQueue = cs_lazy {
|
||||
|
||||
let migrationQueue = OperationQueue()
|
||||
migrationQueue.maxConcurrentOperationCount = 1
|
||||
@@ -476,7 +470,7 @@ public final class DataStack: Equatable {
|
||||
migrationQueue.qualityOfService = .utility
|
||||
migrationQueue.underlyingQueue = DispatchQueue.serial("com.coreStore.migrationQueue", qos: .userInitiated)
|
||||
return migrationQueue
|
||||
}()
|
||||
}
|
||||
|
||||
internal func persistentStoreForStorage(_ storage: StorageInterface) -> NSPersistentStore? {
|
||||
|
||||
@@ -562,7 +556,7 @@ public final class DataStack: Equatable {
|
||||
|
||||
internal func entityDescription(for entityIdentifier: EntityIdentifier) -> NSEntityDescription? {
|
||||
|
||||
return self.model.entityDescriptionsByEntityIdentifier[entityIdentifier]
|
||||
return self.schemaHistory.entityDescriptionsByEntityIdentifier[entityIdentifier]
|
||||
}
|
||||
|
||||
|
||||
@@ -596,6 +590,30 @@ public final class DataStack: Equatable {
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from an `NSManagedObjectModel`.
|
||||
|
||||
- parameter model: the `NSManagedObjectModel` for the stack
|
||||
- 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.
|
||||
*/
|
||||
@available(*, deprecated: 3.1, message: "Use the new DataStack.init(schemaHistory:) initializer passing a LegacyXcodeDataModel instance as argument")
|
||||
public convenience init(model: NSManagedObjectModel, migrationChain: MigrationChain = nil) {
|
||||
|
||||
let modelVersion = migrationChain.leafVersions.first!
|
||||
self.init(
|
||||
schemaHistory: SchemaHistory(
|
||||
allSchema: [
|
||||
LegacyXcodeDataModel(
|
||||
modelName: modelVersion,
|
||||
model: model
|
||||
)
|
||||
],
|
||||
migrationChain: migrationChain,
|
||||
exactCurrentModelVersion: modelVersion
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the entity name-to-class type mapping from the `DataStack`'s model.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// DynamicModel.swift
|
||||
// CoreStoreSchema.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2017 John Rommel Estropia
|
||||
@@ -23,20 +23,31 @@
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import CoreGraphics
|
||||
import CoreData
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: - DynamicModel
|
||||
// MARK: - CoreStoreSchema
|
||||
|
||||
public final class DynamicModel {
|
||||
public final class CoreStoreSchema: DynamicSchema {
|
||||
|
||||
public convenience init(version: String, entities: [EntityProtocol]) {
|
||||
public convenience init(modelVersion: String, _ entity: DynamicEntity, _ entities: DynamicEntity...) {
|
||||
|
||||
self.init(version: version, entitiesByConfiguration: [DataStack.defaultConfigurationName: entities])
|
||||
self.init(
|
||||
modelVersion: modelVersion,
|
||||
entities: [entity] + entities
|
||||
)
|
||||
}
|
||||
|
||||
public required init(version: String, entitiesByConfiguration: [String: [EntityProtocol]]) {
|
||||
public convenience init(modelVersion: String, entities: [DynamicEntity]) {
|
||||
|
||||
self.init(
|
||||
modelVersion: modelVersion,
|
||||
entitiesByConfiguration: [DataStack.defaultConfigurationName: entities]
|
||||
)
|
||||
}
|
||||
|
||||
public required init(modelVersion: String, entitiesByConfiguration: [String: [DynamicEntity]]) {
|
||||
|
||||
var actualEntitiesByConfiguration: [String: Set<AnyEntity>] = [:]
|
||||
for (configuration, entities) in entitiesByConfiguration {
|
||||
@@ -56,19 +67,57 @@ public final class DynamicModel {
|
||||
"Ambiguous entity types or entity names were found in the model. Ensure that the entity types and entity names are unique to each other. Entities: \(allEntities)"
|
||||
)
|
||||
|
||||
self.version = version
|
||||
self.modelVersion = modelVersion
|
||||
self.entitiesByConfiguration = actualEntitiesByConfiguration
|
||||
self.allEntities = allEntities
|
||||
}
|
||||
|
||||
|
||||
// MARK: - DynamicSchema
|
||||
|
||||
public let modelVersion: ModelVersion
|
||||
|
||||
public func rawModel() -> NSManagedObjectModel {
|
||||
|
||||
if let cachedRawModel = self.cachedRawModel {
|
||||
|
||||
return cachedRawModel
|
||||
}
|
||||
let rawModel = NSManagedObjectModel()
|
||||
var entityDescriptionsByEntity: [AnyEntity: NSEntityDescription] = [:]
|
||||
for entity in self.allEntities {
|
||||
|
||||
let entityDescription = self.entityDescription(
|
||||
for: entity,
|
||||
initializer: CoreStoreSchema.firstPassCreateEntityDescription
|
||||
)
|
||||
entityDescriptionsByEntity[entity] = (entityDescription.copy() as! NSEntityDescription)
|
||||
}
|
||||
CoreStoreSchema.secondPassConnectRelationshipAttributes(for: entityDescriptionsByEntity)
|
||||
CoreStoreSchema.thirdPassConnectInheritanceTree(for: entityDescriptionsByEntity)
|
||||
|
||||
rawModel.entities = entityDescriptionsByEntity.values.sorted(by: { $0.name! < $1.name! })
|
||||
for (configuration, entities) in self.entitiesByConfiguration {
|
||||
|
||||
rawModel.setEntities(
|
||||
entities
|
||||
.map({ entityDescriptionsByEntity[$0]! })
|
||||
.sorted(by: { $0.name! < $1.name! }),
|
||||
forConfigurationName: configuration
|
||||
)
|
||||
}
|
||||
self.cachedRawModel = rawModel
|
||||
return rawModel
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
// MARK: - AnyEntity
|
||||
|
||||
internal struct AnyEntity: EntityProtocol, Hashable {
|
||||
internal struct AnyEntity: DynamicEntity, Hashable {
|
||||
|
||||
internal init(_ entity: EntityProtocol) {
|
||||
internal init(_ entity: DynamicEntity) {
|
||||
|
||||
self.type = entity.type
|
||||
self.entityName = entity.entityName
|
||||
@@ -97,7 +146,7 @@ public final class DynamicModel {
|
||||
^ self.entityName.hashValue
|
||||
}
|
||||
|
||||
// MARK: EntityProtocol
|
||||
// MARK: DynamicEntity
|
||||
|
||||
internal let type: CoreStoreObject.Type
|
||||
internal let entityName: EntityName
|
||||
@@ -106,41 +155,30 @@ public final class DynamicModel {
|
||||
|
||||
// MARK: -
|
||||
|
||||
internal func createModel() -> NSManagedObjectModel {
|
||||
internal let entitiesByConfiguration: [String: Set<AnyEntity>]
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private static let barrierQueue = DispatchQueue.concurrent("com.coreStore.coreStoreDataModelBarrierQueue")
|
||||
|
||||
private let allEntities: Set<AnyEntity>
|
||||
|
||||
private var entityDescriptionsByEntity: [CoreStoreSchema.AnyEntity: NSEntityDescription] = [:]
|
||||
private weak var cachedRawModel: NSManagedObjectModel?
|
||||
|
||||
private func entityDescription(for entity: CoreStoreSchema.AnyEntity, initializer: (CoreStoreSchema.AnyEntity) -> NSEntityDescription) -> NSEntityDescription {
|
||||
|
||||
let model = NSManagedObjectModel()
|
||||
let entityDescriptionsByEntity: [AnyEntity: NSEntityDescription] = ModelCache.performUpdate {
|
||||
if let cachedEntityDescription = self.entityDescriptionsByEntity[entity] {
|
||||
|
||||
var entityDescriptionsByEntity: [AnyEntity: NSEntityDescription] = [:]
|
||||
for entity in self.allEntities {
|
||||
|
||||
let entityDescription = ModelCache.entityDescription(
|
||||
for: entity,
|
||||
initializer: DynamicModel.firstPassCreateEntityDescription
|
||||
)
|
||||
entityDescriptionsByEntity[entity] = entityDescription
|
||||
}
|
||||
DynamicModel.secondPassConnectRelationshipAttributes(for: entityDescriptionsByEntity)
|
||||
DynamicModel.thirdPassConnectInheritanceTree(for: entityDescriptionsByEntity)
|
||||
return entityDescriptionsByEntity
|
||||
return cachedEntityDescription
|
||||
}
|
||||
model.entities = entityDescriptionsByEntity.values.sorted(by: { $0.name! < $1.name! })
|
||||
for (configuration, entities) in self.entitiesByConfiguration {
|
||||
|
||||
model.setEntities(
|
||||
entities
|
||||
.map({ entityDescriptionsByEntity[$0]! })
|
||||
.sorted(by: { $0.name! < $1.name! }),
|
||||
forConfigurationName: configuration
|
||||
)
|
||||
}
|
||||
return model
|
||||
let entityDescription = withoutActuallyEscaping(initializer, do: { $0(entity) })
|
||||
self.entityDescriptionsByEntity[entity] = entityDescription
|
||||
return entityDescription
|
||||
}
|
||||
|
||||
|
||||
// MARK: FilePrivate
|
||||
|
||||
fileprivate static func firstPassCreateEntityDescription(from entity: AnyEntity) -> NSEntityDescription {
|
||||
private static func firstPassCreateEntityDescription(from entity: AnyEntity) -> NSEntityDescription {
|
||||
|
||||
let entityDescription = NSEntityDescription()
|
||||
entityDescription.anyEntity = entity
|
||||
@@ -186,7 +224,7 @@ public final class DynamicModel {
|
||||
return entityDescription
|
||||
}
|
||||
|
||||
fileprivate static func secondPassConnectRelationshipAttributes(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) {
|
||||
private static func secondPassConnectRelationshipAttributes(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) {
|
||||
|
||||
var relationshipsByNameByEntity: [AnyEntity: [String: NSRelationshipDescription]] = [:]
|
||||
for (entity, entityDescription) in entityDescriptionsByEntity {
|
||||
@@ -207,7 +245,7 @@ public final class DynamicModel {
|
||||
if matchedEntities.isEmpty {
|
||||
|
||||
CoreStore.abort(
|
||||
"No \(cs_typeName("Entity<\(type)>")) instance found in the \(cs_typeName(DynamicModel.self))."
|
||||
"No \(cs_typeName("Entity<\(type)>")) instance found in the \(cs_typeName(CoreStoreSchema.self))."
|
||||
)
|
||||
}
|
||||
else {
|
||||
@@ -277,7 +315,7 @@ public final class DynamicModel {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate static func thirdPassConnectInheritanceTree(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) {
|
||||
private static func thirdPassConnectInheritanceTree(for entityDescriptionsByEntity: [AnyEntity: NSEntityDescription]) {
|
||||
|
||||
func connectBaseEntity(mirror: Mirror, entityDescription: NSEntityDescription) {
|
||||
|
||||
@@ -304,40 +342,4 @@ public final class DynamicModel {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let version: String
|
||||
private let allEntities: Set<AnyEntity>
|
||||
private let entitiesByConfiguration: [String: Set<AnyEntity>]
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ModelCache
|
||||
|
||||
fileprivate enum ModelCache {
|
||||
|
||||
fileprivate static func performUpdate<T>(_ closure: () -> T) -> T {
|
||||
|
||||
return self.barrierQueue.cs_barrierSync(closure)
|
||||
}
|
||||
|
||||
fileprivate static func entityDescription(for entity: DynamicModel.AnyEntity, initializer: (DynamicModel.AnyEntity) -> NSEntityDescription) -> NSEntityDescription {
|
||||
|
||||
if let cachedEntityDescription = self.entityDescriptionsByEntity[entity] {
|
||||
|
||||
return cachedEntityDescription
|
||||
}
|
||||
let entityDescription = withoutActuallyEscaping(initializer, do: { $0(entity) })
|
||||
self.entityDescriptionsByEntity[entity] = entityDescription
|
||||
return entityDescription
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private static let barrierQueue = DispatchQueue.concurrent("com.coreStore.modelCacheBarrierQueue")
|
||||
|
||||
private static var entityDescriptionsByEntity: [DynamicModel.AnyEntity: NSEntityDescription] = [:]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// DynamicSchema.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: - DynamicSchema
|
||||
|
||||
public protocol DynamicSchema {
|
||||
|
||||
var modelVersion: ModelVersion { get }
|
||||
|
||||
func rawModel() -> NSManagedObjectModel
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// LegacyXcodeDataModel.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: - LegacyXcodeDataModel
|
||||
|
||||
public final class LegacyXcodeDataModel: DynamicSchema {
|
||||
|
||||
public required init(modelName: ModelVersion, model: NSManagedObjectModel) {
|
||||
|
||||
self.modelVersion = modelName
|
||||
self.model = model
|
||||
}
|
||||
|
||||
|
||||
// MARK: DynamicSchema
|
||||
|
||||
public let modelVersion: ModelVersion
|
||||
|
||||
public func rawModel() -> NSManagedObjectModel {
|
||||
|
||||
return self.model
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let model: NSManagedObjectModel
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// XcodeDataModel.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: - XcodeDataModel
|
||||
|
||||
public final class XcodeDataModel: DynamicSchema {
|
||||
|
||||
public required init(modelVersion: ModelVersion, modelVersionFileURL: URL) {
|
||||
|
||||
CoreStore.assert(
|
||||
NSManagedObjectModel(contentsOf: modelVersionFileURL) != nil,
|
||||
"Could not find the \"\(modelVersion).mom\" version file for the model at URL \"\(modelVersionFileURL)\"."
|
||||
)
|
||||
|
||||
self.modelVersion = modelVersion
|
||||
self.modelVersionFileURL = modelVersionFileURL
|
||||
}
|
||||
|
||||
|
||||
// MARK: DynamicSchema
|
||||
|
||||
public let modelVersion: ModelVersion
|
||||
|
||||
public func rawModel() -> NSManagedObjectModel {
|
||||
|
||||
if let cachedRawModel = self.cachedRawModel {
|
||||
|
||||
return cachedRawModel
|
||||
}
|
||||
if let rawModel = NSManagedObjectModel(contentsOf: self.modelVersionFileURL) {
|
||||
|
||||
self.cachedRawModel = rawModel
|
||||
return rawModel
|
||||
}
|
||||
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel.self)) from the model at URL \"\(self.modelVersionFileURL)\".")
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let modelVersionFileURL: URL
|
||||
|
||||
private lazy var rootModelFileURL: URL = cs_lazy { [unowned self] in
|
||||
|
||||
return self.modelVersionFileURL.deletingLastPathComponent()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private weak var cachedRawModel: NSManagedObjectModel?
|
||||
}
|
||||
@@ -28,9 +28,9 @@ import Foundation
|
||||
import ObjectiveC
|
||||
|
||||
|
||||
// MARK: - EntityProtocol
|
||||
// MARK: - DynamicEntity
|
||||
|
||||
public protocol EntityProtocol {
|
||||
public protocol DynamicEntity {
|
||||
|
||||
var type: CoreStoreObject.Type { get }
|
||||
var entityName: EntityName { get }
|
||||
@@ -39,7 +39,7 @@ public protocol EntityProtocol {
|
||||
|
||||
// MARK: Entity
|
||||
|
||||
public struct Entity<O: CoreStoreObject>: EntityProtocol {
|
||||
public struct Entity<O: CoreStoreObject>: DynamicEntity, Hashable {
|
||||
|
||||
public init(_ entityName: String) {
|
||||
|
||||
@@ -47,136 +47,54 @@ public struct Entity<O: CoreStoreObject>: EntityProtocol {
|
||||
self.entityName = entityName
|
||||
}
|
||||
|
||||
// MARK: EntityProtocol
|
||||
public init(_ type: O.Type, _ entityName: String) {
|
||||
|
||||
self.type = type
|
||||
self.entityName = entityName
|
||||
}
|
||||
|
||||
|
||||
// MARK: - VersionHash
|
||||
|
||||
public struct VersionHash: ExpressibleByArrayLiteral {
|
||||
|
||||
let hash: Data
|
||||
|
||||
public init(_ hash: Data) {
|
||||
|
||||
self.hash = hash
|
||||
}
|
||||
|
||||
|
||||
// MARK: ExpressibleByArrayLiteral
|
||||
|
||||
public typealias Element = UInt8
|
||||
|
||||
public init(arrayLiteral elements: UInt8...) {
|
||||
|
||||
self.hash = Data(bytes: elements)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: DynamicEntity
|
||||
|
||||
public let type: CoreStoreObject.Type
|
||||
public let entityName: EntityName
|
||||
}
|
||||
|
||||
|
||||
// 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: CoreStoreObject.Type) {
|
||||
|
||||
self.category = .coreStore
|
||||
self.interfacedClassName = String(reflecting: type)
|
||||
}
|
||||
|
||||
internal init(_ type: DynamicObject.Type) {
|
||||
|
||||
switch type {
|
||||
|
||||
case let type as NSManagedObject.Type:
|
||||
self.init(type)
|
||||
|
||||
case let type as CoreStoreObject.Type:
|
||||
self.init(type)
|
||||
|
||||
default:
|
||||
CoreStore.abort("\(cs_typeName(DynamicObject.self)) is not meant to be implemented by external types.")
|
||||
}
|
||||
}
|
||||
|
||||
internal init(_ entityDescription: NSEntityDescription) {
|
||||
|
||||
if let entity = entityDescription.anyEntity {
|
||||
|
||||
self.category = .coreStore
|
||||
self.interfacedClassName = NSStringFromClass(entity.type)
|
||||
}
|
||||
else {
|
||||
|
||||
self.category = .coreData
|
||||
self.interfacedClassName = entityDescription.managedObjectClassName!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Equatable
|
||||
|
||||
static func == (lhs: EntityIdentifier, rhs: EntityIdentifier) -> Bool {
|
||||
public static func == (lhs: Entity, rhs: Entity) -> Bool {
|
||||
|
||||
return lhs.category == rhs.category
|
||||
&& lhs.interfacedClassName == rhs.interfacedClassName
|
||||
return lhs.type == rhs.type
|
||||
&& lhs.entityName == rhs.entityName
|
||||
}
|
||||
|
||||
|
||||
// MARK: Hashable
|
||||
|
||||
var hashValue: Int {
|
||||
|
||||
return self.category.hashValue
|
||||
^ self.interfacedClassName.hashValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSEntityDescription
|
||||
|
||||
internal extension NSEntityDescription {
|
||||
|
||||
@nonobjc
|
||||
internal var anyEntity: DynamicModel.AnyEntity? {
|
||||
|
||||
get {
|
||||
|
||||
guard let userInfo = self.userInfo,
|
||||
let typeName = userInfo[UserInfoKey.CoreStoreManagedObjectTypeName] as! String?,
|
||||
let entityName = userInfo[UserInfoKey.CoreStoreManagedObjectEntityName] as! String? else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return DynamicModel.AnyEntity(
|
||||
type: NSClassFromString(typeName) as! CoreStoreObject.Type,
|
||||
entityName: entityName
|
||||
)
|
||||
}
|
||||
set {
|
||||
|
||||
if let newValue = newValue {
|
||||
|
||||
self.userInfo = [
|
||||
UserInfoKey.CoreStoreManagedObjectTypeName: NSStringFromClass(newValue.type),
|
||||
UserInfoKey.CoreStoreManagedObjectEntityName: newValue.entityName
|
||||
]
|
||||
}
|
||||
else {
|
||||
|
||||
self.userInfo = [:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
// MARK: - UserInfoKey
|
||||
|
||||
fileprivate enum UserInfoKey {
|
||||
|
||||
fileprivate static let CoreStoreManagedObjectTypeName = "CoreStoreManagedObjectTypeName"
|
||||
fileprivate static let CoreStoreManagedObjectEntityName = "CoreStoreManagedObjectEntityName"
|
||||
public var hashValue: Int {
|
||||
|
||||
return ObjectIdentifier(self.type).hashValue
|
||||
}
|
||||
}
|
||||
|
||||
227
Sources/Setup/Dynamic Models/SchemaHistory.swift
Normal file
227
Sources/Setup/Dynamic Models/SchemaHistory.swift
Normal file
@@ -0,0 +1,227 @@
|
||||
//
|
||||
// SchemaHistory.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: - SchemaHistory
|
||||
|
||||
public final class SchemaHistory: ExpressibleByArrayLiteral {
|
||||
|
||||
public let currentModelVersion: ModelVersion
|
||||
public let migrationChain: MigrationChain
|
||||
|
||||
public convenience init(modelName: XcodeDataModelFileName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) {
|
||||
|
||||
guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else {
|
||||
|
||||
// For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model.
|
||||
let foundModels = bundle
|
||||
.paths(forResourcesOfType: "momd", inDirectory: nil)
|
||||
.map({ ($0 as NSString).lastPathComponent })
|
||||
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle \"\(bundle.bundleIdentifier ?? "<nil>")\". Other model files in bundle: \(foundModels.coreStoreDumpString)")
|
||||
}
|
||||
|
||||
let modelFileURL = URL(fileURLWithPath: modelFilePath)
|
||||
let versionInfoPlistURL = modelFileURL.appendingPathComponent("VersionInfo.plist", isDirectory: false)
|
||||
|
||||
guard let versionInfo = NSDictionary(contentsOf: versionInfoPlistURL),
|
||||
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
|
||||
|
||||
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel.self)) metadata from path \"\(versionInfoPlistURL)\".")
|
||||
}
|
||||
|
||||
let modelVersions = Set(versionHashes.keys)
|
||||
let modelVersionHints = migrationChain.leafVersions
|
||||
let currentModelVersion: String
|
||||
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String,
|
||||
modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
|
||||
|
||||
currentModelVersion = plistModelVersion
|
||||
}
|
||||
else if let resolvedVersion = modelVersions.intersection(modelVersionHints).first {
|
||||
|
||||
CoreStore.log(
|
||||
.warning,
|
||||
message: "The \(cs_typeName(MigrationChain.self)) leaf versions do not include the model file's current version. Resolving to version \"\(resolvedVersion)\"."
|
||||
)
|
||||
currentModelVersion = resolvedVersion
|
||||
}
|
||||
else if let resolvedVersion = modelVersions.first ?? modelVersionHints.first {
|
||||
|
||||
if !modelVersionHints.isEmpty {
|
||||
|
||||
CoreStore.log(
|
||||
.warning,
|
||||
message: "The \(cs_typeName(MigrationChain.self)) leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"."
|
||||
)
|
||||
}
|
||||
currentModelVersion = resolvedVersion
|
||||
}
|
||||
else {
|
||||
|
||||
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
|
||||
}
|
||||
var allSchema: [DynamicSchema] = []
|
||||
for modelVersion in modelVersions {
|
||||
|
||||
let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
|
||||
allSchema.append(XcodeDataModel(modelVersion: modelVersion, modelVersionFileURL: fileURL))
|
||||
}
|
||||
self.init(
|
||||
allSchema: allSchema,
|
||||
migrationChain: migrationChain,
|
||||
exactCurrentModelVersion: currentModelVersion
|
||||
)
|
||||
}
|
||||
|
||||
public convenience init(_ schema: DynamicSchema, _ otherSchema: DynamicSchema..., migrationChain: MigrationChain = nil, exactCurrentModelVersion: String? = nil) {
|
||||
|
||||
self.init(
|
||||
allSchema: [schema] + otherSchema,
|
||||
migrationChain: migrationChain,
|
||||
exactCurrentModelVersion: exactCurrentModelVersion
|
||||
)
|
||||
}
|
||||
|
||||
public required init(allSchema: [DynamicSchema], migrationChain: MigrationChain = nil, exactCurrentModelVersion: String? = nil) {
|
||||
|
||||
if allSchema.isEmpty {
|
||||
|
||||
CoreStore.abort("The \"allSchema\" argument of the \(cs_typeName(SchemaHistory.self)) initializer cannot be empty.")
|
||||
}
|
||||
|
||||
var schemaByVersion: [ModelVersion: DynamicSchema] = [:]
|
||||
for schema in allSchema {
|
||||
|
||||
let modelVersion = schema.modelVersion
|
||||
CoreStore.assert(
|
||||
schemaByVersion[modelVersion] == nil,
|
||||
"Multiple model schema found for model version \"\(modelVersion)\"."
|
||||
)
|
||||
schemaByVersion[modelVersion] = schema
|
||||
}
|
||||
let modelVersions = Set(schemaByVersion.keys)
|
||||
let currentModelVersion: ModelVersion
|
||||
if let exactCurrentModelVersion = exactCurrentModelVersion {
|
||||
|
||||
if !migrationChain.isEmpty && !migrationChain.contains(exactCurrentModelVersion) {
|
||||
|
||||
CoreStore.abort("An \"exactCurrentModelVersion\" argument was provided to \(cs_typeName(SchemaHistory.self)) initializer but a matching schema could not be found from the provided \(cs_typeName(MigrationChain.self)).")
|
||||
}
|
||||
if schemaByVersion[exactCurrentModelVersion] == nil {
|
||||
|
||||
CoreStore.abort("An \"exactCurrentModelVersion\" argument was provided to \(cs_typeName(SchemaHistory.self)) initializer but a matching schema could not be found from the \(cs_typeName(DynamicSchema.self)) list.")
|
||||
}
|
||||
currentModelVersion = exactCurrentModelVersion
|
||||
}
|
||||
else if migrationChain.isEmpty && schemaByVersion.count == 1 {
|
||||
|
||||
currentModelVersion = schemaByVersion.keys.first!
|
||||
}
|
||||
else {
|
||||
|
||||
let candidateVersions = modelVersions.intersection(migrationChain.leafVersions)
|
||||
switch candidateVersions.count {
|
||||
|
||||
case 0:
|
||||
CoreStore.abort("None of the \(cs_typeName(MigrationChain.self)) leaf versions provided to the \(cs_typeName(SchemaHistory.self)) initializer matches any scheme from the \(cs_typeName(DynamicSchema.self)) list.")
|
||||
|
||||
case 1:
|
||||
currentModelVersion = candidateVersions.first!
|
||||
|
||||
default:
|
||||
CoreStore.abort("Could not resolve the \(cs_typeName(SchemaHistory.self)) current model version because the \(cs_typeName(MigrationChain.self)) have ambiguous leaf versions: \(candidateVersions)")
|
||||
}
|
||||
}
|
||||
self.schemaByVersion = schemaByVersion
|
||||
self.migrationChain = migrationChain
|
||||
self.currentModelVersion = currentModelVersion
|
||||
self.rawModel = schemaByVersion[currentModelVersion]!.rawModel()
|
||||
}
|
||||
|
||||
|
||||
// MARK: ExpressibleByArrayLiteral
|
||||
|
||||
public typealias Element = DynamicSchema
|
||||
|
||||
public convenience init(arrayLiteral elements: DynamicSchema...) {
|
||||
|
||||
self.init(
|
||||
allSchema: elements,
|
||||
migrationChain: MigrationChain(elements.map({ $0.modelVersion })),
|
||||
exactCurrentModelVersion: nil
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let schemaByVersion: [ModelVersion: DynamicSchema]
|
||||
internal let rawModel: NSManagedObjectModel
|
||||
|
||||
internal private(set) lazy var entityDescriptionsByEntityIdentifier: [EntityIdentifier: NSEntityDescription] = cs_lazy { [unowned self] in
|
||||
|
||||
var mapping: [EntityIdentifier: NSEntityDescription] = [:]
|
||||
self.rawModel.entities.forEach { (entityDescription) in
|
||||
|
||||
let entityIdentifier = EntityIdentifier(entityDescription)
|
||||
mapping[entityIdentifier] = entityDescription
|
||||
}
|
||||
return mapping
|
||||
}
|
||||
|
||||
internal func rawModel(for modelVersion: ModelVersion) -> NSManagedObjectModel? {
|
||||
|
||||
if modelVersion == self.currentModelVersion {
|
||||
|
||||
return self.rawModel
|
||||
}
|
||||
return self.schemaByVersion[modelVersion]?.rawModel()
|
||||
}
|
||||
|
||||
internal func schema(for storeMetadata: [String: Any]) -> DynamicSchema? {
|
||||
|
||||
guard let modelHashes = storeMetadata[NSStoreModelVersionHashesKey] as! [String: Data]? else {
|
||||
|
||||
return nil
|
||||
}
|
||||
for (_, schema) in self.schemaByVersion {
|
||||
|
||||
let rawModel = schema.rawModel()
|
||||
if modelHashes == rawModel.entityVersionHashesByName {
|
||||
|
||||
return schema
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
internal func mergedModels() -> [NSManagedObjectModel] {
|
||||
|
||||
return self.schemaByVersion.values.map({ $0.rawModel() })
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,7 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal static let defaultRootDirectory: URL = {
|
||||
internal static let defaultRootDirectory: URL = cs_lazy {
|
||||
|
||||
#if os(tvOS)
|
||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
|
||||
@@ -244,7 +244,7 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
|
||||
return FileManager.default.urls(
|
||||
for: systemDirectorySearchPath,
|
||||
in: .userDomainMask).first!
|
||||
}()
|
||||
}
|
||||
|
||||
internal static let defaultFileURL = LegacySQLiteStore.defaultRootDirectory
|
||||
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
|
||||
|
||||
@@ -230,7 +230,7 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal static let defaultRootDirectory: URL = {
|
||||
internal static let defaultRootDirectory: URL = cs_lazy {
|
||||
|
||||
#if os(tvOS)
|
||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
|
||||
@@ -246,7 +246,7 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
|
||||
Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
|
||||
isDirectory: true
|
||||
)
|
||||
}()
|
||||
}
|
||||
|
||||
internal static let defaultFileURL = SQLiteStore.defaultRootDirectory
|
||||
.appendingPathComponent(
|
||||
|
||||
Reference in New Issue
Block a user