mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-23 18:01:23 +01:00
Value.Required now requires an "initial:" parameter. For previous CoreStoreObject users, use the appropriate empty value for your existing properties (0 for numeric types, false for Bool, "" for String)
This commit is contained in:
committed by
John Estropia
parent
a366bcf1a3
commit
28b43f33fa
@@ -449,6 +449,18 @@
|
|||||||
B580857A1CDF808C004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
B580857A1CDF808C004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
||||||
B580857B1CDF808D004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
B580857B1CDF808D004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
||||||
B580857C1CDF808F004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
B580857C1CDF808F004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
||||||
|
B5831B701F34AC3400A9F647 /* AttributeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */; };
|
||||||
|
B5831B711F34AC3400A9F647 /* AttributeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */; };
|
||||||
|
B5831B721F34AC3400A9F647 /* AttributeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */; };
|
||||||
|
B5831B731F34AC3400A9F647 /* AttributeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */; };
|
||||||
|
B5831B751F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */; };
|
||||||
|
B5831B761F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */; };
|
||||||
|
B5831B771F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */; };
|
||||||
|
B5831B781F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */; };
|
||||||
|
B5831B7A1F34ACBA00A9F647 /* Transformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B791F34ACBA00A9F647 /* Transformable.swift */; };
|
||||||
|
B5831B7B1F34ACBA00A9F647 /* Transformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B791F34ACBA00A9F647 /* Transformable.swift */; };
|
||||||
|
B5831B7C1F34ACBA00A9F647 /* Transformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B791F34ACBA00A9F647 /* Transformable.swift */; };
|
||||||
|
B5831B7D1F34ACBA00A9F647 /* Transformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5831B791F34ACBA00A9F647 /* Transformable.swift */; };
|
||||||
B58B22F51C93C1BA00521925 /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F03A53019C5C6DA005002A5 /* CoreStore.framework */; };
|
B58B22F51C93C1BA00521925 /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F03A53019C5C6DA005002A5 /* CoreStore.framework */; };
|
||||||
B58D0C631EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58D0C621EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift */; };
|
B58D0C631EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58D0C621EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift */; };
|
||||||
B58D0C641EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58D0C621EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift */; };
|
B58D0C641EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58D0C621EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift */; };
|
||||||
@@ -816,6 +828,9 @@
|
|||||||
B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestDataTestCase.swift; sourceTree = "<group>"; };
|
B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestDataTestCase.swift; sourceTree = "<group>"; };
|
||||||
B57D27C11D0BC20100539C58 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = "<group>"; };
|
B57D27C11D0BC20100539C58 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = "<group>"; };
|
||||||
B58085741CDF7F00004C2EEB /* SetupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupTests.swift; sourceTree = "<group>"; };
|
B58085741CDF7F00004C2EEB /* SetupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupTests.swift; sourceTree = "<group>"; };
|
||||||
|
B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributeProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelationshipProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
B5831B791F34ACBA00A9F647 /* Transformable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transformable.swift; sourceTree = "<group>"; };
|
||||||
B58D0C621EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+DynamicModel.swift"; sourceTree = "<group>"; };
|
B58D0C621EAA0C7E003EDD87 /* NSManagedObject+DynamicModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+DynamicModel.swift"; sourceTree = "<group>"; };
|
||||||
B596BBAD1DD59FDB001DCDD9 /* ConvenienceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvenienceTests.swift; sourceTree = "<group>"; };
|
B596BBAD1DD59FDB001DCDD9 /* ConvenienceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvenienceTests.swift; sourceTree = "<group>"; };
|
||||||
B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchableSource.swift; sourceTree = "<group>"; };
|
B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchableSource.swift; sourceTree = "<group>"; };
|
||||||
@@ -1235,17 +1250,26 @@
|
|||||||
children = (
|
children = (
|
||||||
B5D339D71E9489AB00C880DE /* CoreStoreObject.swift */,
|
B5D339D71E9489AB00C880DE /* CoreStoreObject.swift */,
|
||||||
B53CA9A11EF1EF1600E0F440 /* PartialObject.swift */,
|
B53CA9A11EF1EF1600E0F440 /* PartialObject.swift */,
|
||||||
|
B5831B6E1F3355C300A9F647 /* Properties */,
|
||||||
B52F74391E9B8724005F3DAC /* Dynamic Schema */,
|
B52F74391E9B8724005F3DAC /* Dynamic Schema */,
|
||||||
B5D339DC1E9489C700C880DE /* DynamicObject.swift */,
|
B5D339DC1E9489C700C880DE /* DynamicObject.swift */,
|
||||||
B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */,
|
B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */,
|
||||||
B5D339E61E9493A500C880DE /* Entity.swift */,
|
B5D339E61E9493A500C880DE /* Entity.swift */,
|
||||||
B5D33A001E96012400C880DE /* Relationship.swift */,
|
|
||||||
B5D339E11E948C3600C880DE /* Value.swift */,
|
|
||||||
B5A991EB1E9DC2CE0091A2E3 /* VersionLock.swift */,
|
B5A991EB1E9DC2CE0091A2E3 /* VersionLock.swift */,
|
||||||
);
|
);
|
||||||
name = "Dynamic Models";
|
name = "Dynamic Models";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B5831B6E1F3355C300A9F647 /* Properties */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B5D33A001E96012400C880DE /* Relationship.swift */,
|
||||||
|
B5D339E11E948C3600C880DE /* Value.swift */,
|
||||||
|
B5831B791F34ACBA00A9F647 /* Transformable.swift */,
|
||||||
|
);
|
||||||
|
name = Properties;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
B5A5F26B1CAFF8D0004AB9AF /* Swift */ = {
|
B5A5F26B1CAFF8D0004AB9AF /* Swift */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -1434,6 +1458,8 @@
|
|||||||
B5E84F291AFF849C0064E85B /* Internal */ = {
|
B5E84F291AFF849C0064E85B /* Internal */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */,
|
||||||
|
B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */,
|
||||||
B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */,
|
B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */,
|
||||||
B526613F1CADD585007B85D9 /* CoreStoreFetchRequest+CoreStore.swift */,
|
B526613F1CADD585007B85D9 /* CoreStoreFetchRequest+CoreStore.swift */,
|
||||||
B53B275E1EE3B92E00E9B352 /* CoreStoreManagedObject.swift */,
|
B53B275E1EE3B92E00E9B352 /* CoreStoreManagedObject.swift */,
|
||||||
@@ -1814,6 +1840,7 @@
|
|||||||
B5ECDC1D1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
B5ECDC1D1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
||||||
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
||||||
B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||||
|
B5831B751F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
B5E1B5A81CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
B5E1B5A81CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||||
B5D339F11E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F11E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
B56007161B4018AB00A9A8F9 /* MigrationChain.swift in Sources */,
|
B56007161B4018AB00A9A8F9 /* MigrationChain.swift in Sources */,
|
||||||
@@ -1906,6 +1933,7 @@
|
|||||||
B59FA0AE1CCBAC95007C9BCA /* ICloudStore.swift in Sources */,
|
B59FA0AE1CCBAC95007C9BCA /* ICloudStore.swift in Sources */,
|
||||||
B5E84EF81AFF846E0064E85B /* CoreStore+Transaction.swift in Sources */,
|
B5E84EF81AFF846E0064E85B /* CoreStore+Transaction.swift in Sources */,
|
||||||
B5E84F301AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
B5E84F301AFF849C0064E85B /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
||||||
|
B5831B7A1F34ACBA00A9F647 /* Transformable.swift in Sources */,
|
||||||
B546F9691C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
B546F9691C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
||||||
B53FBA1E1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */,
|
B53FBA1E1CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */,
|
||||||
B549F65E1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
B549F65E1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
||||||
@@ -1921,6 +1949,7 @@
|
|||||||
B5E84EE61AFF84610064E85B /* DefaultLogger.swift in Sources */,
|
B5E84EE61AFF84610064E85B /* DefaultLogger.swift in Sources */,
|
||||||
B53FBA041CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
B53FBA041CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
||||||
B5E84EF41AFF846E0064E85B /* AsynchronousDataTransaction.swift in Sources */,
|
B5E84EF41AFF846E0064E85B /* AsynchronousDataTransaction.swift in Sources */,
|
||||||
|
B5831B701F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
||||||
B5DBE2CD1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
B5DBE2CD1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
||||||
B546F95D1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
B546F95D1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
||||||
B5D339E71E9493A500C880DE /* Entity.swift in Sources */,
|
B5D339E71E9493A500C880DE /* Entity.swift in Sources */,
|
||||||
@@ -2000,6 +2029,7 @@
|
|||||||
B5ECDC1F1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
B5ECDC1F1CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
|
||||||
B5C976E41C6C9F9A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
B5C976E41C6C9F9A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
||||||
B53FBA141CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
B53FBA141CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||||
|
B5831B761F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||||
B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
B5D3F6461C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
|
B5D3F6461C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
|
||||||
@@ -2092,6 +2122,7 @@
|
|||||||
82BA18D31C4BBD7100A0916E /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
82BA18D31C4BBD7100A0916E /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
||||||
82BA18AD1C4BBD3100A0916E /* UnsafeDataTransaction.swift in Sources */,
|
82BA18AD1C4BBD3100A0916E /* UnsafeDataTransaction.swift in Sources */,
|
||||||
B546F96A1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
B546F96A1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
||||||
|
B5831B7B1F34ACBA00A9F647 /* Transformable.swift in Sources */,
|
||||||
B53FBA201CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */,
|
B53FBA201CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */,
|
||||||
82BA18A81C4BBD2900A0916E /* CoreStoreLogger.swift in Sources */,
|
82BA18A81C4BBD2900A0916E /* CoreStoreLogger.swift in Sources */,
|
||||||
B549F65F1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
B549F65F1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
||||||
@@ -2107,6 +2138,7 @@
|
|||||||
B53FBA061CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
B53FBA061CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
||||||
82BA18BE1C4BBD4A00A0916E /* Tweak.swift in Sources */,
|
82BA18BE1C4BBD4A00A0916E /* Tweak.swift in Sources */,
|
||||||
B5DBE2CE1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
B5DBE2CE1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
||||||
|
B5831B711F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
||||||
B546F95E1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
B546F95E1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
||||||
B5ECDC0D1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
B5ECDC0D1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
||||||
B5D339E81E9493A500C880DE /* Entity.swift in Sources */,
|
B5D339E81E9493A500C880DE /* Entity.swift in Sources */,
|
||||||
@@ -2186,6 +2218,7 @@
|
|||||||
B5D3F6481C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
|
B5D3F6481C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
|
||||||
B5220E1C1D130801009BC71E /* FetchedResultsControllerDelegate.swift in Sources */,
|
B5220E1C1D130801009BC71E /* FetchedResultsControllerDelegate.swift in Sources */,
|
||||||
B52DD19E1BE1F92C00949AFE /* AsynchronousDataTransaction.swift in Sources */,
|
B52DD19E1BE1F92C00949AFE /* AsynchronousDataTransaction.swift in Sources */,
|
||||||
|
B5831B781F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
|
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
|
||||||
B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
B5220E241D13085E009BC71E /* NSFetchedResultsController+Convenience.swift in Sources */,
|
B5220E241D13085E009BC71E /* NSFetchedResultsController+Convenience.swift in Sources */,
|
||||||
@@ -2278,6 +2311,7 @@
|
|||||||
B52DD1A01BE1F92C00949AFE /* UnsafeDataTransaction.swift in Sources */,
|
B52DD1A01BE1F92C00949AFE /* UnsafeDataTransaction.swift in Sources */,
|
||||||
B5ECDC331CA81CDC00C7F112 /* CSCoreStore+Transaction.swift in Sources */,
|
B5ECDC331CA81CDC00C7F112 /* CSCoreStore+Transaction.swift in Sources */,
|
||||||
B52DD1BB1BE1F94000949AFE /* MigrationType.swift in Sources */,
|
B52DD1BB1BE1F94000949AFE /* MigrationType.swift in Sources */,
|
||||||
|
B5831B7D1F34ACBA00A9F647 /* Transformable.swift in Sources */,
|
||||||
B52DD1C91BE1F94600949AFE /* NSManagedObjectContext+Transaction.swift in Sources */,
|
B52DD1C91BE1F94600949AFE /* NSManagedObjectContext+Transaction.swift in Sources */,
|
||||||
B5220E151D130663009BC71E /* CoreStore+Observing.swift in Sources */,
|
B5220E151D130663009BC71E /* CoreStore+Observing.swift in Sources */,
|
||||||
B549F6611E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
B549F6611E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
||||||
@@ -2293,6 +2327,7 @@
|
|||||||
B52DD1B91BE1F94000949AFE /* CoreStore+Migration.swift in Sources */,
|
B52DD1B91BE1F94000949AFE /* CoreStore+Migration.swift in Sources */,
|
||||||
B5519A5C1CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */,
|
B5519A5C1CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */,
|
||||||
B5DBE2D51C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
B5DBE2D51C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
||||||
|
B5831B731F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
||||||
B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
||||||
B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||||
B5D339EA1E9493A500C880DE /* Entity.swift in Sources */,
|
B5D339EA1E9493A500C880DE /* Entity.swift in Sources */,
|
||||||
@@ -2372,6 +2407,7 @@
|
|||||||
B5C976E51C6C9F9B00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
B5C976E51C6C9F9B00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
||||||
B53FBA151CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
B53FBA151CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||||
B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||||
|
B5831B771F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
B5D3F6471C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
|
B5D3F6471C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
|
||||||
B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
||||||
@@ -2464,6 +2500,7 @@
|
|||||||
B56321B11BD6521C006C9394 /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
B56321B11BD6521C006C9394 /* NSManagedObjectContext+CoreStore.swift in Sources */,
|
||||||
B563218D1BD65216006C9394 /* CoreStore+Transaction.swift in Sources */,
|
B563218D1BD65216006C9394 /* CoreStore+Transaction.swift in Sources */,
|
||||||
B546F96B1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
B546F96B1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
||||||
|
B5831B7C1F34ACBA00A9F647 /* Transformable.swift in Sources */,
|
||||||
B53FBA211CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */,
|
B53FBA211CAB63FA00F0D40A /* NSFetchedResultsController+ObjectiveC.swift in Sources */,
|
||||||
B563218B1BD65216006C9394 /* UnsafeDataTransaction.swift in Sources */,
|
B563218B1BD65216006C9394 /* UnsafeDataTransaction.swift in Sources */,
|
||||||
B549F6601E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
B549F6601E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
|
||||||
@@ -2479,6 +2516,7 @@
|
|||||||
B53FBA071CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
B53FBA071CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
||||||
B56321841BD65216006C9394 /* DefaultLogger.swift in Sources */,
|
B56321841BD65216006C9394 /* DefaultLogger.swift in Sources */,
|
||||||
B5DBE2CF1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
B5DBE2CF1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
||||||
|
B5831B721F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
||||||
B546F95F1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
B546F95F1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
||||||
B5ECDC0E1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
B5ECDC0E1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
|
||||||
B5D339E91E9493A500C880DE /* Entity.swift in Sources */,
|
B5D339E91E9493A500C880DE /* Entity.swift in Sources */,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import CoreStore
|
|||||||
|
|
||||||
class Animal: CoreStoreObject {
|
class Animal: CoreStoreObject {
|
||||||
|
|
||||||
let species = Value.Required<String>("species", default: "Swift")
|
let species = Value.Required<String>("species", initial: "Swift")
|
||||||
let master = Relationship.ToOne<Person>("master")
|
let master = Relationship.ToOne<Person>("master")
|
||||||
let color = Transformable.Optional<Color>("color")
|
let color = Transformable.Optional<Color>("color")
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ class Animal: CoreStoreObject {
|
|||||||
class Dog: Animal {
|
class Dog: Animal {
|
||||||
|
|
||||||
let nickname = Value.Optional<String>("nickname")
|
let nickname = Value.Optional<String>("nickname")
|
||||||
let age = Value.Required<Int>("age", default: 1)
|
let age = Value.Required<Int>("age", initial: 1)
|
||||||
let friends = Relationship.ToManyOrdered<Dog>("friends")
|
let friends = Relationship.ToManyOrdered<Dog>("friends")
|
||||||
let friendedBy = Relationship.ToManyUnordered<Dog>("friendedBy", inverse: { $0.friends })
|
let friendedBy = Relationship.ToManyUnordered<Dog>("friendedBy", inverse: { $0.friends })
|
||||||
}
|
}
|
||||||
@@ -54,12 +54,13 @@ class Person: CoreStoreObject {
|
|||||||
|
|
||||||
let title = Value.Required<String>(
|
let title = Value.Required<String>(
|
||||||
"title",
|
"title",
|
||||||
default: "Mr.",
|
initial: "Mr.",
|
||||||
customSetter: Person.setTitle
|
customSetter: Person.setTitle
|
||||||
)
|
)
|
||||||
|
|
||||||
let name = Value.Required<String>(
|
let name = Value.Required<String>(
|
||||||
"name",
|
"name",
|
||||||
|
initial: "",
|
||||||
customSetter: Person.setName
|
customSetter: Person.setName
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
47
Sources/AttributeProtocol.swift
Normal file
47
Sources/AttributeProtocol.swift
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// AttributeProtocol.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2017 John Rommel Estropia
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CoreData
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - AttributeProtocol
|
||||||
|
|
||||||
|
internal protocol AttributeProtocol: class {
|
||||||
|
|
||||||
|
static var attributeType: NSAttributeType { get }
|
||||||
|
|
||||||
|
var keyPath: KeyPath { get }
|
||||||
|
var isOptional: Bool { get }
|
||||||
|
var isIndexed: Bool { get }
|
||||||
|
var isTransient: Bool { get }
|
||||||
|
var versionHashModifier: () -> String? { get }
|
||||||
|
var renamingIdentifier: () -> String? { get }
|
||||||
|
var defaultValue: () -> Any? { get }
|
||||||
|
var affectedByKeyPaths: () -> Set<String> { get }
|
||||||
|
weak var parentObject: CoreStoreObject? { get set }
|
||||||
|
var getter: CoreStoreManagedObject.CustomGetter? { get }
|
||||||
|
var setter: CoreStoreManagedObject.CustomSetter? { get }
|
||||||
|
}
|
||||||
@@ -295,8 +295,8 @@ public final class CoreStoreSchema: DynamicSchema {
|
|||||||
description.isIndexed = attribute.isIndexed
|
description.isIndexed = attribute.isIndexed
|
||||||
description.defaultValue = attribute.defaultValue()
|
description.defaultValue = attribute.defaultValue()
|
||||||
description.isTransient = attribute.isTransient
|
description.isTransient = attribute.isTransient
|
||||||
description.versionHashModifier = attribute.versionHashModifier
|
description.versionHashModifier = attribute.versionHashModifier()
|
||||||
description.renamingIdentifier = attribute.renamingIdentifier
|
description.renamingIdentifier = attribute.renamingIdentifier()
|
||||||
propertyDescriptions.append(description)
|
propertyDescriptions.append(description)
|
||||||
keyPathsByAffectedKeyPaths[attribute.keyPath] = attribute.affectedByKeyPaths()
|
keyPathsByAffectedKeyPaths[attribute.keyPath] = attribute.affectedByKeyPaths()
|
||||||
customGetterSetterByKeyPaths[attribute.keyPath] = (attribute.getter, attribute.setter)
|
customGetterSetterByKeyPaths[attribute.keyPath] = (attribute.getter, attribute.setter)
|
||||||
@@ -308,8 +308,8 @@ public final class CoreStoreSchema: DynamicSchema {
|
|||||||
description.maxCount = relationship.maxCount
|
description.maxCount = relationship.maxCount
|
||||||
description.isOrdered = relationship.isOrdered
|
description.isOrdered = relationship.isOrdered
|
||||||
description.deleteRule = relationship.deleteRule
|
description.deleteRule = relationship.deleteRule
|
||||||
description.versionHashModifier = relationship.versionHashModifier
|
description.versionHashModifier = relationship.versionHashModifier()
|
||||||
description.renamingIdentifier = relationship.renamingIdentifier
|
description.renamingIdentifier = relationship.renamingIdentifier()
|
||||||
propertyDescriptions.append(description)
|
propertyDescriptions.append(description)
|
||||||
keyPathsByAffectedKeyPaths[relationship.keyPath] = relationship.affectedByKeyPaths()
|
keyPathsByAffectedKeyPaths[relationship.keyPath] = relationship.affectedByKeyPaths()
|
||||||
|
|
||||||
|
|||||||
@@ -96,71 +96,62 @@ public extension DynamicSchema {
|
|||||||
|
|
||||||
case .integer16AttributeType:
|
case .integer16AttributeType:
|
||||||
valueType = Int16.self
|
valueType = Int16.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Int16.ImportableNativeType?).flatMap(Int16.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! Int16.ImportableNativeType?).flatMap(Int16.cs_fromImportableNativeType) {
|
||||||
defaultValue != Int16.cs_emptyValue() {
|
|
||||||
|
|
||||||
defaultString = ", default: \(defaultValue)"
|
defaultString = ", initial: \(defaultValue)"
|
||||||
}
|
}
|
||||||
case .integer32AttributeType:
|
case .integer32AttributeType:
|
||||||
valueType = Int32.self
|
valueType = Int32.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Int32.ImportableNativeType?).flatMap(Int32.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! Int32.ImportableNativeType?).flatMap(Int32.cs_fromImportableNativeType) {
|
||||||
defaultValue != Int32.cs_emptyValue() {
|
|
||||||
|
|
||||||
defaultString = ", default: \(defaultValue)"
|
defaultString = ", initial: \(defaultValue)"
|
||||||
}
|
}
|
||||||
case .integer64AttributeType:
|
case .integer64AttributeType:
|
||||||
valueType = Int64.self
|
valueType = Int64.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Int64.ImportableNativeType?).flatMap(Int64.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! Int64.ImportableNativeType?).flatMap(Int64.cs_fromImportableNativeType) {
|
||||||
defaultValue != Int64.cs_emptyValue() {
|
|
||||||
|
|
||||||
defaultString = ", default: \(defaultValue)"
|
defaultString = ", initial: \(defaultValue)"
|
||||||
}
|
}
|
||||||
case .decimalAttributeType:
|
case .decimalAttributeType:
|
||||||
valueType = NSDecimalNumber.self
|
valueType = NSDecimalNumber.self
|
||||||
if let defaultValue = (attribute.defaultValue as! NSDecimalNumber.ImportableNativeType?).flatMap(NSDecimalNumber.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! NSDecimalNumber.ImportableNativeType?).flatMap(NSDecimalNumber.cs_fromImportableNativeType) {
|
||||||
defaultValue != NSDecimalNumber.cs_emptyValue() {
|
|
||||||
|
|
||||||
defaultString = ", default: NSDecimalNumber(string: \"\(defaultValue.description(withLocale: nil))\")"
|
defaultString = ", initial: NSDecimalNumber(string: \"\(defaultValue.description(withLocale: nil))\")"
|
||||||
}
|
}
|
||||||
case .doubleAttributeType:
|
case .doubleAttributeType:
|
||||||
valueType = Double.self
|
valueType = Double.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Double.ImportableNativeType?).flatMap(Double.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! Double.ImportableNativeType?).flatMap(Double.cs_fromImportableNativeType) {
|
||||||
defaultValue != Double.cs_emptyValue() {
|
|
||||||
|
|
||||||
defaultString = ", default: \(defaultValue)"
|
defaultString = ", initial: \(defaultValue)"
|
||||||
}
|
}
|
||||||
case .floatAttributeType:
|
case .floatAttributeType:
|
||||||
valueType = Float.self
|
valueType = Float.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Float.ImportableNativeType?).flatMap(Float.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! Float.ImportableNativeType?).flatMap(Float.cs_fromImportableNativeType) {
|
||||||
defaultValue != Float.cs_emptyValue() {
|
|
||||||
|
|
||||||
defaultString = ", default: \(defaultValue)"
|
defaultString = ", initial: \(defaultValue)"
|
||||||
}
|
}
|
||||||
case .stringAttributeType:
|
case .stringAttributeType:
|
||||||
valueType = String.self
|
valueType = String.self
|
||||||
if let defaultValue = (attribute.defaultValue as! String.ImportableNativeType?).flatMap(String.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! String.ImportableNativeType?).flatMap(String.cs_fromImportableNativeType) {
|
||||||
defaultValue != String.cs_emptyValue() {
|
|
||||||
|
|
||||||
// TODO: escape strings
|
// TODO: escape strings
|
||||||
defaultString = ", default: \"\(defaultValue)\""
|
defaultString = ", initial: \"\(defaultValue)\""
|
||||||
}
|
}
|
||||||
case .booleanAttributeType:
|
case .booleanAttributeType:
|
||||||
valueType = Bool.self
|
valueType = Bool.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Bool.ImportableNativeType?).flatMap(Bool.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! Bool.ImportableNativeType?).flatMap(Bool.cs_fromImportableNativeType) {
|
||||||
defaultValue != Bool.cs_emptyValue() {
|
|
||||||
|
|
||||||
defaultString = ", default: \(defaultValue ? "true" : "false")"
|
defaultString = ", initial: \(defaultValue ? "true" : "false")"
|
||||||
}
|
}
|
||||||
case .dateAttributeType:
|
case .dateAttributeType:
|
||||||
valueType = Date.self
|
valueType = Date.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Date.ImportableNativeType?).flatMap(Date.cs_fromImportableNativeType) {
|
if let defaultValue = (attribute.defaultValue as! Date.ImportableNativeType?).flatMap(Date.cs_fromImportableNativeType) {
|
||||||
|
|
||||||
defaultString = ", default: Date(timeIntervalSinceReferenceDate: \(defaultValue.timeIntervalSinceReferenceDate))"
|
defaultString = ", initial: Date(timeIntervalSinceReferenceDate: \(defaultValue.timeIntervalSinceReferenceDate))"
|
||||||
}
|
}
|
||||||
case .binaryDataAttributeType:
|
case .binaryDataAttributeType:
|
||||||
valueType = Data.self
|
valueType = Data.self
|
||||||
if let defaultValue = (attribute.defaultValue as! Data.ImportableNativeType?).flatMap(Data.cs_fromImportableNativeType),
|
if let defaultValue = (attribute.defaultValue as! Data.ImportableNativeType?).flatMap(Data.cs_fromImportableNativeType) {
|
||||||
defaultValue != Data.cs_emptyValue() {
|
|
||||||
|
|
||||||
let count = defaultValue.count
|
let count = defaultValue.count
|
||||||
let bytes = defaultValue.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) in
|
let bytes = defaultValue.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) in
|
||||||
@@ -168,7 +159,7 @@ public extension DynamicSchema {
|
|||||||
return (0 ..< (count / MemoryLayout<UInt8>.size))
|
return (0 ..< (count / MemoryLayout<UInt8>.size))
|
||||||
.map({ "\("0x\(String(pointer[$0], radix: 16, uppercase: false))")" })
|
.map({ "\("0x\(String(pointer[$0], radix: 16, uppercase: false))")" })
|
||||||
}
|
}
|
||||||
defaultString = ", default: Data(bytes: [\(bytes.joined(separator: ", "))])"
|
defaultString = ", initial: Data(bytes: [\(bytes.joined(separator: ", "))])"
|
||||||
}
|
}
|
||||||
case .transformableAttributeType:
|
case .transformableAttributeType:
|
||||||
if let attributeValueClassName = attribute.attributeValueClassName {
|
if let attributeValueClassName = attribute.attributeValueClassName {
|
||||||
@@ -181,11 +172,11 @@ public extension DynamicSchema {
|
|||||||
}
|
}
|
||||||
if let defaultValue = attribute.defaultValue {
|
if let defaultValue = attribute.defaultValue {
|
||||||
|
|
||||||
defaultString = ", default: /* \"\(defaultValue)\" */"
|
defaultString = ", initial: /* \"\(defaultValue)\" */"
|
||||||
}
|
}
|
||||||
else if !attribute.isOptional {
|
else if !attribute.isOptional {
|
||||||
|
|
||||||
defaultString = ", default: /* required */"
|
defaultString = ", initial: /* required */"
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fatalError("Unsupported attribute type: \(attribute.attributeType.rawValue)")
|
fatalError("Unsupported attribute type: \(attribute.attributeType.rawValue)")
|
||||||
|
|||||||
@@ -78,26 +78,9 @@ public protocol ImportableAttributeType: QueryableAttributeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - EmptyableAttributeType
|
|
||||||
|
|
||||||
/**
|
|
||||||
`ImportableAttributeType`s that have a natural "empty" value. Example: `0` for `Int`, `""` for `String`.
|
|
||||||
|
|
||||||
- Discussion: Not all `ImportableAttributeType`s can have empty values. `URL`s and `Date`s for example have no obvious empty values.
|
|
||||||
*/
|
|
||||||
public protocol EmptyableAttributeType: ImportableAttributeType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the default "empty" value for this type.
|
|
||||||
*/
|
|
||||||
@inline(__always)
|
|
||||||
static func cs_emptyValue() -> Self
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Bool
|
// MARK: - Bool
|
||||||
|
|
||||||
extension Bool: ImportableAttributeType, EmptyableAttributeType {
|
extension Bool: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -114,21 +97,11 @@ extension Bool: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Bool {
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - CGFloat
|
// MARK: - CGFloat
|
||||||
|
|
||||||
extension CGFloat: ImportableAttributeType, EmptyableAttributeType {
|
extension CGFloat: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -145,21 +118,12 @@ extension CGFloat: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> CGFloat {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Data
|
// MARK: - Data
|
||||||
|
|
||||||
extension Data: ImportableAttributeType, EmptyableAttributeType {
|
extension Data: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -176,15 +140,6 @@ extension Data: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Data {
|
|
||||||
|
|
||||||
return Data()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -212,7 +167,7 @@ extension Date: ImportableAttributeType {
|
|||||||
|
|
||||||
// MARK: - Double
|
// MARK: - Double
|
||||||
|
|
||||||
extension Double: ImportableAttributeType, EmptyableAttributeType {
|
extension Double: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -229,21 +184,12 @@ extension Double: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Double {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Float
|
// MARK: - Float
|
||||||
|
|
||||||
extension Float: ImportableAttributeType, EmptyableAttributeType {
|
extension Float: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -260,21 +206,12 @@ extension Float: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Float {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Int
|
// MARK: - Int
|
||||||
|
|
||||||
extension Int: ImportableAttributeType, EmptyableAttributeType {
|
extension Int: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -291,21 +228,12 @@ extension Int: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Int {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Int8
|
// MARK: - Int8
|
||||||
|
|
||||||
extension Int8: ImportableAttributeType, EmptyableAttributeType {
|
extension Int8: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -322,21 +250,12 @@ extension Int8: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Int8 {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Int16
|
// MARK: - Int16
|
||||||
|
|
||||||
extension Int16: ImportableAttributeType, EmptyableAttributeType {
|
extension Int16: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -353,21 +272,12 @@ extension Int16: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Int16 {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Int32
|
// MARK: - Int32
|
||||||
|
|
||||||
extension Int32: ImportableAttributeType, EmptyableAttributeType {
|
extension Int32: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -384,21 +294,12 @@ extension Int32: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Int32 {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Int64
|
// MARK: - Int64
|
||||||
|
|
||||||
extension Int64: ImportableAttributeType, EmptyableAttributeType {
|
extension Int64: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -415,21 +316,12 @@ extension Int64: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> Int64 {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - NSData
|
// MARK: - NSData
|
||||||
|
|
||||||
extension NSData: ImportableAttributeType, EmptyableAttributeType {
|
extension NSData: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -446,15 +338,6 @@ extension NSData: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@nonobjc @inline(__always)
|
|
||||||
public class func cs_emptyValue() -> Self {
|
|
||||||
|
|
||||||
return self.init()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -482,7 +365,7 @@ extension NSDate: ImportableAttributeType {
|
|||||||
|
|
||||||
// MARK: - NSNumber
|
// MARK: - NSNumber
|
||||||
|
|
||||||
extension NSNumber: ImportableAttributeType, EmptyableAttributeType {
|
extension NSNumber: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -499,21 +382,12 @@ extension NSNumber: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@nonobjc @inline(__always)
|
|
||||||
public class func cs_emptyValue() -> Self {
|
|
||||||
|
|
||||||
return self.init()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - NSString
|
// MARK: - NSString
|
||||||
|
|
||||||
extension NSString: ImportableAttributeType, EmptyableAttributeType {
|
extension NSString: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -530,15 +404,6 @@ extension NSString: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@nonobjc @inline(__always)
|
|
||||||
public class func cs_emptyValue() -> Self {
|
|
||||||
|
|
||||||
return self.init()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -588,7 +453,7 @@ extension NSUUID: ImportableAttributeType {
|
|||||||
|
|
||||||
// MARK: - String
|
// MARK: - String
|
||||||
|
|
||||||
extension String: ImportableAttributeType, EmptyableAttributeType {
|
extension String: ImportableAttributeType {
|
||||||
|
|
||||||
// MARK: ImportableAttributeType
|
// MARK: ImportableAttributeType
|
||||||
|
|
||||||
@@ -605,15 +470,6 @@ extension String: ImportableAttributeType, EmptyableAttributeType {
|
|||||||
|
|
||||||
return self.cs_toQueryableNativeType()
|
return self.cs_toQueryableNativeType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: EmptyableAttributeType
|
|
||||||
|
|
||||||
@inline(__always)
|
|
||||||
public static func cs_emptyValue() -> String {
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>4.0.5</string>
|
<string>4.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
public convenience init(
|
public convenience init(
|
||||||
_ keyPath: KeyPath,
|
_ keyPath: KeyPath,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -132,8 +132,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
_ keyPath: KeyPath,
|
_ keyPath: KeyPath,
|
||||||
inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>,
|
inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -167,8 +167,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
_ keyPath: KeyPath,
|
_ keyPath: KeyPath,
|
||||||
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>,
|
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -202,8 +202,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
_ keyPath: KeyPath,
|
_ keyPath: KeyPath,
|
||||||
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>,
|
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -242,8 +242,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
internal let minCount: Int = 0
|
internal let minCount: Int = 0
|
||||||
internal let maxCount: Int = 1
|
internal let maxCount: Int = 1
|
||||||
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
||||||
internal let versionHashModifier: String?
|
internal let versionHashModifier: () -> String?
|
||||||
internal let renamingIdentifier: String?
|
internal let renamingIdentifier: () -> String?
|
||||||
internal let affectedByKeyPaths: () -> Set<String>
|
internal let affectedByKeyPaths: () -> Set<String>
|
||||||
internal weak var parentObject: CoreStoreObject?
|
internal weak var parentObject: CoreStoreObject?
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, versionHashModifier: String?, renamingIdentifier: String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
|
private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
|
||||||
|
|
||||||
self.keyPath = keyPath
|
self.keyPath = keyPath
|
||||||
self.deleteRule = deleteRule.nativeValue
|
self.deleteRule = deleteRule.nativeValue
|
||||||
@@ -345,8 +345,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
minCount: Int = 0,
|
minCount: Int = 0,
|
||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -386,8 +386,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>,
|
inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -427,8 +427,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>,
|
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -468,8 +468,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>,
|
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>,
|
||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -511,8 +511,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
internal let minCount: Int
|
internal let minCount: Int
|
||||||
internal let maxCount: Int
|
internal let maxCount: Int
|
||||||
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
||||||
internal let versionHashModifier: String?
|
internal let versionHashModifier: () -> String?
|
||||||
internal let renamingIdentifier: String?
|
internal let renamingIdentifier: () -> String?
|
||||||
internal let affectedByKeyPaths: () -> Set<String>
|
internal let affectedByKeyPaths: () -> Set<String>
|
||||||
internal weak var parentObject: CoreStoreObject?
|
internal weak var parentObject: CoreStoreObject?
|
||||||
|
|
||||||
@@ -563,7 +563,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private init(keyPath: String, minCount: Int, maxCount: Int, inverseKeyPath: @escaping () -> String?, deleteRule: DeleteRule, versionHashModifier: String?, renamingIdentifier: String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
|
private init(keyPath: String, minCount: Int, maxCount: Int, inverseKeyPath: @escaping () -> String?, deleteRule: DeleteRule, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
|
||||||
|
|
||||||
self.keyPath = keyPath
|
self.keyPath = keyPath
|
||||||
self.deleteRule = deleteRule.nativeValue
|
self.deleteRule = deleteRule.nativeValue
|
||||||
@@ -619,8 +619,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
minCount: Int = 0,
|
minCount: Int = 0,
|
||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -660,8 +660,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
minCount: Int = 0,
|
minCount: Int = 0,
|
||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -701,8 +701,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
minCount: Int = 0,
|
minCount: Int = 0,
|
||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -742,8 +742,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
deleteRule: DeleteRule = .nullify,
|
deleteRule: DeleteRule = .nullify,
|
||||||
minCount: Int = 0,
|
minCount: Int = 0,
|
||||||
maxCount: Int = 0,
|
maxCount: Int = 0,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.init(
|
self.init(
|
||||||
@@ -785,8 +785,8 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
internal let minCount: Int
|
internal let minCount: Int
|
||||||
internal let maxCount: Int
|
internal let maxCount: Int
|
||||||
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?)
|
||||||
internal let versionHashModifier: String?
|
internal let versionHashModifier: () -> String?
|
||||||
internal let renamingIdentifier: String?
|
internal let renamingIdentifier: () -> String?
|
||||||
internal let affectedByKeyPaths: () -> Set<String>
|
internal let affectedByKeyPaths: () -> Set<String>
|
||||||
internal weak var parentObject: CoreStoreObject?
|
internal weak var parentObject: CoreStoreObject?
|
||||||
|
|
||||||
@@ -837,7 +837,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: String?, renamingIdentifier: String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
|
private init(keyPath: KeyPath, inverseKeyPath: @escaping () -> KeyPath?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
|
||||||
|
|
||||||
self.keyPath = keyPath
|
self.keyPath = keyPath
|
||||||
self.deleteRule = deleteRule.nativeValue
|
self.deleteRule = deleteRule.nativeValue
|
||||||
@@ -1204,21 +1204,3 @@ extension RelationshipContainer.ToManyUnordered {
|
|||||||
return relationship.nativeValue.isEqual(relationship2.nativeValue)
|
return relationship.nativeValue.isEqual(relationship2.nativeValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - RelationshipProtocol
|
|
||||||
|
|
||||||
internal protocol RelationshipProtocol: class {
|
|
||||||
|
|
||||||
var keyPath: KeyPath { get }
|
|
||||||
var isToMany: Bool { get }
|
|
||||||
var isOrdered: Bool { get }
|
|
||||||
var deleteRule: NSDeleteRule { get }
|
|
||||||
var inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?) { get }
|
|
||||||
var affectedByKeyPaths: () -> Set<String> { get }
|
|
||||||
weak var parentObject: CoreStoreObject? { get set }
|
|
||||||
var versionHashModifier: String? { get }
|
|
||||||
var renamingIdentifier: String? { get }
|
|
||||||
var minCount: Int { get }
|
|
||||||
var maxCount: Int { get }
|
|
||||||
}
|
|
||||||
|
|||||||
45
Sources/RelationshipProtocol.swift
Normal file
45
Sources/RelationshipProtocol.swift
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// RelationshipProtocol.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2017 John Rommel Estropia
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import CoreData
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - RelationshipProtocol
|
||||||
|
|
||||||
|
internal protocol RelationshipProtocol: class {
|
||||||
|
|
||||||
|
var keyPath: KeyPath { get }
|
||||||
|
var isToMany: Bool { get }
|
||||||
|
var isOrdered: Bool { get }
|
||||||
|
var deleteRule: NSDeleteRule { get }
|
||||||
|
var inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPath?) { get }
|
||||||
|
var affectedByKeyPaths: () -> Set<String> { get }
|
||||||
|
weak var parentObject: CoreStoreObject? { get set }
|
||||||
|
var versionHashModifier: () -> String? { get }
|
||||||
|
var renamingIdentifier: () -> String? { get }
|
||||||
|
var minCount: Int { get }
|
||||||
|
var maxCount: Int { get }
|
||||||
|
}
|
||||||
597
Sources/Transformable.swift
Normal file
597
Sources/Transformable.swift
Normal file
@@ -0,0 +1,597 @@
|
|||||||
|
//
|
||||||
|
// Transformable.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: - DynamicObject
|
||||||
|
|
||||||
|
public extension DynamicObject where Self: CoreStoreObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for transformable properties. `Transformable` properties support types that conforms to `NSCoding & NSCopying`.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
let species = Value.Required<String>("species")
|
||||||
|
let nickname = Value.Optional<String>("nickname")
|
||||||
|
let color = Transformable.Optional<UIColor>("color")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Important: `Transformable` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
||||||
|
*/
|
||||||
|
public typealias Transformable = TransformableContainer<Self>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - TransformableContainer
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for transformable properties. Use the `DynamicObject.Transformable` typealias instead for shorter syntax.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
let species = Value.Required<String>("species")
|
||||||
|
let nickname = Value.Optional<String>("nickname")
|
||||||
|
let color = Transformable.Optional<UIColor>("color")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public enum TransformableContainer<O: CoreStoreObject> {
|
||||||
|
|
||||||
|
// MARK: - Required
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for transformable properties. Any type that conforms to `NSCoding & NSCopying` are supported.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
let species = Value.Required<String>("species")
|
||||||
|
let nickname = Value.Optional<String>("nickname")
|
||||||
|
let color = Transformable.Optional<UIColor>("color")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Important: `Transformable.Required` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
||||||
|
*/
|
||||||
|
public final class Required<V: NSCoding & NSCopying>: AttributeProtocol {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes the metadata for the property.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
let species = Value.Required<String>("species")
|
||||||
|
let color = Transformable.Required<UIColor>(
|
||||||
|
"color",
|
||||||
|
initial: UIColor.clear,
|
||||||
|
isTransient: true,
|
||||||
|
customGetter: Animal.getColor(_:)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func getColor(_ partialObject: PartialObject<Animal>) -> UIColor {
|
||||||
|
let cachedColor = partialObject.primitiveValue(for: { $0.color })
|
||||||
|
if cachedColor != UIColor.clear {
|
||||||
|
|
||||||
|
return cachedColor
|
||||||
|
}
|
||||||
|
let color: UIColor
|
||||||
|
switch partialObject.value(for: { $0.species }) {
|
||||||
|
|
||||||
|
case "Swift": color = UIColor.orange
|
||||||
|
case "Bulbasaur": color = UIColor.green
|
||||||
|
default: color = UIColor.black
|
||||||
|
}
|
||||||
|
partialObject.setPrimitiveValue(color, for: { $0.color })
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- parameter keyPath: the permanent attribute name for this property.
|
||||||
|
- parameter initial: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||||
|
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||||
|
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||||
|
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||||
|
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
||||||
|
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.primitiveValue(for:)` instead of `PartialObject<O>.value(for:)`, which would unintentionally execute the same closure again recursively.
|
||||||
|
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.setPrimitiveValue(_:for:)` instead of `PartialObject<O>.setValue(_:for:)`, which would unintentionally execute the same closure again recursively.
|
||||||
|
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||||
|
*/
|
||||||
|
public init(
|
||||||
|
_ keyPath: KeyPath,
|
||||||
|
initial: @autoclosure @escaping () -> V,
|
||||||
|
isIndexed: Bool = false,
|
||||||
|
isTransient: Bool = false,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
|
self.keyPath = keyPath
|
||||||
|
self.defaultValue = initial
|
||||||
|
self.isIndexed = isIndexed
|
||||||
|
self.isTransient = isTransient
|
||||||
|
self.versionHashModifier = versionHashModifier
|
||||||
|
self.renamingIdentifier = renamingIdentifier
|
||||||
|
self.customGetter = customGetter
|
||||||
|
self.customSetter = customSetter
|
||||||
|
self.affectedByKeyPaths = affectedByKeyPaths
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
The property value.
|
||||||
|
*/
|
||||||
|
public var value: V {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.parentObject != nil,
|
||||||
|
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
if let customGetter = self.customGetter {
|
||||||
|
|
||||||
|
return customGetter(PartialObject<O>(object.rawObject!))
|
||||||
|
}
|
||||||
|
return object.rawObject!.value(forKey: self.keyPath)! as! V
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.parentObject != nil,
|
||||||
|
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isEditableInContext() == true,
|
||||||
|
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
|
||||||
|
)
|
||||||
|
if let customSetter = self.customSetter {
|
||||||
|
|
||||||
|
return customSetter(PartialObject<O>(object.rawObject!), newValue)
|
||||||
|
}
|
||||||
|
object.rawObject!.setValue(
|
||||||
|
newValue,
|
||||||
|
forKey: self.keyPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: AttributeProtocol
|
||||||
|
|
||||||
|
internal static var attributeType: NSAttributeType {
|
||||||
|
|
||||||
|
return .transformableAttributeType
|
||||||
|
}
|
||||||
|
|
||||||
|
public let keyPath: KeyPath
|
||||||
|
|
||||||
|
internal let isOptional = false
|
||||||
|
internal let isIndexed: Bool
|
||||||
|
internal let isTransient: Bool
|
||||||
|
internal let versionHashModifier: () -> String?
|
||||||
|
internal let renamingIdentifier: () -> String?
|
||||||
|
internal let defaultValue: () -> Any?
|
||||||
|
internal let affectedByKeyPaths: () -> Set<String>
|
||||||
|
internal weak var parentObject: CoreStoreObject?
|
||||||
|
|
||||||
|
internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = cs_lazy { [unowned self] in
|
||||||
|
|
||||||
|
guard let customGetter = self.customGetter else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let keyPath = self.keyPath
|
||||||
|
return { (_ id: Any) -> Any? in
|
||||||
|
|
||||||
|
let rawObject = id as! CoreStoreManagedObject
|
||||||
|
rawObject.willAccessValue(forKey: keyPath)
|
||||||
|
defer {
|
||||||
|
|
||||||
|
rawObject.didAccessValue(forKey: keyPath)
|
||||||
|
}
|
||||||
|
let value = customGetter(PartialObject<O>(rawObject))
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal private(set) lazy var setter: CoreStoreManagedObject.CustomSetter? = cs_lazy { [unowned self] in
|
||||||
|
|
||||||
|
guard let customSetter = self.customSetter else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let keyPath = self.keyPath
|
||||||
|
return { (_ id: Any, _ newValue: Any?) -> Void in
|
||||||
|
|
||||||
|
let rawObject = id as! CoreStoreManagedObject
|
||||||
|
rawObject.willChangeValue(forKey: keyPath)
|
||||||
|
defer {
|
||||||
|
|
||||||
|
rawObject.didChangeValue(forKey: keyPath)
|
||||||
|
}
|
||||||
|
customSetter(
|
||||||
|
PartialObject<O>(rawObject),
|
||||||
|
newValue as! V
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private let customGetter: ((_ partialObject: PartialObject<O>) -> V)?
|
||||||
|
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)?
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 3.1, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||||
|
public convenience init(
|
||||||
|
_ keyPath: KeyPath,
|
||||||
|
`default`: @autoclosure @escaping () -> V,
|
||||||
|
isIndexed: Bool = false,
|
||||||
|
isTransient: Bool = false,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath,
|
||||||
|
initial: `default`,
|
||||||
|
isIndexed: isIndexed,
|
||||||
|
isTransient: isTransient,
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: renamingIdentifier,
|
||||||
|
customGetter: customGetter,
|
||||||
|
customSetter: customSetter,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Optional
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for optional transformable properties. Any type that conforms to `NSCoding & NSCopying` are supported.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
let species = Value.Required<String>("species")
|
||||||
|
let nickname = Value.Optional<String>("nickname")
|
||||||
|
let color = Transformable.Optional<UIColor>("color")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Important: `Transformable.Optional` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
||||||
|
*/
|
||||||
|
public final class Optional<V: NSCoding & NSCopying>: AttributeProtocol {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes the metadata for the property.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
let species = Value.Required<String>("species")
|
||||||
|
let color = Transformable.Optional<UIColor>(
|
||||||
|
"color",
|
||||||
|
isTransient: true,
|
||||||
|
customGetter: Animal.getColor(_:)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func getColor(_ partialObject: PartialObject<Animal>) -> UIColor? {
|
||||||
|
if let cachedColor = partialObject.primitiveValue(for: { $0.color }) {
|
||||||
|
return cachedColor
|
||||||
|
}
|
||||||
|
let color: UIColor?
|
||||||
|
switch partialObject.value(for: { $0.species }) {
|
||||||
|
|
||||||
|
case "Swift": color = UIColor.orange
|
||||||
|
case "Bulbasaur": color = UIColor.green
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
partialObject.setPrimitiveValue(color, for: { $0.color })
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- parameter keyPath: the permanent attribute name for this property.
|
||||||
|
- parameter initial: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||||
|
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||||
|
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||||
|
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||||
|
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
||||||
|
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.primitiveValue(for:)` instead of `PartialObject<O>.value(for:)`, which would unintentionally execute the same closure again recursively.
|
||||||
|
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.setPrimitiveValue(_:for:)` instead of `PartialObject<O>.setValue(_:for:)`, which would unintentionally execute the same closure again recursively.
|
||||||
|
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||||
|
*/
|
||||||
|
public init(
|
||||||
|
_ keyPath: KeyPath,
|
||||||
|
initial: @autoclosure @escaping () -> V? = nil,
|
||||||
|
isIndexed: Bool = false,
|
||||||
|
isTransient: Bool = false,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
|
self.keyPath = keyPath
|
||||||
|
self.defaultValue = initial
|
||||||
|
self.isIndexed = isIndexed
|
||||||
|
self.isTransient = isTransient
|
||||||
|
self.versionHashModifier = versionHashModifier
|
||||||
|
self.renamingIdentifier = renamingIdentifier
|
||||||
|
self.customGetter = customGetter
|
||||||
|
self.customSetter = customSetter
|
||||||
|
self.affectedByKeyPaths = affectedByKeyPaths
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
The property value.
|
||||||
|
*/
|
||||||
|
public var value: V? {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.parentObject != nil,
|
||||||
|
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
if let customGetter = self.customGetter {
|
||||||
|
|
||||||
|
return customGetter(PartialObject<O>(object.rawObject!))
|
||||||
|
}
|
||||||
|
return object.rawObject!.value(forKey: self.keyPath) as! V?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.parentObject != nil,
|
||||||
|
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
object.rawObject!.isEditableInContext() == true,
|
||||||
|
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
|
||||||
|
)
|
||||||
|
if let customSetter = self.customSetter {
|
||||||
|
|
||||||
|
return customSetter(PartialObject<O>(object.rawObject!), newValue)
|
||||||
|
}
|
||||||
|
object.rawObject!.setValue(
|
||||||
|
newValue,
|
||||||
|
forKey: self.keyPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: AttributeProtocol
|
||||||
|
|
||||||
|
internal static var attributeType: NSAttributeType {
|
||||||
|
|
||||||
|
return .transformableAttributeType
|
||||||
|
}
|
||||||
|
|
||||||
|
public let keyPath: KeyPath
|
||||||
|
|
||||||
|
internal let isOptional = true
|
||||||
|
internal let isIndexed: Bool
|
||||||
|
internal let isTransient: Bool
|
||||||
|
internal let versionHashModifier: () -> String?
|
||||||
|
internal let renamingIdentifier: () -> String?
|
||||||
|
internal let defaultValue: () -> Any?
|
||||||
|
internal let affectedByKeyPaths: () -> Set<String>
|
||||||
|
internal weak var parentObject: CoreStoreObject?
|
||||||
|
|
||||||
|
internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = cs_lazy { [unowned self] in
|
||||||
|
|
||||||
|
guard let customGetter = self.customGetter else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let keyPath = self.keyPath
|
||||||
|
return { (_ id: Any) -> Any? in
|
||||||
|
|
||||||
|
let rawObject = id as! CoreStoreManagedObject
|
||||||
|
rawObject.willAccessValue(forKey: keyPath)
|
||||||
|
defer {
|
||||||
|
|
||||||
|
rawObject.didAccessValue(forKey: keyPath)
|
||||||
|
}
|
||||||
|
let value = customGetter(PartialObject<O>(rawObject))
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal private(set) lazy var setter: CoreStoreManagedObject.CustomSetter? = cs_lazy { [unowned self] in
|
||||||
|
|
||||||
|
guard let customSetter = self.customSetter else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let keyPath = self.keyPath
|
||||||
|
return { (_ id: Any, _ newValue: Any?) -> Void in
|
||||||
|
|
||||||
|
let rawObject = id as! CoreStoreManagedObject
|
||||||
|
rawObject.willChangeValue(forKey: keyPath)
|
||||||
|
defer {
|
||||||
|
|
||||||
|
rawObject.didChangeValue(forKey: keyPath)
|
||||||
|
}
|
||||||
|
customSetter(
|
||||||
|
PartialObject<O>(rawObject),
|
||||||
|
newValue as! V?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private let customGetter: ((_ partialObject: PartialObject<O>) -> V?)?
|
||||||
|
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)?
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 3.1, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||||
|
public convenience init(
|
||||||
|
_ keyPath: KeyPath,
|
||||||
|
`default`: @autoclosure @escaping () -> V?,
|
||||||
|
isIndexed: Bool = false,
|
||||||
|
isTransient: Bool = false,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath,
|
||||||
|
initial: `default`,
|
||||||
|
isIndexed: isIndexed,
|
||||||
|
isTransient: isTransient,
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: renamingIdentifier,
|
||||||
|
customGetter: customGetter,
|
||||||
|
customSetter: customSetter,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Operations
|
||||||
|
|
||||||
|
infix operator .= : AssignmentPrecedence
|
||||||
|
infix operator .== : ComparisonPrecedence
|
||||||
|
|
||||||
|
extension TransformableContainer.Required {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Assigns a transformable value to the property. The operation
|
||||||
|
```
|
||||||
|
animal.color .= UIColor.red
|
||||||
|
```
|
||||||
|
is equivalent to
|
||||||
|
```
|
||||||
|
animal.color.value = UIColor.red
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func .= (_ property: TransformableContainer<O>.Required<V>, _ newValue: V) {
|
||||||
|
|
||||||
|
property.value = newValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Assigns a transformable value from another property. The operation
|
||||||
|
```
|
||||||
|
animal.nickname .= anotherAnimal.species
|
||||||
|
```
|
||||||
|
is equivalent to
|
||||||
|
```
|
||||||
|
animal.nickname.value = anotherAnimal.species.value
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func .= <O2>(_ property: TransformableContainer<O>.Required<V>, _ property2: TransformableContainer<O2>.Required<V>) {
|
||||||
|
|
||||||
|
property.value = property2.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TransformableContainer.Optional {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Assigns an optional transformable value to the property. The operation
|
||||||
|
```
|
||||||
|
animal.color .= UIColor.red
|
||||||
|
```
|
||||||
|
is equivalent to
|
||||||
|
```
|
||||||
|
animal.color.value = UIColor.red
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func .= (_ property: TransformableContainer<O>.Optional<V>, _ newValue: V?) {
|
||||||
|
|
||||||
|
property.value = newValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Assigns an optional transformable value from another property. The operation
|
||||||
|
```
|
||||||
|
animal.color .= anotherAnimal.color
|
||||||
|
```
|
||||||
|
is equivalent to
|
||||||
|
```
|
||||||
|
animal.color.value = anotherAnimal.color.value
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func .= <O2>(_ property: TransformableContainer<O>.Optional<V>, _ property2: TransformableContainer<O2>.Optional<V>) {
|
||||||
|
|
||||||
|
property.value = property2.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Assigns a transformable value from another property. The operation
|
||||||
|
```
|
||||||
|
animal.color .= anotherAnimal.color
|
||||||
|
```
|
||||||
|
is equivalent to
|
||||||
|
```
|
||||||
|
animal.color.value = anotherAnimal.color.value
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func .= <O2>(_ property: TransformableContainer<O>.Optional<V>, _ property2: TransformableContainer<O2>.Required<V>) {
|
||||||
|
|
||||||
|
property.value = property2.value
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,19 +43,6 @@ public extension DynamicObject where Self: CoreStoreObject {
|
|||||||
- Important: `Value` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
- Important: `Value` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
||||||
*/
|
*/
|
||||||
public typealias Value = ValueContainer<Self>
|
public typealias Value = ValueContainer<Self>
|
||||||
|
|
||||||
/**
|
|
||||||
The containing type for transformable properties. `Transformable` properties support types that conforms to `NSCoding & NSCopying`.
|
|
||||||
```
|
|
||||||
class Animal: CoreStoreObject {
|
|
||||||
let species = Value.Required<String>("species")
|
|
||||||
let nickname = Value.Optional<String>("nickname")
|
|
||||||
let color = Transformable.Optional<UIColor>("color")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Important: `Transformable` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
|
||||||
*/
|
|
||||||
public typealias Transformable = TransformableContainer<Self>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -92,7 +79,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
Initializes the metadata for the property.
|
Initializes the metadata for the property.
|
||||||
```
|
```
|
||||||
class Person: CoreStoreObject {
|
class Person: CoreStoreObject {
|
||||||
let title = Value.Required<String>("title", default: "Mr.")
|
let title = Value.Required<String>("title", initial: "Mr.")
|
||||||
let name = Value.Required<String>("name")
|
let name = Value.Required<String>("name")
|
||||||
let displayName = Value.Required<String>(
|
let displayName = Value.Required<String>(
|
||||||
"displayName",
|
"displayName",
|
||||||
@@ -114,7 +101,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
- parameter keyPath: the permanent attribute name for this property.
|
- parameter keyPath: the permanent attribute name for this property.
|
||||||
- parameter default: the initial value for the property when the object is first created. For types that implement `EmptyableAttributeType`s, this argument may be omitted and the type's "empty" value will be used instead (e.g. `false` for `Bool`, `0` for `Int`, `""` for `String`, etc.)
|
- parameter initial: the initial value for the property when the object is first created
|
||||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||||
@@ -125,11 +112,11 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
*/
|
*/
|
||||||
public init(
|
public init(
|
||||||
_ keyPath: KeyPath,
|
_ keyPath: KeyPath,
|
||||||
`default`: @autoclosure @escaping () -> V,
|
initial: @autoclosure @escaping () -> V,
|
||||||
isIndexed: Bool = false,
|
isIndexed: Bool = false,
|
||||||
isTransient: Bool = false,
|
isTransient: Bool = false,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
||||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
@@ -137,7 +124,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
self.keyPath = keyPath
|
self.keyPath = keyPath
|
||||||
self.isIndexed = isIndexed
|
self.isIndexed = isIndexed
|
||||||
self.isTransient = isTransient
|
self.isTransient = isTransient
|
||||||
self.defaultValue = { `default`().cs_toImportableNativeType() }
|
self.defaultValue = { initial().cs_toImportableNativeType() }
|
||||||
self.versionHashModifier = versionHashModifier
|
self.versionHashModifier = versionHashModifier
|
||||||
self.renamingIdentifier = renamingIdentifier
|
self.renamingIdentifier = renamingIdentifier
|
||||||
self.customGetter = customGetter
|
self.customGetter = customGetter
|
||||||
@@ -212,8 +199,8 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
internal let isOptional = false
|
internal let isOptional = false
|
||||||
internal let isIndexed: Bool
|
internal let isIndexed: Bool
|
||||||
internal let isTransient: Bool
|
internal let isTransient: Bool
|
||||||
internal let versionHashModifier: String?
|
internal let versionHashModifier: () -> String?
|
||||||
internal let renamingIdentifier: String?
|
internal let renamingIdentifier: () -> String?
|
||||||
internal let defaultValue: () -> Any?
|
internal let defaultValue: () -> Any?
|
||||||
internal let affectedByKeyPaths: () -> Set<String>
|
internal let affectedByKeyPaths: () -> Set<String>
|
||||||
internal weak var parentObject: CoreStoreObject?
|
internal weak var parentObject: CoreStoreObject?
|
||||||
@@ -265,6 +252,34 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
|
|
||||||
private let customGetter: ((_ partialObject: PartialObject<O>) -> V)?
|
private let customGetter: ((_ partialObject: PartialObject<O>) -> V)?
|
||||||
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)?
|
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)?
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 3.1, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||||
|
public convenience init(
|
||||||
|
_ keyPath: KeyPath,
|
||||||
|
`default`: @autoclosure @escaping () -> V,
|
||||||
|
isIndexed: Bool = false,
|
||||||
|
isTransient: Bool = false,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath,
|
||||||
|
initial: `default`,
|
||||||
|
isIndexed: isIndexed,
|
||||||
|
isTransient: isTransient,
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: renamingIdentifier,
|
||||||
|
customGetter: customGetter,
|
||||||
|
customSetter: customSetter,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -287,7 +302,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
Initializes the metadata for the property.
|
Initializes the metadata for the property.
|
||||||
```
|
```
|
||||||
class Person: CoreStoreObject {
|
class Person: CoreStoreObject {
|
||||||
let title = Value.Optional<String>("title", default: "Mr.")
|
let title = Value.Optional<String>("title", initial: "Mr.")
|
||||||
let name = Value.Optional<String>("name")
|
let name = Value.Optional<String>("name")
|
||||||
let displayName = Value.Optional<String>(
|
let displayName = Value.Optional<String>(
|
||||||
"displayName",
|
"displayName",
|
||||||
@@ -308,7 +323,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
- parameter keyPath: the permanent attribute name for this property.
|
- parameter keyPath: the permanent attribute name for this property.
|
||||||
- parameter default: the initial value for the property when the object is first created. Defaults to `nil` if not specified.
|
- parameter initial: the initial value for the property when the object is first created. Defaults to `nil` if not specified.
|
||||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
||||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||||
@@ -324,11 +339,11 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
*/
|
*/
|
||||||
public init(
|
public init(
|
||||||
_ keyPath: KeyPath,
|
_ keyPath: KeyPath,
|
||||||
`default`: @autoclosure @escaping () -> V? = nil,
|
initial: @autoclosure @escaping () -> V? = nil,
|
||||||
isIndexed: Bool = false,
|
isIndexed: Bool = false,
|
||||||
isTransient: Bool = false,
|
isTransient: Bool = false,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
||||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
@@ -336,7 +351,7 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
self.keyPath = keyPath
|
self.keyPath = keyPath
|
||||||
self.isIndexed = isIndexed
|
self.isIndexed = isIndexed
|
||||||
self.isTransient = isTransient
|
self.isTransient = isTransient
|
||||||
self.defaultValue = { `default`()?.cs_toImportableNativeType() }
|
self.defaultValue = { initial()?.cs_toImportableNativeType() }
|
||||||
self.versionHashModifier = versionHashModifier
|
self.versionHashModifier = versionHashModifier
|
||||||
self.renamingIdentifier = renamingIdentifier
|
self.renamingIdentifier = renamingIdentifier
|
||||||
self.customGetter = customGetter
|
self.customGetter = customGetter
|
||||||
@@ -409,8 +424,8 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
internal let isOptional = true
|
internal let isOptional = true
|
||||||
internal let isIndexed: Bool
|
internal let isIndexed: Bool
|
||||||
internal let isTransient: Bool
|
internal let isTransient: Bool
|
||||||
internal let versionHashModifier: String?
|
internal let versionHashModifier: () -> String?
|
||||||
internal let renamingIdentifier: String?
|
internal let renamingIdentifier: () -> String?
|
||||||
internal let defaultValue: () -> Any?
|
internal let defaultValue: () -> Any?
|
||||||
internal let affectedByKeyPaths: () -> Set<String>
|
internal let affectedByKeyPaths: () -> Set<String>
|
||||||
internal weak var parentObject: CoreStoreObject?
|
internal weak var parentObject: CoreStoreObject?
|
||||||
@@ -462,457 +477,34 @@ public enum ValueContainer<O: CoreStoreObject> {
|
|||||||
|
|
||||||
private let customGetter: ((_ partialObject: PartialObject<O>) -> V?)?
|
private let customGetter: ((_ partialObject: PartialObject<O>) -> V?)?
|
||||||
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)?
|
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)?
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension ValueContainer.Required where V: EmptyableAttributeType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Initializes the metadata for the property. This convenience initializer uses the `EmptyableAttributeType`'s "empty" value as the initial value for the property when the object is first created (e.g. `false` for `Bool`, `0` for `Int`, `""` for `String`, etc.)
|
|
||||||
```
|
|
||||||
class Person: CoreStoreObject {
|
|
||||||
let title = Value.Required<String>("title", default: "Mr.") // explicit default value
|
|
||||||
let name = Value.Required<String>("name") // initial value defaults to empty string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- parameter keyPath: the permanent attribute name for this property.
|
|
||||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
|
||||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
|
||||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
|
||||||
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
|
||||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.primitiveValue(for:)` instead of `PartialObject<O>.value(for:)`, which would unintentionally execute the same closure again recursively.
|
|
||||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.setPrimitiveValue(_:for:)` instead of `PartialObject<O>.setValue(_:for:)`, which would unintentionally execute the same closure again recursively.
|
|
||||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
|
||||||
*/
|
|
||||||
public convenience init(
|
|
||||||
_ keyPath: KeyPath,
|
|
||||||
isIndexed: Bool = false,
|
|
||||||
isTransient: Bool = false,
|
|
||||||
versionHashModifier: String? = nil,
|
|
||||||
renamingIdentifier: String? = nil,
|
|
||||||
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
|
||||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
|
||||||
|
|
||||||
self.init(
|
|
||||||
keyPath,
|
|
||||||
default: V.cs_emptyValue(),
|
|
||||||
isIndexed: isIndexed,
|
|
||||||
isTransient: isTransient,
|
|
||||||
versionHashModifier: versionHashModifier,
|
|
||||||
renamingIdentifier: renamingIdentifier,
|
|
||||||
customGetter: customGetter,
|
|
||||||
customSetter: customSetter,
|
|
||||||
affectedByKeyPaths: affectedByKeyPaths
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - TransformableContainer
|
|
||||||
|
|
||||||
/**
|
|
||||||
The containing type for transformable properties. Use the `DynamicObject.Transformable` typealias instead for shorter syntax.
|
|
||||||
```
|
|
||||||
class Animal: CoreStoreObject {
|
|
||||||
let species = Value.Required<String>("species")
|
|
||||||
let nickname = Value.Optional<String>("nickname")
|
|
||||||
let color = Transformable.Optional<UIColor>("color")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
public enum TransformableContainer<O: CoreStoreObject> {
|
|
||||||
|
|
||||||
// MARK: - Required
|
|
||||||
|
|
||||||
/**
|
|
||||||
The containing type for transformable properties. Any type that conforms to `NSCoding & NSCopying` are supported.
|
|
||||||
```
|
|
||||||
class Animal: CoreStoreObject {
|
|
||||||
let species = Value.Required<String>("species")
|
|
||||||
let nickname = Value.Optional<String>("nickname")
|
|
||||||
let color = Transformable.Optional<UIColor>("color")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Important: `Transformable.Required` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
|
||||||
*/
|
|
||||||
public final class Required<V: NSCoding & NSCopying>: AttributeProtocol {
|
|
||||||
|
|
||||||
/**
|
// MARK: Deprecated
|
||||||
Initializes the metadata for the property.
|
|
||||||
```
|
@available(*, deprecated: 3.1, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
|
||||||
class Animal: CoreStoreObject {
|
public convenience init(
|
||||||
let species = Value.Required<String>("species")
|
|
||||||
let color = Transformable.Required<UIColor>(
|
|
||||||
"color",
|
|
||||||
default: UIColor.clear,
|
|
||||||
isTransient: true,
|
|
||||||
customGetter: Animal.getColor(_:)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func getColor(_ partialObject: PartialObject<Animal>) -> UIColor {
|
|
||||||
let cachedColor = partialObject.primitiveValue(for: { $0.color })
|
|
||||||
if cachedColor != UIColor.clear {
|
|
||||||
|
|
||||||
return cachedColor
|
|
||||||
}
|
|
||||||
let color: UIColor
|
|
||||||
switch partialObject.value(for: { $0.species }) {
|
|
||||||
|
|
||||||
case "Swift": color = UIColor.orange
|
|
||||||
case "Bulbasaur": color = UIColor.green
|
|
||||||
default: color = UIColor.black
|
|
||||||
}
|
|
||||||
partialObject.setPrimitiveValue(color, for: { $0.color })
|
|
||||||
return color
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- parameter keyPath: the permanent attribute name for this property.
|
|
||||||
- parameter default: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
|
||||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
|
||||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
|
||||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
|
||||||
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
|
||||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.primitiveValue(for:)` instead of `PartialObject<O>.value(for:)`, which would unintentionally execute the same closure again recursively.
|
|
||||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.setPrimitiveValue(_:for:)` instead of `PartialObject<O>.setValue(_:for:)`, which would unintentionally execute the same closure again recursively.
|
|
||||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
|
||||||
*/
|
|
||||||
public init(
|
|
||||||
_ keyPath: KeyPath,
|
_ keyPath: KeyPath,
|
||||||
`default`: @autoclosure @escaping () -> V,
|
`default`: @autoclosure @escaping () -> V?,
|
||||||
isIndexed: Bool = false,
|
isIndexed: Bool = false,
|
||||||
isTransient: Bool = false,
|
isTransient: Bool = false,
|
||||||
versionHashModifier: String? = nil,
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
renamingIdentifier: String? = nil,
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
|
||||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
|
||||||
|
|
||||||
self.keyPath = keyPath
|
|
||||||
self.defaultValue = `default`
|
|
||||||
self.isIndexed = isIndexed
|
|
||||||
self.isTransient = isTransient
|
|
||||||
self.versionHashModifier = versionHashModifier
|
|
||||||
self.renamingIdentifier = renamingIdentifier
|
|
||||||
self.customGetter = customGetter
|
|
||||||
self.customSetter = customSetter
|
|
||||||
self.affectedByKeyPaths = affectedByKeyPaths
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The property value.
|
|
||||||
*/
|
|
||||||
public var value: V {
|
|
||||||
|
|
||||||
get {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.parentObject != nil,
|
|
||||||
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
|
||||||
)
|
|
||||||
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isRunningInAllowedQueue() == true,
|
|
||||||
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
|
||||||
)
|
|
||||||
if let customGetter = self.customGetter {
|
|
||||||
|
|
||||||
return customGetter(PartialObject<O>(object.rawObject!))
|
|
||||||
}
|
|
||||||
return object.rawObject!.value(forKey: self.keyPath)! as! V
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.parentObject != nil,
|
|
||||||
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
|
||||||
)
|
|
||||||
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isRunningInAllowedQueue() == true,
|
|
||||||
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isEditableInContext() == true,
|
|
||||||
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
|
|
||||||
)
|
|
||||||
if let customSetter = self.customSetter {
|
|
||||||
|
|
||||||
return customSetter(PartialObject<O>(object.rawObject!), newValue)
|
|
||||||
}
|
|
||||||
object.rawObject!.setValue(
|
|
||||||
newValue,
|
|
||||||
forKey: self.keyPath
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: AttributeProtocol
|
|
||||||
|
|
||||||
internal static var attributeType: NSAttributeType {
|
|
||||||
|
|
||||||
return .transformableAttributeType
|
|
||||||
}
|
|
||||||
|
|
||||||
public let keyPath: KeyPath
|
|
||||||
|
|
||||||
internal let isOptional = false
|
|
||||||
internal let isIndexed: Bool
|
|
||||||
internal let isTransient: Bool
|
|
||||||
internal let versionHashModifier: String?
|
|
||||||
internal let renamingIdentifier: String?
|
|
||||||
internal let defaultValue: () -> Any?
|
|
||||||
internal let affectedByKeyPaths: () -> Set<String>
|
|
||||||
internal weak var parentObject: CoreStoreObject?
|
|
||||||
|
|
||||||
internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = cs_lazy { [unowned self] in
|
|
||||||
|
|
||||||
guard let customGetter = self.customGetter else {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let keyPath = self.keyPath
|
|
||||||
return { (_ id: Any) -> Any? in
|
|
||||||
|
|
||||||
let rawObject = id as! CoreStoreManagedObject
|
|
||||||
rawObject.willAccessValue(forKey: keyPath)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
rawObject.didAccessValue(forKey: keyPath)
|
|
||||||
}
|
|
||||||
let value = customGetter(PartialObject<O>(rawObject))
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal private(set) lazy var setter: CoreStoreManagedObject.CustomSetter? = cs_lazy { [unowned self] in
|
|
||||||
|
|
||||||
guard let customSetter = self.customSetter else {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let keyPath = self.keyPath
|
|
||||||
return { (_ id: Any, _ newValue: Any?) -> Void in
|
|
||||||
|
|
||||||
let rawObject = id as! CoreStoreManagedObject
|
|
||||||
rawObject.willChangeValue(forKey: keyPath)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
rawObject.didChangeValue(forKey: keyPath)
|
|
||||||
}
|
|
||||||
customSetter(
|
|
||||||
PartialObject<O>(rawObject),
|
|
||||||
newValue as! V
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let customGetter: ((_ partialObject: PartialObject<O>) -> V)?
|
|
||||||
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Optional
|
|
||||||
|
|
||||||
/**
|
|
||||||
The containing type for optional transformable properties. Any type that conforms to `NSCoding & NSCopying` are supported.
|
|
||||||
```
|
|
||||||
class Animal: CoreStoreObject {
|
|
||||||
let species = Value.Required<String>("species")
|
|
||||||
let nickname = Value.Optional<String>("nickname")
|
|
||||||
let color = Transformable.Optional<UIColor>("color")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Important: `Transformable.Optional` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
|
|
||||||
*/
|
|
||||||
public final class Optional<V: NSCoding & NSCopying>: AttributeProtocol {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Initializes the metadata for the property.
|
|
||||||
```
|
|
||||||
class Animal: CoreStoreObject {
|
|
||||||
let species = Value.Required<String>("species")
|
|
||||||
let color = Transformable.Optional<UIColor>(
|
|
||||||
"color",
|
|
||||||
isTransient: true,
|
|
||||||
customGetter: Animal.getColor(_:)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func getColor(_ partialObject: PartialObject<Animal>) -> UIColor? {
|
|
||||||
if let cachedColor = partialObject.primitiveValue(for: { $0.color }) {
|
|
||||||
return cachedColor
|
|
||||||
}
|
|
||||||
let color: UIColor?
|
|
||||||
switch partialObject.value(for: { $0.species }) {
|
|
||||||
|
|
||||||
case "Swift": color = UIColor.orange
|
|
||||||
case "Bulbasaur": color = UIColor.green
|
|
||||||
default: return nil
|
|
||||||
}
|
|
||||||
partialObject.setPrimitiveValue(color, for: { $0.color })
|
|
||||||
return color
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- parameter keyPath: the permanent attribute name for this property.
|
|
||||||
- parameter default: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
|
||||||
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
|
|
||||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
|
||||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
|
||||||
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
|
||||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.primitiveValue(for:)` instead of `PartialObject<O>.value(for:)`, which would unintentionally execute the same closure again recursively.
|
|
||||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `PartialObject<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `PartialObject<O>`, make sure to use `PartialObject<O>.setPrimitiveValue(_:for:)` instead of `PartialObject<O>.setValue(_:for:)`, which would unintentionally execute the same closure again recursively.
|
|
||||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
|
||||||
*/
|
|
||||||
public init(
|
|
||||||
_ keyPath: KeyPath,
|
|
||||||
`default`: @autoclosure @escaping () -> V? = nil,
|
|
||||||
isIndexed: Bool = false,
|
|
||||||
isTransient: Bool = false,
|
|
||||||
versionHashModifier: String? = nil,
|
|
||||||
renamingIdentifier: String? = nil,
|
|
||||||
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
customGetter: ((_ partialObject: PartialObject<O>) -> V?)? = nil,
|
||||||
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)? = nil,
|
||||||
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<String> = []) {
|
||||||
|
|
||||||
self.keyPath = keyPath
|
self.init(
|
||||||
self.defaultValue = `default`
|
keyPath,
|
||||||
self.isIndexed = isIndexed
|
initial: `default`,
|
||||||
self.isTransient = isTransient
|
isIndexed: isIndexed,
|
||||||
self.versionHashModifier = versionHashModifier
|
isTransient: isTransient,
|
||||||
self.renamingIdentifier = renamingIdentifier
|
versionHashModifier: versionHashModifier,
|
||||||
self.customGetter = customGetter
|
renamingIdentifier: renamingIdentifier,
|
||||||
self.customSetter = customSetter
|
customGetter: customGetter,
|
||||||
self.affectedByKeyPaths = affectedByKeyPaths
|
customSetter: customSetter,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
The property value.
|
|
||||||
*/
|
|
||||||
public var value: V? {
|
|
||||||
|
|
||||||
get {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.parentObject != nil,
|
|
||||||
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
|
||||||
)
|
|
||||||
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isRunningInAllowedQueue() == true,
|
|
||||||
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
|
||||||
)
|
|
||||||
if let customGetter = self.customGetter {
|
|
||||||
|
|
||||||
return customGetter(PartialObject<O>(object.rawObject!))
|
|
||||||
}
|
|
||||||
return object.rawObject!.value(forKey: self.keyPath) as! V?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.parentObject != nil,
|
|
||||||
"Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
|
||||||
)
|
|
||||||
return withExtendedLifetime(self.parentObject! as! O) { (object: O) in
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isRunningInAllowedQueue() == true,
|
|
||||||
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
object.rawObject!.isEditableInContext() == true,
|
|
||||||
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
|
|
||||||
)
|
|
||||||
if let customSetter = self.customSetter {
|
|
||||||
|
|
||||||
return customSetter(PartialObject<O>(object.rawObject!), newValue)
|
|
||||||
}
|
|
||||||
object.rawObject!.setValue(
|
|
||||||
newValue,
|
|
||||||
forKey: self.keyPath
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: AttributeProtocol
|
|
||||||
|
|
||||||
internal static var attributeType: NSAttributeType {
|
|
||||||
|
|
||||||
return .transformableAttributeType
|
|
||||||
}
|
|
||||||
|
|
||||||
public let keyPath: KeyPath
|
|
||||||
|
|
||||||
internal let isOptional = true
|
|
||||||
internal let isIndexed: Bool
|
|
||||||
internal let isTransient: Bool
|
|
||||||
internal let versionHashModifier: String?
|
|
||||||
internal let renamingIdentifier: String?
|
|
||||||
internal let defaultValue: () -> Any?
|
|
||||||
internal let affectedByKeyPaths: () -> Set<String>
|
|
||||||
internal weak var parentObject: CoreStoreObject?
|
|
||||||
|
|
||||||
internal private(set) lazy var getter: CoreStoreManagedObject.CustomGetter? = cs_lazy { [unowned self] in
|
|
||||||
|
|
||||||
guard let customGetter = self.customGetter else {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let keyPath = self.keyPath
|
|
||||||
return { (_ id: Any) -> Any? in
|
|
||||||
|
|
||||||
let rawObject = id as! CoreStoreManagedObject
|
|
||||||
rawObject.willAccessValue(forKey: keyPath)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
rawObject.didAccessValue(forKey: keyPath)
|
|
||||||
}
|
|
||||||
let value = customGetter(PartialObject<O>(rawObject))
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal private(set) lazy var setter: CoreStoreManagedObject.CustomSetter? = cs_lazy { [unowned self] in
|
|
||||||
|
|
||||||
guard let customSetter = self.customSetter else {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let keyPath = self.keyPath
|
|
||||||
return { (_ id: Any, _ newValue: Any?) -> Void in
|
|
||||||
|
|
||||||
let rawObject = id as! CoreStoreManagedObject
|
|
||||||
rawObject.willChangeValue(forKey: keyPath)
|
|
||||||
defer {
|
|
||||||
|
|
||||||
rawObject.didChangeValue(forKey: keyPath)
|
|
||||||
}
|
|
||||||
customSetter(
|
|
||||||
PartialObject<O>(rawObject),
|
|
||||||
newValue as! V?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let customGetter: ((_ partialObject: PartialObject<O>) -> V?)?
|
|
||||||
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V?) -> Void)?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,104 +714,3 @@ extension ValueContainer.Optional {
|
|||||||
return property.value == property2.value
|
return property.value == property2.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TransformableContainer.Required {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Assigns a transformable value to the property. The operation
|
|
||||||
```
|
|
||||||
animal.color .= UIColor.red
|
|
||||||
```
|
|
||||||
is equivalent to
|
|
||||||
```
|
|
||||||
animal.color.value = UIColor.red
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
public static func .= (_ property: TransformableContainer<O>.Required<V>, _ newValue: V) {
|
|
||||||
|
|
||||||
property.value = newValue
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Assigns a transformable value from another property. The operation
|
|
||||||
```
|
|
||||||
animal.nickname .= anotherAnimal.species
|
|
||||||
```
|
|
||||||
is equivalent to
|
|
||||||
```
|
|
||||||
animal.nickname.value = anotherAnimal.species.value
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
public static func .= <O2: CoreStoreObject>(_ property: TransformableContainer<O>.Required<V>, _ property2: TransformableContainer<O2>.Required<V>) {
|
|
||||||
|
|
||||||
property.value = property2.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TransformableContainer.Optional {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Assigns an optional transformable value to the property. The operation
|
|
||||||
```
|
|
||||||
animal.color .= UIColor.red
|
|
||||||
```
|
|
||||||
is equivalent to
|
|
||||||
```
|
|
||||||
animal.color.value = UIColor.red
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
public static func .= (_ property: TransformableContainer<O>.Optional<V>, _ newValue: V?) {
|
|
||||||
|
|
||||||
property.value = newValue
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Assigns an optional transformable value from another property. The operation
|
|
||||||
```
|
|
||||||
animal.color .= anotherAnimal.color
|
|
||||||
```
|
|
||||||
is equivalent to
|
|
||||||
```
|
|
||||||
animal.color.value = anotherAnimal.color.value
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
public static func .= <O2: CoreStoreObject>(_ property: TransformableContainer<O>.Optional<V>, _ property2: TransformableContainer<O2>.Optional<V>) {
|
|
||||||
|
|
||||||
property.value = property2.value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Assigns a transformable value from another property. The operation
|
|
||||||
```
|
|
||||||
animal.color .= anotherAnimal.color
|
|
||||||
```
|
|
||||||
is equivalent to
|
|
||||||
```
|
|
||||||
animal.color.value = anotherAnimal.color.value
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
public static func .= <O2: CoreStoreObject>(_ property: TransformableContainer<O>.Optional<V>, _ property2: TransformableContainer<O2>.Required<V>) {
|
|
||||||
|
|
||||||
property.value = property2.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - AttributeProtocol
|
|
||||||
|
|
||||||
internal protocol AttributeProtocol: class {
|
|
||||||
|
|
||||||
static var attributeType: NSAttributeType { get }
|
|
||||||
|
|
||||||
var keyPath: KeyPath { get }
|
|
||||||
var isOptional: Bool { get }
|
|
||||||
var isIndexed: Bool { get }
|
|
||||||
var isTransient: Bool { get }
|
|
||||||
var versionHashModifier: String? { get }
|
|
||||||
var renamingIdentifier: String? { get }
|
|
||||||
var defaultValue: () -> Any? { get }
|
|
||||||
var affectedByKeyPaths: () -> Set<String> { get }
|
|
||||||
weak var parentObject: CoreStoreObject? { get set }
|
|
||||||
var getter: CoreStoreManagedObject.CustomGetter? { get }
|
|
||||||
var setter: CoreStoreManagedObject.CustomSetter? { get }
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user