mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-15 13:43:43 +01:00
added ability to query aggregates and attributes straight from the persistent store
This commit is contained in:
@@ -11,10 +11,14 @@
|
||||
2F03A54019C5C6DA005002A5 /* HardcoreDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F03A53F19C5C6DA005002A5 /* HardcoreDataTests.swift */; };
|
||||
2F03A54D19C5C872005002A5 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F03A54C19C5C872005002A5 /* CoreData.framework */; };
|
||||
2F291E2719C6D3CF007AF63F /* HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F291E2619C6D3CF007AF63F /* HardcoreData.swift */; };
|
||||
B52B68BA1AAB46AD00CE7F48 /* ManagedObjectController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52B68B91AAB46AD00CE7F48 /* ManagedObjectController.swift */; };
|
||||
B52B68BC1AAB46BD00CE7F48 /* ManagedObjectListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52B68BB1AAB46BD00CE7F48 /* ManagedObjectListController.swift */; };
|
||||
B52B68BE1AAB484C00CE7F48 /* DataStack+Observing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52B68BD1AAB484C00CE7F48 /* DataStack+Observing.swift */; };
|
||||
B52B68C01AAB9DAD00CE7F48 /* ManagedObjectListObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52B68BF1AAB9DAD00CE7F48 /* ManagedObjectListObserver.swift */; };
|
||||
B52B68C21AAF554600CE7F48 /* ManagedObjectListSectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52B68C11AAF554600CE7F48 /* ManagedObjectListSectionInfo.swift */; };
|
||||
B5398AA21AA8938D00B66388 /* DetachedDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5398AA11AA8938D00B66388 /* DetachedDataTransaction.swift */; };
|
||||
B54A9F031AA7640200AFEC05 /* AggregateFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54A9F021AA7640200AFEC05 /* AggregateFunction.swift */; };
|
||||
B54A9F051AA7644400AFEC05 /* AggregateResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54A9F041AA7644400AFEC05 /* AggregateResultType.swift */; };
|
||||
B54A9F071AA7654400AFEC05 /* DataStack+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54A9F061AA7654400AFEC05 /* DataStack+Querying.swift */; };
|
||||
B54D53071AB3538500D55BA8 /* QueryClause.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D53061AB3538500D55BA8 /* QueryClause.swift */; };
|
||||
B57078B01A50392D007E33F2 /* FetchClause.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57078AF1A50392D007E33F2 /* FetchClause.swift */; };
|
||||
B582DF821A98B0E7003F09C6 /* HardcoreData+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B582DF811A98B0E7003F09C6 /* HardcoreData+Querying.swift */; };
|
||||
B582DF861A98B11B003F09C6 /* HardcoreData+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B582DF851A98B11B003F09C6 /* HardcoreData+Transaction.swift */; };
|
||||
@@ -25,6 +29,8 @@
|
||||
B5CFF23E19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CFF23D19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift */; };
|
||||
B5CFF24019FD383100D6DFC4 /* BaseDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CFF23F19FD383100D6DFC4 /* BaseDataTransaction.swift */; };
|
||||
B5D022661A90CD340070CA63 /* DataStack+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D022651A90CD340070CA63 /* DataStack+Transaction.swift */; };
|
||||
B5D10DC01AB42C85004B4EEA /* GroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D10DBF1AB42C85004B4EEA /* GroupBy.swift */; };
|
||||
B5D10DC21AB4590F004B4EEA /* Select.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D10DC11AB4590F004B4EEA /* Select.swift */; };
|
||||
B5D19BFB1AA14063001D1A99 /* AsynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D19BFA1AA14063001D1A99 /* AsynchronousDataTransaction.swift */; };
|
||||
B5D19BFF1AA14351001D1A99 /* SynchronousDataTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D19BFE1AA14351001D1A99 /* SynchronousDataTransaction.swift */; };
|
||||
B5D19C011AA15E1F001D1A99 /* HardcoreData+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D19C001AA15E1F001D1A99 /* HardcoreData+Logging.swift */; };
|
||||
@@ -33,7 +39,6 @@
|
||||
B5D372841A39CD6900F583D9 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5D372821A39CD6900F583D9 /* Model.xcdatamodeld */; };
|
||||
B5D372861A39CDDB00F583D9 /* TestEntity1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D372851A39CDDB00F583D9 /* TestEntity1.swift */; };
|
||||
B5D399F119FC818E000E91BB /* DataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D399F019FC818E000E91BB /* DataStack.swift */; };
|
||||
B5D399F519FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D399F419FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift */; };
|
||||
B5D39A0219FD00C9000E91BB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D39A0119FD00C9000E91BB /* Foundation.framework */; };
|
||||
B5D39A0419FD00DE000E91BB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D39A0319FD00DE000E91BB /* UIKit.framework */; };
|
||||
B5D5E0CF1A4D6AAB006468AF /* TestEntity2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */; };
|
||||
@@ -47,7 +52,7 @@
|
||||
B5F409EB1A8B199600A228EA /* DefaultLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F409EA1A8B199600A228EA /* DefaultLogger.swift */; };
|
||||
B5F409ED1A8B200700A228EA /* NSManagedObjectContext+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F409EC1A8B200700A228EA /* NSManagedObjectContext+Querying.swift */; };
|
||||
B5F409EF1A8B243D00A228EA /* BaseDataTransaction+Querying.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F409EE1A8B243D00A228EA /* BaseDataTransaction+Querying.swift */; };
|
||||
B5F409F11A8B27A600A228EA /* CustomizeQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F409F01A8B27A600A228EA /* CustomizeQuery.swift */; };
|
||||
B5F409F11A8B27A600A228EA /* CustomizeFetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F409F01A8B27A600A228EA /* CustomizeFetch.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -83,10 +88,14 @@
|
||||
2F03A53F19C5C6DA005002A5 /* HardcoreDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = HardcoreDataTests.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
2F03A54C19C5C872005002A5 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||
2F291E2619C6D3CF007AF63F /* HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = HardcoreData.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
B52B68B91AAB46AD00CE7F48 /* ManagedObjectController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObjectController.swift; sourceTree = "<group>"; };
|
||||
B52B68BB1AAB46BD00CE7F48 /* ManagedObjectListController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObjectListController.swift; sourceTree = "<group>"; };
|
||||
B52B68BD1AAB484C00CE7F48 /* DataStack+Observing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataStack+Observing.swift"; sourceTree = "<group>"; };
|
||||
B52B68BF1AAB9DAD00CE7F48 /* ManagedObjectListObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObjectListObserver.swift; sourceTree = "<group>"; };
|
||||
B52B68C11AAF554600CE7F48 /* ManagedObjectListSectionInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedObjectListSectionInfo.swift; sourceTree = "<group>"; };
|
||||
B5398AA11AA8938D00B66388 /* DetachedDataTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetachedDataTransaction.swift; sourceTree = "<group>"; };
|
||||
B54A9F021AA7640200AFEC05 /* AggregateFunction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateFunction.swift; sourceTree = "<group>"; };
|
||||
B54A9F041AA7644400AFEC05 /* AggregateResultType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateResultType.swift; sourceTree = "<group>"; };
|
||||
B54A9F061AA7654400AFEC05 /* DataStack+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataStack+Querying.swift"; sourceTree = "<group>"; };
|
||||
B54D53061AB3538500D55BA8 /* QueryClause.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryClause.swift; sourceTree = "<group>"; };
|
||||
B57078AF1A50392D007E33F2 /* FetchClause.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchClause.swift; sourceTree = "<group>"; };
|
||||
B582DF811A98B0E7003F09C6 /* HardcoreData+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HardcoreData+Querying.swift"; sourceTree = "<group>"; };
|
||||
B582DF851A98B11B003F09C6 /* HardcoreData+Transaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HardcoreData+Transaction.swift"; sourceTree = "<group>"; };
|
||||
@@ -97,6 +106,8 @@
|
||||
B5CFF23D19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+HardcoreData.swift"; sourceTree = "<group>"; };
|
||||
B5CFF23F19FD383100D6DFC4 /* BaseDataTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseDataTransaction.swift; sourceTree = "<group>"; };
|
||||
B5D022651A90CD340070CA63 /* DataStack+Transaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataStack+Transaction.swift"; sourceTree = "<group>"; };
|
||||
B5D10DBF1AB42C85004B4EEA /* GroupBy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupBy.swift; sourceTree = "<group>"; };
|
||||
B5D10DC11AB4590F004B4EEA /* Select.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Select.swift; sourceTree = "<group>"; };
|
||||
B5D19BFA1AA14063001D1A99 /* AsynchronousDataTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsynchronousDataTransaction.swift; sourceTree = "<group>"; };
|
||||
B5D19BFE1AA14351001D1A99 /* SynchronousDataTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousDataTransaction.swift; sourceTree = "<group>"; };
|
||||
B5D19C001AA15E1F001D1A99 /* HardcoreData+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HardcoreData+Logging.swift"; sourceTree = "<group>"; };
|
||||
@@ -105,7 +116,6 @@
|
||||
B5D372831A39CD6900F583D9 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5D372851A39CDDB00F583D9 /* TestEntity1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity1.swift; sourceTree = "<group>"; };
|
||||
B5D399F019FC818E000E91BB /* DataStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataStack.swift; sourceTree = "<group>"; };
|
||||
B5D399F419FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+HardcoreData.swift"; sourceTree = "<group>"; };
|
||||
B5D39A0119FD00C9000E91BB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
B5D39A0319FD00DE000E91BB /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity2.swift; sourceTree = "<group>"; };
|
||||
@@ -120,7 +130,7 @@
|
||||
B5F409EA1A8B199600A228EA /* DefaultLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultLogger.swift; sourceTree = "<group>"; };
|
||||
B5F409EC1A8B200700A228EA /* NSManagedObjectContext+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Querying.swift"; sourceTree = "<group>"; };
|
||||
B5F409EE1A8B243D00A228EA /* BaseDataTransaction+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BaseDataTransaction+Querying.swift"; sourceTree = "<group>"; };
|
||||
B5F409F01A8B27A600A228EA /* CustomizeQuery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeQuery.swift; sourceTree = "<group>"; };
|
||||
B5F409F01A8B27A600A228EA /* CustomizeFetch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeFetch.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -175,6 +185,7 @@
|
||||
B5D022621A90BCC60070CA63 /* Saving and Processing */,
|
||||
B5F409E51A8B11B600A228EA /* Logging */,
|
||||
B5E126531A7DCCE400AD8B39 /* Fetching and Querying */,
|
||||
B52B68B61AAB45FB00CE7F48 /* Observing */,
|
||||
B5D808141A34945A00A44484 /* Internal */,
|
||||
2F03A53319C5C6DA005002A5 /* Supporting Files */,
|
||||
);
|
||||
@@ -220,6 +231,18 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B52B68B61AAB45FB00CE7F48 /* Observing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B52B68B91AAB46AD00CE7F48 /* ManagedObjectController.swift */,
|
||||
B52B68BB1AAB46BD00CE7F48 /* ManagedObjectListController.swift */,
|
||||
B52B68C11AAF554600CE7F48 /* ManagedObjectListSectionInfo.swift */,
|
||||
B52B68BF1AAB9DAD00CE7F48 /* ManagedObjectListObserver.swift */,
|
||||
B52B68BD1AAB484C00CE7F48 /* DataStack+Observing.swift */,
|
||||
);
|
||||
name = Observing;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B54A9EFF1AA763D100AFEC05 /* Internal */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -228,6 +251,27 @@
|
||||
name = Internal;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B54D53041AB350CF00D55BA8 /* Fetching */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B57078AF1A50392D007E33F2 /* FetchClause.swift */,
|
||||
B5E126541A7DCE1400AD8B39 /* Where.swift */,
|
||||
B5E126561A7DCE5900AD8B39 /* SortedBy.swift */,
|
||||
B5F409F01A8B27A600A228EA /* CustomizeFetch.swift */,
|
||||
);
|
||||
name = Fetching;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B54D53051AB350FF00D55BA8 /* Querying */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B54D53061AB3538500D55BA8 /* QueryClause.swift */,
|
||||
B5D10DC11AB4590F004B4EEA /* Select.swift */,
|
||||
B5D10DBF1AB42C85004B4EEA /* GroupBy.swift */,
|
||||
);
|
||||
name = Querying;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B595CAC01A9A0AC4009A397F /* Setting Up */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -302,7 +346,6 @@
|
||||
B595CAC71A9A161B009A397F /* WeakObject.swift */,
|
||||
B5D808191A3495BD00A44484 /* NSObject+HardcoreData.swift */,
|
||||
B5CFF23D19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift */,
|
||||
B5D399F419FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift */,
|
||||
);
|
||||
name = Internal;
|
||||
sourceTree = "<group>";
|
||||
@@ -310,15 +353,11 @@
|
||||
B5E126531A7DCCE400AD8B39 /* Fetching and Querying */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B57078AF1A50392D007E33F2 /* FetchClause.swift */,
|
||||
B5E126541A7DCE1400AD8B39 /* Where.swift */,
|
||||
B5E126561A7DCE5900AD8B39 /* SortedBy.swift */,
|
||||
B5F409F01A8B27A600A228EA /* CustomizeQuery.swift */,
|
||||
B54A9F021AA7640200AFEC05 /* AggregateFunction.swift */,
|
||||
B54A9F041AA7644400AFEC05 /* AggregateResultType.swift */,
|
||||
B582DF811A98B0E7003F09C6 /* HardcoreData+Querying.swift */,
|
||||
B54A9F061AA7654400AFEC05 /* DataStack+Querying.swift */,
|
||||
B5F409EE1A8B243D00A228EA /* BaseDataTransaction+Querying.swift */,
|
||||
B54D53041AB350CF00D55BA8 /* Fetching */,
|
||||
B54D53051AB350FF00D55BA8 /* Querying */,
|
||||
B54A9EFF1AA763D100AFEC05 /* Internal */,
|
||||
);
|
||||
name = "Fetching and Querying";
|
||||
@@ -467,7 +506,6 @@
|
||||
files = (
|
||||
B5CFF24019FD383100D6DFC4 /* BaseDataTransaction.swift in Sources */,
|
||||
B5D19C011AA15E1F001D1A99 /* HardcoreData+Logging.swift in Sources */,
|
||||
B5D399F519FCF4E0000E91BB /* NSPersistentStoreCoordinator+HardcoreData.swift in Sources */,
|
||||
B5CFD36E1A0775F000B7885F /* SaveResult.swift in Sources */,
|
||||
B5D022661A90CD340070CA63 /* DataStack+Transaction.swift in Sources */,
|
||||
B582DF861A98B11B003F09C6 /* HardcoreData+Transaction.swift in Sources */,
|
||||
@@ -476,27 +514,33 @@
|
||||
B5CFF23E19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift in Sources */,
|
||||
B54A9F071AA7654400AFEC05 /* DataStack+Querying.swift in Sources */,
|
||||
B5E126571A7DCE5900AD8B39 /* SortedBy.swift in Sources */,
|
||||
B54D53071AB3538500D55BA8 /* QueryClause.swift in Sources */,
|
||||
B5F409EF1A8B243D00A228EA /* BaseDataTransaction+Querying.swift in Sources */,
|
||||
2F291E2719C6D3CF007AF63F /* HardcoreData.swift in Sources */,
|
||||
B5F409E91A8B11CE00A228EA /* HardcoreDataLogger.swift in Sources */,
|
||||
B5D8081A1A3495BD00A44484 /* NSObject+HardcoreData.swift in Sources */,
|
||||
B595CAC41A9A11C1009A397F /* NSManagedObjectContext+Setup.swift in Sources */,
|
||||
B5D19BFF1AA14351001D1A99 /* SynchronousDataTransaction.swift in Sources */,
|
||||
B5D10DC21AB4590F004B4EEA /* Select.swift in Sources */,
|
||||
B5E209E01A0726460089C9D4 /* NSManagedObject+Transaction.swift in Sources */,
|
||||
B582DF821A98B0E7003F09C6 /* HardcoreData+Querying.swift in Sources */,
|
||||
B5D19BFB1AA14063001D1A99 /* AsynchronousDataTransaction.swift in Sources */,
|
||||
B595CAC81A9A161B009A397F /* WeakObject.swift in Sources */,
|
||||
B54A9F051AA7644400AFEC05 /* AggregateResultType.swift in Sources */,
|
||||
B5D1E22A19FA9E63003B2874 /* PersistentStoreResult.swift in Sources */,
|
||||
B5398AA21AA8938D00B66388 /* DetachedDataTransaction.swift in Sources */,
|
||||
B5F409F11A8B27A600A228EA /* CustomizeQuery.swift in Sources */,
|
||||
B5F409F11A8B27A600A228EA /* CustomizeFetch.swift in Sources */,
|
||||
B5F409EB1A8B199600A228EA /* DefaultLogger.swift in Sources */,
|
||||
B54A9F031AA7640200AFEC05 /* AggregateFunction.swift in Sources */,
|
||||
B52B68C01AAB9DAD00CE7F48 /* ManagedObjectListObserver.swift in Sources */,
|
||||
B5D399F119FC818E000E91BB /* DataStack.swift in Sources */,
|
||||
B5D808161A34947300A44484 /* NotificationObserver.swift in Sources */,
|
||||
B52B68BE1AAB484C00CE7F48 /* DataStack+Observing.swift in Sources */,
|
||||
B52B68C21AAF554600CE7F48 /* ManagedObjectListSectionInfo.swift in Sources */,
|
||||
B57078B01A50392D007E33F2 /* FetchClause.swift in Sources */,
|
||||
B5F409ED1A8B200700A228EA /* NSManagedObjectContext+Querying.swift in Sources */,
|
||||
B5D10DC01AB42C85004B4EEA /* GroupBy.swift in Sources */,
|
||||
B5E126551A7DCE1400AD8B39 /* Where.swift in Sources */,
|
||||
B52B68BC1AAB46BD00CE7F48 /* ManagedObjectListController.swift in Sources */,
|
||||
B52B68BA1AAB46AD00CE7F48 /* ManagedObjectController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
//
|
||||
// AggregateFunction.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// 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: - AggregateFunction
|
||||
|
||||
public enum AggregateFunction {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
case Average(AttributeName)
|
||||
case Sum(AttributeName)
|
||||
case Count(AttributeName)
|
||||
case Minimum(AttributeName)
|
||||
case Maximum(AttributeName)
|
||||
case Medium(AttributeName)
|
||||
case Mode(AttributeName)
|
||||
case StandardDeviation(AttributeName)
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func createExpression() -> NSExpression {
|
||||
|
||||
switch self {
|
||||
|
||||
case .Average(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "average:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
|
||||
case .Sum(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "sum:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
|
||||
case .Count(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "count:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
|
||||
case .Minimum(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "min:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
|
||||
case .Maximum(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "max:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
|
||||
case .Medium(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "medium:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
|
||||
case .Mode(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "mode:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
|
||||
case .StandardDeviation(let attributeName):
|
||||
return NSExpression(
|
||||
forFunction: "stddev:",
|
||||
arguments: [NSExpression(forKeyPath: "\(attributeName)")]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
//
|
||||
// AggregateResultType.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - AggregateResultType
|
||||
|
||||
public protocol AggregateResultType {
|
||||
|
||||
static var attributeType: NSAttributeType { get }
|
||||
static func fromResultObject(result: AnyObject) -> Self
|
||||
}
|
||||
|
||||
|
||||
extension Bool: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .BooleanAttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Bool {
|
||||
|
||||
return (result as! NSNumber).boolValue
|
||||
}
|
||||
}
|
||||
|
||||
extension Int8: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int8 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int16: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int16 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int32: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int32 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int64: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int64 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt8: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> UInt8 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt16: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> UInt16 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt32: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> UInt32 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt64: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> UInt64 {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> UInt {
|
||||
|
||||
return numericCast((result as! NSNumber).longLongValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension Double: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .DoubleAttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Double {
|
||||
|
||||
return (result as! NSNumber).doubleValue
|
||||
}
|
||||
}
|
||||
|
||||
extension Float: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .FloatAttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Float {
|
||||
|
||||
return (result as! NSNumber).floatValue
|
||||
}
|
||||
}
|
||||
|
||||
extension NSNumber: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public class func fromResultObject(result: AnyObject) -> Self {
|
||||
|
||||
return self(bytes: result.bytes, objCType: result.objCType)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSDate: AggregateResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .DateAttributeType
|
||||
}
|
||||
|
||||
public class func fromResultObject(result: AnyObject) -> Self {
|
||||
|
||||
return self(timeInterval: 0.0, sinceDate: result as! NSDate)
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
*/
|
||||
public func commit(completion: (result: SaveResult) -> Void) {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.")
|
||||
HardcoreData.assert(!self.isCommitted, "Attempted to commit a <\(self.dynamicType)> more than once.")
|
||||
|
||||
self.isCommitted = true
|
||||
@@ -62,7 +62,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
*/
|
||||
public func commitAndWait() {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.")
|
||||
HardcoreData.assert(!self.isCommitted, "Attempted to commit a <\(self.dynamicType)> more than once.")
|
||||
|
||||
self.isCommitted = true
|
||||
@@ -77,6 +77,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
*/
|
||||
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a <\(self.dynamicType)> outside its designated queue.")
|
||||
HardcoreData.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed <\(self.dynamicType)>.")
|
||||
|
||||
return SynchronousDataTransaction(
|
||||
|
||||
@@ -35,63 +35,113 @@ public extension BaseDataTransaction {
|
||||
|
||||
public func fetchOne<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> T? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchOne(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchOne<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> T? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchOne(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> [T]? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> [T]? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchCount<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> Int? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchCount(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchCount<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> Int? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchCount(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectID(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectID(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectIDs(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.fetchObjectIDs(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func deleteAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> Int? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.deleteAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func deleteAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> Int? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.deleteAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> Int? {
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: FetchClause...) -> U? {
|
||||
|
||||
let result = self.context.queryAggregate(entity, function: function, queryClauses)
|
||||
return result
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.queryValue(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> Int? {
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: [FetchClause]) -> U? {
|
||||
|
||||
let result = self.context.queryAggregate(entity, function: function, queryClauses)
|
||||
return result
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.queryValue(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> U? {
|
||||
public func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.context.queryAggregate(entity, function: function, queryClauses)
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.queryAttributes(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> U? {
|
||||
public func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.context.queryAggregate(entity, function: function, queryClauses)
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
return self.context.queryAttributes(entity, selectClause, queryClauses)
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func create<T: NSManagedObject>(entity: T.Type) -> T {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to create an entity of type <\(entity)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to create an entity of type <\(entity)> outside its designated queue.")
|
||||
|
||||
return T.createInContext(self.context)
|
||||
}
|
||||
@@ -63,7 +63,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func fetch<T: NSManagedObject>(object: T) -> T? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type <\(object.dynamicType)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type <\(object.dynamicType)> outside its designated queue.")
|
||||
|
||||
return object.inContext(self.context)
|
||||
}
|
||||
@@ -75,7 +75,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func delete(object: NSManagedObject) {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete an entity of type <\(object.dynamicType)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete an entity of type <\(object.dynamicType)> outside its designated queue.")
|
||||
|
||||
object.deleteFromContext()
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
*/
|
||||
public func rollback() {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to rollback a <\(self.dynamicType)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to rollback a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
self.context.reset()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// CustomizeQuery.swift
|
||||
// CustomizeFetch.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
@@ -27,9 +27,9 @@ import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - CustomizeQuery
|
||||
// MARK: - CustomizeFetch
|
||||
|
||||
public struct CustomizeQuery: FetchClause {
|
||||
public struct CustomizeFetch: FetchClause {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
50
HardcoreData/DataStack+Observing.swift
Normal file
50
HardcoreData/DataStack+Observing.swift
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// DataStack+Observing.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
public extension DataStack {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
public func observeObjectList<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> ManagedObjectListController<T> {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
// TODO: sectionNameKeyPath and cacheResults
|
||||
return ManagedObjectListController(
|
||||
dataStack: self,
|
||||
entity: entity,
|
||||
sectionNameKeyPath: nil,
|
||||
cacheResults: false,
|
||||
queryClauses: queryClauses
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
@@ -35,63 +36,113 @@ public extension DataStack {
|
||||
|
||||
public func fetchOne<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> T? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchOne(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchOne<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> T? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchOne(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> [T]? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> [T]? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchCount<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> Int? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchCount(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchCount<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> Int? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchCount(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchObjectID(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchObjectID(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchObjectIDs(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.fetchObjectIDs(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func deleteAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> Int? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.deleteAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func deleteAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> Int? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.deleteAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> Int? {
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: FetchClause...) -> U? {
|
||||
|
||||
let result = self.mainContext.queryAggregate(entity, function: function, queryClauses)
|
||||
return result
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.queryValue(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> Int? {
|
||||
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: [FetchClause]) -> U? {
|
||||
|
||||
let result = self.mainContext.queryAggregate(entity, function: function, queryClauses)
|
||||
return result
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.queryValue(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> U? {
|
||||
public func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.mainContext.queryAggregate(entity, function: function, queryClauses)
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.queryAttributes(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> U? {
|
||||
public func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.mainContext.queryAggregate(entity, function: function, queryClauses)
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return self.mainContext.queryAttributes(entity, selectClause, queryClauses)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
@@ -40,6 +41,8 @@ public extension DataStack {
|
||||
*/
|
||||
public func beginAsynchronous(closure: (transaction: AsynchronousDataTransaction) -> Void) {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
AsynchronousDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: self.childTransactionQueue,
|
||||
@@ -54,6 +57,8 @@ public extension DataStack {
|
||||
*/
|
||||
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return SynchronousDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: self.childTransactionQueue,
|
||||
@@ -67,6 +72,8 @@ public extension DataStack {
|
||||
*/
|
||||
public func beginDetached() -> DetachedDataTransaction {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a <\(self.dynamicType)> outside the main queue.")
|
||||
|
||||
return DetachedDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: .Main)
|
||||
|
||||
@@ -105,7 +105,7 @@ public final class DataStack {
|
||||
var error: NSError?
|
||||
|
||||
var store: NSPersistentStore?
|
||||
coordinator.performSynchronously {
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSInMemoryStoreType,
|
||||
@@ -203,7 +203,7 @@ public final class DataStack {
|
||||
|
||||
var store: NSPersistentStore?
|
||||
var persistentStoreError: NSError?
|
||||
coordinator.performSynchronously {
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
@@ -238,7 +238,7 @@ public final class DataStack {
|
||||
error: nil)
|
||||
|
||||
var store: NSPersistentStore?
|
||||
coordinator.performSynchronously {
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
|
||||
@@ -41,7 +41,7 @@ public final class DetachedDataTransaction: BaseDataTransaction {
|
||||
*/
|
||||
public func commit(completion: (result: SaveResult) -> Void) {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.")
|
||||
|
||||
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
|
||||
|
||||
|
||||
@@ -29,7 +29,4 @@ import CoreData
|
||||
|
||||
// MARK: - FetchClause
|
||||
|
||||
public protocol FetchClause {
|
||||
|
||||
func applyToFetchRequest(fetchRequest: NSFetchRequest)
|
||||
}
|
||||
public protocol FetchClause: QueryClause { }
|
||||
|
||||
80
HardcoreData/GroupBy.swift
Normal file
80
HardcoreData/GroupBy.swift
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// GroupBy.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
// MARK: - GroupBy
|
||||
|
||||
public struct GroupBy: QueryClause {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
public init(_ keyPaths: [KeyPath]) {
|
||||
|
||||
self.keyPaths = keyPaths
|
||||
}
|
||||
|
||||
public init() {
|
||||
|
||||
self.init([])
|
||||
}
|
||||
|
||||
public init(_ keyPath: KeyPath, _ subKeyPaths: KeyPath...) {
|
||||
|
||||
self.init([keyPath] + subKeyPaths)
|
||||
}
|
||||
|
||||
public let keyPaths: [KeyPath]
|
||||
|
||||
|
||||
// MARK: QueryClause
|
||||
|
||||
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
|
||||
|
||||
if fetchRequest.propertiesToGroupBy != nil {
|
||||
|
||||
HardcoreData.log(.Warning, message: "An existing \"propertiesToGroupBy\" for the <\(NSFetchRequest.self)> was overwritten by <\(self.dynamicType)> query clause.")
|
||||
}
|
||||
|
||||
fetchRequest.propertiesToGroupBy = self.keyPaths
|
||||
|
||||
// let entityDescription = fetchRequest.entity!
|
||||
// let propertyMapping = entityDescription.propertiesByName
|
||||
// fetchRequest.propertiesToGroupBy = self.keyPaths.reduce([AnyObject]()) { (var properties, keyPath) -> [AnyObject] in
|
||||
//
|
||||
// if let propertyDescription: AnyObject = propertyMapping[keyPath] {
|
||||
//
|
||||
// properties.append(propertyDescription)
|
||||
// }
|
||||
// else {
|
||||
//
|
||||
// HardcoreData.log(.Warning, message: "The property \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by <\(self.dynamicType)> query clause.")
|
||||
// }
|
||||
//
|
||||
// return properties
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,26 @@ public extension HardcoreData {
|
||||
return self.defaultStack.fetchCount(entity, queryClauses)
|
||||
}
|
||||
|
||||
public static func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
return self.defaultStack.fetchObjectID(entity, queryClauses)
|
||||
}
|
||||
|
||||
public static func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
return self.defaultStack.fetchObjectID(entity, queryClauses)
|
||||
}
|
||||
|
||||
public static func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
return self.defaultStack.fetchObjectIDs(entity, queryClauses)
|
||||
}
|
||||
|
||||
public static func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
return self.defaultStack.fetchObjectIDs(entity, queryClauses)
|
||||
}
|
||||
|
||||
public static func deleteAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> Int? {
|
||||
|
||||
return self.defaultStack.deleteAll(entity, queryClauses)
|
||||
@@ -71,25 +91,23 @@ public extension HardcoreData {
|
||||
return self.defaultStack.deleteAll(entity, queryClauses)
|
||||
}
|
||||
|
||||
public static func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> Int? {
|
||||
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: FetchClause...) -> U? {
|
||||
|
||||
let result = self.defaultStack.queryAggregate(entity, function: function, queryClauses)
|
||||
return result
|
||||
return self.defaultStack.queryValue(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public static func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> Int? {
|
||||
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: [FetchClause]) -> U? {
|
||||
|
||||
let result = self.defaultStack.queryAggregate(entity, function: function, queryClauses)
|
||||
return result
|
||||
return self.defaultStack.queryValue(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public static func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> U? {
|
||||
public static func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.defaultStack.queryAggregate(entity, function: function, queryClauses)
|
||||
return self.defaultStack.queryAttributes(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
public static func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> U? {
|
||||
public static func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.defaultStack.queryAggregate(entity, function: function, queryClauses)
|
||||
return self.defaultStack.queryAttributes(entity, selectClause, queryClauses)
|
||||
}
|
||||
}
|
||||
27
HardcoreData/ManagedObjectController.swift
Normal file
27
HardcoreData/ManagedObjectController.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// ManagedObjectController.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
125
HardcoreData/ManagedObjectListController.swift
Normal file
125
HardcoreData/ManagedObjectListController.swift
Normal file
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// ManagedObjectListController.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
|
||||
// MARK: - ManagedObjectListController
|
||||
|
||||
public final class ManagedObjectListController<T: NSManagedObject>: NSFetchedResultsControllerDelegate {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
public typealias EntityType = T
|
||||
|
||||
public func addObserver<U: ManagedObjectListObserver where U.EntityType == EntityType>(observer: U) {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to add a <\(U.self)> outside the main queue.")
|
||||
|
||||
self.observers.addObject(observer)
|
||||
}
|
||||
|
||||
public func removeObserver<U: ManagedObjectListObserver where U.EntityType == EntityType>(observer: U) {
|
||||
|
||||
HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to remove a <\(U.self)> outside the main queue.")
|
||||
|
||||
self.observers.removeObject(observer)
|
||||
}
|
||||
|
||||
|
||||
// MARK: NSFetchedResultsControllerDelegate
|
||||
|
||||
private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
|
||||
|
||||
}
|
||||
|
||||
private func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
|
||||
|
||||
}
|
||||
|
||||
private func controllerWillChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
}
|
||||
|
||||
private func controllerDidChangeContent(controller: NSFetchedResultsController) {
|
||||
|
||||
}
|
||||
|
||||
private func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(dataStack: DataStack, entity: T.Type, sectionNameKeyPath: KeyPath?, cacheResults: Bool, queryClauses: [FetchClause]) {
|
||||
|
||||
let context = dataStack.mainContext
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = context.entityDescriptionForEntityClass(entity)
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectResultType
|
||||
|
||||
for clause in queryClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
let fetchedResultsController = NSFetchedResultsController(
|
||||
fetchRequest: fetchRequest,
|
||||
managedObjectContext: context,
|
||||
sectionNameKeyPath: sectionNameKeyPath,
|
||||
cacheName: (cacheResults
|
||||
? "\(ManagedObjectListController<T>.self).\(NSUUID())"
|
||||
: nil)
|
||||
)
|
||||
|
||||
|
||||
self.fetchedResultsController = fetchedResultsController
|
||||
self.parentStack = dataStack
|
||||
self.observers = NSHashTable.weakObjectsHashTable()
|
||||
|
||||
fetchedResultsController.delegate = self
|
||||
|
||||
var error: NSError?
|
||||
if !fetchedResultsController.performFetch(&error) {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error ?? NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
"Failed to perform fetch on \(NSFetchedResultsController.self)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let fetchedResultsController: NSFetchedResultsController
|
||||
private weak var parentStack: DataStack?
|
||||
private let observers: NSHashTable
|
||||
}
|
||||
80
HardcoreData/ManagedObjectListObserver.swift
Normal file
80
HardcoreData/ManagedObjectListObserver.swift
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// ManagedObjectListObserver.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - ManagedObjectListObserver
|
||||
|
||||
public protocol ManagedObjectListObserver: class {
|
||||
|
||||
typealias EntityType: NSManagedObject
|
||||
|
||||
func managedObjectListWillChange(listController: ManagedObjectListController<EntityType>)
|
||||
|
||||
|
||||
// func managedObjectList(listController: ManagedObjectListController<EntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int)
|
||||
//
|
||||
// func managedObjectList(listController: ManagedObjectListController<EntityType>, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int)
|
||||
//
|
||||
// func managedObjectList(listController: ManagedObjectListController<EntityType>, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int)
|
||||
//
|
||||
// func managedObjectList(listController: ManagedObjectListController<EntityType>, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int)
|
||||
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didInsertObject object: EntityType, toItemIndex itemIndex: Int)
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didDeleteObject object: EntityType, fromItemIndex itemIndex: Int)
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didUpdateObject object: EntityType, atItemIndex itemIndex: Int)
|
||||
|
||||
func managedObjectList(listController: ManagedObjectListController<EntityType>, didMoveObject object: EntityType, fromItemIndex: Int, toItemIndex: Int)
|
||||
|
||||
|
||||
func managedObjectListDidChange(listController: ManagedObjectListController<EntityType>)
|
||||
|
||||
|
||||
// private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private func controllerWillChangeContent(controller: NSFetchedResultsController) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private func controllerDidChangeContent(controller: NSFetchedResultsController) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? {
|
||||
//
|
||||
// return nil
|
||||
// }
|
||||
}
|
||||
13
HardcoreData/ManagedObjectListSectionInfo.swift
Normal file
13
HardcoreData/ManagedObjectListSectionInfo.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// ManagedObjectListSectionInfo.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/03/11.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ManagedObjectListSectionInfo: NSObject {
|
||||
|
||||
}
|
||||
@@ -133,6 +133,74 @@ internal extension NSManagedObjectContext {
|
||||
return count
|
||||
}
|
||||
|
||||
internal func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
|
||||
return self.fetchObjectID(entity, queryClauses)
|
||||
}
|
||||
|
||||
internal func fetchObjectID<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = self.entityDescriptionForEntityClass(entity)
|
||||
fetchRequest.fetchLimit = 1
|
||||
fetchRequest.resultType = .ManagedObjectIDResultType
|
||||
|
||||
for clause in queryClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [NSManagedObjectID]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error ?? NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults?.first
|
||||
}
|
||||
|
||||
internal func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
|
||||
return self.fetchObjectIDs(entity, queryClauses)
|
||||
}
|
||||
|
||||
internal func fetchObjectIDs<T: NSManagedObject>(entity: T.Type, _ queryClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = self.entityDescriptionForEntityClass(entity)
|
||||
fetchRequest.fetchLimit = 0
|
||||
fetchRequest.resultType = .ManagedObjectIDResultType
|
||||
|
||||
for clause in queryClauses {
|
||||
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [NSManagedObjectID]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObjectID]
|
||||
}
|
||||
if fetchResults == nil {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error ?? NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return fetchResults
|
||||
}
|
||||
|
||||
internal func deleteAll<T: NSManagedObject>(entity: T.Type, _ queryClauses: FetchClause...) -> Int? {
|
||||
|
||||
return self.deleteAll(entity, queryClauses)
|
||||
@@ -178,38 +246,18 @@ internal extension NSManagedObjectContext {
|
||||
return numberOfDeletedObjects
|
||||
}
|
||||
|
||||
internal func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> Int? {
|
||||
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: FetchClause...) -> U? {
|
||||
|
||||
return self.queryAggregateImplementation(entity, function: function, queryClauses)
|
||||
return self.queryValue(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
internal func queryAggregate<T: NSManagedObject>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> Int? {
|
||||
|
||||
return self.queryAggregateImplementation(entity, function: function, queryClauses)
|
||||
}
|
||||
|
||||
internal func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: FetchClause...) -> U? {
|
||||
|
||||
return self.queryAggregateImplementation(entity, function: function, queryClauses)
|
||||
}
|
||||
|
||||
internal func queryAggregate<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> U? {
|
||||
|
||||
return self.queryAggregateImplementation(entity, function: function, queryClauses)
|
||||
}
|
||||
|
||||
internal func queryAggregateImplementation<T: NSManagedObject, U: AggregateResultType>(entity: T.Type, function: AggregateFunction, _ queryClauses: [FetchClause]) -> U? {
|
||||
|
||||
let expressionDescription = NSExpressionDescription()
|
||||
expressionDescription.name = "queryAggregate"
|
||||
expressionDescription.expressionResultType = U.attributeType
|
||||
expressionDescription.expression = function.createExpression()
|
||||
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(entity: T.Type, _ selectClause: Select<U>, _ queryClauses: [FetchClause]) -> U? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = self.entityDescriptionForEntityClass(entity)
|
||||
fetchRequest.resultType = .DictionaryResultType
|
||||
fetchRequest.propertiesToFetch = [expressionDescription]
|
||||
fetchRequest.includesPendingChanges = false
|
||||
fetchRequest.fetchLimit = 0
|
||||
|
||||
selectClause.applyToFetchRequest(fetchRequest)
|
||||
|
||||
for clause in queryClauses {
|
||||
|
||||
@@ -222,19 +270,54 @@ internal extension NSManagedObjectContext {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
|
||||
}
|
||||
if fetchResults == nil {
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
HardcoreData.handleError(
|
||||
error ?? NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
if let rawResult = fetchResults.first as? NSDictionary,
|
||||
let rawObject: AnyObject = rawResult[selectClause.keyPathForFirstSelectTerm()] {
|
||||
|
||||
return Select<U>.ReturnType.fromResultObject(rawObject)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if let result: AnyObject = (fetchResults?.first as! [String: AnyObject])[expressionDescription.name] {
|
||||
HardcoreData.handleError(
|
||||
error ?? NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
|
||||
internal func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
|
||||
|
||||
return self.queryAttributes(entity, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
internal func queryAttributes<T: NSManagedObject>(entity: T.Type, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
|
||||
|
||||
let fetchRequest = NSFetchRequest()
|
||||
fetchRequest.entity = self.entityDescriptionForEntityClass(entity)
|
||||
fetchRequest.fetchLimit = 0
|
||||
|
||||
selectClause.applyToFetchRequest(fetchRequest)
|
||||
|
||||
for clause in queryClauses {
|
||||
|
||||
return U.fromResultObject(result)
|
||||
clause.applyToFetchRequest(fetchRequest)
|
||||
}
|
||||
|
||||
var fetchResults: [AnyObject]?
|
||||
var error: NSError?
|
||||
self.performBlockAndWait {
|
||||
|
||||
fetchResults = self.executeFetchRequest(fetchRequest, error: &error)
|
||||
}
|
||||
if let fetchResults = fetchResults {
|
||||
|
||||
return Select<NSDictionary>.ReturnType.fromResultObjects(fetchResults)
|
||||
}
|
||||
|
||||
HardcoreData.handleError(
|
||||
error ?? NSError(hardcoreDataErrorCode: .UnknownError),
|
||||
"Failed executing fetch request.")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
//
|
||||
// NSPersistentStoreCoordinator+HardcoreData.swift
|
||||
// QueryClause.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2014 John Rommel Estropia
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -27,23 +27,9 @@ import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - NSPersistentStoreCoordinator
|
||||
// MARK: - QueryClause
|
||||
|
||||
internal extension NSPersistentStoreCoordinator {
|
||||
public protocol QueryClause {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func performSynchronously(closure: () -> Void) {
|
||||
|
||||
if self.respondsToSelector("performBlockAndWait:") {
|
||||
|
||||
self.performBlockAndWait(closure)
|
||||
}
|
||||
else {
|
||||
|
||||
self.lock()
|
||||
autoreleasepool(closure)
|
||||
self.unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
func applyToFetchRequest(fetchRequest: NSFetchRequest)
|
||||
}
|
||||
515
HardcoreData/Select.swift
Normal file
515
HardcoreData/Select.swift
Normal file
@@ -0,0 +1,515 @@
|
||||
//
|
||||
// Select.swift
|
||||
// HardcoreData
|
||||
//
|
||||
// Copyright (c) 2015 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - SelectResultType
|
||||
|
||||
public protocol SelectResultType { }
|
||||
|
||||
|
||||
// MARK: - SelectValueResultType
|
||||
|
||||
public protocol SelectValueResultType: SelectResultType {
|
||||
|
||||
static func fromResultObject(result: AnyObject) -> Self?
|
||||
}
|
||||
|
||||
|
||||
// MARK: - SelectAttributesResultType
|
||||
|
||||
public protocol SelectAttributesResultType: SelectResultType {
|
||||
|
||||
static func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]]
|
||||
}
|
||||
|
||||
|
||||
// MARK: - SelectTerm
|
||||
|
||||
public enum SelectTerm: StringLiteralConvertible {
|
||||
|
||||
case Attribute(KeyPath)
|
||||
case Aggregate(function: String, KeyPath, As: String)
|
||||
|
||||
public static func Average(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return .Aggregate(
|
||||
function: "average:",
|
||||
keyPath,
|
||||
As: alias ?? "average(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
public static func Count(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return .Aggregate(
|
||||
function: "count:",
|
||||
keyPath,
|
||||
As: alias ?? "count(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
public static func Maximum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return .Aggregate(
|
||||
function: "max:",
|
||||
keyPath,
|
||||
As: alias ?? "max(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
public static func Median(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return .Aggregate(
|
||||
function: "median:",
|
||||
keyPath, As:
|
||||
alias ?? "median(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
public static func Minimum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return .Aggregate(
|
||||
function: "min:",
|
||||
keyPath,
|
||||
As: alias ?? "min(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
public static func StandardDeviation(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return .Aggregate(
|
||||
function: "stddev:",
|
||||
keyPath,
|
||||
As: alias ?? "stddev(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
public static func Sum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return .Aggregate(
|
||||
function: "sum:",
|
||||
keyPath,
|
||||
As: alias ?? "sum(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
public init(stringLiteral value: KeyPath) {
|
||||
|
||||
self = .Attribute(value)
|
||||
}
|
||||
|
||||
public init(unicodeScalarLiteral value: KeyPath) {
|
||||
|
||||
self = .Attribute(value)
|
||||
}
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: KeyPath) {
|
||||
|
||||
self = .Attribute(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Select
|
||||
|
||||
public struct Select<T: SelectResultType> {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
public typealias ReturnType = T
|
||||
|
||||
public init(_ selectTerm: SelectTerm, _ selectTerms: SelectTerm...) {
|
||||
|
||||
self.selectTerms = [selectTerm] + selectTerms
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func applyToFetchRequest(fetchRequest: NSFetchRequest) {
|
||||
|
||||
if fetchRequest.propertiesToFetch != nil {
|
||||
|
||||
HardcoreData.log(.Warning, message: "An existing \"propertiesToFetch\" for the <\(NSFetchRequest.self)> was overwritten by <\(self.dynamicType)> query clause.")
|
||||
}
|
||||
|
||||
fetchRequest.includesPendingChanges = false
|
||||
fetchRequest.resultType = .DictionaryResultType
|
||||
|
||||
let entityDescription = fetchRequest.entity!
|
||||
let propertiesByName = entityDescription.propertiesByName
|
||||
let attributesByName = entityDescription.attributesByName
|
||||
|
||||
var propertiesToFetch = [AnyObject]()
|
||||
for term in self.selectTerms {
|
||||
|
||||
switch term {
|
||||
|
||||
case .Attribute(let keyPath):
|
||||
if let propertyDescription = propertiesByName[keyPath] as? NSPropertyDescription {
|
||||
|
||||
propertiesToFetch.append(propertyDescription)
|
||||
}
|
||||
else {
|
||||
|
||||
HardcoreData.log(.Warning, message: "The property \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by <\(self.dynamicType)> query clause.")
|
||||
}
|
||||
|
||||
case .Aggregate(let function, let keyPath, let alias):
|
||||
if let attributeDescription = attributesByName[keyPath] as? NSAttributeDescription {
|
||||
|
||||
let expressionDescription = NSExpressionDescription()
|
||||
expressionDescription.name = alias
|
||||
expressionDescription.expressionResultType = attributeDescription.attributeType
|
||||
expressionDescription.expression = NSExpression(
|
||||
forFunction: function,
|
||||
arguments: [NSExpression(forKeyPath: keyPath)]
|
||||
)
|
||||
|
||||
propertiesToFetch.append(expressionDescription)
|
||||
}
|
||||
else {
|
||||
|
||||
HardcoreData.log(.Warning, message: "The attribute \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by <\(self.dynamicType)> query clause.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchRequest.propertiesToFetch = propertiesToFetch
|
||||
}
|
||||
|
||||
internal func keyPathForFirstSelectTerm() -> KeyPath {
|
||||
|
||||
switch self.selectTerms.first! {
|
||||
|
||||
case .Attribute(let keyPath):
|
||||
return keyPath
|
||||
|
||||
case .Aggregate(_, _, let alias):
|
||||
return alias
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let selectTerms: [SelectTerm]
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Bool: SelectValueResultType
|
||||
|
||||
extension Bool: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .BooleanAttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Bool? {
|
||||
|
||||
return (result as? NSNumber)?.boolValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Int8: SelectValueResultType
|
||||
|
||||
extension Int8: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int8? {
|
||||
|
||||
if let value = (result as? NSNumber)?.longLongValue {
|
||||
|
||||
return numericCast(value) as Int8
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Int16: SelectValueResultType
|
||||
|
||||
extension Int16: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int16? {
|
||||
|
||||
if let value = (result as? NSNumber)?.longLongValue {
|
||||
|
||||
return numericCast(value) as Int16
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Int32: SelectValueResultType
|
||||
|
||||
extension Int32: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int32? {
|
||||
|
||||
if let value = (result as? NSNumber)?.longLongValue {
|
||||
|
||||
return numericCast(value) as Int32
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Int64: SelectValueResultType
|
||||
|
||||
extension Int64: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int64? {
|
||||
|
||||
return (result as? NSNumber)?.longLongValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Int: SelectValueResultType
|
||||
|
||||
extension Int: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Int? {
|
||||
|
||||
if let value = (result as? NSNumber)?.longLongValue {
|
||||
|
||||
return numericCast(value) as Int
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Double : SelectValueResultType
|
||||
|
||||
extension Double: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .DoubleAttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Double? {
|
||||
|
||||
return (result as? NSNumber)?.doubleValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Float: SelectValueResultType
|
||||
|
||||
extension Float: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .FloatAttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> Float? {
|
||||
|
||||
return (result as? NSNumber)?.floatValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - String: SelectValueResultType
|
||||
|
||||
extension String: SelectValueResultType {
|
||||
|
||||
public static var attributeType: NSAttributeType {
|
||||
|
||||
return .StringAttributeType
|
||||
}
|
||||
|
||||
public static func fromResultObject(result: AnyObject) -> String? {
|
||||
|
||||
return result as? NSString as? String
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSNumber: SelectValueResultType
|
||||
|
||||
extension NSNumber: SelectValueResultType {
|
||||
|
||||
public class var attributeType: NSAttributeType {
|
||||
|
||||
return .Integer64AttributeType
|
||||
}
|
||||
|
||||
public class func fromResultObject(result: AnyObject) -> Self? {
|
||||
|
||||
func forceCast<T: NSNumber>(object: AnyObject) -> T? {
|
||||
|
||||
return (object as? T)
|
||||
}
|
||||
return forceCast(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSString: SelectValueResultType
|
||||
|
||||
extension NSString: SelectValueResultType {
|
||||
|
||||
public class var attributeType: NSAttributeType {
|
||||
|
||||
return .StringAttributeType
|
||||
}
|
||||
|
||||
public class func fromResultObject(result: AnyObject) -> Self? {
|
||||
|
||||
func forceCast<T: NSString>(object: AnyObject) -> T? {
|
||||
|
||||
return (object as? T)
|
||||
}
|
||||
return forceCast(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSDecimalNumber: SelectValueResultType
|
||||
|
||||
extension NSDecimalNumber: SelectValueResultType {
|
||||
|
||||
public override class var attributeType: NSAttributeType {
|
||||
|
||||
return .DecimalAttributeType
|
||||
}
|
||||
|
||||
public override class func fromResultObject(result: AnyObject) -> Self? {
|
||||
|
||||
func forceCast<T: NSDecimalNumber>(object: AnyObject) -> T? {
|
||||
|
||||
return (object as? T)
|
||||
}
|
||||
return forceCast(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSDate: SelectValueResultType
|
||||
|
||||
extension NSDate: SelectValueResultType {
|
||||
|
||||
public class var attributeType: NSAttributeType {
|
||||
|
||||
return .DateAttributeType
|
||||
}
|
||||
|
||||
public class func fromResultObject(result: AnyObject) -> Self? {
|
||||
|
||||
func forceCast<T: NSDate>(object: AnyObject) -> T? {
|
||||
|
||||
return (object as? T)
|
||||
}
|
||||
return forceCast(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSData: SelectValueResultType
|
||||
|
||||
extension NSData: SelectValueResultType {
|
||||
|
||||
public class var attributeType: NSAttributeType {
|
||||
|
||||
return .BinaryDataAttributeType
|
||||
}
|
||||
|
||||
public class func fromResultObject(result: AnyObject) -> Self? {
|
||||
|
||||
func forceCast<T: NSData>(object: AnyObject) -> T? {
|
||||
|
||||
return (object as? T)
|
||||
}
|
||||
return forceCast(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSManagedObjectID: SelectValueResultType
|
||||
|
||||
extension NSManagedObjectID: SelectValueResultType {
|
||||
|
||||
public class var attributeType: NSAttributeType {
|
||||
|
||||
return .ObjectIDAttributeType
|
||||
}
|
||||
|
||||
public class func fromResultObject(result: AnyObject) -> Self? {
|
||||
|
||||
func forceCast<T: NSManagedObjectID>(object: AnyObject) -> T? {
|
||||
|
||||
return (object as? T)
|
||||
}
|
||||
return forceCast(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSManagedObjectID: SelectAttributesResultType
|
||||
|
||||
extension NSDictionary: SelectAttributesResultType {
|
||||
|
||||
// MARK: SelectAttributesResultType
|
||||
|
||||
public class func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]] {
|
||||
|
||||
return result as! [[NSString: AnyObject]]
|
||||
}
|
||||
}
|
||||
@@ -32,17 +32,17 @@ public func +(left: SortedBy, right: SortedBy) -> SortedBy {
|
||||
}
|
||||
|
||||
|
||||
// MARK: - AttributeName
|
||||
// MARK: - KeyPath
|
||||
|
||||
public typealias AttributeName = Selector
|
||||
public typealias KeyPath = String
|
||||
|
||||
|
||||
// MARK: - SortOrder
|
||||
|
||||
public enum SortOrder {
|
||||
|
||||
case Ascending(AttributeName)
|
||||
case Descending(AttributeName)
|
||||
case Ascending(KeyPath)
|
||||
case Descending(KeyPath)
|
||||
}
|
||||
|
||||
|
||||
@@ -69,21 +69,19 @@ public struct SortedBy: FetchClause {
|
||||
|
||||
public init(_ order: [SortOrder]) {
|
||||
|
||||
self.init(order.map { sortOrder -> NSSortDescriptor in
|
||||
|
||||
switch sortOrder {
|
||||
self.init(
|
||||
order.map { sortOrder -> NSSortDescriptor in
|
||||
|
||||
case .Ascending(let attributeName):
|
||||
return NSSortDescriptor(
|
||||
key: NSStringFromSelector(attributeName),
|
||||
ascending: true)
|
||||
|
||||
case .Descending(let attributeName):
|
||||
return NSSortDescriptor(
|
||||
key: NSStringFromSelector(attributeName),
|
||||
ascending: false)
|
||||
switch sortOrder {
|
||||
|
||||
case .Ascending(let keyPath):
|
||||
return NSSortDescriptor(key: keyPath, ascending: true)
|
||||
|
||||
case .Descending(let keyPath):
|
||||
return NSSortDescriptor(key: keyPath, ascending: false)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
public init(_ order: SortOrder, _ subOrder: SortOrder...) {
|
||||
|
||||
@@ -20,7 +20,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
|
||||
*/
|
||||
public func commitAndWait() {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside a transaction queue.")
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.")
|
||||
HardcoreData.assert(!self.isCommitted, "Attempted to commit a <\(self.dynamicType)> more than once.")
|
||||
|
||||
self.isCommitted = true
|
||||
@@ -35,6 +35,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
|
||||
*/
|
||||
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a <\(self.dynamicType)> outside its designated queue.")
|
||||
HardcoreData.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed <\(self.dynamicType)>.")
|
||||
|
||||
return SynchronousDataTransaction(
|
||||
|
||||
@@ -68,16 +68,16 @@ public struct Where: FetchClause {
|
||||
self.init(NSPredicate(format: format, argumentArray: args))
|
||||
}
|
||||
|
||||
public init(_ format: String, argumentArray: [AnyObject]?) {
|
||||
public init(_ format: String, argumentArray: [NSObject]?) {
|
||||
|
||||
self.init(NSPredicate(format: format, argumentArray: argumentArray))
|
||||
}
|
||||
|
||||
public init(_ attributeName: AttributeName, isEqualTo value: NSObject?) {
|
||||
public init(_ keyPath: KeyPath, isEqualTo value: NSObject?) {
|
||||
|
||||
self.init(value == nil
|
||||
? NSPredicate(format: "\(attributeName) == nil")
|
||||
: NSPredicate(format: "\(attributeName) == %@", value!))
|
||||
? NSPredicate(format: "\(keyPath) == nil")
|
||||
: NSPredicate(format: "\(keyPath) == %@", value!))
|
||||
}
|
||||
|
||||
public let predicate: NSPredicate
|
||||
|
||||
@@ -76,9 +76,9 @@ class HardcoreDataTests: XCTestCase {
|
||||
obj1.testNumber = 42
|
||||
obj1.testDate = NSDate()
|
||||
|
||||
let count = transaction.queryAggregate(
|
||||
let count = transaction.queryValue(
|
||||
TestEntity1.self,
|
||||
function: .Count("testNumber")
|
||||
Select<Int>(.Count("testNumber"))
|
||||
)
|
||||
XCTAssertTrue(count == 0, "count == 0 (actual: \(count))") // counts only objects in store
|
||||
|
||||
@@ -90,10 +90,16 @@ class HardcoreDataTests: XCTestCase {
|
||||
|
||||
let obj3 = transaction.create(TestEntity2)
|
||||
obj3.testEntityID = 3
|
||||
obj3.testString = "hohoho"
|
||||
obj3.testString = "hahaha"
|
||||
obj3.testNumber = 90
|
||||
obj3.testDate = NSDate()
|
||||
|
||||
let obj4 = transaction.create(TestEntity2)
|
||||
obj4.testEntityID = 5
|
||||
obj4.testString = "hohoho"
|
||||
obj4.testNumber = 80
|
||||
obj4.testDate = NSDate()
|
||||
|
||||
|
||||
transaction.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
@@ -106,12 +112,23 @@ class HardcoreDataTests: XCTestCase {
|
||||
let objs4test = transaction.fetchOne(
|
||||
TestEntity2.self,
|
||||
Where("testEntityID", isEqualTo: 4),
|
||||
CustomizeQuery { (fetchRequest) -> Void in
|
||||
CustomizeFetch { (fetchRequest) -> Void in
|
||||
|
||||
fetchRequest.includesPendingChanges = true
|
||||
}
|
||||
)
|
||||
XCTAssertNotNil(objs4test, "objs4test != nil")
|
||||
|
||||
let objs5test = transaction.fetchOne(
|
||||
TestEntity2.self,
|
||||
Where("testEntityID", isEqualTo: 4),
|
||||
CustomizeFetch { (fetchRequest) -> Void in
|
||||
|
||||
fetchRequest.includesPendingChanges = false
|
||||
}
|
||||
)
|
||||
XCTAssertNil(objs5test, "objs5test == nil")
|
||||
|
||||
// Dont commit1
|
||||
}
|
||||
|
||||
@@ -119,12 +136,16 @@ class HardcoreDataTests: XCTestCase {
|
||||
|
||||
let objs4test = HardcoreData.fetchOne(
|
||||
TestEntity2.self,
|
||||
Where("testEntityID", isEqualTo: 4)
|
||||
Where("testEntityID", isEqualTo: 4),
|
||||
CustomizeFetch { (fetchRequest) -> Void in
|
||||
|
||||
fetchRequest.includesPendingChanges = false
|
||||
}
|
||||
)
|
||||
XCTAssertNil(objs4test, "objs4test == nil")
|
||||
|
||||
let objs5test = detachedTransaction.fetchCount(TestEntity2)
|
||||
XCTAssertTrue(objs5test == 2, "objs5test == 2")
|
||||
XCTAssertTrue(objs5test == 3, "objs5test == 3")
|
||||
|
||||
XCTAssertTrue(NSThread.isMainThread(), "NSThread.isMainThread()")
|
||||
switch result {
|
||||
@@ -149,7 +170,7 @@ class HardcoreDataTests: XCTestCase {
|
||||
TestEntity2.self,
|
||||
Where("testNumber", isEqualTo: 100) || Where("%K == %@", "testNumber", 90),
|
||||
SortedBy(.Ascending("testEntityID"), .Descending("testString")),
|
||||
CustomizeQuery { (fetchRequest) -> Void in
|
||||
CustomizeFetch { (fetchRequest) -> Void in
|
||||
|
||||
fetchRequest.includesPendingChanges = true
|
||||
}
|
||||
@@ -159,6 +180,13 @@ class HardcoreDataTests: XCTestCase {
|
||||
|
||||
transaction.commit { (result) -> Void in
|
||||
|
||||
let counts = HardcoreData.queryAttributes(
|
||||
TestEntity2.self,
|
||||
Select(.Count("testString", As: "count"), "testString"),
|
||||
GroupBy("testString")
|
||||
)
|
||||
println(counts)
|
||||
|
||||
XCTAssertTrue(NSThread.isMainThread(), "NSThread.isMainThread()")
|
||||
switch result {
|
||||
|
||||
@@ -174,15 +202,15 @@ class HardcoreDataTests: XCTestCase {
|
||||
|
||||
self.waitForExpectationsWithTimeout(100, handler: nil)
|
||||
|
||||
let max1 = HardcoreData.queryAggregate(
|
||||
let max1 = HardcoreData.queryValue(
|
||||
TestEntity2.self,
|
||||
function: .Maximum("testNumber")
|
||||
Select<Int>(.Maximum("testNumber"))
|
||||
)
|
||||
XCTAssertTrue(max1 == 100, "max == 100 (actual: \(max1))")
|
||||
|
||||
let max2 = HardcoreData.queryAggregate(
|
||||
let max2 = HardcoreData.queryValue(
|
||||
TestEntity2.self,
|
||||
function: .Maximum("testNumber"),
|
||||
Select<NSNumber>(.Maximum("testNumber")),
|
||||
Where("%K > %@", "testEntityID", 2)
|
||||
)
|
||||
XCTAssertTrue(max2 == 90, "max == 90 (actual: \(max2))")
|
||||
@@ -196,7 +224,7 @@ class HardcoreDataTests: XCTestCase {
|
||||
TestEntity2.self,
|
||||
Where("%K > %@", "testEntityID", 2)
|
||||
)
|
||||
XCTAssertTrue(numberOfDeletedObjects2 == 1, "numberOfDeletedObjects2 == 1 (actual: \(numberOfDeletedObjects2))")
|
||||
XCTAssertTrue(numberOfDeletedObjects2 == 2, "numberOfDeletedObjects2 == 2 (actual: \(numberOfDeletedObjects2))")
|
||||
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
@@ -225,9 +253,9 @@ class HardcoreDataTests: XCTestCase {
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges, "hasChanges == true")
|
||||
|
||||
let count = HardcoreData.queryAggregate(
|
||||
let count: Int? = HardcoreData.queryValue(
|
||||
TestEntity1.self,
|
||||
function: .Count("testNumber")
|
||||
Select(.Count("testNumber"))
|
||||
)
|
||||
XCTAssertTrue(count == 1, "count == 1 (actual: \(count))")
|
||||
|
||||
@@ -245,9 +273,9 @@ class HardcoreDataTests: XCTestCase {
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges, "hasChanges == true")
|
||||
|
||||
let count = HardcoreData.queryAggregate(
|
||||
let count = HardcoreData.queryValue(
|
||||
TestEntity1.self,
|
||||
function: .Count("testNumber")
|
||||
Select<Int>(.Count("testNumber"))
|
||||
)
|
||||
XCTAssertTrue(count == 2, "count == 2 (actual: \(count))")
|
||||
|
||||
|
||||
@@ -32,5 +32,4 @@ class TestEntity1: NSManagedObject {
|
||||
@NSManaged var testString: String?
|
||||
@NSManaged var testNumber: NSNumber?
|
||||
@NSManaged var testDate: NSDate?
|
||||
|
||||
}
|
||||
|
||||
@@ -33,4 +33,5 @@ class TestEntity2: NSManagedObject {
|
||||
@NSManaged var testNumber: NSNumber?
|
||||
@NSManaged var testDate: NSDate?
|
||||
|
||||
var testProperty: NSNumber?
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user