Merge branch 'develop'

This commit is contained in:
John Rommel Estropia
2017-12-29 01:09:07 +09:00
94 changed files with 6034 additions and 1760 deletions
+1 -1
View File
@@ -1 +1 @@
3.2 4.0
+148 -32
View File
@@ -34,7 +34,7 @@
82BA18B51C4BBD3F00A0916E /* BaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */; }; 82BA18B51C4BBD3F00A0916E /* BaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */; };
82BA18B61C4BBD3F00A0916E /* DataStack+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */; }; 82BA18B61C4BBD3F00A0916E /* DataStack+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */; };
82BA18B71C4BBD3F00A0916E /* CoreStore+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */; }; 82BA18B71C4BBD3F00A0916E /* CoreStore+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */; };
82BA18B81C4BBD4200A0916E /* ClauseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* ClauseTypes.swift */; }; 82BA18B81C4BBD4200A0916E /* TypeErasedClauses.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* TypeErasedClauses.swift */; };
82BA18B91C4BBD4A00A0916E /* From.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F011AFF847B0064E85B /* From.swift */; }; 82BA18B91C4BBD4A00A0916E /* From.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F011AFF847B0064E85B /* From.swift */; };
82BA18BA1C4BBD4A00A0916E /* Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F031AFF847B0064E85B /* Select.swift */; }; 82BA18BA1C4BBD4A00A0916E /* Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F031AFF847B0064E85B /* Select.swift */; };
82BA18BB1C4BBD4A00A0916E /* Where.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F051AFF847B0064E85B /* Where.swift */; }; 82BA18BB1C4BBD4A00A0916E /* Where.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F051AFF847B0064E85B /* Where.swift */; };
@@ -101,6 +101,18 @@
B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; }; B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */; };
B5202CFA1C04688100DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; }; B5202CFA1C04688100DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; }; B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
B5215CA41FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA31FA47DFD00139E3A /* FetchChainBuilder.swift */; };
B5215CA51FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA31FA47DFD00139E3A /* FetchChainBuilder.swift */; };
B5215CA61FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA31FA47DFD00139E3A /* FetchChainBuilder.swift */; };
B5215CA71FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA31FA47DFD00139E3A /* FetchChainBuilder.swift */; };
B5215CA91FA4810300139E3A /* QueryChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA81FA4810300139E3A /* QueryChainBuilder.swift */; };
B5215CAA1FA4810300139E3A /* QueryChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA81FA4810300139E3A /* QueryChainBuilder.swift */; };
B5215CAB1FA4810300139E3A /* QueryChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA81FA4810300139E3A /* QueryChainBuilder.swift */; };
B5215CAC1FA4810300139E3A /* QueryChainBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CA81FA4810300139E3A /* QueryChainBuilder.swift */; };
B5215CAE1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CAD1FA4812500139E3A /* SectionMonitorBuilder.swift */; };
B5215CAF1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CAD1FA4812500139E3A /* SectionMonitorBuilder.swift */; };
B5215CB01FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CAD1FA4812500139E3A /* SectionMonitorBuilder.swift */; };
B5215CB11FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5215CAD1FA4812500139E3A /* SectionMonitorBuilder.swift */; };
B5220E081D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */; }; B5220E081D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */; };
B5220E091D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */; }; B5220E091D0C5F8D009BC71E /* ObjectObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */; };
B5220E0C1D0D0D19009BC71E /* ImportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E0B1D0D0D19009BC71E /* ImportTests.swift */; }; B5220E0C1D0D0D19009BC71E /* ImportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220E0B1D0D0D19009BC71E /* ImportTests.swift */; };
@@ -184,7 +196,7 @@
B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */; }; B52DD1A71BE1F93200949AFE /* BaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */; };
B52DD1A81BE1F93200949AFE /* DataStack+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */; }; B52DD1A81BE1F93200949AFE /* DataStack+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */; };
B52DD1A91BE1F93200949AFE /* CoreStore+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */; }; B52DD1A91BE1F93200949AFE /* CoreStore+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */; };
B52DD1AA1BE1F93500949AFE /* ClauseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* ClauseTypes.swift */; }; B52DD1AA1BE1F93500949AFE /* TypeErasedClauses.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* TypeErasedClauses.swift */; };
B52DD1AB1BE1F93900949AFE /* From.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F011AFF847B0064E85B /* From.swift */; }; B52DD1AB1BE1F93900949AFE /* From.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F011AFF847B0064E85B /* From.swift */; };
B52DD1AC1BE1F93900949AFE /* Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F031AFF847B0064E85B /* Select.swift */; }; B52DD1AC1BE1F93900949AFE /* Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F031AFF847B0064E85B /* Select.swift */; };
B52DD1AD1BE1F93900949AFE /* Where.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F051AFF847B0064E85B /* Where.swift */; }; B52DD1AD1BE1F93900949AFE /* Where.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F051AFF847B0064E85B /* Where.swift */; };
@@ -324,6 +336,10 @@
B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */; }; B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */; };
B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */; }; B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */; };
B5519A621CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */; }; B5519A621CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */; };
B55514EA1EED8BF900BAB888 /* From+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55514E91EED8BF900BAB888 /* From+Querying.swift */; };
B55514EB1EED8BF900BAB888 /* From+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55514E91EED8BF900BAB888 /* From+Querying.swift */; };
B55514EC1EED8BF900BAB888 /* From+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55514E91EED8BF900BAB888 /* From+Querying.swift */; };
B55514ED1EED8BF900BAB888 /* From+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55514E91EED8BF900BAB888 /* From+Querying.swift */; };
B55717441D15B09E009BDBCA /* CoreStoreBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; B55717441D15B09E009BDBCA /* CoreStoreBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */; settings = {ATTRIBUTES = (Public, ); }; };
B55717451D15B09F009BDBCA /* CoreStoreBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; B55717451D15B09F009BDBCA /* CoreStoreBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */; settings = {ATTRIBUTES = (Public, ); }; };
B55717461D15B0A1009BDBCA /* CoreStoreBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; B55717461D15B0A1009BDBCA /* CoreStoreBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -362,7 +378,7 @@
B56321921BD65216006C9394 /* BaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */; }; B56321921BD65216006C9394 /* BaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */; };
B56321931BD65216006C9394 /* DataStack+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */; }; B56321931BD65216006C9394 /* DataStack+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */; };
B56321941BD65216006C9394 /* CoreStore+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */; }; B56321941BD65216006C9394 /* CoreStore+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */; };
B56321951BD65216006C9394 /* ClauseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* ClauseTypes.swift */; }; B56321951BD65216006C9394 /* TypeErasedClauses.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* TypeErasedClauses.swift */; };
B56321961BD65216006C9394 /* From.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F011AFF847B0064E85B /* From.swift */; }; B56321961BD65216006C9394 /* From.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F011AFF847B0064E85B /* From.swift */; };
B56321971BD65216006C9394 /* Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F031AFF847B0064E85B /* Select.swift */; }; B56321971BD65216006C9394 /* Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F031AFF847B0064E85B /* Select.swift */; };
B56321981BD65216006C9394 /* Where.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F051AFF847B0064E85B /* Where.swift */; }; B56321981BD65216006C9394 /* Where.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F051AFF847B0064E85B /* Where.swift */; };
@@ -485,6 +501,10 @@
B59FA0B01CCBACA7007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; }; B59FA0B01CCBACA7007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; };
B59FA0B11CCBACA7007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; }; B59FA0B11CCBACA7007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; };
B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; }; B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; };
B5A1DAC81F111BFA003CF369 /* KeyPath+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */; };
B5A1DAC91F111BFA003CF369 /* KeyPath+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */; };
B5A1DACA1F111BFA003CF369 /* KeyPath+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */; };
B5A1DACB1F111BFA003CF369 /* KeyPath+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */; };
B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A261201B64BFDB006EB6D3 /* MigrationType.swift */; }; B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A261201B64BFDB006EB6D3 /* MigrationType.swift */; };
B5A5F2661CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; }; B5A5F2661CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
B5A5F2681CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; }; B5A5F2681CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
@@ -508,6 +528,14 @@
B5C976E71C6E3A5A00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; }; B5C976E71C6E3A5A00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; };
B5C976E81C6E3A5D00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; }; B5C976E81C6E3A5D00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; };
B5C976E91C6E3A5E00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; }; B5C976E91C6E3A5E00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */; };
B5CA2B081F7E5ACA004B1936 /* WhereClauseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */; };
B5CA2B091F7E5ACA004B1936 /* WhereClauseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */; };
B5CA2B0A1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */; };
B5CA2B0B1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */; };
B5CA2B121F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; };
B5CA2B131F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; };
B5CA2B141F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; };
B5CA2B151F81DBFF004B1936 /* DynamicKeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */; };
B5D1E22C19FA9FBC003B2874 /* CoreStoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */; }; B5D1E22C19FA9FBC003B2874 /* CoreStoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */; };
B5D339B41E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; }; B5D339B41E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; };
B5D339B51E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; }; B5D339B51E925C2B00C880DE /* DynamicModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */; };
@@ -630,7 +658,7 @@
B5E84F361AFF85470064E85B /* NSManagedObjectContext+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */; }; B5E84F361AFF85470064E85B /* NSManagedObjectContext+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */; };
B5E84F371AFF85470064E85B /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; }; B5E84F371AFF85470064E85B /* NSManagedObjectContext+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */; };
B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */; }; B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */; };
B5E84F411AFF8CCD0064E85B /* ClauseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* ClauseTypes.swift */; }; B5E84F411AFF8CCD0064E85B /* TypeErasedClauses.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E84F401AFF8CCD0064E85B /* TypeErasedClauses.swift */; };
B5ECDBDF1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */; }; B5ECDBDF1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */; };
B5ECDBE11CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */; }; B5ECDBE11CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */; };
B5ECDBE21CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */; }; B5ECDBE21CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */; };
@@ -749,6 +777,9 @@
B51260921E9B28F100402229 /* EntityIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityIdentifier.swift; sourceTree = "<group>"; }; B51260921E9B28F100402229 /* EntityIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityIdentifier.swift; sourceTree = "<group>"; };
B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+CustomDebugStringConvertible.swift"; sourceTree = "<group>"; }; B51FE5AA1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+CustomDebugStringConvertible.swift"; sourceTree = "<group>"; };
B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+Convenience.swift"; sourceTree = "<group>"; }; B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+Convenience.swift"; sourceTree = "<group>"; };
B5215CA31FA47DFD00139E3A /* FetchChainBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchChainBuilder.swift; sourceTree = "<group>"; };
B5215CA81FA4810300139E3A /* QueryChainBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryChainBuilder.swift; sourceTree = "<group>"; };
B5215CAD1FA4812500139E3A /* SectionMonitorBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionMonitorBuilder.swift; sourceTree = "<group>"; };
B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectObserverTests.swift; sourceTree = "<group>"; }; B5220E071D0C5F8D009BC71E /* ObjectObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectObserverTests.swift; sourceTree = "<group>"; };
B5220E0B1D0D0D19009BC71E /* ImportTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportTests.swift; sourceTree = "<group>"; }; B5220E0B1D0D0D19009BC71E /* ImportTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportTests.swift; sourceTree = "<group>"; };
B5220E0F1D0DA6AB009BC71E /* ListObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListObserverTests.swift; sourceTree = "<group>"; }; B5220E0F1D0DA6AB009BC71E /* ListObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListObserverTests.swift; sourceTree = "<group>"; };
@@ -798,6 +829,7 @@
B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSAsynchronousDataTransaction.swift; sourceTree = "<group>"; }; B5519A5E1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSAsynchronousDataTransaction.swift; sourceTree = "<group>"; };
B5548CD51BD65AE00077652A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; B5548CD51BD65AE00077652A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
B5548CD71BD65AE50077652A /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; B5548CD71BD65AE50077652A /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; };
B55514E91EED8BF900BAB888 /* From+Querying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "From+Querying.swift"; sourceTree = "<group>"; };
B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreStoreBridge.h; sourceTree = "<group>"; }; B55717421D15AF9C009BDBCA /* CoreStoreBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreStoreBridge.h; sourceTree = "<group>"; };
B559CD421CAA8B6300E4D58B /* CSSetupResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSetupResult.swift; sourceTree = "<group>"; }; B559CD421CAA8B6300E4D58B /* CSSetupResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSetupResult.swift; sourceTree = "<group>"; };
B559CD481CAA8C6D00E4D58B /* CSStorageInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSStorageInterface.swift; sourceTree = "<group>"; }; B559CD481CAA8C6D00E4D58B /* CSStorageInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSStorageInterface.swift; sourceTree = "<group>"; };
@@ -837,6 +869,7 @@
B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryableSource.swift; sourceTree = "<group>"; }; B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryableSource.swift; sourceTree = "<group>"; };
B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+Setup.swift"; sourceTree = "<group>"; }; B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+Setup.swift"; sourceTree = "<group>"; };
B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ICloudStore.swift; sourceTree = "<group>"; }; B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ICloudStore.swift; sourceTree = "<group>"; };
B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyPath+Querying.swift"; sourceTree = "<group>"; };
B5A261201B64BFDB006EB6D3 /* MigrationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationType.swift; sourceTree = "<group>"; }; B5A261201B64BFDB006EB6D3 /* MigrationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationType.swift; sourceTree = "<group>"; };
B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSelect.swift; sourceTree = "<group>"; }; B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSelect.swift; sourceTree = "<group>"; };
B5A991EB1E9DC2CE0091A2E3 /* VersionLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionLock.swift; sourceTree = "<group>"; }; B5A991EB1E9DC2CE0091A2E3 /* VersionLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionLock.swift; sourceTree = "<group>"; };
@@ -847,6 +880,8 @@
B5BDC9271C2024F2008147CD /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = SOURCE_ROOT; }; B5BDC9271C2024F2008147CD /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = SOURCE_ROOT; };
B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafeDataTransaction+Observing.swift"; sourceTree = "<group>"; }; B5C976E21C6C9F6A00B1AF90 /* UnsafeDataTransaction+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafeDataTransaction+Observing.swift"; sourceTree = "<group>"; };
B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreFetchedResultsController.swift; sourceTree = "<group>"; }; B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreFetchedResultsController.swift; sourceTree = "<group>"; };
B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhereClauseType.swift; sourceTree = "<group>"; };
B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicKeyPath.swift; sourceTree = "<group>"; };
B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreError.swift; sourceTree = "<group>"; }; B5D1E22B19FA9FBC003B2874 /* CoreStoreError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreError.swift; sourceTree = "<group>"; };
B5D2D5A91F7558CB00A4DE67 /* .cocoapods.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .cocoapods.yml; sourceTree = SOURCE_ROOT; }; B5D2D5A91F7558CB00A4DE67 /* .cocoapods.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .cocoapods.yml; sourceTree = SOURCE_ROOT; };
B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicModelTests.swift; sourceTree = "<group>"; }; B5D339B31E925C2B00C880DE /* DynamicModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicModelTests.swift; sourceTree = "<group>"; };
@@ -914,7 +949,7 @@
B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Setup.swift"; sourceTree = "<group>"; }; B5E84F321AFF85470064E85B /* NSManagedObjectContext+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Setup.swift"; sourceTree = "<group>"; };
B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Transaction.swift"; sourceTree = "<group>"; }; B5E84F331AFF85470064E85B /* NSManagedObjectContext+Transaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Transaction.swift"; sourceTree = "<group>"; };
B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Querying.swift"; sourceTree = "<group>"; }; B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Querying.swift"; sourceTree = "<group>"; };
B5E84F401AFF8CCD0064E85B /* ClauseTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClauseTypes.swift; sourceTree = "<group>"; }; B5E84F401AFF8CCD0064E85B /* TypeErasedClauses.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeErasedClauses.swift; sourceTree = "<group>"; };
B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSBaseDataTransaction+Querying.swift"; sourceTree = "<group>"; }; B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSBaseDataTransaction+Querying.swift"; sourceTree = "<group>"; };
B5ECDBE41CA6BEA300C7F112 /* CSClauseTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSClauseTypes.swift; sourceTree = "<group>"; }; B5ECDBE41CA6BEA300C7F112 /* CSClauseTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSClauseTypes.swift; sourceTree = "<group>"; };
B5ECDBEB1CA6BF2000C7F112 /* CSFrom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSFrom.swift; sourceTree = "<group>"; }; B5ECDBEB1CA6BF2000C7F112 /* CSFrom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSFrom.swift; sourceTree = "<group>"; };
@@ -1129,6 +1164,17 @@
name = Observing; name = Observing;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
B5215CA21FA47BF300139E3A /* Chained Clauses */ = {
isa = PBXGroup;
children = (
B55514E91EED8BF900BAB888 /* From+Querying.swift */,
B5215CA31FA47DFD00139E3A /* FetchChainBuilder.swift */,
B5215CA81FA4810300139E3A /* QueryChainBuilder.swift */,
B5215CAD1FA4812500139E3A /* SectionMonitorBuilder.swift */,
);
name = "Chained Clauses";
sourceTree = "<group>";
};
B52F74391E9B8724005F3DAC /* Dynamic Schema */ = { B52F74391E9B8724005F3DAC /* Dynamic Schema */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -1272,6 +1318,16 @@
name = Properties; name = Properties;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
B5A1DAC61F111BBE003CF369 /* KeyPath Utilities */ = {
isa = PBXGroup;
children = (
B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */,
B5D339EB1E9495E500C880DE /* CoreStoreObject+Querying.swift */,
B5CA2B111F81DBFE004B1936 /* DynamicKeyPath.swift */,
);
name = "KeyPath Utilities";
sourceTree = "<group>";
};
B5A5F26B1CAFF8D0004AB9AF /* Swift */ = { B5A5F26B1CAFF8D0004AB9AF /* Swift */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -1395,13 +1451,14 @@
B5E84EFD1AFF847B0064E85B /* Fetching and Querying */ = { B5E84EFD1AFF847B0064E85B /* Fetching and Querying */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B5D339EB1E9495E500C880DE /* CoreStoreObject+Querying.swift */,
B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */, B5E84EFE1AFF847B0064E85B /* BaseDataTransaction+Querying.swift */,
B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */, B5E84F061AFF847B0064E85B /* DataStack+Querying.swift */,
B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */, B5E84F071AFF847B0064E85B /* CoreStore+Querying.swift */,
B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */, B596BBB51DD5BC67001DCDD9 /* FetchableSource.swift */,
B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */, B596BBBA1DD5C39F001DCDD9 /* QueryableSource.swift */,
B549F65D1E569C7400FBAB2D /* QueryableAttributeType.swift */, B549F65D1E569C7400FBAB2D /* QueryableAttributeType.swift */,
B5215CA21FA47BF300139E3A /* Chained Clauses */,
B5A1DAC61F111BBE003CF369 /* KeyPath Utilities */,
B5E84F0A1AFF847B0064E85B /* Protocol Clauses */, B5E84F0A1AFF847B0064E85B /* Protocol Clauses */,
B5E84EFF1AFF847B0064E85B /* Concrete Clauses */, B5E84EFF1AFF847B0064E85B /* Concrete Clauses */,
); );
@@ -1424,7 +1481,8 @@
B5E84F0A1AFF847B0064E85B /* Protocol Clauses */ = { B5E84F0A1AFF847B0064E85B /* Protocol Clauses */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B5E84F401AFF8CCD0064E85B /* ClauseTypes.swift */, B5E84F401AFF8CCD0064E85B /* TypeErasedClauses.swift */,
B5CA2B071F7E5ACA004B1936 /* WhereClauseType.swift */,
); );
name = "Protocol Clauses"; name = "Protocol Clauses";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1696,32 +1754,32 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0730; LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0800; LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "John Rommel Estropia"; ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = { TargetAttributes = {
2F03A52F19C5C6DA005002A5 = { 2F03A52F19C5C6DA005002A5 = {
CreatedOnToolsVersion = 6.0; CreatedOnToolsVersion = 6.0;
LastSwiftMigration = 0800; LastSwiftMigration = 0900;
}; };
2F03A53A19C5C6DA005002A5 = { 2F03A53A19C5C6DA005002A5 = {
CreatedOnToolsVersion = 6.0; CreatedOnToolsVersion = 6.0;
LastSwiftMigration = 0800; LastSwiftMigration = 0900;
}; };
82BA18881C4BBCBA00A0916E = { 82BA18881C4BBCBA00A0916E = {
CreatedOnToolsVersion = 7.2; CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0800; LastSwiftMigration = 0900;
}; };
82BA18911C4BBCBA00A0916E = { 82BA18911C4BBCBA00A0916E = {
CreatedOnToolsVersion = 7.2; CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0800; LastSwiftMigration = 0900;
}; };
B52DD1731BE1F8CC00949AFE = { B52DD1731BE1F8CC00949AFE = {
CreatedOnToolsVersion = 7.1; CreatedOnToolsVersion = 7.1;
LastSwiftMigration = 0800; LastSwiftMigration = 0900;
}; };
B52DD17C1BE1F8CC00949AFE = { B52DD17C1BE1F8CC00949AFE = {
CreatedOnToolsVersion = 7.1; CreatedOnToolsVersion = 7.1;
LastSwiftMigration = 0800; LastSwiftMigration = 0900;
}; };
B563216E1BD65082006C9394 = { B563216E1BD65082006C9394 = {
CreatedOnToolsVersion = 7.0.1; CreatedOnToolsVersion = 7.0.1;
@@ -1811,6 +1869,7 @@
files = ( files = (
B5E84F221AFF84860064E85B /* ObjectMonitor.swift in Sources */, B5E84F221AFF84860064E85B /* ObjectMonitor.swift in Sources */,
B5ECDBF91CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */, B5ECDBF91CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
B5CA2B081F7E5ACA004B1936 /* WhereClauseType.swift in Sources */,
B5C976E71C6E3A5A00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */, B5C976E71C6E3A5A00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */,
B56923F51EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */, B56923F51EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */,
B5F1DA901B9AA991007C5CBB /* ImportableUniqueObject.swift in Sources */, B5F1DA901B9AA991007C5CBB /* ImportableUniqueObject.swift in Sources */,
@@ -1822,6 +1881,7 @@
B5D339D81E9489AB00C880DE /* CoreStoreObject.swift in Sources */, B5D339D81E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
B5D3F6451C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */, B5D3F6451C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
B56923FA1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */, B56923FA1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
B55514EA1EED8BF900BAB888 /* From+Querying.swift in Sources */,
B596BBBB1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B596BBBB1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B5ECDBFF1CA80CBA00C7F112 /* CSWhere.swift in Sources */, B5ECDBFF1CA80CBA00C7F112 /* CSWhere.swift in Sources */,
B5ECDC051CA8138100C7F112 /* CSOrderBy.swift in Sources */, B5ECDC051CA8138100C7F112 /* CSOrderBy.swift in Sources */,
@@ -1882,10 +1942,11 @@
B501FDE71CA8D20500BE22EF /* CSListObserver.swift in Sources */, B501FDE71CA8D20500BE22EF /* CSListObserver.swift in Sources */,
B5E41EC01EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */, B5E41EC01EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */,
B501FDE21CA8D1F500BE22EF /* CSListMonitor.swift in Sources */, B501FDE21CA8D1F500BE22EF /* CSListMonitor.swift in Sources */,
B5A1DAC81F111BFA003CF369 /* KeyPath+Querying.swift in Sources */,
2F291E2719C6D3CF007AF63F /* CoreStore.swift in Sources */, 2F291E2719C6D3CF007AF63F /* CoreStore.swift in Sources */,
B5ECDC111CA816E500C7F112 /* CSTweak.swift in Sources */, B5ECDC111CA816E500C7F112 /* CSTweak.swift in Sources */,
B56923C41EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */, B56923C41EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
B5E84F411AFF8CCD0064E85B /* ClauseTypes.swift in Sources */, B5E84F411AFF8CCD0064E85B /* TypeErasedClauses.swift in Sources */,
B5E84F0D1AFF847B0064E85B /* BaseDataTransaction+Querying.swift in Sources */, B5E84F0D1AFF847B0064E85B /* BaseDataTransaction+Querying.swift in Sources */,
B52F74451E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */, B52F74451E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */,
B5FAD6AC1B51285300714891 /* MigrationManager.swift in Sources */, B5FAD6AC1B51285300714891 /* MigrationManager.swift in Sources */,
@@ -1910,6 +1971,7 @@
B5E84F0F1AFF847B0064E85B /* From.swift in Sources */, B5E84F0F1AFF847B0064E85B /* From.swift in Sources */,
B5FAD6A91B50A4B400714891 /* Progress+Convenience.swift in Sources */, B5FAD6A91B50A4B400714891 /* Progress+Convenience.swift in Sources */,
B5E84EFC1AFF846E0064E85B /* SynchronousDataTransaction.swift in Sources */, B5E84EFC1AFF846E0064E85B /* SynchronousDataTransaction.swift in Sources */,
B5215CA91FA4810300139E3A /* QueryChainBuilder.swift in Sources */,
B5E222231CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */, B5E222231CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
B5E84F281AFF84920064E85B /* NSManagedObject+Convenience.swift in Sources */, B5E84F281AFF84920064E85B /* NSManagedObject+Convenience.swift in Sources */,
B52F744A1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */, B52F744A1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
@@ -1918,6 +1980,7 @@
B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */, B5E84F391AFF85470064E85B /* NSManagedObjectContext+Querying.swift in Sources */,
B56923E81EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */, B56923E81EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */,
B53B275F1EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */, B53B275F1EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */,
B5215CA41FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */,
B5D33A011E96012400C880DE /* Relationship.swift in Sources */, B5D33A011E96012400C880DE /* Relationship.swift in Sources */,
B5E84EE81AFF84610064E85B /* CoreStoreLogger.swift in Sources */, B5E84EE81AFF84610064E85B /* CoreStoreLogger.swift in Sources */,
B56923C91EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */, B56923C91EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */,
@@ -1941,10 +2004,12 @@
B549F65E1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B549F65E1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
B5E84F211AFF84860064E85B /* CoreStore+Observing.swift in Sources */, B5E84F211AFF84860064E85B /* CoreStore+Observing.swift in Sources */,
B559CD431CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, B559CD431CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
B5CA2B121F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */,
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 */,
B56923FF1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */, B56923FF1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CAE1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
B5ECDBEC1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B5ECDBEC1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B56923EC1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923EC1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */, B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */,
@@ -2000,6 +2065,7 @@
files = ( files = (
82BA18B61C4BBD3F00A0916E /* DataStack+Querying.swift in Sources */, 82BA18B61C4BBD3F00A0916E /* DataStack+Querying.swift in Sources */,
B5ECDBFB1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */, B5ECDBFB1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
B5CA2B091F7E5ACA004B1936 /* WhereClauseType.swift in Sources */,
B5C976E81C6E3A5D00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */, B5C976E81C6E3A5D00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */,
B56923F61EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */, B56923F61EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */,
82BA18A21C4BBD1D00A0916E /* CoreStoreError.swift in Sources */, 82BA18A21C4BBD1D00A0916E /* CoreStoreError.swift in Sources */,
@@ -2011,6 +2077,7 @@
B5D339D91E9489AB00C880DE /* CoreStoreObject.swift in Sources */, B5D339D91E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
82BA18CE1C4BBD7100A0916E /* FetchedResultsControllerDelegate.swift in Sources */, 82BA18CE1C4BBD7100A0916E /* FetchedResultsControllerDelegate.swift in Sources */,
B56923FB1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */, B56923FB1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
B55514EB1EED8BF900BAB888 /* From+Querying.swift in Sources */,
B596BBBC1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B596BBBC1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B5ECDC011CA80CBA00C7F112 /* CSWhere.swift in Sources */, B5ECDC011CA80CBA00C7F112 /* CSWhere.swift in Sources */,
B5ECDC071CA8138100C7F112 /* CSOrderBy.swift in Sources */, B5ECDC071CA8138100C7F112 /* CSOrderBy.swift in Sources */,
@@ -2071,6 +2138,7 @@
B501FDE91CA8D20500BE22EF /* CSListObserver.swift in Sources */, B501FDE91CA8D20500BE22EF /* CSListObserver.swift in Sources */,
B5E41EC11EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */, B5E41EC11EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */,
B501FDE41CA8D1F500BE22EF /* CSListMonitor.swift in Sources */, B501FDE41CA8D1F500BE22EF /* CSListMonitor.swift in Sources */,
B5A1DAC91F111BFA003CF369 /* KeyPath+Querying.swift in Sources */,
B5FE4DA31C8481E100FA6A91 /* StorageInterface.swift in Sources */, B5FE4DA31C8481E100FA6A91 /* StorageInterface.swift in Sources */,
B5ECDC131CA816E500C7F112 /* CSTweak.swift in Sources */, B5ECDC131CA816E500C7F112 /* CSTweak.swift in Sources */,
B56923C51EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */, B56923C51EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
@@ -2099,6 +2167,7 @@
82BA18C71C4BBD5900A0916E /* CoreStore+Migration.swift in Sources */, 82BA18C71C4BBD5900A0916E /* CoreStore+Migration.swift in Sources */,
B5E222251CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */, B5E222251CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
82BA18C41C4BBD5300A0916E /* ListMonitor.swift in Sources */, 82BA18C41C4BBD5300A0916E /* ListMonitor.swift in Sources */,
B5215CAA1FA4810300139E3A /* QueryChainBuilder.swift in Sources */,
82BA18BA1C4BBD4A00A0916E /* Select.swift in Sources */, 82BA18BA1C4BBD4A00A0916E /* Select.swift in Sources */,
B52F744B1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */, B52F744B1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, B5AEFAB61C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
@@ -2107,6 +2176,7 @@
82BA18D81C4BBD7100A0916E /* WeakObject.swift in Sources */, 82BA18D81C4BBD7100A0916E /* WeakObject.swift in Sources */,
B56923E91EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */, B56923E91EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */,
B53B27601EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */, B53B27601EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */,
B5215CA51FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */,
B5D33A021E96012400C880DE /* Relationship.swift in Sources */, B5D33A021E96012400C880DE /* Relationship.swift in Sources */,
B559CD4B1CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */, B559CD4B1CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */,
B56923CA1EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */, B56923CA1EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */,
@@ -2129,11 +2199,13 @@
82BA18A81C4BBD2900A0916E /* CoreStoreLogger.swift in Sources */, 82BA18A81C4BBD2900A0916E /* CoreStoreLogger.swift in Sources */,
B549F65F1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B549F65F1E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
B559CD451CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, B559CD451CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
82BA18B81C4BBD4200A0916E /* ClauseTypes.swift in Sources */, 82BA18B81C4BBD4200A0916E /* TypeErasedClauses.swift in Sources */,
B5CA2B131F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */,
B5A991ED1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5A991ED1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B56924001EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */, B56924001EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CAF1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */, 82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */,
B56923ED1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923ED1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
82BA18B91C4BBD4A00A0916E /* From.swift in Sources */, 82BA18B91C4BBD4A00A0916E /* From.swift in Sources */,
@@ -2189,6 +2261,7 @@
files = ( files = (
B5220E1E1D13080D009BC71E /* CSListMonitor.swift in Sources */, B5220E1E1D13080D009BC71E /* CSListMonitor.swift in Sources */,
B5DBE2D01C9914A900B5CEFA /* CSCoreStore.swift in Sources */, B5DBE2D01C9914A900B5CEFA /* CSCoreStore.swift in Sources */,
B5CA2B0B1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */,
B5677D411CD3B1E400322BFC /* ICloudStoreObserver.swift in Sources */, B5677D411CD3B1E400322BFC /* ICloudStoreObserver.swift in Sources */,
B56923F81EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */, B56923F81EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */,
B52DD1BE1BE1F94300949AFE /* Progress+Convenience.swift in Sources */, B52DD1BE1BE1F94300949AFE /* Progress+Convenience.swift in Sources */,
@@ -2200,6 +2273,7 @@
B5D339DB1E9489AB00C880DE /* CoreStoreObject.swift in Sources */, B5D339DB1E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
B52DD1951BE1F92500949AFE /* CoreStoreError.swift in Sources */, B52DD1951BE1F92500949AFE /* CoreStoreError.swift in Sources */,
B56923FD1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */, B56923FD1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
B55514ED1EED8BF900BAB888 /* From+Querying.swift in Sources */,
B596BBBE1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B596BBBE1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B546F9601C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */, B546F9601C9A12B800D5AC55 /* CSSQliteStore.swift in Sources */,
B5ECDC0F1CA8161B00C7F112 /* CSGroupBy.swift in Sources */, B5ECDC0F1CA8161B00C7F112 /* CSGroupBy.swift in Sources */,
@@ -2260,6 +2334,7 @@
B559CD4D1CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */, B559CD4D1CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */,
B5E41EC31EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */, B5E41EC31EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */,
B5ECDBE91CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */, B5ECDBE91CA6BEA300C7F112 /* CSClauseTypes.swift in Sources */,
B5A1DACB1F111BFA003CF369 /* KeyPath+Querying.swift in Sources */,
B52DD1B81BE1F94000949AFE /* DataStack+Migration.swift in Sources */, B52DD1B81BE1F94000949AFE /* DataStack+Migration.swift in Sources */,
B5ECDC091CA8138100C7F112 /* CSOrderBy.swift in Sources */, B5ECDC091CA8138100C7F112 /* CSOrderBy.swift in Sources */,
B56923C71EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */, B56923C71EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
@@ -2288,6 +2363,7 @@
B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */, B52DD1CB1BE1F94600949AFE /* WeakObject.swift in Sources */,
B52DD1C11BE1F94600949AFE /* Functions.swift in Sources */, B52DD1C11BE1F94600949AFE /* Functions.swift in Sources */,
B5220E1A1D130791009BC71E /* CoreStoreFetchedResultsController.swift in Sources */, B5220E1A1D130791009BC71E /* CoreStoreFetchedResultsController.swift in Sources */,
B5215CAC1FA4810300139E3A /* QueryChainBuilder.swift in Sources */,
B53FBA0F1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */, B53FBA0F1CAB5E6500F0D40A /* CSCoreStore+Migrating.swift in Sources */,
B52F744D1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */, B52F744D1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */, B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */,
@@ -2296,6 +2372,7 @@
B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */, B546F96C1C9AF26D00D5AC55 /* CSInMemoryStore.swift in Sources */,
B56923EB1EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */, B56923EB1EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */,
B53B27621EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */, B53B27621EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */,
B5215CA71FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */,
B5D33A041E96012400C880DE /* Relationship.swift in Sources */, B5D33A041E96012400C880DE /* Relationship.swift in Sources */,
B52DD1C61BE1F94600949AFE /* NSManagedObjectContext+CoreStore.swift in Sources */, B52DD1C61BE1F94600949AFE /* NSManagedObjectContext+CoreStore.swift in Sources */,
B56923CC1EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */, B56923CC1EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */,
@@ -2319,10 +2396,12 @@
B549F6611E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B549F6611E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
B52DD19B1BE1F92800949AFE /* CoreStoreLogger.swift in Sources */, B52DD19B1BE1F92800949AFE /* CoreStoreLogger.swift in Sources */,
B52DD1991BE1F92800949AFE /* DefaultLogger.swift in Sources */, B52DD1991BE1F92800949AFE /* DefaultLogger.swift in Sources */,
B5CA2B151F81DBFF004B1936 /* DynamicKeyPath.swift in Sources */,
B5A991EF1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5A991EF1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
B5220E201D130813009BC71E /* CSObjectMonitor.swift in Sources */, B5220E201D130813009BC71E /* CSObjectMonitor.swift in Sources */,
B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */, B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */, B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CB11FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */, B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */,
B56923EF1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923EF1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
B53FBA081CAB300C00F0D40A /* CSMigrationType.swift in Sources */, B53FBA081CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
@@ -2333,7 +2412,7 @@
B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, B5AEFAB81C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */, B598514B1C90289F00C99590 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
B5D339EA1E9493A500C880DE /* Entity.swift in Sources */, B5D339EA1E9493A500C880DE /* Entity.swift in Sources */,
B52DD1AA1BE1F93500949AFE /* ClauseTypes.swift in Sources */, B52DD1AA1BE1F93500949AFE /* TypeErasedClauses.swift in Sources */,
B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */, B53FBA021CAB2D2F00F0D40A /* CSMigrationResult.swift in Sources */,
B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, B51FE5AF1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
); );
@@ -2378,6 +2457,7 @@
files = ( files = (
B56321A91BD65219006C9394 /* Progress+Convenience.swift in Sources */, B56321A91BD65219006C9394 /* Progress+Convenience.swift in Sources */,
B5ECDBFC1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */, B5ECDBFC1CA804FD00C7F112 /* NSManagedObjectContext+ObjectiveC.swift in Sources */,
B5CA2B0A1F7E5ACA004B1936 /* WhereClauseType.swift in Sources */,
B5C976E91C6E3A5E00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */, B5C976E91C6E3A5E00B1AF90 /* CoreStoreFetchedResultsController.swift in Sources */,
B56923F71EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */, B56923F71EB828BF007C4DC9 /* CSDynamicSchema.swift in Sources */,
B56321801BD65216006C9394 /* CoreStoreError.swift in Sources */, B56321801BD65216006C9394 /* CoreStoreError.swift in Sources */,
@@ -2389,6 +2469,7 @@
B5D339DA1E9489AB00C880DE /* CoreStoreObject.swift in Sources */, B5D339DA1E9489AB00C880DE /* CoreStoreObject.swift in Sources */,
B5ECDC021CA80CBA00C7F112 /* CSWhere.swift in Sources */, B5ECDC021CA80CBA00C7F112 /* CSWhere.swift in Sources */,
B56923FC1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */, B56923FC1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */,
B55514EC1EED8BF900BAB888 /* From+Querying.swift in Sources */,
B596BBBD1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */, B596BBBD1DD5C39F001DCDD9 /* QueryableSource.swift in Sources */,
B5ECDC081CA8138100C7F112 /* CSOrderBy.swift in Sources */, B5ECDC081CA8138100C7F112 /* CSOrderBy.swift in Sources */,
B5E1B59B1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */, B5E1B59B1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
@@ -2449,6 +2530,7 @@
B501FDE51CA8D1F500BE22EF /* CSListMonitor.swift in Sources */, B501FDE51CA8D1F500BE22EF /* CSListMonitor.swift in Sources */,
B5E41EC21EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */, B5E41EC21EA9BB37006240F0 /* DynamicSchema+Convenience.swift in Sources */,
B5ECDC141CA816E500C7F112 /* CSTweak.swift in Sources */, B5ECDC141CA816E500C7F112 /* CSTweak.swift in Sources */,
B5A1DACA1F111BFA003CF369 /* KeyPath+Querying.swift in Sources */,
B56321AE1BD6521C006C9394 /* NotificationObserver.swift in Sources */, B56321AE1BD6521C006C9394 /* NotificationObserver.swift in Sources */,
B56321931BD65216006C9394 /* DataStack+Querying.swift in Sources */, B56321931BD65216006C9394 /* DataStack+Querying.swift in Sources */,
B56923C61EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */, B56923C61EB823B4007C4DC9 /* NSEntityDescription+Migration.swift in Sources */,
@@ -2477,6 +2559,7 @@
B563218E1BD65216006C9394 /* SaveResult.swift in Sources */, B563218E1BD65216006C9394 /* SaveResult.swift in Sources */,
B5E222261CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */, B5E222261CA4E12600BA2E95 /* CSSynchronousDataTransaction.swift in Sources */,
B56321A21BD65216006C9394 /* ListObserver.swift in Sources */, B56321A21BD65216006C9394 /* ListObserver.swift in Sources */,
B5215CAB1FA4810300139E3A /* QueryChainBuilder.swift in Sources */,
B563218A1BD65216006C9394 /* SynchronousDataTransaction.swift in Sources */, B563218A1BD65216006C9394 /* SynchronousDataTransaction.swift in Sources */,
B52F744C1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */, B52F744C1E9B8740005F3DAC /* CoreStoreSchema.swift in Sources */,
B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */, B5AEFAB71C9962AE00AD137F /* CoreStoreBridge.swift in Sources */,
@@ -2485,6 +2568,7 @@
B56321B61BD6521C006C9394 /* WeakObject.swift in Sources */, B56321B61BD6521C006C9394 /* WeakObject.swift in Sources */,
B56923EA1EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */, B56923EA1EB827F5007C4DC9 /* InferredSchemaMappingProvider.swift in Sources */,
B53B27611EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */, B53B27611EE3B92E00E9B352 /* CoreStoreManagedObject.swift in Sources */,
B5215CA61FA47DFD00139E3A /* FetchChainBuilder.swift in Sources */,
B5D33A031E96012400C880DE /* Relationship.swift in Sources */, B5D33A031E96012400C880DE /* Relationship.swift in Sources */,
B559CD4C1CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */, B559CD4C1CAA8C6D00E4D58B /* CSStorageInterface.swift in Sources */,
B56923CB1EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */, B56923CB1EB82410007C4DC9 /* NSManagedObjectModel+Migration.swift in Sources */,
@@ -2508,10 +2592,12 @@
B549F6601E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */, B549F6601E569C7400FBAB2D /* QueryableAttributeType.swift in Sources */,
B559CD461CAA8B6300E4D58B /* CSSetupResult.swift in Sources */, B559CD461CAA8B6300E4D58B /* CSSetupResult.swift in Sources */,
B56321A61BD65216006C9394 /* MigrationType.swift in Sources */, B56321A61BD65216006C9394 /* MigrationType.swift in Sources */,
B5CA2B141F81DBFE004B1936 /* DynamicKeyPath.swift in Sources */,
B5A991EE1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5A991EE1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B56924011EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */, B56924011EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CB01FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */, B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */,
B56923EE1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923EE1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
B56321861BD65216006C9394 /* CoreStoreLogger.swift in Sources */, B56321861BD65216006C9394 /* CoreStoreLogger.swift in Sources */,
@@ -2524,7 +2610,7 @@
B5D339E91E9493A500C880DE /* Entity.swift in Sources */, B5D339E91E9493A500C880DE /* Entity.swift in Sources */,
B56321A41BD65216006C9394 /* CoreStore+Migration.swift in Sources */, B56321A41BD65216006C9394 /* CoreStore+Migration.swift in Sources */,
B56321A01BD65216006C9394 /* ObjectObserver.swift in Sources */, B56321A01BD65216006C9394 /* ObjectObserver.swift in Sources */,
B56321951BD65216006C9394 /* ClauseTypes.swift in Sources */, B56321951BD65216006C9394 /* TypeErasedClauses.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -2558,7 +2644,9 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
@@ -2566,7 +2654,11 @@
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -2600,6 +2692,8 @@
PRODUCT_NAME = CoreStore; PRODUCT_NAME = CoreStore;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 9.0; TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@@ -2617,7 +2711,9 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
@@ -2625,7 +2721,11 @@
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -2652,6 +2752,8 @@
PRODUCT_NAME = CoreStore; PRODUCT_NAME = CoreStore;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 9.0; TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
@@ -2675,7 +2777,8 @@
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -2693,7 +2796,8 @@
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Release; name = Release;
}; };
@@ -2713,7 +2817,8 @@
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -2728,7 +2833,8 @@
PRODUCT_NAME = CoreStoreTests; PRODUCT_NAME = CoreStoreTests;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Release; name = Release;
}; };
@@ -2748,7 +2854,8 @@
SDKROOT = appletvos; SDKROOT = appletvos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3; TARGETED_DEVICE_FAMILY = 3;
}; };
name = Debug; name = Debug;
@@ -2769,7 +2876,8 @@
SDKROOT = appletvos; SDKROOT = appletvos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3; TARGETED_DEVICE_FAMILY = 3;
}; };
name = Release; name = Release;
@@ -2787,7 +2895,8 @@
SDKROOT = appletvos; SDKROOT = appletvos;
SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3; TARGETED_DEVICE_FAMILY = 3;
}; };
name = Debug; name = Debug;
@@ -2805,7 +2914,8 @@
PRODUCT_NAME = CoreStoreTests; PRODUCT_NAME = CoreStoreTests;
SDKROOT = appletvos; SDKROOT = appletvos;
SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3; TARGETED_DEVICE_FAMILY = 3;
}; };
name = Release; name = Release;
@@ -2829,7 +2939,8 @@
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -2853,7 +2964,8 @@
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Release; name = Release;
}; };
@@ -2873,7 +2985,8 @@
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -2893,7 +3006,8 @@
PRODUCT_NAME = CoreStoreTests; PRODUCT_NAME = CoreStoreTests;
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "CoreStoreTests/CoreStoreTests-Bridging-Header.h";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Release; name = Release;
}; };
@@ -2914,7 +3028,8 @@
SDKROOT = watchos; SDKROOT = watchos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 4; TARGETED_DEVICE_FAMILY = 4;
}; };
name = Debug; name = Debug;
@@ -2937,7 +3052,8 @@
SDKROOT = watchos; SDKROOT = watchos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 4; TARGETED_DEVICE_FAMILY = 4;
}; };
name = Release; name = Release;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0800" LastUpgradeVersion = "0900"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
@@ -55,6 +56,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0800" LastUpgradeVersion = "0900"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -40,6 +40,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
@@ -74,6 +75,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0800" LastUpgradeVersion = "0900"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
@@ -55,6 +56,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0800" LastUpgradeVersion = "0900"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@@ -36,6 +37,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
@@ -265,12 +265,12 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0700; LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0800; LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "John Rommel Estropia"; ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = { TargetAttributes = {
B54AAD481AF4D26E00848AE0 = { B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3; CreatedOnToolsVersion = 6.3;
LastSwiftMigration = 0800; LastSwiftMigration = 0900;
}; };
}; };
}; };
@@ -371,14 +371,20 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -407,6 +413,8 @@
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -418,14 +426,20 @@
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -445,6 +459,8 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
@@ -458,7 +474,8 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo; PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -472,7 +489,8 @@
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo; PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0; SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
}; };
name = Release; name = Release;
}; };
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0800" LastUpgradeVersion = "0900"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
@@ -165,8 +165,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From<TimeZone>(), From<TimeZone>()
OrderBy(.ascending(#keyPath(TimeZone.name))) .orderBy(.ascending(\.name))
)! )!
} }
), ),
@@ -175,9 +175,13 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From<TimeZone>(), From<TimeZone>()
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Asia"), .where(
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT))) format: "%K BEGINSWITH[c] %@",
#keyPath(TimeZone.name),
"Asia"
)
.orderBy(.ascending(\.secondsFromGMT))
)! )!
} }
), ),
@@ -186,10 +190,15 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From<TimeZone>(), From<TimeZone>()
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America") .where(
|| Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Europe"), format: "%K BEGINSWITH[c] %@ OR %K BEGINSWITH[c] %@",
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT))) #keyPath(TimeZone.name),
"America",
#keyPath(TimeZone.name),
"Europe"
)
.orderBy(.ascending(\.secondsFromGMT))
)! )!
} }
), ),
@@ -198,9 +207,13 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From<TimeZone>(), From<TimeZone>()
!Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America"), .where(
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT))) format: "%K BEGINSWITH[c] %@",
#keyPath(TimeZone.name),
"America"
)
.orderBy(.ascending(\.secondsFromGMT))
)! )!
} }
), ),
@@ -209,23 +222,23 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll( return Static.timeZonesStack.fetchAll(
From<TimeZone>(), From<TimeZone>()
Where("hasDaylightSavingTime", isEqualTo: true), .where(\.hasDaylightSavingTime == true)
OrderBy(.ascending(#keyPath(TimeZone.name))) .orderBy(.ascending(\.name))
)! )!
} }
) )
] ]
private let queryingItems = [ private let queryingItems: [(title: String, query: () -> Any)] = [
( (
title: "Number of Time Zones", title: "Number of Time Zones",
query: { () -> Any in query: { () -> Any in
return Static.timeZonesStack.queryValue( return Static.timeZonesStack.queryValue(
From<TimeZone>(), From<TimeZone>()
Select<NSNumber>(.count(#keyPath(TimeZone.name))) .select(NSNumber.self, .count(\.name))
)! )! as Any
} }
), ),
( (
@@ -233,10 +246,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
query: { () -> Any in query: { () -> Any in
return Static.timeZonesStack.queryValue( return Static.timeZonesStack.queryValue(
From<TimeZone>(), From<TimeZone>()
Select<String>(#keyPath(TimeZone.abbreviation)), .select(String.self, .attribute(\.abbreviation))
Where("%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo") .where(format: "%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
)! )! as Any
} }
), ),
( (
@@ -244,9 +257,13 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
query: { () -> Any in query: { () -> Any in
return Static.timeZonesStack.queryAttributes( return Static.timeZonesStack.queryAttributes(
From<TimeZone>(), From<TimeZone>()
Select<NSDictionary>(#keyPath(TimeZone.name), #keyPath(TimeZone.abbreviation)), .select(
OrderBy(.ascending(#keyPath(TimeZone.name))) NSDictionary.self,
.attribute(\.name),
.attribute(\.abbreviation)
)
.orderBy(.ascending(\.name))
)! )!
} }
), ),
@@ -255,10 +272,17 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
query: { () -> Any in query: { () -> Any in
return Static.timeZonesStack.queryAttributes( return Static.timeZonesStack.queryAttributes(
From<TimeZone>(), From<TimeZone>()
Select<NSDictionary>(.count(#keyPath(TimeZone.abbreviation)), #keyPath(TimeZone.abbreviation)), .select(
GroupBy(#keyPath(TimeZone.abbreviation)), NSDictionary.self,
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)), .ascending(#keyPath(TimeZone.name))) .count(\.abbreviation),
.attribute(\.abbreviation)
)
.groupBy(\.abbreviation)
.orderBy(
.ascending(\.secondsFromGMT),
.ascending(\.name)
)
)! )!
} }
), ),
@@ -267,13 +291,17 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
query: { () -> Any in query: { () -> Any in
return Static.timeZonesStack.queryAttributes( return Static.timeZonesStack.queryAttributes(
From<TimeZone>(), From<TimeZone>()
Select<NSDictionary>( .select(
.count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"), NSDictionary.self,
#keyPath(TimeZone.hasDaylightSavingTime) .count(\.hasDaylightSavingTime, as: "numberOfCountries"),
), .attribute(\.hasDaylightSavingTime)
GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)), )
OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime))) .groupBy(\.hasDaylightSavingTime)
.orderBy(
.descending(\.hasDaylightSavingTime),
.ascending(\.name)
)
)! )!
} }
) )
@@ -28,13 +28,13 @@ struct ColorsDemo {
} }
} }
func whereClause() -> Where { func whereClause() -> Where<Palette> {
switch self { switch self {
case .all: return Where(true) case .all: return .init()
case .light: return Palette.where({ $0.brightness >= 0.9 }) case .light: return (\Palette.brightness >= 0.9)
case .dark: return Palette.where({ $0.brightness <= 0.4 }) case .dark: return (\Palette.brightness <= 0.4)
} }
} }
} }
@@ -45,7 +45,7 @@ struct ColorsDemo {
self.palettes.refetch( self.palettes.refetch(
self.filter.whereClause(), self.filter.whereClause(),
Palette.orderBy(ascending: { $0.hue }) OrderBy<Palette>(.ascending(\.hue))
) )
} }
} }
@@ -74,9 +74,9 @@ struct ColorsDemo {
) )
) )
return ColorsDemo.stack.monitorSectionedList( return ColorsDemo.stack.monitorSectionedList(
From<Palette>(), From<Palette>()
SectionBy(Palette.keyPath({ $0.colorName })), .sectionBy(\.colorName)
Palette.orderBy(ascending: { $0.hue }) .orderBy(.ascending(\.hue))
) )
}() }()
} }
@@ -50,7 +50,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
if let palette = ColorsDemo.stack.fetchOne(From<Palette>(), Palette.orderBy(ascending: { $0.hue })) { if let palette = ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue))) {
self.monitor = ColorsDemo.stack.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
@@ -64,7 +64,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
} }
) )
let palette = ColorsDemo.stack.fetchOne(From<Palette>(), Palette.orderBy(ascending: { $0.hue }))! let palette = ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue)))!
self.monitor = ColorsDemo.stack.monitorObject(palette) self.monitor = ColorsDemo.stack.monitorObject(palette)
} }
@@ -85,7 +85,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
// MARK: ObjectObserver // MARK: ObjectObserver
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<RawKeyPath>) { func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPathString>) {
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys) self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
} }
@@ -99,8 +99,8 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
case 0?: case 0?:
let request = NSFetchRequest<NSFetchRequestResult>() let request = NSFetchRequest<NSFetchRequestResult>()
Where(true).applyToFetchRequest(request) Where<NSManagedObject>(true).applyToFetchRequest(request)
Where(false).applyToFetchRequest(request) Where<NSManagedObject>(false).applyToFetchRequest(request)
case 1?: case 1?:
_ = try? dataStack.addStorageAndWait( _ = try? dataStack.addStorageAndWait(
@@ -109,7 +109,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? "" let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
cell.dnaLabel?.text = "DNA: \(dna)" cell.dnaLabel?.text = "DNA: \(dna)"
cell.mutateButtonHandler = { [weak self] _ -> Void in cell.mutateButtonHandler = { [weak self] () -> Void in
guard let `self` = self, guard let `self` = self,
let dataStack = self.dataStack, let dataStack = self.dataStack,
@@ -287,8 +287,8 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
self.set(dataStack: dataStack, model: model, scrollToSelection: true) self.set(dataStack: dataStack, model: model, scrollToSelection: true)
let count = dataStack.queryValue( let count = dataStack.queryValue(
From(model.entityType), From<NSManagedObject>(model.entityType)
Select<Int>(.count(#keyPath(OrganismV1.dna))))! .select(Int.self, .count(#keyPath(OrganismV1.dna))))!
if count > 0 { if count > 0 {
self.setEnabled(true) self.setEnabled(true)
@@ -361,14 +361,18 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
self.segmentedControl?.selectedSegmentIndex = self.models self.segmentedControl?.selectedSegmentIndex = self.models
.index( .index(
where: { (_, _, schemaHistory) -> Bool in where: { (arg) -> Bool in
schemaHistory.currentModelVersion == model.schemaHistory.currentModelVersion let (_, _, schemaHistory) = arg
return schemaHistory.currentModelVersion == model.schemaHistory.currentModelVersion
} }
)! )!
self._dataStack = dataStack self._dataStack = dataStack
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.descending("dna"))) let listMonitor = dataStack.monitorList(
From(model.entityType),
OrderBy<NSManagedObject>(.descending(#keyPath(OrganismV1.dna)))
)
listMonitor.addObserver(self) listMonitor.addObserver(self)
self._listMonitor = listMonitor self._listMonitor = listMonitor
@@ -131,7 +131,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
// none // none
} }
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<RawKeyPath>) { func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPathString>) {
if let mapView = self.mapView { if let mapView = self.mapView {
@@ -2,8 +2,25 @@
// BaseTestDataTestCase.swift // BaseTestDataTestCase.swift
// CoreStore // CoreStore
// //
// Created by John Rommel Estropia on 2016/06/11. // Copyright © 2017 John Rommel Estropia
// Copyright © 2016 John Rommel Estropia. All rights reserved. //
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// //
import Foundation import Foundation
+8 -8
View File
@@ -40,8 +40,8 @@ class ConvenienceTests: BaseTestCase {
let controller = stack.createFetchedResultsController( let controller = stack.createFetchedResultsController(
From<TestEntity1>(), From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)), SectionBy(#keyPath(TestEntity1.testString)),
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100), Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.ascending(#keyPath(TestEntity1.testString))), OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 } Tweak { $0.fetchLimit = 10 }
) )
XCTAssertEqual(controller.managedObjectContext, stack.mainContext) XCTAssertEqual(controller.managedObjectContext, stack.mainContext)
@@ -49,11 +49,11 @@ class ConvenienceTests: BaseTestCase {
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString)) XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual( XCTAssertEqual(
controller.fetchRequest.sortDescriptors!, controller.fetchRequest.sortDescriptors!,
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
) )
XCTAssertEqual( XCTAssertEqual(
controller.fetchRequest.predicate, controller.fetchRequest.predicate,
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
) )
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10) XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
} }
@@ -69,8 +69,8 @@ class ConvenienceTests: BaseTestCase {
let controller = transaction.createFetchedResultsController( let controller = transaction.createFetchedResultsController(
From<TestEntity1>(), From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)), SectionBy(#keyPath(TestEntity1.testString)),
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100), Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.ascending(#keyPath(TestEntity1.testString))), OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 } Tweak { $0.fetchLimit = 10 }
) )
XCTAssertEqual(controller.managedObjectContext, transaction.context) XCTAssertEqual(controller.managedObjectContext, transaction.context)
@@ -78,11 +78,11 @@ class ConvenienceTests: BaseTestCase {
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString)) XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual( XCTAssertEqual(
controller.fetchRequest.sortDescriptors!, controller.fetchRequest.sortDescriptors!,
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
) )
XCTAssertEqual( XCTAssertEqual(
controller.fetchRequest.predicate, controller.fetchRequest.predicate,
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
) )
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10) XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
} }
+51 -13
View File
@@ -101,8 +101,8 @@ class Person: CoreStoreObject {
static func keyPathsAffectingDisplayName() -> Set<String> { static func keyPathsAffectingDisplayName() -> Set<String> {
return [ return [
self.keyPath({ $0.title }), String(keyPath: \Person.title),
self.keyPath({ $0.name }) String(keyPath: \Person.name)
] ]
} }
} }
@@ -112,7 +112,8 @@ class Person: CoreStoreObject {
class DynamicModelTests: BaseTestDataTestCase { class DynamicModelTests: BaseTestDataTestCase {
func testDynamicModels_CanBeDeclaredCorrectly() { @objc
dynamic func test_ThatDynamicModels_CanBeDeclaredCorrectly() {
let dataStack = DataStack( let dataStack = DataStack(
CoreStoreSchema( CoreStoreSchema(
@@ -131,13 +132,13 @@ class DynamicModelTests: BaseTestDataTestCase {
) )
self.prepareStack(dataStack, configurations: [nil]) { (stack) in self.prepareStack(dataStack, configurations: [nil]) { (stack) in
let k1 = Animal.keyPath({ $0.species }) let k1 = String(keyPath: \Animal.species)
XCTAssertEqual(k1, "species") XCTAssertEqual(k1, "species")
let k2 = Dog.keyPath({ $0.species }) let k2 = String(keyPath: \Dog.species)
XCTAssertEqual(k2, "species") XCTAssertEqual(k2, "species")
let k3 = Dog.keyPath({ $0.nickname }) let k3 = String(keyPath: \Dog.nickname)
XCTAssertEqual(k3, "nickname") XCTAssertEqual(k3, "nickname")
let updateDone = self.expectation(description: "update-done") let updateDone = self.expectation(description: "update-done")
@@ -170,7 +171,7 @@ class DynamicModelTests: BaseTestDataTestCase {
XCTAssertTrue(person.pets.value.isEmpty) XCTAssertTrue(person.pets.value.isEmpty)
XCTAssertEqual( XCTAssertEqual(
object_getClass(person.rawObject!).keyPathsForValuesAffectingValue(forKey: "displayName"), type(of: person.rawObject!).keyPathsForValuesAffectingValue(forKey: "displayName"),
["title", "name"] ["title", "name"]
) )
@@ -196,7 +197,7 @@ class DynamicModelTests: BaseTestDataTestCase {
XCTAssertEqual(dog.master.value, person) XCTAssertEqual(dog.master.value, person)
XCTAssertEqual(dog.master.value?.pets.value.first, dog) XCTAssertEqual(dog.master.value?.pets.value.first, dog)
}, },
success: { success: { _ in
updateDone.fulfill() updateDone.fulfill()
}, },
@@ -208,17 +209,17 @@ class DynamicModelTests: BaseTestDataTestCase {
stack.perform( stack.perform(
asynchronous: { (transaction) in asynchronous: { (transaction) in
let p1 = Animal.where({ $0.species == "Sparrow" }) let p1 = Where<Animal>({ $0.species == "Sparrow" })
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow")) XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
let bird = transaction.fetchOne(From<Animal>(), p1) let bird = transaction.fetchOne(From<Animal>(), p1)
XCTAssertNotNil(bird) XCTAssertNotNil(bird)
XCTAssertEqual(bird!.species.value, "Sparrow") XCTAssertEqual(bird!.species.value, "Sparrow")
let p2 = Dog.where({ $0.nickname == "Spot" }) let p2 = Where<Dog>({ $0.nickname == "Spot" })
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot")) XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
let dog = transaction.fetchOne(From<Dog>(), p2) let dog = transaction.fetchOne(From<Dog>().where(\.nickname == "Spot"))
XCTAssertNotNil(dog) XCTAssertNotNil(dog)
XCTAssertEqual(dog!.nickname.value, "Spot") XCTAssertEqual(dog!.nickname.value, "Spot")
XCTAssertEqual(dog!.species.value, "Dog") XCTAssertEqual(dog!.species.value, "Dog")
@@ -227,10 +228,40 @@ class DynamicModelTests: BaseTestDataTestCase {
XCTAssertNotNil(person) XCTAssertNotNil(person)
XCTAssertEqual(person!.pets.value.first, dog) XCTAssertEqual(person!.pets.value.first, dog)
let p3 = Dog.where({ $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))
_ = transaction.fetchAll(
From<Dog>()
.where(\Animal.species == "Dog" && \.age == 10)
)
_ = transaction.fetchAll(
From<Dog>()
.where(\.age == 10 && \Animal.species == "Dog")
.orderBy(.ascending({ $0.species }))
)
_ = transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.age > 10 && $0.age <= 15 })
)
_ = transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.species == "Dog" && $0.age == 10 })
)
_ = transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.age == 10 && $0.species == "Dog" })
)
_ = transaction.fetchAll(
From<Dog>(),
Where<Dog>({ $0.age > 10 && $0.age <= 15 })
)
_ = transaction.fetchAll(
From<Dog>(),
(\Dog.age > 10 && \Dog.age <= 15)
)
}, },
success: { success: { _ in
fetchDone.fulfill() fetchDone.fulfill()
}, },
@@ -243,6 +274,13 @@ class DynamicModelTests: BaseTestDataTestCase {
} }
} }
@objc
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertEqual(String(keyPath: \Animal.species), "species")
XCTAssertEqual(String(keyPath: \Dog.species), "species")
}
@nonobjc @nonobjc
func prepareStack(_ dataStack: DataStack, configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> Void) { func prepareStack(_ dataStack: DataStack, configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> Void) {
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -38,14 +38,14 @@ final class GroupByTests: BaseTestCase {
do { do {
let groupBy = GroupBy() let groupBy = GroupBy<NSManagedObject>()
XCTAssertEqual(groupBy, GroupBy([] as [String])) XCTAssertEqual(groupBy, GroupBy([] as [String]))
XCTAssertNotEqual(groupBy, GroupBy("key")) XCTAssertNotEqual(groupBy, GroupBy("key"))
XCTAssertTrue(groupBy.keyPaths.isEmpty) XCTAssertTrue(groupBy.keyPaths.isEmpty)
} }
do { do {
let groupBy = GroupBy("key1") let groupBy = GroupBy<NSManagedObject>("key1")
XCTAssertEqual(groupBy, GroupBy("key1")) XCTAssertEqual(groupBy, GroupBy("key1"))
XCTAssertEqual(groupBy, GroupBy(["key1"])) XCTAssertEqual(groupBy, GroupBy(["key1"]))
XCTAssertNotEqual(groupBy, GroupBy("key2")) XCTAssertNotEqual(groupBy, GroupBy("key2"))
@@ -53,7 +53,7 @@ final class GroupByTests: BaseTestCase {
} }
do { do {
let groupBy = GroupBy("key1", "key2") let groupBy = GroupBy<NSManagedObject>("key1", "key2")
XCTAssertEqual(groupBy, GroupBy("key1", "key2")) XCTAssertEqual(groupBy, GroupBy("key1", "key2"))
XCTAssertEqual(groupBy, GroupBy(["key1", "key2"])) XCTAssertEqual(groupBy, GroupBy(["key1", "key2"]))
XCTAssertNotEqual(groupBy, GroupBy("key2", "key1")) XCTAssertNotEqual(groupBy, GroupBy("key2", "key1"))
@@ -66,7 +66,7 @@ final class GroupByTests: BaseTestCase {
self.prepareStack { (dataStack) in self.prepareStack { (dataStack) in
let groupBy = GroupBy(#keyPath(TestEntity1.testString)) let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
let request = CoreStoreFetchRequest() let request = CoreStoreFetchRequest()
_ = From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext) _ = From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
+13 -11
View File
@@ -444,7 +444,7 @@ class ImportTests: BaseTestDataTestCase {
XCTAssertNil(object) XCTAssertNil(object)
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5) XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5)
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105)) let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
XCTAssertNotNil(existingObjects) XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1) XCTAssertEqual(existingObjects?.count, 1)
@@ -565,7 +565,9 @@ class ImportTests: BaseTestDataTestCase {
XCTAssertEqual(objects.count, 2) XCTAssertEqual(objects.count, 2)
zip(objects, sourceArray) zip(objects, sourceArray)
.forEach { object, dictionary in .forEach {
let (object, dictionary) = $0
XCTAssertEqual(object.testEntityID, dictionary[(#keyPath(TestEntity1.testEntityID))] as? NSNumber) XCTAssertEqual(object.testEntityID, dictionary[(#keyPath(TestEntity1.testEntityID))] as? NSNumber)
XCTAssertEqual(object.testBoolean, dictionary[(#keyPath(TestEntity1.testBoolean))] as? NSNumber) XCTAssertEqual(object.testBoolean, dictionary[(#keyPath(TestEntity1.testBoolean))] as? NSNumber)
XCTAssertEqual(object.testNumber, dictionary[(#keyPath(TestEntity1.testNumber))] as? NSNumber) XCTAssertEqual(object.testNumber, dictionary[(#keyPath(TestEntity1.testNumber))] as? NSNumber)
@@ -618,7 +620,7 @@ class ImportTests: BaseTestDataTestCase {
errorExpectation.fulfill() errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6) XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
let object = transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106)) let object = transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
XCTAssertNotNil(object) XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(value: 106)) XCTAssertEqual(object?.testEntityID, NSNumber(value: 106))
XCTAssertNil(object?.testBoolean) XCTAssertNil(object?.testBoolean)
@@ -657,7 +659,7 @@ class ImportTests: BaseTestDataTestCase {
errorExpectation.fulfill() errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6) XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105)) let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
XCTAssertNotNil(existingObjects) XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1) XCTAssertEqual(existingObjects?.count, 1)
@@ -743,7 +745,7 @@ class ImportTests: BaseTestDataTestCase {
XCTAssertEqual(object?.testData, ("nil:TestEntity1:7" as NSString).data(using: String.Encoding.utf8.rawValue)!) XCTAssertEqual(object?.testData, ("nil:TestEntity1:7" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-07T00:00:00Z")!) XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-07T00:00:00Z")!)
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106)) let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
XCTAssertNotNil(existingObjects) XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1) XCTAssertEqual(existingObjects?.count, 1)
@@ -864,8 +866,8 @@ class ImportTests: BaseTestDataTestCase {
errorExpectation.fulfill() errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5) XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5)
XCTAssertNil(transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))) XCTAssertNil(transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106)))
XCTAssertNil(transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 107))) XCTAssertNil(transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 107)))
} }
transaction.unsafeContext().reset() transaction.unsafeContext().reset()
self.checkExpectationsImmediately() self.checkExpectationsImmediately()
@@ -908,7 +910,7 @@ class ImportTests: BaseTestDataTestCase {
errorExpectation.fulfill() errorExpectation.fulfill()
let object = transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106)) let object = transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
XCTAssertNotNil(object) XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(value: 106)) XCTAssertEqual(object?.testEntityID, NSNumber(value: 106))
XCTAssertNil(object?.testBoolean) XCTAssertNil(object?.testBoolean)
@@ -951,7 +953,7 @@ class ImportTests: BaseTestDataTestCase {
errorExpectation.fulfill() errorExpectation.fulfill()
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5) XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5)
let object = transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105)) let object = transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
XCTAssertNotNil(object) XCTAssertNotNil(object)
XCTAssertEqual(object?.testEntityID, NSNumber(value: 105)) XCTAssertEqual(object?.testEntityID, NSNumber(value: 105))
XCTAssertEqual(object?.testBoolean, NSNumber(value: true)) XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
@@ -961,7 +963,7 @@ class ImportTests: BaseTestDataTestCase {
XCTAssertEqual(object?.testData, ("nil:TestEntity1:5" as NSString).data(using: String.Encoding.utf8.rawValue)!) XCTAssertEqual(object?.testData, ("nil:TestEntity1:5" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-05T00:00:00Z")!) XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-05T00:00:00Z")!)
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105)) let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
XCTAssertNotNil(existingObjects) XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1) XCTAssertEqual(existingObjects?.count, 1)
@@ -1030,7 +1032,7 @@ class ImportTests: BaseTestDataTestCase {
XCTAssertEqual(object.testData, dictionary[(#keyPath(TestEntity1.testData))] as? Data) XCTAssertEqual(object.testData, dictionary[(#keyPath(TestEntity1.testData))] as? Data)
XCTAssertEqual(object.testDate, dictionary[(#keyPath(TestEntity1.testDate))] as? Date) XCTAssertEqual(object.testDate, dictionary[(#keyPath(TestEntity1.testDate))] as? Date)
} }
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105)) let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
XCTAssertNotNil(existingObjects) XCTAssertNotNil(existingObjects)
XCTAssertEqual(existingObjects?.count, 1) XCTAssertEqual(existingObjects?.count, 1)
+22 -22
View File
@@ -43,7 +43,7 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From<TestEntity1>(), From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID))) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
@@ -54,7 +54,7 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let willChangeExpectation = self.expectation( let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -68,7 +68,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didInsertSectionExpectation = self.expectation( let didInsertSectionExpectation = self.expectation(
forNotification: "listMonitor:didInsertSection:toSectionIndex:", forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -88,7 +88,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didInsertObjectExpectation = self.expectation( let didInsertObjectExpectation = self.expectation(
forNotification: "listMonitor:didInsertObject:toIndexPath:", forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -120,7 +120,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didChangeExpectation = self.expectation( let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -171,7 +171,7 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From<TestEntity1>(), From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID))) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
@@ -185,7 +185,7 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let willChangeExpectation = self.expectation( let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -200,7 +200,7 @@ class ListObserverTests: BaseTestDataTestCase {
) )
let didUpdateObjectExpectation = self.expectation( let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didUpdateObject:atIndexPath:", forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -251,7 +251,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didChangeExpectation = self.expectation( let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -270,7 +270,7 @@ class ListObserverTests: BaseTestDataTestCase {
if let object = transaction.fetchOne( if let object = transaction.fetchOne(
From<TestEntity1>(), From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) { Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
object.testNumber = NSNumber(value: 11) object.testNumber = NSNumber(value: 11)
object.testDecimal = NSDecimalNumber(string: "11") object.testDecimal = NSDecimalNumber(string: "11")
@@ -284,7 +284,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
if let object = transaction.fetchOne( if let object = transaction.fetchOne(
From<TestEntity1>(), From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) { Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
object.testNumber = NSNumber(value: 22) object.testNumber = NSNumber(value: 22)
object.testDecimal = NSDecimalNumber(string: "22") object.testDecimal = NSDecimalNumber(string: "22")
@@ -323,14 +323,14 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From<TestEntity1>(), From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID))) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
var events = 0 var events = 0
let willChangeExpectation = self.expectation( let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -344,7 +344,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didMoveObjectExpectation = self.expectation( let didMoveObjectExpectation = self.expectation(
forNotification: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:", forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -377,7 +377,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didChangeExpectation = self.expectation( let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -396,7 +396,7 @@ class ListObserverTests: BaseTestDataTestCase {
if let object = transaction.fetchOne( if let object = transaction.fetchOne(
From<TestEntity1>(), From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) { Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
object.testBoolean = NSNumber(value: true) object.testBoolean = NSNumber(value: true)
} }
@@ -431,14 +431,14 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList( let monitor = stack.monitorSectionedList(
From<TestEntity1>(), From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)), SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID))) OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
var events = 0 var events = 0
let willChangeExpectation = self.expectation( let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -452,7 +452,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didUpdateObjectExpectation = self.expectation( let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didDeleteObject:fromIndexPath:", forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -481,7 +481,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didDeleteSectionExpectation = self.expectation( let didDeleteSectionExpectation = self.expectation(
forNotification: "listMonitor:didDeleteSection:fromSectionIndex:", forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -509,7 +509,7 @@ class ListObserverTests: BaseTestDataTestCase {
} }
) )
let didChangeExpectation = self.expectation( let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -528,7 +528,7 @@ class ListObserverTests: BaseTestDataTestCase {
let count = transaction.deleteAll( let count = transaction.deleteAll(
From<TestEntity1>(), From<TestEntity1>(),
Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false) Where<TestEntity1>(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
) )
XCTAssertEqual(count, 2) XCTAssertEqual(count, 2)
return transaction.hasChanges return transaction.hasChanges
+5 -5
View File
@@ -43,7 +43,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
guard let object = stack.fetchOne( guard let object = stack.fetchOne(
From<TestEntity1>(), From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else { Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail() XCTFail()
return return
@@ -58,7 +58,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let willUpdateExpectation = self.expectation( let willUpdateExpectation = self.expectation(
forNotification: "objectMonitor:willUpdateObject:", forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -75,7 +75,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
} }
) )
let didUpdateExpectation = self.expectation( let didUpdateExpectation = self.expectation(
forNotification: "objectMonitor:didUpdateObject:changedPersistentKeys:", forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -140,7 +140,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
guard let object = stack.fetchOne( guard let object = stack.fetchOne(
From<TestEntity1>(), From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else { Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail() XCTFail()
return return
@@ -155,7 +155,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0 var events = 0
let didDeleteExpectation = self.expectation( let didDeleteExpectation = self.expectation(
forNotification: "objectMonitor:didDeleteObject:", forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
+44 -44
View File
@@ -38,21 +38,21 @@ final class OrderByTests: XCTestCase {
do { do {
let orderBy = OrderBy() let orderBy = OrderBy<NSManagedObject>()
XCTAssertEqual(orderBy, OrderBy([NSSortDescriptor]())) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([NSSortDescriptor]()))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key", ascending: false))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key", ascending: false)))
XCTAssertTrue(orderBy.sortDescriptors.isEmpty) XCTAssertTrue(orderBy.sortDescriptors.isEmpty)
} }
do { do {
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true) let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
let orderBy = OrderBy(sortDescriptor) let orderBy = OrderBy<NSManagedObject>(sortDescriptor)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor)) XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.descending("key1"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key1", ascending: false))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key1", ascending: false)))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor])) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor]) XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
} }
do { do {
@@ -61,76 +61,76 @@ final class OrderByTests: XCTestCase {
NSSortDescriptor(key: "key1", ascending: true), NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
let orderBy = OrderBy(sortDescriptors) let orderBy = OrderBy<NSManagedObject>(sortDescriptors)
XCTAssertEqual(orderBy, OrderBy(sortDescriptors)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy<NSManagedObject>(
[ [
NSSortDescriptor(key: "key1", ascending: false), NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
do { do {
let orderBy = OrderBy(.ascending("key1")) let orderBy = OrderBy<NSManagedObject>(.ascending("key1"))
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true) let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.descending("key1"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor])) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor]) XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
} }
do { do {
let orderBy = OrderBy(.ascending("key1"), .descending("key2")) let orderBy = OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"))
let sortDescriptors = [ let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true), NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy<NSManagedObject>(
[ [
NSSortDescriptor(key: "key1", ascending: false), NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
do { do {
let sortKeys: [SortKey] = [.ascending("key1"), .descending("key2")] let sortKeys: [OrderBy<NSManagedObject>.SortKey] = [.ascending("key1"), .descending("key2")]
let orderBy = OrderBy(sortKeys) let orderBy = OrderBy<NSManagedObject>(sortKeys)
let sortDescriptors = [ let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true), NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors)) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2"))) XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual( XCTAssertNotEqual(
orderBy, orderBy,
OrderBy( OrderBy<NSManagedObject>(
[ [
NSSortDescriptor(key: "key1", ascending: false), NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false) NSSortDescriptor(key: "key2", ascending: false)
] ]
) )
) )
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3"))) XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors) XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
} }
} }
@@ -138,15 +138,15 @@ final class OrderByTests: XCTestCase {
@objc @objc
dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() { dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() {
let orderBy1 = OrderBy(.ascending("key1")) let orderBy1 = OrderBy<NSManagedObject>(.ascending("key1"))
let orderBy2 = OrderBy(.descending("key2")) let orderBy2 = OrderBy<NSManagedObject>(.descending("key2"))
let orderBy3 = OrderBy(.ascending("key3")) let orderBy3 = OrderBy<NSManagedObject>(.ascending("key3"))
do { do {
let plusOrderBy = orderBy1 + orderBy2 + orderBy3 let plusOrderBy = orderBy1 + orderBy2 + orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2"), .ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.descending("key2"), .ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2"), .ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2) XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -158,14 +158,14 @@ final class OrderByTests: XCTestCase {
var plusOrderBy = orderBy1 var plusOrderBy = orderBy1
plusOrderBy += orderBy2 plusOrderBy += orderBy2
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.descending("key2"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2")))
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1)
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors) XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors)
plusOrderBy += orderBy3 plusOrderBy += orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2"), .ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2")) + OrderBy(.ascending("key3"))) XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")) + OrderBy<NSManagedObject>(.ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2) XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1) XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -178,7 +178,7 @@ final class OrderByTests: XCTestCase {
@objc @objc
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() { dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
let orderBy = OrderBy(.ascending("key")) let orderBy = OrderBy<NSManagedObject>(.ascending("key"))
let request = CoreStoreFetchRequest() let request = CoreStoreFetchRequest()
orderBy.applyToFetchRequest(request) orderBy.applyToFetchRequest(request)
XCTAssertNotNil(request.sortDescriptors) XCTAssertNotNil(request.sortDescriptors)
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -39,13 +39,13 @@ final class SectionByTests: XCTestCase {
do { do {
let sectionBy = SectionBy("key") let sectionBy = SectionBy<NSManagedObject>("key")
XCTAssertEqual(sectionBy.sectionKeyPath, "key") XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key") XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key")
} }
do { do {
let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } } let sectionBy = SectionBy<NSManagedObject>("key") { $0.flatMap { "\($0):suffix" } }
XCTAssertEqual(sectionBy.sectionKeyPath, "key") XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix") XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(nil)) XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
+19 -19
View File
@@ -38,7 +38,7 @@ final class SelectTests: XCTestCase {
do { do {
let term: SelectTerm = "attribute" let term: SelectTerm<NSManagedObject> = "attribute"
XCTAssertEqual(term, SelectTerm.attribute("attribute")) XCTAssertEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
@@ -58,7 +58,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.attribute("attribute") let term = SelectTerm<NSManagedObject>.attribute("attribute")
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute")) XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute")) XCTAssertNotEqual(term, SelectTerm.count("attribute"))
@@ -82,7 +82,7 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.average("attribute") let term = SelectTerm<NSManagedObject>.average("attribute")
XCTAssertEqual(term, SelectTerm.average("attribute")) XCTAssertEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2")) XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
@@ -106,7 +106,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.average("attribute", as: "alias") let term = SelectTerm<NSManagedObject>.average("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias")) XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2")) XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
@@ -135,7 +135,7 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.count("attribute") let term = SelectTerm<NSManagedObject>.count("attribute")
XCTAssertEqual(term, SelectTerm.count("attribute")) XCTAssertEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2")) XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
@@ -159,7 +159,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.count("attribute", as: "alias") let term = SelectTerm<NSManagedObject>.count("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias")) XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2")) XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
@@ -188,7 +188,7 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.maximum("attribute") let term = SelectTerm<NSManagedObject>.maximum("attribute")
XCTAssertEqual(term, SelectTerm.maximum("attribute")) XCTAssertEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
@@ -212,7 +212,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.maximum("attribute", as: "alias") let term = SelectTerm<NSManagedObject>.maximum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias")) XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2")) XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
@@ -241,7 +241,7 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.minimum("attribute") let term = SelectTerm<NSManagedObject>.minimum("attribute")
XCTAssertEqual(term, SelectTerm.minimum("attribute")) XCTAssertEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
@@ -265,7 +265,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.minimum("attribute", as: "alias") let term = SelectTerm<NSManagedObject>.minimum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias")) XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2")) XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
@@ -294,7 +294,7 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.sum("attribute") let term = SelectTerm<NSManagedObject>.sum("attribute")
XCTAssertEqual(term, SelectTerm.sum("attribute")) XCTAssertEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias")) XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2")) XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
@@ -318,7 +318,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.sum("attribute", as: "alias") let term = SelectTerm<NSManagedObject>.sum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias")) XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2")) XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2")) XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
@@ -347,7 +347,7 @@ final class SelectTests: XCTestCase {
do { do {
let term = SelectTerm.objectID() let term = SelectTerm<NSManagedObject>.objectID()
XCTAssertEqual(term, SelectTerm.objectID()) XCTAssertEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias")) XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute")) XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
@@ -368,7 +368,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let term = SelectTerm.objectID(as: "alias") let term = SelectTerm<NSManagedObject>.objectID(as: "alias")
XCTAssertEqual(term, SelectTerm.objectID(as: "alias")) XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2")) XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.objectID()) XCTAssertNotEqual(term, SelectTerm.objectID())
@@ -393,12 +393,12 @@ final class SelectTests: XCTestCase {
@objc @objc
dynamic func test_ThatSelectClauses_ConfigureCorrectly() { dynamic func test_ThatSelectClauses_ConfigureCorrectly() {
let term1 = SelectTerm.attribute("attribute1") let term1 = SelectTerm<NSManagedObject>.attribute("attribute1")
let term2 = SelectTerm.attribute("attribute2") let term2 = SelectTerm<NSManagedObject>.attribute("attribute2")
let term3 = SelectTerm.attribute("attribute3") let term3 = SelectTerm<NSManagedObject>.attribute("attribute3")
do { do {
let select = Select<Int>(term1, term2, term3) let select = Select<NSManagedObject, Int>(term1, term2, term3)
XCTAssertEqual(select.selectTerms, [term1, term2, term3]) XCTAssertEqual(select.selectTerms, [term1, term2, term3])
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2]) XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3]) XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
@@ -408,7 +408,7 @@ final class SelectTests: XCTestCase {
} }
do { do {
let select = Select<Int>([term1, term2, term3]) let select = Select<NSManagedObject, Int>([term1, term2, term3])
XCTAssertEqual(select.selectTerms, [term1, term2, term3]) XCTAssertEqual(select.selectTerms, [term1, term2, term3])
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2]) XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3]) XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
+7 -7
View File
@@ -396,7 +396,7 @@ final class TransactionTests: BaseTestCase {
let observer = TestListObserver() let observer = TestListObserver()
let monitor = stack.monitorList( let monitor = stack.monitorList(
From<TestEntity1>(), From<TestEntity1>(),
OrderBy(.ascending("testEntityID")) OrderBy<TestEntity1>(.ascending("testEntityID"))
) )
monitor.addObserver(observer) monitor.addObserver(observer)
@@ -404,7 +404,7 @@ final class TransactionTests: BaseTestCase {
var events = 0 var events = 0
let willChangeExpectation = self.expectation( let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:", forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -418,7 +418,7 @@ final class TransactionTests: BaseTestCase {
} }
) )
let didInsertObjectExpectation = self.expectation( let didInsertObjectExpectation = self.expectation(
forNotification: "listMonitor:didInsertObject:toIndexPath:", forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -448,7 +448,7 @@ final class TransactionTests: BaseTestCase {
} }
) )
let didChangeExpectation = self.expectation( let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:", forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer, object: observer,
handler: { (note) -> Bool in handler: { (note) -> Bool in
@@ -737,7 +737,7 @@ final class TransactionTests: BaseTestCase {
createDiscardExpectation.fulfill() createDiscardExpectation.fulfill()
try transaction.cancel() try transaction.cancel()
}, },
success: { success: { _ in
XCTFail() XCTFail()
}, },
@@ -795,7 +795,7 @@ final class TransactionTests: BaseTestCase {
try transaction.cancel() try transaction.cancel()
}, },
success: { success: { _ in
XCTFail() XCTFail()
}, },
@@ -828,7 +828,7 @@ final class TransactionTests: BaseTestCase {
try transaction.cancel() try transaction.cancel()
}, },
success: { success: { _ in
XCTFail() XCTFail()
}, },
+100 -94
View File
@@ -31,12 +31,12 @@ import CoreStore
// MARK: - XCTAssertAllEqual // MARK: - XCTAssertAllEqual
private func XCTAssertAllEqual(_ whereClauses: Where...) { private func XCTAssertAllEqual<D>(_ whereClauses: Where<D>...) {
XCTAssertAllEqual(whereClauses) XCTAssertAllEqual(whereClauses)
} }
private func XCTAssertAllEqual(_ whereClauses: [Where]) { private func XCTAssertAllEqual<D>(_ whereClauses: [Where<D>]) {
for i in whereClauses.indices { for i in whereClauses.indices {
@@ -52,56 +52,62 @@ private func XCTAssertAllEqual(_ whereClauses: [Where]) {
final class WhereTests: XCTestCase { final class WhereTests: XCTestCase {
@objc
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
}
@objc @objc
dynamic func test_ThatWhereClauses_ConfigureCorrectly() { dynamic func test_ThatWhereClauses_ConfigureCorrectly() {
do { do {
let whereClause = Where() let whereClause = Where<NSManagedObject>()
XCTAssertEqual(whereClause, Where(true)) XCTAssertEqual(whereClause, Where<NSManagedObject>(true))
XCTAssertNotEqual(whereClause, Where(false)) XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true)) XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
} }
do { do {
let whereClause = Where(true) let whereClause = Where<NSManagedObject>(true)
XCTAssertEqual(whereClause, Where()) XCTAssertEqual(whereClause, Where<NSManagedObject>())
XCTAssertNotEqual(whereClause, Where(false)) XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true)) XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
} }
do { do {
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
let whereClause = Where(predicate) let whereClause = Where<NSManagedObject>(predicate)
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("%K == %@", "key", "value") let whereClause = Where<NSManagedObject>("%K == %@", "key", "value")
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("%K == %@", argumentArray: ["key", "value"]) let whereClause = Where<NSManagedObject>("%K == %@", argumentArray: ["key", "value"])
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("key", isEqualTo: "value") let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let predicate = NSPredicate(format: "%K == %@", "key", "value") let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
do { do {
let whereClause = Where("key", isMemberOf: ["value1", "value2", "value3"]) let whereClause = Where<NSManagedObject>("key", isMemberOf: ["value1", "value2", "value3"])
let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"]) let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"])
XCTAssertEqual(whereClause, Where(predicate)) XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertEqual(whereClause.predicate, predicate) XCTAssertEqual(whereClause.predicate, predicate)
} }
} }
@@ -113,112 +119,112 @@ final class WhereTests: XCTestCase {
let value: Int = 100 let value: Int = 100
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K == %d", "key", value), Where<NSManagedObject>("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject), Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", NSNumber(value: value)), Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
Where("%K == %@", "key", value), Where<NSManagedObject>("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject), Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", NSNumber(value: value)), Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
Where("key", isEqualTo: value), Where<NSManagedObject>("key", isEqualTo: value),
Where("key", isEqualTo: NSNumber(value: value)) Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
) )
} }
do { do {
let value = NSNumber(value: 100) let value = NSNumber(value: 100)
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K == %d", "key", value), Where<NSManagedObject>("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject), Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", value.intValue), Where<NSManagedObject>("%K == %d", "key", value.intValue),
Where("%K == %@", "key", value), Where<NSManagedObject>("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject), Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", value.intValue), Where<NSManagedObject>("%K == %@", "key", value.intValue),
Where("key", isEqualTo: value), Where<NSManagedObject>("key", isEqualTo: value),
Where("key", isEqualTo: value.intValue) Where<NSManagedObject>("key", isEqualTo: value.intValue)
) )
} }
do { do {
let value: Int64 = Int64.max let value: Int64 = Int64.max
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K == %d", "key", value), Where<NSManagedObject>("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject), Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", NSNumber(value: value)), Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
Where("%K == %@", "key", value), Where<NSManagedObject>("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject), Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", NSNumber(value: value)), Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
Where("key", isEqualTo: value), Where<NSManagedObject>("key", isEqualTo: value),
Where("key", isEqualTo: NSNumber(value: value)) Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
) )
} }
do { do {
let value = NSNumber(value: Int64.max) let value = NSNumber(value: Int64.max)
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K == %d", "key", value), Where<NSManagedObject>("%K == %d", "key", value),
Where("%K == %d", "key", value as AnyObject), Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where("%K == %d", "key", value.int64Value), Where<NSManagedObject>("%K == %d", "key", value.int64Value),
Where("%K == %@", "key", value), Where<NSManagedObject>("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject), Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", value.int64Value), Where<NSManagedObject>("%K == %@", "key", value.int64Value),
Where("key", isEqualTo: value), Where<NSManagedObject>("key", isEqualTo: value),
Where("key", isEqualTo: value.int64Value) Where<NSManagedObject>("key", isEqualTo: value.int64Value)
) )
} }
do { do {
let value: String = "value" let value: String = "value"
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K == %s", "key", value), Where<NSManagedObject>("%K == %s", "key", value),
Where("%K == %s", "key", value as AnyObject), Where<NSManagedObject>("%K == %s", "key", value as AnyObject),
Where("%K == %s", "key", NSString(string: value)), Where<NSManagedObject>("%K == %s", "key", NSString(string: value)),
Where("%K == %@", "key", value), Where<NSManagedObject>("%K == %@", "key", value),
Where("%K == %@", "key", value as AnyObject), Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where("%K == %@", "key", NSString(string: value)), Where<NSManagedObject>("%K == %@", "key", NSString(string: value)),
Where("key", isEqualTo: value), Where<NSManagedObject>("key", isEqualTo: value),
Where("key", isEqualTo: value as NSString), Where<NSManagedObject>("key", isEqualTo: value as NSString),
Where("key", isEqualTo: NSString(string: value)) Where<NSManagedObject>("key", isEqualTo: NSString(string: value))
) )
} }
do { do {
let value = NSString(string: "value") let value = NSString(string: "value")
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K == %s", "key", value), Where<NSManagedObject>("%K == %s", "key", value),
Where("%K == %s", "key", value as String), Where<NSManagedObject>("%K == %s", "key", value as String),
Where("%K == %s", "key", value as String as AnyObject), Where<NSManagedObject>("%K == %s", "key", value as String as AnyObject),
Where("%K == %@", "key", value), Where<NSManagedObject>("%K == %@", "key", value),
Where("%K == %@", "key", value as String), Where<NSManagedObject>("%K == %@", "key", value as String),
Where("%K == %@", "key", value as String as AnyObject), Where<NSManagedObject>("%K == %@", "key", value as String as AnyObject),
Where("key", isEqualTo: value), Where<NSManagedObject>("key", isEqualTo: value),
Where("key", isEqualTo: value as String), Where<NSManagedObject>("key", isEqualTo: value as String),
Where("key", isEqualTo: value as String as NSString) Where<NSManagedObject>("key", isEqualTo: value as String as NSString)
) )
} }
do { do {
let value: [Int] = [100, 200] let value: [Int] = [100, 200]
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K IN %@", "key", value), Where<NSManagedObject>("%K IN %@", "key", value),
Where("%K IN %@", "key", value as AnyObject), Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
Where("%K IN %@", "key", value as [AnyObject]), Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
Where("%K IN %@", "key", value as NSArray), Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
Where("%K IN %@", "key", NSArray(array: value)), Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
Where("%K IN %@", "key", value as AnyObject as! NSArray), Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
Where("key", isMemberOf: value) Where<NSManagedObject>("key", isMemberOf: value)
) )
} }
do { do {
let value: [Int64] = [Int64.min, 100, Int64.max] let value: [Int64] = [Int64.min, 100, Int64.max]
XCTAssertAllEqual( XCTAssertAllEqual(
Where("%K IN %@", "key", value), Where<NSManagedObject>("%K IN %@", "key", value),
Where("%K IN %@", "key", value as AnyObject), Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
Where("%K IN %@", "key", value as [AnyObject]), Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
Where("%K IN %@", "key", value as NSArray), Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
Where("%K IN %@", "key", NSArray(array: value)), Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
Where("%K IN %@", "key", value as AnyObject as! NSArray), Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
Where("key", isMemberOf: value) Where<NSManagedObject>("key", isMemberOf: value)
) )
} }
} }
@@ -226,9 +232,9 @@ final class WhereTests: XCTestCase {
@objc @objc
dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() { dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() {
let whereClause1 = Where("key1", isEqualTo: "value1") let whereClause1 = Where<NSManagedObject>("key1", isEqualTo: "value1")
let whereClause2 = Where("key2", isEqualTo: "value2") let whereClause2 = Where<NSManagedObject>("key2", isEqualTo: "value2")
let whereClause3 = Where("key3", isEqualTo: "value3") let whereClause3 = Where<NSManagedObject>("key3", isEqualTo: "value3")
do { do {
@@ -259,12 +265,12 @@ final class WhereTests: XCTestCase {
do { do {
let andWhere = whereClause1 && whereClause2 && whereClause3 let andWhere = whereClause1 && whereClause2 && whereClause3
let noneWhere: Where? = nil let noneWhere: Where<NSManagedObject>? = nil
let someWhere: Where? = Where("key4", isEqualTo: "value4") let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
let finalNoneWhere = andWhere && noneWhere let finalNoneWhere = andWhere &&? noneWhere
let finalSomeWhere = andWhere && someWhere let finalSomeWhere = andWhere &&? someWhere
let unwrappedFinalSomeWhere = andWhere && someWhere! let unwrappedFinalSomeWhere = andWhere && someWhere!
@@ -290,12 +296,12 @@ final class WhereTests: XCTestCase {
do { do {
let orWhere = whereClause1 || whereClause2 || whereClause3 let orWhere = whereClause1 || whereClause2 || whereClause3
let noneWhere: Where? = nil let noneWhere: Where<NSManagedObject>? = nil
let someWhere: Where? = Where("key4", isEqualTo: "value4") let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
let finalNoneWhere = orWhere && noneWhere let finalNoneWhere = orWhere &&? noneWhere
let finalSomeWhere = orWhere && someWhere let finalSomeWhere = orWhere &&? someWhere
let unwrappedFinalSomeWhere = orWhere && someWhere! let unwrappedFinalSomeWhere = orWhere && someWhere!
XCTAssertEqual(orWhere.predicate, finalNoneWhere.predicate) XCTAssertEqual(orWhere.predicate, finalNoneWhere.predicate)
@@ -307,7 +313,7 @@ final class WhereTests: XCTestCase {
@objc @objc
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() { dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where("key", isEqualTo: "value") let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let request = CoreStoreFetchRequest() let request = CoreStoreFetchRequest()
whereClause.applyToFetchRequest(request) whereClause.applyToFetchRequest(request)
XCTAssertNotNil(request.predicate) XCTAssertNotNil(request.predicate)
+146 -90
View File
@@ -18,36 +18,35 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
<br /> <br />
</p> </p>
* **Swift 3.2:** iOS 8+ / macOS 10.10+ / watchOS 2.0+ / tvOS 9.0+ * **Swift 4.0:** iOS 8+ / macOS 10.10+ / watchOS 2.0+ / tvOS 9.0+
* Other Swift versions: [Swift 3.1(version 4.1.4)](https://github.com/JohnEstropia/CoreStore/tree/4.1.4), [Swift 4.0](https://github.com/JohnEstropia/CoreStore/tree/5.0.0) * Other Swift versions: [Swift 3.2(version 4.2.3)](https://github.com/JohnEstropia/CoreStore/tree/4.2.3)
Upgrading from CoreStore 4.1 (Swift 3.1) to 4.2 (Swift 3.2)? Check out the [new features](#features) and make sure to read the [Change logs](https://github.com/JohnEstropia/CoreStore/releases). Upgrading from CoreStore 4.2 (Swift 3.2) to 5.0 (Swift 4.0)? Check out the [new features](#features) and make sure to read the [Change logs](https://github.com/JohnEstropia/CoreStore/releases).
CoreStore is now part of the [Swift Source Compatibility projects](https://swift.org/source-compatibility/#current-list-of-projects). CoreStore is now part of the [Swift Source Compatibility projects](https://swift.org/source-compatibility/#current-list-of-projects).
## Why use CoreStore? ## Why use CoreStore?
CoreStore is the answer to the [challenges](http://inessential.com/2010/02/26/on_switching_away_from_core_data) [of](http://bsktapp.com/blog/why-is-realm-great-and-why-are-we-not-using-it/) [using](https://www.quora.com/Why-would-you-use-Realm-over-Core-Data) [Core](http://sebastiandobrincu.com/blog/5-reasons-why-you-should-choose-realm-over-coredata) [Data](https://medium.com/the-way-north/ditching-core-data-865c1bb5564c#.a5h8ou6ri).
CoreStore was (and is) heavily shaped by real-world needs of developing data-dependent apps. It enforces safe and convenient Core Data usage while letting you take advantage of the industry's encouraged best practices. CoreStore was (and is) heavily shaped by real-world needs of developing data-dependent apps. It enforces safe and convenient Core Data usage while letting you take advantage of the industry's encouraged best practices.
### Features ### Features
- **Tight design around Swifts code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features. - **💎Tight design around Swifts code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features.
- **Safer concurrency architecture.** CoreStore makes it hard to fall into common concurrency mistakes. The main `NSManagedObjectContext` is strictly read-only, while all updates are done through serial *transactions*. *(See [Saving and processing transactions](#saving-and-processing-transactions))* - **🚦Safer concurrency architecture.** CoreStore makes it hard to fall into common concurrency mistakes. The main `NSManagedObjectContext` is strictly read-only, while all updates are done through serial *transactions*. *(See [Saving and processing transactions](#saving-and-processing-transactions))*
- **Clean fetching and querying API.** Fetching objects is easy, but querying for raw aggregates (`min`, `max`, etc.) and raw property values is now just as convenient. *(See [Fetching and querying](#fetching-and-querying))* - **🔍Clean fetching and querying API.** Fetching objects is easy, but querying for raw aggregates (`min`, `max`, etc.) and raw property values is now just as convenient. *(See [Fetching and querying](#fetching-and-querying))*
- **Type-safe, easy to configure observers.** You don't have to deal with the burden of setting up `NSFetchedResultsController`s and KVO. As an added bonus, `ListMonitor`s and `ObjectMonitor`s can have multiple observers. This means you can have multiple view controllers efficiently share a single resource! *(See [Observing changes and notifications](#observing-changes-and-notifications))* - **🔭Type-safe, easy to configure observers.** You don't have to deal with the burden of setting up `NSFetchedResultsController`s and KVO. As an added bonus, `ListMonitor`s and `ObjectMonitor`s can have multiple observers. This means you can have multiple view controllers efficiently share a single resource! *(See [Observing changes and notifications](#observing-changes-and-notifications))*
- **Efficient importing utilities.** Map your entities once with their corresponding import source (JSON for example), and importing from *transactions* becomes elegant. Uniquing is also done with an efficient find-and-replace algorithm. *(See [Importing data](#importing-data))* - **📥Efficient importing utilities.** Map your entities once with their corresponding import source (JSON for example), and importing from *transactions* becomes elegant. Uniquing is also done with an efficient find-and-replace algorithm. *(See [Importing data](#importing-data))*
- **Say goodbye to *.xcdatamodeld* files!** The new `CoreStoreObject` is *the* replacement to `NSManagedObject`. `CoreStoreObject` subclasses can declare type-safe properties all in Swift code, no need to maintain separate resource files for the models. As bonus, these special properties support custom types, and can be used to create type-safe keypaths and queries. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects))* - **🗑Say goodbye to *.xcdatamodeld* files!** The new `CoreStoreObject` is *the* replacement to `NSManagedObject`. `CoreStoreObject` subclasses can declare type-safe properties all in Swift code, no need to maintain separate resource files for the models. As bonus, these special properties support custom types, and can be used to create type-safe keypaths and queries. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects))*
- **Progressive migrations.** No need to think how to migrate from all previous model versions to your latest model. Just tell the `DataStack` the sequence of version strings (`MigrationChain`s) and CoreStore will automatically use progressive migrations when needed. *(See [Migrations](#migrations))* - **🔗Progressive migrations.** No need to think how to migrate from all previous model versions to your latest model. Just tell the `DataStack` the sequence of version strings (`MigrationChain`s) and CoreStore will automatically use progressive migrations when needed. *(See [Migrations](#migrations))*
- **Easier custom migrations.** Say goodbye to *.xcmappingmodel* files; CoreStore can now infer entity mappings when possible, while still allowing an easy way to write custom mappings. *(See [Migrations](#migrations))* - **Easier custom migrations.** Say goodbye to *.xcmappingmodel* files; CoreStore can now infer entity mappings when possible, while still allowing an easy way to write custom mappings. *(See [Migrations](#migrations))*
- **Plug-in your own logging framework.** Although a default logger is built-in, all logging, asserting, and error reporting can be funneled to `CoreStoreLogger` protocol implementations. *(See [Logging and error reporting](#logging-and-error-reporting))* - **📝Plug-in your own logging framework.** Although a default logger is built-in, all logging, asserting, and error reporting can be funneled to `CoreStoreLogger` protocol implementations. *(See [Logging and error reporting](#logging-and-error-reporting))*
- **Heavy support for multiple persistent stores per data stack.** CoreStore lets you manage separate stores in a single `DataStack`, just the way *.xcdatamodeld* configurations are designed to. CoreStore will also manage one stack by default, but you can create and manage as many as you need. *(See [Setting up](#setting-up))* - **Heavy support for multiple persistent stores per data stack.** CoreStore lets you manage separate stores in a single `DataStack`, just the way *.xcdatamodeld* configurations are designed to. CoreStore will also manage one stack by default, but you can create and manage as many as you need. *(See [Setting up](#setting-up))*
- **Free to name entities and their class names independently.** CoreStore gets around a restriction with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you can assign different names for the entities and their class names. - **🎯Free to name entities and their class names independently.** CoreStore gets around a restriction with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you can assign different names for the entities and their class names.
- **Full Documentation.** No magic here; all public classes, functions, properties, etc. have detailed *Apple Docs*. This *README* also introduces a lot of concepts and explains a lot of CoreStore's behavior. - **📙Full Documentation.** No magic here; all public classes, functions, properties, etc. have detailed *Apple Docs*. This *README* also introduces a lot of concepts and explains a lot of CoreStore's behavior.
- **Informative (and pretty) logs.** All CoreStore and Core Data-related types now have very informative and pretty print outputs! *(See [Logging and error reporting](#logging-and-error-reporting))* - **Informative (and pretty) logs.** All CoreStore and Core Data-related types now have very informative and pretty print outputs! *(See [Logging and error reporting](#logging-and-error-reporting))*
- **Objective-C support!** Is your project transitioning from Objective-C to Swift but still can't quite fully convert some huge classes to Swift yet? CoreStore adjusts to the ever-increasing Swift adoption. While still written in pure Swift, all CoreStore types have their corresponding Objective-C-visible "bridging classes". *(See [Objective-C support](#objective-c-support))* - **🎗Objective-C support!** Is your project transitioning from Objective-C to Swift but still can't quite fully convert some huge classes to Swift yet? CoreStore adjusts to the ever-increasing Swift adoption. While still written in pure Swift, all CoreStore types have their corresponding Objective-C-visible "bridging classes". *(See [Objective-C support](#objective-c-support))*
- **More extensive Unit Tests.** Extending CoreStore is safe without having to worry about breaking old behavior. - **🛡More extensive Unit Tests.** Extending CoreStore is safe without having to worry about breaking old behavior.
*Have ideas that may benefit other Core Data users? [Feature Request](https://github.com/JohnEstropia/CoreStore/issues)s are welcome!* *Have ideas that may benefit other Core Data users? [Feature Request](https://github.com/JohnEstropia/CoreStore/issues)s are welcome!*
@@ -86,7 +85,7 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
- [`Select<T>` clause](#selectt-clause) - [`Select<T>` clause](#selectt-clause)
- [`GroupBy` clause](#groupby-clause) - [`GroupBy` clause](#groupby-clause)
- [Logging and error reporting](#logging-and-error-reporting) - [Logging and error reporting](#logging-and-error-reporting)
- [Observing changes and notifications](#observing-changes-and-notifications) (unavailable on macOS) - [Observing changes and notifications](#observing-changes-and-notifications)
- [Observe a single object](#observe-a-single-object) - [Observe a single object](#observe-a-single-object)
- [Observe a list of objects](#observe-a-list-of-objects) - [Observe a list of objects](#observe-a-list-of-objects)
- [Objective-C support](#objective-c-support) - [Objective-C support](#objective-c-support)
@@ -146,20 +145,18 @@ let people = CoreStore.fetchAll(From<MyPersonEntity>())
Fetching objects (complex): Fetching objects (complex):
```swift ```swift
let people = CoreStore.fetchAll( let people = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>()
Where("age > 30"), .where(\.age > 30),
OrderBy(.ascending("name"), .descending("age")), .orderBy(.ascending(\.name), .descending(.\age)),
Tweak { (fetchRequest) -> Void in .tweak({ $0.includesPendingChanges = false })
fetchRequest.includesPendingChanges = false
}
) )
``` ```
Querying values: Querying values:
```swift ```swift
let maxAge = CoreStore.queryValue( let maxAge = CoreStore.queryValue(
From<MyPersonEntity>(), From<MyPersonEntity>()
Select<Int>(.maximum("age")) .select(Int.self, .maximum(\.age))
) )
``` ```
@@ -228,8 +225,8 @@ let migrationProgress = dataStack.addStorage(
CoreStore.defaultStack = dataStack // pass the dataStack to CoreStore for easier access later on CoreStore.defaultStack = dataStack // pass the dataStack to CoreStore for easier access later on
``` ```
(If you have never heard of "Configurations", you'll find them in your *.xcdatamodeld* file) > 💡If you have never heard of "Configurations", you'll find them in your *.xcdatamodeld* file
<img src="https://cloud.githubusercontent.com/assets/3029684/8333192/e52cfaac-1acc-11e5-9902-08724f9f1324.png" alt="xcode configurations screenshot" height=212 /> > <img src="https://cloud.githubusercontent.com/assets/3029684/8333192/e52cfaac-1acc-11e5-9902-08724f9f1324.png" alt="xcode configurations screenshot" height=212 />
In our sample code above, note that you don't need to do the `CoreStore.defaultStack = dataStack` line. You can just as well hold a reference to the `DataStack` like below and call all its instance methods directly: In our sample code above, note that you don't need to do the `CoreStore.defaultStack = dataStack` line. You can just as well hold a reference to the `DataStack` like below and call all its instance methods directly:
```swift ```swift
@@ -262,12 +259,14 @@ class MyViewController: UIViewController {
} }
} }
func methodToBeCalledLaterOn() { func methodToBeCalledLaterOn() {
let objects = CoreStore.fetchAll(From(MyEntity)) let objects = CoreStore.fetchAll(From<MyEntity>())
print(objects) print(objects)
} }
} }
``` ```
> 💡By default, CoreStore will initialize `NSManagedObject`s from *.xcdatamodeld* files, but you can create models completely from source code using `CoreStoreObject`s and `CoreStoreSchema`. To use this feature, refer to [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects).
Notice that in our previous examples, `addStorageAndWait(_:)` and `addStorage(_:completion:)` both accept either `InMemoryStore`, `SQLiteStore`, or `ICloudStore`. These implement the `StorageInterface` protocol. Notice that in our previous examples, `addStorageAndWait(_:)` and `addStorage(_:completion:)` both accept either `InMemoryStore`, `SQLiteStore`, or `ICloudStore`. These implement the `StorageInterface` protocol.
### In-memory store ### In-memory store
@@ -313,7 +312,7 @@ public protocol LocalStorage: StorageInterface {
If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`. If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`.
### iCloud Store ### iCloud Store
> **Important:** The iCloud Store is currently in beta. Please use with caution. If you have any concerns please do send me a message on [Twitter](https://twitter.com/JohnEstropia) or on the [CoreStore Slack Team](http://swift-corestore-slack.herokuapp.com/) > ⚠️**Important:** The iCloud Store is being deprecated. Please use with caution. If you have any concerns please do send me a message on [Twitter](https://twitter.com/JohnEstropia) or on the [CoreStore Slack Team](http://swift-corestore-slack.herokuapp.com/)
As a counterpart to `LocalStorage`, the `CloudStorage` protocol abstracts stores managed in the cloud. CoreStore currently provides the concrete class `ICloudStore`. Unlike `InMemoryStore` and `SQLiteStore` though, the `ICloudStore`'s initializer may return `nil` if the iCloud container could not be located or if iCloud is not available on the device: As a counterpart to `LocalStorage`, the `CloudStorage` protocol abstracts stores managed in the cloud. CoreStore currently provides the concrete class `ICloudStore`. Unlike `InMemoryStore` and `SQLiteStore` though, the `ICloudStore`'s initializer may return `nil` if the iCloud container could not be located or if iCloud is not available on the device:
```swift ```swift
@@ -552,14 +551,14 @@ This closure is executed on the main thread so UIKit and AppKit calls can be don
### Progressive migrations ### Progressive migrations
By default, CoreStore uses Core Data's default automatic migration mechanism. In other words, CoreStore will try to migrate the existing persistent store to the *.xcdatamodeld* file's current model version. If no mapping model is found from the store's version to the data model's version, CoreStore gives up and reports an error. By default, CoreStore uses Core Data's default automatic migration mechanism. In other words, CoreStore will try to migrate the existing persistent store until it matches the `SchemaHistory`'s `currentModelVersion`. If no mapping model path is found from the store's version to the data model's version, CoreStore gives up and reports an error.
The `DataStack` lets you specify hints on how to break a migration into several sub-migrations using a `MigrationChain`. This is typically passed to the `DataStack` initializer and will be applied to all stores added to the `DataStack` with `addSQLiteStore(...)` and its variants: The `DataStack` lets you specify hints on how to break a migration into several sub-migrations using a `MigrationChain`. This is typically passed to the `DataStack` initializer and will be applied to all stores added to the `DataStack` with `addSQLiteStore(...)` and its variants:
```swift ```swift
let dataStack = DataStack(migrationChain: let dataStack = DataStack(migrationChain:
["MyAppModel", "MyAppModelV2", "MyAppModelV3", "MyAppModelV4"]) ["MyAppModel", "MyAppModelV2", "MyAppModelV3", "MyAppModelV4"])
``` ```
The most common usage is to pass in the *.xcdatamodeld* version names in increasing order as above. The most common usage is to pass in the model version (*.xcdatamodeld* version names for `NSManagedObject`s, or the `modelName` for `CoreStoreSchema`s) in increasing order as above.
For more complex, non-linear migration paths, you can also pass in a version tree that maps the key-values to the source-destination versions: For more complex, non-linear migration paths, you can also pass in a version tree that maps the key-values to the source-destination versions:
```swift ```swift
@@ -584,7 +583,7 @@ The `MigrationChain` is validated when passed to the `DataStack` and unless it i
- a version appears twice as a key in a dictionary literal - a version appears twice as a key in a dictionary literal
- a loop is found in any of the paths - a loop is found in any of the paths
One important thing to remember is that **if a `MigrationChain` is specified, the *.xcdatamodeld*'s "Current Version" will be bypassed** and the `MigrationChain`'s leafmost version will be the `DataStack`'s base model version. > ⚠️**Important: If a `MigrationChain` is specified, the *.xcdatamodeld*'s "Current Version" will be bypassed** and the `MigrationChain`'s leafmost version will be the `DataStack`'s base model version.
### Forecasting migrations ### Forecasting migrations
@@ -719,7 +718,7 @@ dataStack.perform(
} }
) )
``` ```
Never use `try?` or `try!` on a `transaction.cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to save as normal. Using `try!` will crash the app as `transaction.cancel()` will *always* throw an error. > ⚠️**Important:** Never use `try?` or `try!` on a `transaction.cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to save as normal. Using `try!` will crash the app as `transaction.cancel()` will *always* throw an error.
The examples above use `perform(asynchronous:...)`, but there are actually 3 types of transactions at your disposal: *asynchronous*, *synchronous*, and *unsafe*. The examples above use `perform(asynchronous:...)`, but there are actually 3 types of transactions at your disposal: *asynchronous*, *synchronous*, and *unsafe*.
@@ -756,6 +755,9 @@ CoreStore.perform(
} }
) )
``` ```
> ⚠️Be careful when returning `NSManagedObject`s or `CoreStoreObject`s from the transaction closure. Those instances are for the transaction's use only. See [Passing objects safely](#passing-objects-safely).
Transactions created from `perform(asynchronous:...)` are instances of `AsynchronousDataTransaction`. Transactions created from `perform(asynchronous:...)` are instances of `AsynchronousDataTransaction`.
#### Synchronous transactions #### Synchronous transactions
@@ -772,6 +774,21 @@ let hasChanges = CoreStore.perform(
Since `perform(synchronous:...)` technically blocks two queues (the caller's queue and the transaction's background queue), it is considered less safe as it's more prone to deadlock. Take special care that the closure does not block on any other external queues. Since `perform(synchronous:...)` technically blocks two queues (the caller's queue and the transaction's background queue), it is considered less safe as it's more prone to deadlock. Take special care that the closure does not block on any other external queues.
By default, `perform(synchronous:...)` will wait for observers such as `ListMonitor`s to be notified before the method returns. This may cause deadlocks, especially if you are calling this from the main thread. To reduce this risk, you may try to set the `waitForAllObservers:` parameter to `false`. Doing so tells the `SynchronousDataTransaction` to block only until it completes saving. It will not wait for other context's to receive those changes. This reduces deadlock risk but may have surprising side-effects:
```swift
CoreStore.perform(
synchronous: { (transaction) in
let person = transaction.create(Into<Person>())
person.name = "John"
},
waitForAllObservers: false
)
let newPerson = CoreStore.fetchOne(From<Person>.where(\.name == "John"))
// newPerson may be nil!
// The DataStack may have not yet received the update notification.
```
Due to this complicated nature of synchronous transactions, if your app has very heavy transaction throughput it is highly recommended to use [asynchronous transactions](#asynchronous-transactions) instead.
#### Unsafe transactions #### Unsafe transactions
are special in that they do not enclose updates within a closure: are special in that they do not enclose updates within a closure:
```swift ```swift
@@ -804,8 +821,8 @@ let person = transaction.create(Into<MyPersonEntity>())
While the syntax is straightforward, CoreStore does not just naively insert a new object. This single line does the following: While the syntax is straightforward, CoreStore does not just naively insert a new object. This single line does the following:
- Checks that the entity type exists in any of the transaction's parent persistent store - Checks that the entity type exists in any of the transaction's parent persistent store
- If the entity belongs to only one persistent store, a new object is inserted into that store and returned from `create(...)` - If the entity belongs to only one persistent store, a new object is inserted into that store and returned from `create(...)`
- If the entity does not belong to any store, an assert will be triggered. **This is a programmer error and should never occur in production code.** - If the entity does not belong to any store, an assertion failure will be raised. **This is a programmer error and should never occur in production code.**
- If the entity belongs to multiple stores, an assert will be triggered. **This is also a programmer error and should never occur in production code.** Normally, with Core Data you can insert an object in this state but saving the `NSManagedObjectContext` will always fail. CoreStore checks this for you at creation time when it makes sense (not during save). - If the entity belongs to multiple stores, an assertion failure will be raised. **This is also a programmer error and should never occur in production code.** Normally, with Core Data you can insert an object in this state but saving the `NSManagedObjectContext` will always fail. CoreStore checks this for you at creation time when it makes sense (not during save).
If the entity exists in multiple configurations, you need to provide the configuration name for the destination persistent store: If the entity exists in multiple configurations, you need to provide the configuration name for the destination persistent store:
@@ -835,8 +852,8 @@ To update an existing object, fetch the object's instance from the transaction:
CoreStore.perform( CoreStore.perform(
asynchronous: { (transaction) -> Void in asynchronous: { (transaction) -> Void in
let person = transaction.fetchOne( let person = transaction.fetchOne(
From<MyPersonEntity>(), From<MyPersonEntity>()
Where("name", isEqualTo: "Jane Smith") .where(\.name == "Jane Smith")
) )
person.age = person.age + 1 person.age = person.age + 1
}, },
@@ -907,8 +924,8 @@ If you do not have references yet to the objects to be deleted, transactions hav
CoreStore.perform( CoreStore.perform(
asynchronous: { (transaction) -> Void in asynchronous: { (transaction) -> Void in
transaction.deleteAll( transaction.deleteAll(
From<MyPersonEntity>(), From<MyPersonEntity>()
Where("age > 30") .where(\.age > 30)
) )
}, },
completion: { _ in } completion: { _ in }
@@ -955,8 +972,8 @@ var peopleIDs: [NSManagedObjectID] = // ...
CoreStore.perform( CoreStore.perform(
asynchronous: { (transaction) -> Void in asynchronous: { (transaction) -> Void in
let jane = transaction.fetchOne( let jane = transaction.fetchOne(
From<MyPersonEntity>(), From<MyPersonEntity>()
Where("name", isEqualTo: "Jane Smith") .where(\.name == "Jane Smith")
) )
jane.friends = NSSet(array: transaction.fetchExisting(peopleIDs)!) jane.friends = NSSet(array: transaction.fetchExisting(peopleIDs)!)
// ... // ...
@@ -1001,7 +1018,7 @@ typealias ImportSource = [String: Any]
```swift ```swift
typealias ImportSource = NSData typealias ImportSource = NSData
``` ```
You can even use external types from popular 3rd-party JSON libraries ([SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)'s `JSON` type is a personal favorite), or just simple tuples or primitives. You can even use external types from popular 3rd-party JSON libraries, or just simple tuples or primitives.
#### `ImportableObject` #### `ImportableObject`
`ImportableObject` is a very simple protocol: `ImportableObject` is a very simple protocol:
@@ -1199,11 +1216,11 @@ The `Where` clause is CoreStore's `NSPredicate` wrapper. It specifies the search
```swift ```swift
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>(),
Where("%K > %d", "age", 30) // string format initializer Where<MyPersonEntity>("%K > %d", "age", 30) // string format initializer
) )
people = CoreStore.fetchAll( people = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>(),
Where(true) // boolean initializer Where<MyPersonEntity>(true) // boolean initializer
) )
``` ```
If you do have an existing `NSPredicate` instance already, you can pass that to `Where` as well: If you do have an existing `NSPredicate` instance already, you can pass that to `Where` as well:
@@ -1211,14 +1228,21 @@ If you do have an existing `NSPredicate` instance already, you can pass that to
let predicate = NSPredicate(...) let predicate = NSPredicate(...)
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>(),
Where(predicate) // predicate initializer Where<MyPersonEntity>(predicate) // predicate initializer
)
```
⭐️Starting CoreStore 5.0, `Where` clauses became more type-safe and are now generic types. To avoid verbose repetition of the generic object type, fetch methods now support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `Where` clause expression:
```swift
var people = CoreStore.fetchAll(
From<MyPersonEntity>()
.where(\.age > 30) // Type-safe!
) )
``` ```
`Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings: `Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings:
```swift ```swift
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>()
Where("age > %d", 30) && Where("gender == %@", "M") .where(\.age > 30 && \.gender == "M")
) )
``` ```
If you do not provide a `Where` clause, all objects that belong to the specified `From` will be returned. If you do not provide a `Where` clause, all objects that belong to the specified `From` will be returned.
@@ -1229,16 +1253,23 @@ The `OrderBy` clause is CoreStore's `NSSortDescriptor` wrapper. Use it to specif
```swift ```swift
var mostValuablePeople = CoreStore.fetchAll( var mostValuablePeople = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>(),
OrderBy(.descending("rating"), .ascending("surname")) OrderBy<MyPersonEntity>(.descending("rating"), .ascending("surname"))
) )
``` ```
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.ascending` or `.descending`. As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.ascending` or `.descending`.
⭐️As with `Where` clauses, CoreStore 5.0 turned `OrderBy` clauses into generic types. To avoid verbose repetition of the generic object type, fetch methods now support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `OrderBy` clause expression:
```swift
var people = CoreStore.fetchAll(
From<MyPersonEntity>()
.orderBy(.descending(\.rating), .ascending(\.surname)) // Type-safe!
)
```
You can use the `+` and `+=` operator to append `OrderBy`s together. This is useful when sorting conditionally: You can use the `+` and `+=` operator to append `OrderBy`s together. This is useful when sorting conditionally:
```swift ```swift
var orderBy = OrderBy(.descending("rating")) var orderBy = OrderBy<MyPersonEntity>(.descending(\.rating))
if sortFromYoungest { if sortFromYoungest {
orderBy += OrderBy(.ascending("age")) orderBy += OrderBy(.ascending(\.age))
} }
var mostValuablePeople = CoreStore.fetchAll( var mostValuablePeople = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>(),
@@ -1252,8 +1283,8 @@ The `Tweak` clause lets you, uh, *tweak* the fetch (or query). `Tweak` exposes t
```swift ```swift
var people = CoreStore.fetchAll( var people = CoreStore.fetchAll(
From<MyPersonEntity>(), From<MyPersonEntity>(),
Where("age > %d", 30), Where<MyPersonEntity>("age > %d", 30),
OrderBy(.ascending("surname")), OrderBy<MyPersonEntity>(.ascending("surname")),
Tweak { (fetchRequest) -> Void in Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false fetchRequest.includesPendingChanges = false
fetchRequest.returnsObjectsAsFaults = false fetchRequest.returnsObjectsAsFaults = false
@@ -1261,6 +1292,19 @@ var people = CoreStore.fetchAll(
} }
) )
``` ```
`Tweak` also supports **Fetch Chain builders**:
```swift
var people = CoreStore.fetchAll(
From<MyPersonEntity>(),
.where(\.age > 30)
.orderBy(.ascending(\.surname))
.tweak {
$0.includesPendingChanges = false
$0.returnsObjectsAsFaults = false
$0.includesSubentities = false
}
)
```
The clauses are evaluated the order they appear in the fetch/query, so you typically need to set `Tweak` as the last clause. The clauses are evaluated the order they appear in the fetch/query, so you typically need to set `Tweak` as the last clause.
`Tweak`'s closure is executed only just before the fetch occurs, so make sure that any values captured by the closure is not prone to race conditions. `Tweak`'s closure is executed only just before the fetch occurs, so make sure that any values captured by the closure is not prone to race conditions.
@@ -1296,6 +1340,14 @@ let allAges = CoreStore.queryAttributes(
Select("age") Select("age")
) )
``` ```
⭐️Starting CoreStore 5.0, query methods now support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
```swift
let johnsAge = CoreStore.queryValue(
From<MyPersonEntity>()
.select(\.age) // binds the result to Int
.where(\.name == "John Smith")
)
```
If you only need a value for a particular attribute, you can just specify the key name (like we did with `Select<Int>("age")`), but several aggregate functions can also be used as parameter to `Select`: If you only need a value for a particular attribute, you can just specify the key name (like we did with `Select<Int>("age")`), but several aggregate functions can also be used as parameter to `Select`:
- `.average(...)` - `.average(...)`
@@ -1382,6 +1434,14 @@ let personJSON = CoreStore.queryAttributes(
GroupBy("age") GroupBy("age")
) )
``` ```
⭐️Starting CoreStore 5.0, `GroupBy` clauses are now also generic types and now support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
```swift
let personJSON = CoreStore.queryAttributes(
From<MyPersonEntity>()
.select(.attribute(\.age), .count(\.age, as: "count"))
.groupBy(\.age)
)
```
this returns dictionaries that shows the count for each `"age"`: this returns dictionaries that shows the count for each `"age"`:
```swift ```swift
[ [
@@ -1430,7 +1490,9 @@ A couple of examples, `ListMonitor`:
These are all implemented with `CustomDebugStringConvertible.debugDescription`, so they work with lldb's `po` command as well. These are all implemented with `CustomDebugStringConvertible.debugDescription`, so they work with lldb's `po` command as well.
## Observing changes and notifications (unavailable on macOS) ## Observing changes and notifications
> (unavailable on macOS versions below 10.12)
CoreStore provides type-safe wrappers for observing managed objects: CoreStore provides type-safe wrappers for observing managed objects:
- `ObjectMonitor`: use to monitor changes to a single `NSManagedObject` or `CoreStoreObject` instance (instead of Key-Value Observing) - `ObjectMonitor`: use to monitor changes to a single `NSManagedObject` or `CoreStoreObject` instance (instead of Key-Value Observing)
@@ -1445,7 +1507,7 @@ class MyViewController: UIViewController, ObjectObserver {
// ... // ...
} }
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, didUpdateObject object: MyPersonEntity, changedPersistentKeys: Set<RawKeyPath>) { func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, didUpdateObject object: MyPersonEntity, changedPersistentKeys: Set<KeyPathString>) {
// ... // ...
} }
@@ -1505,12 +1567,10 @@ Including `ListObserver`, there are 3 observer protocols you can implement depen
We then need to create a `ListMonitor` instance and register our `ListObserver` as an observer: We then need to create a `ListMonitor` instance and register our `ListObserver` as an observer:
```swift ```swift
self.monitor = CoreStore.monitorList( self.monitor = CoreStore.monitorList(
From<MyPersonEntity>(), From<MyPersonEntity>()
Where("age > 30"), .where(\.age > 30)
OrderBy(.ascending("name")), .orderBy(.ascending(\.name))
Tweak { (fetchRequest) -> Void in .tweak { $0.fetchBatchSize = 20 }
fetchRequest.fetchBatchSize = 20
}
) )
self.monitor.addObserver(self) self.monitor.addObserver(self)
``` ```
@@ -1526,13 +1586,11 @@ let firstPerson = self.monitor[0]
If the list needs to be grouped into sections, create the `ListMonitor` instance with the `monitorSectionedList(...)` method and a `SectionBy` clause: If the list needs to be grouped into sections, create the `ListMonitor` instance with the `monitorSectionedList(...)` method and a `SectionBy` clause:
```swift ```swift
self.monitor = CoreStore.monitorSectionedList( self.monitor = CoreStore.monitorSectionedList(
From<MyPersonEntity>(), From<MyPersonEntity>()
SectionBy("age"), .sectionBy(\.age)
Where("gender", isEqualTo: "M"), .where(\.gender == "M")
OrderBy(.ascending("age"), .ascending("name")), .orderBy(.ascending(\.age), .ascending(\.name))
Tweak { (fetchRequest) -> Void in .tweak { $0.fetchBatchSize = 20 }
fetchRequest.fetchBatchSize = 20
}
) )
``` ```
A list controller created this way will group the objects by the attribute key indicated by the `SectionBy` clause. One more thing to remember is that the `OrderBy` clause should sort the list in such a way that the `SectionBy` attribute would be sorted together (a requirement shared by `NSFetchedResultsController`.) A list controller created this way will group the objects by the attribute key indicated by the `SectionBy` clause. One more thing to remember is that the `OrderBy` clause should sort the list in such a way that the `SectionBy` attribute would be sorted together (a requirement shared by `NSFetchedResultsController`.)
@@ -1540,11 +1598,11 @@ A list controller created this way will group the objects by the attribute key i
The `SectionBy` clause can also be passed a closure to transform the section name into a displayable string: The `SectionBy` clause can also be passed a closure to transform the section name into a displayable string:
```swift ```swift
self.monitor = CoreStore.monitorSectionedList( self.monitor = CoreStore.monitorSectionedList(
From<MyPersonEntity>(), From<MyPersonEntity>()
SectionBy("age") { (sectionName) -> String? in .sectionBy(\.age) { (sectionName) -> String? in
"\(sectionName) years old" "\(sectionName) years old"
}, }
OrderBy(.ascending("age"), .ascending("name")) .orderBy(.ascending(\.age), .ascending(\.name))
) )
``` ```
This is useful when implementing a `UITableViewDelegate`'s section header: This is useful when implementing a `UITableViewDelegate`'s section header:
@@ -1564,9 +1622,9 @@ let person2 = self.monitor[1, 2]
``` ```
## Objective-C support ## Objective-C support
CoreStore 2.0 was a big move to address the large number of apps starting to convert from Objective-C to Swift. The basic problem is this: The cost of converting all code base to Swift is very big, so most apps are forced to do undergo a *transitional* ObjC-Swift hybrid phase. This used to mean that these apps could not use the Swifty-est libraries out there yet, or that they may have to write their own bridging methods just to make new code usable in their old Objective-C code. > ⚠️Objective-C support is planned to be deprecated in a future CoreStore version.
With 2.0, all CoreStore types are still written in pure Swift, but they now have Objective-C "bridging classes" that are visible to Objective-C code. To show a couple of usage examples: All CoreStore types are still written in pure Swift, but most core types have Objective-C "bridging classes" that are visible to Objective-C code. To show a couple of usage examples:
<table> <table>
<tr><th>Swift</th><th>Objective-C</th></tr> <tr><th>Swift</th><th>Objective-C</th></tr>
@@ -1614,7 +1672,7 @@ All of these `CS`-prefixed bridging classes have very similar usage to the exist
For example, you may have a new, modern Swift class that holds a `ListMonitor`: For example, you may have a new, modern Swift class that holds a `ListMonitor`:
```swift ```swift
class MyViewController: UIViewController { class MyViewController: UIViewController {
let monitor = CoreStore.monitorList(From(MyEntity), ...) let monitor = CoreStore.monitorList(From<MyEntity>(), ...)
// ... // ...
} }
``` ```
@@ -1628,7 +1686,7 @@ Now let's say you have a legacy Objective-C class that previously uses `NSFetche
When you need to instantiate this class from Swift, you just call `bridgeToObjectiveC`: When you need to instantiate this class from Swift, you just call `bridgeToObjectiveC`:
```swift ```swift
class MyViewController: UIViewController { class MyViewController: UIViewController {
let monitor = CoreStore.monitorList(From(MyEntity), ...) let monitor = CoreStore.monitorList(From<MyEntity>(), ...)
func showOldController() { func showOldController() {
let controller = MYOldViewController(monitor: self.monitor.bridgeToObjectiveC) let controller = MYOldViewController(monitor: self.monitor.bridgeToObjectiveC)
self.presentViewController(controller, animated: true, completion: nil) self.presentViewController(controller, animated: true, completion: nil)
@@ -1690,14 +1748,14 @@ The property names to be saved to Core Data is specified as the `keyPath` argume
```swift ```swift
class Person: CoreStoreObject { class Person: CoreStoreObject {
private let _name = Value.Required<String>("name", initial: "") private let _name = Value.Required<String>("name", initial: "")
// ... // note property name is independent of the storage key name
} }
``` ```
Here we added an underscore to the property name and made it `private`, but the underlying key-path `"name"` was unchanged so our model will not trigger a data migration. Here we added an underscore to the property name and made it `private`, but the underlying key-path `"name"` was unchanged so our model will not trigger a data migration.
> **Important:** As a rule, CoreStore can only process *stored properties*. Computed, `static`, `weak`, or `lazy` properties will not be added to the store. It is also strictly advised use `let` instead of `var` to declare these properties, as any changes to the schema after declaration is not allowed. > ⚠️**Important:** As a rule, CoreStore can only process *stored properties*. Computed, `static`, `weak`, or `lazy` properties will be ignored and will not be added to the store. It is also strictly advised use `let` instead of `var` to declare these properties, as any changes to the property value will break the schema.
Also note how `Relationship`s are linked statically with the `inverse:` argument. All relationships are required to have an "inverse" relationship. Unfortunately, due to Swift compiler limitation we can only declare the `inverse:` on one end of the relationship-pair. Also note how `Relationship`s are linked statically with the `inverse:` argument. **All relationships are required to have an "inverse" relationship**. Unfortunately, due to Swift compiler limitation we can only declare the `inverse:` on one end of the relationship-pair.
To tell the `DataStack` about these types, add all `CoreStoreObject`s' entities to a `CoreStoreSchema`: To tell the `DataStack` about these types, add all `CoreStoreObject`s' entities to a `CoreStoreSchema`:
```swift ```swift
@@ -1739,9 +1797,9 @@ let keyPath: String = Dog.keyPath { $0.nickname }
as well as `Where` and `OrderBy` clauses as well as `Where` and `OrderBy` clauses
```swift ```swift
let puppies = CoreStore.fetchAll( let puppies = CoreStore.fetchAll(
From<Dog>(), From<Dog>()
Dog.where { $0.age < 1 }, .where(\.age < 1)
Dog.ascending { $0.age } .orderBy(.ascending(\.age))
) )
``` ```
@@ -1751,7 +1809,7 @@ All CoreStore APIs that are usable with `NSManagedObject`s are also available fo
While it is convenient to be able to declare entities only in code, it is worrying that we might accidentally change the `CoreStoreObject`'s properties and break our users' model version history. For this, the `CoreStoreSchema` allows us to "lock" our properties to a particular configuration. Any changes to that `VersionLock` will raise an assertion failure during the `CoreStoreSchema` initialization, so you can then look for the commit which changed the `VersionLock` hash. While it is convenient to be able to declare entities only in code, it is worrying that we might accidentally change the `CoreStoreObject`'s properties and break our users' model version history. For this, the `CoreStoreSchema` allows us to "lock" our properties to a particular configuration. Any changes to that `VersionLock` will raise an assertion failure during the `CoreStoreSchema` initialization, so you can then look for the commit which changed the `VersionLock` hash.
To use `VersionLock`s, create the `CoreStoreSchema`, run the app, and look for this particular log message that is automatically printed to the console: To use `VersionLock`s, create the `CoreStoreSchema`, run the app, and look for a similar log message that is automatically printed to the console:
<img width="700" alt="VersionLock" src="https://cloud.githubusercontent.com/assets/3029684/26525632/757f1bd0-4398-11e7-9795-4132a2df0538.png" /> <img width="700" alt="VersionLock" src="https://cloud.githubusercontent.com/assets/3029684/26525632/757f1bd0-4398-11e7-9795-4132a2df0538.png" />
@@ -1784,7 +1842,7 @@ Once the version lock is set, any changes in the properties or to the model will
# Installation # Installation
- Requires: - Requires:
- iOS 8 SDK and above - iOS 8 SDK and above
- Swift 3.1 (Xcode 8.3.2+) - Swift 4 (Xcode 9+)
- Dependencies: - Dependencies:
- *None* - *None*
- Other notes: - Other notes:
@@ -1793,7 +1851,7 @@ Once the version lock is set, any changes in the properties or to the model will
### Install with CocoaPods ### Install with CocoaPods
In your `Podfile`, add In your `Podfile`, add
``` ```
pod 'CoreStore', '~> 4.0' pod 'CoreStore', '~> 5.0'
``` ```
and run and run
``` ```
@@ -1804,7 +1862,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
### Install with Carthage ### Install with Carthage
In your `Cartfile`, add In your `Cartfile`, add
``` ```
github "JohnEstropia/CoreStore" >= 4.0.0 github "JohnEstropia/CoreStore" >= 5.0.0
``` ```
and run and run
``` ```
@@ -1835,9 +1893,7 @@ For the full Changelog, refer to the [Releases](https://github.com/JohnEstropia/
# Contact # Contact
Questions? Suggestions? You can reach me on Twitter [@JohnEstropia](https://twitter.com/JohnEstropia)
Reach me on Twitter [@JohnEstropia](https://twitter.com/JohnEstropia)
or join our Slack team at [swift-corestore.slack.com](http://swift-corestore-slack.herokuapp.com/) or join our Slack team at [swift-corestore.slack.com](http://swift-corestore-slack.herokuapp.com/)
+15 -12
View File
@@ -100,7 +100,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration - parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type. - returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
*/ */
public override func create<T>(_ into: Into<T>) -> T { public override func create<D>(_ into: Into<D>) -> D {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -116,7 +116,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited - parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T: DynamicObject>(_ object: T?) -> T? { public override func edit<D: DynamicObject>(_ object: D?) -> D? {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -133,7 +133,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
- parameter objectID: the `NSManagedObjectID` for the object to be edited - parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? { public override func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -148,7 +148,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted - parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object: T?) { public override func delete<D: DynamicObject>(_ object: D?) {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -165,7 +165,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
- parameter object2: another `DynamicObject` to be deleted - parameter object2: another `DynamicObject` to be deleted
- parameter objects: other `DynamicObject`s to be deleted - parameter objects: other `DynamicObject`s to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) { public override func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -203,10 +203,10 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
self.isCommitted = true self.isCommitted = true
let group = DispatchGroup() let group = DispatchGroup()
group.enter() group.enter()
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in self.context.saveAsynchronouslyWithCompletion { (hasChanges, error) -> Void in
completion(result.0, result.1) completion(hasChanges, error)
self.result = result self.result = (hasChanges, error)
group.leave() group.leave()
} }
group.wait() group.wait()
@@ -227,12 +227,15 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
!self.isCommitted, !self.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once." "Attempted to commit a \(cs_typeName(self)) more than once."
) )
self.autoCommit { (result) in self.autoCommit { (hasChanges, error) in
switch result { if let error = error {
case (let hasChanges, nil): completion(SaveResult(hasChanges: hasChanges)) completion(SaveResult(error))
case (_, let error?): completion(SaveResult(error)) }
else {
completion(SaveResult(hasChanges: hasChanges))
} }
} }
} }
+1 -1
View File
@@ -33,7 +33,7 @@ internal protocol AttributeProtocol: class {
static var attributeType: NSAttributeType { get } static var attributeType: NSAttributeType { get }
var keyPath: RawKeyPath { get } var keyPath: KeyPathString { get }
var isOptional: Bool { get } var isOptional: Bool { get }
var isIndexed: Bool { get } var isIndexed: Bool { get }
var isTransient: Bool { get } var isTransient: Bool { get }
+23 -23
View File
@@ -39,9 +39,9 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableObject` methods - throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the created `ImportableObject` instance, or `nil` if the import was ignored - returns: the created `ImportableObject` instance, or `nil` if the import was ignored
*/ */
public func importObject<T: DynamicObject & ImportableObject>( public func importObject<D: ImportableObject>(
_ into: Into<T>, _ into: Into<D>,
source: T.ImportSource) throws -> T? { source: D.ImportSource) throws -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -69,9 +69,9 @@ public extension BaseDataTransaction {
- parameter source: the object to import values from - parameter source: the object to import values from
- throws: an `Error` thrown from any of the `ImportableObject` methods - throws: an `Error` thrown from any of the `ImportableObject` methods
*/ */
public func importObject<T: DynamicObject & ImportableObject>( public func importObject<D: ImportableObject>(
_ object: T, _ object: D,
source: T.ImportSource) throws { source: D.ImportSource) throws {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -97,9 +97,9 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableObject` methods - throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the array of created `ImportableObject` instances - returns: the array of created `ImportableObject` instances
*/ */
public func importObjects<T: DynamicObject & ImportableObject, S: Sequence>( public func importObjects<D: ImportableObject, S: Sequence>(
_ into: Into<T>, _ into: Into<D>,
sourceArray: S) throws -> [T] where S.Iterator.Element == T.ImportSource { sourceArray: S) throws -> [D] where S.Iterator.Element == D.ImportSource {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -108,7 +108,7 @@ public extension BaseDataTransaction {
return try autoreleasepool { return try autoreleasepool {
return try sourceArray.flatMap { (source) -> T? in return try sourceArray.flatMap { (source) -> D? in
let entityType = into.entityClass let entityType = into.entityClass
guard entityType.shouldInsert(from: source, in: self) else { guard entityType.shouldInsert(from: source, in: self) else {
@@ -133,9 +133,9 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods - throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored - returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored
*/ */
public func importUniqueObject<T: DynamicObject & ImportableUniqueObject>( public func importUniqueObject<D: ImportableUniqueObject>(
_ into: Into<T>, _ into: Into<D>,
source: T.ImportSource) throws -> T? { source: D.ImportSource) throws -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -151,7 +151,7 @@ public extension BaseDataTransaction {
return nil return nil
} }
if let object = self.fetchOne(From(entityType), Where(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) { if let object = self.fetchOne(From(entityType), Where<D>(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
guard entityType.shouldUpdate(from: source, in: self) else { guard entityType.shouldUpdate(from: source, in: self) else {
@@ -185,10 +185,10 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods - throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the array of created/updated `ImportableUniqueObject` instances - returns: the array of created/updated `ImportableUniqueObject` instances
*/ */
public func importUniqueObjects<T: DynamicObject & ImportableUniqueObject, S: Sequence>( public func importUniqueObjects<D: ImportableUniqueObject, S: Sequence>(
_ into: Into<T>, _ into: Into<D>,
sourceArray: S, sourceArray: S,
preProcess: @escaping (_ mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] where S.Iterator.Element == T.ImportSource { preProcess: @escaping (_ mapping: [D.UniqueIDType: D.ImportSource]) throws -> [D.UniqueIDType: D.ImportSource] = { $0 }) throws -> [D] where S.Iterator.Element == D.ImportSource {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -198,10 +198,10 @@ public extension BaseDataTransaction {
return try autoreleasepool { return try autoreleasepool {
let entityType = into.entityClass let entityType = into.entityClass
var importSourceByID = Dictionary<T.UniqueIDType, T.ImportSource>() var importSourceByID = Dictionary<D.UniqueIDType, D.ImportSource>()
let sortedIDs = try autoreleasepool { let sortedIDs = try autoreleasepool {
return try sourceArray.flatMap { (source) -> T.UniqueIDType? in return try sourceArray.flatMap { (source) -> D.UniqueIDType? in
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else { guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
@@ -214,12 +214,12 @@ public extension BaseDataTransaction {
importSourceByID = try autoreleasepool { try preProcess(importSourceByID) } importSourceByID = try autoreleasepool { try preProcess(importSourceByID) }
var existingObjectsByID = Dictionary<T.UniqueIDType, T>() var existingObjectsByID = Dictionary<D.UniqueIDType, D>()
self.fetchAll(From(entityType), Where(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))? self.fetchAll(From(entityType), Where<D>(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))?
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 } .forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
var processedObjectIDs = Set<T.UniqueIDType>() var processedObjectIDs = Set<D.UniqueIDType>()
var result = [T]() var result = [D]()
for objectID in sortedIDs where !processedObjectIDs.contains(objectID) { for objectID in sortedIDs where !processedObjectIDs.contains(objectID) {
+199 -22
View File
@@ -39,13 +39,12 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- returns: the number of `DynamicObject`s deleted - returns: the number of `DynamicObject`s deleted
*/ */
@discardableResult @discardableResult
public func deleteAll<T>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? { public func deleteAll<D>(_ from: From<D>, _ deleteClauses: DeleteClause...) -> Int? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue." "Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
) )
return self.context.deleteAll(from, deleteClauses) return self.context.deleteAll(from, deleteClauses)
} }
@@ -57,14 +56,32 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- returns: the number of `DynamicObject`s deleted - returns: the number of `DynamicObject`s deleted
*/ */
@discardableResult @discardableResult
public func deleteAll<T>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? { public func deleteAll<D>(_ from: From<D>, _ deleteClauses: [DeleteClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.deleteAll(from, deleteClauses)
}
/**
Deletes all `DynamicObject`s that satisfy the specified conditions.
```
transaction.deleteAll(From<Person>().where(\.age > 50))
```
- parameter clauseChain: a `FetchChainableBuilderType` clause chain created from a `From` clause
- returns: the number of `DynamicObject`s deleted
*/
@discardableResult
public func deleteAll<B: FetchChainableBuilderType>(_ clauseChain: B) -> Int? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue." "Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
) )
return self.context.deleteAll(from, deleteClauses) return self.context.deleteAll(clauseChain.from, clauseChain.fetchClauses)
} }
@@ -76,7 +93,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter object: a reference to the object created/fetched outside the transaction - parameter object: a reference to the object created/fetched outside the transaction
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ object: T) -> T? { public func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
return self.context.fetchExisting(object) return self.context.fetchExisting(object)
} }
@@ -87,7 +104,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? { public func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
return self.context.fetchExisting(objectID) return self.context.fetchExisting(objectID)
} }
@@ -98,7 +115,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter objects: an array of `DynamicObject`s created/fetched outside the transaction - parameter objects: an array of `DynamicObject`s created/fetched outside the transaction
- returns: the `DynamicObject` array for objects that exists in the transaction - returns: the `DynamicObject` array for objects that exists in the transaction
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
return self.context.fetchExisting(objects) return self.context.fetchExisting(objects)
} }
@@ -109,7 +126,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `DynamicObject` array for objects that exists in the transaction - returns: the `DynamicObject` array for objects that exists in the transaction
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID { public func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
return self.context.fetchExisting(objectIDs) return self.context.fetchExisting(objectIDs)
} }
@@ -121,7 +138,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? { public func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -137,7 +154,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? { public func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -146,6 +163,27 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
return self.context.fetchOne(from, fetchClauses) return self.context.fetchOne(from, fetchClauses)
} }
/**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeen = transaction.fetchOne(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType`
*/
public func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) -> B.ObjectType? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchOne(clauseChain)
}
/** /**
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -153,7 +191,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? { public func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [D]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -169,7 +207,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? { public func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [D]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -178,6 +216,27 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
return self.context.fetchAll(from, fetchClauses) return self.context.fetchAll(from, fetchClauses)
} }
/**
Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let people = transaction.fetchAll(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType`
*/
public func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) -> [B.ObjectType]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchAll(clauseChain)
}
/** /**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -185,7 +244,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? { public func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -201,7 +260,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? { public func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -210,6 +269,27 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
return self.context.fetchCount(from, fetchClauses) return self.context.fetchCount(from, fetchClauses)
} }
/**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let numberOfAdults = transaction.fetchCount(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(clauseChain)
}
/** /**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -217,7 +297,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? { public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -233,7 +313,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? { public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -242,6 +322,27 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
return self.context.fetchObjectID(from, fetchClauses) return self.context.fetchObjectID(from, fetchClauses)
} }
/**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeenID = transaction.fetchObjectID(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType`
*/
public func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectID(clauseChain)
}
/** /**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -249,7 +350,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? { public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -265,7 +366,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -274,6 +375,27 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
return self.context.fetchObjectIDs(from, fetchClauses) return self.context.fetchObjectIDs(from, fetchClauses)
} }
/**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let idsOfAdults = transaction.fetchObjectIDs(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectIDs(clauseChain)
}
// MARK: QueryableSource // MARK: QueryableSource
@@ -287,7 +409,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? { public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -306,7 +428,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? { public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -315,6 +437,29 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
return self.context.queryValue(from, selectClause, queryClauses) return self.context.queryValue(from, selectClause, queryClauses)
} }
/**
Queries a property value or aggregate as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let averageAdultAge = transaction.queryValue(
From<MyPersonEntity>()
.select(Int.self, .average(\.age))
.where(\.age > 18)
)
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the property/aggregate to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
public func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) -> B.ResultType? where B.ResultType: QueryableAttributeType {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
/** /**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -325,7 +470,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? { public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -344,7 +489,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? { public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -353,6 +498,38 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
return self.context.queryAttributes(from, selectClause, queryClauses) return self.context.queryAttributes(from, selectClause, queryClauses)
} }
/**
Queries a dictionary of attribute values or as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let results = dataStack.queryAttributes(
From<MyPersonEntity>()
.select(
NSDictionary.self,
.attribute(\.age, as: "age"),
.count(\.age, as: "numberOfPeople")
)
.groupBy(\.age)
)
for dictionary in results! {
let age = dictionary["age"] as! Int
let count = dictionary["numberOfPeople"] as! Int
print("There are \(count) people who are \(age) years old."
}
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the properties to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
public func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) -> [[String: Any]]? where B.ResultType == NSDictionary {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryAttributes(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
// MARK: FetchableSource, QueryableSource // MARK: FetchableSource, QueryableSource
+23 -23
View File
@@ -50,7 +50,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration - parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type. - returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
*/ */
public func create<T>(_ into: Into<T>) -> T { public func create<D>(_ into: Into<D>) -> D {
let entityClass = into.entityClass let entityClass = into.entityClass
CoreStore.assert( CoreStore.assert(
@@ -116,12 +116,12 @@ public /*abstract*/ class BaseDataTransaction {
} }
/** /**
Returns an editable proxy of a specified `NSManagedObject`. Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` type to be edited - parameter object: the `NSManagedObject` or `CoreStoreObject` type to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public func edit<T: DynamicObject>(_ object: T?) -> T? { public func edit<D: DynamicObject>(_ object: D?) -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -139,9 +139,9 @@ public /*abstract*/ class BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter objectID: the `NSManagedObjectID` for the object to be edited - parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public func edit<T>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? { public func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -156,11 +156,11 @@ public /*abstract*/ class BaseDataTransaction {
} }
/** /**
Deletes a specified `NSManagedObject`. Deletes a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` to be deleted - parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
*/ */
public func delete<T: DynamicObject>(_ object: T?) { public func delete<D: DynamicObject>(_ object: D?) {
CoreStore.assert( CoreStore.assert(
self.isRunningInAllowedQueue(), self.isRunningInAllowedQueue(),
@@ -173,21 +173,21 @@ public /*abstract*/ class BaseDataTransaction {
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
- parameter object1: the `NSManagedObject` to be deleted - parameter object1: the `NSManagedObject` or `CoreStoreObject` to be deleted
- parameter object2: another `NSManagedObject` to be deleted - parameter object2: another `NSManagedObject` or `CoreStoreObject` to be deleted
- parameter objects: other `NSManagedObject`s to be deleted - parameter objects: other `NSManagedObject`s or `CoreStoreObject`s to be deleted
*/ */
public func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) { public func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
self.delete(([object1, object2] + objects).flatMap { $0 }) self.delete(([object1, object2] + objects).flatMap { $0 })
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
- parameter objects: the `NSManagedObject`s to be deleted - parameter objects: the `NSManagedObject`s or `CoreStoreObject`s to be deleted
*/ */
public func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject { public func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
@@ -220,7 +220,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter entity: the `DynamicObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were inserted to the transaction. - returns: a `Set` of pending `DynamicObject`s of the specified type that were inserted to the transaction.
*/ */
public func insertedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> { public func insertedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -257,7 +257,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter entity: the `DynamicObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction.
*/ */
public func insertedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> { public func insertedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -276,7 +276,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter entity: the `DynamicObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were updated in the transaction. - returns: a `Set` of pending `DynamicObject`s of the specified type that were updated in the transaction.
*/ */
public func updatedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> { public func updatedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -313,7 +313,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter entity: the `DynamicObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction.
*/ */
public func updatedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> { public func updatedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -332,7 +332,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter entity: the `DynamicObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were deleted from the transaction. - returns: a `Set` of pending `DynamicObject`s of the specified type that were deleted from the transaction.
*/ */
public func deletedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> { public func deletedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -370,7 +370,7 @@ public /*abstract*/ class BaseDataTransaction {
- parameter entity: the `DynamicObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
public func deletedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> { public func deletedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
+7 -4
View File
@@ -54,12 +54,15 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction, CoreSto
!self.bridgeToSwift.isCommitted, !self.bridgeToSwift.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once." "Attempted to commit a \(cs_typeName(self)) more than once."
) )
self.bridgeToSwift.autoCommit { (result) in self.bridgeToSwift.autoCommit { (_, error) in
switch result { if let error = error {
case (_, nil): success?() failure?(error.bridgeToObjectiveC)
case (_, let error?): failure?(error.bridgeToObjectiveC) }
else {
success?()
} }
} }
} }
+2 -2
View File
@@ -145,7 +145,7 @@ public final class CSFrom: NSObject {
public let bridgeToSwift: From<NSManagedObject> public let bridgeToSwift: From<NSManagedObject>
public init<T: NSManagedObject>(_ swiftValue: From<T>) { public init<D: NSManagedObject>(_ swiftValue: From<D>) {
self.bridgeToSwift = swiftValue.downcast() self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
@@ -155,7 +155,7 @@ public final class CSFrom: NSObject {
// MARK: - From // MARK: - From
extension From where T: NSManagedObject { extension From where D: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
+16 -8
View File
@@ -35,13 +35,13 @@ import CoreData
- SeeAlso: `GroupBy` - SeeAlso: `GroupBy`
*/ */
@objc @objc
public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType { public final class CSGroupBy: NSObject, CSQueryClause {
/** /**
The list of key path strings to group results with The list of key path strings to group results with
*/ */
@objc @objc
public var keyPaths: [RawKeyPath] { public var keyPaths: [KeyPathString] {
return self.bridgeToSwift.keyPaths return self.bridgeToSwift.keyPaths
} }
@@ -52,7 +52,7 @@ public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType {
- parameter keyPath: a key path string to group results with - parameter keyPath: a key path string to group results with
*/ */
@objc @objc
public convenience init(keyPath: RawKeyPath) { public convenience init(keyPath: KeyPathString) {
self.init(GroupBy(keyPath)) self.init(GroupBy(keyPath))
} }
@@ -63,7 +63,7 @@ public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType {
- parameter keyPaths: a list of key path strings to group results with - parameter keyPaths: a list of key path strings to group results with
*/ */
@objc @objc
public convenience init(keyPaths: [RawKeyPath]) { public convenience init(keyPaths: [KeyPathString]) {
self.init(GroupBy(keyPaths)) self.init(GroupBy(keyPaths))
} }
@@ -102,11 +102,11 @@ public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public let bridgeToSwift: GroupBy public let bridgeToSwift: GroupBy<NSManagedObject>
public init(_ swiftValue: GroupBy) { public init<D: NSManagedObject>(_ swiftValue: GroupBy<D>) {
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -114,7 +114,7 @@ public final class CSGroupBy: NSObject, CSQueryClause, CoreStoreObjectiveCType {
// MARK: - GroupBy // MARK: - GroupBy
extension GroupBy: CoreStoreSwiftType { extension GroupBy where D: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -122,4 +122,12 @@ extension GroupBy: CoreStoreSwiftType {
return CSGroupBy(self) return CSGroupBy(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> GroupBy<NSManagedObject> {
return GroupBy<NSManagedObject>(self.keyPaths)
}
} }
+2 -2
View File
@@ -112,7 +112,7 @@ public final class CSInto: NSObject {
public let bridgeToSwift: Into<NSManagedObject> public let bridgeToSwift: Into<NSManagedObject>
public required init<T: NSManagedObject>(_ swiftValue: Into<T>) { public required init<D: NSManagedObject>(_ swiftValue: Into<D>) {
self.bridgeToSwift = swiftValue.downcast() self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
@@ -122,7 +122,7 @@ public final class CSInto: NSObject {
// MARK: - Into // MARK: - Into
extension Into where T: NSManagedObject { extension Into where D: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
+13 -5
View File
@@ -35,7 +35,7 @@ import CoreData
- SeeAlso: `OrderBy` - SeeAlso: `OrderBy`
*/ */
@objc @objc
public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteClause, CoreStoreObjectiveCType { public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteClause {
/** /**
The list of sort descriptors The list of sort descriptors
@@ -110,11 +110,11 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public let bridgeToSwift: OrderBy public let bridgeToSwift: OrderBy<NSManagedObject>
public init(_ swiftValue: OrderBy) { public init<D: NSManagedObject>(_ swiftValue: OrderBy<D>) {
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -122,7 +122,7 @@ public final class CSOrderBy: NSObject, CSFetchClause, CSQueryClause, CSDeleteCl
// MARK: - OrderBy // MARK: - OrderBy
extension OrderBy: CoreStoreSwiftType { extension OrderBy where D: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -130,4 +130,12 @@ extension OrderBy: CoreStoreSwiftType {
return CSOrderBy(self) return CSOrderBy(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> OrderBy<NSManagedObject> {
return OrderBy<NSManagedObject>(self.sortDescriptors)
}
} }
+17 -9
View File
@@ -36,7 +36,7 @@ import CoreData
*/ */
@available(OSX 10.12, *) @available(OSX 10.12, *)
@objc @objc
public final class CSSectionBy: NSObject, CoreStoreObjectiveCType { public final class CSSectionBy: NSObject {
/** /**
Initializes a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections Initializes a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections
@@ -45,9 +45,9 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections - returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections
*/ */
@objc @objc
public static func keyPath(_ sectionKeyPath: RawKeyPath) -> CSSectionBy { public static func keyPath(_ sectionKeyPath: KeyPathString) -> CSSectionBy {
return self.init(SectionBy(sectionKeyPath)) return self.init(SectionBy<NSManagedObject>(sectionKeyPath))
} }
/** /**
@@ -58,9 +58,9 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections - returns: a `CSSectionBy` clause with the key path to use to group `CSListMonitor` objects into sections
*/ */
@objc @objc
public static func keyPath(_ sectionKeyPath: RawKeyPath, sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> CSSectionBy { public static func keyPath(_ sectionKeyPath: KeyPathString, sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> CSSectionBy {
return self.init(SectionBy(sectionKeyPath, sectionIndexTransformer)) return self.init(SectionBy<NSManagedObject>(sectionKeyPath, sectionIndexTransformer))
} }
@@ -74,11 +74,11 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public let bridgeToSwift: SectionBy public let bridgeToSwift: SectionBy<NSManagedObject>
public init(_ swiftValue: SectionBy) { public init<D>(_ swiftValue: SectionBy<D>) {
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -87,7 +87,7 @@ public final class CSSectionBy: NSObject, CoreStoreObjectiveCType {
// MARK: - SectionBy // MARK: - SectionBy
@available(OSX 10.12, *) @available(OSX 10.12, *)
extension SectionBy: CoreStoreSwiftType { extension SectionBy {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -95,4 +95,12 @@ extension SectionBy: CoreStoreSwiftType {
return CSSectionBy(self) return CSSectionBy(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> SectionBy<NSManagedObject> {
return SectionBy<NSManagedObject>(self.sectionKeyPath, self.sectionIndexTransformer)
}
} }
+148 -26
View File
@@ -35,7 +35,7 @@ import CoreData
- SeeAlso: `SelectTerm` - SeeAlso: `SelectTerm`
*/ */
@objc @objc
public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType { public final class CSSelectTerm: NSObject {
/** /**
Provides a `CSSelectTerm` to a `CSSelect` clause for querying an entity attribute. Provides a `CSSelectTerm` to a `CSSelect` clause for querying an entity attribute.
@@ -48,7 +48,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
- parameter keyPath: the attribute name - parameter keyPath: the attribute name
*/ */
@objc @objc
public convenience init(keyPath: RawKeyPath) { public convenience init(keyPath: KeyPathString) {
self.init(.attribute(keyPath)) self.init(.attribute(keyPath))
} }
@@ -65,7 +65,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSelectTerm` to a `CSSelect` clause for querying the average value of an attribute - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the average value of an attribute
*/ */
@objc @objc
public static func average(_ keyPath: RawKeyPath, as alias: RawKeyPath?) -> CSSelectTerm { public static func average(_ keyPath: KeyPathString, as alias: KeyPathString?) -> CSSelectTerm {
return self.init(.average(keyPath, as: alias)) return self.init(.average(keyPath, as: alias))
} }
@@ -82,7 +82,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
- returns: a `SelectTerm` to a `Select` clause for a count query - returns: a `SelectTerm` to a `Select` clause for a count query
*/ */
@objc @objc
public static func count(_ keyPath: RawKeyPath, as alias: RawKeyPath?) -> CSSelectTerm { public static func count(_ keyPath: KeyPathString, as alias: KeyPathString?) -> CSSelectTerm {
return self.init(.count(keyPath, as: alias)) return self.init(.count(keyPath, as: alias))
} }
@@ -99,7 +99,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSelectTerm` to a `CSSelect` clause for querying the maximum value for an attribute - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the maximum value for an attribute
*/ */
@objc @objc
public static func maximum(_ keyPath: RawKeyPath, as alias: RawKeyPath?) -> CSSelectTerm { public static func maximum(_ keyPath: KeyPathString, as alias: KeyPathString?) -> CSSelectTerm {
return self.init(.maximum(keyPath, as: alias)) return self.init(.maximum(keyPath, as: alias))
} }
@@ -116,7 +116,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSelectTerm` to a `CSSelect` clause for querying the minimum value for an attribute - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the minimum value for an attribute
*/ */
@objc @objc
public static func minimum(_ keyPath: RawKeyPath, as alias: RawKeyPath?) -> CSSelectTerm { public static func minimum(_ keyPath: KeyPathString, as alias: KeyPathString?) -> CSSelectTerm {
return self.init(.minimum(keyPath, as: alias)) return self.init(.minimum(keyPath, as: alias))
} }
@@ -133,7 +133,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
- returns: a `CSSelectTerm` to a `CSSelect` clause for querying the sum value for an attribute - returns: a `CSSelectTerm` to a `CSSelect` clause for querying the sum value for an attribute
*/ */
@objc @objc
public static func sum(_ keyPath: RawKeyPath, as alias: RawKeyPath?) -> CSSelectTerm { public static func sum(_ keyPath: KeyPathString, as alias: KeyPathString?) -> CSSelectTerm {
return self.init(.sum(keyPath, as: alias)) return self.init(.sum(keyPath, as: alias))
} }
@@ -150,7 +150,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
- 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
*/ */
@objc @objc
public static func objectIDAs(_ alias: RawKeyPath? = nil) -> CSSelectTerm { public static func objectIDAs(_ alias: KeyPathString? = nil) -> CSSelectTerm {
return self.init(.objectID(as: alias)) return self.init(.objectID(as: alias))
} }
@@ -175,11 +175,11 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public let bridgeToSwift: SelectTerm public let bridgeToSwift: SelectTerm<NSManagedObject>
public init(_ swiftValue: SelectTerm) { public init<D: NSManagedObject>(_ swiftValue: SelectTerm<D>) {
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -187,7 +187,7 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
// MARK: - SelectTerm // MARK: - SelectTerm
extension SelectTerm: CoreStoreSwiftType { extension SelectTerm where D: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -195,6 +195,24 @@ extension SelectTerm: CoreStoreSwiftType {
return CSSelectTerm(self) return CSSelectTerm(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> SelectTerm<NSManagedObject> {
switch self {
case ._attribute(let keyPath):
return SelectTerm<NSManagedObject>._attribute(keyPath)
case ._aggregate(let function, let keyPath, let alias, let nativeType):
return SelectTerm<NSManagedObject>._aggregate(function: function, keyPath: keyPath, alias: alias, nativeType: nativeType)
case ._identity(let alias, let nativeType):
return SelectTerm<NSManagedObject>._identity(alias: alias, nativeType: nativeType)
}
}
} }
@@ -218,9 +236,10 @@ public final class CSSelect: NSObject {
``` ```
- parameter numberTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter numberTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
@objc
public convenience init(numberTerm: CSSelectTerm) { public convenience init(numberTerm: CSSelectTerm) {
self.init(Select<NSNumber>(numberTerm.bridgeToSwift)) self.init(Select<NSManagedObject, NSNumber>(numberTerm.bridgeToSwift))
} }
/** /**
@@ -233,9 +252,10 @@ public final class CSSelect: NSObject {
``` ```
- parameter decimalTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter decimalTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
@objc
public convenience init(decimalTerm: CSSelectTerm) { public convenience init(decimalTerm: CSSelectTerm) {
self.init(Select<NSDecimalNumber>(decimalTerm.bridgeToSwift)) self.init(Select<NSManagedObject, NSDecimalNumber>(decimalTerm.bridgeToSwift))
} }
/** /**
@@ -248,9 +268,10 @@ public final class CSSelect: NSObject {
``` ```
- parameter stringTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter stringTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
@objc
public convenience init(stringTerm: CSSelectTerm) { public convenience init(stringTerm: CSSelectTerm) {
self.init(Select<NSString>(stringTerm.bridgeToSwift)) self.init(Select<NSManagedObject, NSString>(stringTerm.bridgeToSwift))
} }
/** /**
@@ -263,9 +284,10 @@ public final class CSSelect: NSObject {
``` ```
- parameter dateTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter dateTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
@objc
public convenience init(dateTerm: CSSelectTerm) { public convenience init(dateTerm: CSSelectTerm) {
self.init(Select<Date>(dateTerm.bridgeToSwift)) self.init(Select<NSManagedObject, Date>(dateTerm.bridgeToSwift))
} }
/** /**
@@ -278,9 +300,10 @@ public final class CSSelect: NSObject {
``` ```
- parameter dataTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter dataTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
@objc
public convenience init(dataTerm: CSSelectTerm) { public convenience init(dataTerm: CSSelectTerm) {
self.init(Select<Data>(dataTerm.bridgeToSwift)) self.init(Select<NSManagedObject, Data>(dataTerm.bridgeToSwift))
} }
/** /**
@@ -292,9 +315,10 @@ public final class CSSelect: NSObject {
// ... // ...
``` ```
*/ */
@objc
public convenience init(objectIDTerm: ()) { public convenience init(objectIDTerm: ()) {
self.init(Select<NSManagedObjectID>(.objectID())) self.init(Select<NSManagedObject, NSManagedObjectID>(.objectID()))
} }
/** /**
@@ -307,9 +331,10 @@ public final class CSSelect: NSObject {
- parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query
- returns: a `CSSelect` clause for querying an entity attribute - returns: a `CSSelect` clause for querying an entity attribute
*/ */
@objc
public static func dictionaryForTerm(_ term: CSSelectTerm) -> CSSelect { public static func dictionaryForTerm(_ term: CSSelectTerm) -> CSSelect {
return self.init(Select<NSDictionary>(term.bridgeToSwift)) return self.init(Select<NSManagedObject, NSDictionary>(term.bridgeToSwift))
} }
/** /**
@@ -325,9 +350,10 @@ public final class CSSelect: NSObject {
- parameter terms: the `CSSelectTerm`s specifying the attribute/aggregate values to query - parameter terms: the `CSSelectTerm`s specifying the attribute/aggregate values to query
- returns: a `CSSelect` clause for querying an entity attribute - returns: a `CSSelect` clause for querying an entity attribute
*/ */
@objc
public static func dictionaryForTerms(_ terms: [CSSelectTerm]) -> CSSelect { public static func dictionaryForTerms(_ terms: [CSSelectTerm]) -> CSSelect {
return self.init(Select<NSDictionary>(terms.map { $0.bridgeToSwift })) return self.init(Select<NSManagedObject, NSDictionary>(terms.map { $0.bridgeToSwift }))
} }
@@ -357,18 +383,18 @@ public final class CSSelect: NSObject {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public init<T: QueryableAttributeType>(_ swiftValue: Select<T>) { public init<D: NSManagedObject, T: QueryableAttributeType>(_ swiftValue: Select<D, T>) {
self.attributeType = T.cs_rawAttributeType self.attributeType = T.cs_rawAttributeType
self.selectTerms = swiftValue.selectTerms self.selectTerms = swiftValue.selectTerms.map({ $0.downcast() })
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue
super.init() super.init()
} }
public init<T>(_ swiftValue: Select<T>) { public init<D: NSManagedObject, T>(_ swiftValue: Select<D, T>) {
self.attributeType = .undefinedAttributeType self.attributeType = .undefinedAttributeType
self.selectTerms = swiftValue.selectTerms self.selectTerms = swiftValue.selectTerms.map({ $0.downcast() })
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue
super.init() super.init()
} }
@@ -377,7 +403,95 @@ public final class CSSelect: NSObject {
// MARK: Internal // MARK: Internal
internal let attributeType: NSAttributeType internal let attributeType: NSAttributeType
internal let selectTerms: [SelectTerm] internal let selectTerms: [SelectTerm<NSManagedObject>]
// MARK: Internal
internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
fetchRequest.includesPendingChanges = false
fetchRequest.resultType = .dictionaryResultType
func attributeDescription(for keyPath: String, in entity: NSEntityDescription) -> NSAttributeDescription? {
let components = keyPath.components(separatedBy: ".")
switch components.count {
case 0:
return nil
case 1:
return entity.attributesByName[components[0]]
default:
guard let relationship = entity.relationshipsByName[components[0]],
let destinationEntity = relationship.destinationEntity else {
return nil
}
return attributeDescription(
for: components.dropFirst().joined(separator: "."),
in: destinationEntity
)
}
}
var propertiesToFetch = [Any]()
for term in self.selectTerms {
switch term {
case ._attribute(let keyPath):
propertiesToFetch.append(keyPath)
case ._aggregate(let function, let keyPath, let alias, let nativeType):
let entityDescription = fetchRequest.entity!
if let attributeDescription = attributeDescription(for: keyPath, in: entityDescription) {
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .undefinedAttributeType {
expressionDescription.expressionResultType = attributeDescription.attributeType
}
else {
expressionDescription.expressionResultType = nativeType
}
expressionDescription.expression = NSExpression(
forFunction: function,
arguments: [NSExpression(forKeyPath: keyPath)]
)
propertiesToFetch.append(expressionDescription)
}
else {
CoreStore.log(
.warning,
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(self)) query clause."
)
}
case ._identity(let alias, let nativeType):
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .undefinedAttributeType {
expressionDescription.expressionResultType = .objectIDAttributeType
}
else {
expressionDescription.expressionResultType = nativeType
}
expressionDescription.expression = NSExpression.expressionForEvaluatedObject()
propertiesToFetch.append(expressionDescription)
}
}
fetchRequest.propertiesToFetch = propertiesToFetch
}
// MARK: Private // MARK: Private
@@ -388,7 +502,7 @@ public final class CSSelect: NSObject {
// MARK: - Select // MARK: - Select
extension Select: CoreStoreSwiftType { extension Select where D: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -396,4 +510,12 @@ extension Select: CoreStoreSwiftType {
return CSSelect(self) return CSSelect(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> Select<NSManagedObject, T> {
return Select<NSManagedObject, T>(self.selectTerms.map({ $0.downcast() }))
}
} }
+15 -7
View File
@@ -35,7 +35,7 @@ import CoreData
- SeeAlso: `Where` - SeeAlso: `Where`
*/ */
@objc @objc
public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClause, CoreStoreObjectiveCType { public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClause {
/** /**
The internal `NSPredicate` instance for the `Where` clause The internal `NSPredicate` instance for the `Where` clause
@@ -85,7 +85,7 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
- parameter value: the arguments for the `==` operator - parameter value: the arguments for the `==` operator
*/ */
@objc @objc
public convenience init(keyPath: RawKeyPath, isEqualTo value: CoreDataNativeType?) { public convenience init(keyPath: KeyPathString, isEqualTo value: CoreDataNativeType?) {
self.init(value == nil || value is NSNull self.init(value == nil || value is NSNull
? Where("\(keyPath) == nil") ? Where("\(keyPath) == nil")
@@ -99,7 +99,7 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
- parameter list: the array to check membership of - parameter list: the array to check membership of
*/ */
@objc @objc
public convenience init(keyPath: RawKeyPath, isMemberOf list: [CoreDataNativeType]) { public convenience init(keyPath: KeyPathString, isMemberOf list: [CoreDataNativeType]) {
self.init(Where("\(keyPath) IN %@", list as NSArray)) self.init(Where("\(keyPath) IN %@", list as NSArray))
} }
@@ -149,11 +149,11 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public let bridgeToSwift: Where public let bridgeToSwift: Where<NSManagedObject>
public init(_ swiftValue: Where) { public init<D: NSManagedObject>(_ swiftValue: Where<D>) {
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue.downcast()
super.init() super.init()
} }
} }
@@ -161,7 +161,7 @@ public final class CSWhere: NSObject, CSFetchClause, CSQueryClause, CSDeleteClau
// MARK: - Where // MARK: - Where
extension Where: CoreStoreSwiftType { extension Where where D: NSManagedObject {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
@@ -169,4 +169,12 @@ extension Where: CoreStoreSwiftType {
return CSWhere(self) return CSWhere(self)
} }
// MARK: FilePrivate
fileprivate func downcast() -> Where<NSManagedObject> {
return Where<NSManagedObject>(self.predicate)
}
} }
@@ -1093,15 +1093,6 @@ fileprivate extension String {
return String(repeating: " ", count: level * 4) return String(repeating: " ", count: level * 4)
} }
fileprivate func trimSwiftModuleName() -> String {
if self.hasPrefix("Swift.") {
return self.substring(from: "Swift.".endIndex)
}
return self
}
fileprivate mutating func indent(_ level: Int) { fileprivate mutating func indent(_ level: Int) {
self = self.replacingOccurrences(of: "\n", with: "\n\(String.indention(level))") self = self.replacingOccurrences(of: "\n", with: "\n\(String.indention(level))")
+100 -9
View File
@@ -38,7 +38,7 @@ public extension CoreStore {
- parameter object: the `DynamicObject` to observe changes from - parameter object: the `DynamicObject` to observe changes from
- returns: a `ObjectMonitor` that monitors changes to `object` - returns: a `ObjectMonitor` that monitors changes to `object`
*/ */
public static func monitorObject<T>(_ object: T) -> ObjectMonitor<T> { public static func monitorObject<D>(_ object: D) -> ObjectMonitor<D> {
return self.defaultStack.monitorObject(object) return self.defaultStack.monitorObject(object)
} }
@@ -50,7 +50,7 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public static func monitorList<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> ListMonitor<T> { public static func monitorList<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
return self.defaultStack.monitorList(from, fetchClauses) return self.defaultStack.monitorList(from, fetchClauses)
} }
@@ -62,11 +62,28 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public static func monitorList<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> ListMonitor<T> { public static func monitorList<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
return self.defaultStack.monitorList(from, fetchClauses) return self.defaultStack.monitorList(from, fetchClauses)
} }
/**
Creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let monitor = CoreStore.monitorList(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public static func monitorList<B: FetchChainableBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
return self.defaultStack.monitorList(clauseChain.from, clauseChain.fetchClauses)
}
/** /**
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
@@ -74,7 +91,7 @@ public extension CoreStore {
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public static func monitorList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ fetchClauses: FetchClause...) { public static func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: FetchClause...) {
self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses) self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
} }
@@ -86,11 +103,37 @@ public extension CoreStore {
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public static func monitorList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ fetchClauses: [FetchClause]) { public static func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: [FetchClause]) {
self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses) self.defaultStack.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
} }
/**
Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
```
CoreStore.monitorList(
{ (monitor) in
self.monitor = monitor
},
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public static func monitorList<B: FetchChainableBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
self.defaultStack.monitorList(
createAsynchronously: createAsynchronously,
clauseChain.from,
clauseChain.fetchClauses
)
}
/** /**
Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
@@ -99,7 +142,7 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public static func monitorSectionedList<T>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor<T> { public static func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses) return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses)
} }
@@ -112,11 +155,33 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public static func monitorSectionedList<T>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor<T> { public static func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses) return self.defaultStack.monitorSectionedList(from, sectionBy, fetchClauses)
} }
/**
Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
```
let monitor = CoreStore.monitorSectionedList(
From<MyPersonEntity>()
.sectionBy(\.age, { "\($0!) years old" })
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType`
*/
public static func monitorSectionedList<B: SectionMonitorBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
return self.defaultStack.monitorSectionedList(
clauseChain.from,
clauseChain.sectionBy,
clauseChain.fetchClauses
)
}
/** /**
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
@@ -125,7 +190,7 @@ public extension CoreStore {
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public static func monitorSectionedList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { public static func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) {
self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
} }
@@ -138,8 +203,34 @@ public extension CoreStore {
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public static func monitorSectionedList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { public static func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) {
self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) self.defaultStack.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
} }
/**
Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
```
CoreStore.monitorSectionedList(
{ (monitor) in
self.monitor = monitor
},
From<MyPersonEntity>()
.sectionBy(\.age, { "\($0!) years old" })
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType`
*/
public static func monitorSectionedList<B: SectionMonitorBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
self.defaultStack.monitorSectionedList(
createAsynchronously: createAsynchronously,
clauseChain.from,
clauseChain.sectionBy,
clauseChain.fetchClauses
)
}
} }
+150 -18
View File
@@ -37,7 +37,7 @@ public extension CoreStore {
- parameter object: a reference to the object created/fetched outside the `DataStack` - parameter object: a reference to the object created/fetched outside the `DataStack`
- returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public static func fetchExisting<T: DynamicObject>(_ object: T) -> T? { public static func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
return self.defaultStack.fetchExisting(object) return self.defaultStack.fetchExisting(object)
} }
@@ -48,7 +48,7 @@ public extension CoreStore {
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public static func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? { public static func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
return self.defaultStack.fetchExisting(objectID) return self.defaultStack.fetchExisting(objectID)
} }
@@ -59,7 +59,7 @@ public extension CoreStore {
- parameter objects: an array of `DynamicObject`s created/fetched outside the `DataStack` - parameter objects: an array of `DynamicObject`s created/fetched outside the `DataStack`
- returns: the `DynamicObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public static func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public static func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
return self.defaultStack.fetchExisting(objects) return self.defaultStack.fetchExisting(objects)
} }
@@ -70,7 +70,7 @@ public extension CoreStore {
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `DynamicObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public static func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID { public static func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
return self.defaultStack.fetchExisting(objectIDs) return self.defaultStack.fetchExisting(objectIDs)
} }
@@ -82,7 +82,7 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public static func fetchOne<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? { public static func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> D? {
return self.defaultStack.fetchOne(from, fetchClauses) return self.defaultStack.fetchOne(from, fetchClauses)
} }
@@ -94,11 +94,28 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public static func fetchOne<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? { public static func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> D? {
return self.defaultStack.fetchOne(from, fetchClauses) return self.defaultStack.fetchOne(from, fetchClauses)
} }
/**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeen = CoreStore.fetchOne(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType`
*/
public static func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) -> B.ObjectType? {
return self.defaultStack.fetchOne(clauseChain)
}
/** /**
Using the `defaultStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -106,7 +123,7 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public static func fetchAll<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? { public static func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [D]? {
return self.defaultStack.fetchAll(from, fetchClauses) return self.defaultStack.fetchAll(from, fetchClauses)
} }
@@ -118,11 +135,28 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public static func fetchAll<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? { public static func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [D]? {
return self.defaultStack.fetchAll(from, fetchClauses) return self.defaultStack.fetchAll(from, fetchClauses)
} }
/**
Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let people = CoreStore.fetchAll(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType`
*/
public static func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) -> [B.ObjectType]? {
return self.defaultStack.fetchAll(clauseChain)
}
/** /**
Using the `defaultStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -130,7 +164,7 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchCount<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? { public static func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses) return self.defaultStack.fetchCount(from, fetchClauses)
} }
@@ -142,11 +176,28 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchCount<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? { public static func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses) return self.defaultStack.fetchCount(from, fetchClauses)
} }
/**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let numberOfAdults = CoreStore.fetchCount(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public static func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) -> Int? {
return self.defaultStack.fetchCount(clauseChain)
}
/** /**
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -154,7 +205,7 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public static func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? { public static func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses) return self.defaultStack.fetchObjectID(from, fetchClauses)
} }
@@ -166,11 +217,28 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public static func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? { public static func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses) return self.defaultStack.fetchObjectID(from, fetchClauses)
} }
/**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeenID = CoreStore.fetchObjectID(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType`
*/
public static func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(clauseChain)
}
/** /**
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -178,7 +246,7 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? { public static func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses) return self.defaultStack.fetchObjectIDs(from, fetchClauses)
} }
@@ -190,11 +258,28 @@ public extension CoreStore {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { public static func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses) return self.defaultStack.fetchObjectIDs(from, fetchClauses)
} }
/**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let idsOfAdults = transaction.fetchObjectIDs(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public static func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(clauseChain)
}
/** /**
Using the `defaultStack`, queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Using the `defaultStack`, queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -205,7 +290,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public static func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? { public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses) return self.defaultStack.queryValue(from, selectClause, queryClauses)
} }
@@ -220,11 +305,30 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public static func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? { public static func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses) return self.defaultStack.queryValue(from, selectClause, queryClauses)
} }
/**
Queries a property value or aggregate as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let averageAdultAge = CoreStore.queryValue(
From<MyPersonEntity>()
.select(Int.self, .average(\.age))
.where(\.age > 18)
)
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the property/aggregate to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
public static func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) -> B.ResultType? where B.ResultType: QueryableAttributeType {
return self.defaultStack.queryValue(clauseChain)
}
/** /**
Using the `defaultStack`, queries a dictionary of attribtue values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Using the `defaultStack`, queries a dictionary of attribtue values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -235,7 +339,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public static func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? { public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses) return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
} }
@@ -250,8 +354,36 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public static func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? { public static func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses) return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
} }
/**
Queries a dictionary of attribute values or as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let results = CoreStore.queryAttributes(
From<MyPersonEntity>()
.select(
NSDictionary.self,
.attribute(\.age, as: "age"),
.count(\.age, as: "numberOfPeople")
)
.groupBy(\.age)
)
for dictionary in results! {
let age = dictionary["age"] as! Int
let count = dictionary["numberOfPeople"] as! Int
print("There are \(count) people who are \(age) years old."
}
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the properties to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
public static func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) -> [[String: Any]]? where B.ResultType == NSDictionary {
return self.defaultStack.queryAttributes(clauseChain)
}
} }
+2 -2
View File
@@ -43,7 +43,7 @@
#define CORESTORE_RETURNS_RETAINED __attribute__((ns_returns_retained)) #define CORESTORE_RETURNS_RETAINED __attribute__((ns_returns_retained))
#pragma mark - RawKeyPath Utilities #pragma mark - KeyPathString Utilities
#define CSKeyPath(type, property) ({ \ #define CSKeyPath(type, property) ({ \
type *_je_keypath_dummy __attribute__((unused)); \ type *_je_keypath_dummy __attribute__((unused)); \
@@ -477,7 +477,7 @@ CSSelect *_Nonnull CSSelectData(CSSelectTerm *_Nonnull selectTerm) CORESTORE_RET
a <tt>CSSelect</tt> clause for querying an <tt>NSManagedObjectID</tt> value a <tt>CSSelect</tt> clause for querying an <tt>NSManagedObjectID</tt> value
*/ */
CORESTORE_EXTERN CORESTORE_EXTERN
CSSelect *_Nonnull CSSelectObjectID() CORESTORE_RETURNS_RETAINED; CSSelect *_Nonnull CSSelectObjectID(void) CORESTORE_RETURNS_RETAINED;
#pragma mark CSTweak #pragma mark CSTweak
@@ -35,7 +35,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
// MARK: Internal // MARK: Internal
@nonobjc @nonobjc
internal convenience init<T>(dataStack: DataStack, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) { internal convenience init<D>(dataStack: DataStack, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<D>, sectionBy: SectionBy<D>? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
self.init( self.init(
context: dataStack.mainContext, context: dataStack.mainContext,
@@ -47,7 +47,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
} }
@nonobjc @nonobjc
internal init<T>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) { internal init<D>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<D>, sectionBy: SectionBy<D>? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
_ = from.applyToFetchRequest( _ = from.applyToFetchRequest(
fetchRequest, fetchRequest,
+20 -3
View File
@@ -2,8 +2,25 @@
// CoreStoreManagedObject.swift // CoreStoreManagedObject.swift
// CoreStore // CoreStore
// //
// Created by John Rommel Estropia on 2017/06/04. // Copyright © 2017 John Rommel Estropia
// Copyright © 2017 John Rommel Estropia. All rights reserved. //
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// //
import CoreData import CoreData
@@ -30,5 +47,5 @@ import CoreData
private enum Static { private enum Static {
static let queue = DispatchQueue.concurrent("com.coreStore.coreStoreManagerObjectBarrierQueue") static let queue = DispatchQueue.concurrent("com.coreStore.coreStoreManagerObjectBarrierQueue")
static var cache: [ObjectIdentifier: [RawKeyPath: Set<RawKeyPath>]] = [:] static var cache: [ObjectIdentifier: [KeyPathString: Set<KeyPathString>]] = [:]
} }
+117 -211
View File
@@ -27,221 +27,83 @@ import CoreData
import Foundation import Foundation
// MARK: - DynamicObject
public extension DynamicObject where Self: CoreStoreObject {
/**
Extracts the keyPath string from a `CoreStoreObject.Value` property.
```
let keyPath: String = Person.keyPath { $0.nickname }
```
*/
public static func keyPath<O, V>(_ attribute: (Self) -> ValueContainer<O>.Required<V>) -> String {
return attribute(self.meta).keyPath
}
/**
Extracts the keyPath string from a `CoreStoreObject.Value` property.
```
let keyPath: String = Person.keyPath { $0.nickname }
```
*/
public static func keyPath<O, V>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> String {
return attribute(self.meta).keyPath
}
/**
Extracts the keyPath string from a `CoreStoreObject.Relationship` property.
```
let keyPath: String = Person.keyPath { $0.pets }
```
*/
public static func keyPath<O, D>(_ relationship: (Self) -> RelationshipContainer<O>.ToOne<D>) -> String {
return relationship(self.meta).keyPath
}
/**
Extracts the keyPath string from a `CoreStoreObject.Relationship` property.
```
let keyPath: String = Person.keyPath { $0.pets }
```
*/
public static func keyPath<O, D>(_ relationship: (Self) -> RelationshipContainer<O>.ToManyOrdered<D>) -> String {
return relationship(self.meta).keyPath
}
/**
Extracts the keyPath string from a `CoreStoreObject.Relationship` property.
```
let keyPath: String = Person.keyPath { $0.pets }
```
*/
public static func keyPath<O, D>(_ relationship: (Self) -> RelationshipContainer<O>.ToManyUnordered<D>) -> String {
return relationship(self.meta).keyPath
}
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname == "John" })
```
*/
public static func `where`(_ condition: (Self) -> Where) -> Where {
return condition(self.meta)
}
/**
Creates an `OrderBy` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchAll(From<Person>(), Person.orderBy(ascending: { $0.age }))
```
*/
public static func orderBy<O, V>(ascending attribute: (Self) -> ValueContainer<O>.Required<V>) -> OrderBy {
return OrderBy(.ascending(attribute(self.meta).keyPath))
}
/**
Creates an `OrderBy` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchAll(From<Person>(), Person.orderBy(ascending: { $0.age }))
```
*/
public static func orderBy<O, V>(ascending attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy {
return OrderBy(.ascending(attribute(self.meta).keyPath))
}
/**
Creates an `OrderBy` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchAll(From<Person>(), Person.orderBy(descending: { $0.age }))
```
*/
public static func orderBy<O, V>(descending attribute: (Self) -> ValueContainer<O>.Required<V>) -> OrderBy {
return OrderBy(.descending(attribute(self.meta).keyPath))
}
/**
Creates an `OrderBy` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchAll(From<Person>(), Person.orderBy(descending: { $0.age }))
```
*/
public static func orderBy<O, V>(descending attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy {
return OrderBy(.descending(attribute(self.meta).keyPath))
}
// MARK: Deprecated
@available(*, deprecated, renamed: "orderBy(ascending:)")
public static func ascending<O, V>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy {
return OrderBy(.ascending(attribute(self.meta).keyPath))
}
@available(*, deprecated, renamed: "orderBy(descending:)")
public static func descending<O, V>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy {
return OrderBy(.descending(attribute(self.meta).keyPath))
}
}
// MARK: - ValueContainer.Required // MARK: - ValueContainer.Required
public extension ValueContainer.Required { public extension ValueContainer.Required {
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname == "John" }) let person = CoreStore.fetchOne(From<Person>().where({ $0.nickname == "John" }))
``` ```
*/ */
@inline(__always) public static func == (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where<O> {
public static func == (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where(attribute.keyPath, isEqualTo: value) return Where(attribute.keyPath, isEqualTo: value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is not equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname != "John" }) let person = CoreStore.fetchOne(From<Person>().where({ $0.nickname != "John" }))
``` ```
*/ */
@inline(__always) public static func != (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where<O> {
public static func != (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return !Where(attribute.keyPath, isEqualTo: value) return !Where(attribute.keyPath, isEqualTo: value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is less than a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age < 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age < 20 }))
``` ```
*/ */
@inline(__always) public static func < (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where<O> {
public static func < (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K < %@", attribute.keyPath, value) return Where("%K < %@", attribute.keyPath, value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is greater than a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age > 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age > 20 }))
``` ```
*/ */
@inline(__always) public static func > (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where<O> {
public static func > (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K > %@", attribute.keyPath, value) return Where("%K > %@", attribute.keyPath, value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is less than or equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age <= 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age <= 20 }))
``` ```
*/ */
@inline(__always) public static func <= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where<O> {
public static func <= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K <= %@", attribute.keyPath, value) return Where("%K <= %@", attribute.keyPath, value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is greater than or equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age >= 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age >= 20 }))
``` ```
*/ */
@inline(__always) public static func >= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where<O> {
public static func >= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K >= %@", attribute.keyPath, value) return Where("%K >= %@", attribute.keyPath, value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by checking if a sequence contains the value of a property
``` ```
let dog = CoreStore.fetchOne(From<Dog>(), Dog.where { ["Pluto", "Snoopy", "Scooby"] ~= $0.nickname }) let dog = CoreStore.fetchOne(From<Dog>().where({ ["Pluto", "Snoopy", "Scooby"] ~= $0.nickname }))
``` ```
*/ */
@inline(__always) public static func ~= <S: Sequence>(_ sequence: S, _ attribute: ValueContainer<O>.Required<V>) -> Where<O> where S.Iterator.Element == V {
public static func ~= <S: Sequence>(_ sequence: S, _ attribute: ValueContainer<O>.Required<V>) -> Where where S.Iterator.Element == V {
return Where(attribute.keyPath, isMemberOf: sequence) return Where(attribute.keyPath, isMemberOf: sequence)
} }
@@ -253,37 +115,34 @@ public extension ValueContainer.Required {
public extension ValueContainer.Optional { public extension ValueContainer.Optional {
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname == "John" }) let person = CoreStore.fetchOne(From<Person>().where({ $0.nickname == "John" }))
``` ```
*/ */
@inline(__always) public static func == (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where<O> {
public static func == (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {
return Where(attribute.keyPath, isEqualTo: value) return Where(attribute.keyPath, isEqualTo: value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is not equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname != "John" }) let person = CoreStore.fetchOne(From<Person>().where({ $0.nickname != "John" }))
``` ```
*/ */
@inline(__always) public static func != (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where<O> {
public static func != (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {
return !Where(attribute.keyPath, isEqualTo: value) return !Where(attribute.keyPath, isEqualTo: value)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is less than a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age < 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age < 20 }))
``` ```
*/ */
@inline(__always) public static func < (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where<O> {
public static func < (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {
if let value = value { if let value = value {
@@ -296,13 +155,12 @@ public extension ValueContainer.Optional {
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is greater than a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age > 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age > 20 }))
``` ```
*/ */
@inline(__always) public static func > (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where<O> {
public static func > (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {
if let value = value { if let value = value {
@@ -315,13 +173,12 @@ public extension ValueContainer.Optional {
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is less than or equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age <= 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age <= 20 }))
``` ```
*/ */
@inline(__always) public static func <= (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where<O> {
public static func <= (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {
if let value = value { if let value = value {
@@ -334,13 +191,12 @@ public extension ValueContainer.Optional {
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by comparing if a property is greater than or equal to a value
``` ```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age >= 20 }) let person = CoreStore.fetchOne(From<Person>().where({ $0.age >= 20 }))
``` ```
*/ */
@inline(__always) public static func >= (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where<O> {
public static func >= (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {
if let value = value { if let value = value {
@@ -353,13 +209,12 @@ public extension ValueContainer.Optional {
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Value` property. Creates a `Where` clause by checking if a sequence contains the value of a property
``` ```
let dog = CoreStore.fetchOne(From<Dog>(), Dog.where { ["Pluto", "Snoopy", "Scooby"] ~= $0.nickname }) let dog = CoreStore.fetchOne(From<Dog>().where({ ["Pluto", "Snoopy", "Scooby"] ~= $0.nickname }))
``` ```
*/ */
@inline(__always) public static func ~= <S: Sequence>(_ sequence: S, _ attribute: ValueContainer<O>.Optional<V>) -> Where<O> where S.Iterator.Element == V {
public static func ~= <S: Sequence>(_ sequence: S, _ attribute: ValueContainer<O>.Optional<V>) -> Where where S.Iterator.Element == V {
return Where(attribute.keyPath, isMemberOf: sequence) return Where(attribute.keyPath, isMemberOf: sequence)
} }
@@ -371,50 +226,101 @@ public extension ValueContainer.Optional {
public extension RelationshipContainer.ToOne { public extension RelationshipContainer.ToOne {
/** /**
Creates a `Where` clause from a `CoreStoreObject.Relationship` property. Creates a `Where` clause by comparing if a property is equal to a value
``` ```
let dog = CoreStore.fetchOne(From<Dog>(), Dog.where { $0.master == me }) let dog = CoreStore.fetchOne(From<Dog>().where({ $0.master == me }))
``` ```
*/ */
@inline(__always) public static func == (_ relationship: RelationshipContainer<O>.ToOne<D>, _ object: D?) -> Where<O> {
public static func == (_ relationship: RelationshipContainer<O>.ToOne<D>, _ object: D?) -> Where {
return Where(relationship.keyPath, isEqualTo: object) return Where(relationship.keyPath, isEqualTo: object)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Relationship` property. Creates a `Where` clause by comparing if a property is not equal to a value
``` ```
let dog = CoreStore.fetchOne(From<Dog>(), Dog.where { $0.master != me }) let dog = CoreStore.fetchOne(From<Dog>().where({ $0.master != me }))
``` ```
*/ */
@inline(__always) public static func != (_ relationship: RelationshipContainer<O>.ToOne<D>, _ object: D?) -> Where<O> {
public static func != (_ relationship: RelationshipContainer<O>.ToOne<D>, _ object: D?) -> Where {
return !Where(relationship.keyPath, isEqualTo: object) return !Where(relationship.keyPath, isEqualTo: object)
} }
/** /**
Creates a `Where` clause from a `CoreStoreObject.Relationship` property. Creates a `Where` clause by checking if a sequence contains the value of a property
``` ```
let dog = CoreStore.fetchOne(From<Dog>(), Dog.where { $0.master ~= me }) let dog = CoreStore.fetchOne(From<Dog>().where({ [john, joe, bob] ~= $0.master }))
``` ```
*/ */
@inline(__always) public static func ~= <S: Sequence>(_ sequence: S, _ relationship: RelationshipContainer<O>.ToOne<D>) -> Where<O> where S.Iterator.Element == D {
public static func ~= (_ relationship: RelationshipContainer<O>.ToOne<D>, _ object: D?) -> Where {
return Where(relationship.keyPath, isEqualTo: object)
}
/**
Creates a `Where` clause from a `CoreStoreObject.Relationship` property.
```
let dog = CoreStore.fetchOne(From<Dog>(), Dog.where { [john, joe, bob] ~= $0.master })
```
*/
@inline(__always)
public static func ~= <S: Sequence>(_ sequence: S, _ relationship: RelationshipContainer<O>.ToOne<D>) -> Where where S.Iterator.Element == D {
return Where(relationship.keyPath, isMemberOf: sequence) return Where(relationship.keyPath, isMemberOf: sequence)
} }
} }
// MARK: Deprecated
extension DynamicObject where Self: CoreStoreObject {
@available(*, deprecated, message: "Use the String(keyPath:) initializer and pass the KeyPath: String(keyPath: \\Person.name)")
public static func keyPath<O, V>(_ attribute: (Self) -> ValueContainer<O>.Required<V>) -> String {
return attribute(self.meta).keyPath
}
@available(*, deprecated, message: "Use the String(keyPath:) initializer and pass the KeyPath: String(keyPath: \\Person.name)")
public static func keyPath<O, V>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> String {
return attribute(self.meta).keyPath
}
@available(*, deprecated, message: "Use the String(keyPath:) initializer and pass the KeyPath: String(keyPath: \\Person.friend)")
public static func keyPath<O, D>(_ relationship: (Self) -> RelationshipContainer<O>.ToOne<D>) -> String {
return relationship(self.meta).keyPath
}
@available(*, deprecated, message: "Use the String(keyPath:) initializer and pass the KeyPath: String(keyPath: \\Person.friends)")
public static func keyPath<O, D>(_ relationship: (Self) -> RelationshipContainer<O>.ToManyOrdered<D>) -> String {
return relationship(self.meta).keyPath
}
@available(*, deprecated, message: "Use the String(keyPath:) initializer and pass the KeyPath: String(keyPath: \\Person.friends)")
public static func keyPath<O, D>(_ relationship: (Self) -> RelationshipContainer<O>.ToManyUnordered<D>) -> String {
return relationship(self.meta).keyPath
}
@available(*, deprecated, message: "Use the Where<DynamicObject>(_:) initializer that accepts the same closure argument")
public static func `where`(_ condition: (Self) -> Where<Self>) -> Where<Self> {
return condition(self.meta)
}
@available(*, deprecated, message: "Use the new OrderBy<DynamicObject>(ascending:) overload that accepts the same closure argument")
public static func orderBy<O, V>(ascending attribute: (Self) -> ValueContainer<O>.Required<V>) -> OrderBy<Self> {
return OrderBy(.ascending(attribute(self.meta).keyPath))
}
@available(*, deprecated, message: "Use the new OrderBy<DynamicObject>(ascending:) overload that accepts the same closure argument")
public static func orderBy<O, V>(ascending attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy<Self> {
return OrderBy(.ascending(attribute(self.meta).keyPath))
}
@available(*, deprecated, message: "Use the new OrderBy<DynamicObject>(descending:) overload that accepts the same closure argument")
public static func orderBy<O, V>(descending attribute: (Self) -> ValueContainer<O>.Required<V>) -> OrderBy<Self> {
return OrderBy(.descending(attribute(self.meta).keyPath))
}
@available(*, deprecated, message: "Use the new OrderBy<DynamicObject>(descending:) overload that accepts the same closure argument")
public static func orderBy<O, V>(descending attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy<Self> {
return OrderBy(.descending(attribute(self.meta).keyPath))
}
}
+11 -11
View File
@@ -208,7 +208,7 @@ public final class CoreStoreSchema: DynamicSchema {
} }
let rawModel = NSManagedObjectModel() let rawModel = NSManagedObjectModel()
var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:] var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:]
var allCustomGettersSetters: [DynamicEntity: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter]] = [:] var allCustomGettersSetters: [DynamicEntity: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]] = [:]
for entity in self.allEntities { for entity in self.allEntities {
let (entityDescription, customGetterSetterByKeyPaths) = self.entityDescription( let (entityDescription, customGetterSetterByKeyPaths) = self.entityDescription(
@@ -253,10 +253,10 @@ public final class CoreStoreSchema: DynamicSchema {
private let allEntities: Set<DynamicEntity> private let allEntities: Set<DynamicEntity>
private var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:] private var entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription] = [:]
private var customGettersSettersByEntity: [DynamicEntity: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter]] = [:] private var customGettersSettersByEntity: [DynamicEntity: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]] = [:]
private weak var cachedRawModel: NSManagedObjectModel? private weak var cachedRawModel: NSManagedObjectModel?
private func entityDescription(for entity: DynamicEntity, initializer: (DynamicEntity, ModelVersion) -> (entity: NSEntityDescription, customGetterSetterByKeyPaths: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter])) -> (entity: NSEntityDescription, customGetterSetterByKeyPaths: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter]) { private func entityDescription(for entity: DynamicEntity, initializer: (DynamicEntity, ModelVersion) -> (entity: NSEntityDescription, customGetterSetterByKeyPaths: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter])) -> (entity: NSEntityDescription, customGetterSetterByKeyPaths: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]) {
if let cachedEntityDescription = self.entityDescriptionsByEntity[entity] { if let cachedEntityDescription = self.entityDescriptionsByEntity[entity] {
@@ -269,7 +269,7 @@ public final class CoreStoreSchema: DynamicSchema {
return (entityDescription, customGetterSetterByKeyPaths) return (entityDescription, customGetterSetterByKeyPaths)
} }
private static func firstPassCreateEntityDescription(from entity: DynamicEntity, in modelVersion: ModelVersion) -> (entity: NSEntityDescription, customGetterSetterByKeyPaths: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter]) { private static func firstPassCreateEntityDescription(from entity: DynamicEntity, in modelVersion: ModelVersion) -> (entity: NSEntityDescription, customGetterSetterByKeyPaths: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]) {
let entityDescription = NSEntityDescription() let entityDescription = NSEntityDescription()
entityDescription.coreStoreEntity = entity entityDescription.coreStoreEntity = entity
@@ -278,8 +278,8 @@ public final class CoreStoreSchema: DynamicSchema {
entityDescription.versionHashModifier = entity.versionHashModifier entityDescription.versionHashModifier = entity.versionHashModifier
entityDescription.managedObjectClassName = CoreStoreManagedObject.cs_subclassName(for: entity, in: modelVersion) entityDescription.managedObjectClassName = CoreStoreManagedObject.cs_subclassName(for: entity, in: modelVersion)
var keyPathsByAffectedKeyPaths: [RawKeyPath: Set<RawKeyPath>] = [:] var keyPathsByAffectedKeyPaths: [KeyPathString: Set<KeyPathString>] = [:]
var customGetterSetterByKeyPaths: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter] = [:] var customGetterSetterByKeyPaths: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter] = [:]
func createProperties(for type: CoreStoreObject.Type) -> [NSPropertyDescription] { func createProperties(for type: CoreStoreObject.Type) -> [NSPropertyDescription] {
var propertyDescriptions: [NSPropertyDescription] = [] var propertyDescriptions: [NSPropertyDescription] = []
@@ -290,7 +290,7 @@ public final class CoreStoreSchema: DynamicSchema {
case let attribute as AttributeProtocol: case let attribute as AttributeProtocol:
let description = NSAttributeDescription() let description = NSAttributeDescription()
description.name = attribute.keyPath description.name = attribute.keyPath
description.attributeType = type(of: attribute).attributeType description.attributeType = Swift.type(of: attribute).attributeType
description.isOptional = attribute.isOptional description.isOptional = attribute.isOptional
description.isIndexed = attribute.isIndexed description.isIndexed = attribute.isIndexed
description.defaultValue = attribute.defaultValue() description.defaultValue = attribute.defaultValue()
@@ -443,9 +443,9 @@ public final class CoreStoreSchema: DynamicSchema {
} }
} }
private static func fourthPassSynthesizeManagedObjectClasses(for entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription], allCustomGettersSetters: [DynamicEntity: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter]]) { private static func fourthPassSynthesizeManagedObjectClasses(for entityDescriptionsByEntity: [DynamicEntity: NSEntityDescription], allCustomGettersSetters: [DynamicEntity: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]]) {
func createManagedObjectSubclass(for entityDescription: NSEntityDescription, customGetterSetterByKeyPaths: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter]?) { func createManagedObjectSubclass(for entityDescription: NSEntityDescription, customGetterSetterByKeyPaths: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]?) {
let superEntity = entityDescription.superentity let superEntity = entityDescription.superentity
let className = entityDescription.managedObjectClassName! let className = entityDescription.managedObjectClassName!
@@ -527,7 +527,7 @@ public final class CoreStoreSchema: DynamicSchema {
let origSelector = #selector(NSManagedObject.keyPathsForValuesAffectingValue(forKey:)) let origSelector = #selector(NSManagedObject.keyPathsForValuesAffectingValue(forKey:))
let metaClass: AnyClass = object_getClass(managedObjectClass)! let metaClass: AnyClass = object_getClass(managedObjectClass)!
let origMethod = class_getClassMethod(managedObjectClass, origSelector) let origMethod = class_getClassMethod(managedObjectClass, origSelector)!
let origImp = method_getImplementation(origMethod) let origImp = method_getImplementation(origMethod)
let newImp = imp_implementationWithBlock(keyPathsForValuesAffectingValue) let newImp = imp_implementationWithBlock(keyPathsForValuesAffectingValue)
@@ -538,7 +538,7 @@ public final class CoreStoreSchema: DynamicSchema {
} }
else { else {
let newMethod = class_getClassMethod(managedObjectClass, newSelector) let newMethod = class_getClassMethod(managedObjectClass, newSelector)!
method_exchangeImplementations(origMethod, newMethod) method_exchangeImplementations(origMethod, newMethod)
} }
} }
+8
View File
@@ -64,3 +64,11 @@ public typealias EntityName = String
An `String` that pertains to a dynamically-accessable class name (usable with NSClassFromString(...)). An `String` that pertains to a dynamically-accessable class name (usable with NSClassFromString(...)).
*/ */
public typealias ClassName = String public typealias ClassName = String
// MARK: - KeyPathString
/**
An `String` that pertains to a attribute keyPaths.
*/
public typealias KeyPathString = String
+8 -8
View File
@@ -210,7 +210,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
/** /**
Accesses the property value via its keyPath. Accesses the property value via its keyPath.
*/ */
public subscript(attribute: RawKeyPath) -> Any? { public subscript(attribute: KeyPathString) -> Any? {
return self.rawObject.cs_accessValueForKVCKey(attribute) return self.rawObject.cs_accessValueForKVCKey(attribute)
} }
@@ -267,7 +267,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
/** /**
Accesses or mutates the property value via its keyPath. Accesses or mutates the property value via its keyPath.
*/ */
public subscript(attribute: RawKeyPath) -> Any? { public subscript(attribute: KeyPathString) -> Any? {
get { return self.rawObject.cs_accessValueForKVCKey(attribute) } get { return self.rawObject.cs_accessValueForKVCKey(attribute) }
set { self.rawObject.cs_setValue(newValue, forKVCKey: attribute) } set { self.rawObject.cs_setValue(newValue, forKVCKey: attribute) }
@@ -304,7 +304,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: Internal // MARK: Internal
internal init(_ rawObject: NSManagedObject, _ sourceAttributesByDestinationKey: [RawKeyPath: NSAttributeDescription]) { internal init(_ rawObject: NSManagedObject, _ sourceAttributesByDestinationKey: [KeyPathString: NSAttributeDescription]) {
self.rawObject = rawObject self.rawObject = rawObject
self.sourceAttributesByDestinationKey = sourceAttributesByDestinationKey self.sourceAttributesByDestinationKey = sourceAttributesByDestinationKey
@@ -314,7 +314,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: FilePrivate // MARK: FilePrivate
fileprivate let rawObject: NSManagedObject fileprivate let rawObject: NSManagedObject
fileprivate let sourceAttributesByDestinationKey: [RawKeyPath: NSAttributeDescription] fileprivate let sourceAttributesByDestinationKey: [KeyPathString: NSAttributeDescription]
} }
@@ -477,7 +477,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
let transformedRenamingIdentifiers = Set(destinationAttributes.keys) let transformedRenamingIdentifiers = Set(destinationAttributes.keys)
.intersection(sourceAttributes.keys) .intersection(sourceAttributes.keys)
var sourceAttributesByDestinationKey: [RawKeyPath: NSAttributeDescription] = [:] var sourceAttributesByDestinationKey: [KeyPathString: NSAttributeDescription] = [:]
for renamingIdentifier in transformedRenamingIdentifiers { for renamingIdentifier in transformedRenamingIdentifiers {
let sourceAttribute = sourceAttributes[renamingIdentifier]!.attribute let sourceAttribute = sourceAttributes[renamingIdentifier]!.attribute
@@ -535,7 +535,7 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
let userInfo = mapping.userInfo! let userInfo = mapping.userInfo!
let transformer = userInfo[CustomEntityMigrationPolicy.UserInfoKey.transformer]! as! CustomMapping.Transformer let transformer = userInfo[CustomEntityMigrationPolicy.UserInfoKey.transformer]! as! CustomMapping.Transformer
let sourceAttributesByDestinationKey = userInfo[CustomEntityMigrationPolicy.UserInfoKey.sourceAttributesByDestinationKey] as! [RawKeyPath: NSAttributeDescription] let sourceAttributesByDestinationKey = userInfo[CustomEntityMigrationPolicy.UserInfoKey.sourceAttributesByDestinationKey] as! [KeyPathString: NSAttributeDescription]
var destinationObject: UnsafeDestinationObject? var destinationObject: UnsafeDestinationObject?
try transformer( try transformer(
@@ -585,8 +585,8 @@ public class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
var insertMappings: Set<CustomMapping> = [] var insertMappings: Set<CustomMapping> = []
var copyMappings: Set<CustomMapping> = [] var copyMappings: Set<CustomMapping> = []
var transformMappings: Set<CustomMapping> = [] var transformMappings: Set<CustomMapping> = []
var allMappedSourceKeys: [RawKeyPath: RawKeyPath] = [:] var allMappedSourceKeys: [KeyPathString: KeyPathString] = [:]
var allMappedDestinationKeys: [RawKeyPath: RawKeyPath] = [:] var allMappedDestinationKeys: [KeyPathString: KeyPathString] = [:]
let sourceRenamingIdentifiers = sourceModel.cs_resolvedRenamingIdentities() let sourceRenamingIdentifiers = sourceModel.cs_resolvedRenamingIdentities()
let sourceEntityNames = sourceModel.entitiesByName let sourceEntityNames = sourceModel.entitiesByName
+13 -5
View File
@@ -648,8 +648,9 @@ public extension DataStack {
let mappingProviders = storage.migrationMappingProviders let mappingProviders = storage.migrationMappingProviders
do { do {
try withExtendedLifetime((sourceSchema.rawModel(), destinationSchema.rawModel())) { (sourceModel, destinationModel) in try withExtendedLifetime((sourceSchema.rawModel(), destinationSchema.rawModel())) {
let (sourceModel, destinationModel) = $0
let mapping = try mappingProviders.findMapping( let mapping = try mappingProviders.findMapping(
sourceSchema: sourceSchema, sourceSchema: sourceSchema,
destinationSchema: destinationSchema, destinationSchema: destinationSchema,
@@ -682,6 +683,15 @@ public extension DataStack {
private func startMigrationForStorage<T: LocalStorage>(_ storage: T, sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType, progress: Progress) throws { private func startMigrationForStorage<T: LocalStorage>(_ storage: T, sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType, progress: Progress) throws {
do {
try storage.cs_finalizeStorageAndWait(soureModelHint: sourceModel)
}
catch {
throw CoreStoreError(error)
}
let fileURL = storage.fileURL let fileURL = storage.fileURL
if case .lightweight = migrationType { if case .lightweight = migrationType {
@@ -714,7 +724,6 @@ public extension DataStack {
} }
timerQueue.async(execute: recursiveCheck) timerQueue.async(execute: recursiveCheck)
_ = try storage.cs_finalizeStorageAndWait(soureModelHint: sourceModel)
_ = try withExtendedLifetime(NSPersistentStoreCoordinator(managedObjectModel: destinationModel)) { (coordinator: NSPersistentStoreCoordinator) in _ = try withExtendedLifetime(NSPersistentStoreCoordinator(managedObjectModel: destinationModel)) { (coordinator: NSPersistentStoreCoordinator) in
try coordinator.addPersistentStoreSynchronously( try coordinator.addPersistentStoreSynchronously(
@@ -730,13 +739,13 @@ public extension DataStack {
fakeProgress = 1 fakeProgress = 1
} }
_ = try? storage.cs_finalizeStorageAndWait(soureModelHint: destinationModel) try storage.cs_finalizeStorageAndWait(soureModelHint: destinationModel)
progress.completedUnitCount = progress.totalUnitCount progress.completedUnitCount = progress.totalUnitCount
return return
} }
catch { catch {
// try manual migration throw CoreStoreError(error)
} }
} }
@@ -764,7 +773,6 @@ public extension DataStack {
do { do {
try storage.cs_finalizeStorageAndWait(soureModelHint: sourceModel)
try migrationManager.migrateStore( try migrationManager.migrateStore(
from: fileURL, from: fileURL,
sourceType: type(of: storage).storeType, sourceType: type(of: storage).storeType,
+104 -13
View File
@@ -38,7 +38,7 @@ public extension DataStack {
- parameter object: the `DynamicObject` to observe changes from - parameter object: the `DynamicObject` to observe changes from
- returns: a `ObjectMonitor` that monitors changes to `object` - returns: a `ObjectMonitor` that monitors changes to `object`
*/ */
public func monitorObject<T>(_ object: T) -> ObjectMonitor<T> { public func monitorObject<D>(_ object: D) -> ObjectMonitor<D> {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -54,7 +54,7 @@ public extension DataStack {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorList<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> ListMonitor<T> { public func monitorList<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
return self.monitorList(from, fetchClauses) return self.monitorList(from, fetchClauses)
} }
@@ -66,7 +66,7 @@ public extension DataStack {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorList<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> ListMonitor<T> { public func monitorList<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -82,12 +82,29 @@ public extension DataStack {
CoreStore.assert( CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false, fetchRequest.sortDescriptors?.isEmpty == false,
"An \(cs_typeName(ListMonitor<T>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor." "An \(cs_typeName(ListMonitor<D>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy<D>.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor."
) )
} }
) )
} }
/**
Creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let monitor = dataStack.monitorList(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public func monitorList<B: FetchChainableBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
return self.monitorList(clauseChain.from, clauseChain.fetchClauses)
}
/** /**
Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
@@ -95,7 +112,7 @@ public extension DataStack {
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ fetchClauses: FetchClause...) { public func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: FetchClause...) {
self.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses) self.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
} }
@@ -107,7 +124,7 @@ public extension DataStack {
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ fetchClauses: [FetchClause]) { public func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: [FetchClause]) {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -123,13 +140,39 @@ public extension DataStack {
CoreStore.assert( CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false, fetchRequest.sortDescriptors?.isEmpty == false,
"An \(cs_typeName(ListMonitor<T>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor." "An \(cs_typeName(ListMonitor<D>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy<D>.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor."
) )
}, },
createAsynchronously: createAsynchronously createAsynchronously: createAsynchronously
) )
} }
/**
Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
```
dataStack.monitorList(
{ (monitor) in
self.monitor = monitor
},
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public func monitorList<B: FetchChainableBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
self.monitorList(
createAsynchronously: createAsynchronously,
clauseChain.from,
clauseChain.fetchClauses
)
}
/** /**
Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
@@ -138,7 +181,7 @@ public extension DataStack {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorSectionedList<T>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor<T> { public func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
return self.monitorSectionedList(from, sectionBy, fetchClauses) return self.monitorSectionedList(from, sectionBy, fetchClauses)
} }
@@ -151,7 +194,7 @@ public extension DataStack {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorSectionedList<T>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor<T> { public func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -168,12 +211,34 @@ public extension DataStack {
CoreStore.assert( CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false, fetchRequest.sortDescriptors?.isEmpty == false,
"An \(cs_typeName(ListMonitor<T>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor." "An \(cs_typeName(ListMonitor<D>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy<D>.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor."
) )
} }
) )
} }
/**
Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
```
let monitor = dataStack.monitorSectionedList(
From<MyPersonEntity>()
.sectionBy(\.age, { "\($0!) years old" })
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType`
*/
public func monitorSectionedList<B: SectionMonitorBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
return self.monitorSectionedList(
clauseChain.from,
clauseChain.sectionBy,
clauseChain.fetchClauses
)
}
/** /**
Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
@@ -182,7 +247,7 @@ public extension DataStack {
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorSectionedList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { public func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) {
self.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) self.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
} }
@@ -195,7 +260,7 @@ public extension DataStack {
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorSectionedList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { public func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -212,10 +277,36 @@ public extension DataStack {
CoreStore.assert( CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false, fetchRequest.sortDescriptors?.isEmpty == false,
"An \(cs_typeName(ListMonitor<T>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor." "An \(cs_typeName(ListMonitor<D>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy<D>.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor."
) )
}, },
createAsynchronously: createAsynchronously createAsynchronously: createAsynchronously
) )
} }
/**
Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
```
dataStack.monitorSectionedList(
{ (monitor) in
self.monitor = monitor
},
From<MyPersonEntity>()
.sectionBy(\.age, { "\($0!) years old" })
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType`
*/
public func monitorSectionedList<B: SectionMonitorBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
self.monitorSectionedList(
createAsynchronously: createAsynchronously,
clauseChain.from,
clauseChain.sectionBy,
clauseChain.fetchClauses
)
}
} }
+178 -18
View File
@@ -39,7 +39,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter object: a reference to the object created/fetched outside the `DataStack` - parameter object: a reference to the object created/fetched outside the `DataStack`
- returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ object: T) -> T? { public func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
return self.mainContext.fetchExisting(object) return self.mainContext.fetchExisting(object)
} }
@@ -50,7 +50,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? { public func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
return self.mainContext.fetchExisting(objectID) return self.mainContext.fetchExisting(objectID)
} }
@@ -61,7 +61,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter objects: an array of `DynamicObject`s created/fetched outside the `DataStack` - parameter objects: an array of `DynamicObject`s created/fetched outside the `DataStack`
- returns: the `DynamicObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
return self.mainContext.fetchExisting(objects) return self.mainContext.fetchExisting(objects)
} }
@@ -72,7 +72,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `DynamicObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID { public func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
return self.mainContext.fetchExisting(objectIDs) return self.mainContext.fetchExisting(objectIDs)
} }
@@ -84,7 +84,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? { public func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> D? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -100,7 +100,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? { public func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> D? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -109,6 +109,27 @@ extension DataStack: FetchableSource, QueryableSource {
return self.mainContext.fetchOne(from, fetchClauses) return self.mainContext.fetchOne(from, fetchClauses)
} }
/**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeen = dataStack.fetchOne(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType`
*/
public func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) -> B.ObjectType? {
CoreStore.assert(
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchOne(clauseChain)
}
/** /**
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -116,7 +137,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? { public func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [D]? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -132,7 +153,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? { public func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [D]? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -141,6 +162,27 @@ extension DataStack: FetchableSource, QueryableSource {
return self.mainContext.fetchAll(from, fetchClauses) return self.mainContext.fetchAll(from, fetchClauses)
} }
/**
Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let people = dataStack.fetchAll(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType`
*/
public func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) -> [B.ObjectType]? {
CoreStore.assert(
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchAll(clauseChain)
}
/** /**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -148,7 +190,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? { public func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -164,7 +206,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? { public func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -173,6 +215,27 @@ extension DataStack: FetchableSource, QueryableSource {
return self.mainContext.fetchCount(from, fetchClauses) return self.mainContext.fetchCount(from, fetchClauses)
} }
/**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let numberOfAdults = dataStack.fetchCount(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) -> Int? {
CoreStore.assert(
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchCount(clauseChain)
}
/** /**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -180,7 +243,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? { public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -196,7 +259,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? { public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -205,6 +268,27 @@ extension DataStack: FetchableSource, QueryableSource {
return self.mainContext.fetchObjectID(from, fetchClauses) return self.mainContext.fetchObjectID(from, fetchClauses)
} }
/**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeenID = dataStack.fetchObjectID(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType`
*/
public func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) -> NSManagedObjectID? {
CoreStore.assert(
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectID(clauseChain)
}
/** /**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -212,7 +296,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? { public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -228,7 +312,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -237,6 +321,27 @@ extension DataStack: FetchableSource, QueryableSource {
return self.mainContext.fetchObjectIDs(from, fetchClauses) return self.mainContext.fetchObjectIDs(from, fetchClauses)
} }
/**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let idsOfAdults = dataStack.fetchObjectIDs(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) -> [NSManagedObjectID]? {
CoreStore.assert(
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectIDs(clauseChain)
}
// MARK: QueryableSource // MARK: QueryableSource
@@ -250,7 +355,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? { public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -269,7 +374,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? { public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -278,6 +383,29 @@ extension DataStack: FetchableSource, QueryableSource {
return self.mainContext.queryValue(from, selectClause, queryClauses) return self.mainContext.queryValue(from, selectClause, queryClauses)
} }
/**
Queries a property value or aggregate as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let averageAdultAge = dataStack.queryValue(
From<MyPersonEntity>()
.select(Int.self, .average(\.age))
.where(\.age > 18)
)
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the property/aggregate to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
public func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) -> B.ResultType? where B.ResultType: QueryableAttributeType {
CoreStore.assert(
Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
/** /**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -288,7 +416,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? { public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -307,7 +435,7 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
public func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? { public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
CoreStore.assert( CoreStore.assert(
Thread.isMainThread, Thread.isMainThread,
@@ -316,6 +444,38 @@ extension DataStack: FetchableSource, QueryableSource {
return self.mainContext.queryAttributes(from, selectClause, queryClauses) return self.mainContext.queryAttributes(from, selectClause, queryClauses)
} }
/**
Queries a dictionary of attribute values or as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let results = dataStack.queryAttributes(
From<MyPersonEntity>()
.select(
NSDictionary.self,
.attribute(\.age, as: "age"),
.count(\.age, as: "numberOfPeople")
)
.groupBy(\.age)
)
for dictionary in results! {
let age = dictionary["age"] as! Int
let count = dictionary["numberOfPeople"] as! Int
print("There are \(count) people who are \(age) years old."
}
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the properties to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
public func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) -> [[String: Any]]? where B.ResultType == NSDictionary {
CoreStore.assert(
Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryAttributes(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
// MARK: FetchableSource, QueryableSource // MARK: FetchableSource, QueryableSource
+5 -2
View File
@@ -34,6 +34,11 @@ import CoreData
*/ */
public final class DataStack: Equatable { public final class DataStack: Equatable {
/**
The resolved application name, used by the `DataStack` as the default Xcode model name (.xcdatamodel filename) if not explicitly provided.
*/
public static let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
/** /**
Convenience initializer for `DataStack` that creates a `SchemaHistory` from the model with the specified `modelName` in the specified `bundle`. Convenience initializer for `DataStack` that creates a `SchemaHistory` from the model with the specified `modelName` in the specified `bundle`.
@@ -474,8 +479,6 @@ public final class DataStack: Equatable {
internal static var defaultConfigurationName = "PF_DEFAULT_CONFIGURATION_NAME" internal static var defaultConfigurationName = "PF_DEFAULT_CONFIGURATION_NAME"
internal static let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
internal let coordinator: NSPersistentStoreCoordinator internal let coordinator: NSPersistentStoreCoordinator
internal let rootSavingContext: NSManagedObjectContext internal let rootSavingContext: NSManagedObjectContext
internal let mainContext: NSManagedObjectContext internal let mainContext: NSManagedObjectContext
+193
View File
@@ -0,0 +1,193 @@
//
// DynamicKeyPath.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - DynamicKeyPath
/**
Used only for utility methods.
*/
public protocol DynamicKeyPath {
/**
The DynamicObject type
*/
associatedtype ObjectType
/**
The Value type
*/
associatedtype ValueType
/**
The keyPath string
*/
var cs_keyPathString: String { get }
}
// MARK: - KeyPathString
public extension KeyPathString {
/**
Extracts the keyPath string from the property.
```
let keyPath = String(keyPath: \Person.nickname)
```
*/
public init<O: NSManagedObject, V>(keyPath: KeyPath<O, V>) {
self = keyPath.cs_keyPathString
}
/**
Extracts the keyPath string from the property.
```
let keyPath = String(keyPath: \Person.nickname)
```
*/
public init<O: CoreStoreObject, K: DynamicKeyPath>(keyPath: KeyPath<O, K>) {
self = O.meta[keyPath: keyPath].cs_keyPathString
}
}
// MARK: - KeyPath: DynamicKeyPath
// TODO: SE-0143 is not implemented: https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md
//extension KeyPath: DynamicKeyPath where Root: NSManagedObject, Value: ImportableAttributeType {
extension KeyPath: DynamicKeyPath {
public typealias ObjectType = Root
public typealias ValueType = Value
public var cs_keyPathString: String {
return self._kvcKeyPathString!
}
}
// MARK: - ValueContainer.Required: DynamicKeyPath
extension ValueContainer.Required: DynamicKeyPath {
public typealias ObjectType = O
public typealias ValueType = V
public var cs_keyPathString: String {
return self.keyPath
}
}
// MARK: - ValueContainer.Optional: DynamicKeyPath
extension ValueContainer.Optional: DynamicKeyPath {
public typealias ObjectType = O
public typealias ValueType = V
public var cs_keyPathString: String {
return self.keyPath
}
}
// MARK: - TransformableContainer.Required: DynamicKeyPath
extension TransformableContainer.Required: DynamicKeyPath {
public typealias ObjectType = O
public typealias ValueType = V
public var cs_keyPathString: String {
return self.keyPath
}
}
// MARK: - TransformableContainer.Optional: DynamicKeyPath
extension TransformableContainer.Optional: DynamicKeyPath {
public typealias ObjectType = O
public typealias ValueType = V
public var cs_keyPathString: String {
return self.keyPath
}
}
// MARK: - RelationshipContainer.ToOne: DynamicKeyPath
extension RelationshipContainer.ToOne: DynamicKeyPath {
public typealias ObjectType = O
public typealias ValueType = D
public var cs_keyPathString: String {
return self.keyPath
}
}
// MARK: - RelationshipContainer.ToManyOrdered: DynamicKeyPath
extension RelationshipContainer.ToManyOrdered: DynamicKeyPath {
public typealias ObjectType = O
public typealias ValueType = D
public var cs_keyPathString: String {
return self.keyPath
}
}
// MARK: - RelationshipContainer.ToManyUnordered: DynamicKeyPath
extension RelationshipContainer.ToManyUnordered: DynamicKeyPath {
public typealias ObjectType = O
public typealias ValueType = D
public var cs_keyPathString: String {
return self.keyPath
}
}
+74
View File
@@ -0,0 +1,74 @@
//
// FetchChainBuilder.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - FetchChainBuilder
/**
The fetch builder type used for fetches. A `FetchChainBuilder` is created from a `From` clause.
```
let people = source.fetchAll(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
*/
public struct FetchChainBuilder<D: DynamicObject>: FetchChainableBuilderType {
// MARK: FetchChainableBuilderType
public typealias ObjectType = D
public var from: From<D>
public var fetchClauses: [FetchClause] = []
}
// MARK: - FetchChainableBuilderType
/**
Utility protocol for `FetchChainBuilder`. Used in fetch methods that support chained fetch builders.
*/
public protocol FetchChainableBuilderType {
/**
The `DynamicObject` type for the fetch
*/
associatedtype ObjectType: DynamicObject
/**
The `From` clause specifies the source entity and source persistent store for the fetch
*/
var from: From<ObjectType> { get set }
/**
The `FetchClause`s to be used for the fetch
*/
var fetchClauses: [FetchClause] { get set }
}
+84 -14
View File
@@ -40,7 +40,7 @@ public protocol FetchableSource: class {
- parameter object: a reference to the object created/fetched outside the `FetchableSource`'s context - parameter object: a reference to the object created/fetched outside the `FetchableSource`'s context
- returns: the `DynamicObject` instance if the object exists in the `FetchableSource`'s context, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `FetchableSource`'s context, or `nil` if not found.
*/ */
func fetchExisting<T: DynamicObject>(_ object: T) -> T? func fetchExisting<D: DynamicObject>(_ object: D) -> D?
/** /**
Fetches the `DynamicObject` instance in the `FetchableSource`'s context from an `NSManagedObjectID`. Fetches the `DynamicObject` instance in the `FetchableSource`'s context from an `NSManagedObjectID`.
@@ -48,7 +48,7 @@ public protocol FetchableSource: class {
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `DynamicObject` instance if the object exists in the `FetchableSource`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `FetchableSource`, or `nil` if not found.
*/ */
func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D?
/** /**
Fetches the `DynamicObject` instances in the `FetchableSource`'s context from references created from another managed object context. Fetches the `DynamicObject` instances in the `FetchableSource`'s context from references created from another managed object context.
@@ -56,7 +56,7 @@ public protocol FetchableSource: class {
- parameter objects: an array of `DynamicObject`s created/fetched outside the `FetchableSource`'s context - parameter objects: an array of `DynamicObject`s created/fetched outside the `FetchableSource`'s context
- returns: the `DynamicObject` array for objects that exists in the `FetchableSource` - returns: the `DynamicObject` array for objects that exists in the `FetchableSource`
*/ */
func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D
/** /**
Fetches the `DynamicObject` instances in the `FetchableSource`'s context from a list of `NSManagedObjectID`. Fetches the `DynamicObject` instances in the `FetchableSource`'s context from a list of `NSManagedObjectID`.
@@ -64,7 +64,7 @@ public protocol FetchableSource: class {
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `DynamicObject` array for objects that exists in the `FetchableSource`'s context - returns: the `DynamicObject` array for objects that exists in the `FetchableSource`'s context
*/ */
func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID
/** /**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -73,7 +73,7 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
func fetchOne<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> D?
/** /**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -82,7 +82,21 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
func fetchOne<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> D?
/**
Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeen = source.fetchOne(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType`
*/
func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) -> B.ObjectType?
/** /**
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -91,7 +105,7 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
func fetchAll<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [D]?
/** /**
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -100,7 +114,21 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
func fetchAll<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [D]?
/**
Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let people = source.fetchAll(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType`
*/
func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) -> [B.ObjectType]?
/** /**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -109,7 +137,7 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchCount<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> Int?
/** /**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -118,7 +146,21 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchCount<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> Int?
/**
Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let numberOfAdults = source.fetchCount(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the number `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) -> Int?
/** /**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -127,7 +169,7 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> NSManagedObjectID?
/** /**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -136,7 +178,21 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID?
/**
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let youngestTeenID = source.fetchObjectID(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType`
*/
func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) -> NSManagedObjectID?
/** /**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -145,7 +201,7 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]?
/** /**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -154,7 +210,21 @@ public protocol FetchableSource: class {
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]?
/**
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
```
let idsOfAdults = source.fetchObjectIDs(
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) -> [NSManagedObjectID]?
/** /**
The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases. The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
+858
View File
@@ -0,0 +1,858 @@
//
// From+Querying.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - From
public extension From {
/**
Creates a `FetchChainBuilder` that starts with the specified `Where` clause
- parameter clause: the `Where` clause to create a `FetchChainBuilder` with
- returns: a `FetchChainBuilder` that starts with the specified `Where` clause
*/
public func `where`(_ clause: Where<D>) -> FetchChainBuilder<D> {
return self.fetchChain(appending: clause)
}
/**
Creates a `FetchChainBuilder` with a predicate using the specified string format and arguments
- parameter format: the format string for the predicate
- parameter args: the arguments for `format`
- returns: a `FetchChainBuilder` with a predicate using the specified string format and arguments
*/
public func `where`(format: String, _ args: Any...) -> FetchChainBuilder<D> {
return self.fetchChain(appending: Where<D>(format, argumentArray: args))
}
/**
Creates a `FetchChainBuilder` with a predicate using the specified string format and arguments
- parameter format: the format string for the predicate
- parameter argumentArray: the arguments for `format`
- returns: a `FetchChainBuilder` with a predicate using the specified string format and arguments
*/
public func `where`(format: String, argumentArray: [Any]?) -> FetchChainBuilder<D> {
return self.fetchChain(appending: Where<D>(format, argumentArray: argumentArray))
}
/**
Creates a `FetchChainBuilder` with a series of `SortKey`s
- parameter sortKey: a single `SortKey`
- parameter sortKeys: a series of other `SortKey`s
- returns: a `FetchChainBuilder` with a series of `SortKey`s
*/
public func orderBy(_ sortKey: OrderBy<D>.SortKey, _ sortKeys: OrderBy<D>.SortKey...) -> FetchChainBuilder<D> {
return self.fetchChain(appending: OrderBy<D>([sortKey] + sortKeys))
}
/**
Creates a `FetchChainBuilder` with a closure where the `NSFetchRequest` may be configured
- parameter fetchRequest: the block to customize the `NSFetchRequest`
- returns: a `FetchChainBuilder` with closure where the `NSFetchRequest` may be configured
*/
public func tweak(_ fetchRequest: @escaping (NSFetchRequest<NSFetchRequestResult>) -> Void) -> FetchChainBuilder<D> {
return self.fetchChain(appending: Tweak(fetchRequest))
}
/**
Creates a `FetchChainBuilder` and immediately appending a `FetchClause`
- parameter clause: the `FetchClause` to add to the `FetchChainBuilder`
- returns: a `FetchChainBuilder` containing the specified `FetchClause`
*/
public func appending(_ clause: FetchClause) -> FetchChainBuilder<D> {
return self.fetchChain(appending: clause)
}
/**
Creates a `FetchChainBuilder` and immediately appending a series of `FetchClause`s
- parameter clauses: the `FetchClause`s to add to the `FetchChainBuilder`
- returns: a `FetchChainBuilder` containing the specified `FetchClause`s
*/
public func appending<S: Sequence>(contentsOf clauses: S) -> FetchChainBuilder<D> where S.Element == FetchClause {
return self.fetchChain(appending: clauses)
}
/**
Creates a `QueryChainBuilder` that starts with the specified `Select` clause
- parameter clause: the `Select` clause to create a `QueryChainBuilder` with
- returns: a `QueryChainBuilder` that starts with the specified `Select` clause
*/
public func select<R>(_ clause: Select<D, R>) -> QueryChainBuilder<D, R> {
return .init(
from: self,
select: clause,
queryClauses: []
)
}
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified `SelectTerm`s
- parameter resultType: the generic `SelectResultType` for the `Select` clause
- parameter selectTerm: a `SelectTerm`
- parameter selectTerms: a series of `SelectTerm`s
- returns: a `QueryChainBuilder` that starts with a `Select` clause created from the specified `SelectTerm`s
*/
public func select<R>(_ resultType: R.Type, _ selectTerm: SelectTerm<D>, _ selectTerms: SelectTerm<D>...) -> QueryChainBuilder<D, R> {
return self.select(resultType, [selectTerm] + selectTerms)
}
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified `SelectTerm`s
- parameter resultType: the generic `SelectResultType` for the `Select` clause
- parameter selectTerms: a series of `SelectTerm`s
- returns: a `QueryChainBuilder` that starts with a `Select` clause created from the specified `SelectTerm`s
*/
public func select<R>(_ resultType: R.Type, _ selectTerms: [SelectTerm<D>]) -> QueryChainBuilder<D, R> {
return .init(
from: self,
select: .init(selectTerms),
queryClauses: []
)
}
/**
Creates a `SectionMonitorChainBuilder` that starts with the `SectionBy` to use to group `ListMonitor` objects into sections
- parameter clause: the `SectionBy` to be used by the `ListMonitor`
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy(_ clause: SectionBy<D>) -> SectionMonitorChainBuilder<D> {
return .init(
from: self,
sectionBy: clause,
fetchClauses: []
)
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the key path to use to group the objects into sections
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy(_ sectionKeyPath: KeyPathString) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(sectionKeyPath, { $0 })
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the key path to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy(_ sectionKeyPath: KeyPathString, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return .init(
from: self,
sectionBy: .init(sectionKeyPath, sectionIndexTransformer),
fetchClauses: []
)
}
// MARK: Private
private func fetchChain(appending clause: FetchClause) -> FetchChainBuilder<D> {
return .init(from: self, fetchClauses: [clause])
}
private func fetchChain<S: Sequence>(appending clauses: S) -> FetchChainBuilder<D> where S.Element == FetchClause {
return .init(from: self, fetchClauses: Array(clauses))
}
}
public extension From where D: NSManagedObject {
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
- parameter keyPath: the keyPath to query the value for
- returns: a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
*/
public func select<R>(_ keyPath: KeyPath<D, R>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, T>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(sectionKeyPath._kvcKeyPathString!, { $0 })
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, T>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(sectionKeyPath._kvcKeyPathString!, sectionIndexTransformer)
}
}
public extension From where D: CoreStoreObject {
/**
Creates a `FetchChainBuilder` that starts with the specified `Where` clause
- parameter clause: a closure that returns a `Where` clause
- returns: a `FetchChainBuilder` that starts with the specified `Where` clause
*/
public func `where`<T: AnyWhereClause>(_ clause: (D) -> T) -> FetchChainBuilder<D> {
return self.fetchChain(appending: clause(D.meta))
}
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
- parameter keyPath: the keyPath to query the value for
- returns: a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
*/
public func select<R>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
- parameter keyPath: the keyPath to query the value for
- returns: a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
*/
public func select<R>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
- parameter keyPath: the keyPath to query the value for
- returns: a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
*/
public func select<R>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
/**
Creates a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
- parameter keyPath: the keyPath to query the value for
- returns: a `QueryChainBuilder` that starts with a `Select` clause created from the specified key path
*/
public func select<R>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<R>>) -> QueryChainBuilder<D, R> {
return self.select(R.self, [SelectTerm<D>.attribute(keyPath)])
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Required<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, { $0 })
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Required<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Optional<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Required<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
/**
Creates a `SectionMonitorChainBuilder` with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the `KeyPath` to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
- returns: a `SectionMonitorChainBuilder` that is sectioned by the specified key path
*/
@available(OSX 10.12, *)
public func sectionBy<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) -> SectionMonitorChainBuilder<D> {
return self.sectionBy(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
}
public extension FetchChainBuilder {
/**
Adds a `Where` clause to the `FetchChainBuilder`
- parameter clause: a `Where` clause to add to the fetch builder
- returns: a new `FetchChainBuilder` containing the `Where` clause
*/
public func `where`(_ clause: Where<D>) -> FetchChainBuilder<D> {
return self.fetchChain(appending: clause)
}
/**
Adds a `Where` clause to the `FetchChainBuilder`
- parameter format: the format string for the predicate
- parameter args: the arguments for `format`
- returns: a new `FetchChainBuilder` containing the `Where` clause
*/
public func `where`(format: String, _ args: Any...) -> FetchChainBuilder<D> {
return self.fetchChain(appending: Where<D>(format, argumentArray: args))
}
/**
Adds a `Where` clause to the `FetchChainBuilder`
- parameter format: the format string for the predicate
- parameter argumentArray: the arguments for `format`
- returns: a new `FetchChainBuilder` containing the `Where` clause
*/
public func `where`(format: String, argumentArray: [Any]?) -> FetchChainBuilder<D> {
return self.fetchChain(appending: Where<D>(format, argumentArray: argumentArray))
}
/**
Adds an `OrderBy` clause to the `FetchChainBuilder`
- parameter sortKey: a single `SortKey`
- parameter sortKeys: a series of other `SortKey`s
- returns: a new `FetchChainBuilder` containing the `OrderBy` clause
*/
public func orderBy(_ sortKey: OrderBy<D>.SortKey, _ sortKeys: OrderBy<D>.SortKey...) -> FetchChainBuilder<D> {
return self.fetchChain(appending: OrderBy<D>([sortKey] + sortKeys))
}
/**
Adds a `Tweak` clause to the `FetchChainBuilder` with a closure where the `NSFetchRequest` may be configured
- parameter fetchRequest: the block to customize the `NSFetchRequest`
- returns: a new `FetchChainBuilder` containing the `Tweak` clause
*/
public func tweak(_ fetchRequest: @escaping (NSFetchRequest<NSFetchRequestResult>) -> Void) -> FetchChainBuilder<D> {
return self.fetchChain(appending: Tweak(fetchRequest))
}
/**
Appends a `FetchClause` to the `FetchChainBuilder`
- parameter clause: the `FetchClause` to add to the `FetchChainBuilder`
- returns: a new `FetchChainBuilder` containing the `FetchClause`
*/
public func appending(_ clause: FetchClause) -> FetchChainBuilder<D> {
return self.fetchChain(appending: clause)
}
/**
Appends a series of `FetchClause`s to the `FetchChainBuilder`
- parameter clauses: the `FetchClause`s to add to the `FetchChainBuilder`
- returns: a new `FetchChainBuilder` containing the `FetchClause`s
*/
public func appending<S: Sequence>(contentsOf clauses: S) -> FetchChainBuilder<D> where S.Element == FetchClause {
return self.fetchChain(appending: clauses)
}
// MARK: Private
private func fetchChain(appending clause: FetchClause) -> FetchChainBuilder<D> {
return .init(
from: self.from,
fetchClauses: self.fetchClauses + [clause]
)
}
private func fetchChain<S: Sequence>(appending clauses: S) -> FetchChainBuilder<D> where S.Element == FetchClause {
return .init(
from: self.from,
fetchClauses: self.fetchClauses + Array(clauses)
)
}
}
public extension FetchChainBuilder where D: CoreStoreObject {
public func `where`<T: AnyWhereClause>(_ clause: (D) -> T) -> FetchChainBuilder<D> {
return self.fetchChain(appending: clause(D.meta))
}
}
public extension QueryChainBuilder {
/**
Adds a `Where` clause to the `QueryChainBuilder`
- parameter clause: a `Where` clause to add to the query builder
- returns: a new `QueryChainBuilder` containing the `Where` clause
*/
public func `where`(_ clause: Where<D>) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: clause)
}
/**
Adds a `Where` clause to the `QueryChainBuilder`
- parameter format: the format string for the predicate
- parameter args: the arguments for `format`
- returns: a new `QueryChainBuilder` containing the `Where` clause
*/
public func `where`(format: String, _ args: Any...) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: Where<D>(format, argumentArray: args))
}
/**
Adds a `Where` clause to the `QueryChainBuilder`
- parameter format: the format string for the predicate
- parameter argumentArray: the arguments for `format`
- returns: a new `QueryChainBuilder` containing the `Where` clause
*/
public func `where`(format: String, argumentArray: [Any]?) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: Where<D>(format, argumentArray: argumentArray))
}
/**
Adds an `OrderBy` clause to the `QueryChainBuilder`
- parameter sortKey: a single `SortKey`
- parameter sortKeys: a series of other `SortKey`s
- returns: a new `QueryChainBuilder` containing the `OrderBy` clause
*/
public func orderBy(_ sortKey: OrderBy<D>.SortKey, _ sortKeys: OrderBy<D>.SortKey...) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: OrderBy<D>([sortKey] + sortKeys))
}
/**
Adds a `Tweak` clause to the `QueryChainBuilder` with a closure where the `NSFetchRequest` may be configured
- parameter fetchRequest: the block to customize the `NSFetchRequest`
- returns: a new `QueryChainBuilder` containing the `Tweak` clause
*/
public func tweak(_ fetchRequest: @escaping (NSFetchRequest<NSFetchRequestResult>) -> Void) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: Tweak(fetchRequest))
}
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter clause: a `GroupBy` clause to add to the query builder
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy(_ clause: GroupBy<D>) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: clause)
}
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter keyPath: a key path to group the query results with
- parameter keyPaths: other key paths to group the query results with
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy(_ keyPath: KeyPathString, _ keyPaths: KeyPathString...) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>([keyPath] + keyPaths))
}
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter keyPaths: a series of key paths to group the query results with
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy(_ keyPaths: [KeyPathString]) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: GroupBy<D>(keyPaths))
}
/**
Appends a `QueryClause` to the `QueryChainBuilder`
- parameter clause: the `QueryClause` to add to the `QueryChainBuilder`
- returns: a new `QueryChainBuilder` containing the `QueryClause`
*/
public func appending(_ clause: QueryClause) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: clause)
}
/**
Appends a series of `QueryClause`s to the `QueryChainBuilder`
- parameter clauses: the `QueryClause`s to add to the `QueryChainBuilder`
- returns: a new `QueryChainBuilder` containing the `QueryClause`s
*/
public func appending<S: Sequence>(contentsOf clauses: S) -> QueryChainBuilder<D, R> where S.Element == QueryClause {
return self.queryChain(appending: clauses)
}
// MARK: Private
private func queryChain(appending clause: QueryClause) -> QueryChainBuilder<D, R> {
return .init(
from: self.from,
select: self.select,
queryClauses: self.queryClauses + [clause]
)
}
private func queryChain<S: Sequence>(appending clauses: S) -> QueryChainBuilder<D, R> where S.Element == QueryClause {
return .init(
from: self.from,
select: self.select,
queryClauses: self.queryClauses + Array(clauses)
)
}
}
public extension QueryChainBuilder where D: NSManagedObject {
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter keyPath: a key path to group the query results with
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy<T>(_ keyPath: KeyPath<D, T>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
}
public extension QueryChainBuilder where D: CoreStoreObject {
/**
Adds a `Where` clause to the `QueryChainBuilder`
- parameter clause: a `Where` clause to add to the query builder
- returns: a new `QueryChainBuilder` containing the `Where` clause
*/
public func `where`<T: AnyWhereClause>(_ clause: (D) -> T) -> QueryChainBuilder<D, R> {
return self.queryChain(appending: clause(D.meta))
}
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter keyPath: a key path to group the query results with
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter keyPath: a key path to group the query results with
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter keyPath: a key path to group the query results with
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
/**
Adds a `GroupBy` clause to the `QueryChainBuilder`
- parameter keyPath: a key path to group the query results with
- returns: a new `QueryChainBuilder` containing the `GroupBy` clause
*/
public func groupBy<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) -> QueryChainBuilder<D, R> {
return self.groupBy(GroupBy<D>(keyPath))
}
}
@available(OSX 10.12, *)
public extension SectionMonitorChainBuilder {
/**
Adds a `Where` clause to the `SectionMonitorChainBuilder`
- parameter clause: a `Where` clause to add to the fetch builder
- returns: a new `SectionMonitorChainBuilder` containing the `Where` clause
*/
public func `where`(_ clause: Where<D>) -> SectionMonitorChainBuilder<D> {
return self.sectionMonitorChain(appending: clause)
}
/**
Adds a `Where` clause to the `SectionMonitorChainBuilder`
- parameter format: the format string for the predicate
- parameter args: the arguments for `format`
- returns: a new `SectionMonitorChainBuilder` containing the `Where` clause
*/
public func `where`(format: String, _ args: Any...) -> SectionMonitorChainBuilder<D> {
return self.sectionMonitorChain(appending: Where<D>(format, argumentArray: args))
}
/**
Adds a `Where` clause to the `SectionMonitorChainBuilder`
- parameter format: the format string for the predicate
- parameter argumentArray: the arguments for `format`
- returns: a new `SectionMonitorChainBuilder` containing the `Where` clause
*/
public func `where`(format: String, argumentArray: [Any]?) -> SectionMonitorChainBuilder<D> {
return self.sectionMonitorChain(appending: Where<D>(format, argumentArray: argumentArray))
}
/**
Adds an `OrderBy` clause to the `SectionMonitorChainBuilder`
- parameter sortKey: a single `SortKey`
- parameter sortKeys: a series of other `SortKey`s
- returns: a new `SectionMonitorChainBuilder` containing the `OrderBy` clause
*/
public func orderBy(_ sortKey: OrderBy<D>.SortKey, _ sortKeys: OrderBy<D>.SortKey...) -> SectionMonitorChainBuilder<D> {
return self.sectionMonitorChain(appending: OrderBy<D>([sortKey] + sortKeys))
}
/**
Adds a `Tweak` clause to the `SectionMonitorChainBuilder` with a closure where the `NSFetchRequest` may be configured
- parameter fetchRequest: the block to customize the `NSFetchRequest`
- returns: a new `SectionMonitorChainBuilder` containing the `Tweak` clause
*/
public func tweak(_ fetchRequest: @escaping (NSFetchRequest<NSFetchRequestResult>) -> Void) -> SectionMonitorChainBuilder<D> {
return self.sectionMonitorChain(appending: Tweak(fetchRequest))
}
/**
Appends a `QueryClause` to the `SectionMonitorChainBuilder`
- parameter clause: the `QueryClause` to add to the `SectionMonitorChainBuilder`
- returns: a new `SectionMonitorChainBuilder` containing the `QueryClause`
*/
public func appending(_ clause: FetchClause) -> SectionMonitorChainBuilder<D> {
return self.sectionMonitorChain(appending: clause)
}
/**
Appends a series of `QueryClause`s to the `SectionMonitorChainBuilder`
- parameter clauses: the `QueryClause`s to add to the `SectionMonitorChainBuilder`
- returns: a new `SectionMonitorChainBuilder` containing the `QueryClause`s
*/
public func appending<S: Sequence>(contentsOf clauses: S) -> SectionMonitorChainBuilder<D> where S.Element == FetchClause {
return self.sectionMonitorChain(appending: clauses)
}
// MARK: Private
private func sectionMonitorChain(appending clause: FetchClause) -> SectionMonitorChainBuilder<D> {
return .init(
from: self.from,
sectionBy: self.sectionBy,
fetchClauses: self.fetchClauses + [clause]
)
}
private func sectionMonitorChain<S: Sequence>(appending clauses: S) -> SectionMonitorChainBuilder<D> where S.Element == FetchClause {
return .init(
from: self.from,
sectionBy: self.sectionBy,
fetchClauses: self.fetchClauses + Array(clauses)
)
}
}
@available(OSX 10.12, *)
public extension SectionMonitorChainBuilder where D: CoreStoreObject {
/**
Adds a `Where` clause to the `SectionMonitorChainBuilder`
- parameter clause: a `Where` clause to add to the fetch builder
- returns: a new `SectionMonitorChainBuilder` containing the `Where` clause
*/
public func `where`<T: AnyWhereClause>(_ clause: (D) -> T) -> SectionMonitorChainBuilder<D> {
return self.sectionMonitorChain(appending: clause(D.meta))
}
}
+10 -10
View File
@@ -39,12 +39,12 @@ import CoreData
let person = transaction.fetchOne(From<Person>("Configuration1")) let person = transaction.fetchOne(From<Person>("Configuration1"))
``` ```
*/ */
public struct From<T: DynamicObject> { public struct From<D: DynamicObject> {
/** /**
The associated `NSManagedObject` or `CoreStoreObject` entity class The associated `NSManagedObject` or `CoreStoreObject` entity class
*/ */
public let entityClass: T.Type public let entityClass: D.Type
/** /**
The `NSPersistentStore` configuration names to associate objects from. The `NSPersistentStore` configuration names to associate objects from.
@@ -60,7 +60,7 @@ public struct From<T: DynamicObject> {
*/ */
public init() { public init() {
self.init(entityClass: T.self, configurations: nil) self.init(entityClass: D.self, configurations: nil)
} }
/** /**
@@ -70,7 +70,7 @@ public struct From<T: DynamicObject> {
``` ```
- parameter entity: the associated `NSManagedObject` or `CoreStoreObject` type - parameter entity: the associated `NSManagedObject` or `CoreStoreObject` type
*/ */
public init(_ entity: T.Type) { public init(_ entity: D.Type) {
self.init(entityClass: entity, configurations: nil) self.init(entityClass: entity, configurations: nil)
} }
@@ -85,7 +85,7 @@ public struct From<T: DynamicObject> {
*/ */
public init(_ configuration: ModelConfiguration, _ otherConfigurations: ModelConfiguration...) { public init(_ configuration: ModelConfiguration, _ otherConfigurations: ModelConfiguration...) {
self.init(entityClass: T.self, configurations: [configuration] + otherConfigurations) self.init(entityClass: D.self, configurations: [configuration] + otherConfigurations)
} }
/** /**
@@ -97,7 +97,7 @@ public struct From<T: DynamicObject> {
*/ */
public init(_ configurations: [ModelConfiguration]) { public init(_ configurations: [ModelConfiguration]) {
self.init(entityClass: T.self, configurations: configurations) self.init(entityClass: D.self, configurations: configurations)
} }
/** /**
@@ -109,7 +109,7 @@ public struct From<T: DynamicObject> {
- parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `CoreStoreObject`'s entity type. Set to `nil` to use the default configuration. - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `CoreStoreObject`'s entity type. Set to `nil` to use the default configuration.
- parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter) - parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter)
*/ */
public init(_ entity: T.Type, _ configuration: ModelConfiguration, _ otherConfigurations: ModelConfiguration...) { public init(_ entity: D.Type, _ configuration: ModelConfiguration, _ otherConfigurations: ModelConfiguration...) {
self.init(entityClass: entity, configurations: [configuration] + otherConfigurations) self.init(entityClass: entity, configurations: [configuration] + otherConfigurations)
} }
@@ -122,7 +122,7 @@ public struct From<T: DynamicObject> {
- parameter entity: the associated `NSManagedObject` or `CoreStoreObject` type - parameter entity: the associated `NSManagedObject` or `CoreStoreObject` type
- parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `CoreStoreObject`'s entity type. Set to `nil` to use the default configuration. - parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject` or `CoreStoreObject`'s entity type. Set to `nil` to use the default configuration.
*/ */
public init(_ entity: T.Type, _ configurations: [ModelConfiguration]) { public init(_ entity: D.Type, _ configurations: [ModelConfiguration]) {
self.init(entityClass: entity, configurations: configurations) self.init(entityClass: entity, configurations: configurations)
} }
@@ -132,7 +132,7 @@ public struct From<T: DynamicObject> {
internal let findPersistentStores: (_ context: NSManagedObjectContext) -> [NSPersistentStore]? internal let findPersistentStores: (_ context: NSManagedObjectContext) -> [NSPersistentStore]?
internal init(entityClass: T.Type, configurations: [ModelConfiguration]?, findPersistentStores: @escaping (_ context: NSManagedObjectContext) -> [NSPersistentStore]?) { internal init(entityClass: D.Type, configurations: [ModelConfiguration]?, findPersistentStores: @escaping (_ context: NSManagedObjectContext) -> [NSPersistentStore]?) {
self.entityClass = entityClass self.entityClass = entityClass
self.configurations = configurations self.configurations = configurations
@@ -167,7 +167,7 @@ public struct From<T: DynamicObject> {
// MARK: Private // MARK: Private
private init(entityClass: T.Type, configurations: [ModelConfiguration]?) { private init(entityClass: D.Type, configurations: [ModelConfiguration]?) {
self.entityClass = entityClass self.entityClass = entityClass
self.configurations = configurations self.configurations = configurations
+85 -8
View File
@@ -32,12 +32,7 @@ import CoreData
/** /**
The `GroupBy` clause specifies that the result of a query be grouped accoording to the specified key path. The `GroupBy` clause specifies that the result of a query be grouped accoording to the specified key path.
*/ */
public struct GroupBy: QueryClause, Hashable { public struct GroupBy<D: DynamicObject>: GroupByClause, QueryClause, Hashable {
/**
The list of key path strings to group results with
*/
public let keyPaths: [RawKeyPath]
/** /**
Initializes a `GroupBy` clause with an empty list of key path strings Initializes a `GroupBy` clause with an empty list of key path strings
@@ -53,7 +48,7 @@ public struct GroupBy: QueryClause, Hashable {
- parameter keyPath: a key path string to group results with - parameter keyPath: a key path string to group results with
- parameter keyPaths: a series of key path strings to group results with - parameter keyPaths: a series of key path strings to group results with
*/ */
public init(_ keyPath: RawKeyPath, _ keyPaths: RawKeyPath...) { public init(_ keyPath: KeyPathString, _ keyPaths: KeyPathString...) {
self.init([keyPath] + keyPaths) self.init([keyPath] + keyPaths)
} }
@@ -63,12 +58,19 @@ public struct GroupBy: QueryClause, Hashable {
- parameter keyPaths: a list of key path strings to group results with - parameter keyPaths: a list of key path strings to group results with
*/ */
public init(_ keyPaths: [RawKeyPath]) { public init(_ keyPaths: [KeyPathString]) {
self.keyPaths = keyPaths self.keyPaths = keyPaths
} }
// MARK: GroupByClause
public typealias ObjectType = D
public let keyPaths: [KeyPathString]
// MARK: QueryClause // MARK: QueryClause
public func applyToFetchRequest<ResultType>(_ fetchRequest: NSFetchRequest<ResultType>) { public func applyToFetchRequest<ResultType>(_ fetchRequest: NSFetchRequest<ResultType>) {
@@ -100,3 +102,78 @@ public struct GroupBy: QueryClause, Hashable {
return (self.keyPaths as NSArray).hashValue return (self.keyPaths as NSArray).hashValue
} }
} }
public extension GroupBy where D: NSManagedObject {
/**
Initializes a `GroupBy` clause with a key path
- parameter keyPath: a key path to group results with
*/
public init<T>(_ keyPath: KeyPath<D, T>) {
self.init([keyPath._kvcKeyPathString!])
}
}
public extension GroupBy where D: CoreStoreObject {
/**
Initializes a `GroupBy` clause with a key path
- parameter keyPath: a key path to group results with
*/
public init<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
/**
Initializes a `GroupBy` clause with a key path
- parameter keyPath: a key path to group results with
*/
public init<T>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
/**
Initializes a `GroupBy` clause with a key path
- parameter keyPath: a key path to group results with
*/
public init<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
/**
Initializes a `GroupBy` clause with a key path
- parameter keyPath: a key path to group results with
*/
public init<T>(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) {
self.init([D.meta[keyPath: keyPath].keyPath])
}
}
// MARK: - GroupByClause
/**
Abstracts the `GroupBy` clause for protocol utilities.
*/
public protocol GroupByClause {
/**
The `DynamicObject` type associated with the clause
*/
associatedtype ObjectType: DynamicObject
/**
The list of key path strings to group results with
*/
var keyPaths: [KeyPathString] { get }
}
+6
View File
@@ -163,12 +163,18 @@ extension UUID: ImportableAttributeType {}
extension RawRepresentable where RawValue: ImportableAttributeType { extension RawRepresentable where RawValue: ImportableAttributeType {
/**
Creates an instance of this type from its `QueryableNativeType` value.
*/
@inline(__always) @inline(__always)
public static func cs_fromQueryableNativeType(_ value: QueryableNativeType) -> Self? { public static func cs_fromQueryableNativeType(_ value: QueryableNativeType) -> Self? {
return RawValue.cs_fromQueryableNativeType(value).flatMap({ self.init(rawValue: $0) }) return RawValue.cs_fromQueryableNativeType(value).flatMap({ self.init(rawValue: $0) })
} }
/**
Creates `QueryableNativeType` value from this instance.
*/
@inline(__always) @inline(__always)
public func cs_toQueryableNativeType() -> QueryableNativeType { public func cs_toQueryableNativeType() -> QueryableNativeType {
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.2.4</string> <string>5.0.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
+15 -15
View File
@@ -39,12 +39,12 @@ import CoreData
let person = transaction.create(Into<MyPersonEntity>("Configuration1")) let person = transaction.create(Into<MyPersonEntity>("Configuration1"))
``` ```
*/ */
public struct Into<T: DynamicObject>: Hashable { public struct Into<D: DynamicObject>: Hashable {
/** /**
The associated `NSManagedObject` or `CoreStoreObject` entity class The associated `NSManagedObject` or `CoreStoreObject` entity class
*/ */
public let entityClass: T.Type public let entityClass: D.Type
/** /**
The `NSPersistentStore` configuration name to associate objects from. The `NSPersistentStore` configuration name to associate objects from.
@@ -60,17 +60,17 @@ public struct Into<T: DynamicObject>: Hashable {
*/ */
public init() { public init() {
self.init(entityClass: T.self, configuration: nil, inferStoreIfPossible: true) self.init(entityClass: D.self, configuration: nil, inferStoreIfPossible: true)
} }
/** /**
Initializes an `Into` clause with the specified entity type. Initializes an `Into` clause with the specified entity type. This is useful for querying a subclass while binding the generic type with a base class.
``` ```
let person = transaction.create(Into(MyPersonEntity.self)) let person = transaction.create(Into<MyPersonEntity>(MyEmployeeEntity.self))
``` ```
- parameter entity: the `NSManagedObject` type to be created - parameter entity: the `NSManagedObject` or `CoreStoreObject` type to be created
*/ */
public init(_ entity: T.Type) { public init(_ entity: D.Type) {
self.init(entityClass: entity, configuration: nil, inferStoreIfPossible: true) self.init(entityClass: entity, configuration: nil, inferStoreIfPossible: true)
} }
@@ -80,22 +80,22 @@ public struct Into<T: DynamicObject>: Hashable {
``` ```
let person = transaction.create(Into<MyPersonEntity>("Configuration1")) let person = transaction.create(Into<MyPersonEntity>("Configuration1"))
``` ```
- parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. - parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s or `CoreStoreObject`'s entity type. Set to `nil` to use the default configuration.
*/ */
public init(_ configuration: ModelConfiguration) { public init(_ configuration: ModelConfiguration) {
self.init(entityClass: T.self, configuration: configuration, inferStoreIfPossible: false) self.init(entityClass: D.self, configuration: configuration, inferStoreIfPossible: false)
} }
/** /**
Initializes an `Into` clause with the specified entity type and configuration. Initializes an `Into` clause with the specified entity type and configuration. This is useful for querying a subclass while binding the generic type with a base class.
``` ```
let person = transaction.create(Into(MyPersonEntity.self, "Configuration1")) let person = transaction.create(Into<MyPersonEntity>(MyEmployeeEntity.self, "Configuration1"))
``` ```
- parameter entity: the `NSManagedObject` type to be created - parameter entity: the `NSManagedObject` or `CoreStoreObject` type to be created
- parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration. - parameter configuration: the `NSPersistentStore` configuration name to associate the object to. This parameter is required if multiple configurations contain the created `NSManagedObject`'s or `CoreStoreObject`'s entity type. Set to `nil` to use the default configuration.
*/ */
public init(_ entity: T.Type, _ configuration: ModelConfiguration) { public init(_ entity: D.Type, _ configuration: ModelConfiguration) {
self.init(entityClass: entity, configuration: configuration, inferStoreIfPossible: false) self.init(entityClass: entity, configuration: configuration, inferStoreIfPossible: false)
} }
@@ -125,7 +125,7 @@ public struct Into<T: DynamicObject>: Hashable {
internal let inferStoreIfPossible: Bool internal let inferStoreIfPossible: Bool
internal init(entityClass: T.Type, configuration: ModelConfiguration, inferStoreIfPossible: Bool) { internal init(entityClass: D.Type, configuration: ModelConfiguration, inferStoreIfPossible: Bool) {
self.entityClass = entityClass self.entityClass = entityClass
self.configuration = configuration self.configuration = configuration
+611
View File
@@ -0,0 +1,611 @@
//
// KeyPath+Querying.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import CoreData
import Foundation
// MARK: - KeyPath where Root: NSManagedObject, Value: QueryableAttributeType & Equatable
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname == "John"))
```
*/
public func == <O: NSManagedObject, V: QueryableAttributeType & Equatable>(_ keyPath: KeyPath<O, V>, _ value: V) -> Where<O> {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: value)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname != "John"))
```
*/
public func != <O: NSManagedObject, V: QueryableAttributeType & Equatable>(_ keyPath: KeyPath<O, V>, _ value: V) -> Where<O> {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: value)
}
/**
Creates a `Where` clause by checking if a sequence contains the value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where(["Pluto", "Snoopy", "Scooby"] ~= \.nickname))
```
*/
public func ~= <O: NSManagedObject, V: QueryableAttributeType & Equatable, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, V>) -> Where<O> where S.Iterator.Element == V {
return Where<O>(keyPath._kvcKeyPathString!, isMemberOf: sequence)
}
// MARK: - KeyPath where Root: NSManagedObject, Value: Optional<QueryableAttributeType & Equatable>
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname == "John"))
```
*/
public func == <O: NSManagedObject, V: QueryableAttributeType & Equatable>(_ keyPath: KeyPath<O, Optional<V>>, _ value: V?) -> Where<O> {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: value)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname != "John"))
```
*/
public func != <O: NSManagedObject, V: QueryableAttributeType & Equatable>(_ keyPath: KeyPath<O, Optional<V>>, _ value: V?) -> Where<O> {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: value)
}
/**
Creates a `Where` clause by checking if a sequence contains the value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where(["Pluto", "Snoopy", "Scooby"] ~= \.nickname))
```
*/
public func ~= <O: NSManagedObject, V: QueryableAttributeType & Equatable, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, Optional<V>>) -> Where<O> where S.Iterator.Element == V {
return Where<O>(keyPath._kvcKeyPathString!, isMemberOf: sequence)
}
// MARK: - KeyPath where Root: NSManagedObject, Value: QueryableAttributeType & Comparable
/**
Creates a `Where` clause by comparing if a property is less than a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age < 20))
```
*/
public func < <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, V>, _ value: V) -> Where<O> {
return Where<O>("%K < %@", keyPath._kvcKeyPathString!, value)
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age > 20))
```
*/
public func > <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, V>, _ value: V) -> Where<O> {
return Where<O>("%K > %@", keyPath._kvcKeyPathString!, value)
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age <= 20))
```
*/
public func <= <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, V>, _ value: V) -> Where<O> {
return Where<O>("%K <= %@", keyPath._kvcKeyPathString!, value)
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age >= 20))
```
*/
public func >= <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, V>, _ value: V) -> Where<O> {
return Where<O>("%K >= %@", keyPath._kvcKeyPathString!, value)
}
// MARK: - KeyPath where Root: NSManagedObject, Value: Optional<QueryableAttributeType & Comparable>
/**
Creates a `Where` clause by comparing if a property is less than a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age < 20))
```
*/
public func < <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K < %@", keyPath._kvcKeyPathString!, value)
}
else {
return Where<O>("%K < nil", keyPath._kvcKeyPathString!)
}
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age > 20))
```
*/
public func > <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K > %@", keyPath._kvcKeyPathString!, value)
}
else {
return Where<O>("%K > nil", keyPath._kvcKeyPathString!)
}
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age <= 20))
```
*/
public func <= <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K <= %@", keyPath._kvcKeyPathString!, value)
}
else {
return Where<O>("%K <= nil", keyPath._kvcKeyPathString!)
}
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age >= 20))
```
*/
public func >= <O: NSManagedObject, V: QueryableAttributeType & Comparable>(_ keyPath: KeyPath<O, Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K >= %@", keyPath._kvcKeyPathString!, value)
}
else {
return Where<O>("%K >= nil", keyPath._kvcKeyPathString!)
}
}
// MARK: - KeyPath where Root: NSManagedObject, Value: NSManagedObject
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, D>, _ object: D) -> Where<O> {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, D>, _ object: D) -> Where<O> {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object)
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where([john, bob, joe] ~= \.master))
```
*/
public func ~= <O: NSManagedObject, D: NSManagedObject, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, D>) -> Where<O> where S.Iterator.Element == D {
return Where<O>(keyPath._kvcKeyPathString!, isMemberOf: sequence)
}
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, D>, _ objectID: NSManagedObjectID) -> Where<O> {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: objectID)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, D>, _ objectID: NSManagedObjectID) -> Where<O> {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: objectID)
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where([john, bob, joe] ~= \.master))
```
*/
public func ~= <O: NSManagedObject, D: NSManagedObject, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, D>) -> Where<O> where S.Iterator.Element == NSManagedObjectID {
return Where<O>(keyPath._kvcKeyPathString!, isMemberOf: sequence)
}
// MARK: - KeyPath where Root: NSManagedObject, Value: Optional<NSManagedObject>
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, Optional<D>>, _ object: D?) -> Where<O> {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, Optional<D>>, _ object: D?) -> Where<O> {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: object)
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where([john, bob, joe] ~= \.master))
```
*/
public func ~= <O: NSManagedObject, D: NSManagedObject, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, Optional<D>>) -> Where<O> where S.Iterator.Element == D {
return Where<O>(keyPath._kvcKeyPathString!, isMemberOf: sequence)
}
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, Optional<D>>, _ objectID: NSManagedObjectID) -> Where<O> {
return Where<O>(keyPath._kvcKeyPathString!, isEqualTo: objectID)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O: NSManagedObject, D: NSManagedObject>(_ keyPath: KeyPath<O, Optional<D>>, _ objectID: NSManagedObjectID) -> Where<O> {
return !Where<O>(keyPath._kvcKeyPathString!, isEqualTo: objectID)
}
/**
Creates a `Where` clause by checking if a sequence contains a value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where([john, bob, joe] ~= \.master))
```
*/
public func ~= <O: NSManagedObject, D: NSManagedObject, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, Optional<D>>) -> Where<O> where S.Iterator.Element == NSManagedObjectID {
return Where<O>(keyPath._kvcKeyPathString!, isMemberOf: sequence)
}
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Required<QueryableAttributeType & Equatable>
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname == "John"))
```
*/
public func == <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, _ value: V) -> Where<O> {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname != "John"))
```
*/
public func != <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, _ value: V) -> Where<O> {
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
}
/**
Creates a `Where` clause by checking if a sequence contains the value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where(["Pluto", "Snoopy", "Scooby"] ~= \.nickname))
```
*/
public func ~= <O, V, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>) -> Where<O> where S.Iterator.Element == V {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isMemberOf: sequence)
}
// MARK: - KeyPath where Root: CoreStoreObject, Value: ValueContainer<Root>.Optional<QueryableAttributeType & Equatable>
/**
Creates a `Where` clause by comparing if a property is equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname == "John"))
```
*/
public func == <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ value: V?) -> Where<O> {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
}
/**
Creates a `Where` clause by comparing if a property is not equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.nickname != "John"))
```
*/
public func != <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ value: V?) -> Where<O> {
return !Where<O>(O.meta[keyPath: keyPath].keyPath, isEqualTo: value)
}
/**
Creates a `Where` clause by checking if a sequence contains the value of a property
```
let dog = CoreStore.fetchOne(From<Dog>().where(["Pluto", "Snoopy", "Scooby"] ~= \.nickname))
```
*/
public func ~= <O, V, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>) -> Where<O> where S.Iterator.Element == V {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isMemberOf: sequence)
}
// 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 = CoreStore.fetchOne(From<Person>().where(\.age < 20))
```
*/
public func < <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, _ value: V) -> Where<O> {
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value)
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age > 20))
```
*/
public func > <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, _ value: V) -> Where<O> {
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value)
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age <= 20))
```
*/
public func <= <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, _ value: V) -> Where<O> {
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value)
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age >= 20))
```
*/
public func >= <O, V: Comparable>(_ keyPath: KeyPath<O, ValueContainer<O>.Required<V>>, _ value: V) -> Where<O> {
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value)
}
// 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 = CoreStore.fetchOne(From<Person>().where(\.age < 20))
```
*/
public func < <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K < %@", O.meta[keyPath: keyPath].keyPath, value)
}
else {
return Where<O>("%K < nil", O.meta[keyPath: keyPath].keyPath)
}
}
/**
Creates a `Where` clause by comparing if a property is greater than a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age > 20))
```
*/
public func > <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K > %@", O.meta[keyPath: keyPath].keyPath, value)
}
else {
return Where<O>("%K > nil", O.meta[keyPath: keyPath].keyPath)
}
}
/**
Creates a `Where` clause by comparing if a property is less than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age <= 20))
```
*/
public func <= <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K <= %@", O.meta[keyPath: keyPath].keyPath, value)
}
else {
return Where<O>("%K <= nil", O.meta[keyPath: keyPath].keyPath)
}
}
/**
Creates a `Where` clause by comparing if a property is greater than or equal to a value
```
let person = CoreStore.fetchOne(From<Person>().where(\.age >= 20))
```
*/
public func >= <O, V>(_ keyPath: KeyPath<O, ValueContainer<O>.Optional<V>>, _ value: V?) -> Where<O> {
if let value = value {
return Where<O>("%K >= %@", O.meta[keyPath: keyPath].keyPath, value)
}
else {
return Where<O>("%K >= nil", O.meta[keyPath: keyPath].keyPath)
}
}
// 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 = CoreStore.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>, _ object: D) -> 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
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master == john))
```
*/
public func == <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>, _ object: D?) -> 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
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>, _ object: D) -> 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
```
let dog = CoreStore.fetchOne(From<Dog>().where(\.master != john))
```
*/
public func != <O, D>(_ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>, _ object: D?) -> Where<O> {
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 = CoreStore.fetchOne(From<Dog>().where([john, bob, joe] ~= \.master))
```
*/
public func ~= <O, D, S: Sequence>(_ sequence: S, _ keyPath: KeyPath<O, RelationshipContainer<O>.ToOne<D>>) -> Where<O> where S.Iterator.Element == D {
return Where<O>(O.meta[keyPath: keyPath].keyPath, isMemberOf: sequence)
}
+8 -8
View File
@@ -626,7 +626,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
// MARK: Internal // MARK: Internal
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) { internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
self.init( self.init(
context: dataStack.mainContext, context: dataStack.mainContext,
@@ -638,7 +638,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
) )
} }
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) { internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) {
self.init( self.init(
context: dataStack.mainContext, context: dataStack.mainContext,
@@ -650,7 +650,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
) )
} }
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) { internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
self.init( self.init(
context: unsafeTransaction.context, context: unsafeTransaction.context,
@@ -662,7 +662,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
) )
} }
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) { internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) {
self.init( self.init(
context: unsafeTransaction.context, context: unsafeTransaction.context,
@@ -997,7 +997,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
fileprivate var fetchedResultsController: CoreStoreFetchedResultsController fileprivate var fetchedResultsController: CoreStoreFetchedResultsController
fileprivate let taskGroup = DispatchGroup() fileprivate let taskGroup = DispatchGroup()
fileprivate let sectionIndexTransformer: (_ sectionName: RawKeyPath?) -> String? fileprivate let sectionIndexTransformer: (_ sectionName: KeyPathString?) -> String?
private let isSectioned: Bool private let isSectioned: Bool
@@ -1041,7 +1041,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
} }
private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) -> (controller: CoreStoreFetchedResultsController, delegate: FetchedResultsControllerDelegate) { private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) -> (controller: CoreStoreFetchedResultsController, delegate: FetchedResultsControllerDelegate) {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
@@ -1065,9 +1065,9 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
private let from: From<ObjectType> private let from: From<ObjectType>
private let sectionBy: SectionBy? private let sectionBy: SectionBy<ObjectType>?
private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From<ObjectType>, sectionBy: SectionBy?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: ((ListMonitor<ObjectType>) -> Void)?) { private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: ((ListMonitor<ObjectType>) -> Void)?) {
self.isSectioned = (sectionBy != nil) self.isSectioned = (sectionBy != nil)
self.from = from self.from = from
+4 -3
View File
@@ -117,8 +117,9 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
var isValid = true var isValid = true
var versionTree = [String: String]() var versionTree = [String: String]()
elements.forEach { (sourceVersion, destinationVersion) in elements.forEach {
let (sourceVersion, destinationVersion) = $0
guard let _ = versionTree.updateValue(destinationVersion, forKey: sourceVersion) else { guard let _ = versionTree.updateValue(destinationVersion, forKey: sourceVersion) else {
return return
@@ -130,8 +131,8 @@ public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLitera
} }
let leafVersions = Set( let leafVersions = Set(
elements elements
.filter { versionTree[$1] == nil } .filter { versionTree[$0.1] == nil }
.map { $1 } .map { $0.1 }
) )
let isVersionAmbiguous = { (start: String) -> Bool in let isVersionAmbiguous = { (start: String) -> Bool in
@@ -87,14 +87,14 @@ internal extension NSEntityDescription {
} }
@nonobjc @nonobjc
internal var keyPathsByAffectedKeyPaths: [RawKeyPath: Set<RawKeyPath>] { internal var keyPathsByAffectedKeyPaths: [KeyPathString: Set<KeyPathString>] {
get { get {
if let userInfo = self.userInfo, if let userInfo = self.userInfo,
let value = userInfo[UserInfoKey.CoreStoreManagedObjectKeyPathsByAffectedKeyPaths] { let value = userInfo[UserInfoKey.CoreStoreManagedObjectKeyPathsByAffectedKeyPaths] {
return value as! [RawKeyPath: Set<RawKeyPath>] return value as! [KeyPathString: Set<KeyPathString>]
} }
return [:] return [:]
} }
@@ -108,14 +108,14 @@ internal extension NSEntityDescription {
} }
@nonobjc @nonobjc
internal var customGetterSetterByKeyPaths: [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter] { internal var customGetterSetterByKeyPaths: [KeyPathString: CoreStoreManagedObject.CustomGetterSetter] {
get { get {
if let userInfo = self.userInfo, if let userInfo = self.userInfo,
let value = userInfo[UserInfoKey.CoreStoreManagedObjectCustomGetterSetterByKeyPaths] { let value = userInfo[UserInfoKey.CoreStoreManagedObjectCustomGetterSetterByKeyPaths] {
return value as! [RawKeyPath: CoreStoreManagedObject.CustomGetterSetter] return value as! [KeyPathString: CoreStoreManagedObject.CustomGetterSetter]
} }
return [:] return [:]
} }
@@ -42,7 +42,7 @@ public extension DataStack {
- returns: an `NSFetchedResultsController` that observes the `DataStack` - returns: an `NSFetchedResultsController` that observes the `DataStack`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.mainContext, fromContext: self.mainContext,
@@ -62,7 +62,7 @@ public extension DataStack {
- returns: an `NSFetchedResultsController` that observes the `DataStack` - returns: an `NSFetchedResultsController` that observes the `DataStack`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.mainContext, fromContext: self.mainContext,
@@ -81,7 +81,7 @@ public extension DataStack {
- returns: an `NSFetchedResultsController` that observes the `DataStack` - returns: an `NSFetchedResultsController` that observes the `DataStack`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(_ from: From<D>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.mainContext, fromContext: self.mainContext,
@@ -100,7 +100,7 @@ public extension DataStack {
- returns: an `NSFetchedResultsController` that observes the `DataStack` - returns: an `NSFetchedResultsController` that observes the `DataStack`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(forDataStack dataStack: DataStack, _ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(forDataStack dataStack: DataStack, _ from: From<D>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.mainContext, fromContext: self.mainContext,
@@ -127,7 +127,7 @@ public extension UnsafeDataTransaction {
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction` - returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.context, fromContext: self.context,
@@ -147,7 +147,7 @@ public extension UnsafeDataTransaction {
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction` - returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.context, fromContext: self.context,
@@ -166,7 +166,7 @@ public extension UnsafeDataTransaction {
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction` - returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(_ from: From<D>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.context, fromContext: self.context,
@@ -185,7 +185,7 @@ public extension UnsafeDataTransaction {
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction` - returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/ */
@nonobjc @nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> { public func createFetchedResultsController<D: NSManagedObject>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<D> {
return createFRC( return createFRC(
fromContext: self.context, fromContext: self.context,
@@ -201,7 +201,7 @@ public extension UnsafeDataTransaction {
// MARK: - Private // MARK: - Private
@available(OSX 10.12, *) @available(OSX 10.12, *)
fileprivate func createFRC<T: NSManagedObject>(fromContext context: NSManagedObjectContext, from: From<T>, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> { fileprivate func createFRC<D: NSManagedObject>(fromContext context: NSManagedObjectContext, from: From<D>, sectionBy: SectionBy<D>? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController<D> {
let controller = CoreStoreFetchedResultsController( let controller = CoreStoreFetchedResultsController(
context: context, context: context,
@@ -214,7 +214,7 @@ fileprivate func createFRC<T: NSManagedObject>(fromContext context: NSManagedObj
CoreStore.assert( CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false, fetchRequest.sortDescriptors?.isEmpty == false,
"An \(cs_typeName(NSFetchedResultsController<NSManagedObject>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor." "An \(cs_typeName(NSFetchedResultsController<D>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy<D>.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor."
) )
} }
) )
+10 -10
View File
@@ -84,7 +84,7 @@ public extension NSManagedObject {
- returns: the primitive value for the KVC key - returns: the primitive value for the KVC key
*/ */
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func getValue(forKvcKey kvcKey: RawKeyPath) -> Any? { public func getValue(forKvcKey kvcKey: KeyPathString) -> Any? {
self.willAccessValue(forKey: kvcKey) self.willAccessValue(forKey: kvcKey)
defer { defer {
@@ -102,7 +102,7 @@ public extension NSManagedObject {
- returns: the primitive value transformed by the `didGetValue` closure - returns: the primitive value transformed by the `didGetValue` closure
*/ */
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func getValue<T>(forKvcKey kvcKey: RawKeyPath, didGetValue: (Any?) throws -> T) rethrows -> T { public func getValue<T>(forKvcKey kvcKey: KeyPathString, didGetValue: (Any?) throws -> T) rethrows -> T {
self.willAccessValue(forKey: kvcKey) self.willAccessValue(forKey: kvcKey)
defer { defer {
@@ -121,7 +121,7 @@ public extension NSManagedObject {
- returns: the primitive value transformed by the `didGetValue` closure - returns: the primitive value transformed by the `didGetValue` closure
*/ */
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func getValue<T>(forKvcKey kvcKey: RawKeyPath, willGetValue: () throws -> Void, didGetValue: (Any?) throws -> T) rethrows -> T { public func getValue<T>(forKvcKey kvcKey: KeyPathString, willGetValue: () throws -> Void, didGetValue: (Any?) throws -> T) rethrows -> T {
self.willAccessValue(forKey: kvcKey) self.willAccessValue(forKey: kvcKey)
defer { defer {
@@ -139,7 +139,7 @@ public extension NSManagedObject {
- parameter KVCKey: the KVC key - parameter KVCKey: the KVC key
*/ */
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func setValue(_ value: Any?, forKvcKey KVCKey: RawKeyPath) { public func setValue(_ value: Any?, forKvcKey KVCKey: KeyPathString) {
self.willChangeValue(forKey: KVCKey) self.willChangeValue(forKey: KVCKey)
defer { defer {
@@ -157,7 +157,7 @@ public extension NSManagedObject {
- parameter didSetValue: called after executing `setPrimitiveValue(forKey:)`. - parameter didSetValue: called after executing `setPrimitiveValue(forKey:)`.
*/ */
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func setValue(_ value: Any?, forKvcKey KVCKey: RawKeyPath, didSetValue: () -> Void) { public func setValue(_ value: Any?, forKvcKey KVCKey: KeyPathString, didSetValue: () -> Void) {
self.willChangeValue(forKey: KVCKey) self.willChangeValue(forKey: KVCKey)
defer { defer {
@@ -177,7 +177,7 @@ public extension NSManagedObject {
- parameter didSetValue: called after executing `setPrimitiveValue(forKey:)`. - parameter didSetValue: called after executing `setPrimitiveValue(forKey:)`.
*/ */
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func setValue<T>(_ value: T, forKvcKey KVCKey: RawKeyPath, willSetValue: (T) throws -> Any?, didSetValue: (Any?) -> Void = { _ in }) rethrows { public func setValue<T>(_ value: T, forKvcKey KVCKey: KeyPathString, willSetValue: (T) throws -> Any?, didSetValue: (Any?) -> Void = { _ in }) rethrows {
self.willChangeValue(forKey: KVCKey) self.willChangeValue(forKey: KVCKey)
defer { defer {
@@ -212,7 +212,7 @@ public extension NSManagedObject {
@available(*, deprecated, renamed: "getValue(forKvcKey:)") @available(*, deprecated, renamed: "getValue(forKvcKey:)")
@nonobjc @nonobjc
public func accessValueForKVCKey(_ KVCKey: RawKeyPath) -> Any? { public func accessValueForKVCKey(_ KVCKey: KeyPathString) -> Any? {
self.willAccessValue(forKey: KVCKey) self.willAccessValue(forKey: KVCKey)
defer { defer {
@@ -225,7 +225,7 @@ public extension NSManagedObject {
@available(*, deprecated, renamed: "getValue(forKvcKey:didGetValue:)") @available(*, deprecated, renamed: "getValue(forKvcKey:didGetValue:)")
@discardableResult @discardableResult
@nonobjc @nonobjc
public func accessValueForKVCKey<T>(_ KVCKey: RawKeyPath, _ didAccessPrimitiveValue: (Any?) throws -> T) rethrows -> T { public func accessValueForKVCKey<T>(_ KVCKey: KeyPathString, _ didAccessPrimitiveValue: (Any?) throws -> T) rethrows -> T {
self.willAccessValue(forKey: KVCKey) self.willAccessValue(forKey: KVCKey)
defer { defer {
@@ -237,7 +237,7 @@ public extension NSManagedObject {
@available(*, deprecated, renamed: "setValue(_:forKvcKey:)") @available(*, deprecated, renamed: "setValue(_:forKvcKey:)")
@nonobjc @nonobjc
public func setValue(_ value: Any?, forKVCKey KVCKey: RawKeyPath) { public func setValue(_ value: Any?, forKVCKey KVCKey: KeyPathString) {
self.willChangeValue(forKey: KVCKey) self.willChangeValue(forKey: KVCKey)
defer { defer {
@@ -250,7 +250,7 @@ public extension NSManagedObject {
@available(*, deprecated, renamed: "setValue(_:forKvcKey:didSetValue:)") @available(*, deprecated, renamed: "setValue(_:forKvcKey:didSetValue:)")
@discardableResult @discardableResult
@nonobjc @nonobjc
public func setValue<T>(_ value: Any?, forKVCKey KVCKey: RawKeyPath, _ didSetPrimitiveValue: (Any?) throws -> T) rethrows -> T { public func setValue<T>(_ value: Any?, forKVCKey KVCKey: KeyPathString, _ didSetPrimitiveValue: (Any?) throws -> T) rethrows -> T {
self.willChangeValue(forKey: KVCKey) self.willChangeValue(forKey: KVCKey)
defer { defer {
+2 -2
View File
@@ -38,7 +38,7 @@ public extension NSManagedObject {
- returns: the primitive value for the KVC key - returns: the primitive value for the KVC key
*/ */
@objc @objc
public func cs_accessValueForKVCKey(_ KVCKey: RawKeyPath) -> Any? { public func cs_accessValueForKVCKey(_ KVCKey: KeyPathString) -> Any? {
return self.getValue(forKvcKey: KVCKey) return self.getValue(forKvcKey: KVCKey)
} }
@@ -50,7 +50,7 @@ public extension NSManagedObject {
- parameter KVCKey: the KVC key - parameter KVCKey: the KVC key
*/ */
@objc @objc
public func cs_setValue(_ value: Any?, forKVCKey KVCKey: RawKeyPath) { public func cs_setValue(_ value: Any?, forKVCKey KVCKey: KeyPathString) {
self.setValue(value, forKvcKey: KVCKey) self.setValue(value, forKvcKey: KVCKey)
} }
@@ -142,15 +142,14 @@ internal extension NSManagedObjectContext {
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
let selectTerms = selectClause.selectTerms selectClause.applyToFetchRequest(fetchRequest)
selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) } queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else { guard storeFound else {
return nil return nil
} }
return self.queryValue(selectTerms, fetchRequest: fetchRequest.dynamicCast()) return self.queryValue(selectClause.selectTerms, fetchRequest: fetchRequest.dynamicCast())
} }
@nonobjc @nonobjc
@@ -161,7 +160,7 @@ internal extension NSManagedObjectContext {
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
selectClause.selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause) selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) } queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else { guard storeFound else {
+77 -41
View File
@@ -34,7 +34,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
// MARK: FetchableSource // MARK: FetchableSource
@nonobjc @nonobjc
public func fetchExisting<T: DynamicObject>(_ object: T) -> T? { public func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
let rawObject = object.cs_toRaw() let rawObject = object.cs_toRaw()
if rawObject.objectID.isTemporaryID { if rawObject.objectID.isTemporaryID {
@@ -75,12 +75,12 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
} }
@nonobjc @nonobjc
public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? { public func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
do { do {
let existingObject = try self.existingObject(with: objectID) let existingObject = try self.existingObject(with: objectID)
return T.cs_fromRaw(object: existingObject) return D.cs_fromRaw(object: existingObject)
} }
catch _ { catch _ {
@@ -89,25 +89,25 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
} }
@nonobjc @nonobjc
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
return objects.flatMap({ self.fetchExisting($0.cs_id()) }) return objects.flatMap({ self.fetchExisting($0.cs_id()) })
} }
@nonobjc @nonobjc
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID { public func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
return objectIDs.flatMap({ self.fetchExisting($0) }) return objectIDs.flatMap({ self.fetchExisting($0) })
} }
@nonobjc @nonobjc
public func fetchOne<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? { public func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> D? {
return self.fetchOne(from, fetchClauses) return self.fetchOne(from, fetchClauses)
} }
@nonobjc @nonobjc
public func fetchOne<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? { public func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> D? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -124,13 +124,19 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
} }
@nonobjc @nonobjc
public func fetchAll<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? { public func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) -> B.ObjectType? {
return self.fetchOne(clauseChain.from, clauseChain.fetchClauses)
}
@nonobjc
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [D]? {
return self.fetchAll(from, fetchClauses) return self.fetchAll(from, fetchClauses)
} }
@nonobjc @nonobjc
public func fetchAll<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? { public func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [D]? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -148,13 +154,19 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
} }
@nonobjc @nonobjc
public func fetchCount<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? { public func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) -> [B.ObjectType]? {
return self.fetchAll(clauseChain.from, clauseChain.fetchClauses)
}
@nonobjc
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses) return self.fetchCount(from, fetchClauses)
} }
@nonobjc @nonobjc
public func fetchCount<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? { public func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -168,13 +180,19 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
} }
@nonobjc @nonobjc
public func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? { public func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) -> Int? {
return self.fetchCount(clauseChain.from, clauseChain.fetchClauses)
}
@nonobjc
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses) return self.fetchObjectID(from, fetchClauses)
} }
@nonobjc @nonobjc
public func fetchObjectID<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? { public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -190,14 +208,21 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
return self.fetchObjectID(fetchRequest.dynamicCast()) return self.fetchObjectID(fetchRequest.dynamicCast())
} }
// TODO: docs
@nonobjc @nonobjc
public func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? { public func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) -> NSManagedObjectID? {
return self.fetchObjectID(clauseChain.from, clauseChain.fetchClauses)
}
@nonobjc
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses) return self.fetchObjectIDs(from, fetchClauses)
} }
@nonobjc @nonobjc
public func fetchObjectIDs<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -213,6 +238,13 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
return self.fetchObjectIDs(fetchRequest.dynamicCast()) return self.fetchObjectIDs(fetchRequest.dynamicCast())
} }
// TODO: docs
@nonobjc
public func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(clauseChain.from, clauseChain.fetchClauses)
}
@nonobjc @nonobjc
internal func fetchObjectIDs(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> [NSManagedObjectID]? { internal func fetchObjectIDs(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> [NSManagedObjectID]? {
@@ -244,45 +276,50 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
// MARK: QueryableSource // MARK: QueryableSource
@nonobjc @nonobjc
public func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? { public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U? {
return self.queryValue(from, selectClause, queryClauses) return self.queryValue(from, selectClause, queryClauses)
} }
@nonobjc @nonobjc
public func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? { public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
let selectTerms = selectClause.selectTerms selectClause.applyToFetchRequest(fetchRequest)
selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) } queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else { guard storeFound else {
return nil return nil
} }
return self.queryValue(selectTerms, fetchRequest: fetchRequest) return self.queryValue(selectClause.selectTerms, fetchRequest: fetchRequest)
} }
@nonobjc @nonobjc
public func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? { public func queryValue<B>(_ clauseChain: B) -> B.ResultType? where B: QueryChainableBuilderType, B.ResultType: QueryableAttributeType {
return self.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
@nonobjc
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.queryAttributes(from, selectClause, queryClauses) return self.queryAttributes(from, selectClause, queryClauses)
} }
@nonobjc @nonobjc
public func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? { public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
selectClause.selectTerms.applyToFetchRequest(fetchRequest, owner: selectClause) selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) } queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else { guard storeFound else {
@@ -292,6 +329,11 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
return self.queryAttributes(fetchRequest) return self.queryAttributes(fetchRequest)
} }
public func queryAttributes<B>(_ clauseChain: B) -> [[String : Any]]? where B : QueryChainableBuilderType, B.ResultType == NSDictionary {
return self.queryAttributes(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
}
// MARK: FetchableSource, QueryableSource // MARK: FetchableSource, QueryableSource
@@ -305,13 +347,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
// MARK: Deleting // MARK: Deleting
@nonobjc @nonobjc
internal func deleteAll<T>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? { internal func deleteAll<D>(_ from: From<D>, _ deleteClauses: [FetchClause]) -> Int? {
return self.deleteAll(from, deleteClauses)
}
@nonobjc
internal func deleteAll<T>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self) let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -347,9 +383,9 @@ internal extension NSManagedObjectContext {
// MARK: Fetching // MARK: Fetching
@nonobjc @nonobjc
internal func fetchOne<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> T? { internal func fetchOne<D: NSManagedObject>(_ fetchRequest: NSFetchRequest<D>) -> D? {
var fetchResults: [T]? var fetchResults: [D]?
var fetchError: Error? var fetchError: Error?
self.performAndWait { self.performAndWait {
@@ -374,9 +410,9 @@ internal extension NSManagedObjectContext {
} }
@nonobjc @nonobjc
internal func fetchAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> [T]? { internal func fetchAll<D: NSManagedObject>(_ fetchRequest: NSFetchRequest<D>) -> [D]? {
var fetchResults: [T]? var fetchResults: [D]?
var fetchError: Error? var fetchError: Error?
self.performAndWait { self.performAndWait {
@@ -458,7 +494,7 @@ internal extension NSManagedObjectContext {
// MARK: Querying // MARK: Querying
@nonobjc @nonobjc
internal func queryValue<U: QueryableAttributeType>(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> U? { internal func queryValue<D, U: QueryableAttributeType>(_ selectTerms: [SelectTerm<D>], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> U? {
var fetchResults: [Any]? var fetchResults: [Any]?
var fetchError: Error? var fetchError: Error?
@@ -476,9 +512,9 @@ internal extension NSManagedObjectContext {
if let fetchResults = fetchResults { if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary, if let rawResult = fetchResults.first as? NSDictionary,
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] as? U.QueryableNativeType { let rawObject = rawResult[selectTerms.first!.keyPathString] as? U.QueryableNativeType {
return Select<U>.ReturnType.cs_fromQueryableNativeType(rawObject) return Select<D, U>.ReturnType.cs_fromQueryableNativeType(rawObject)
} }
return nil return nil
} }
@@ -491,7 +527,7 @@ internal extension NSManagedObjectContext {
} }
@nonobjc @nonobjc
internal func queryValue(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Any? { internal func queryValue<D>(_ selectTerms: [SelectTerm<D>], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Any? {
var fetchResults: [Any]? var fetchResults: [Any]?
var fetchError: Error? var fetchError: Error?
@@ -509,7 +545,7 @@ internal extension NSManagedObjectContext {
if let fetchResults = fetchResults { if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary, if let rawResult = fetchResults.first as? NSDictionary,
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] { let rawObject = rawResult[selectTerms.first!.keyPathString] {
return rawObject return rawObject
} }
@@ -541,7 +577,7 @@ internal extension NSManagedObjectContext {
} }
if let fetchResults = fetchResults { if let fetchResults = fetchResults {
return Select<NSDictionary>.ReturnType.cs_fromQueryResultsNativeType(fetchResults) return NSDictionary.cs_fromQueryResultsNativeType(fetchResults)
} }
CoreStore.log( CoreStore.log(
@@ -555,7 +591,7 @@ internal extension NSManagedObjectContext {
// MARK: Deleting // MARK: Deleting
@nonobjc @nonobjc
internal func deleteAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> Int? { internal func deleteAll<D: NSManagedObject>(_ fetchRequest: NSFetchRequest<D>) -> Int? {
var numberOfDeletedObjects: Int? var numberOfDeletedObjects: Int?
var fetchError: Error? var fetchError: Error?
@@ -179,7 +179,7 @@ internal extension NSManagedObjectContext {
} }
@nonobjc @nonobjc
internal func saveAsynchronouslyWithCompletion(_ completion: @escaping (_ hasChanges: Bool, _ error: CoreStoreError?) -> Void = { _ in }) { internal func saveAsynchronouslyWithCompletion(_ completion: @escaping (_ hasChanges: Bool, _ error: CoreStoreError?) -> Void = { (_, _) in }) {
self.perform { self.perform {
+1 -1
View File
@@ -273,7 +273,7 @@ public final class ObjectMonitor<D: DynamicObject>: Equatable {
context: context, context: context,
fetchRequest: fetchRequest.dynamicCast(), fetchRequest: fetchRequest.dynamicCast(),
from: From<ObjectType>([objectID.persistentStore?.configurationName]), from: From<ObjectType>([objectID.persistentStore?.configurationName]),
applyFetchClauses: Where("SELF", isEqualTo: objectID).applyToFetchRequest applyFetchClauses: Where<ObjectType>("SELF", isEqualTo: objectID).applyToFetchRequest
) )
let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate() let fetchedResultsControllerDelegate = FetchedResultsControllerDelegate()
+2 -2
View File
@@ -61,7 +61,7 @@ public protocol ObjectObserver: class {
- parameter object: the `DynamicObject` instance being observed - parameter object: the `DynamicObject` instance being observed
- parameter changedPersistentKeys: a `Set` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported. - parameter changedPersistentKeys: a `Set` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported.
*/ */
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<RawKeyPath>) func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<KeyPathString>)
/** /**
Handles processing right after `object` is deleted. (Optional) Handles processing right after `object` is deleted. (Optional)
@@ -81,7 +81,7 @@ public extension ObjectObserver {
public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, willUpdateObject object: ObjectEntityType) { } public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, willUpdateObject object: ObjectEntityType) { }
public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<RawKeyPath>) { } public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<KeyPathString>) { }
public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didDeleteObject object: ObjectEntityType) { } public func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didDeleteObject object: ObjectEntityType) { }
} }
+169 -63
View File
@@ -27,46 +27,12 @@ import Foundation
import CoreData import CoreData
// MARK: - RawKeyPath
public typealias RawKeyPath = String
// MARK: - SortKey
/**
The `SortKey` is passed to the `OrderBy` clause to indicate the sort keys and their sort direction.
*/
public enum SortKey {
/**
Indicates that the `RawKeyPath` should be sorted in ascending order
*/
case ascending(RawKeyPath)
/**
Indicates that the `RawKeyPath` should be sorted in descending order
*/
case descending(RawKeyPath)
/**
Indicates that the `RawKeyPath` should be sorted in ascending order in a case-insenstive manner
*/
case ascendingInsensitive(RawKeyPath)
/**
Indicates that the `RawKeyPath` should be sorted in descending order in a case-insenstive manner
*/
case descendingInsensitive(RawKeyPath)
}
// MARK: - OrderBy // MARK: - OrderBy
/** /**
The `OrderBy` clause specifies the sort order for results for a fetch or a query. The `OrderBy` clause specifies the sort order for results for a fetch or a query.
*/ */
public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable { public struct OrderBy<D: DynamicObject>: OrderByClause, FetchClause, QueryClause, DeleteClause, Hashable {
/** /**
Combines two `OrderBy` sort descriptors together Combines two `OrderBy` sort descriptors together
@@ -84,11 +50,6 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
left = left + right left = left + right
} }
/**
The list of sort descriptors
*/
public let sortDescriptors: [NSSortDescriptor]
/** /**
Initializes a `OrderBy` clause with an empty list of sort descriptors Initializes a `OrderBy` clause with an empty list of sort descriptors
*/ */
@@ -122,27 +83,9 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter sortKey: a series of `SortKey`s - parameter sortKey: a series of `SortKey`s
*/ */
public init(_ sortKey: [SortKey]) { public init(_ sortKeys: [SortKey]) {
self.init( self.init(sortKeys.map({ $0.descriptor }))
sortKey.map { sortKey -> NSSortDescriptor in
switch sortKey {
case .ascending(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: true)
case .descending(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: false)
case .ascendingInsensitive(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
case .descendingInsensitive(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: false, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
}
}
)
} }
/** /**
@@ -157,6 +100,13 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
} }
// MARK: OrderByClause
public typealias ObjectType = D
public let sortDescriptors: [NSSortDescriptor]
// MARK: FetchClause, QueryClause, DeleteClause // MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest<ResultType>(_ fetchRequest: NSFetchRequest<ResultType>) { public func applyToFetchRequest<ResultType>(_ fetchRequest: NSFetchRequest<ResultType>) {
@@ -187,17 +137,173 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
return (self.sortDescriptors as NSArray).hashValue return (self.sortDescriptors as NSArray).hashValue
} }
// MARK: - SortKey
/**
The `SortKey` is passed to the `OrderBy` clause to indicate the sort keys and their sort direction.
*/
public struct SortKey {
// MARK: Raw Key Paths
/**
Indicates that the `KeyPathString` should be sorted in ascending order
*/
public static func ascending(_ keyPath: KeyPathString) -> SortKey {
return SortKey(descriptor: .init(key: keyPath, ascending: true))
}
/**
Indicates that the `KeyPathString` should be sorted in descending order
*/
public static func descending(_ keyPath: KeyPathString) -> SortKey {
return SortKey(descriptor: .init(key: keyPath, ascending: false))
} }
// MARK: - Sequence where Element == OrderBy // MARK: NSManagedObject Key Paths
public extension Sequence where Iterator.Element == OrderBy { /**
Indicates that the `KeyPathString` should be sorted in ascending order
*/
public static func ascending<T>(_ keyPath: KeyPath<D, T>) -> SortKey where D: NSManagedObject {
return .ascending(keyPath._kvcKeyPathString!)
}
/**
Indicates that the `KeyPathString` should be sorted in descending order
*/
public static func descending<T>(_ keyPath: KeyPath<D, T>) -> SortKey where D: NSManagedObject {
return .descending(keyPath._kvcKeyPathString!)
}
// MARK: CoreStoreObject Key Paths
/**
Indicates that the `KeyPathString` should be sorted in ascending order
*/
public static func ascending<T>(_ attribute: KeyPath<D, ValueContainer<D>.Required<T>>) -> SortKey {
return .ascending(D.meta[keyPath: attribute].keyPath)
}
/**
Indicates that the `KeyPathString` should be sorted in ascending order
*/
public static func ascending<T>(_ attribute: KeyPath<D, ValueContainer<D>.Optional<T>>) -> SortKey {
return .ascending(D.meta[keyPath: attribute].keyPath)
}
/**
Indicates that the `KeyPathString` should be sorted in ascending order
*/
public static func ascending<T>(_ attribute: KeyPath<D, TransformableContainer<D>.Required<T>>) -> SortKey {
return .ascending(D.meta[keyPath: attribute].keyPath)
}
/**
Indicates that the `KeyPathString` should be sorted in ascending order
*/
public static func ascending<T>(_ attribute: KeyPath<D, TransformableContainer<D>.Optional<T>>) -> SortKey {
return .ascending(D.meta[keyPath: attribute].keyPath)
}
/**
Indicates that the `KeyPathString` should be sorted in descending order
*/
public static func descending<T>(_ attribute: KeyPath<D, ValueContainer<D>.Required<T>>) -> SortKey {
return .descending(D.meta[keyPath: attribute].keyPath)
}
/**
Indicates that the `KeyPathString` should be sorted in descending order
*/
public static func descending<T>(_ attribute: KeyPath<D, ValueContainer<D>.Optional<T>>) -> SortKey {
return .descending(D.meta[keyPath: attribute].keyPath)
}
/**
Indicates that the `KeyPathString` should be sorted in descending order
*/
public static func descending<T>(_ attribute: KeyPath<D, TransformableContainer<D>.Required<T>>) -> SortKey {
return .descending(D.meta[keyPath: attribute].keyPath)
}
/**
Indicates that the `KeyPathString` should be sorted in descending order
*/
public static func descending<T>(_ attribute: KeyPath<D, TransformableContainer<D>.Optional<T>>) -> SortKey {
return .descending(D.meta[keyPath: attribute].keyPath)
}
// MARK: Private
fileprivate let descriptor: NSSortDescriptor
}
}
public extension OrderBy.SortKey where D: CoreStoreObject {
/**
Indicates that the `KeyPathString` should be sorted in ascending order
*/
public static func ascending<K: DynamicKeyPath>(_ attribute: (D) -> K) -> OrderBy<D>.SortKey {
return .ascending(attribute(D.meta).cs_keyPathString)
}
/**
Indicates that the `KeyPathString` should be sorted in descending order
*/
public static func descending<K: DynamicKeyPath>(_ attribute: (D) -> K) -> OrderBy<D>.SortKey {
return .descending(attribute(D.meta).cs_keyPathString)
}
}
// MARK: - OrderByClause
/**
Abstracts the `OrderBy` clause for protocol utilities.
*/
public protocol OrderByClause {
/**
The `DynamicObject` type associated with the clause
*/
associatedtype ObjectType: DynamicObject
/**
The `NSSortDescriptor` array for the fetch or query
*/
var sortDescriptors: [NSSortDescriptor] { get }
}
// MARK: - Sequence where Iterator.Element: OrderByClause
public extension Sequence where Iterator.Element: OrderByClause {
/** /**
Combines multiple `OrderBy` predicates together Combines multiple `OrderBy` predicates together
*/ */
public func combined() -> OrderBy { public func combined() -> OrderBy<Iterator.Element.ObjectType> {
return OrderBy(self.flatMap({ $0.sortDescriptors })) return OrderBy(self.flatMap({ $0.sortDescriptors }))
} }
+86
View File
@@ -0,0 +1,86 @@
//
// QueryChainBuilder.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - QueryChainBuilder
/**
The fetch builder type used for a queries. A `QueryChainBuilder` is created from a `From` clause and then a `select(...)` chain.
```
let averageAdultAge = dataStack.queryValue(
From<MyPersonEntity>()
.select(Int.self, .average(\.age))
.where(\.age > 18)
)
```
*/
public struct QueryChainBuilder<D: DynamicObject, R: SelectResultType>: QueryChainableBuilderType {
// MARK: QueryChainableBuilderType
public typealias ObjectType = D
public typealias ResultType = R
public var from: From<D>
public var select: Select<D, R>
public var queryClauses: [QueryClause] = []
}
// MARK: - QueryChainableBuilderType
/**
Utility protocol for `QueryChainBuilder`. Used in fetch methods that support chained query builders.
*/
public protocol QueryChainableBuilderType {
/**
The `DynamicObject` type for the query
*/
associatedtype ObjectType: DynamicObject
/**
The `SelectResultType` type for the query
*/
associatedtype ResultType: SelectResultType
/**
The `From` clause specifies the source entity and source persistent store for the query
*/
var from: From<ObjectType> { get set }
/**
The `Select` clause to be used for the query
*/
var select: Select<ObjectType, ResultType> { get set }
/**
The `QueryClause`s to be used for the query
*/
var queryClauses: [QueryClause] { get set }
}
+8
View File
@@ -342,6 +342,7 @@ extension NSData: QueryableAttributeType {
public typealias QueryableNativeType = NSData public typealias QueryableNativeType = NSData
@nonobjc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .binaryDataAttributeType return .binaryDataAttributeType
@@ -371,6 +372,7 @@ extension NSDate: QueryableAttributeType {
public typealias QueryableNativeType = NSDate public typealias QueryableNativeType = NSDate
@nonobjc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .dateAttributeType return .dateAttributeType
@@ -411,6 +413,7 @@ extension NSManagedObjectID: QueryableAttributeType {
public typealias QueryableNativeType = NSManagedObjectID public typealias QueryableNativeType = NSManagedObjectID
@nonobjc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .objectIDAttributeType return .objectIDAttributeType
@@ -440,6 +443,7 @@ extension NSNull: QueryableAttributeType {
public typealias QueryableNativeType = NSNull public typealias QueryableNativeType = NSNull
@nonobjc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .undefinedAttributeType return .undefinedAttributeType
@@ -469,6 +473,7 @@ extension NSNumber: QueryableAttributeType {
public typealias QueryableNativeType = NSNumber public typealias QueryableNativeType = NSNumber
@objc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .integer64AttributeType return .integer64AttributeType
@@ -498,6 +503,7 @@ extension NSString: QueryableAttributeType {
public typealias QueryableNativeType = NSString public typealias QueryableNativeType = NSString
@nonobjc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .stringAttributeType return .stringAttributeType
@@ -527,6 +533,7 @@ extension NSURL: QueryableAttributeType {
public typealias QueryableNativeType = NSString public typealias QueryableNativeType = NSString
@nonobjc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .stringAttributeType return .stringAttributeType
@@ -552,6 +559,7 @@ extension NSUUID: QueryableAttributeType {
public typealias QueryableNativeType = NSString public typealias QueryableNativeType = NSString
@nonobjc
public class var cs_rawAttributeType: NSAttributeType { public class var cs_rawAttributeType: NSAttributeType {
return .stringAttributeType return .stringAttributeType
+45 -4
View File
@@ -44,7 +44,7 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) -> U?
/** /**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -56,7 +56,23 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
func queryValue<T, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) -> U?
/**
Queries a property value or aggregate as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let averageAdultAge = dataStack.queryValue(
From<MyPersonEntity>()
.select(Int.self, .average(\.age))
.where(\.age > 18)
)
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the property/aggregate to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) -> B.ResultType? where B.ResultType: QueryableAttributeType
/** /**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -68,7 +84,7 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]?
/** /**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -80,7 +96,32 @@ public protocol QueryableSource: class {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses. - parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter. - returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/ */
func queryAttributes<T>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]?
/**
Queries a dictionary of attribute values or as specified by the `QueryChainableBuilderType` built from a chain of clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
```
let results = source.queryAttributes(
From<MyPersonEntity>()
.select(
NSDictionary.self,
.attribute(\.age, as: "age"),
.count(\.age, as: "numberOfPeople")
)
.groupBy(\.age)
)
for dictionary in results! {
let age = dictionary["age"] as! Int
let count = dictionary["numberOfPeople"] as! Int
print("There are \(count) people who are \(age) years old."
}
```
- parameter clauseChain: a `QueryChainableBuilderType` indicating the properties to fetch and the series of queries for the request.
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
*/
func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) -> [[String: Any]]? where B.ResultType == NSDictionary
/** /**
The internal `NSManagedObjectContext` managed by this `QueryableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases. The internal `NSManagedObjectContext` managed by this `QueryableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
+20 -23
View File
@@ -95,7 +95,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
versionHashModifier: @autoclosure @escaping () -> String? = nil, versionHashModifier: @autoclosure @escaping () -> String? = nil,
renamingIdentifier: @autoclosure @escaping () -> String? = nil, renamingIdentifier: @autoclosure @escaping () -> String? = nil,
@@ -129,7 +129,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
versionHashModifier: @autoclosure @escaping () -> String? = nil, versionHashModifier: @autoclosure @escaping () -> String? = nil,
@@ -164,7 +164,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
versionHashModifier: @autoclosure @escaping () -> String? = nil, versionHashModifier: @autoclosure @escaping () -> String? = nil,
@@ -199,7 +199,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
versionHashModifier: @autoclosure @escaping () -> String? = nil, versionHashModifier: @autoclosure @escaping () -> String? = nil,
@@ -234,14 +234,13 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: RelationshipProtocol // MARK: RelationshipProtocol
public let keyPath: RawKeyPath internal let keyPath: KeyPathString
internal let isToMany = false internal let isToMany = false
internal let isOrdered = false internal let isOrdered = false
internal let deleteRule: NSDeleteRule internal let deleteRule: NSDeleteRule
internal let minCount: Int = 0 internal let minCount: Int = 0
internal let maxCount: Int = 1 internal let maxCount: Int = 1
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> RawKeyPath?) internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?)
internal let versionHashModifier: () -> String? internal let versionHashModifier: () -> String?
internal let renamingIdentifier: () -> String? internal let renamingIdentifier: () -> String?
internal let affectedByKeyPaths: () -> Set<String> internal let affectedByKeyPaths: () -> Set<String>
@@ -294,7 +293,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: Private // MARK: Private
private init(keyPath: RawKeyPath, inverseKeyPath: @escaping () -> RawKeyPath?, deleteRule: DeleteRule, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) { private init(keyPath: KeyPathString, inverseKeyPath: @escaping () -> KeyPathString?, deleteRule: DeleteRule, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
self.keyPath = keyPath self.keyPath = keyPath
self.deleteRule = deleteRule.nativeValue self.deleteRule = deleteRule.nativeValue
@@ -341,7 +340,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
minCount: Int = 0, minCount: Int = 0,
maxCount: Int = 0, maxCount: Int = 0,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
@@ -381,7 +380,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
minCount: Int = 0, minCount: Int = 0,
maxCount: Int = 0, maxCount: Int = 0,
inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>,
@@ -422,7 +421,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
minCount: Int = 0, minCount: Int = 0,
maxCount: Int = 0, maxCount: Int = 0,
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>,
@@ -463,7 +462,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
minCount: Int = 0, minCount: Int = 0,
maxCount: Int = 0, maxCount: Int = 0,
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>,
@@ -502,15 +501,14 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: RelationshipProtocol // MARK: RelationshipProtocol
public let keyPath: RawKeyPath internal let keyPath: KeyPathString
internal let isToMany = true internal let isToMany = true
internal let isOptional = true internal let isOptional = true
internal let isOrdered = true internal let isOrdered = true
internal let deleteRule: NSDeleteRule internal let deleteRule: NSDeleteRule
internal let minCount: Int internal let minCount: Int
internal let maxCount: Int internal let maxCount: Int
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> RawKeyPath?) internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?)
internal let versionHashModifier: () -> String? internal let versionHashModifier: () -> String?
internal let renamingIdentifier: () -> String? internal let renamingIdentifier: () -> String?
internal let affectedByKeyPaths: () -> Set<String> internal let affectedByKeyPaths: () -> Set<String>
@@ -615,7 +613,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
minCount: Int = 0, minCount: Int = 0,
maxCount: Int = 0, maxCount: Int = 0,
@@ -655,7 +653,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
minCount: Int = 0, minCount: Int = 0,
@@ -696,7 +694,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
minCount: Int = 0, minCount: Int = 0,
@@ -737,7 +735,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>,
deleteRule: DeleteRule = .nullify, deleteRule: DeleteRule = .nullify,
minCount: Int = 0, minCount: Int = 0,
@@ -776,15 +774,14 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: RelationshipProtocol // MARK: RelationshipProtocol
public let keyPath: RawKeyPath internal let keyPath: KeyPathString
internal let isToMany = true internal let isToMany = true
internal let isOptional = true internal let isOptional = true
internal let isOrdered = false internal let isOrdered = false
internal let deleteRule: NSDeleteRule internal let deleteRule: NSDeleteRule
internal let minCount: Int internal let minCount: Int
internal let maxCount: Int internal let maxCount: Int
internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> RawKeyPath?) internal let inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?)
internal let versionHashModifier: () -> String? internal let versionHashModifier: () -> String?
internal let renamingIdentifier: () -> String? internal let renamingIdentifier: () -> String?
internal let affectedByKeyPaths: () -> Set<String> internal let affectedByKeyPaths: () -> Set<String>
@@ -837,7 +834,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: Private // MARK: Private
private init(keyPath: RawKeyPath, inverseKeyPath: @escaping () -> RawKeyPath?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) { private init(keyPath: KeyPathString, inverseKeyPath: @escaping () -> KeyPathString?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: @autoclosure @escaping () -> String?, renamingIdentifier: @autoclosure @escaping () -> String?, affectedByKeyPaths: @autoclosure @escaping () -> Set<String>) {
self.keyPath = keyPath self.keyPath = keyPath
self.deleteRule = deleteRule.nativeValue self.deleteRule = deleteRule.nativeValue
+2 -2
View File
@@ -31,11 +31,11 @@ import CoreData
internal protocol RelationshipProtocol: class { internal protocol RelationshipProtocol: class {
var keyPath: RawKeyPath { get } var keyPath: KeyPathString { get }
var isToMany: Bool { get } var isToMany: Bool { get }
var isOrdered: Bool { get } var isOrdered: Bool { get }
var deleteRule: NSDeleteRule { get } var deleteRule: NSDeleteRule { get }
var inverse: (type: CoreStoreObject.Type, keyPath: () -> RawKeyPath?) { get } var inverse: (type: CoreStoreObject.Type, keyPath: () -> KeyPathString?) { get }
var affectedByKeyPaths: () -> Set<String> { get } var affectedByKeyPaths: () -> Set<String> { get }
weak var parentObject: CoreStoreObject? { get set } weak var parentObject: CoreStoreObject? { get set }
var versionHashModifier: () -> String? { get } var versionHashModifier: () -> String? { get }
+1
View File
@@ -219,6 +219,7 @@ public final class SQLiteStore: LocalStorage {
options: [NSSQLitePragmasOption: ["journal_mode": "DELETE"]] options: [NSSQLitePragmasOption: ["journal_mode": "DELETE"]]
) )
} }
_ = try? FileManager.default.removeItem(atPath: "\(self.fileURL.path)-shm")
} }
/** /**
+122 -4
View File
@@ -40,14 +40,14 @@ import CoreData
``` ```
*/ */
@available(OSX 10.12, *) @available(OSX 10.12, *)
public struct SectionBy { public struct SectionBy<D: DynamicObject> {
/** /**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the key path to use to group the objects into sections - parameter sectionKeyPath: the key path to use to group the objects into sections
*/ */
public init(_ sectionKeyPath: RawKeyPath) { public init(_ sectionKeyPath: KeyPathString) {
self.init(sectionKeyPath, { $0 }) self.init(sectionKeyPath, { $0 })
} }
@@ -59,7 +59,7 @@ public struct SectionBy {
- parameter sectionKeyPath: the key path to use to group the objects into sections - parameter sectionKeyPath: the key path to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name - parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
*/ */
public init(_ sectionKeyPath: RawKeyPath, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) { public init(_ sectionKeyPath: KeyPathString, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) {
self.sectionKeyPath = sectionKeyPath self.sectionKeyPath = sectionKeyPath
self.sectionIndexTransformer = sectionIndexTransformer self.sectionIndexTransformer = sectionIndexTransformer
@@ -68,6 +68,124 @@ public struct SectionBy {
// MARK: Internal // MARK: Internal
internal let sectionKeyPath: RawKeyPath internal let sectionKeyPath: KeyPathString
internal let sectionIndexTransformer: (_ sectionName: String?) -> String? internal let sectionIndexTransformer: (_ sectionName: String?) -> String?
} }
@available(OSX 10.12, *)
public extension SectionBy where D: NSManagedObject {
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the key path to use to group the objects into sections
*/
public init<T>(_ sectionKeyPath: KeyPath<D, T>) {
self.init(sectionKeyPath, { $0 })
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the key path to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
*/
public init<T>(_ sectionKeyPath: KeyPath<D, T>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) {
self.init(sectionKeyPath._kvcKeyPathString!, sectionIndexTransformer)
}
}
@available(OSX 10.12, *)
public extension SectionBy where D: CoreStoreObject {
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the key path to use to group the objects into sections
*/
public init<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Required<T>>) {
self.init(sectionKeyPath, { $0 })
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the key path to use to group the objects into sections
*/
public init<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) {
self.init(sectionKeyPath, { $0 })
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the key path to use to group the objects into sections
*/
public init<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) {
self.init(sectionKeyPath, { $0 })
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections
- parameter sectionKeyPath: the key path to use to group the objects into sections
*/
public init<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) {
self.init(sectionKeyPath, { $0 })
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the key path to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
*/
public init<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Required<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) {
self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the key path to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
*/
public init<T>(_ sectionKeyPath: KeyPath<D, ValueContainer<D>.Optional<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) {
self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the key path to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
*/
public init<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Required<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) {
self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
/**
Initializes a `SectionBy` clause with the key path to use to group `ListMonitor` objects into sections, and a closure to transform the value for the key path to an appropriate section name
- Important: Some utilities (such as `ListMonitor`s) may keep `SectionBy`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter sectionKeyPath: the key path to use to group the objects into sections
- parameter sectionIndexTransformer: a closure to transform the value for the key path to an appropriate section name
*/
public init<T>(_ sectionKeyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>, _ sectionIndexTransformer: @escaping (_ sectionName: String?) -> String?) {
self.init(D.meta[keyPath: sectionKeyPath].keyPath, sectionIndexTransformer)
}
}
+81
View File
@@ -0,0 +1,81 @@
//
// SectionMonitorBuilder.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - SectionMonitorChainBuilder
/**
The fetch builder type used for a sectioned `ListMonitor`. A `SectionMonitorChainBuilder` is created from a `From` clause and then a `sectionBy(...)` chain.
```
let monitor = transaction.monitorSectionedList(
From<MyPersonEntity>()
.sectionBy(\.age, { "\($0!) years old" })
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
*/
@available(OSX 10.12, *)
public struct SectionMonitorChainBuilder<D: DynamicObject>: SectionMonitorBuilderType {
// MARK: SectionMonitorBuilderType
public var from: From<D>
public var sectionBy: SectionBy<D>
public var fetchClauses: [FetchClause] = []
}
// MARK: - SectionMonitorBuilderType
/**
Utility protocol for `SectionMonitorChainBuilder`. Used in methods that support chained fetch builders.
*/
@available(OSX 10.12, *)
public protocol SectionMonitorBuilderType {
/**
The `DynamicObject` type for the `ListMonitor`
*/
associatedtype ObjectType: DynamicObject
/**
The `From` clause specifies the source entity and source persistent store for the `ListMonitor`
*/
var from: From<ObjectType> { get set }
/**
The `SectionBy` clause to be used for the `ListMonitor`
*/
var sectionBy: SectionBy<ObjectType> { get set }
/**
The `FetchClause`s to be used for the `ListMonitor`
*/
var fetchClauses: [FetchClause] { get set }
}
+478 -66
View File
@@ -52,7 +52,7 @@ public protocol SelectAttributesResultType: SelectResultType {
/** /**
The `SelectTerm` is passed to the `Select` clause to indicate the attributes/aggregate keys to be queried. The `SelectTerm` is passed to the `Select` clause to indicate the attributes/aggregate keys to be queried.
*/ */
public enum SelectTerm: ExpressibleByStringLiteral, Hashable { public enum SelectTerm<D: DynamicObject>: ExpressibleByStringLiteral, Hashable {
/** /**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute. A shorter way to do the same is to assign from the string keypath directly: Provides a `SelectTerm` to a `Select` clause for querying an entity attribute. A shorter way to do the same is to assign from the string keypath directly:
@@ -74,7 +74,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- 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(_ keyPath: RawKeyPath) -> SelectTerm { public static func attribute(_ keyPath: KeyPathString) -> SelectTerm<D> {
return ._attribute(keyPath) return ._attribute(keyPath)
} }
@@ -91,7 +91,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- 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(_ keyPath: RawKeyPath, as alias: RawKeyPath? = nil) -> SelectTerm { public static func average(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate( return ._aggregate(
function: "average:", function: "average:",
@@ -113,7 +113,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- 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(_ keyPath: RawKeyPath, as alias: RawKeyPath? = nil) -> SelectTerm { public static func count(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate( return ._aggregate(
function: "count:", function: "count:",
@@ -135,7 +135,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- 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(_ keyPath: RawKeyPath, as alias: RawKeyPath? = nil) -> SelectTerm { public static func maximum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate( return ._aggregate(
function: "max:", function: "max:",
@@ -157,7 +157,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- 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(_ keyPath: RawKeyPath, as alias: RawKeyPath? = nil) -> SelectTerm { public static func minimum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate( return ._aggregate(
function: "min:", function: "min:",
@@ -179,7 +179,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- 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(_ keyPath: RawKeyPath, as alias: RawKeyPath? = nil) -> SelectTerm { public static func sum(_ keyPath: KeyPathString, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._aggregate( return ._aggregate(
function: "sum:", function: "sum:",
@@ -202,7 +202,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- 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 "objecID" 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 "objecID" 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 objectID(as alias: RawKeyPath? = nil) -> SelectTerm { public static func objectID(as alias: KeyPathString? = nil) -> SelectTerm<D> {
return ._identity( return ._identity(
alias: alias ?? "objectID", alias: alias ?? "objectID",
@@ -213,17 +213,17 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
// MARK: ExpressibleByStringLiteral // MARK: ExpressibleByStringLiteral
public init(stringLiteral value: RawKeyPath) { public init(stringLiteral value: KeyPathString) {
self = ._attribute(value) self = ._attribute(value)
} }
public init(unicodeScalarLiteral value: RawKeyPath) { public init(unicodeScalarLiteral value: KeyPathString) {
self = ._attribute(value) self = ._attribute(value)
} }
public init(extendedGraphemeClusterLiteral value: RawKeyPath) { public init(extendedGraphemeClusterLiteral value: KeyPathString) {
self = ._attribute(value) self = ._attribute(value)
} }
@@ -231,7 +231,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
// MARK: Equatable // MARK: Equatable
public static func == (lhs: SelectTerm, rhs: SelectTerm) -> Bool { public static func == (lhs: SelectTerm<D>, rhs: SelectTerm<D>) -> Bool {
switch (lhs, rhs) { switch (lhs, rhs) {
@@ -248,7 +248,9 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
case (._identity(let alias1, let nativeType1), ._identity(let alias2, let nativeType2)): case (._identity(let alias1, let nativeType1), ._identity(let alias2, let nativeType2)):
return alias1 == alias2 && nativeType1 == nativeType2 return alias1 == alias2 && nativeType1 == nativeType2
default: case (._attribute, _),
(._aggregate, _),
(._identity, _):
return false return false
} }
} }
@@ -274,9 +276,358 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
// MARK: Internal // MARK: Internal
case _attribute(RawKeyPath) case _attribute(KeyPathString)
case _aggregate(function: String, keyPath: RawKeyPath, alias: String, nativeType: NSAttributeType) case _aggregate(function: String, keyPath: KeyPathString, alias: String, nativeType: NSAttributeType)
case _identity(alias: String, nativeType: NSAttributeType) case _identity(alias: String, nativeType: NSAttributeType)
internal var keyPathString: String {
switch self {
case ._attribute(let keyPath): return keyPath
case ._aggregate(_, _, let alias, _): return alias
case ._identity(let alias, _): return alias
}
}
}
extension SelectTerm where D: NSManagedObject {
/**
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<D, V>) -> SelectTerm<D> {
return self.attribute(keyPath._kvcKeyPathString!)
}
/**
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<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(keyPath._kvcKeyPathString!, 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<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(keyPath._kvcKeyPathString!, 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<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(keyPath._kvcKeyPathString!, 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<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(keyPath._kvcKeyPathString!, 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<D, V>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(keyPath._kvcKeyPathString!, as: alias)
}
}
extension SelectTerm where D: CoreStoreObject {
/**
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<D, ValueContainer<D>.Required<V>>) -> SelectTerm<D> {
return self.attribute(D.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<D, ValueContainer<D>.Optional<V>>) -> SelectTerm<D> {
return self.attribute(D.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<D, TransformableContainer<D>.Required<V>>) -> SelectTerm<D> {
return self.attribute(D.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<D, TransformableContainer<D>.Optional<V>>) -> SelectTerm<D> {
return self.attribute(D.meta[keyPath: keyPath].keyPath)
}
/**
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<D, ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.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<D, ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.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<D, TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.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<D, TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.average(D.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<D,
ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.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<D,
ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.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<D,
TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.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<D,
TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.count(D.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<D,
ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.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<D,
ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.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<D,
TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.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<D,
TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.maximum(D.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<D, ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.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<D, ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.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<D, TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.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<D, TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.minimum(D.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<D, ValueContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.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<D, ValueContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.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<D, TransformableContainer<D>.Required<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.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<D, TransformableContainer<D>.Optional<V>>, as alias: KeyPathString? = nil) -> SelectTerm<D> {
return self.sum(D.meta[keyPath: keyPath].keyPath, as: alias)
}
} }
@@ -308,12 +659,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- parameter sortDescriptors: a series of `NSSortDescriptor`s - parameter sortDescriptors: a series of `NSSortDescriptor`s
*/ */
public struct Select<T: SelectResultType>: Hashable { public struct Select<D: DynamicObject, T: SelectResultType>: SelectClause, Hashable {
/**
The `SelectResultType` type for the query's return value
*/
public typealias ReturnType = T
/** /**
Initializes a `Select` clause with a list of `SelectTerm`s Initializes a `Select` clause with a list of `SelectTerm`s
@@ -321,7 +667,7 @@ public struct Select<T: SelectResultType>: Hashable {
- parameter selectTerm: a `SelectTerm` - parameter selectTerm: a `SelectTerm`
- parameter selectTerms: a series of `SelectTerm`s - parameter selectTerms: a series of `SelectTerm`s
*/ */
public init(_ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) { public init(_ selectTerm: SelectTerm<D>, _ selectTerms: SelectTerm<D>...) {
self.selectTerms = [selectTerm] + selectTerms self.selectTerms = [selectTerm] + selectTerms
} }
@@ -331,7 +677,7 @@ public struct Select<T: SelectResultType>: Hashable {
- parameter selectTerms: a series of `SelectTerm`s - parameter selectTerms: a series of `SelectTerm`s
*/ */
public init(_ selectTerms: [SelectTerm]) { public init(_ selectTerms: [SelectTerm<D>]) {
self.selectTerms = selectTerms self.selectTerms = selectTerms
} }
@@ -339,12 +685,20 @@ public struct Select<T: SelectResultType>: Hashable {
// MARK: Equatable // MARK: Equatable
public static func == <T, U>(lhs: Select<T>, rhs: Select<U>) -> Bool { public static func == <T, U>(lhs: Select<D, T>, rhs: Select<D, U>) -> Bool {
return lhs.selectTerms == rhs.selectTerms return lhs.selectTerms == rhs.selectTerms
} }
// MARK: SelectClause
public typealias ObjectType = D
public typealias ReturnType = T
public let selectTerms: [SelectTerm<D>]
// MARK: Hashable // MARK: Hashable
public var hashValue: Int { public var hashValue: Int {
@@ -355,36 +709,7 @@ public struct Select<T: SelectResultType>: Hashable {
// MARK: Internal // MARK: Internal
internal let selectTerms: [SelectTerm] internal func applyToFetchRequest(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
}
public extension Select where T: NSManagedObjectID {
public init() {
self.init(.objectID())
}
}
// MARK: - NSDictionary: SelectAttributesResultType
extension NSDictionary: SelectAttributesResultType {
// MARK: SelectAttributesResultType
public static func cs_fromQueryResultsNativeType(_ result: [Any]) -> [[String : Any]] {
return result as! [[String: Any]]
}
}
// MARK: - Internal
internal extension Collection where Iterator.Element == SelectTerm {
internal func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>, owner: T) {
fetchRequest.includesPendingChanges = false fetchRequest.includesPendingChanges = false
fetchRequest.resultType = .dictionaryResultType fetchRequest.resultType = .dictionaryResultType
@@ -414,7 +739,7 @@ internal extension Collection where Iterator.Element == SelectTerm {
} }
var propertiesToFetch = [Any]() var propertiesToFetch = [Any]()
for term in self { for term in self.selectTerms {
switch term { switch term {
@@ -445,7 +770,7 @@ internal extension Collection where Iterator.Element == SelectTerm {
CoreStore.log( CoreStore.log(
.warning, .warning,
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(owner)) query clause." message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(self)) query clause."
) )
} }
@@ -468,19 +793,106 @@ internal extension Collection where Iterator.Element == SelectTerm {
fetchRequest.propertiesToFetch = propertiesToFetch fetchRequest.propertiesToFetch = propertiesToFetch
} }
}
internal func keyPathForFirstSelectTerm() -> RawKeyPath { public extension Select where T: NSManagedObjectID {
switch self.first! { /**
Initializes a `Select` that queries for `NSManagedObjectID` results
*/
public init() {
case ._attribute(let keyPath): self.init(.objectID())
return keyPath
case ._aggregate(_, _, let alias, _):
return alias
case ._identity(let alias, _):
return alias
} }
} }
public extension Select where D: NSManagedObject {
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, T>) {
self.init(.attribute(keyPath))
}
}
public extension Select where D: CoreStoreObject, T: ImportableAttributeType {
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, ValueContainer<D>.Required<T>>) {
self.init(.attribute(keyPath))
}
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<T>>) {
self.init(.attribute(keyPath))
}
}
public extension Select where D: CoreStoreObject, T: ImportableAttributeType & NSCoding & NSCopying {
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, TransformableContainer<D>.Required<T>>) {
self.init(.attribute(keyPath))
}
/**
Initializes a `Select` that queries the value of an attribute pertained by a keyPath
- parameter keyPath: the keyPath for the attribute
*/
public init(_ keyPath: KeyPath<D, TransformableContainer<D>.Optional<T>>) {
self.init(.attribute(keyPath))
}
}
// MARK: - SelectClause
/**
Abstracts the `Select` clause for protocol utilities.
*/
public protocol SelectClause {
/**
The `DynamicObject` type associated with the clause
*/
associatedtype ObjectType: DynamicObject
/**
The `SelectResultType` type associated with the clause
*/
associatedtype ReturnType: SelectResultType
/**
The `SelectTerm`s for the query
*/
var selectTerms: [SelectTerm<ObjectType>] { get }
}
// MARK: - NSDictionary: SelectAttributesResultType
extension NSDictionary: SelectAttributesResultType {
// MARK: SelectAttributesResultType
public static func cs_fromQueryResultsNativeType(_ result: [Any]) -> [[String : Any]] {
return result as! [[String: Any]]
}
} }
+5 -5
View File
@@ -55,7 +55,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration - parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type. - returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
*/ */
public override func create<T>(_ into: Into<T>) -> T { public override func create<D>(_ into: Into<D>) -> D {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -71,7 +71,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited - parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T: DynamicObject>(_ object: T?) -> T? { public override func edit<D: DynamicObject>(_ object: D?) -> D? {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -88,7 +88,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
- parameter objectID: the `NSManagedObjectID` for the object to be edited - parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? { public override func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -103,7 +103,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
- parameter object: the `NSManagedObject` or `CoreStoreObject` type to be deleted - parameter object: the `NSManagedObject` or `CoreStoreObject` type to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object: T?) { public override func delete<D: DynamicObject>(_ object: D?) {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -120,7 +120,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
- parameter object2: another `DynamicObject` to be deleted - parameter object2: another `DynamicObject` to be deleted
- parameter objects: other `DynamicObject`s to be deleted - parameter objects: other `DynamicObject`s to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) { public override func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
+6 -8
View File
@@ -116,7 +116,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public init( public init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
initial: @autoclosure @escaping () -> V, initial: @autoclosure @escaping () -> V,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
@@ -197,8 +197,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
return .transformableAttributeType return .transformableAttributeType
} }
public let keyPath: RawKeyPath internal let keyPath: KeyPathString
internal let isOptional = false internal let isOptional = false
internal let isIndexed: Bool internal let isIndexed: Bool
internal let isTransient: Bool internal let isTransient: Bool
@@ -261,7 +260,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)") @available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
`default`: @autoclosure @escaping () -> V, `default`: @autoclosure @escaping () -> V,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
@@ -339,7 +338,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public init( public init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
initial: @autoclosure @escaping () -> V? = nil, initial: @autoclosure @escaping () -> V? = nil,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
@@ -420,8 +419,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
return .transformableAttributeType return .transformableAttributeType
} }
public let keyPath: RawKeyPath internal let keyPath: KeyPathString
internal let isOptional = true internal let isOptional = true
internal let isIndexed: Bool internal let isIndexed: Bool
internal let isTransient: Bool internal let isTransient: Bool
@@ -484,7 +482,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)") @available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
`default`: @autoclosure @escaping () -> V? = nil, `default`: @autoclosure @escaping () -> V? = nil,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
@@ -1,5 +1,5 @@
// //
// ClauseTypes.swift // TypeErasedClauses.swift
// CoreStore // CoreStore
// //
// Copyright © 2014 John Rommel Estropia // Copyright © 2014 John Rommel Estropia
@@ -43,7 +43,7 @@ public protocol FetchClause {
/** /**
The `QueryClause` implement clauses used to configure `NSFetchRequest`s. The `QueryClause` implement clauses used to configure `NSFetchRequest`s.
*/ */
public protocol QueryClause { public protocol QueryClause: FetchClause {
func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<T>) func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<T>)
} }
@@ -54,7 +54,28 @@ public protocol QueryClause {
/** /**
The `DeleteClause` implement clauses used to configure `NSFetchRequest`s. The `DeleteClause` implement clauses used to configure `NSFetchRequest`s.
*/ */
public protocol DeleteClause { public protocol DeleteClause: FetchClause {
func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<T>) func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<T>)
} }
// MARK: - AnyWhereClause
/**
Type-erased `Where` clause for protocol utilities.
*/
public protocol AnyWhereClause: QueryClause, DeleteClause {
/**
The `NSPredicate` for the fetch or query
*/
var predicate: NSPredicate { get }
/**
Initializes a `Where` clause with an `NSPredicate`
- parameter predicate: the `NSPredicate` for the fetch or query
*/
init(_ predicate: NSPredicate)
}
+93 -13
View File
@@ -38,7 +38,7 @@ public extension UnsafeDataTransaction {
- parameter object: the `DynamicObject` to observe changes from - parameter object: the `DynamicObject` to observe changes from
- returns: a `ObjectMonitor` that monitors changes to `object` - returns: a `ObjectMonitor` that monitors changes to `object`
*/ */
public func monitorObject<T>(_ object: T) -> ObjectMonitor<T> { public func monitorObject<D>(_ object: D) -> ObjectMonitor<D> {
return ObjectMonitor( return ObjectMonitor(
unsafeTransaction: self, unsafeTransaction: self,
@@ -53,7 +53,7 @@ public extension UnsafeDataTransaction {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorList<T>(_ from: From<T>, _ fetchClauses: FetchClause...) -> ListMonitor<T> { public func monitorList<D>(_ from: From<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
return self.monitorList(from, fetchClauses) return self.monitorList(from, fetchClauses)
} }
@@ -65,10 +65,10 @@ public extension UnsafeDataTransaction {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorList<T>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> ListMonitor<T> { public func monitorList<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
CoreStore.assert( CoreStore.assert(
fetchClauses.filter { $0 is OrderBy }.count > 0, fetchClauses.filter { $0 is OrderBy<D> }.count > 0,
"A ListMonitor requires an OrderBy clause." "A ListMonitor requires an OrderBy clause."
) )
@@ -83,6 +83,28 @@ public extension UnsafeDataTransaction {
) )
} }
/**
Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
```
transaction.monitorList(
{ (monitor) in
self.monitor = monitor
},
From<MyPersonEntity>()
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
*/
public func monitorList<B: FetchChainableBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
return self.monitorList(clauseChain.from, clauseChain.fetchClauses)
}
/** /**
Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
@@ -90,7 +112,7 @@ public extension UnsafeDataTransaction {
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ fetchClauses: FetchClause...) { public func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: FetchClause...) {
self.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses) self.monitorList(createAsynchronously: createAsynchronously, from, fetchClauses)
} }
@@ -102,10 +124,10 @@ public extension UnsafeDataTransaction {
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ fetchClauses: [FetchClause]) { public func monitorList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ fetchClauses: [FetchClause]) {
CoreStore.assert( CoreStore.assert(
fetchClauses.filter { $0 is OrderBy }.count > 0, fetchClauses.filter { $0 is OrderBy<D> }.count > 0,
"A ListMonitor requires an OrderBy clause." "A ListMonitor requires an OrderBy clause."
) )
@@ -121,6 +143,16 @@ public extension UnsafeDataTransaction {
) )
} }
// TODO: docs
public func monitorList<B: FetchChainableBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
self.monitorList(
createAsynchronously: createAsynchronously,
clauseChain.from,
clauseChain.fetchClauses
)
}
/** /**
Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
@@ -129,7 +161,7 @@ public extension UnsafeDataTransaction {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorSectionedList<T>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> ListMonitor<T> { public func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) -> ListMonitor<D> {
return self.monitorSectionedList(from, sectionBy, fetchClauses) return self.monitorSectionedList(from, sectionBy, fetchClauses)
} }
@@ -142,10 +174,10 @@ public extension UnsafeDataTransaction {
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: a `ListMonitor` instance that monitors changes to the list - returns: a `ListMonitor` instance that monitors changes to the list
*/ */
public func monitorSectionedList<T>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> ListMonitor<T> { public func monitorSectionedList<D>(_ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) -> ListMonitor<D> {
CoreStore.assert( CoreStore.assert(
fetchClauses.filter { $0 is OrderBy }.count > 0, fetchClauses.filter { $0 is OrderBy<D> }.count > 0,
"A ListMonitor requires an OrderBy clause." "A ListMonitor requires an OrderBy clause."
) )
@@ -160,6 +192,28 @@ public extension UnsafeDataTransaction {
) )
} }
/**
Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
```
let monitor = transaction.monitorSectionedList(
From<MyPersonEntity>()
.sectionBy(\.age, { "\($0!) years old" })
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType`
*/
public func monitorSectionedList<B: SectionMonitorBuilderType>(_ clauseChain: B) -> ListMonitor<B.ObjectType> {
return self.monitorSectionedList(
clauseChain.from,
clauseChain.sectionBy,
clauseChain.fetchClauses
)
}
/** /**
Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
@@ -168,7 +222,7 @@ public extension UnsafeDataTransaction {
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorSectionedList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) { public func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: FetchClause...) {
self.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses) self.monitorSectionedList(createAsynchronously: createAsynchronously, from, sectionBy, fetchClauses)
} }
@@ -181,10 +235,10 @@ public extension UnsafeDataTransaction {
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
*/ */
public func monitorSectionedList<T>(createAsynchronously: @escaping (ListMonitor<T>) -> Void, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) { public func monitorSectionedList<D>(createAsynchronously: @escaping (ListMonitor<D>) -> Void, _ from: From<D>, _ sectionBy: SectionBy<D>, _ fetchClauses: [FetchClause]) {
CoreStore.assert( CoreStore.assert(
fetchClauses.filter { $0 is OrderBy }.count > 0, fetchClauses.filter { $0 is OrderBy<D> }.count > 0,
"A ListMonitor requires an OrderBy clause." "A ListMonitor requires an OrderBy clause."
) )
@@ -199,4 +253,30 @@ public extension UnsafeDataTransaction {
createAsynchronously: createAsynchronously createAsynchronously: createAsynchronously
) )
} }
/**
Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType` built from a chain of clauses.
```
transaction.monitorSectionedList(
{ (monitor) in
self.monitor = monitor
},
From<MyPersonEntity>()
.sectionBy(\.age, { "\($0!) years old" })
.where(\.age > 18)
.orderBy(.ascending(\.age))
)
```
- parameter clauseChain: a `SectionMonitorBuilderType` built from a chain of clauses
- returns: a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified `SectionMonitorBuilderType`
*/
public func monitorSectionedList<B: SectionMonitorBuilderType>(createAsynchronously: @escaping (ListMonitor<B.ObjectType>) -> Void, _ clauseChain: B) {
self.monitorSectionedList(
createAsynchronously: createAsynchronously,
clauseChain.from,
clauseChain.sectionBy,
clauseChain.fetchClauses
)
}
} }
+6 -7
View File
@@ -112,7 +112,7 @@ public enum ValueContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public init( public init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
initial: @autoclosure @escaping () -> V, initial: @autoclosure @escaping () -> V,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
@@ -195,8 +195,7 @@ public enum ValueContainer<O: CoreStoreObject> {
return V.cs_rawAttributeType return V.cs_rawAttributeType
} }
public let keyPath: RawKeyPath internal let keyPath: KeyPathString
internal let isOptional = false internal let isOptional = false
internal let isIndexed: Bool internal let isIndexed: Bool
internal let isTransient: Bool internal let isTransient: Bool
@@ -259,7 +258,7 @@ public enum ValueContainer<O: CoreStoreObject> {
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)") @available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
`default`: @autoclosure @escaping () -> V, `default`: @autoclosure @escaping () -> V,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
@@ -339,7 +338,7 @@ public enum ValueContainer<O: CoreStoreObject> {
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`. - parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
*/ */
public init( public init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
initial: @autoclosure @escaping () -> V? = nil, initial: @autoclosure @escaping () -> V? = nil,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
@@ -421,7 +420,7 @@ public enum ValueContainer<O: CoreStoreObject> {
return V.cs_rawAttributeType return V.cs_rawAttributeType
} }
public let keyPath: RawKeyPath internal let keyPath: KeyPathString
internal let isOptional = true internal let isOptional = true
internal let isIndexed: Bool internal let isIndexed: Bool
internal let isTransient: Bool internal let isTransient: Bool
@@ -484,7 +483,7 @@ public enum ValueContainer<O: CoreStoreObject> {
@available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)") @available(*, deprecated: 3.2, renamed: "init(_:initial:isIndexed:isTransient:versionHashModifier:renamingIdentifier:customGetter:customSetter:affectedByKeyPaths:)")
public convenience init( public convenience init(
_ keyPath: RawKeyPath, _ keyPath: KeyPathString,
`default`: @autoclosure @escaping () -> V? = nil, `default`: @autoclosure @escaping () -> V? = nil,
isIndexed: Bool = false, isIndexed: Bool = false,
isTransient: Bool = false, isTransient: Bool = false,
+353 -70
View File
@@ -27,66 +27,72 @@ import Foundation
import CoreData import CoreData
infix operator &&? : LogicalConjunctionPrecedence
infix operator ||? : LogicalConjunctionPrecedence
// MARK: - Where // MARK: - Where
/** /**
The `Where` clause specifies the conditions for a fetch or a query. The `Where` clause specifies the conditions for a fetch or a query.
*/ */
public struct Where: FetchClause, QueryClause, DeleteClause, Hashable { public struct Where<D: DynamicObject>: WhereClauseType, FetchClause, QueryClause, DeleteClause, Hashable {
/** /**
Combines two `Where` predicates together using `AND` operator Combines two `Where` predicates together using `AND` operator
*/ */
public static func && (left: Where, right: Where) -> Where { public static func && (left: Where<D>, right: Where<D>) -> Where<D> {
return Where(NSCompoundPredicate(type: .and, subpredicates: [left.predicate, right.predicate])) return Where<D>(NSCompoundPredicate(type: .and, subpredicates: [left.predicate, right.predicate]))
}
/**
Combines two `Where` predicates together using `AND` operator.
- parameter left: the left hand side `Where` clause
- parameter right: the right hand side `Where` clause
- returns: Return `left` unchanged if `right` is nil
*/
public static func && (left: Where, right: Where?) -> Where {
if let right = right {
return left && right
}
return left
}
/**
Combines two `Where` predicates together using `AND` operator.
- parameter left: the left hand side `Where` clause
- parameter right: the right hand side `Where` clause
- returns: Returns `right` unchanged if `left` is nil
*/
public static func && (left: Where?, right: Where) -> Where {
if let left = left {
return left && right
}
return right
} }
/** /**
Combines two `Where` predicates together using `OR` operator Combines two `Where` predicates together using `OR` operator
*/ */
public static func || (left: Where, right: Where) -> Where { public static func || (left: Where<D>, right: Where<D>) -> Where<D> {
return Where(NSCompoundPredicate(type: .or, subpredicates: [left.predicate, right.predicate])) return Where<D>(NSCompoundPredicate(type: .or, subpredicates: [left.predicate, right.predicate]))
}
/**
Inverts the predicate of a `Where` clause using `NOT` operator
*/
public static prefix func ! (clause: Where<D>) -> Where<D> {
return Where<D>(NSCompoundPredicate(type: .not, subpredicates: [clause.predicate]))
}
/**
Combines two `Where` predicates together using `AND` operator.
- returns: `left` if `right` is `nil`, otherwise equivalent to `(left && right)`
*/
public static func &&? (left: Where<D>, right: Where<D>?) -> Where<D> {
if let right = right {
return left && right
}
return left
}
/**
Combines two `Where` predicates together using `AND` operator.
- returns: `right` if `left` is `nil`, otherwise equivalent to `(left && right)`
*/
public static func &&? (left: Where<D>?, right: Where<D>) -> Where<D> {
if let left = left {
return left && right
}
return right
} }
/** /**
Combines two `Where` predicates together using `OR` operator. Combines two `Where` predicates together using `OR` operator.
- parameter left: the left hand side `Where` clause - returns: `left` if `right` is `nil`, otherwise equivalent to `(left || right)`
- parameter right: the right hand side `Where` clause
- returns: Returns `left` unchanged if `right` is nil
*/ */
public static func || (left: Where, right: Where?) -> Where { public static func ||? (left: Where<D>, right: Where<D>?) -> Where<D> {
if let right = right { if let right = right {
@@ -97,11 +103,9 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
/** /**
Combines two `Where` predicates together using `OR` operator. Combines two `Where` predicates together using `OR` operator.
- parameter left: the left hand side `Where` clause - returns: `right` if `left` is `nil`, otherwise equivalent to `(left || right)`
- parameter right: the right hand side `Where` clause
- returns: Return `right` unchanged if `left` is nil
*/ */
public static func || (left: Where?, right: Where) -> Where { public static func ||? (left: Where<D>?, right: Where<D>) -> Where<D> {
if let left = left { if let left = left {
@@ -110,19 +114,6 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
return right return right
} }
/**
Inverts the predicate of a `Where` clause using `NOT` operator
*/
public static prefix func ! (clause: Where) -> Where {
return Where(NSCompoundPredicate(type: .not, subpredicates: [clause.predicate]))
}
/**
The `NSPredicate` for the fetch or query
*/
public let predicate: NSPredicate
/** /**
Initializes a `Where` clause with a predicate that always evaluates to `true` Initializes a `Where` clause with a predicate that always evaluates to `true`
*/ */
@@ -167,9 +158,9 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
Initializes a `Where` clause that compares equality to `nil` Initializes a `Where` clause that compares equality to `nil`
- parameter keyPath: the keyPath to compare with - parameter keyPath: the keyPath to compare with
- parameter value: the arguments for the `==` operator - parameter null: the arguments for the `==` operator
*/ */
public init(_ keyPath: RawKeyPath, isEqualTo value: Void?) { public init(_ keyPath: KeyPathString, isEqualTo null: Void?) {
self.init(NSPredicate(format: "\(keyPath) == nil")) self.init(NSPredicate(format: "\(keyPath) == nil"))
} }
@@ -180,7 +171,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter keyPath: the keyPath to compare with - parameter keyPath: the keyPath to compare with
- parameter value: the arguments for the `==` operator - parameter value: the arguments for the `==` operator
*/ */
public init<T: QueryableAttributeType>(_ keyPath: RawKeyPath, isEqualTo value: T?) { public init<U: QueryableAttributeType>(_ keyPath: KeyPathString, isEqualTo value: U?) {
switch value { switch value {
@@ -199,12 +190,11 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter keyPath: the keyPath to compare with - parameter keyPath: the keyPath to compare with
- parameter object: the arguments for the `==` operator - parameter object: the arguments for the `==` operator
*/ */
public init<T: DynamicObject>(_ keyPath: RawKeyPath, isEqualTo object: T?) { public init<D: DynamicObject>(_ keyPath: KeyPathString, isEqualTo object: D?) {
switch object { switch object {
case nil, case nil:
is NSNull:
self.init(NSPredicate(format: "\(keyPath) == nil")) self.init(NSPredicate(format: "\(keyPath) == nil"))
case let object?: case let object?:
@@ -212,13 +202,24 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
} }
} }
/**
Initializes a `Where` clause that compares equality
- parameter keyPath: the keyPath to compare with
- parameter objectID: the arguments for the `==` operator
*/
public init(_ keyPath: KeyPathString, isEqualTo objectID: NSManagedObjectID) {
self.init(NSPredicate(format: "\(keyPath) == %@", argumentArray: [objectID]))
}
/** /**
Initializes a `Where` clause that compares membership Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with - parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of - parameter list: the sequence to check membership of
*/ */
public init<S: Sequence>(_ keyPath: RawKeyPath, isMemberOf list: S) where S.Iterator.Element: QueryableAttributeType { public init<S: Sequence>(_ keyPath: KeyPathString, isMemberOf list: S) where S.Iterator.Element: QueryableAttributeType {
self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_toQueryableNativeType() }) as NSArray)) self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_toQueryableNativeType() }) as NSArray))
} }
@@ -229,22 +230,38 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter keyPath: the keyPath to compare with - parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of - parameter list: the sequence to check membership of
*/ */
public init<S: Sequence>(_ keyPath: RawKeyPath, isMemberOf list: S) where S.Iterator.Element: DynamicObject { public init<S: Sequence>(_ keyPath: KeyPathString, isMemberOf list: S) where S.Iterator.Element: DynamicObject {
self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_id() }) as NSArray)) self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_id() }) as NSArray))
} }
/** /**
Initializes a `Where` clause with an `NSPredicate` Initializes a `Where` clause that compares membership
- parameter predicate: the `NSPredicate` for the fetch or query - parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/ */
public init<S: Sequence>(_ keyPath: KeyPathString, isMemberOf list: S) where S.Iterator.Element: NSManagedObjectID {
self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0 }) as NSArray))
}
// MARK: AnyWhereClause
public let predicate: NSPredicate
public init(_ predicate: NSPredicate) { public init(_ predicate: NSPredicate) {
self.predicate = predicate self.predicate = predicate
} }
// MARK: WhereClauseType
public typealias ObjectType = D
// MARK: FetchClause, QueryClause, DeleteClause // MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest<ResultType>(_ fetchRequest: NSFetchRequest<ResultType>) { public func applyToFetchRequest<ResultType>(_ fetchRequest: NSFetchRequest<ResultType>) {
@@ -278,14 +295,234 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
} }
// MARK: - Sequence where Element == Where // MARK: - Where where D: NSManagedObject
public extension Sequence where Iterator.Element == Where { public extension Where where D: NSManagedObject {
/**
Initializes a `Where` clause that compares equality to `nil`
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<V: QueryableAttributeType>(_ keyPath: KeyPath<D, V>, isEqualTo null: Void?) {
self.init(keyPath._kvcKeyPathString!, isEqualTo: null)
}
/**
Initializes a `Where` clause that compares equality to `nil`
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<O: DynamicObject>(_ keyPath: KeyPath<D, O>, isEqualTo null: Void?) {
self.init(keyPath._kvcKeyPathString!, isEqualTo: null)
}
/**
Initializes a `Where` clause that compares equality
- parameter keyPath: the keyPath to compare with
- parameter value: the arguments for the `==` operator
*/
public init<V: QueryableAttributeType>(_ keyPath: KeyPath<D, V>, isEqualTo value: V?) {
self.init(keyPath._kvcKeyPathString!, 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<O: DynamicObject>(_ keyPath: KeyPath<D, O>, isEqualTo value: O?) {
self.init(keyPath._kvcKeyPathString!, isEqualTo: value)
}
/**
Initializes a `Where` clause that compares equality
- parameter keyPath: the keyPath to compare with
- parameter objectID: the arguments for the `==` operator
*/
public init<O: DynamicObject>(_ keyPath: KeyPath<D, O>, isEqualTo objectID: NSManagedObjectID) {
self.init(keyPath._kvcKeyPathString!, isEqualTo: objectID)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<V: QueryableAttributeType, S: Sequence>(_ keyPath: KeyPath<D, V>, isMemberOf list: S) where S.Iterator.Element == V {
self.init(keyPath._kvcKeyPathString!, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<O: DynamicObject, S: Sequence>(_ keyPath: KeyPath<D, O>, isMemberOf list: S) where S.Iterator.Element == O {
self.init(keyPath._kvcKeyPathString!, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<O: DynamicObject, S: Sequence>(_ keyPath: KeyPath<D, O>, isMemberOf list: S) where S.Iterator.Element: NSManagedObjectID {
self.init(keyPath._kvcKeyPathString!, isMemberOf: list)
}
}
// MARK: - Where where D: CoreStoreObject
public extension Where where D: CoreStoreObject {
/**
Initializes a `Where` clause that compares equality to `nil`
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<V>>, isEqualTo null: Void?) {
self.init(D.meta[keyPath: keyPath].keyPath, isEqualTo: null)
}
/**
Initializes a `Where` clause that compares equality to `nil`
- parameter keyPath: the keyPath to compare with
- parameter null: the arguments for the `==` operator
*/
public init<O>(_ keyPath: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, isEqualTo null: Void?) {
self.init(D.meta[keyPath: keyPath].keyPath, isEqualTo: null)
}
/**
Initializes a `Where` clause that compares equality
- parameter keyPath: the keyPath to compare with
- parameter value: the arguments for the `==` operator
*/
public init<V>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<V>>, isEqualTo value: V?) {
self.init(D.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>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<V>>, isEqualTo value: V?) {
self.init(D.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<O>(_ keyPath: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, isEqualTo value: O?) {
self.init(D.meta[keyPath: keyPath].keyPath, isEqualTo: value)
}
/**
Initializes a `Where` clause that compares equality
- parameter keyPath: the keyPath to compare with
- parameter objectID: the arguments for the `==` operator
*/
public init<O>(_ keyPath: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, isEqualTo objectID: NSManagedObjectID) {
self.init(D.meta[keyPath: keyPath].keyPath, isEqualTo: objectID)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<V, S: Sequence>(_ keyPath: KeyPath<D, ValueContainer<D>.Required<V>>, isMemberOf list: S) where S.Iterator.Element == V {
self.init(D.meta[keyPath: keyPath].keyPath, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<V, S: Sequence>(_ keyPath: KeyPath<D, ValueContainer<D>.Optional<V>>, isMemberOf list: S) where S.Iterator.Element == V {
self.init(D.meta[keyPath: keyPath].keyPath, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<O, S: Sequence>(_ keyPath: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, isMemberOf list: S) where S.Iterator.Element == O {
self.init(D.meta[keyPath: keyPath].keyPath, isMemberOf: list)
}
/**
Initializes a `Where` clause that compares membership
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<O, S: Sequence>(_ keyPath: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, isMemberOf list: S) where S.Iterator.Element: NSManagedObjectID {
self.init(D.meta[keyPath: keyPath].keyPath, isMemberOf: list)
}
/**
Initializes a `Where` clause from a closure
- parameter condition: closure that returns the `Where` clause
*/
public init(_ condition: (D) -> Where<D>) {
self = condition(D.meta)
}
}
// MARK: - Sequence where Iterator.Element: WhereClauseType
public extension Sequence where Iterator.Element: WhereClauseType {
/** /**
Combines multiple `Where` predicates together using `AND` operator Combines multiple `Where` predicates together using `AND` operator
*/ */
public func combinedByAnd() -> Where { public func combinedByAnd() -> Where<Iterator.Element.ObjectType> {
return Where(NSCompoundPredicate(type: .and, subpredicates: self.map({ $0.predicate }))) return Where(NSCompoundPredicate(type: .and, subpredicates: self.map({ $0.predicate })))
} }
@@ -293,8 +530,54 @@ public extension Sequence where Iterator.Element == Where {
/** /**
Combines multiple `Where` predicates together using `OR` operator Combines multiple `Where` predicates together using `OR` operator
*/ */
public func combinedByOr() -> Where { public func combinedByOr() -> Where<Iterator.Element.ObjectType> {
return Where(NSCompoundPredicate(type: .or, subpredicates: self.map({ $0.predicate }))) return Where(NSCompoundPredicate(type: .or, subpredicates: self.map({ $0.predicate })))
} }
} }
// MARK: - Deprecated
public extension Where {
@available(*, deprecated: 4.0, renamed: "&&?")
public static func && (left: Where<D>, right: Where<D>?) -> Where<D> {
if let right = right {
return left && right
}
return left
}
@available(*, deprecated: 4.0, renamed: "&&?")
public static func && (left: Where<D>?, right: Where<D>) -> Where<D> {
if let left = left {
return left && right
}
return right
}
@available(*, deprecated: 4.0, renamed: "||?")
public static func || (left: Where<D>, right: Where<D>?) -> Where<D> {
if let right = right {
return left || right
}
return left
}
@available(*, deprecated: 4.0, renamed: "||?")
public static func || (left: Where<D>?, right: Where<D>) -> Where<D> {
if let left = left {
return left || right
}
return right
}
}
+79
View File
@@ -0,0 +1,79 @@
//
// WhereClauseType.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - WhereClauseType
/**
Abstracts the `Where` clause for protocol utilities.
*/
public protocol WhereClauseType: AnyWhereClause {
/**
The `DynamicObject` type associated with the clause
*/
associatedtype ObjectType: DynamicObject
}
public extension WhereClauseType {
/**
Combines two `Where` predicates together using `AND` operator.
- Warning: This operator overload is a workaround for Swift generics' inability to constrain by inheritance (https://bugs.swift.org/browse/SR-5213). In effect, this is less type-safe than other overloads because it allows AND'ing clauses of unrelated `DynamicObject` types.
*/
public static func && <TWhere: WhereClauseType>(left: Self, right: TWhere) -> Self {
return Self.init(NSCompoundPredicate(type: .and, subpredicates: [left.predicate, right.predicate]))
}
/**
Combines two `Where` predicates together using `AND` operator.
- Warning: This operator overload is a workaround for Swift generics' inability to constrain by inheritance (https://bugs.swift.org/browse/SR-5213). In effect, this is less type-safe than other overloads because it allows AND'ing clauses of unrelated `DynamicObject` types.
*/
public static func && <TWhere: WhereClauseType>(left: TWhere, right: Self) -> Self {
return Self.init(NSCompoundPredicate(type: .and, subpredicates: [left.predicate, right.predicate]))
}
/**
Combines two `Where` predicates together using `OR` operator.
- Warning: This operator overload is a workaround for Swift generics' inability to constrain by inheritance (https://bugs.swift.org/browse/SR-5213). In effect, this is less type-safe than other overloads because it allows OR'ing clauses of unrelated `DynamicObject` types.
*/
public static func || <TWhere: WhereClauseType>(left: Self, right: TWhere) -> Self {
return Self.init(NSCompoundPredicate(type: .or, subpredicates: [left.predicate, right.predicate]))
}
/**
Combines two `Where` predicates together using `OR` operator.
- Warning: This operator overload is a workaround for Swift generics' inability to constrain by inheritance (https://bugs.swift.org/browse/SR-5213). In effect, this is less type-safe than other overloads because it allows OR'ing clauses of unrelated `DynamicObject` types.
*/
public static func || <TWhere: WhereClauseType>(left: TWhere, right: Self) -> Self {
return Self.init(NSCompoundPredicate(type: .or, subpredicates: [left.predicate, right.predicate]))
}
}