mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-31 06:33:06 +02:00
prototype new Fields as propertyWrappers (Swift 5.2 above only)
This commit is contained in:
@@ -322,7 +322,6 @@
|
|||||||
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||||
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||||
B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */; };
|
||||||
B53304AA230BA4F7007C2BD8 /* DynamicObjectMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53304A9230BA4F7007C2BD8 /* DynamicObjectMeta.swift */; };
|
|
||||||
B533C4DB1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
B533C4DB1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
||||||
B533C4DC1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
B533C4DC1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
||||||
B533C4DD1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
B533C4DD1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */; };
|
||||||
@@ -548,6 +547,34 @@
|
|||||||
B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */; };
|
B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */; };
|
||||||
B56964D41B22FFAD0075EE4A /* DataStack+Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */; };
|
B56964D41B22FFAD0075EE4A /* DataStack+Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */; };
|
||||||
B56965241B356B820075EE4A /* MigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965231B356B820075EE4A /* MigrationResult.swift */; };
|
B56965241B356B820075EE4A /* MigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965231B356B820075EE4A /* MigrationResult.swift */; };
|
||||||
|
B56E4ECA23CD9B4800E1708C /* Field.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EC923CD9B4800E1708C /* Field.swift */; };
|
||||||
|
B56E4ECB23CD9B4800E1708C /* Field.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EC923CD9B4800E1708C /* Field.swift */; };
|
||||||
|
B56E4ECC23CD9B4800E1708C /* Field.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EC923CD9B4800E1708C /* Field.swift */; };
|
||||||
|
B56E4ECD23CD9B4800E1708C /* Field.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EC923CD9B4800E1708C /* Field.swift */; };
|
||||||
|
B56E4ECF23CD9E4200E1708C /* Field.Stored.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */; };
|
||||||
|
B56E4ED023CD9E4200E1708C /* Field.Stored.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */; };
|
||||||
|
B56E4ED123CD9E4200E1708C /* Field.Stored.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */; };
|
||||||
|
B56E4ED223CD9E4200E1708C /* Field.Stored.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */; };
|
||||||
|
B56E4ED423CDB54A00E1708C /* FieldProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */; };
|
||||||
|
B56E4ED523CDB54A00E1708C /* FieldProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */; };
|
||||||
|
B56E4ED623CDB54A00E1708C /* FieldProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */; };
|
||||||
|
B56E4ED723CDB54A00E1708C /* FieldProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */; };
|
||||||
|
B56E4ED923CEB8E700E1708C /* FieldStorableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */; };
|
||||||
|
B56E4EDA23CEB8E700E1708C /* FieldStorableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */; };
|
||||||
|
B56E4EDB23CEB8E700E1708C /* FieldStorableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */; };
|
||||||
|
B56E4EDC23CEB8E700E1708C /* FieldStorableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */; };
|
||||||
|
B56E4EDF23CEBCF000E1708C /* FieldOptionalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */; };
|
||||||
|
B56E4EE023CEBCF000E1708C /* FieldOptionalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */; };
|
||||||
|
B56E4EE123CEBCF000E1708C /* FieldOptionalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */; };
|
||||||
|
B56E4EE223CEBCF000E1708C /* FieldOptionalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */; };
|
||||||
|
B56E4EE423CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; };
|
||||||
|
B56E4EE523CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; };
|
||||||
|
B56E4EE623CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; };
|
||||||
|
B56E4EE723CEDF0900E1708C /* Field.Computed.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE323CEDF0900E1708C /* Field.Computed.swift */; };
|
||||||
|
B56E4EE923CF0C4500E1708C /* Field.PlistCoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE823CF0C4500E1708C /* Field.PlistCoded.swift */; };
|
||||||
|
B56E4EEA23CF0C4500E1708C /* Field.PlistCoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE823CF0C4500E1708C /* Field.PlistCoded.swift */; };
|
||||||
|
B56E4EEB23CF0C4500E1708C /* Field.PlistCoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE823CF0C4500E1708C /* Field.PlistCoded.swift */; };
|
||||||
|
B56E4EEC23CF0C4500E1708C /* Field.PlistCoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56E4EE823CF0C4500E1708C /* Field.PlistCoded.swift */; };
|
||||||
B57D27BE1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
B57D27BE1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
||||||
B57D27BF1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
B57D27BF1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
||||||
B57D27C01D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
B57D27C01D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
|
||||||
@@ -979,7 +1006,6 @@
|
|||||||
B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeDataModelSchema.swift; sourceTree = "<group>"; };
|
B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeDataModelSchema.swift; sourceTree = "<group>"; };
|
||||||
B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreSchema.swift; sourceTree = "<group>"; };
|
B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreSchema.swift; sourceTree = "<group>"; };
|
||||||
B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Logging.swift"; sourceTree = "<group>"; };
|
B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Logging.swift"; sourceTree = "<group>"; };
|
||||||
B53304A9230BA4F7007C2BD8 /* DynamicObjectMeta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicObjectMeta.swift; sourceTree = "<group>"; };
|
|
||||||
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+CoreStore.swift"; sourceTree = "<group>"; };
|
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+CoreStore.swift"; sourceTree = "<group>"; };
|
||||||
B538BA701D15B3E30003A766 /* CoreStoreBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreStoreBridge.m; sourceTree = "<group>"; };
|
B538BA701D15B3E30003A766 /* CoreStoreBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CoreStoreBridge.m; sourceTree = "<group>"; };
|
||||||
B53B275E1EE3B92E00E9B352 /* CoreStoreManagedObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreManagedObject.swift; sourceTree = "<group>"; };
|
B53B275E1EE3B92E00E9B352 /* CoreStoreManagedObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreManagedObject.swift; sourceTree = "<group>"; };
|
||||||
@@ -1038,6 +1064,13 @@
|
|||||||
B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSUnsafeDataModelSchema.swift; sourceTree = "<group>"; };
|
B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSUnsafeDataModelSchema.swift; sourceTree = "<group>"; };
|
||||||
B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "DataStack+Migration.swift"; sourceTree = "<group>"; };
|
B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "DataStack+Migration.swift"; sourceTree = "<group>"; };
|
||||||
B56965231B356B820075EE4A /* MigrationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationResult.swift; sourceTree = "<group>"; };
|
B56965231B356B820075EE4A /* MigrationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationResult.swift; sourceTree = "<group>"; };
|
||||||
|
B56E4EC923CD9B4800E1708C /* Field.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.swift; sourceTree = "<group>"; };
|
||||||
|
B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Stored.swift; sourceTree = "<group>"; };
|
||||||
|
B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldStorableType.swift; sourceTree = "<group>"; };
|
||||||
|
B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldOptionalType.swift; sourceTree = "<group>"; };
|
||||||
|
B56E4EE323CEDF0900E1708C /* Field.Computed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Computed.swift; sourceTree = "<group>"; };
|
||||||
|
B56E4EE823CF0C4500E1708C /* Field.PlistCoded.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.PlistCoded.swift; sourceTree = "<group>"; };
|
||||||
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>"; };
|
||||||
@@ -1386,6 +1419,7 @@
|
|||||||
children = (
|
children = (
|
||||||
B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */,
|
B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */,
|
||||||
B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */,
|
B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */,
|
||||||
|
B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */,
|
||||||
B50564D22350CC3100482308 /* PropertyProtocol.swift */,
|
B50564D22350CC3100482308 /* PropertyProtocol.swift */,
|
||||||
B53D9E5823513712000F48FB /* DiffableDataSourceSnapshotProtocol.swift */,
|
B53D9E5823513712000F48FB /* DiffableDataSourceSnapshotProtocol.swift */,
|
||||||
B50E175623517DE4004F033C /* Differentiable.swift */,
|
B50E175623517DE4004F033C /* Differentiable.swift */,
|
||||||
@@ -1513,13 +1547,34 @@
|
|||||||
name = Migrating;
|
name = Migrating;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B56E4EC823CD9B2E00E1708C /* Field Properties */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B56E4EC923CD9B4800E1708C /* Field.swift */,
|
||||||
|
B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */,
|
||||||
|
B56E4EE323CEDF0900E1708C /* Field.Computed.swift */,
|
||||||
|
B56E4EE823CF0C4500E1708C /* Field.PlistCoded.swift */,
|
||||||
|
B56E4EDD23CEBB0400E1708C /* Supported Values */,
|
||||||
|
);
|
||||||
|
name = "Field Properties";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
B56E4EDD23CEBB0400E1708C /* Supported Values */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */,
|
||||||
|
B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */,
|
||||||
|
);
|
||||||
|
name = "Supported Values";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
B57358D71E5A7F9B0094B50A /* Dynamic Models */ = {
|
B57358D71E5A7F9B0094B50A /* Dynamic Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
B5D339D71E9489AB00C880DE /* CoreStoreObject.swift */,
|
B5D339D71E9489AB00C880DE /* CoreStoreObject.swift */,
|
||||||
B53304A9230BA4F7007C2BD8 /* DynamicObjectMeta.swift */,
|
|
||||||
B53CA9A11EF1EF1600E0F440 /* PartialObject.swift */,
|
B53CA9A11EF1EF1600E0F440 /* PartialObject.swift */,
|
||||||
B5831B6E1F3355C300A9F647 /* Properties */,
|
B56E4EC823CD9B2E00E1708C /* Field Properties */,
|
||||||
|
B5831B6E1F3355C300A9F647 /* Legacy Properties */,
|
||||||
B52F74391E9B8724005F3DAC /* Dynamic Schema */,
|
B52F74391E9B8724005F3DAC /* Dynamic Schema */,
|
||||||
B5D339DC1E9489C700C880DE /* DynamicObject.swift */,
|
B5D339DC1E9489C700C880DE /* DynamicObject.swift */,
|
||||||
B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */,
|
B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */,
|
||||||
@@ -1529,7 +1584,7 @@
|
|||||||
name = "Dynamic Models";
|
name = "Dynamic Models";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
B5831B6E1F3355C300A9F647 /* Properties */ = {
|
B5831B6E1F3355C300A9F647 /* Legacy Properties */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
B5D33A001E96012400C880DE /* Relationship.swift */,
|
B5D33A001E96012400C880DE /* Relationship.swift */,
|
||||||
@@ -1543,7 +1598,7 @@
|
|||||||
B509D7D223C84E1900F42824 /* Transformable.Required.swift */,
|
B509D7D223C84E1900F42824 /* Transformable.Required.swift */,
|
||||||
B509D7D723C84E2600F42824 /* Transformable.Optional.swift */,
|
B509D7D723C84E2600F42824 /* Transformable.Optional.swift */,
|
||||||
);
|
);
|
||||||
name = Properties;
|
name = "Legacy Properties";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
B5A1DAC61F111BBE003CF369 /* KeyPath Utilities */ = {
|
B5A1DAC61F111BBE003CF369 /* KeyPath Utilities */ = {
|
||||||
@@ -2145,6 +2200,7 @@
|
|||||||
files = (
|
files = (
|
||||||
B5BF7FB7234C97CE0070E741 /* DiffableDataSource.TableViewAdapter-UIKit.swift in Sources */,
|
B5BF7FB7234C97CE0070E741 /* DiffableDataSource.TableViewAdapter-UIKit.swift in Sources */,
|
||||||
B5DE5230230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
B5DE5230230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
||||||
|
B56E4ED423CDB54A00E1708C /* FieldProtocol.swift in Sources */,
|
||||||
B509D7C423C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
B509D7C423C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
||||||
B5E84F221AFF84860064E85B /* ObjectMonitor.swift in Sources */,
|
B5E84F221AFF84860064E85B /* ObjectMonitor.swift in Sources */,
|
||||||
B5ECDBF91CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
|
B5ECDBF91CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
|
||||||
@@ -2194,6 +2250,7 @@
|
|||||||
B5E1B5A81CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
B5E1B5A81CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||||
B50132302346B76E00FC238B /* Internals.FetchedDiffableDataSourceSnapshotDelegate.swift in Sources */,
|
B50132302346B76E00FC238B /* Internals.FetchedDiffableDataSourceSnapshotDelegate.swift in Sources */,
|
||||||
B5D339F11E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F11E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
|
B56E4EE923CF0C4500E1708C /* Field.PlistCoded.swift in Sources */,
|
||||||
B56007161B4018AB00A9A8F9 /* MigrationChain.swift in Sources */,
|
B56007161B4018AB00A9A8F9 /* MigrationChain.swift in Sources */,
|
||||||
B5E1B59D1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
B5E1B59D1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
||||||
B5ECDC231CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
B5ECDC231CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
||||||
@@ -2213,10 +2270,12 @@
|
|||||||
B50E175223517C6B004F033C /* Internals.DiffableDataUIDispatcher.Changeset.swift in Sources */,
|
B50E175223517C6B004F033C /* Internals.DiffableDataUIDispatcher.Changeset.swift in Sources */,
|
||||||
B5E84EE71AFF84610064E85B /* CoreStore+Logging.swift in Sources */,
|
B5E84EE71AFF84610064E85B /* CoreStore+Logging.swift in Sources */,
|
||||||
B546F9731C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
B546F9731C9C553300D5AC55 /* SetupResult.swift in Sources */,
|
||||||
|
B56E4EDF23CEBCF000E1708C /* FieldOptionalType.swift in Sources */,
|
||||||
B53CA9A21EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
B53CA9A21EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
||||||
B56007111B3F6BD500A9A8F9 /* Into.swift in Sources */,
|
B56007111B3F6BD500A9A8F9 /* Into.swift in Sources */,
|
||||||
B5E84F111AFF847B0064E85B /* Select.swift in Sources */,
|
B5E84F111AFF847B0064E85B /* Select.swift in Sources */,
|
||||||
B51260931E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
B51260931E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
||||||
|
B56E4ECA23CD9B4800E1708C /* Field.swift in Sources */,
|
||||||
B5DAFB482203D9F8003FCCD0 /* Where.Expression.swift in Sources */,
|
B5DAFB482203D9F8003FCCD0 /* Where.Expression.swift in Sources */,
|
||||||
B509D7D823C84E2600F42824 /* Transformable.Optional.swift in Sources */,
|
B509D7D823C84E2600F42824 /* Transformable.Optional.swift in Sources */,
|
||||||
B5FE4DA21C8481E100FA6A91 /* StorageInterface.swift in Sources */,
|
B5FE4DA21C8481E100FA6A91 /* StorageInterface.swift in Sources */,
|
||||||
@@ -2254,7 +2313,6 @@
|
|||||||
B5E1B5A21CAA4365007FD580 /* CSCoreStore+Observing.swift in Sources */,
|
B5E1B5A21CAA4365007FD580 /* CSCoreStore+Observing.swift in Sources */,
|
||||||
B5E84EDF1AFF84500064E85B /* DataStack.swift in Sources */,
|
B5E84EDF1AFF84500064E85B /* DataStack.swift in Sources */,
|
||||||
B50E175723517DE4004F033C /* Differentiable.swift in Sources */,
|
B50E175723517DE4004F033C /* Differentiable.swift in Sources */,
|
||||||
B53304AA230BA4F7007C2BD8 /* DynamicObjectMeta.swift in Sources */,
|
|
||||||
B59AFF411C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
B59AFF411C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||||
B5E84F231AFF84860064E85B /* ListMonitor.swift in Sources */,
|
B5E84F231AFF84860064E85B /* ListMonitor.swift in Sources */,
|
||||||
B5BF7FC6234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
B5BF7FC6234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
||||||
@@ -2271,9 +2329,11 @@
|
|||||||
B5FAD6A91B50A4B400714891 /* Progress+Convenience.swift in Sources */,
|
B5FAD6A91B50A4B400714891 /* Progress+Convenience.swift in Sources */,
|
||||||
B5E84EFC1AFF846E0064E85B /* SynchronousDataTransaction.swift in Sources */,
|
B5E84EFC1AFF846E0064E85B /* SynchronousDataTransaction.swift in Sources */,
|
||||||
B5215CA91FA4810300139E3A /* QueryChainBuilder.swift in Sources */,
|
B5215CA91FA4810300139E3A /* QueryChainBuilder.swift in Sources */,
|
||||||
|
B56E4EE423CEDF0900E1708C /* Field.Computed.swift in Sources */,
|
||||||
B50E174D23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */,
|
B50E174D23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */,
|
||||||
B5E222231CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
|
B5E222231CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
|
||||||
B5E84F281AFF84920064E85B /* NSManagedObject+Convenience.swift in Sources */,
|
B5E84F281AFF84920064E85B /* NSManagedObject+Convenience.swift in Sources */,
|
||||||
|
B56E4ECF23CD9E4200E1708C /* Field.Stored.swift in Sources */,
|
||||||
B52F744A1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
B52F744A1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||||
B5AEFAB51C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
B5AEFAB51C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
||||||
B5E2222A1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
B5E2222A1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
||||||
@@ -2314,6 +2374,7 @@
|
|||||||
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
||||||
B5E8A72021C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
|
B5E8A72021C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
|
||||||
B53D9E5923513712000F48FB /* DiffableDataSourceSnapshotProtocol.swift in Sources */,
|
B53D9E5923513712000F48FB /* DiffableDataSourceSnapshotProtocol.swift in Sources */,
|
||||||
|
B56E4ED923CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
B5474D152227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
B5474D152227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
||||||
B56923FF1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
B56923FF1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
||||||
B5215CAE1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
B5215CAE1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
||||||
@@ -2429,6 +2490,7 @@
|
|||||||
B5ECDC251CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
B5ECDC251CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
||||||
B549F6741E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
B549F6741E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
||||||
B509C7F51E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
B509C7F51E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
||||||
|
B56E4EEA23CF0C4500E1708C /* Field.PlistCoded.swift in Sources */,
|
||||||
82BA18B31C4BBD3900A0916E /* ImportableUniqueObject.swift in Sources */,
|
82BA18B31C4BBD3900A0916E /* ImportableUniqueObject.swift in Sources */,
|
||||||
B50EE14323473C96009B8C47 /* CoreStoreObject+DataSources.swift in Sources */,
|
B50EE14323473C96009B8C47 /* CoreStoreObject+DataSources.swift in Sources */,
|
||||||
B55BB4DA23503B9600C33E34 /* EnvironmentValues+DataSources.swift in Sources */,
|
B55BB4DA23503B9600C33E34 /* EnvironmentValues+DataSources.swift in Sources */,
|
||||||
@@ -2448,6 +2510,7 @@
|
|||||||
B5831F432212700400D8604C /* Where.Expression.swift in Sources */,
|
B5831F432212700400D8604C /* Where.Expression.swift in Sources */,
|
||||||
B51260941E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
B51260941E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
||||||
B5FE4DA81C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
B5FE4DA81C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||||
|
B56E4EE023CEBCF000E1708C /* FieldOptionalType.swift in Sources */,
|
||||||
B5F8496D234898240029D57B /* ListSnapshot.swift in Sources */,
|
B5F8496D234898240029D57B /* ListSnapshot.swift in Sources */,
|
||||||
B53FBA001CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
B53FBA001CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||||
B5DBE2D31C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
B5DBE2D31C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
||||||
@@ -2475,6 +2538,7 @@
|
|||||||
B5D8CA772346EAEE0055D7D1 /* DataStack+DataSources.swift in Sources */,
|
B5D8CA772346EAEE0055D7D1 /* DataStack+DataSources.swift in Sources */,
|
||||||
82BA18D01C4BBD7100A0916E /* Internals.MigrationManager.swift in Sources */,
|
82BA18D01C4BBD7100A0916E /* Internals.MigrationManager.swift in Sources */,
|
||||||
B5DE5231230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
B5DE5231230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
||||||
|
B56E4ED523CDB54A00E1708C /* FieldProtocol.swift in Sources */,
|
||||||
B52F74461E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */,
|
B52F74461E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */,
|
||||||
82BA18C61C4BBD5900A0916E /* DataStack+Migration.swift in Sources */,
|
82BA18C61C4BBD5900A0916E /* DataStack+Migration.swift in Sources */,
|
||||||
B59851491C90289D00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
B59851491C90289D00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||||
@@ -2505,6 +2569,7 @@
|
|||||||
B514EF0F23A8DB180093DBA4 /* DiffableDataSource.Target.swift in Sources */,
|
B514EF0F23A8DB180093DBA4 /* DiffableDataSource.Target.swift in Sources */,
|
||||||
B52F744B1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
B52F744B1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||||
B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
||||||
|
B56E4EE523CEDF0900E1708C /* Field.Computed.swift in Sources */,
|
||||||
B5E2222C1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
B5E2222C1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
||||||
82BA18A71C4BBD2900A0916E /* CoreStore+Logging.swift in Sources */,
|
82BA18A71C4BBD2900A0916E /* CoreStore+Logging.swift in Sources */,
|
||||||
B50E174E23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */,
|
B50E174E23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */,
|
||||||
@@ -2549,6 +2614,7 @@
|
|||||||
B5474D162227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
B5474D162227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
||||||
B501322B2346A9AE00FC238B /* ListPublisher.swift in Sources */,
|
B501322B2346A9AE00FC238B /* ListPublisher.swift in Sources */,
|
||||||
B56924001EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
B56924001EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
||||||
|
B56E4EDA23CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
B5215CAF1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
B5215CAF1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
||||||
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */,
|
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */,
|
||||||
B56923ED1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
|
B56923ED1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
|
||||||
@@ -2564,8 +2630,10 @@
|
|||||||
B5BF7FC7234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
B5BF7FC7234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
||||||
82BA18CC1C4BBD6400A0916E /* Progress+Convenience.swift in Sources */,
|
82BA18CC1C4BBD6400A0916E /* Progress+Convenience.swift in Sources */,
|
||||||
B5BF7FB8234C97CE0070E741 /* DiffableDataSource.TableViewAdapter-UIKit.swift in Sources */,
|
B5BF7FB8234C97CE0070E741 /* DiffableDataSource.TableViewAdapter-UIKit.swift in Sources */,
|
||||||
|
B56E4ED023CD9E4200E1708C /* Field.Stored.swift in Sources */,
|
||||||
82BA18C01C4BBD5300A0916E /* DataStack+Observing.swift in Sources */,
|
82BA18C01C4BBD5300A0916E /* DataStack+Observing.swift in Sources */,
|
||||||
82BA18A61C4BBD2900A0916E /* DefaultLogger.swift in Sources */,
|
82BA18A61C4BBD2900A0916E /* DefaultLogger.swift in Sources */,
|
||||||
|
B56E4ECB23CD9B4800E1708C /* Field.swift in Sources */,
|
||||||
B509D7BE23C8480A00F42824 /* Value.Optional.swift in Sources */,
|
B509D7BE23C8480A00F42824 /* Value.Optional.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -2662,6 +2730,7 @@
|
|||||||
B559CD471CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
|
B559CD471CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
|
||||||
B50E17642351FA66004F033C /* Internals.Closure.swift in Sources */,
|
B50E17642351FA66004F033C /* Internals.Closure.swift in Sources */,
|
||||||
B5ECDBF01CA6BF2000C7F112 /* CSFrom.swift in Sources */,
|
B5ECDBF01CA6BF2000C7F112 /* CSFrom.swift in Sources */,
|
||||||
|
B56E4EEC23CF0C4500E1708C /* Field.PlistCoded.swift in Sources */,
|
||||||
B549F6761E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
B549F6761E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
||||||
B509C7F71E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
B509C7F71E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
||||||
B5220E1F1D130810009BC71E /* CSListObserver.swift in Sources */,
|
B5220E1F1D130810009BC71E /* CSListObserver.swift in Sources */,
|
||||||
@@ -2681,6 +2750,7 @@
|
|||||||
B52DD1BD1BE1F94300949AFE /* NSManagedObject+Convenience.swift in Sources */,
|
B52DD1BD1BE1F94300949AFE /* NSManagedObject+Convenience.swift in Sources */,
|
||||||
B5831F4222126FED00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
B5831F4222126FED00D8604C /* KeyPathGenericBindings.swift in Sources */,
|
||||||
B53CA9A51EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
B53CA9A51EF1EF1600E0F440 /* PartialObject.swift in Sources */,
|
||||||
|
B56E4EE223CEBCF000E1708C /* FieldOptionalType.swift in Sources */,
|
||||||
B52DD1AD1BE1F93900949AFE /* Where.swift in Sources */,
|
B52DD1AD1BE1F93900949AFE /* Where.swift in Sources */,
|
||||||
B53FBA1C1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */,
|
B53FBA1C1CAB63E200F0D40A /* NSManagedObject+ObjectiveC.swift in Sources */,
|
||||||
B5F8496F234898240029D57B /* ListSnapshot.swift in Sources */,
|
B5F8496F234898240029D57B /* ListSnapshot.swift in Sources */,
|
||||||
@@ -2708,6 +2778,7 @@
|
|||||||
B52DD1B81BE1F94000949AFE /* DataStack+Migration.swift in Sources */,
|
B52DD1B81BE1F94000949AFE /* DataStack+Migration.swift in Sources */,
|
||||||
B5ECDC091CA8138100C7F112 /* CSOrderBy.swift in Sources */,
|
B5ECDC091CA8138100C7F112 /* CSOrderBy.swift in Sources */,
|
||||||
B5D8CA792346EAEF0055D7D1 /* DataStack+DataSources.swift in Sources */,
|
B5D8CA792346EAEF0055D7D1 /* DataStack+DataSources.swift in Sources */,
|
||||||
|
B56E4ED723CDB54A00E1708C /* FieldProtocol.swift in Sources */,
|
||||||
B56923C71EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
|
B56923C71EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
|
||||||
B5DE5233230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
B5DE5233230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
||||||
B52DD1A51BE1F92F00949AFE /* ImportableUniqueObject.swift in Sources */,
|
B52DD1A51BE1F92F00949AFE /* ImportableUniqueObject.swift in Sources */,
|
||||||
@@ -2738,6 +2809,7 @@
|
|||||||
B514EF1123A8DB190093DBA4 /* DiffableDataSource.Target.swift in Sources */,
|
B514EF1123A8DB190093DBA4 /* DiffableDataSource.Target.swift in Sources */,
|
||||||
B50E175A23517DE4004F033C /* Differentiable.swift in Sources */,
|
B50E175A23517DE4004F033C /* Differentiable.swift in Sources */,
|
||||||
B52F744D1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
B52F744D1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||||
|
B56E4EE723CEDF0900E1708C /* Field.Computed.swift in Sources */,
|
||||||
B52DD19A1BE1F92800949AFE /* CoreStore+Logging.swift in Sources */,
|
B52DD19A1BE1F92800949AFE /* CoreStore+Logging.swift in Sources */,
|
||||||
B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */,
|
B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */,
|
||||||
B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
|
||||||
@@ -2782,6 +2854,7 @@
|
|||||||
B50E175F2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
B50E175F2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
||||||
B5474D182227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
B5474D182227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
||||||
B501322E2346A9B100FC238B /* ListPublisher.swift in Sources */,
|
B501322E2346A9B100FC238B /* ListPublisher.swift in Sources */,
|
||||||
|
B56E4EDC23CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
||||||
B5215CB11FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
B5215CB11FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
||||||
B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */,
|
B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */,
|
||||||
@@ -2797,8 +2870,10 @@
|
|||||||
B5D339EA1E9493A500C880DE /* Entity.swift in Sources */,
|
B5D339EA1E9493A500C880DE /* Entity.swift in Sources */,
|
||||||
B5BF7FC9234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
B5BF7FC9234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
||||||
B52DD1AA1BE1F93500949AFE /* TypeErasedClauses.swift in Sources */,
|
B52DD1AA1BE1F93500949AFE /* TypeErasedClauses.swift in Sources */,
|
||||||
|
B56E4ED223CD9E4200E1708C /* Field.Stored.swift in Sources */,
|
||||||
B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||||
B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
|
||||||
|
B56E4ECD23CD9B4800E1708C /* Field.swift in Sources */,
|
||||||
B509D7C223C8480B00F42824 /* Value.Optional.swift in Sources */,
|
B509D7C223C8480B00F42824 /* Value.Optional.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -2895,6 +2970,7 @@
|
|||||||
B563217F1BD65216006C9394 /* CoreStore.swift in Sources */,
|
B563217F1BD65216006C9394 /* CoreStore.swift in Sources */,
|
||||||
B549F6751E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
B549F6751E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
||||||
B509C7F61E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
B509C7F61E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
||||||
|
B56E4EEB23CF0C4500E1708C /* Field.PlistCoded.swift in Sources */,
|
||||||
B5E1B5961CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
B5E1B5961CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
||||||
B50EE14423473C97009B8C47 /* CoreStoreObject+DataSources.swift in Sources */,
|
B50EE14423473C97009B8C47 /* CoreStoreObject+DataSources.swift in Sources */,
|
||||||
B55BB4D923503B9600C33E34 /* EnvironmentValues+DataSources.swift in Sources */,
|
B55BB4D923503B9600C33E34 /* EnvironmentValues+DataSources.swift in Sources */,
|
||||||
@@ -2914,6 +2990,7 @@
|
|||||||
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */,
|
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */,
|
||||||
B5FE4DA91C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
B5FE4DA91C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||||
B5831F442212700500D8604C /* Where.Expression.swift in Sources */,
|
B5831F442212700500D8604C /* Where.Expression.swift in Sources */,
|
||||||
|
B56E4EE123CEBCF000E1708C /* FieldOptionalType.swift in Sources */,
|
||||||
B5F8496E234898240029D57B /* ListSnapshot.swift in Sources */,
|
B5F8496E234898240029D57B /* ListSnapshot.swift in Sources */,
|
||||||
B51260951E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
B51260951E9B28F100402229 /* Internals.EntityIdentifier.swift in Sources */,
|
||||||
B53FBA011CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
B53FBA011CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
|
||||||
@@ -2941,6 +3018,7 @@
|
|||||||
B5D8CA782346EAEF0055D7D1 /* DataStack+DataSources.swift in Sources */,
|
B5D8CA782346EAEF0055D7D1 /* DataStack+DataSources.swift in Sources */,
|
||||||
B56923C61EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
|
B56923C61EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
|
||||||
B56321A71BD65216006C9394 /* MigrationResult.swift in Sources */,
|
B56321A71BD65216006C9394 /* MigrationResult.swift in Sources */,
|
||||||
|
B56E4ED623CDB54A00E1708C /* FieldProtocol.swift in Sources */,
|
||||||
B5DE5232230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
B5DE5232230BDA1300A22534 /* CoreStoreDefaults.swift in Sources */,
|
||||||
B598514A1C90289E00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
B598514A1C90289E00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||||
B52F74471E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */,
|
B52F74471E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */,
|
||||||
@@ -2971,6 +3049,7 @@
|
|||||||
B514EF1023A8DB190093DBA4 /* DiffableDataSource.Target.swift in Sources */,
|
B514EF1023A8DB190093DBA4 /* DiffableDataSource.Target.swift in Sources */,
|
||||||
B563218A1BD65216006C9394 /* SynchronousDataTransaction.swift in Sources */,
|
B563218A1BD65216006C9394 /* SynchronousDataTransaction.swift in Sources */,
|
||||||
B52F744C1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
B52F744C1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
|
||||||
|
B56E4EE623CEDF0900E1708C /* Field.Computed.swift in Sources */,
|
||||||
B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
|
||||||
B5E2222D1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
B5E2222D1CA51B6E00BA2E95 /* CSUnsafeDataTransaction.swift in Sources */,
|
||||||
B50E174F23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */,
|
B50E174F23517C03004F033C /* Internals.DiffableDataUIDispatcher.StagedChangeset.swift in Sources */,
|
||||||
@@ -3015,6 +3094,7 @@
|
|||||||
B5474D172227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
B5474D172227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
||||||
B501322D2346A9B000FC238B /* ListPublisher.swift in Sources */,
|
B501322D2346A9B000FC238B /* ListPublisher.swift in Sources */,
|
||||||
B56924011EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
B56924011EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
|
||||||
|
B56E4EDB23CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
B5215CB01FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
B5215CB01FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
|
||||||
B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */,
|
B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */,
|
||||||
B56923EE1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
|
B56923EE1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
|
||||||
@@ -3030,8 +3110,10 @@
|
|||||||
B5BF7FC8234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
B5BF7FC8234D7E460070E741 /* ObjectSnapshot.swift in Sources */,
|
||||||
B56321A41BD65216006C9394 /* CoreStore+Migration.swift in Sources */,
|
B56321A41BD65216006C9394 /* CoreStore+Migration.swift in Sources */,
|
||||||
B5BF7FB9234C97CE0070E741 /* DiffableDataSource.TableViewAdapter-UIKit.swift in Sources */,
|
B5BF7FB9234C97CE0070E741 /* DiffableDataSource.TableViewAdapter-UIKit.swift in Sources */,
|
||||||
|
B56E4ED123CD9E4200E1708C /* Field.Stored.swift in Sources */,
|
||||||
B56321A01BD65216006C9394 /* ObjectObserver.swift in Sources */,
|
B56321A01BD65216006C9394 /* ObjectObserver.swift in Sources */,
|
||||||
B56321951BD65216006C9394 /* TypeErasedClauses.swift in Sources */,
|
B56321951BD65216006C9394 /* TypeErasedClauses.swift in Sources */,
|
||||||
|
B56E4ECC23CD9B4800E1708C /* Field.swift in Sources */,
|
||||||
B509D7C023C8480B00F42824 /* Value.Optional.swift in Sources */,
|
B509D7C023C8480B00F42824 /* Value.Optional.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|||||||
@@ -38,14 +38,18 @@ import CoreStore
|
|||||||
|
|
||||||
class Animal: CoreStoreObject {
|
class Animal: CoreStoreObject {
|
||||||
|
|
||||||
let species = Value.Required<String>("species", initial: "Swift")
|
@Field.Stored("species")
|
||||||
|
var species: String = "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")
|
||||||
}
|
}
|
||||||
|
|
||||||
class Dog: Animal {
|
class Dog: Animal {
|
||||||
|
|
||||||
let nickname = Value.Optional<String>("nickname")
|
@Field.Stored("nickname")
|
||||||
|
var nickname: String?
|
||||||
|
|
||||||
let age = Value.Required<Int>("age", initial: 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 })
|
||||||
@@ -53,24 +57,18 @@ class Dog: Animal {
|
|||||||
|
|
||||||
class Person: CoreStoreObject {
|
class Person: CoreStoreObject {
|
||||||
|
|
||||||
let title = Value.Required<String>(
|
@Field.Stored("title", customSetter: Person.setTitle(_:_:))
|
||||||
"title",
|
var title: String = "Mr."
|
||||||
initial: "Mr.",
|
|
||||||
customSetter: Person.setTitle
|
|
||||||
)
|
|
||||||
|
|
||||||
let name = Value.Required<String>(
|
@Field.Stored("name", customSetter: Person.setName(_:_:))
|
||||||
"name",
|
var name: String = ""
|
||||||
initial: "",
|
|
||||||
customSetter: Person.setName
|
|
||||||
)
|
|
||||||
|
|
||||||
let displayName = Value.Optional<String>(
|
@Field.Computed(
|
||||||
"displayName",
|
"displayName",
|
||||||
isTransient: true,
|
|
||||||
customGetter: Person.getDisplayName(_:),
|
customGetter: Person.getDisplayName(_:),
|
||||||
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
|
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
|
||||||
)
|
)
|
||||||
|
var displayName: String?
|
||||||
|
|
||||||
let spouse = Relationship.ToOne<Person>("spouse")
|
let spouse = Relationship.ToOne<Person>("spouse")
|
||||||
|
|
||||||
@@ -81,34 +79,34 @@ class Person: CoreStoreObject {
|
|||||||
|
|
||||||
private static func setTitle(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
private static func setTitle(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
||||||
|
|
||||||
partialObject.setPrimitiveValue(newValue, for: { $0.title })
|
partialObject.setPrimitiveValue(newValue, for: \.$title)
|
||||||
partialObject.setPrimitiveValue(nil, for: { $0.displayName })
|
partialObject.setPrimitiveValue(nil, for: { $0.$displayName })
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func setName(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
private static func setName(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
||||||
|
|
||||||
partialObject.setPrimitiveValue(newValue, for: { $0.name })
|
partialObject.setPrimitiveValue(newValue, for: \.$name)
|
||||||
partialObject.setPrimitiveValue(nil, for: { $0.displayName })
|
partialObject.setPrimitiveValue(nil, for: \.$displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getDisplayName(_ partialObject: PartialObject<Person>) -> String? {
|
static func getDisplayName(_ partialObject: PartialObject<Person>) -> String? {
|
||||||
|
|
||||||
if let displayName = partialObject.primitiveValue(for: { $0.displayName }) {
|
if let displayName = partialObject.primitiveValue(for: \.$displayName) {
|
||||||
|
|
||||||
return displayName
|
return displayName
|
||||||
}
|
}
|
||||||
let title = partialObject.value(for: { $0.title })
|
let title = partialObject.value(for: \.$title)
|
||||||
let name = partialObject.value(for: { $0.name })
|
let name = partialObject.value(for: \.$name)
|
||||||
let displayName = "\(title) \(name)"
|
let displayName = "\(title) \(name)"
|
||||||
partialObject.setPrimitiveValue(displayName, for: { $0.displayName })
|
partialObject.setPrimitiveValue(displayName, for: \.$displayName)
|
||||||
return displayName
|
return displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
static func keyPathsAffectingDisplayName() -> Set<String> {
|
static func keyPathsAffectingDisplayName() -> Set<String> {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
String(keyPath: \Person.title),
|
String(keyPath: \Person.$title),
|
||||||
String(keyPath: \Person.name)
|
String(keyPath: \Person.$name)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,13 +136,13 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
)
|
)
|
||||||
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
|
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
|
||||||
|
|
||||||
let k1 = String(keyPath: \Animal.species)
|
let k1 = String(keyPath: \Animal.$species)
|
||||||
XCTAssertEqual(k1, "species")
|
XCTAssertEqual(k1, "species")
|
||||||
|
|
||||||
let k2 = String(keyPath: \Dog.species)
|
let k2 = String(keyPath: \Dog.$species)
|
||||||
XCTAssertEqual(k2, "species")
|
XCTAssertEqual(k2, "species")
|
||||||
|
|
||||||
let k3 = String(keyPath: \Dog.nickname)
|
let k3 = String(keyPath: \Dog.$nickname)
|
||||||
XCTAssertEqual(k3, "nickname")
|
XCTAssertEqual(k3, "nickname")
|
||||||
|
|
||||||
let updateDone = self.expectation(description: "update-done")
|
let updateDone = self.expectation(description: "update-done")
|
||||||
@@ -156,11 +154,11 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
asynchronous: { (transaction) in
|
asynchronous: { (transaction) in
|
||||||
|
|
||||||
let animal = transaction.create(Into<Animal>())
|
let animal = transaction.create(Into<Animal>())
|
||||||
XCTAssertEqual(animal.species.value, "Swift")
|
XCTAssertEqual(animal.species, "Swift")
|
||||||
XCTAssertTrue(type(of: animal.species.value) == String.self)
|
XCTAssertTrue(type(of: animal.species) == String.self)
|
||||||
|
|
||||||
animal.species .= "Sparrow"
|
animal.species = "Sparrow"
|
||||||
XCTAssertEqual(animal.species.value, "Sparrow")
|
XCTAssertEqual(animal.species, "Sparrow")
|
||||||
|
|
||||||
animal.color .= .yellow
|
animal.color .= .yellow
|
||||||
XCTAssertEqual(animal.color.value, Color.yellow)
|
XCTAssertEqual(animal.color.value, Color.yellow)
|
||||||
@@ -169,8 +167,8 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
switch property.keyPath {
|
switch property.keyPath {
|
||||||
|
|
||||||
case String(keyPath: \Animal.species):
|
case String(keyPath: \Animal.$species):
|
||||||
XCTAssertTrue(property is ValueContainer<Animal>.Required<String>)
|
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
|
||||||
|
|
||||||
case String(keyPath: \Animal.master):
|
case String(keyPath: \Animal.master):
|
||||||
XCTAssertTrue(property is RelationshipContainer<Animal>.ToOne<Person>)
|
XCTAssertTrue(property is RelationshipContainer<Animal>.ToOne<Person>)
|
||||||
@@ -184,16 +182,16 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dog = transaction.create(Into<Dog>())
|
let dog = transaction.create(Into<Dog>())
|
||||||
XCTAssertEqual(dog.species.value, "Swift")
|
XCTAssertEqual(dog.species, "Swift")
|
||||||
XCTAssertEqual(dog.nickname.value, nil)
|
XCTAssertEqual(dog.nickname, nil)
|
||||||
XCTAssertEqual(dog.age.value, 1)
|
XCTAssertEqual(dog.age.value, 1)
|
||||||
|
|
||||||
for property in Dog.metaProperties(includeSuperclasses: true) {
|
for property in Dog.metaProperties(includeSuperclasses: true) {
|
||||||
|
|
||||||
switch property.keyPath {
|
switch property.keyPath {
|
||||||
|
|
||||||
case String(keyPath: \Dog.species):
|
case String(keyPath: \Dog.$species):
|
||||||
XCTAssertTrue(property is ValueContainer<Animal>.Required<String>)
|
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
|
||||||
|
|
||||||
case String(keyPath: \Dog.master):
|
case String(keyPath: \Dog.master):
|
||||||
XCTAssertTrue(property is RelationshipContainer<Animal>.ToOne<Person>)
|
XCTAssertTrue(property is RelationshipContainer<Animal>.ToOne<Person>)
|
||||||
@@ -201,8 +199,8 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
case String(keyPath: \Dog.color):
|
case String(keyPath: \Dog.color):
|
||||||
XCTAssertTrue(property is TransformableContainer<Animal>.Optional<Color>)
|
XCTAssertTrue(property is TransformableContainer<Animal>.Optional<Color>)
|
||||||
|
|
||||||
case String(keyPath: \Dog.nickname):
|
case String(keyPath: \Dog.$nickname):
|
||||||
XCTAssertTrue(property is ValueContainer<Dog>.Optional<String>)
|
XCTAssertTrue(property is FieldContainer<Dog>.Stored<String?>)
|
||||||
|
|
||||||
case String(keyPath: \Dog.age):
|
case String(keyPath: \Dog.age):
|
||||||
XCTAssertTrue(property is ValueContainer<Dog>.Required<Int>)
|
XCTAssertTrue(property is ValueContainer<Dog>.Required<Int>)
|
||||||
@@ -231,17 +229,17 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
//
|
//
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
let didSetObserver = dog.species.observe(options: [.new, .old]) { (object, change) in
|
let didSetObserver = dog.observe(\.$species, options: [.new, .old]) { (object, change) in
|
||||||
|
|
||||||
XCTAssertEqual(object, dog)
|
XCTAssertEqual(object, dog)
|
||||||
XCTAssertEqual(change.kind, .setting)
|
XCTAssertEqual(change.kind, .setting)
|
||||||
XCTAssertEqual(change.newValue, "Dog")
|
XCTAssertEqual(change.newValue, "Dog")
|
||||||
XCTAssertEqual(change.oldValue, "Swift")
|
XCTAssertEqual(change.oldValue, "Swift")
|
||||||
XCTAssertFalse(change.isPrior)
|
XCTAssertFalse(change.isPrior)
|
||||||
XCTAssertEqual(object.species.value, "Dog")
|
XCTAssertEqual(object.species, "Dog")
|
||||||
didSetObserverDone.fulfill()
|
didSetObserverDone.fulfill()
|
||||||
}
|
}
|
||||||
let willSetObserver = dog.species.observe(options: [.new, .old, .prior]) { (object, change) in
|
let willSetObserver = dog.observe(\.$species, options: [.new, .old, .prior]) { (object, change) in
|
||||||
|
|
||||||
XCTAssertEqual(object, dog)
|
XCTAssertEqual(object, dog)
|
||||||
XCTAssertEqual(change.kind, .setting)
|
XCTAssertEqual(change.kind, .setting)
|
||||||
@@ -250,25 +248,25 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
if change.isPrior {
|
if change.isPrior {
|
||||||
|
|
||||||
XCTAssertNil(change.newValue)
|
XCTAssertNil(change.newValue)
|
||||||
XCTAssertEqual(object.species.value, "Swift")
|
XCTAssertEqual(object.species, "Swift")
|
||||||
willSetPriorObserverDone.fulfill()
|
willSetPriorObserverDone.fulfill()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
XCTAssertEqual(change.newValue, "Dog")
|
XCTAssertEqual(change.newValue, "Dog")
|
||||||
XCTAssertEqual(object.species.value, "Dog")
|
XCTAssertEqual(object.species, "Dog")
|
||||||
willSetNotPriorObserverDone.fulfill()
|
willSetNotPriorObserverDone.fulfill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dog.species .= "Dog"
|
dog.species = "Dog"
|
||||||
XCTAssertEqual(dog.species.value, "Dog")
|
XCTAssertEqual(dog.species, "Dog")
|
||||||
|
|
||||||
didSetObserver.invalidate()
|
didSetObserver.invalidate()
|
||||||
willSetObserver.invalidate()
|
willSetObserver.invalidate()
|
||||||
|
|
||||||
dog.nickname .= "Spot"
|
dog.nickname = "Spot"
|
||||||
XCTAssertEqual(dog.nickname.value, "Spot")
|
XCTAssertEqual(dog.nickname, "Spot")
|
||||||
|
|
||||||
let person = transaction.create(Into<Person>())
|
let person = transaction.create(Into<Person>())
|
||||||
XCTAssertTrue(person.pets.value.isEmpty)
|
XCTAssertTrue(person.pets.value.isEmpty)
|
||||||
@@ -280,7 +278,7 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
["title", "name"]
|
["title", "name"]
|
||||||
)
|
)
|
||||||
|
|
||||||
person.name .= "Joe"
|
person.name = "Joe"
|
||||||
|
|
||||||
XCTAssertEqual(person.rawObject!.value(forKey: "name") as! String?, "Joe")
|
XCTAssertEqual(person.rawObject!.value(forKey: "name") as! String?, "Joe")
|
||||||
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "Mr. Joe")
|
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "Mr. Joe")
|
||||||
@@ -288,35 +286,35 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
person.rawObject!.setValue("AAAA", forKey: "displayName")
|
person.rawObject!.setValue("AAAA", forKey: "displayName")
|
||||||
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "AAAA")
|
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "AAAA")
|
||||||
|
|
||||||
person.name .= "John"
|
person.name = "John"
|
||||||
XCTAssertEqual(person.name.value, "John")
|
XCTAssertEqual(person.name, "John")
|
||||||
XCTAssertEqual(person.displayName.value, "Mr. John") // Custom getter
|
XCTAssertEqual(person.displayName, "Mr. John") // Custom getter
|
||||||
|
|
||||||
let personSnapshot1 = person.asSnapshot(in: transaction)!
|
let personSnapshot1 = person.asSnapshot(in: transaction)!
|
||||||
XCTAssertEqual(person.name.value, personSnapshot1.name)
|
XCTAssertEqual(person.name, personSnapshot1.$name)
|
||||||
XCTAssertEqual(person.title.value, personSnapshot1.title)
|
XCTAssertEqual(person.title, personSnapshot1.$title)
|
||||||
XCTAssertEqual(person.displayName.value, personSnapshot1.displayName)
|
XCTAssertEqual(person.displayName, personSnapshot1.$displayName)
|
||||||
|
|
||||||
person.title .= "Sir"
|
person.title = "Sir"
|
||||||
XCTAssertEqual(person.displayName.value, "Sir John")
|
XCTAssertEqual(person.displayName, "Sir John")
|
||||||
|
|
||||||
XCTAssertEqual(personSnapshot1.name, "John")
|
XCTAssertEqual(personSnapshot1.$name, "John")
|
||||||
XCTAssertEqual(personSnapshot1.title, "Mr.")
|
XCTAssertEqual(personSnapshot1.$title, "Mr.")
|
||||||
XCTAssertEqual(personSnapshot1.displayName, "Mr. John")
|
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
|
||||||
|
|
||||||
let personSnapshot2 = person.asSnapshot(in: transaction)!
|
let personSnapshot2 = person.asSnapshot(in: transaction)!
|
||||||
XCTAssertEqual(person.name.value, personSnapshot2.name)
|
XCTAssertEqual(person.name, personSnapshot2.$name)
|
||||||
XCTAssertEqual(person.title.value, personSnapshot2.title)
|
XCTAssertEqual(person.title, personSnapshot2.$title)
|
||||||
XCTAssertEqual(person.displayName.value, personSnapshot2.displayName)
|
XCTAssertEqual(person.displayName, personSnapshot2.$displayName)
|
||||||
|
|
||||||
var personSnapshot3 = personSnapshot2
|
var personSnapshot3 = personSnapshot2
|
||||||
personSnapshot3.name = "James"
|
personSnapshot3.$name = "James"
|
||||||
XCTAssertEqual(personSnapshot1.name, "John")
|
XCTAssertEqual(personSnapshot1.$name, "John")
|
||||||
XCTAssertEqual(personSnapshot1.displayName, "Mr. John")
|
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
|
||||||
XCTAssertEqual(personSnapshot2.name, "John")
|
XCTAssertEqual(personSnapshot2.$name, "John")
|
||||||
XCTAssertEqual(personSnapshot2.displayName, "Sir John")
|
XCTAssertEqual(personSnapshot2.$displayName, "Sir John")
|
||||||
XCTAssertEqual(personSnapshot3.name, "James")
|
XCTAssertEqual(personSnapshot3.$name, "James")
|
||||||
XCTAssertEqual(personSnapshot3.displayName, "Sir John")
|
XCTAssertEqual(personSnapshot3.$displayName, "Sir John")
|
||||||
|
|
||||||
|
|
||||||
person.pets.value.insert(dog)
|
person.pets.value.insert(dog)
|
||||||
@@ -338,20 +336,20 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
stack.perform(
|
stack.perform(
|
||||||
asynchronous: { (transaction) in
|
asynchronous: { (transaction) in
|
||||||
|
|
||||||
let p1 = Where<Animal>({ $0.species == "Sparrow" })
|
let p1 = Where<Animal>({ $0.$species == "Sparrow" })
|
||||||
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
|
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
|
||||||
|
|
||||||
let bird = try transaction.fetchOne(From<Animal>(), p1)
|
let bird = try transaction.fetchOne(From<Animal>(), p1)
|
||||||
XCTAssertNotNil(bird)
|
XCTAssertNotNil(bird)
|
||||||
XCTAssertEqual(bird!.species.value, "Sparrow")
|
XCTAssertEqual(bird!.species, "Sparrow")
|
||||||
|
|
||||||
let p2 = Where<Dog>({ $0.nickname == "Spot" })
|
let p2 = Where<Dog>({ $0.$nickname == "Spot" })
|
||||||
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
|
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
|
||||||
|
|
||||||
let dog = try transaction.fetchOne(From<Dog>().where(\.nickname == "Spot"))
|
let dog = try transaction.fetchOne(From<Dog>().where(\.$nickname == "Spot"))
|
||||||
XCTAssertNotNil(dog)
|
XCTAssertNotNil(dog)
|
||||||
XCTAssertEqual(dog!.nickname.value, "Spot")
|
XCTAssertEqual(dog!.nickname, "Spot")
|
||||||
XCTAssertEqual(dog!.species.value, "Dog")
|
XCTAssertEqual(dog!.species, "Dog")
|
||||||
|
|
||||||
let person = try transaction.fetchOne(From<Person>())
|
let person = try transaction.fetchOne(From<Person>())
|
||||||
XCTAssertNotNil(person)
|
XCTAssertNotNil(person)
|
||||||
@@ -365,12 +363,12 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
_ = try transaction.fetchAll(
|
_ = try transaction.fetchAll(
|
||||||
From<Dog>()
|
From<Dog>()
|
||||||
.where(\Animal.species == "Dog" && \Dog.age == 10)
|
.where(\Animal.$species == "Dog" && \Dog.age == 10)
|
||||||
)
|
)
|
||||||
_ = try transaction.fetchAll(
|
_ = try transaction.fetchAll(
|
||||||
From<Dog>()
|
From<Dog>()
|
||||||
.where(\Dog.age == 10 && \Animal.species == "Dog")
|
.where(\Dog.age == 10 && \Animal.$species == "Dog")
|
||||||
.orderBy(.ascending({ $0.species }))
|
.orderBy(.ascending({ $0.$species }))
|
||||||
)
|
)
|
||||||
_ = try transaction.fetchAll(
|
_ = try transaction.fetchAll(
|
||||||
From<Dog>(),
|
From<Dog>(),
|
||||||
@@ -378,11 +376,11 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
)
|
)
|
||||||
_ = try transaction.fetchAll(
|
_ = try transaction.fetchAll(
|
||||||
From<Dog>(),
|
From<Dog>(),
|
||||||
Where<Dog>({ $0.species == "Dog" && $0.age == 10 })
|
Where<Dog>({ $0.$species == "Dog" && $0.age == 10 })
|
||||||
)
|
)
|
||||||
_ = try transaction.fetchAll(
|
_ = try transaction.fetchAll(
|
||||||
From<Dog>(),
|
From<Dog>(),
|
||||||
Where<Dog>({ $0.age == 10 && $0.species == "Dog" })
|
Where<Dog>({ $0.age == 10 && $0.$species == "Dog" })
|
||||||
)
|
)
|
||||||
_ = try transaction.fetchAll(
|
_ = try transaction.fetchAll(
|
||||||
From<Dog>(),
|
From<Dog>(),
|
||||||
@@ -409,8 +407,8 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
@objc
|
@objc
|
||||||
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
|
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
|
||||||
|
|
||||||
XCTAssertEqual(String(keyPath: \Animal.species), "species")
|
XCTAssertEqual(String(keyPath: \Animal.$species), "species")
|
||||||
XCTAssertEqual(String(keyPath: \Dog.species), "species")
|
XCTAssertEqual(String(keyPath: \Dog.$species), "species")
|
||||||
}
|
}
|
||||||
|
|
||||||
@nonobjc
|
@nonobjc
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
var events = 0
|
var events = 0
|
||||||
|
|
||||||
let willChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -67,7 +67,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 0
|
return events == 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didInsertSectionExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -87,7 +87,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 1
|
return events == 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didInsertObjectExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -119,7 +119,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 2
|
return events == 2
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -184,7 +184,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
var events = 0
|
var events = 0
|
||||||
|
|
||||||
let willChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -199,7 +199,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let didUpdateObjectExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -250,7 +250,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 1 || events == 2
|
return events == 1 || events == 2
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -329,7 +329,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
var events = 0
|
var events = 0
|
||||||
|
|
||||||
let willChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -343,7 +343,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 0
|
return events == 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didMoveObjectExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -376,7 +376,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 1
|
return events == 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -437,7 +437,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
var events = 0
|
var events = 0
|
||||||
|
|
||||||
let willChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -451,7 +451,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 0
|
return events == 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didUpdateObjectExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -480,7 +480,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 1 || events == 2
|
return events == 1 || events == 2
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didDeleteSectionExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -508,7 +508,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 3
|
return events == 3
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
var events = 0
|
var events = 0
|
||||||
|
|
||||||
let willUpdateExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
|
forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -74,7 +74,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
|||||||
return events == 0
|
return events == 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didUpdateExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -154,7 +154,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
var events = 0
|
var events = 0
|
||||||
|
|
||||||
let didDeleteExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
|
forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ final class TransactionTests: BaseTestCase {
|
|||||||
XCTAssertFalse(monitor.hasObjects())
|
XCTAssertFalse(monitor.hasObjects())
|
||||||
|
|
||||||
var events = 0
|
var events = 0
|
||||||
let willChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -414,7 +414,7 @@ final class TransactionTests: BaseTestCase {
|
|||||||
return events == 0
|
return events == 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didInsertObjectExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
@@ -444,7 +444,7 @@ final class TransactionTests: BaseTestCase {
|
|||||||
return events == 1
|
return events == 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let didChangeExpectation = self.expectation(
|
_ = self.expectation(
|
||||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||||
object: observer,
|
object: observer,
|
||||||
handler: { (note) -> Bool in
|
handler: { (note) -> Bool in
|
||||||
|
|||||||
@@ -109,8 +109,8 @@ final class WhereTests: XCTestCase {
|
|||||||
)
|
)
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"master.pets.species",
|
"master.pets.species",
|
||||||
(\Animal.master ~ \.pets ~ \.species).description,
|
(\Animal.master ~ \.pets ~ \.$species).description,
|
||||||
String(keyPath: \Animal.master ~ \.pets ~ \.species)
|
String(keyPath: \Animal.master ~ \.pets ~ \.$species)
|
||||||
)
|
)
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"master.pets.master",
|
"master.pets.master",
|
||||||
@@ -167,8 +167,8 @@ final class WhereTests: XCTestCase {
|
|||||||
)
|
)
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"ANY master.pets.species",
|
"ANY master.pets.species",
|
||||||
(\Animal.master ~ \.pets ~ \.species).any().description,
|
(\Animal.master ~ \.pets ~ \.$species).any().description,
|
||||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).any())
|
String(keyPath: (\Animal.master ~ \.pets ~ \.$species).any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,8 +196,8 @@ final class WhereTests: XCTestCase {
|
|||||||
)
|
)
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"ALL master.pets.species",
|
"ALL master.pets.species",
|
||||||
(\Animal.master ~ \.pets ~ \.species).all().description,
|
(\Animal.master ~ \.pets ~ \.$species).all().description,
|
||||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).all())
|
String(keyPath: (\Animal.master ~ \.pets ~ \.$species).all())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,8 +225,8 @@ final class WhereTests: XCTestCase {
|
|||||||
)
|
)
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"NONE master.pets.species",
|
"NONE master.pets.species",
|
||||||
(\Animal.master ~ \.pets ~ \.species).none().description,
|
(\Animal.master ~ \.pets ~ \.$species).none().description,
|
||||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).none())
|
String(keyPath: (\Animal.master ~ \.pets ~ \.$species).none())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +247,7 @@ final class WhereTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.master ~ \.name) == dummy
|
let whereClause: Where<Animal> = (\.master ~ \.$name) == dummy
|
||||||
let predicate = NSPredicate(format: "master.name == %@", dummy)
|
let predicate = NSPredicate(format: "master.name == %@", dummy)
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||||
@@ -265,7 +265,7 @@ final class WhereTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.master ~ \.spouse ~ \.name) == dummy
|
let whereClause: Where<Animal> = (\.master ~ \.spouse ~ \.$name) == dummy
|
||||||
let predicate = NSPredicate(format: "master.spouse.name == %@", dummy)
|
let predicate = NSPredicate(format: "master.spouse.name == %@", dummy)
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||||
@@ -301,7 +301,7 @@ final class WhereTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).any() == dummy
|
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.$species).any() == dummy
|
||||||
let predicate = NSPredicate(format: "ANY master.pets.species == %@", dummy)
|
let predicate = NSPredicate(format: "ANY master.pets.species == %@", dummy)
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||||
@@ -319,7 +319,7 @@ final class WhereTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).all() == dummy
|
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.$species).all() == dummy
|
||||||
let predicate = NSPredicate(format: "ALL master.pets.species == %@", dummy)
|
let predicate = NSPredicate(format: "ALL master.pets.species == %@", dummy)
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||||
@@ -337,7 +337,7 @@ final class WhereTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).none() == dummy
|
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.$species).none() == dummy
|
||||||
let predicate = NSPredicate(format: "NONE master.pets.species == %@", dummy)
|
let predicate = NSPredicate(format: "NONE master.pets.species == %@", dummy)
|
||||||
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
|
||||||
XCTAssertAllEqual(whereClause.predicate, predicate)
|
XCTAssertAllEqual(whereClause.predicate, predicate)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import CoreData
|
|||||||
|
|
||||||
// MARK: - AttributeProtocol
|
// MARK: - AttributeProtocol
|
||||||
|
|
||||||
internal protocol AttributeProtocol: PropertyProtocol {
|
internal protocol AttributeProtocol: AnyObject, PropertyProtocol {
|
||||||
|
|
||||||
typealias EntityDescriptionValues = (
|
typealias EntityDescriptionValues = (
|
||||||
attributeType: NSAttributeType,
|
attributeType: NSAttributeType,
|
||||||
|
|||||||
@@ -94,9 +94,10 @@ extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConv
|
|||||||
firstLine = ".progressiveMigrationRequired"
|
firstLine = ".progressiveMigrationRequired"
|
||||||
info.append(("localStoreURL", localStoreURL))
|
info.append(("localStoreURL", localStoreURL))
|
||||||
|
|
||||||
case .asynchronousMigrationRequired(let localStoreURL):
|
case .asynchronousMigrationRequired(let localStoreURL, let NSError):
|
||||||
firstLine = ".asynchronousMigrationRequired"
|
firstLine = ".asynchronousMigrationRequired"
|
||||||
info.append(("localStoreURL", localStoreURL))
|
info.append(("localStoreURL", localStoreURL))
|
||||||
|
info.append(("NSError", NSError))
|
||||||
|
|
||||||
case .internalError(let NSError):
|
case .internalError(let NSError):
|
||||||
firstLine = ".internalError"
|
firstLine = ".internalError"
|
||||||
|
|||||||
@@ -199,9 +199,6 @@ public enum CoreStoreError: Error, CustomNSError, Hashable {
|
|||||||
case (.userError(let error1), .userError(let error2)):
|
case (.userError(let error1), .userError(let error2)):
|
||||||
switch (error1, error2) {
|
switch (error1, error2) {
|
||||||
|
|
||||||
case (let error1 as AnyHashable, let error2 as AnyHashable):
|
|
||||||
return error1 == error2
|
|
||||||
|
|
||||||
case (let error1 as NSError, let error2 as NSError):
|
case (let error1 as NSError, let error2 as NSError):
|
||||||
return error1.isEqual(error2)
|
return error1.isEqual(error2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,26 @@
|
|||||||
//
|
//
|
||||||
// CoreStoreObject+DataSources.swift
|
// CoreStoreObject+DataSources.swift
|
||||||
// CoreStore iOS
|
// CoreStore
|
||||||
//
|
//
|
||||||
// Created by John Estropia on 2019/10/04.
|
// Copyright © 2020 John Rommel Estropia
|
||||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
//
|
||||||
|
// 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.
|
||||||
//
|
//
|
||||||
|
|
||||||
#if canImport(UIKit) || canImport(AppKit)
|
#if canImport(UIKit) || canImport(AppKit)
|
||||||
|
|||||||
@@ -27,6 +27,33 @@ import Foundation
|
|||||||
import CoreData
|
import CoreData
|
||||||
|
|
||||||
|
|
||||||
|
extension DynamicObject where Self: CoreStoreObject {
|
||||||
|
|
||||||
|
public func observe<O, V>(_ keyPath: KeyPath<Self, FieldContainer<O>.Stored<V>>, options: NSKeyValueObservingOptions = [], changeHandler: @escaping (Self, CoreStoreObjectValueDiff<V>) -> Void) -> CoreStoreObjectKeyValueObservation {
|
||||||
|
|
||||||
|
let result = _CoreStoreObjectKeyValueObservation(
|
||||||
|
object: self.rawObject!,
|
||||||
|
keyPath: self[keyPath: keyPath].keyPath,
|
||||||
|
callback: { (object, kind, newValue, oldValue, _, isPrior) in
|
||||||
|
|
||||||
|
let notification = CoreStoreObjectValueDiff<V>(
|
||||||
|
kind: kind,
|
||||||
|
newNativeValue: newValue as? V.QueryableNativeType,
|
||||||
|
oldNativeValue: oldValue as? V.QueryableNativeType,
|
||||||
|
isPrior: isPrior
|
||||||
|
)
|
||||||
|
changeHandler(
|
||||||
|
Self.cs_fromRaw(object: object),
|
||||||
|
notification
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
result.start(options)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: CoreStoreObjectKeyValueObservation
|
// MARK: CoreStoreObjectKeyValueObservation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,6 +26,88 @@
|
|||||||
import CoreData
|
import CoreData
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
// MARK: - FieldContainer.Value
|
||||||
|
|
||||||
|
extension FieldContainer.Stored {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where({ $0.nickname == "John" }))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func == (_ attribute: Self, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where(attribute.keyPath, isEqualTo: value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is not equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where({ $0.nickname != "John" }))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func != (_ attribute: Self, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return !Where(attribute.keyPath, isEqualTo: value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is less than a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where({ $0.age < 20 }))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func < (_ attribute: Self, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where("%K < %@", attribute.keyPath, value.cs_toFieldStoredNativeType() as Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is greater than a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where({ $0.age > 20 }))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func > (_ attribute: Self, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where("%K > %@", attribute.keyPath, value.cs_toFieldStoredNativeType() as Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is less than or equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where({ $0.age <= 20 }))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func <= (_ attribute: Self, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where("%K <= %@", attribute.keyPath, value.cs_toFieldStoredNativeType() as Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is greater than or equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where({ $0.age >= 20 }))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func >= (_ attribute: Self, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where("%K >= %@", attribute.keyPath, value.cs_toFieldStoredNativeType() as Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by checking if a sequence contains the value of a property
|
||||||
|
```
|
||||||
|
let dog = dataStack.fetchOne(From<Dog>().where({ ["Pluto", "Snoopy", "Scooby"] ~= $0.nickname }))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public static func ~= <S: Sequence>(_ sequence: S, _ attribute: Self) -> Where<O> where S.Iterator.Element == V {
|
||||||
|
|
||||||
|
return Where(attribute.keyPath, isMemberOf: sequence)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - ValueContainer.Required
|
// MARK: - ValueContainer.Required
|
||||||
|
|
||||||
extension ValueContainer.Required {
|
extension ValueContainer.Required {
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ open /*abstract*/ class CoreStoreObject: DynamicObject, Hashable {
|
|||||||
|
|
||||||
self.isMeta = false
|
self.isMeta = false
|
||||||
self.rawObject = (rawObject as! CoreStoreManagedObject)
|
self.rawObject = (rawObject as! CoreStoreManagedObject)
|
||||||
|
|
||||||
|
guard Self.meta.needsReflection else {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
self.registerReceiver(
|
self.registerReceiver(
|
||||||
mirror: Mirror(reflecting: self),
|
mirror: Mirror(reflecting: self),
|
||||||
object: self
|
object: self
|
||||||
@@ -117,6 +122,11 @@ open /*abstract*/ class CoreStoreObject: DynamicObject, Hashable {
|
|||||||
internal let rawObject: CoreStoreManagedObject?
|
internal let rawObject: CoreStoreManagedObject?
|
||||||
internal let isMeta: Bool
|
internal let isMeta: Bool
|
||||||
|
|
||||||
|
internal lazy var needsReflection: Bool = self.containsLegacyAttributes(
|
||||||
|
mirror: Mirror(reflecting: self),
|
||||||
|
object: self
|
||||||
|
)
|
||||||
|
|
||||||
internal class func metaProperties(includeSuperclasses: Bool) -> [PropertyProtocol] {
|
internal class func metaProperties(includeSuperclasses: Bool) -> [PropertyProtocol] {
|
||||||
|
|
||||||
func keyPaths(_ allKeyPaths: inout [PropertyProtocol], for dynamicType: CoreStoreObject.Type) {
|
func keyPaths(_ allKeyPaths: inout [PropertyProtocol], for dynamicType: CoreStoreObject.Type) {
|
||||||
@@ -141,6 +151,30 @@ open /*abstract*/ class CoreStoreObject: DynamicObject, Hashable {
|
|||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
|
private func containsLegacyAttributes(mirror: Mirror, object: CoreStoreObject) -> Bool {
|
||||||
|
|
||||||
|
if let superclassMirror = mirror.superclassMirror,
|
||||||
|
self.containsLegacyAttributes(mirror: superclassMirror, object: object) {
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for child in mirror.children {
|
||||||
|
|
||||||
|
switch child.value {
|
||||||
|
|
||||||
|
case is AttributeProtocol:
|
||||||
|
return true
|
||||||
|
|
||||||
|
case is RelationshipProtocol:
|
||||||
|
return true
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private func registerReceiver(mirror: Mirror, object: CoreStoreObject) {
|
private func registerReceiver(mirror: Mirror, object: CoreStoreObject) {
|
||||||
|
|
||||||
if let superclassMirror = mirror.superclassMirror {
|
if let superclassMirror = mirror.superclassMirror {
|
||||||
|
|||||||
@@ -287,6 +287,25 @@ public final class CoreStoreSchema: DynamicSchema {
|
|||||||
|
|
||||||
switch property {
|
switch property {
|
||||||
|
|
||||||
|
case let attribute as FieldAttributeProtocol:
|
||||||
|
Internals.assert(
|
||||||
|
!NSManagedObject.instancesRespond(to: Selector(attribute.keyPath)),
|
||||||
|
"Attribute Property name \"\(String(reflecting: entity.type)).\(attribute.keyPath)\" is not allowed because it collides with \"\(String(reflecting: NSManagedObject.self)).\(attribute.keyPath)\""
|
||||||
|
)
|
||||||
|
let entityDescriptionValues = attribute.entityDescriptionValues()
|
||||||
|
let description = NSAttributeDescription()
|
||||||
|
description.name = attribute.keyPath
|
||||||
|
description.attributeType = entityDescriptionValues.attributeType
|
||||||
|
description.isOptional = entityDescriptionValues.isOptional
|
||||||
|
description.defaultValue = entityDescriptionValues.defaultValue
|
||||||
|
description.isTransient = entityDescriptionValues.isTransient
|
||||||
|
description.allowsExternalBinaryDataStorage = entityDescriptionValues.allowsExternalBinaryDataStorage
|
||||||
|
description.versionHashModifier = entityDescriptionValues.versionHashModifier
|
||||||
|
description.renamingIdentifier = entityDescriptionValues.renamingIdentifier
|
||||||
|
propertyDescriptions.append(description)
|
||||||
|
keyPathsByAffectedKeyPaths[attribute.keyPath] = entityDescriptionValues.affectedByKeyPaths
|
||||||
|
customGetterSetterByKeyPaths[attribute.keyPath] = (attribute.getter, attribute.setter)
|
||||||
|
|
||||||
case let attribute as AttributeProtocol:
|
case let attribute as AttributeProtocol:
|
||||||
Internals.assert(
|
Internals.assert(
|
||||||
!NSManagedObject.instancesRespond(to: Selector(attribute.keyPath)),
|
!NSManagedObject.instancesRespond(to: Selector(attribute.keyPath)),
|
||||||
|
|||||||
@@ -153,41 +153,68 @@ extension CoreStoreObject {
|
|||||||
|
|
||||||
public class func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any]? {
|
public class func cs_snapshotDictionary(id: ObjectID, context: NSManagedObjectContext) -> [String: Any]? {
|
||||||
|
|
||||||
func initializeAttributes(mirror: Mirror, object: Self, into attributes: inout [KeyPathString: Any]) {
|
var values: [KeyPathString: Any] = [:]
|
||||||
|
if self.meta.needsReflection {
|
||||||
|
|
||||||
if let superClassMirror = mirror.superclassMirror {
|
func initializeAttributes(mirror: Mirror, object: Self, into attributes: inout [KeyPathString: Any]) {
|
||||||
|
|
||||||
initializeAttributes(
|
if let superClassMirror = mirror.superclassMirror {
|
||||||
mirror: superClassMirror,
|
|
||||||
object: object,
|
initializeAttributes(
|
||||||
into: &attributes
|
mirror: superClassMirror,
|
||||||
)
|
object: object,
|
||||||
|
into: &attributes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for child in mirror.children {
|
||||||
|
|
||||||
|
switch child.value {
|
||||||
|
|
||||||
|
case let property as FieldAttributeProtocol:
|
||||||
|
attributes[property.keyPath] = type(of: property).read(field: property, for: object.rawObject!)
|
||||||
|
|
||||||
|
case let property as AttributeProtocol:
|
||||||
|
attributes[property.keyPath] = property.valueForSnapshot
|
||||||
|
|
||||||
|
case let property as RelationshipProtocol:
|
||||||
|
attributes[property.keyPath] = property.valueForSnapshot
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for child in mirror.children {
|
guard let object = context.fetchExisting(id) as CoreStoreObject? else {
|
||||||
|
|
||||||
switch child.value {
|
return nil
|
||||||
|
}
|
||||||
|
initializeAttributes(
|
||||||
|
mirror: Mirror(reflecting: object),
|
||||||
|
object: object as! Self,
|
||||||
|
into: &values
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
case let property as AttributeProtocol:
|
guard
|
||||||
attributes[property.keyPath] = property.valueForSnapshot
|
let object = context.fetchExisting(id) as CoreStoreObject?,
|
||||||
|
let rawObject = object.rawObject
|
||||||
|
else {
|
||||||
|
|
||||||
case let property as RelationshipProtocol:
|
return nil
|
||||||
attributes[property.keyPath] = property.valueForSnapshot
|
}
|
||||||
|
for property in self.metaProperties(includeSuperclasses: true) {
|
||||||
|
|
||||||
|
switch property {
|
||||||
|
|
||||||
|
case let property as FieldAttributeProtocol:
|
||||||
|
values[property.keyPath] = type(of: property).read(field: property, for: rawObject)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guard let object = context.fetchExisting(id) as CoreStoreObject? else {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var values: [KeyPathString: Any] = [:]
|
|
||||||
initializeAttributes(
|
|
||||||
mirror: Mirror(reflecting: object),
|
|
||||||
object: object as! Self,
|
|
||||||
into: &values
|
|
||||||
)
|
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
//
|
|
||||||
// DynamicObjectMeta.swift
|
|
||||||
// CoreStore iOS
|
|
||||||
//
|
|
||||||
// Created by John Estropia on 2019/08/20.
|
|
||||||
// Copyright © 2019 John Rommel Estropia. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#if swift(>=5.1)
|
|
||||||
|
|
||||||
import CoreData
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - DynamicObjectMeta
|
|
||||||
|
|
||||||
@dynamicMemberLookup
|
|
||||||
public struct DynamicObjectMeta<R, D>: CustomDebugStringConvertible {
|
|
||||||
|
|
||||||
// MARK: Public
|
|
||||||
|
|
||||||
public typealias Root = R
|
|
||||||
public typealias Destination = D
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: CustomDebugStringConvertible
|
|
||||||
|
|
||||||
public var debugDescription: String {
|
|
||||||
|
|
||||||
return self.keyPathString
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
internal let keyPathString: KeyPathString
|
|
||||||
|
|
||||||
internal init(keyPathString: KeyPathString) {
|
|
||||||
|
|
||||||
self.keyPathString = keyPathString
|
|
||||||
}
|
|
||||||
|
|
||||||
internal func appending<D2>(keyPathString: KeyPathString) -> DynamicObjectMeta<(R, D), D2> {
|
|
||||||
|
|
||||||
return .init(keyPathString: [self.keyPathString, keyPathString].joined(separator: "."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - DynamicObjectMeta where Destination: NSManagedObject
|
|
||||||
|
|
||||||
extension DynamicObjectMeta where Destination: NSManagedObject {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<V: AllowedObjectiveCAttributeKeyPathValue>(dynamicMember member: KeyPath<Destination, V>) -> DynamicObjectMeta<(Root, Destination), V.ReturnValueType> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<V: NSManagedObject>(dynamicMember member: KeyPath<Destination, V>) -> DynamicObjectMeta<(Root, Destination), V> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<V: NSManagedObject>(dynamicMember member: KeyPath<Destination, V?>) -> DynamicObjectMeta<(Root, Destination), V> {
|
|
||||||
|
|
||||||
// TODO: not working
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<V: NSOrderedSet>(dynamicMember member: KeyPath<Destination, V>) -> DynamicObjectMeta<(Root, Destination), V> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<V: NSOrderedSet>(dynamicMember member: KeyPath<Destination, V?>) -> DynamicObjectMeta<(Root, Destination), V> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<V: NSSet>(dynamicMember member: KeyPath<Destination, V>) -> DynamicObjectMeta<(Root, Destination), V> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<V: NSSet>(dynamicMember member: KeyPath<Destination, V?>) -> DynamicObjectMeta<(Root, Destination), V> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - DynamicObjectMeta where Destination: CoreStoreObject
|
|
||||||
|
|
||||||
extension DynamicObjectMeta where Destination: CoreStoreObject {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<K: AttributeKeyPathStringConvertible>(dynamicMember member: KeyPath<Destination, K>) -> DynamicObjectMeta<(Root, Destination), K.ReturnValueType> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the value for the property identified by a given key.
|
|
||||||
*/
|
|
||||||
public subscript<K: RelationshipKeyPathStringConvertible>(dynamicMember member: KeyPath<Destination, K>) -> DynamicObjectMeta<(Root, Destination), K.DestinationValueType> {
|
|
||||||
|
|
||||||
let keyPathString = String(keyPath: member)
|
|
||||||
return self.appending(keyPathString: keyPathString)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
305
Sources/Field.Computed.swift
Normal file
305
Sources/Field.Computed.swift
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
//
|
||||||
|
// Field.Computed.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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: - FieldContainer
|
||||||
|
|
||||||
|
extension FieldContainer {
|
||||||
|
|
||||||
|
// MARK: - Computed
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for computed property values. Any type that conforms to `FieldStorableType` are supported.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
@Field.Stored("species")
|
||||||
|
var species = ""
|
||||||
|
|
||||||
|
@Field.Computed("pluralName", customGetter: Animal.pluralName(_:))
|
||||||
|
var pluralName: String = ""
|
||||||
|
|
||||||
|
@Field.PlistCoded("color")
|
||||||
|
var color: UIColor?
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Important: `Field` properties are required to be used as `@propertyWrapper`s. Any other declaration not using the `@Field.Computed(...) var` syntax will be ignored.
|
||||||
|
*/
|
||||||
|
@propertyWrapper
|
||||||
|
public struct Computed<V>: AttributeKeyPathStringConvertible, FieldAttributeProtocol {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes the metadata for the property.
|
||||||
|
```
|
||||||
|
class Person: CoreStoreObject {
|
||||||
|
@Field.Stored("title")
|
||||||
|
var title: String = "Mr."
|
||||||
|
|
||||||
|
@Field.Stored("name")
|
||||||
|
var name: String = ""
|
||||||
|
|
||||||
|
@Field.Computed("displayName", customGetter: Person.getName(_:))
|
||||||
|
var displayName: String = ""
|
||||||
|
|
||||||
|
private static func getName(_ partialObject: PartialObject<Person>) -> String {
|
||||||
|
let cachedDisplayName = partialObject.primitiveValue(for: \.$displayName)
|
||||||
|
if !cachedDisplayName.isEmpty {
|
||||||
|
return cachedDisplayName
|
||||||
|
}
|
||||||
|
let title = partialObject.value(for: \.$title)
|
||||||
|
let name = partialObject.value(for: \.$name)
|
||||||
|
let displayName = "\(title) \(name)"
|
||||||
|
partialObject.setPrimitiveValue(displayName, for: { $0.displayName })
|
||||||
|
return displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- parameter keyPath: the permanent attribute name for this property.
|
||||||
|
- 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: KeyPathString,
|
||||||
|
renamingIdentifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V)? = nil,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<KeyPathString> = []) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath: keyPath,
|
||||||
|
isOptional: false,
|
||||||
|
renamingIdentifier: renamingIdentifier,
|
||||||
|
customGetter: customGetter,
|
||||||
|
customSetter: customSetter,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Overload for compiler message only
|
||||||
|
*/
|
||||||
|
@available(*, unavailable, message: "Field.Computed properties are not allowed to have default values.")
|
||||||
|
public init(
|
||||||
|
wrappedValue initial: @autoclosure @escaping () -> V,
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
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<KeyPathString> = []) {
|
||||||
|
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: @propertyWrapper
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
public var wrappedValue: V {
|
||||||
|
|
||||||
|
get { fatalError() }
|
||||||
|
set { fatalError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
public var projectedValue: Self {
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public static subscript(
|
||||||
|
_enclosingInstance instance: O,
|
||||||
|
wrapped wrappedKeyPath: ReferenceWritableKeyPath<O, V>,
|
||||||
|
storage storageKeyPath: ReferenceWritableKeyPath<O, Self>
|
||||||
|
) -> V {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
instance.rawObject != nil,
|
||||||
|
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return self.read(field: instance[keyPath: storageKeyPath], for: instance.rawObject!) as! V
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
instance.rawObject != nil,
|
||||||
|
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return self.modify(field: instance[keyPath: storageKeyPath], for: instance.rawObject!, newValue: newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: AnyKeyPathStringConvertible
|
||||||
|
|
||||||
|
public var cs_keyPathString: String {
|
||||||
|
|
||||||
|
return self.keyPath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: KeyPathStringConvertible
|
||||||
|
|
||||||
|
public typealias ObjectType = O
|
||||||
|
public typealias DestinationValueType = V
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: AttributeKeyPathStringConvertible
|
||||||
|
|
||||||
|
public typealias ReturnValueType = DestinationValueType
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: PropertyProtocol
|
||||||
|
|
||||||
|
internal let keyPath: KeyPathString
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FieldProtocol
|
||||||
|
|
||||||
|
internal static func read(field: FieldProtocol, for rawObject: CoreStoreManagedObject) -> Any? {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
rawObject.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
let field = field as! Self
|
||||||
|
if let customGetter = field.customGetter {
|
||||||
|
|
||||||
|
return customGetter(PartialObject<O>(rawObject))
|
||||||
|
}
|
||||||
|
let keyPath = field.keyPath
|
||||||
|
switch rawObject.value(forKey: keyPath) {
|
||||||
|
|
||||||
|
case let rawValue as V:
|
||||||
|
return rawValue
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static func modify(field: FieldProtocol, for rawObject: CoreStoreManagedObject, newValue: Any?) {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
rawObject.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
Internals.assert(
|
||||||
|
rawObject.isEditableInContext() == true,
|
||||||
|
"Attempted to update a \(Internals.typeName(O.self))'s value from outside a transaction."
|
||||||
|
)
|
||||||
|
let newValue = newValue as! V
|
||||||
|
let field = field as! Self
|
||||||
|
let keyPath = field.keyPath
|
||||||
|
if let customSetter = field.customSetter {
|
||||||
|
|
||||||
|
return customSetter(PartialObject<O>(rawObject), newValue)
|
||||||
|
}
|
||||||
|
return rawObject.setValue(newValue, forKey: keyPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FieldAttributeProtocol
|
||||||
|
|
||||||
|
internal let entityDescriptionValues: () -> FieldAttributeProtocol.EntityDescriptionValues
|
||||||
|
|
||||||
|
internal var getter: CoreStoreManagedObject.CustomGetter? {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return customGetter(PartialObject<O>(rawObject))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal var setter: CoreStoreManagedObject.CustomSetter? {
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return customSetter(PartialObject<O>(rawObject), newValue as! V)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FilePrivate
|
||||||
|
|
||||||
|
fileprivate init(
|
||||||
|
keyPath: KeyPathString,
|
||||||
|
isOptional: Bool,
|
||||||
|
renamingIdentifier: @escaping () -> String?,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V)?,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? ,
|
||||||
|
affectedByKeyPaths: @escaping () -> Set<KeyPathString>) {
|
||||||
|
|
||||||
|
self.keyPath = keyPath
|
||||||
|
self.entityDescriptionValues = {
|
||||||
|
(
|
||||||
|
attributeType: .undefinedAttributeType,
|
||||||
|
isOptional: isOptional,
|
||||||
|
isTransient: true,
|
||||||
|
allowsExternalBinaryDataStorage: false,
|
||||||
|
versionHashModifier: nil,
|
||||||
|
renamingIdentifier: renamingIdentifier(),
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths(),
|
||||||
|
defaultValue: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.customGetter = customGetter
|
||||||
|
self.customSetter = customSetter
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private let customGetter: ((_ partialObject: PartialObject<O>) -> V)?
|
||||||
|
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)?
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Sources/Field.PlistCoded.swift
Normal file
9
Sources/Field.PlistCoded.swift
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// Field.PlistCoded.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Created by John Estropia on 2020/01/15.
|
||||||
|
// Copyright © 2020 John Rommel Estropia. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
362
Sources/Field.Stored.swift
Normal file
362
Sources/Field.Stored.swift
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
//
|
||||||
|
// Field.Stored.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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: - FieldContainer
|
||||||
|
|
||||||
|
extension FieldContainer {
|
||||||
|
|
||||||
|
// MARK: - Stored
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for stored property values. Any type that conforms to `FieldStorableType` are supported.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
@Field.Stored("species")
|
||||||
|
var species = ""
|
||||||
|
|
||||||
|
@Field.Computed("pluralName", customGetter: Animal.pluralName(_:))
|
||||||
|
var pluralName: String = ""
|
||||||
|
|
||||||
|
@Field.PlistCoded("color")
|
||||||
|
var color: UIColor?
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Important: `Field` properties are required to be used as `@propertyWrapper`s. Any other declaration not using the `@Field.Stored(...) var` syntax will be ignored.
|
||||||
|
*/
|
||||||
|
@propertyWrapper
|
||||||
|
public struct Stored<V: FieldStorableType>: AttributeKeyPathStringConvertible, FieldAttributeProtocol {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes the metadata for the property.
|
||||||
|
```
|
||||||
|
class Person: CoreStoreObject {
|
||||||
|
@Field.Stored("title")
|
||||||
|
var title: String = "Mr."
|
||||||
|
|
||||||
|
@Field.Stored("name")
|
||||||
|
var name: String = ""
|
||||||
|
|
||||||
|
@Field.Computed("displayName", customGetter: Person.getName(_:))
|
||||||
|
var displayName: String = ""
|
||||||
|
|
||||||
|
private static func getName(_ partialObject: PartialObject<Person>) -> String {
|
||||||
|
let cachedDisplayName = partialObject.primitiveValue(for: \.$displayName)
|
||||||
|
if !cachedDisplayName.isEmpty {
|
||||||
|
return cachedDisplayName
|
||||||
|
}
|
||||||
|
let title = partialObject.value(for: \.$title)
|
||||||
|
let name = partialObject.value(for: \.$name)
|
||||||
|
let displayName = "\(title) \(name)"
|
||||||
|
partialObject.setPrimitiveValue(displayName, for: { $0.displayName })
|
||||||
|
return displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- parameter initial: the initial value for the property when the object is first create
|
||||||
|
- parameter keyPath: the permanent attribute name for this property.
|
||||||
|
- 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(
|
||||||
|
wrappedValue initial: @autoclosure @escaping () -> V,
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
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<KeyPathString> = []) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
wrappedValue: initial,
|
||||||
|
keyPath: keyPath,
|
||||||
|
isOptional: false,
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: renamingIdentifier,
|
||||||
|
customGetter: customGetter,
|
||||||
|
customSetter: customSetter,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: @propertyWrapper
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
public var wrappedValue: V {
|
||||||
|
|
||||||
|
get { fatalError() }
|
||||||
|
set { fatalError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
public var projectedValue: Self {
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public static subscript(
|
||||||
|
_enclosingInstance instance: O,
|
||||||
|
wrapped wrappedKeyPath: ReferenceWritableKeyPath<O, V>,
|
||||||
|
storage storageKeyPath: ReferenceWritableKeyPath<O, Self>
|
||||||
|
) -> V {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
instance.rawObject != nil,
|
||||||
|
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return self.read(field: instance[keyPath: storageKeyPath], for: instance.rawObject!) as! V
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
instance.rawObject != nil,
|
||||||
|
"Attempted to access values from a \(Internals.typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types."
|
||||||
|
)
|
||||||
|
return self.modify(field: instance[keyPath: storageKeyPath], for: instance.rawObject!, newValue: newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: AnyKeyPathStringConvertible
|
||||||
|
|
||||||
|
public var cs_keyPathString: String {
|
||||||
|
|
||||||
|
return self.keyPath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: KeyPathStringConvertible
|
||||||
|
|
||||||
|
public typealias ObjectType = O
|
||||||
|
public typealias DestinationValueType = V
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: AttributeKeyPathStringConvertible
|
||||||
|
|
||||||
|
public typealias ReturnValueType = DestinationValueType
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: PropertyProtocol
|
||||||
|
|
||||||
|
internal let keyPath: KeyPathString
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FieldProtocol
|
||||||
|
|
||||||
|
internal static func read(field: FieldProtocol, for rawObject: CoreStoreManagedObject) -> Any? {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
rawObject.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
let field = field as! Self
|
||||||
|
if let customGetter = field.customGetter {
|
||||||
|
|
||||||
|
return customGetter(PartialObject<O>(rawObject))
|
||||||
|
}
|
||||||
|
let keyPath = field.keyPath
|
||||||
|
guard case let rawValue as V.FieldStoredNativeType = rawObject.value(forKey: keyPath) else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return V.cs_fromFieldStoredNativeType(rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static func modify(field: FieldProtocol, for rawObject: CoreStoreManagedObject, newValue: Any?) {
|
||||||
|
|
||||||
|
Internals.assert(
|
||||||
|
rawObject.isRunningInAllowedQueue() == true,
|
||||||
|
"Attempted to access \(Internals.typeName(O.self))'s value outside it's designated queue."
|
||||||
|
)
|
||||||
|
Internals.assert(
|
||||||
|
rawObject.isEditableInContext() == true,
|
||||||
|
"Attempted to update a \(Internals.typeName(O.self))'s value from outside a transaction."
|
||||||
|
)
|
||||||
|
let newValue = newValue as! V
|
||||||
|
let field = field as! Self
|
||||||
|
let keyPath = field.keyPath
|
||||||
|
if let customSetter = field.customSetter {
|
||||||
|
|
||||||
|
return customSetter(PartialObject<O>(rawObject), newValue)
|
||||||
|
}
|
||||||
|
return rawObject.setValue(
|
||||||
|
newValue.cs_toFieldStoredNativeType(),
|
||||||
|
forKey: keyPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FieldAttributeProtocol
|
||||||
|
|
||||||
|
internal let entityDescriptionValues: () -> FieldAttributeProtocol.EntityDescriptionValues
|
||||||
|
|
||||||
|
internal var getter: CoreStoreManagedObject.CustomGetter? {
|
||||||
|
|
||||||
|
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.cs_toFieldStoredNativeType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal var setter: CoreStoreManagedObject.CustomSetter? {
|
||||||
|
|
||||||
|
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),
|
||||||
|
V.cs_fromFieldStoredNativeType(newValue as! V.FieldStoredNativeType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FilePrivate
|
||||||
|
|
||||||
|
fileprivate init(
|
||||||
|
wrappedValue initial: @escaping () -> V,
|
||||||
|
keyPath: KeyPathString,
|
||||||
|
isOptional: Bool,
|
||||||
|
versionHashModifier: @escaping () -> String?,
|
||||||
|
renamingIdentifier: @escaping () -> String?,
|
||||||
|
customGetter: ((_ partialObject: PartialObject<O>) -> V)?,
|
||||||
|
customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)? ,
|
||||||
|
affectedByKeyPaths: @escaping () -> Set<KeyPathString>) {
|
||||||
|
|
||||||
|
self.keyPath = keyPath
|
||||||
|
self.entityDescriptionValues = {
|
||||||
|
(
|
||||||
|
attributeType: V.cs_rawAttributeType,
|
||||||
|
isOptional: isOptional,
|
||||||
|
isTransient: false,
|
||||||
|
allowsExternalBinaryDataStorage: false,
|
||||||
|
versionHashModifier: versionHashModifier(),
|
||||||
|
renamingIdentifier: renamingIdentifier(),
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths(),
|
||||||
|
defaultValue: initial().cs_toFieldStoredNativeType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.customGetter = customGetter
|
||||||
|
self.customSetter = customSetter
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
|
||||||
|
private let customGetter: ((_ partialObject: PartialObject<O>) -> V)?
|
||||||
|
private let customSetter: ((_ partialObject: PartialObject<O>, _ newValue: V) -> Void)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - FieldContainer.Stored where V: FieldOptionalType
|
||||||
|
|
||||||
|
extension FieldContainer.Stored where V: FieldOptionalType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes the metadata for the property.
|
||||||
|
```
|
||||||
|
class Person: CoreStoreObject {
|
||||||
|
@Field.Stored("title")
|
||||||
|
var title: String = "Mr."
|
||||||
|
|
||||||
|
@Field.Stored("name")
|
||||||
|
var name: String = ""
|
||||||
|
|
||||||
|
@Field.Computed("displayName", customGetter: Person.getName(_:))
|
||||||
|
var displayName: String = ""
|
||||||
|
|
||||||
|
private static func getName(_ partialObject: PartialObject<Person>) -> String {
|
||||||
|
let cachedDisplayName = partialObject.primitiveValue(for: \.$displayName)
|
||||||
|
if !cachedDisplayName.isEmpty {
|
||||||
|
return cachedDisplayName
|
||||||
|
}
|
||||||
|
let title = partialObject.value(for: \.$title)
|
||||||
|
let name = partialObject.value(for: \.$name)
|
||||||
|
let displayName = "\(title) \(name)"
|
||||||
|
partialObject.setPrimitiveValue(displayName, for: { $0.displayName })
|
||||||
|
return displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- parameter initial: the initial value for the property when the object is first create
|
||||||
|
- parameter keyPath: the permanent attribute name for this property.
|
||||||
|
- 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(
|
||||||
|
wrappedValue initial: @autoclosure @escaping () -> V = nil,
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
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<KeyPathString> = []) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
wrappedValue: initial,
|
||||||
|
keyPath: keyPath,
|
||||||
|
isOptional: true,
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: renamingIdentifier,
|
||||||
|
customGetter: customGetter,
|
||||||
|
customSetter: customSetter,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
71
Sources/Field.swift
Normal file
71
Sources/Field.swift
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// Field.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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
|
||||||
|
|
||||||
|
extension DynamicObject where Self: CoreStoreObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for value propertiess. `Field` properties support any type that conforms to `ImportableAttributeType`.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
@Field.Stored("species")
|
||||||
|
var species = ""
|
||||||
|
|
||||||
|
@Field.Stored("nickname")
|
||||||
|
var nickname: String?
|
||||||
|
|
||||||
|
@Field.PlistCoded("color")
|
||||||
|
var color: UIColor?
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Important: `Field` properties are required to be used as `@propertyWrapper`s. Any other declaration not using the `@Field.*(...) var` syntax will be ignored.
|
||||||
|
*/
|
||||||
|
public typealias Field = FieldContainer<Self>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - FieldContainer
|
||||||
|
|
||||||
|
/**
|
||||||
|
The containing type for value properties. Use the `DynamicObject.Field` typealias instead for shorter syntax.
|
||||||
|
```
|
||||||
|
class Animal: CoreStoreObject {
|
||||||
|
@Field.Stored("species")
|
||||||
|
var species = ""
|
||||||
|
|
||||||
|
@Field.Stored("nickname")
|
||||||
|
var nickname: String?
|
||||||
|
|
||||||
|
@Field.PlistCoded("color")
|
||||||
|
var color: UIColor?
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public enum FieldContainer<O: CoreStoreObject> {}
|
||||||
56
Sources/FieldOptionalType.swift
Normal file
56
Sources/FieldOptionalType.swift
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// FieldOptionalType.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2020 John Rommel Estropia
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - FieldOptionalType
|
||||||
|
|
||||||
|
public protocol FieldOptionalType: ExpressibleByNilLiteral {
|
||||||
|
|
||||||
|
/**
|
||||||
|
The type for the wrapped value
|
||||||
|
*/
|
||||||
|
associatedtype Wrapped
|
||||||
|
|
||||||
|
/**
|
||||||
|
The wrapped value
|
||||||
|
*/
|
||||||
|
var cs_wrappedValue: Wrapped? { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Optional: FieldOptionalType
|
||||||
|
|
||||||
|
extension Optional: FieldOptionalType {
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
|
||||||
|
@inlinable
|
||||||
|
public var cs_wrappedValue: Wrapped? {
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
}
|
||||||
57
Sources/FieldProtocol.swift
Normal file
57
Sources/FieldProtocol.swift
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// FieldProtocol.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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: - FieldProtocol
|
||||||
|
|
||||||
|
internal protocol FieldProtocol: PropertyProtocol {
|
||||||
|
|
||||||
|
static func read(field: FieldProtocol, for rawObject: CoreStoreManagedObject) -> Any?
|
||||||
|
static func modify(field: FieldProtocol, for rawObject: CoreStoreManagedObject, newValue: Any?)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - FieldAttributeProtocol
|
||||||
|
|
||||||
|
internal protocol FieldAttributeProtocol: FieldProtocol {
|
||||||
|
|
||||||
|
typealias EntityDescriptionValues = (
|
||||||
|
attributeType: NSAttributeType,
|
||||||
|
isOptional: Bool,
|
||||||
|
isTransient: Bool,
|
||||||
|
allowsExternalBinaryDataStorage: Bool,
|
||||||
|
versionHashModifier: String?,
|
||||||
|
renamingIdentifier: String?,
|
||||||
|
affectedByKeyPaths: Set<KeyPathString>,
|
||||||
|
defaultValue: Any?
|
||||||
|
)
|
||||||
|
|
||||||
|
var entityDescriptionValues: () -> EntityDescriptionValues { get }
|
||||||
|
var getter: CoreStoreManagedObject.CustomGetter? { get }
|
||||||
|
var setter: CoreStoreManagedObject.CustomSetter? { get }
|
||||||
|
}
|
||||||
259
Sources/FieldStorableType.swift
Normal file
259
Sources/FieldStorableType.swift
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
//
|
||||||
|
// FieldStorableType.swift
|
||||||
|
// CoreStore
|
||||||
|
//
|
||||||
|
// Copyright © 2020 John Rommel Estropia
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import CoreData
|
||||||
|
import Foundation
|
||||||
|
import CoreGraphics
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - FieldStorableType
|
||||||
|
|
||||||
|
public protocol FieldStorableType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
The `NSAttributeType` for this type
|
||||||
|
*/
|
||||||
|
associatedtype FieldStoredNativeType
|
||||||
|
|
||||||
|
/**
|
||||||
|
The `NSAttributeType` for this type
|
||||||
|
*/
|
||||||
|
static var cs_rawAttributeType: NSAttributeType { get }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates an instance of this type from raw native value.
|
||||||
|
*/
|
||||||
|
@inline(__always)
|
||||||
|
static func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates `FieldStoredNativeType` value from this instance.
|
||||||
|
*/
|
||||||
|
@inline(__always)
|
||||||
|
func cs_toFieldStoredNativeType() -> Any?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - FieldStorableType where Self: ImportableAttributeType, FieldStoredNativeType == QueryableNativeType
|
||||||
|
|
||||||
|
extension FieldStorableType where Self: ImportableAttributeType, FieldStoredNativeType == QueryableNativeType {
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
public static func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
return self.cs_fromQueryableNativeType(value)!
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
public func cs_toFieldStoredNativeType() -> Any? {
|
||||||
|
|
||||||
|
return self.cs_toQueryableNativeType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Bool
|
||||||
|
|
||||||
|
extension Bool: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - CGFloat
|
||||||
|
|
||||||
|
extension CGFloat: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Data
|
||||||
|
|
||||||
|
extension Data: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Date
|
||||||
|
|
||||||
|
extension Date: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Double
|
||||||
|
|
||||||
|
extension Double: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Float
|
||||||
|
|
||||||
|
extension Float: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Int
|
||||||
|
|
||||||
|
extension Int: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Int8
|
||||||
|
|
||||||
|
extension Int8: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Int16
|
||||||
|
|
||||||
|
extension Int16: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Int32
|
||||||
|
|
||||||
|
extension Int32: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Int64
|
||||||
|
|
||||||
|
extension Int64: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSData
|
||||||
|
|
||||||
|
extension NSData: FieldStorableType {
|
||||||
|
|
||||||
|
@nonobjc @inline(__always)
|
||||||
|
public class func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
return self.cs_fromQueryableNativeType(value)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSDate
|
||||||
|
|
||||||
|
extension NSDate: FieldStorableType {
|
||||||
|
|
||||||
|
@nonobjc @inline(__always)
|
||||||
|
public class func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
return self.cs_fromQueryableNativeType(value)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSNumber
|
||||||
|
|
||||||
|
extension NSNumber: FieldStorableType {
|
||||||
|
|
||||||
|
@nonobjc @inline(__always)
|
||||||
|
public class func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
return self.cs_fromQueryableNativeType(value)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSString
|
||||||
|
|
||||||
|
extension NSString: FieldStorableType {
|
||||||
|
|
||||||
|
@nonobjc @inline(__always)
|
||||||
|
public class func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
return self.cs_fromQueryableNativeType(value)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSURL
|
||||||
|
|
||||||
|
extension NSURL: FieldStorableType {
|
||||||
|
|
||||||
|
@nonobjc @inline(__always)
|
||||||
|
public class func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
return self.cs_fromQueryableNativeType(value)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - NSUUID
|
||||||
|
|
||||||
|
extension NSUUID: FieldStorableType {
|
||||||
|
|
||||||
|
@nonobjc @inline(__always)
|
||||||
|
public class func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
return self.cs_fromQueryableNativeType(value)!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - String
|
||||||
|
|
||||||
|
extension String: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - URL
|
||||||
|
|
||||||
|
extension URL: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - UUID
|
||||||
|
|
||||||
|
extension UUID: FieldStorableType {}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Optional<FieldStorableType>
|
||||||
|
|
||||||
|
extension Optional: FieldStorableType where Wrapped: FieldStorableType {
|
||||||
|
|
||||||
|
// MARK: FieldStorableType
|
||||||
|
|
||||||
|
public typealias FieldStoredNativeType = Wrapped.FieldStoredNativeType?
|
||||||
|
|
||||||
|
public static var cs_rawAttributeType: NSAttributeType {
|
||||||
|
|
||||||
|
return Wrapped.cs_rawAttributeType
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
public static func cs_fromFieldStoredNativeType(_ value: FieldStoredNativeType) -> Self {
|
||||||
|
|
||||||
|
switch value {
|
||||||
|
|
||||||
|
case nil,
|
||||||
|
is NSNull:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case let value?:
|
||||||
|
return Wrapped.cs_fromFieldStoredNativeType(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
public func cs_toFieldStoredNativeType() -> Any? {
|
||||||
|
|
||||||
|
switch self {
|
||||||
|
|
||||||
|
case nil,
|
||||||
|
is NSNull:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case let value?:
|
||||||
|
return value.cs_toFieldStoredNativeType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -359,6 +359,20 @@ public func ~= <O: NSManagedObject, D: NSManagedObject, S: Sequence>(_ sequence:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - KeyPath where Root: CoreStoreObject, Value: FieldContainer<Root>.Stored<QueryableAttributeType & Equatable>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.nickname == "John"))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func == <O, V>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where<O>(keyPath, isEqualTo: value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Required<QueryableAttributeType & Equatable>
|
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Required<QueryableAttributeType & Equatable>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -106,47 +106,47 @@ extension Int64: AllowedObjectiveCKeyPathValue {
|
|||||||
|
|
||||||
extension NSData: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSData: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSData
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSDate: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSDate: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSDate
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSManagedObject: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSManagedObject: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSManagedObject
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSNumber: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSNumber: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSString: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSString: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSString
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSSet: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSSet: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSSet
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSOrderedSet: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSOrderedSet: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSOrderedSet
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSURL: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSURL: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSURL
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSUUID: AllowedOptionalObjectiveCKeyPathValue {
|
extension NSUUID: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
|
|
||||||
public typealias DestinationValueType = Self
|
public typealias DestinationValueType = NSUUID
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String: AllowedOptionalObjectiveCKeyPathValue {
|
extension String: AllowedOptionalObjectiveCKeyPathValue {
|
||||||
@@ -240,32 +240,32 @@ extension Int64: AllowedObjectiveCAttributeKeyPathValue {
|
|||||||
|
|
||||||
extension NSData: AllowedObjectiveCAttributeKeyPathValue {
|
extension NSData: AllowedObjectiveCAttributeKeyPathValue {
|
||||||
|
|
||||||
public typealias ReturnValueType = Self
|
public typealias ReturnValueType = NSData
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSDate: AllowedObjectiveCAttributeKeyPathValue {
|
extension NSDate: AllowedObjectiveCAttributeKeyPathValue {
|
||||||
|
|
||||||
public typealias ReturnValueType = Self
|
public typealias ReturnValueType = NSDate
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSNumber: AllowedObjectiveCAttributeKeyPathValue {
|
extension NSNumber: AllowedObjectiveCAttributeKeyPathValue {
|
||||||
|
|
||||||
public typealias ReturnValueType = Self
|
public typealias ReturnValueType = NSNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSString: AllowedObjectiveCAttributeKeyPathValue {
|
extension NSString: AllowedObjectiveCAttributeKeyPathValue {
|
||||||
|
|
||||||
public typealias ReturnValueType = Self
|
public typealias ReturnValueType = NSString
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSURL: AllowedObjectiveCAttributeKeyPathValue {
|
extension NSURL: AllowedObjectiveCAttributeKeyPathValue {
|
||||||
|
|
||||||
public typealias ReturnValueType = Self
|
public typealias ReturnValueType = NSURL
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NSUUID: AllowedObjectiveCAttributeKeyPathValue {
|
extension NSUUID: AllowedObjectiveCAttributeKeyPathValue {
|
||||||
|
|
||||||
public typealias ReturnValueType = Self
|
public typealias ReturnValueType = NSUUID
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String: AllowedObjectiveCAttributeKeyPathValue {
|
extension String: AllowedObjectiveCAttributeKeyPathValue {
|
||||||
|
|||||||
@@ -367,6 +367,36 @@ extension ObjectPublisher where O: CoreStoreObject {
|
|||||||
|
|
||||||
// MARK: Public
|
// MARK: Public
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the property identified by a given key.
|
||||||
|
*/
|
||||||
|
public subscript<OBase, V>(dynamicMember member: KeyPath<O, FieldContainer<OBase>.Stored<V>>) -> V? {
|
||||||
|
|
||||||
|
guard
|
||||||
|
let object = self.object,
|
||||||
|
let rawObject = object.rawObject
|
||||||
|
else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return FieldContainer<OBase>.Stored<V>.read(field: object[keyPath: member], for: rawObject) as! V?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the property identified by a given key.
|
||||||
|
*/
|
||||||
|
public subscript<OBase, V>(dynamicMember member: KeyPath<O, FieldContainer<OBase>.Computed<V>>) -> V? {
|
||||||
|
|
||||||
|
guard
|
||||||
|
let object = self.object,
|
||||||
|
let rawObject = object.rawObject
|
||||||
|
else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return FieldContainer<OBase>.Computed<V>.read(field: object[keyPath: member], for: rawObject) as! V?
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the value for the property identified by a given key.
|
Returns the value for the property identified by a given key.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -175,6 +175,40 @@ extension ObjectSnapshot where O: NSManagedObject {
|
|||||||
|
|
||||||
extension ObjectSnapshot where O: CoreStoreObject {
|
extension ObjectSnapshot where O: CoreStoreObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the property identified by a given key.
|
||||||
|
*/
|
||||||
|
public subscript<OBase, V>(dynamicMember member: KeyPath<O, FieldContainer<OBase>.Stored<V>>) -> V {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
let key = String(keyPath: member)
|
||||||
|
return self.values[key] as! V
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
let key = String(keyPath: member)
|
||||||
|
self.values[key] = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the property identified by a given key.
|
||||||
|
*/
|
||||||
|
public subscript<OBase, V>(dynamicMember member: KeyPath<O, FieldContainer<OBase>.Computed<V>>) -> V {
|
||||||
|
|
||||||
|
get {
|
||||||
|
|
||||||
|
let key = String(keyPath: member)
|
||||||
|
return self.values[key] as! V
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
|
||||||
|
let key = String(keyPath: member)
|
||||||
|
self.values[key] = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the value for the property identified by a given key.
|
Returns the value for the property identified by a given key.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,6 +43,89 @@ public struct PartialObject<O: CoreStoreObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Field.Stored accessors/mutators
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the property identified by a given key.
|
||||||
|
*/
|
||||||
|
public func value<V>(for property: (O) -> FieldContainer<O>.Stored<V>) -> V {
|
||||||
|
|
||||||
|
return V.cs_fromFieldStoredNativeType(
|
||||||
|
self.rawObject.value(forKey: property(O.meta).keyPath) as! V.FieldStoredNativeType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the property identified by a given key.
|
||||||
|
*/
|
||||||
|
public func value<V>(for property: (O) -> FieldContainer<O>.Computed<V>) -> V {
|
||||||
|
|
||||||
|
switch self.rawObject.value(forKey: property(O.meta).keyPath) {
|
||||||
|
|
||||||
|
case let value as V:
|
||||||
|
return value
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil as Any? as! V // filter NSNull
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the specified property from the managed object’s private internal storage.
|
||||||
|
|
||||||
|
This method does not invoke the access notification methods (`willAccessValue(forKey:)` and `didAccessValue(forKey:)`). This method is used primarily by subclasses that implement custom accessor methods that need direct access to the receiver’s private storage.
|
||||||
|
*/
|
||||||
|
public func primitiveValue<V>(for property: (O) -> FieldContainer<O>.Stored<V>) -> V {
|
||||||
|
|
||||||
|
return V.cs_fromFieldStoredNativeType(
|
||||||
|
self.rawObject.primitiveValue(forKey: property(O.meta).keyPath) as! V.FieldStoredNativeType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value for the specified property from the managed object’s private internal storage.
|
||||||
|
|
||||||
|
This method does not invoke the access notification methods (`willAccessValue(forKey:)` and `didAccessValue(forKey:)`). This method is used primarily by subclasses that implement custom accessor methods that need direct access to the receiver’s private storage.
|
||||||
|
*/
|
||||||
|
public func primitiveValue<V>(for property: (O) -> FieldContainer<O>.Computed<V>) -> V {
|
||||||
|
|
||||||
|
switch self.rawObject.primitiveValue(forKey: property(O.meta).keyPath) {
|
||||||
|
|
||||||
|
case let value as V:
|
||||||
|
return value
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil as Any? as! V // filter NSNull
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets in the object's private internal storage the value of a given property.
|
||||||
|
|
||||||
|
Sets in the receiver’s private internal storage the value of the property specified by key to value.
|
||||||
|
*/
|
||||||
|
public func setPrimitiveValue<V>(_ value: V, for property: (O) -> FieldContainer<O>.Stored<V>) {
|
||||||
|
|
||||||
|
self.rawObject.setPrimitiveValue(
|
||||||
|
value.cs_toFieldStoredNativeType(),
|
||||||
|
forKey: property(O.meta).keyPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets in the object's private internal storage the value of a given property.
|
||||||
|
|
||||||
|
Sets in the receiver’s private internal storage the value of the property specified by key to value.
|
||||||
|
*/
|
||||||
|
public func setPrimitiveValue<V>(_ value: V, for property: (O) -> FieldContainer<O>.Computed<V>) {
|
||||||
|
|
||||||
|
self.rawObject.setPrimitiveValue(
|
||||||
|
value,
|
||||||
|
forKey: property(O.meta).keyPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Value.Required accessors/mutators
|
// MARK: Value.Required accessors/mutators
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import CoreData
|
|||||||
|
|
||||||
// MARK: - PropertyProtocol
|
// MARK: - PropertyProtocol
|
||||||
|
|
||||||
internal protocol PropertyProtocol: AnyObject {
|
internal protocol PropertyProtocol {
|
||||||
|
|
||||||
var keyPath: KeyPathString { get }
|
var keyPath: KeyPathString { get }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import CoreData
|
|||||||
|
|
||||||
// MARK: - RelationshipProtocol
|
// MARK: - RelationshipProtocol
|
||||||
|
|
||||||
internal protocol RelationshipProtocol: PropertyProtocol {
|
internal protocol RelationshipProtocol: AnyObject, PropertyProtocol {
|
||||||
|
|
||||||
typealias EntityDescriptionValues = (
|
typealias EntityDescriptionValues = (
|
||||||
isToMany: Bool,
|
isToMany: Bool,
|
||||||
|
|||||||
@@ -73,22 +73,22 @@ public struct LocalStorageOptions: OptionSet, ExpressibleByNilLiteral {
|
|||||||
/**
|
/**
|
||||||
Tells the `DataStack` that the store should not be migrated or recreated, and should simply fail on model mismatch
|
Tells the `DataStack` that the store should not be migrated or recreated, and should simply fail on model mismatch
|
||||||
*/
|
*/
|
||||||
public static let none = LocalStorageOptions(rawValue: 0)
|
public static let none: LocalStorageOptions = []
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tells the `DataStack` to delete and recreate the store on model mismatch, otherwise exceptions will be thrown on failure instead
|
Tells the `DataStack` to delete and recreate the store on model mismatch, otherwise exceptions will be thrown on failure instead
|
||||||
*/
|
*/
|
||||||
public static let recreateStoreOnModelMismatch = LocalStorageOptions(rawValue: 1 << 0)
|
public static let recreateStoreOnModelMismatch: LocalStorageOptions = .init(rawValue: 1 << 0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tells the `DataStack` to prevent progressive migrations for the store
|
Tells the `DataStack` to prevent progressive migrations for the store
|
||||||
*/
|
*/
|
||||||
public static let preventProgressiveMigration = LocalStorageOptions(rawValue: 1 << 1)
|
public static let preventProgressiveMigration: LocalStorageOptions = .init(rawValue: 1 << 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tells the `DataStack` to allow lightweight migration for the store when added synchronously
|
Tells the `DataStack` to allow lightweight migration for the store when added synchronously
|
||||||
*/
|
*/
|
||||||
public static let allowSynchronousLightweightMigration = LocalStorageOptions(rawValue: 1 << 2)
|
public static let allowSynchronousLightweightMigration: LocalStorageOptions = .init(rawValue: 1 << 2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -111,12 +111,7 @@ public struct VersionLock: ExpressibleByDictionaryLiteral, Equatable {
|
|||||||
var hashesByEntityName: [EntityName: Data] = [:]
|
var hashesByEntityName: [EntityName: Data] = [:]
|
||||||
for (entityName, intArray) in keyValues {
|
for (entityName, intArray) in keyValues {
|
||||||
|
|
||||||
hashesByEntityName[entityName] = Data(
|
hashesByEntityName[entityName] = intArray.withUnsafeBufferPointer(Data.init(buffer:))
|
||||||
buffer: UnsafeBufferPointer(
|
|
||||||
start: intArray,
|
|
||||||
count: intArray.count
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
self.hashesByEntityName = hashesByEntityName
|
self.hashesByEntityName = hashesByEntityName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,26 @@ public struct Where<O: DynamicObject>: WhereClauseType, FetchClause, QueryClause
|
|||||||
- parameter keyPath: the keyPath to compare with
|
- parameter keyPath: the keyPath to compare with
|
||||||
- parameter value: the arguments for the `==` operator
|
- parameter value: the arguments for the `==` operator
|
||||||
*/
|
*/
|
||||||
|
public init<V: FieldStorableType>(_ keyPath: KeyPathString, isEqualTo value: V) {
|
||||||
|
|
||||||
|
switch value {
|
||||||
|
|
||||||
|
case nil,
|
||||||
|
is NSNull:
|
||||||
|
self.init(NSPredicate(format: "\(keyPath) == nil"))
|
||||||
|
|
||||||
|
case let value:
|
||||||
|
self.init(NSPredicate(format: "\(keyPath) == %@", argumentArray: [value.cs_toFieldStoredNativeType() as Any]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes a `Where` clause that compares equality
|
||||||
|
|
||||||
|
- parameter keyPath: the keyPath to compare with
|
||||||
|
- parameter value: the arguments for the `==` operator
|
||||||
|
*/
|
||||||
|
@_disfavoredOverload
|
||||||
public init<U: QueryableAttributeType>(_ keyPath: KeyPathString, isEqualTo value: U?) {
|
public init<U: QueryableAttributeType>(_ keyPath: KeyPathString, isEqualTo value: U?) {
|
||||||
|
|
||||||
switch value {
|
switch value {
|
||||||
@@ -229,6 +249,18 @@ public struct Where<O: DynamicObject>: WhereClauseType, FetchClause, QueryClause
|
|||||||
- parameter keyPath: the keyPath to compare with
|
- parameter keyPath: the keyPath to compare with
|
||||||
- parameter list: the sequence to check membership of
|
- parameter list: the sequence to check membership of
|
||||||
*/
|
*/
|
||||||
|
public init<S: Sequence>(_ keyPath: KeyPathString, isMemberOf list: S) where S.Iterator.Element: FieldStorableType {
|
||||||
|
|
||||||
|
self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_toFieldStoredNativeType() }) as NSArray))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes a `Where` clause that compares membership
|
||||||
|
|
||||||
|
- parameter keyPath: the keyPath to compare with
|
||||||
|
- parameter list: the sequence to check membership of
|
||||||
|
*/
|
||||||
|
@_disfavoredOverload
|
||||||
public init<S: Sequence>(_ keyPath: KeyPathString, isMemberOf list: S) where S.Iterator.Element: QueryableAttributeType {
|
public init<S: Sequence>(_ keyPath: KeyPathString, isMemberOf list: S) where S.Iterator.Element: QueryableAttributeType {
|
||||||
|
|
||||||
self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_toQueryableNativeType() }) as NSArray))
|
self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_toQueryableNativeType() }) as NSArray))
|
||||||
@@ -409,6 +441,17 @@ extension Where where O: NSManagedObject {
|
|||||||
|
|
||||||
extension Where where O: CoreStoreObject {
|
extension Where where O: CoreStoreObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes a `Where` clause that compares equality
|
||||||
|
|
||||||
|
- parameter keyPath: the keyPath to compare with
|
||||||
|
- parameter value: the arguments for the `==` operator
|
||||||
|
*/
|
||||||
|
public init<V>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, isEqualTo value: V) {
|
||||||
|
|
||||||
|
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initializes a `Where` clause that compares equality to `nil`
|
Initializes a `Where` clause that compares equality to `nil`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user