mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-03-27 11:51:31 +01:00
Field.Relationship propertyWrapper
This commit is contained in:
@@ -613,6 +613,18 @@
|
|||||||
B57D27C21D0BC20100539C58 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27C11D0BC20100539C58 /* QueryTests.swift */; };
|
B57D27C21D0BC20100539C58 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27C11D0BC20100539C58 /* QueryTests.swift */; };
|
||||||
B57D27C31D0BC20100539C58 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27C11D0BC20100539C58 /* QueryTests.swift */; };
|
B57D27C31D0BC20100539C58 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27C11D0BC20100539C58 /* QueryTests.swift */; };
|
||||||
B57D27C41D0BC20100539C58 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27C11D0BC20100539C58 /* QueryTests.swift */; };
|
B57D27C41D0BC20100539C58 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27C11D0BC20100539C58 /* QueryTests.swift */; };
|
||||||
|
B57E6FA223D302FA000FD031 /* Field.Relationship.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA123D302FA000FD031 /* Field.Relationship.swift */; };
|
||||||
|
B57E6FA323D302FA000FD031 /* Field.Relationship.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA123D302FA000FD031 /* Field.Relationship.swift */; };
|
||||||
|
B57E6FA423D302FA000FD031 /* Field.Relationship.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA123D302FA000FD031 /* Field.Relationship.swift */; };
|
||||||
|
B57E6FA523D302FA000FD031 /* Field.Relationship.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA123D302FA000FD031 /* Field.Relationship.swift */; };
|
||||||
|
B57E6FA723D305D6000FD031 /* FIeldRelationshipType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA623D305D6000FD031 /* FIeldRelationshipType.swift */; };
|
||||||
|
B57E6FA823D305D6000FD031 /* FIeldRelationshipType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA623D305D6000FD031 /* FIeldRelationshipType.swift */; };
|
||||||
|
B57E6FA923D305D6000FD031 /* FIeldRelationshipType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA623D305D6000FD031 /* FIeldRelationshipType.swift */; };
|
||||||
|
B57E6FAA23D305D6000FD031 /* FIeldRelationshipType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FA623D305D6000FD031 /* FIeldRelationshipType.swift */; };
|
||||||
|
B57E6FAC23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FAB23D30A5B000FD031 /* FieldRelationshipProtocol.swift */; };
|
||||||
|
B57E6FAD23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FAB23D30A5B000FD031 /* FieldRelationshipProtocol.swift */; };
|
||||||
|
B57E6FAE23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FAB23D30A5B000FD031 /* FieldRelationshipProtocol.swift */; };
|
||||||
|
B57E6FAF23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57E6FAB23D30A5B000FD031 /* FieldRelationshipProtocol.swift */; };
|
||||||
B580857A1CDF808C004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
B580857A1CDF808C004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
||||||
B580857B1CDF808D004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
B580857B1CDF808D004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
||||||
B580857C1CDF808F004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
B580857C1CDF808F004C2EEB /* SetupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58085741CDF7F00004C2EEB /* SetupTests.swift */; };
|
||||||
@@ -1113,6 +1125,9 @@
|
|||||||
B56E4EE323CEDF0900E1708C /* Field.Computed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Computed.swift; sourceTree = "<group>"; };
|
B56E4EE323CEDF0900E1708C /* Field.Computed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Computed.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>"; };
|
||||||
|
B57E6FA123D302FA000FD031 /* Field.Relationship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Field.Relationship.swift; sourceTree = "<group>"; };
|
||||||
|
B57E6FA623D305D6000FD031 /* FIeldRelationshipType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FIeldRelationshipType.swift; sourceTree = "<group>"; };
|
||||||
|
B57E6FAB23D30A5B000FD031 /* FieldRelationshipProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldRelationshipProtocol.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>"; };
|
||||||
B581B9312362BB8C002BDB2B /* ObjectPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectPublisherTests.swift; sourceTree = "<group>"; };
|
B581B9312362BB8C002BDB2B /* ObjectPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectPublisherTests.swift; sourceTree = "<group>"; };
|
||||||
B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributeProtocol.swift; sourceTree = "<group>"; };
|
B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributeProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -1461,6 +1476,7 @@
|
|||||||
B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */,
|
B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */,
|
||||||
B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */,
|
B56E4ED323CDB54A00E1708C /* FieldProtocol.swift */,
|
||||||
B50C3ED923D0545700B29880 /* FieldAttributeProtocol.swift */,
|
B50C3ED923D0545700B29880 /* FieldAttributeProtocol.swift */,
|
||||||
|
B57E6FAB23D30A5B000FD031 /* FieldRelationshipProtocol.swift */,
|
||||||
B50564D22350CC3100482308 /* PropertyProtocol.swift */,
|
B50564D22350CC3100482308 /* PropertyProtocol.swift */,
|
||||||
B53D9E5823513712000F48FB /* DiffableDataSourceSnapshotProtocol.swift */,
|
B53D9E5823513712000F48FB /* DiffableDataSourceSnapshotProtocol.swift */,
|
||||||
B50E175623517DE4004F033C /* Differentiable.swift */,
|
B50E175623517DE4004F033C /* Differentiable.swift */,
|
||||||
@@ -1608,6 +1624,7 @@
|
|||||||
B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */,
|
B56E4ECE23CD9E4200E1708C /* Field.Stored.swift */,
|
||||||
B56E4EE323CEDF0900E1708C /* Field.Computed.swift */,
|
B56E4EE323CEDF0900E1708C /* Field.Computed.swift */,
|
||||||
B50C3EE423D153EA00B29880 /* Field.Coded.swift */,
|
B50C3EE423D153EA00B29880 /* Field.Coded.swift */,
|
||||||
|
B57E6FA123D302FA000FD031 /* Field.Relationship.swift */,
|
||||||
B50C3EDE23D05BB200B29880 /* Coders */,
|
B50C3EDE23D05BB200B29880 /* Coders */,
|
||||||
B56E4EDD23CEBB0400E1708C /* Supported Values */,
|
B56E4EDD23CEBB0400E1708C /* Supported Values */,
|
||||||
);
|
);
|
||||||
@@ -1619,6 +1636,7 @@
|
|||||||
children = (
|
children = (
|
||||||
B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */,
|
B56E4EDE23CEBCF000E1708C /* FieldOptionalType.swift */,
|
||||||
B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */,
|
B56E4ED823CEB8E700E1708C /* FieldStorableType.swift */,
|
||||||
|
B57E6FA623D305D6000FD031 /* FIeldRelationshipType.swift */,
|
||||||
);
|
);
|
||||||
name = "Supported Values";
|
name = "Supported Values";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -2301,6 +2319,7 @@
|
|||||||
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
B5C976E31C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
|
||||||
B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
B53FBA121CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||||
B5831B751F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
B5831B751F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
|
B57E6FA723D305D6000FD031 /* FIeldRelationshipType.swift in Sources */,
|
||||||
B51B5C2D22D43E38009FA3BA /* KeyPath+KeyPaths.swift in Sources */,
|
B51B5C2D22D43E38009FA3BA /* KeyPath+KeyPaths.swift in Sources */,
|
||||||
B50564D32350CC3100482308 /* PropertyProtocol.swift in Sources */,
|
B50564D32350CC3100482308 /* PropertyProtocol.swift in Sources */,
|
||||||
B5D8CA762346E7590055D7D1 /* DataStack+DataSources.swift in Sources */,
|
B5D8CA762346E7590055D7D1 /* DataStack+DataSources.swift in Sources */,
|
||||||
@@ -2435,6 +2454,7 @@
|
|||||||
B5A991EC1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
|
B5A991EC1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
|
||||||
B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
|
||||||
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
|
||||||
|
B57E6FA223D302FA000FD031 /* Field.Relationship.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 */,
|
B56E4ED923CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
@@ -2446,6 +2466,7 @@
|
|||||||
B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */,
|
B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */,
|
||||||
B5E84EE61AFF84610064E85B /* DefaultLogger.swift in Sources */,
|
B5E84EE61AFF84610064E85B /* DefaultLogger.swift in Sources */,
|
||||||
B53FBA041CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
B53FBA041CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
|
||||||
|
B57E6FAC23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */,
|
||||||
B509D7C923C8491C00F42824 /* Relationship.ToManyOrdered.swift in Sources */,
|
B509D7C923C8491C00F42824 /* Relationship.ToManyOrdered.swift in Sources */,
|
||||||
B5E84EF41AFF846E0064E85B /* AsynchronousDataTransaction.swift in Sources */,
|
B5E84EF41AFF846E0064E85B /* AsynchronousDataTransaction.swift in Sources */,
|
||||||
B50C3EEF23D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
B50C3EEF23D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
||||||
@@ -2549,6 +2570,7 @@
|
|||||||
B53FBA141CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
B53FBA141CAB63CB00F0D40A /* Progress+ObjectiveC.swift in Sources */,
|
||||||
B5831B761F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
B5831B761F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
B5BF7FB3234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
B5BF7FB3234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
||||||
|
B57E6FA823D305D6000FD031 /* FIeldRelationshipType.swift in Sources */,
|
||||||
B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
B5E1B5AA1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||||
B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F21E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
B5E1B59F1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
B5E1B59F1CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
||||||
@@ -2683,6 +2705,7 @@
|
|||||||
B5AA37F2235C28EE00FFD4B9 /* DiffableDataSource.CollectionViewAdapter-AppKit.swift in Sources */,
|
B5AA37F2235C28EE00FFD4B9 /* DiffableDataSource.CollectionViewAdapter-AppKit.swift in Sources */,
|
||||||
B50E175D2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
B50E175D2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
||||||
B5474D162227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
B5474D162227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
||||||
|
B57E6FA323D302FA000FD031 /* Field.Relationship.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 */,
|
B56E4EDA23CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
@@ -2694,6 +2717,7 @@
|
|||||||
82BA18BE1C4BBD4A00A0916E /* Tweak.swift in Sources */,
|
82BA18BE1C4BBD4A00A0916E /* Tweak.swift in Sources */,
|
||||||
B509D7C523C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
B509D7C523C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
||||||
B5DBE2CE1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
B5DBE2CE1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
||||||
|
B57E6FAD23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */,
|
||||||
B5831B711F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
B5831B711F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
||||||
B546F95E1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
B546F95E1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
||||||
B50C3EF023D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
B50C3EF023D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
||||||
@@ -2797,6 +2821,7 @@
|
|||||||
B5BF7FCE234D80910070E741 /* Internals.LazyNonmutating.swift in Sources */,
|
B5BF7FCE234D80910070E741 /* Internals.LazyNonmutating.swift in Sources */,
|
||||||
B52DD19E1BE1F92C00949AFE /* AsynchronousDataTransaction.swift in Sources */,
|
B52DD19E1BE1F92C00949AFE /* AsynchronousDataTransaction.swift in Sources */,
|
||||||
B50564D62350CC3100482308 /* PropertyProtocol.swift in Sources */,
|
B50564D62350CC3100482308 /* PropertyProtocol.swift in Sources */,
|
||||||
|
B57E6FAA23D305D6000FD031 /* FIeldRelationshipType.swift in Sources */,
|
||||||
B5831B781F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
B5831B781F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
|
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
|
||||||
B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F41E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
@@ -2931,6 +2956,7 @@
|
|||||||
18166886232B9ED20097C275 /* KeyPath+KeyPaths.swift in Sources */,
|
18166886232B9ED20097C275 /* KeyPath+KeyPaths.swift in Sources */,
|
||||||
B5E8A72321C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
|
B5E8A72321C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
|
||||||
B50E175F2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
B50E175F2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
||||||
|
B57E6FA523D302FA000FD031 /* Field.Relationship.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 */,
|
B56E4EDC23CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
@@ -2942,6 +2968,7 @@
|
|||||||
B52DD1B91BE1F94000949AFE /* CoreStore+Migration.swift in Sources */,
|
B52DD1B91BE1F94000949AFE /* CoreStore+Migration.swift in Sources */,
|
||||||
B509D7C723C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
B509D7C723C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
||||||
B5519A5C1CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */,
|
B5519A5C1CA2008C002BEF78 /* CSBaseDataTransaction.swift in Sources */,
|
||||||
|
B57E6FAF23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */,
|
||||||
B5DBE2D51C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
B5DBE2D51C991B3E00B5CEFA /* CSDataStack.swift in Sources */,
|
||||||
B5831B731F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
B5831B731F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
||||||
B50C3EF223D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
B50C3EF223D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
||||||
@@ -3045,6 +3072,7 @@
|
|||||||
B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
B5E1B5AB1CAA49E2007FD580 /* CSDataStack+Migrating.swift in Sources */,
|
||||||
B5831B771F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
B5831B771F34AC7A00A9F647 /* RelationshipProtocol.swift in Sources */,
|
||||||
B5BF7FB4234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
B5BF7FB4234C97910070E741 /* DiffableDataSource.swift in Sources */,
|
||||||
|
B57E6FA923D305D6000FD031 /* FIeldRelationshipType.swift in Sources */,
|
||||||
B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
B5D339F31E94AF5800C880DE /* CoreStoreStrings.swift in Sources */,
|
||||||
B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
B5E1B5A01CAA2568007FD580 /* CSDataStack+Observing.swift in Sources */,
|
||||||
B5ECDC261CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
B5ECDC261CA81A3900C7F112 /* CSCoreStore+Querying.swift in Sources */,
|
||||||
@@ -3179,6 +3207,7 @@
|
|||||||
B5AA37F3235C28EE00FFD4B9 /* DiffableDataSource.CollectionViewAdapter-AppKit.swift in Sources */,
|
B5AA37F3235C28EE00FFD4B9 /* DiffableDataSource.CollectionViewAdapter-AppKit.swift in Sources */,
|
||||||
B50E175E2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
B50E175E2351848E004F033C /* Internals.DiffableDataUIDispatcher.DiffResult.swift in Sources */,
|
||||||
B5474D172227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
B5474D172227C08700B21FEC /* Internals.CoreStoreFetchRequest.swift in Sources */,
|
||||||
|
B57E6FA423D302FA000FD031 /* Field.Relationship.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 */,
|
B56E4EDB23CEB8E700E1708C /* FieldStorableType.swift in Sources */,
|
||||||
@@ -3190,6 +3219,7 @@
|
|||||||
B56321841BD65216006C9394 /* DefaultLogger.swift in Sources */,
|
B56321841BD65216006C9394 /* DefaultLogger.swift in Sources */,
|
||||||
B509D7C623C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
B509D7C623C848DA00F42824 /* Relationship.ToOne.swift in Sources */,
|
||||||
B5DBE2CF1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
B5DBE2CF1C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
|
||||||
|
B57E6FAE23D30A5B000FD031 /* FieldRelationshipProtocol.swift in Sources */,
|
||||||
B5831B721F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
B5831B721F34AC3400A9F647 /* AttributeProtocol.swift in Sources */,
|
||||||
B546F95F1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
B546F95F1C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
|
||||||
B50C3EF123D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
B50C3EF123D1605C00B29880 /* FieldCoders.DefaultNSSecureCoding.swift in Sources */,
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ class Animal: CoreStoreObject {
|
|||||||
@Field.Coded("color", coder: FieldCoders.NSCoding.self)
|
@Field.Coded("color", coder: FieldCoders.NSCoding.self)
|
||||||
var color: Color? = .blue
|
var color: Color? = .blue
|
||||||
|
|
||||||
let master = Relationship.ToOne<Person>("master")
|
@Field.Relationship("master")
|
||||||
|
var master: Person?
|
||||||
}
|
}
|
||||||
|
|
||||||
class Dog: Animal {
|
class Dog: Animal {
|
||||||
@@ -52,15 +53,45 @@ class Dog: Animal {
|
|||||||
@Field.Stored("nickname")
|
@Field.Stored("nickname")
|
||||||
var nickname: String?
|
var nickname: String?
|
||||||
|
|
||||||
let age = Value.Required<Int>("age", initial: 1)
|
@Field.Stored("age")
|
||||||
let friends = Relationship.ToManyOrdered<Dog>("friends")
|
var age: Int = 1
|
||||||
let friendedBy = Relationship.ToManyUnordered<Dog>("friendedBy", inverse: { $0.friends })
|
|
||||||
|
@Field.Relationship("friends")
|
||||||
|
var friends: [Dog]
|
||||||
|
|
||||||
|
@Field.Relationship("friendedBy", inverse: \.$friends)
|
||||||
|
var friendedBy: Set<Dog>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomType {
|
struct CustomType {
|
||||||
var string = "customString"
|
var string = "customString"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Job: String {
|
||||||
|
|
||||||
|
case unemployed
|
||||||
|
case engineer
|
||||||
|
case doctor
|
||||||
|
case lawyer
|
||||||
|
|
||||||
|
init?(data: Data) {
|
||||||
|
|
||||||
|
guard
|
||||||
|
let rawValue = String(data: data, encoding: .utf8),
|
||||||
|
let value = Self.init(rawValue: rawValue)
|
||||||
|
else {
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
self = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func toData() -> Data {
|
||||||
|
|
||||||
|
return Data(self.rawValue.utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Person: CoreStoreObject {
|
class Person: CoreStoreObject {
|
||||||
|
|
||||||
@Field.Stored("title", customSetter: Person.setTitle(_:_:))
|
@Field.Stored("title", customSetter: Person.setTitle(_:_:))
|
||||||
@@ -84,47 +115,25 @@ class Person: CoreStoreObject {
|
|||||||
|
|
||||||
@Field.Coded(
|
@Field.Coded(
|
||||||
"job", coder: (
|
"job", coder: (
|
||||||
encode: { $0.data },
|
encode: { $0.toData() },
|
||||||
decode: { $0.flatMap(Job.init(data:)) ?? .unemployed }
|
decode: { $0.flatMap(Job.init(data:)) ?? .unemployed }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
var job: Job = .unemployed
|
var job: Job = .unemployed
|
||||||
|
|
||||||
let spouse = Relationship.ToOne<Person>("spouse")
|
@Field.Relationship("spouse")
|
||||||
|
var spouse: Person?
|
||||||
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
|
|
||||||
|
|
||||||
private let _spouse = Relationship.ToOne<Person>("_spouseInverse", inverse: { $0.spouse })
|
@Field.Relationship("pets", inverse: \.$master)
|
||||||
|
var pets: Set<Animal>
|
||||||
|
|
||||||
enum Job: String {
|
@Field.Relationship("_spouseInverse", inverse: \.$spouse)
|
||||||
|
private var spouseInverse: Person?
|
||||||
case unemployed
|
|
||||||
case engineer
|
|
||||||
case doctor
|
|
||||||
case lawyer
|
|
||||||
|
|
||||||
init?(data: Data) {
|
|
||||||
|
|
||||||
guard
|
|
||||||
let rawValue = String(data: data, encoding: .utf8),
|
|
||||||
let value = Self.init(rawValue: rawValue)
|
|
||||||
else {
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
self = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var data: Data {
|
|
||||||
|
|
||||||
return Data(self.rawValue.utf8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func setTitle(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
private static func setTitle(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
||||||
|
|
||||||
partialObject.setPrimitiveValue(newValue, for: \.$title)
|
partialObject.setPrimitiveValue(newValue, for: \.$title)
|
||||||
partialObject.setPrimitiveValue(nil, for: { $0.$displayName })
|
partialObject.setPrimitiveValue(nil, for: \.$displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func setName(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
private static func setName(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
||||||
@@ -226,8 +235,8 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
case String(keyPath: \Animal.$species):
|
case String(keyPath: \Animal.$species):
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Stored<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 FieldContainer<Animal>.Relationship<Person?>)
|
||||||
|
|
||||||
case String(keyPath: \Animal.$color):
|
case String(keyPath: \Animal.$color):
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
|
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
|
||||||
@@ -240,7 +249,7 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
let dog = transaction.create(Into<Dog>())
|
let dog = transaction.create(Into<Dog>())
|
||||||
XCTAssertEqual(dog.species, "Swift")
|
XCTAssertEqual(dog.species, "Swift")
|
||||||
XCTAssertEqual(dog.nickname, nil)
|
XCTAssertEqual(dog.nickname, nil)
|
||||||
XCTAssertEqual(dog.age.value, 1)
|
XCTAssertEqual(dog.age, 1)
|
||||||
|
|
||||||
for property in Dog.metaProperties(includeSuperclasses: true) {
|
for property in Dog.metaProperties(includeSuperclasses: true) {
|
||||||
|
|
||||||
@@ -249,8 +258,8 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
case String(keyPath: \Dog.$species):
|
case String(keyPath: \Dog.$species):
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Stored<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 FieldContainer<Animal>.Relationship<Person?>)
|
||||||
|
|
||||||
case String(keyPath: \Dog.$color):
|
case String(keyPath: \Dog.$color):
|
||||||
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
|
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
|
||||||
@@ -258,14 +267,14 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
case String(keyPath: \Dog.$nickname):
|
case String(keyPath: \Dog.$nickname):
|
||||||
XCTAssertTrue(property is FieldContainer<Dog>.Stored<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 FieldContainer<Dog>.Stored<Int>)
|
||||||
|
|
||||||
case String(keyPath: \Dog.friends):
|
case String(keyPath: \Dog.$friends):
|
||||||
XCTAssertTrue(property is RelationshipContainer<Dog>.ToManyOrdered<Dog>)
|
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<[Dog]>)
|
||||||
|
|
||||||
case String(keyPath: \Dog.friendedBy):
|
case String(keyPath: \Dog.$friendedBy):
|
||||||
XCTAssertTrue(property is RelationshipContainer<Dog>.ToManyUnordered<Dog>)
|
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<Set<Dog>>)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
|
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
|
||||||
@@ -325,7 +334,7 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
XCTAssertEqual(dog.nickname, "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.isEmpty)
|
||||||
XCTAssertEqual(person.customField.string, "customString")
|
XCTAssertEqual(person.customField.string, "customString")
|
||||||
XCTAssertEqual(person.job, .unemployed)
|
XCTAssertEqual(person.job, .unemployed)
|
||||||
|
|
||||||
@@ -382,12 +391,12 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
person.pets.value.insert(dog)
|
person.pets.insert(dog)
|
||||||
XCTAssertEqual(person.pets.count, 1)
|
XCTAssertEqual(person.pets.count, 1)
|
||||||
XCTAssertEqual(person.pets.value.first, dog)
|
XCTAssertEqual(person.pets.first, dog)
|
||||||
XCTAssertEqual(person.pets.value.first?.master.value, person)
|
XCTAssertEqual(person.pets.first?.master, person)
|
||||||
XCTAssertEqual(dog.master.value, person)
|
XCTAssertEqual(dog.master, person)
|
||||||
XCTAssertEqual(dog.master.value?.pets.value.first, dog)
|
XCTAssertEqual(dog.master?.pets.first, dog)
|
||||||
},
|
},
|
||||||
success: { _ in
|
success: { _ in
|
||||||
|
|
||||||
@@ -424,42 +433,44 @@ class DynamicModelTests: BaseTestDataTestCase {
|
|||||||
XCTAssertEqual(person!.displayName, "Sir John")
|
XCTAssertEqual(person!.displayName, "Sir John")
|
||||||
XCTAssertEqual(person!.customField.string, "customString")
|
XCTAssertEqual(person!.customField.string, "customString")
|
||||||
XCTAssertEqual(person!.job, .engineer)
|
XCTAssertEqual(person!.job, .engineer)
|
||||||
XCTAssertEqual(person!.pets.value.first, dog)
|
XCTAssertEqual(person!.pets.first, dog)
|
||||||
|
|
||||||
let p3 = Where<Dog>({ $0.age == 10 })
|
let p3 = Where<Dog>({ $0.$age == 10 })
|
||||||
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
|
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
|
||||||
|
|
||||||
let totalAge = try transaction.queryValue(From<Dog>().select(Int.self, .sum(\Dog.age)))
|
let totalAge = try transaction.queryValue(
|
||||||
|
From<Dog>().select(Int.self, .sum(\.$age))
|
||||||
|
)
|
||||||
XCTAssertEqual(totalAge, 1)
|
XCTAssertEqual(totalAge, 1)
|
||||||
|
|
||||||
_ = 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>(),
|
||||||
Where<Dog>({ $0.age > 10 && $0.age <= 15 })
|
Where<Dog>({ $0.$age > 10 && $0.$age <= 15 })
|
||||||
)
|
)
|
||||||
_ = 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>(),
|
||||||
Where<Dog>({ $0.age > 10 && $0.age <= 15 })
|
Where<Dog>({ $0.$age > 10 && $0.$age <= 15 })
|
||||||
)
|
)
|
||||||
_ = try transaction.fetchAll(
|
_ = try transaction.fetchAll(
|
||||||
From<Dog>(),
|
From<Dog>(),
|
||||||
(\Dog.age > 10 && \Dog.age <= 15)
|
(\Dog.$age > 10 && \Dog.$age <= 15)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
success: { _ in
|
success: { _ in
|
||||||
|
|||||||
@@ -104,18 +104,18 @@ final class WhereTests: XCTestCase {
|
|||||||
|
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"master.pets",
|
"master.pets",
|
||||||
(\Animal.master ~ \.pets).description,
|
(\Animal.$master ~ \.$pets).description,
|
||||||
String(keyPath: \Animal.master ~ \.pets)
|
String(keyPath: \Animal.$master ~ \.$pets)
|
||||||
)
|
)
|
||||||
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",
|
||||||
(\Animal.master ~ \.pets ~ \.master).description,
|
(\Animal.$master ~ \.$pets ~ \.$master).description,
|
||||||
String(keyPath: \Animal.master ~ \.pets ~ \.master)
|
String(keyPath: \Animal.$master ~ \.$pets ~ \.$master)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,8 +138,8 @@ final class WhereTests: XCTestCase {
|
|||||||
|
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"master.pets.@count",
|
"master.pets.@count",
|
||||||
(\Animal.master ~ \.pets).count().description,
|
(\Animal.$master ~ \.$pets).count().description,
|
||||||
String(keyPath: (\Animal.master ~ \.pets).count())
|
String(keyPath: (\Animal.$master ~ \.$pets).count())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,13 +162,13 @@ final class WhereTests: XCTestCase {
|
|||||||
|
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"ANY master.pets",
|
"ANY master.pets",
|
||||||
(\Animal.master ~ \.pets).any().description,
|
(\Animal.$master ~ \.$pets).any().description,
|
||||||
String(keyPath: (\Animal.master ~ \.pets).any())
|
String(keyPath: (\Animal.$master ~ \.$pets).any())
|
||||||
)
|
)
|
||||||
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())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,13 +191,13 @@ final class WhereTests: XCTestCase {
|
|||||||
|
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"ALL master.pets",
|
"ALL master.pets",
|
||||||
(\Animal.master ~ \.pets).all().description,
|
(\Animal.$master ~ \.$pets).all().description,
|
||||||
String(keyPath: (\Animal.master ~ \.pets).all())
|
String(keyPath: (\Animal.$master ~ \.$pets).all())
|
||||||
)
|
)
|
||||||
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())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,13 +220,13 @@ final class WhereTests: XCTestCase {
|
|||||||
|
|
||||||
XCTAssertAllEqual(
|
XCTAssertAllEqual(
|
||||||
"NONE master.pets",
|
"NONE master.pets",
|
||||||
(\Animal.master ~ \.pets).none().description,
|
(\Animal.$master ~ \.$pets).none().description,
|
||||||
String(keyPath: (\Animal.master ~ \.pets).none())
|
String(keyPath: (\Animal.$master ~ \.$pets).none())
|
||||||
)
|
)
|
||||||
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)
|
||||||
@@ -283,7 +283,7 @@ final class WhereTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
||||||
let whereClause: Where<Animal> = (\.master ~ \.pets).count() == count
|
let whereClause: Where<Animal> = (\.$master ~ \.$pets).count() == count
|
||||||
let predicate = NSPredicate(format: "master.pets.@count == %d", count)
|
let predicate = NSPredicate(format: "master.pets.@count == %d", count)
|
||||||
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)
|
||||||
|
|||||||
@@ -339,6 +339,23 @@ public final class CoreStoreSchema: DynamicSchema {
|
|||||||
keyPathsByAffectedKeyPaths[attribute.keyPath] = entityDescriptionValues.affectedByKeyPaths
|
keyPathsByAffectedKeyPaths[attribute.keyPath] = entityDescriptionValues.affectedByKeyPaths
|
||||||
customGetterSetterByKeyPaths[attribute.keyPath] = (attribute.getter, attribute.setter)
|
customGetterSetterByKeyPaths[attribute.keyPath] = (attribute.getter, attribute.setter)
|
||||||
fieldCoders[attribute.keyPath] = valueTransformer
|
fieldCoders[attribute.keyPath] = valueTransformer
|
||||||
|
|
||||||
|
case let relationship as FieldRelationshipProtocol:
|
||||||
|
Internals.assert(
|
||||||
|
!NSManagedObject.instancesRespond(to: Selector(relationship.keyPath)),
|
||||||
|
"Relationship Property name \"\(String(reflecting: entity.type)).\(relationship.keyPath)\" is not allowed because it collides with \"\(String(reflecting: NSManagedObject.self)).\(relationship.keyPath)\""
|
||||||
|
)
|
||||||
|
let entityDescriptionValues = relationship.entityDescriptionValues()
|
||||||
|
let description = NSRelationshipDescription()
|
||||||
|
description.name = relationship.keyPath
|
||||||
|
description.minCount = entityDescriptionValues.minCount
|
||||||
|
description.maxCount = entityDescriptionValues.maxCount
|
||||||
|
description.isOrdered = entityDescriptionValues.isOrdered
|
||||||
|
description.deleteRule = entityDescriptionValues.deleteRule
|
||||||
|
description.versionHashModifier = entityDescriptionValues.versionHashModifier
|
||||||
|
description.renamingIdentifier = entityDescriptionValues.renamingIdentifier
|
||||||
|
propertyDescriptions.append(description)
|
||||||
|
keyPathsByAffectedKeyPaths[relationship.keyPath] = entityDescriptionValues.affectedByKeyPaths
|
||||||
|
|
||||||
case let attribute as AttributeProtocol:
|
case let attribute as AttributeProtocol:
|
||||||
Internals.assert(
|
Internals.assert(
|
||||||
@@ -437,6 +454,26 @@ public final class CoreStoreSchema: DynamicSchema {
|
|||||||
for property in entityType.metaProperties(includeSuperclasses: false) {
|
for property in entityType.metaProperties(includeSuperclasses: false) {
|
||||||
|
|
||||||
switch property {
|
switch property {
|
||||||
|
|
||||||
|
case let relationship as FieldRelationshipProtocol:
|
||||||
|
let (destinationType, destinationKeyPath) = relationship.entityDescriptionValues().inverse
|
||||||
|
let destinationEntity = findEntity(for: destinationType)
|
||||||
|
let description = relationshipsByName[relationship.keyPath]!
|
||||||
|
description.destinationEntity = entityDescriptionsByEntity[destinationEntity]!
|
||||||
|
|
||||||
|
if let destinationKeyPath = destinationKeyPath {
|
||||||
|
|
||||||
|
let inverseRelationshipDescription = findInverseRelationshipMatching(
|
||||||
|
destinationEntity: destinationEntity,
|
||||||
|
destinationKeyPath: destinationKeyPath
|
||||||
|
)
|
||||||
|
description.inverseRelationship = inverseRelationshipDescription
|
||||||
|
|
||||||
|
inverseRelationshipDescription.inverseRelationship = description
|
||||||
|
inverseRelationshipDescription.destinationEntity = entityDescription
|
||||||
|
|
||||||
|
description.destinationEntity!.properties = description.destinationEntity!.properties
|
||||||
|
}
|
||||||
|
|
||||||
case let relationship as RelationshipProtocol:
|
case let relationship as RelationshipProtocol:
|
||||||
let (destinationType, destinationKeyPath) = relationship.entityDescriptionValues().inverse
|
let (destinationType, destinationKeyPath) = relationship.entityDescriptionValues().inverse
|
||||||
|
|||||||
@@ -173,6 +173,9 @@ extension CoreStoreObject {
|
|||||||
case let property as FieldAttributeProtocol:
|
case let property as FieldAttributeProtocol:
|
||||||
attributes[property.keyPath] = type(of: property).read(field: property, for: object.rawObject!)
|
attributes[property.keyPath] = type(of: property).read(field: property, for: object.rawObject!)
|
||||||
|
|
||||||
|
case let property as FieldRelationshipProtocol:
|
||||||
|
attributes[property.keyPath] = type(of: property).valueForSnapshot(field: property, for: object.rawObject!)
|
||||||
|
|
||||||
case let property as AttributeProtocol:
|
case let property as AttributeProtocol:
|
||||||
attributes[property.keyPath] = property.valueForSnapshot
|
attributes[property.keyPath] = property.valueForSnapshot
|
||||||
|
|
||||||
|
|||||||
142
Sources/FIeldRelationshipType.swift
Normal file
142
Sources/FIeldRelationshipType.swift
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
//
|
||||||
|
// FIeldRelationshipType.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: - FieldRelationshipType
|
||||||
|
|
||||||
|
public protocol FieldRelationshipType {
|
||||||
|
|
||||||
|
associatedtype DestinationObjectType: CoreStoreObject
|
||||||
|
|
||||||
|
associatedtype NativeValueType: AnyObject
|
||||||
|
|
||||||
|
associatedtype SnapshotValueType
|
||||||
|
|
||||||
|
static func cs_toReturnType(from value: NativeValueType?) -> Self
|
||||||
|
|
||||||
|
static func cs_toNativeType(from value: Self) -> NativeValueType?
|
||||||
|
|
||||||
|
static func cs_valueForSnapshot(from value: NativeValueType?) -> SnapshotValueType
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol FieldRelationshipToOneType: FieldRelationshipType {}
|
||||||
|
|
||||||
|
|
||||||
|
public protocol FieldRelationshipToManyType: FieldRelationshipType where Self: Sequence {}
|
||||||
|
public protocol FieldRelationshipToManyOrderedType: FieldRelationshipToManyType {}
|
||||||
|
public protocol FieldRelationshipToManyUnorderedType: FieldRelationshipToManyType {}
|
||||||
|
|
||||||
|
|
||||||
|
extension Optional: FieldRelationshipType, FieldRelationshipToOneType where Wrapped: CoreStoreObject {
|
||||||
|
|
||||||
|
public typealias DestinationObjectType = Wrapped
|
||||||
|
|
||||||
|
public typealias NativeValueType = NSManagedObject
|
||||||
|
|
||||||
|
public typealias SnapshotValueType = NSManagedObjectID?
|
||||||
|
|
||||||
|
public static func cs_toReturnType(from value: NativeValueType?) -> Self {
|
||||||
|
|
||||||
|
return value.map(Wrapped.cs_fromRaw(object:))
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func cs_toNativeType(from value: Self) -> NativeValueType? {
|
||||||
|
|
||||||
|
return value?.cs_toRaw()
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func cs_valueForSnapshot(from value: NativeValueType?) -> SnapshotValueType {
|
||||||
|
|
||||||
|
return value?.objectID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension Array: FieldRelationshipType, FieldRelationshipToManyType, FieldRelationshipToManyOrderedType where Element: CoreStoreObject {
|
||||||
|
|
||||||
|
public typealias DestinationObjectType = Element
|
||||||
|
|
||||||
|
public typealias NativeValueType = NSOrderedSet
|
||||||
|
|
||||||
|
public typealias SnapshotValueType = [NSManagedObjectID]
|
||||||
|
|
||||||
|
public static func cs_toReturnType(from value: NativeValueType?) -> Self {
|
||||||
|
|
||||||
|
guard let value = value else {
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return value.map({ Element.cs_fromRaw(object: $0 as! NSManagedObject) })
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func cs_toNativeType(from value: Self) -> NativeValueType? {
|
||||||
|
|
||||||
|
return NSOrderedSet(array: value.map({ $0.rawObject! }))
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func cs_valueForSnapshot(from value: NativeValueType?) -> SnapshotValueType {
|
||||||
|
|
||||||
|
guard let value = value else {
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return value.map({ ($0 as! NSManagedObject).objectID })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Set: FieldRelationshipType, FieldRelationshipToManyType, FieldRelationshipToManyUnorderedType where Element: CoreStoreObject {
|
||||||
|
|
||||||
|
public typealias DestinationObjectType = Element
|
||||||
|
|
||||||
|
public typealias NativeValueType = NSSet
|
||||||
|
|
||||||
|
public typealias SnapshotValueType = Set<NSManagedObjectID>
|
||||||
|
|
||||||
|
public static func cs_toReturnType(from value: NativeValueType?) -> Self {
|
||||||
|
|
||||||
|
guard let value = value else {
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return Set(value.map({ Element.cs_fromRaw(object: $0 as! NSManagedObject) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func cs_toNativeType(from value: Self) -> NativeValueType? {
|
||||||
|
|
||||||
|
return NSSet(array: value.map({ $0.rawObject! }))
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func cs_valueForSnapshot(from value: NativeValueType?) -> SnapshotValueType {
|
||||||
|
|
||||||
|
guard let value = value else {
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return .init(value.map({ ($0 as! NSManagedObject).objectID }))
|
||||||
|
}
|
||||||
|
}
|
||||||
346
Sources/Field.Relationship.swift
Normal file
346
Sources/Field.Relationship.swift
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
//
|
||||||
|
// Field.ToOne.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: - Relationship
|
||||||
|
|
||||||
|
@propertyWrapper
|
||||||
|
// @dynamicMemberLookup
|
||||||
|
public struct Relationship<V: FieldRelationshipType>: RelationshipKeyPathStringConvertible, FieldRelationshipProtocol {
|
||||||
|
|
||||||
|
public typealias DeleteRule = RelationshipContainer<O>.DeleteRule
|
||||||
|
|
||||||
|
|
||||||
|
// 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.DestinationObjectType
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: RelationshipKeyPathStringConvertible
|
||||||
|
|
||||||
|
public typealias ReturnValueType = V
|
||||||
|
|
||||||
|
|
||||||
|
// 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
|
||||||
|
let keyPath = field.keyPath
|
||||||
|
return V.cs_toReturnType(
|
||||||
|
from: rawObject.value(forKey: keyPath) as! V.NativeValueType?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
return rawObject.setValue(
|
||||||
|
V.cs_toNativeType(from: newValue),
|
||||||
|
forKey: keyPath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FieldRelationshipProtocol
|
||||||
|
|
||||||
|
internal let entityDescriptionValues: () -> FieldRelationshipProtocol.EntityDescriptionValues
|
||||||
|
|
||||||
|
internal static func valueForSnapshot(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
|
||||||
|
let keyPath = field.keyPath
|
||||||
|
return V.cs_valueForSnapshot(
|
||||||
|
from: rawObject.value(forKey: keyPath) as! V.NativeValueType?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: FilePrivate
|
||||||
|
|
||||||
|
fileprivate init(
|
||||||
|
keyPath: KeyPathString,
|
||||||
|
isToMany: Bool,
|
||||||
|
isOrdered: Bool,
|
||||||
|
deleteRule: DeleteRule,
|
||||||
|
inverseKeyPath: @escaping () -> KeyPathString?,
|
||||||
|
versionHashModifier: @escaping () -> String?,
|
||||||
|
renamingIdentifier: @escaping () -> String?,
|
||||||
|
affectedByKeyPaths: @escaping () -> Set<KeyPathString>,
|
||||||
|
minCount: Int,
|
||||||
|
maxCount: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
self.keyPath = keyPath
|
||||||
|
self.entityDescriptionValues = {
|
||||||
|
|
||||||
|
let range = (Swift.max(0, minCount) ... maxCount)
|
||||||
|
return (
|
||||||
|
isToMany: isToMany,
|
||||||
|
isOrdered: isOrdered,
|
||||||
|
deleteRule: deleteRule.nativeValue,
|
||||||
|
inverse: (type: V.DestinationObjectType.self, keyPath: inverseKeyPath()),
|
||||||
|
versionHashModifier: versionHashModifier(),
|
||||||
|
renamingIdentifier: renamingIdentifier(),
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths(),
|
||||||
|
minCount: range.lowerBound,
|
||||||
|
maxCount: range.upperBound
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FieldContainer.Relationship where V: FieldRelationshipToOneType {
|
||||||
|
|
||||||
|
public init(
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
deleteRule: DeleteRule = .nullify,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
previousVersionKeyPath: @autoclosure @escaping () -> String? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<KeyPathString> = []
|
||||||
|
) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath: keyPath,
|
||||||
|
isToMany: false,
|
||||||
|
isOrdered: false,
|
||||||
|
deleteRule: deleteRule,
|
||||||
|
inverseKeyPath: { nil },
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: previousVersionKeyPath,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths,
|
||||||
|
minCount: 0,
|
||||||
|
maxCount: 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init<D>(
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
inverse: KeyPath<V.DestinationObjectType, FieldContainer<V.DestinationObjectType>.Relationship<D>>,
|
||||||
|
deleteRule: DeleteRule = .nullify,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
previousVersionKeyPath: @autoclosure @escaping () -> String? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<KeyPathString> = []
|
||||||
|
) where D: FieldRelationshipType {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath: keyPath,
|
||||||
|
isToMany: false,
|
||||||
|
isOrdered: false,
|
||||||
|
deleteRule: deleteRule,
|
||||||
|
inverseKeyPath: { V.DestinationObjectType.meta[keyPath: inverse].keyPath },
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: previousVersionKeyPath,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths,
|
||||||
|
minCount: 0,
|
||||||
|
maxCount: 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FieldContainer.Relationship: ToManyRelationshipKeyPathStringConvertible where V: FieldRelationshipToManyType {}
|
||||||
|
|
||||||
|
extension FieldContainer.Relationship where V: FieldRelationshipToManyOrderedType {
|
||||||
|
|
||||||
|
public init(
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
minCount: Int = 0,
|
||||||
|
maxCount: Int = 0,
|
||||||
|
deleteRule: DeleteRule = .nullify,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
previousVersionKeyPath: @autoclosure @escaping () -> String? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<KeyPathString> = []
|
||||||
|
) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath: keyPath,
|
||||||
|
isToMany: true,
|
||||||
|
isOrdered: true,
|
||||||
|
deleteRule: deleteRule,
|
||||||
|
inverseKeyPath: { nil },
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: previousVersionKeyPath,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths,
|
||||||
|
minCount: minCount,
|
||||||
|
maxCount: maxCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init<D>(
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
minCount: Int = 0,
|
||||||
|
maxCount: Int = 0,
|
||||||
|
inverse: @escaping (V.DestinationObjectType) -> FieldContainer<V.DestinationObjectType>.Relationship<D>,
|
||||||
|
deleteRule: DeleteRule = .nullify,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
previousVersionKeyPath: @autoclosure @escaping () -> String? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<KeyPathString> = []
|
||||||
|
) where D: FieldRelationshipType {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath: keyPath,
|
||||||
|
isToMany: true,
|
||||||
|
isOrdered: true,
|
||||||
|
deleteRule: deleteRule,
|
||||||
|
inverseKeyPath: { inverse(V.DestinationObjectType.meta).keyPath },
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: previousVersionKeyPath,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths,
|
||||||
|
minCount: minCount,
|
||||||
|
maxCount: maxCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FieldContainer.Relationship where V: FieldRelationshipToManyUnorderedType {
|
||||||
|
|
||||||
|
public init(
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
minCount: Int = 0,
|
||||||
|
maxCount: Int = 0,
|
||||||
|
deleteRule: DeleteRule = .nullify,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
previousVersionKeyPath: @autoclosure @escaping () -> String? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<KeyPathString> = []
|
||||||
|
) {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath: keyPath,
|
||||||
|
isToMany: true,
|
||||||
|
isOrdered: false,
|
||||||
|
deleteRule: deleteRule,
|
||||||
|
inverseKeyPath: { nil },
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: previousVersionKeyPath,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths,
|
||||||
|
minCount: minCount,
|
||||||
|
maxCount: maxCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init<D>(
|
||||||
|
_ keyPath: KeyPathString,
|
||||||
|
minCount: Int = 0,
|
||||||
|
maxCount: Int = 0,
|
||||||
|
inverse: @escaping (V.DestinationObjectType) -> FieldContainer<V.DestinationObjectType>.Relationship<D>,
|
||||||
|
deleteRule: DeleteRule = .nullify,
|
||||||
|
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||||
|
previousVersionKeyPath: @autoclosure @escaping () -> String? = nil,
|
||||||
|
affectedByKeyPaths: @autoclosure @escaping () -> Set<KeyPathString> = []
|
||||||
|
) where D: FieldRelationshipType {
|
||||||
|
|
||||||
|
self.init(
|
||||||
|
keyPath: keyPath,
|
||||||
|
isToMany: true,
|
||||||
|
isOrdered: false,
|
||||||
|
deleteRule: deleteRule,
|
||||||
|
inverseKeyPath: { inverse(V.DestinationObjectType.meta).keyPath },
|
||||||
|
versionHashModifier: versionHashModifier,
|
||||||
|
renamingIdentifier: previousVersionKeyPath,
|
||||||
|
affectedByKeyPaths: affectedByKeyPaths,
|
||||||
|
minCount: minCount,
|
||||||
|
maxCount: maxCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
49
Sources/FieldRelationshipProtocol.swift
Normal file
49
Sources/FieldRelationshipProtocol.swift
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// FieldRelationshipProtocol.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: - FieldRelationshipProtocol
|
||||||
|
|
||||||
|
internal protocol FieldRelationshipProtocol: FieldProtocol {
|
||||||
|
|
||||||
|
typealias EntityDescriptionValues = (
|
||||||
|
isToMany: Bool,
|
||||||
|
isOrdered: Bool,
|
||||||
|
deleteRule: NSDeleteRule,
|
||||||
|
inverse: (type: CoreStoreObject.Type, KeyPathString?),
|
||||||
|
versionHashModifier: String?,
|
||||||
|
renamingIdentifier: String?,
|
||||||
|
affectedByKeyPaths: Set<KeyPathString>,
|
||||||
|
minCount: Int,
|
||||||
|
maxCount: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
var entityDescriptionValues: () -> EntityDescriptionValues { get }
|
||||||
|
|
||||||
|
static func valueForSnapshot(field: FieldProtocol, for rawObject: CoreStoreManagedObject) -> Any?
|
||||||
|
}
|
||||||
@@ -447,6 +447,17 @@ public func ~= <O, V, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, ValueCon
|
|||||||
|
|
||||||
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Required<QueryableAttributeType & Comparable>
|
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Required<QueryableAttributeType & Comparable>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is less than a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age < 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func < <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is less than a value
|
Creates a `Where` clause by comparing if a property is less than a value
|
||||||
```
|
```
|
||||||
@@ -458,6 +469,17 @@ public func < <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Require
|
|||||||
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
|
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is greater than a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age > 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func > <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is greater than a value
|
Creates a `Where` clause by comparing if a property is greater than a value
|
||||||
```
|
```
|
||||||
@@ -469,6 +491,17 @@ public func > <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Require
|
|||||||
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
|
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is less than or equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age <= 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func <= <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is less than or equal to a value
|
Creates a `Where` clause by comparing if a property is less than or equal to a value
|
||||||
```
|
```
|
||||||
@@ -480,6 +513,17 @@ public func <= <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Requir
|
|||||||
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
|
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toQueryableNativeType())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is greater than or equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age >= 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func >= <O, V: Comparable>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> {
|
||||||
|
|
||||||
|
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is greater than or equal to a value
|
Creates a `Where` clause by comparing if a property is greater than or equal to a value
|
||||||
```
|
```
|
||||||
@@ -494,6 +538,17 @@ public func >= <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Requir
|
|||||||
|
|
||||||
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Optional<QueryableAttributeType & Comparable>
|
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Optional<QueryableAttributeType & Comparable>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is less than a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age < 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func < <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
|
||||||
|
|
||||||
|
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is less than a value
|
Creates a `Where` clause by comparing if a property is less than a value
|
||||||
```
|
```
|
||||||
@@ -512,6 +567,17 @@ public func < <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is greater than a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age > 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func > <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
|
||||||
|
|
||||||
|
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is greater than a value
|
Creates a `Where` clause by comparing if a property is greater than a value
|
||||||
```
|
```
|
||||||
@@ -530,6 +596,17 @@ public func > <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is less than or equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age <= 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func <= <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
|
||||||
|
|
||||||
|
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is less than or equal to a value
|
Creates a `Where` clause by comparing if a property is less than or equal to a value
|
||||||
```
|
```
|
||||||
@@ -548,6 +625,17 @@ public func <= <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is greater than or equal to a value
|
||||||
|
```
|
||||||
|
let person = dataStack.fetchOne(From<Person>().where(\.$age >= 20))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func >= <O, V: FieldOptionalType>(_ keyPath: KeyPath<O, FieldContainer<O>.Stored<V>>, _ value: V) -> Where<O> where V.Wrapped: Comparable {
|
||||||
|
|
||||||
|
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value.cs_toFieldStoredNativeType() as! V.FieldStoredNativeType)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is greater than or equal to a value
|
Creates a `Where` clause by comparing if a property is greater than or equal to a value
|
||||||
```
|
```
|
||||||
@@ -569,6 +657,17 @@ public func >= <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ va
|
|||||||
|
|
||||||
// MARK: - KeyPath where Root: CoreStoreObject, Value: RelationshipContainer<Root>.ToOne<CoreStoreObject>
|
// MARK: - KeyPath where Root: CoreStoreObject, Value: RelationshipContainer<Root>.ToOne<CoreStoreObject>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is equal to a value
|
||||||
|
```
|
||||||
|
let dog = dataStack.fetchOne(From<Dog>().where(\.$master == john))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func == <O, D: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: D.DestinationObjectType?) -> Where<O> {
|
||||||
|
|
||||||
|
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is equal to a value
|
Creates a `Where` clause by comparing if a property is equal to a value
|
||||||
```
|
```
|
||||||
@@ -591,6 +690,17 @@ public func == <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>,
|
|||||||
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
|
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by comparing if a property is not equal to a value
|
||||||
|
```
|
||||||
|
let dog = dataStack.fetchOne(From<Dog>().where(\.$master != john))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func != <O, D: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ object: D.DestinationObjectType?) -> Where<O> {
|
||||||
|
|
||||||
|
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by comparing if a property is not equal to a value
|
Creates a `Where` clause by comparing if a property is not equal to a value
|
||||||
```
|
```
|
||||||
@@ -613,6 +723,17 @@ public func != <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>,
|
|||||||
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
|
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a `Where` clause by checking if a sequence contains a value of a property
|
||||||
|
```
|
||||||
|
let dog = dataStack.fetchOne(From<Dog>().where([john, bob, joe] ~= \.$master))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func ~= <O, D: FieldRelationshipToOneType, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, FieldContainer<O>.Relationship<D>>) -> Where<O> where S.Iterator.Element == D.DestinationObjectType {
|
||||||
|
|
||||||
|
return Where<O>(O.meta[keyPath: keyPath].keyPath, isMemberOf: sequence)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a `Where` clause by checking if a sequence contains a value of a property
|
Creates a `Where` clause by checking if a sequence contains a value of a property
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -379,45 +379,15 @@ extension SelectTerm where O: NSManagedObject {
|
|||||||
// MARK: - SelectTerm where O: CoreStoreObject
|
// MARK: - SelectTerm where O: CoreStoreObject
|
||||||
|
|
||||||
extension SelectTerm where O: CoreStoreObject {
|
extension SelectTerm where O: CoreStoreObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
|
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
|
||||||
- parameter keyPath: the attribute name
|
- parameter keyPath: the attribute name
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
|
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
|
||||||
*/
|
*/
|
||||||
public static func attribute<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>) -> SelectTerm<O> {
|
public static func attribute<K: AttributeKeyPathStringConvertible>(_ keyPath: KeyPath<O, K>) -> SelectTerm<O> where K.ObjectType == O {
|
||||||
|
|
||||||
return self.attribute(O.meta[keyPath: keyPath].keyPath)
|
return self.attribute(O.meta[keyPath: keyPath].cs_keyPathString)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
|
|
||||||
*/
|
|
||||||
public static func attribute<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.attribute(O.meta[keyPath: keyPath].keyPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
|
|
||||||
*/
|
|
||||||
public static func attribute<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Required<V>>) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.attribute(O.meta[keyPath: keyPath].keyPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
|
|
||||||
*/
|
|
||||||
public static func attribute<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Optional<V>>) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.attribute(O.meta[keyPath: keyPath].keyPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -426,42 +396,9 @@ extension SelectTerm where O: CoreStoreObject {
|
|||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
|
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
|
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
|
||||||
*/
|
*/
|
||||||
public static func average<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
public static func average<K: AttributeKeyPathStringConvertible>(_ keyPath: KeyPath<O, K>, as alias: KeyPathString? = nil) -> SelectTerm<O> where K.ObjectType == O{
|
||||||
|
|
||||||
return self.average(O.meta[keyPath: keyPath].keyPath, as: alias)
|
return self.average(O.meta[keyPath: keyPath].cs_keyPathString, as: alias)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
|
|
||||||
*/
|
|
||||||
public static func average<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.average(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
|
|
||||||
*/
|
|
||||||
public static func average<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.average(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
|
|
||||||
*/
|
|
||||||
public static func average<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.average(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -470,46 +407,10 @@ extension SelectTerm where O: CoreStoreObject {
|
|||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
|
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
|
||||||
- returns: a `SelectTerm` to a `Select` clause for a count query
|
- returns: a `SelectTerm` to a `Select` clause for a count query
|
||||||
*/
|
*/
|
||||||
public static func count<V>(_ keyPath: KeyPath<O,
|
public static func count<K: AttributeKeyPathStringConvertible>(_ keyPath: KeyPath<O,
|
||||||
ValueContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
K>, as alias: KeyPathString? = nil) -> SelectTerm<O> where K.ObjectType == O {
|
||||||
|
|
||||||
return self.count(O.meta[keyPath: keyPath].keyPath, as: alias)
|
return self.count(O.meta[keyPath: keyPath].cs_keyPathString, as: alias)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for a count query.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for a count query
|
|
||||||
*/
|
|
||||||
public static func count<V>(_ keyPath: KeyPath<O,
|
|
||||||
ValueContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.count(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for a count query.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for a count query
|
|
||||||
*/
|
|
||||||
public static func count<V>(_ keyPath: KeyPath<O,
|
|
||||||
TransformableContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.count(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for a count query.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for a count query
|
|
||||||
*/
|
|
||||||
public static func count<V>(_ keyPath: KeyPath<O,
|
|
||||||
TransformableContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.count(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -518,46 +419,10 @@ extension SelectTerm where O: CoreStoreObject {
|
|||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
|
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
|
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
|
||||||
*/
|
*/
|
||||||
public static func maximum<V>(_ keyPath: KeyPath<O,
|
public static func maximum<K: AttributeKeyPathStringConvertible>(_ keyPath: KeyPath<O,
|
||||||
ValueContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
K>, as alias: KeyPathString? = nil) -> SelectTerm<O> where K.ObjectType == O {
|
||||||
|
|
||||||
return self.maximum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
return self.maximum(O.meta[keyPath: keyPath].cs_keyPathString, as: alias)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func maximum<V>(_ keyPath: KeyPath<O,
|
|
||||||
ValueContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.maximum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func maximum<V>(_ keyPath: KeyPath<O,
|
|
||||||
TransformableContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.maximum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func maximum<V>(_ keyPath: KeyPath<O,
|
|
||||||
TransformableContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.maximum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -566,42 +431,9 @@ extension SelectTerm where O: CoreStoreObject {
|
|||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
|
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
|
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
|
||||||
*/
|
*/
|
||||||
public static func minimum<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
public static func minimum<K: AttributeKeyPathStringConvertible>(_ keyPath: KeyPath<O, K>, as alias: KeyPathString? = nil) -> SelectTerm<O> where K.ObjectType == O {
|
||||||
|
|
||||||
return self.minimum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
return self.minimum(O.meta[keyPath: keyPath].cs_keyPathString, as: alias)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func minimum<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.minimum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func minimum<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.minimum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func minimum<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.minimum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -610,42 +442,9 @@ extension SelectTerm where O: CoreStoreObject {
|
|||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
|
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
|
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
|
||||||
*/
|
*/
|
||||||
public static func sum<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
public static func sum<K: AttributeKeyPathStringConvertible>(_ keyPath: KeyPath<O, K>, as alias: KeyPathString? = nil) -> SelectTerm<O> where K.ObjectType == O {
|
||||||
|
|
||||||
return self.sum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
return self.sum(O.meta[keyPath: keyPath].cs_keyPathString, as: alias)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func sum<V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.sum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func sum<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.sum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
|
|
||||||
- parameter keyPath: the attribute name
|
|
||||||
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
|
|
||||||
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
|
|
||||||
*/
|
|
||||||
public static func sum<V>(_ keyPath: KeyPath<O, TransformableContainer<O>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<O> {
|
|
||||||
|
|
||||||
return self.sum(O.meta[keyPath: keyPath].keyPath, as: alias)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,6 +235,20 @@ public func ~ <O: NSManagedObject, D: NSManagedObject, T, C: AllowedObjectiveCTo
|
|||||||
|
|
||||||
// MARK: - ~ where D: CoreStoreObject
|
// MARK: - ~ where D: CoreStoreObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions
|
||||||
|
```
|
||||||
|
let owner = dataStack.fetchOne(From<Pet>().where((\.$master ~ \.$name) == "John"))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func ~ <O: CoreStoreObject, D: FieldRelationshipToOneType, K: KeyPathStringConvertible>(_ lhs: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ rhs: KeyPath<D.DestinationObjectType, K>) -> Where<O>.Expression<Where<O>.SingleTarget, K.DestinationValueType> where K.ObjectType == D.DestinationObjectType {
|
||||||
|
|
||||||
|
return .init(
|
||||||
|
O.meta[keyPath: lhs].cs_keyPathString,
|
||||||
|
D.DestinationObjectType.meta[keyPath: rhs].cs_keyPathString
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions
|
Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions
|
||||||
```
|
```
|
||||||
@@ -277,6 +291,20 @@ public func ~ <O: CoreStoreObject, D: CoreStoreObject, T, K: KeyPathStringConver
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions
|
||||||
|
```
|
||||||
|
let happyPets = dataStack.fetchAll(From<Pet>().where((\.$master ~ \.$pets).count() > 1))
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
public func ~ <O: CoreStoreObject, D: FieldRelationshipToOneType, K: ToManyRelationshipKeyPathStringConvertible>(_ lhs: KeyPath<O, FieldContainer<O>.Relationship<D>>, _ rhs: KeyPath<D.DestinationObjectType, K>) -> Where<O>.Expression<Where<O>.CollectionTarget, K.DestinationValueType> where K.ObjectType == D.DestinationObjectType {
|
||||||
|
|
||||||
|
return .init(
|
||||||
|
O.meta[keyPath: lhs].cs_keyPathString,
|
||||||
|
D.DestinationObjectType.meta[keyPath: rhs].cs_keyPathString
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions
|
Connects multiple `KeyPathStringConvertible`s to create a type-safe chain usable in query/fetch expressions
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -451,6 +451,17 @@ extension Where where O: CoreStoreObject {
|
|||||||
|
|
||||||
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
|
self.init(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes a `Where` clause that compares equality
|
||||||
|
|
||||||
|
- parameter keyPath: the keyPath to compare with
|
||||||
|
- parameter value: the arguments for the `==` operator
|
||||||
|
*/
|
||||||
|
public init<V: FieldRelationshipToOneType>(_ keyPath: KeyPath<O, FieldContainer<O>.Relationship<V>>, isEqualTo value: V.DestinationObjectType?) {
|
||||||
|
|
||||||
|
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