Compare commits

...

11 Commits

Author SHA1 Message Date
John Estropia
0376ac6908 bump 2019-02-28 18:57:28 +09:00
John Estropia
b3421888a6 version bump 2019-02-28 18:55:32 +09:00
John Estropia
7b3f4ae0a4 fix compile error 2019-02-28 17:58:17 +09:00
John Estropia
b4e12cc922 restore NSPersistentStore.affectedStores ARC bug workaround 2019-02-28 17:57:34 +09:00
John Estropia
6c282b18af version bump 2019-02-28 13:14:27 +09:00
John Estropia
ebbde8b7b6 minor fix in demo app 2019-02-28 13:13:01 +09:00
John Estropia
a1407e4121 Revert workaround for iOS 10 NSFetchedResultsController (#100) 2019-02-28 13:07:47 +09:00
John Estropia
99b871b97a add missing documentations for Where.Expression, updated playgrounds 2019-02-20 18:47:29 +09:00
John Estropia
1cd3c4fcf4 fix compile error 2019-02-12 18:18:44 +09:00
John Estropia
e09ac9ee00 add macOS playground 2019-02-12 18:05:06 +09:00
John Estropia
4b0d134acb remove swift 5 annotation 2019-02-12 18:03:59 +09:00
36 changed files with 875 additions and 241 deletions

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ CoreStore.xcworkspace/xcuserdata
DerivedData
*.orig
build
Playground_macOS.playground/playground.xcworkspace/xcuserdata

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "6.0.0"
s.version = "6.2.1"
s.swift_version = "4.2"
s.license = "MIT"
s.homepage = "https://github.com/JohnEstropia/CoreStore"

View File

@@ -293,6 +293,10 @@
B546F9741C9C553300D5AC55 /* SetupResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B546F9721C9C553300D5AC55 /* SetupResult.swift */; };
B546F9751C9C553300D5AC55 /* SetupResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B546F9721C9C553300D5AC55 /* SetupResult.swift */; };
B546F9761C9C553300D5AC55 /* SetupResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B546F9721C9C553300D5AC55 /* SetupResult.swift */; };
B5474D152227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5474D142227C08700B21FEC /* CoreStoreFetchRequest.swift */; };
B5474D162227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5474D142227C08700B21FEC /* CoreStoreFetchRequest.swift */; };
B5474D172227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5474D142227C08700B21FEC /* CoreStoreFetchRequest.swift */; };
B5474D182227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5474D142227C08700B21FEC /* CoreStoreFetchRequest.swift */; };
B5489F3F1CF5EEBC008B4978 /* TestEntity1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5489F3D1CF5EEBC008B4978 /* TestEntity1.swift */; };
B5489F401CF5EEBC008B4978 /* TestEntity1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5489F3D1CF5EEBC008B4978 /* TestEntity1.swift */; };
B5489F411CF5EEBC008B4978 /* TestEntity1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5489F3D1CF5EEBC008B4978 /* TestEntity1.swift */; };
@@ -823,6 +827,7 @@
B546F95C1C9A12B800D5AC55 /* CSSQliteStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSQliteStore.swift; sourceTree = "<group>"; };
B546F9681C9AF26D00D5AC55 /* CSInMemoryStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSInMemoryStore.swift; sourceTree = "<group>"; };
B546F9721C9C553300D5AC55 /* SetupResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetupResult.swift; sourceTree = "<group>"; };
B5474D142227C08700B21FEC /* CoreStoreFetchRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreStoreFetchRequest.swift; sourceTree = "<group>"; };
B5489F3D1CF5EEBC008B4978 /* TestEntity1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity1.swift; sourceTree = "<group>"; };
B5489F3E1CF5EEBC008B4978 /* TestEntity2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity2.swift; sourceTree = "<group>"; };
B5489F451CF5F017008B4978 /* TransactionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionTests.swift; sourceTree = "<group>"; };
@@ -880,6 +885,8 @@
B5A1DAC71F111BFA003CF369 /* KeyPath+Querying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyPath+Querying.swift"; sourceTree = "<group>"; };
B5A261201B64BFDB006EB6D3 /* MigrationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationType.swift; sourceTree = "<group>"; };
B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSelect.swift; sourceTree = "<group>"; };
B5A80DF42212C1AB006096AA /* Playground_macOS.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground_macOS.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
B5A80DF52212C1BC006096AA /* Playground_iOS.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground_iOS.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
B5A991EB1E9DC2CE0091A2E3 /* VersionLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionLock.swift; sourceTree = "<group>"; };
B5A9921E1EA898710091A2E3 /* UserInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = "<group>"; };
B5AD60CD1C90141E00F2B2E8 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; };
@@ -961,7 +968,6 @@
B5E84F351AFF85470064E85B /* NSManagedObjectContext+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Querying.swift"; sourceTree = "<group>"; };
B5E84F401AFF8CCD0064E85B /* TypeErasedClauses.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeErasedClauses.swift; sourceTree = "<group>"; };
B5E8A71F21C1015300EF006A /* CoreStoreObject+Observing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CoreStoreObject+Observing.swift"; sourceTree = "<group>"; };
B5E8A72621C3B85000EF006A /* Playground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
B5ECDBDE1CA6BB2B00C7F112 /* CSBaseDataTransaction+Querying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSBaseDataTransaction+Querying.swift"; sourceTree = "<group>"; };
B5ECDBE41CA6BEA300C7F112 /* CSClauseTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSClauseTypes.swift; sourceTree = "<group>"; };
B5ECDBEB1CA6BF2000C7F112 /* CSFrom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSFrom.swift; sourceTree = "<group>"; };
@@ -1052,7 +1058,8 @@
2F03A52619C5C6DA005002A5 = {
isa = PBXGroup;
children = (
B5E8A72621C3B85000EF006A /* Playground.playground */,
B5A80DF52212C1BC006096AA /* Playground_iOS.playground */,
B5A80DF42212C1AB006096AA /* Playground_macOS.playground */,
2F291E3119C6D4D3007AF63F /* Frameworks */,
2F03A53219C5C6DA005002A5 /* Sources */,
2F03A53C19C5C6DA005002A5 /* CoreStoreTests */,
@@ -1537,6 +1544,7 @@
children = (
B5831B6F1F34AC3400A9F647 /* AttributeProtocol.swift */,
B5831B741F34AC7A00A9F647 /* RelationshipProtocol.swift */,
B5474D142227C08700B21FEC /* CoreStoreFetchRequest.swift */,
B5C976E61C6E3A5900B1AF90 /* CoreStoreFetchedResultsController.swift */,
B53B275E1EE3B92E00E9B352 /* CoreStoreManagedObject.swift */,
B533C4DA1D7D4BFA001383CB /* DispatchQueue+CoreStore.swift */,
@@ -2026,6 +2034,7 @@
B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B5E8A72021C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
B5474D152227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */,
B56923FF1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CAE1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
B5ECDBEC1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
@@ -2224,6 +2233,7 @@
B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B5E8A72121C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
B5474D162227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */,
B56924001EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CAF1FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */,
@@ -2422,6 +2432,7 @@
B5220E201D130813009BC71E /* CSObjectMonitor.swift in Sources */,
B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B5E8A72321C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
B5474D182227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */,
B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CB11FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */,
@@ -2620,6 +2631,7 @@
B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B5E8A72221C1015300EF006A /* CoreStoreObject+Observing.swift in Sources */,
B5474D172227C08700B21FEC /* CoreStoreFetchRequest.swift in Sources */,
B56924011EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5215CB01FA4812500139E3A /* SectionMonitorBuilder.swift in Sources */,
B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */,

View File

@@ -313,6 +313,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
@IBAction private dynamic func shuffleBarButtonItemTouched(_ sender: AnyObject?) {
self.setTable(enabled: false)
ColorsDemo.stack.perform(
asynchronous: { (transaction) in
@@ -322,12 +323,16 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
palette.colorName .= nil
}
},
completion: { _ in }
completion: { _ in
self.setTable(enabled: true)
}
)
}
private func setTable(enabled: Bool) {
tableView.isUserInteractionEnabled = enabled
UIView.animate(
withDuration: 0.2,
delay: 0,
@@ -337,7 +342,6 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.isUserInteractionEnabled = enabled
}
},
completion: nil

View File

@@ -141,10 +141,8 @@ class DynamicModelTests: BaseTestDataTestCase {
let k1 = String(keyPath: \Animal.species)
XCTAssertEqual(k1, "species")
#if swift(<5.0)
let k2 = String(keyPath: \Dog.species)
XCTAssertEqual(k2, "species")
#endif
let k3 = String(keyPath: \Dog.nickname)
XCTAssertEqual(k3, "nickname")
@@ -325,9 +323,7 @@ class DynamicModelTests: BaseTestDataTestCase {
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertEqual(String(keyPath: \Animal.species), "species")
#if swift(<5.0)
XCTAssertEqual(String(keyPath: \Dog.species), "species")
#endif
}
@nonobjc

View File

@@ -74,31 +74,31 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
try from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -113,98 +113,98 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config1")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -219,96 +219,96 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity2>("Config1")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -323,94 +323,94 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
do {
let from = From<TestEntity2>("Config1")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores?.map { $0.configurationName } ?? []
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
}

View File

@@ -68,7 +68,7 @@ final class GroupByTests: BaseTestCase {
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
try From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
groupBy.applyToFetchRequest(request)

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>6.0.0</string>
<string>6.2.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@@ -179,7 +179,7 @@ final class OrderByTests: XCTestCase {
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
let orderBy = OrderBy<NSManagedObject>(.ascending("key"))
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
orderBy.applyToFetchRequest(request)
XCTAssertNotNil(request.sortDescriptors)
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)

View File

@@ -43,7 +43,7 @@ final class TweakTests: XCTestCase {
$0.fetchLimit = 200
$0.predicate = predicate
}
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
tweak.applyToFetchRequest(request)
XCTAssertEqual(request.fetchOffset, 100)
XCTAssertEqual(request.fetchLimit, 200)

View File

@@ -583,7 +583,7 @@ final class WhereTests: XCTestCase {
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let request = NSFetchRequest<NSFetchRequestResult>()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
whereClause.applyToFetchRequest(request)
XCTAssertNotNil(request.predicate)
XCTAssertEqual(request.predicate, whereClause.predicate)

View File

@@ -1,53 +0,0 @@
import UIKit
import CoreStore
/// Model Declaration =====
class Animal: CoreStoreObject {
let species = Value.Required<String>("species", initial: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<UIColor>("color", initial: .orange)
}
class Person: CoreStoreObject {
let name = Value.Optional<String>("name")
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
}
/// =======================
/// Stack setup ===========
let dataStack = DataStack(
CoreStoreSchema(
modelVersion: "V1",
entities: [
Entity<Animal>("Animal"),
Entity<Person>("Person")
]
)
)
try dataStack.addStorageAndWait(SQLiteStore(fileName: "data.sqlite"))
/// =======================
/// Transactions ==========
dataStack.perform(synchronous: { transaction in
let animal = transaction.create(Into<Animal>())
animal.species .= "Sparrow"
animal.color .= .yellow
let person = transaction.create(Into<Person>())
person.name .= "John"
person.pets.value.insert(animal)
})
/// =======================
/// Accessing Objects =====
let bird = dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
bird.species.value
bird.color.value
print(bird)
let owner = bird.master.value!
owner.name.value
owner.pets.count
print(owner)
/// =======================

View File

@@ -0,0 +1,79 @@
import UIKit
import CoreStore
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
/// Model Declaration =====
class Animal: CoreStoreObject {
let species = Value.Required<String>("species", initial: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<UIColor>("color", initial: .orange)
}
class Person: CoreStoreObject {
let name = Value.Optional<String>("name")
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
}
/// =======================
/// Stack setup ===========
let dataStack = DataStack(
CoreStoreSchema(
modelVersion: "V1",
entities: [
Entity<Animal>("Animal"),
Entity<Person>("Person")
]
)
)
dataStack.addStorage(
SQLiteStore(fileName: "data.sqlite"),
completion: { result in
switch result {
case .failure(let error):
print(error)
case .success:
/// Transactions ==========
dataStack.perform(
asynchronous: { transaction in
let animal = transaction.create(Into<Animal>())
animal.species .= "Sparrow"
animal.color .= .yellow
let person = transaction.create(Into<Person>())
person.name .= "John"
person.pets.value.insert(animal)
},
completion: { result in
switch result {
case .failure(let error):
print(error)
case .success:
/// Accessing Objects =====
let bird = try! dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
print(bird.species.value)
print(bird.color.value as Any)
print(bird)
let owner = bird.master.value!
print(owner.name.value as Any)
print(owner.pets.count)
print(owner)
/// =======================
}
}
)
/// =======================
}
}
)

View File

@@ -0,0 +1,77 @@
import AppKit
import CoreStore
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
/// Model Declaration =====
class Animal: CoreStoreObject {
let species = Value.Required<String>("species", initial: "Swift")
let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<NSColor>("color", initial: .orange)
}
class Person: CoreStoreObject {
let name = Value.Optional<String>("name")
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
}
/// =======================
/// Stack setup ===========
let dataStack = DataStack(
CoreStoreSchema(
modelVersion: "V1",
entities: [
Entity<Animal>("Animal"),
Entity<Person>("Person")
]
)
)
dataStack.addStorage(
SQLiteStore(fileName: "data.sqlite"),
completion: { result in
switch result {
case .failure(let error):
print(error)
case .success:
/// Transactions ==========
dataStack.perform(
asynchronous: { transaction in
let animal = transaction.create(Into<Animal>())
animal.species .= "Sparrow"
animal.color .= .yellow
let person = transaction.create(Into<Person>())
person.name .= "John"
person.pets.value.insert(animal)
},
completion: { result in
switch result {
case .failure(let error):
print(error)
case .success:
/// Accessing Objects =====
let bird = try! dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
print(bird.species.value)
print(bird.color.value as Any)
print(bird)
let owner = bird.master.value!
print(owner.name.value as Any)
print(owner.pets.count)
print(owner)
/// =======================
}
}
)
/// =======================
}
}
)

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
<timeline fileName='timeline.xctimeline'/>
</playground>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -1872,7 +1872,7 @@ Once the version lock is set, any changes in the properties or to the model will
### Install with CocoaPods
In your `Podfile`, add
```
pod 'CoreStore', '~> 6.0'
pod 'CoreStore', '~> 6.1'
```
and run
```
@@ -1883,7 +1883,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
### Install with Carthage
In your `Cartfile`, add
```
github "JohnEstropia/CoreStore" >= 6.0.0
github "JohnEstropia/CoreStore" >= 6.2.1
```
and run
```
@@ -1894,7 +1894,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
#### Install with Swift Package Manager:
```swift
dependencies: [
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "6.0.0"))
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "6.2.1"))
]
```
Declare `import CoreStore` in your swift file to use the library.

View File

@@ -68,7 +68,7 @@ extension CSDataStack {
sectionBy: nil,
applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
}
).bridgeToObjectiveC
}
@@ -97,7 +97,7 @@ extension CSDataStack {
sectionBy: nil,
applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
},
createAsynchronously: {
@@ -131,7 +131,7 @@ extension CSDataStack {
sectionBy: sectionBy.bridgeToSwift,
applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
}
).bridgeToObjectiveC
}
@@ -160,7 +160,7 @@ extension CSDataStack {
sectionBy: sectionBy.bridgeToSwift,
applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
},
createAsynchronously: {

View File

@@ -503,7 +503,7 @@ public final class CSListMonitor: NSObject {
self.bridgeToSwift.refetch { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
}
}

View File

@@ -0,0 +1,91 @@
//
// CoreStoreFetchRequest.swift
// CoreStore
//
// Copyright © 2019 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 ObjectiveC
// MARK: - CoreStoreFetchRequest
// Bugfix for NSFetchRequest messing up memory management for `affectedStores`
// http://stackoverflow.com/questions/14396375/nsfetchedresultscontroller-crashes-in-ios-6-if-affectedstores-is-specified
internal final class CoreStoreFetchRequest<T: NSFetchRequestResult>: NSFetchRequest<NSFetchRequestResult> {
@nonobjc
internal func safeAffectedStores() -> [NSPersistentStore]? {
return self.copiedAffectedStores as! [NSPersistentStore]?
}
@nonobjc @inline(__always)
internal func staticCast() -> NSFetchRequest<T> {
return unsafeBitCast(self, to: NSFetchRequest<T>.self)
}
@nonobjc @inline(__always)
internal func dynamicCast<U>() -> NSFetchRequest<U> {
return unsafeBitCast(self, to: NSFetchRequest<U>.self)
}
// MARK: NSFetchRequest
@objc dynamic
override var affectedStores: [NSPersistentStore]? {
get {
return super.affectedStores
}
set {
if #available(iOS 11.0, macOS 10.13, watchOS 4.0, tvOS 11.0, *) {
self.copiedAffectedStores = (newValue as NSArray?)?.copy() as! NSArray?
super.affectedStores = newValue
return
}
// Bugfix for NSFetchRequest messing up memory management for `affectedStores`
// http://stackoverflow.com/questions/14396375/nsfetchedresultscontroller-crashes-in-ios-6-if-affectedstores-is-specified
if let releaseArray = self.releaseArray {
releaseArray.release()
self.releaseArray = nil
}
self.copiedAffectedStores = (newValue as NSArray?)?.copy() as! NSArray?
super.affectedStores = newValue
self.releaseArray = (super.affectedStores as NSArray?).map(Unmanaged<NSArray>.passRetained(_:))
}
}
// MARK: Private
private var copiedAffectedStores: NSArray?
private var releaseArray: Unmanaged<NSArray>?
}

View File

@@ -33,10 +33,13 @@ import CoreData
internal final class CoreStoreFetchedResultsController: NSFetchedResultsController<NSManagedObject> {
// MARK: Internal
@nonobjc
internal let typedFetchRequest: CoreStoreFetchRequest<NSManagedObject>
@nonobjc
internal convenience init<D>(dataStack: DataStack, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<D>, sectionBy: SectionBy<D>? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
internal convenience init<D>(dataStack: DataStack, fetchRequest: CoreStoreFetchRequest<NSManagedObject>, from: From<D>, sectionBy: SectionBy<D>? = nil, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void) {
self.init(
context: dataStack.mainContext,
fetchRequest: fetchRequest,
@@ -47,7 +50,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
}
@nonobjc
internal init<D>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<D>, sectionBy: SectionBy<D>? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
internal init<D>(context: NSManagedObjectContext, fetchRequest: CoreStoreFetchRequest<NSManagedObject>, from: From<D>, sectionBy: SectionBy<D>? = nil, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void) {
_ = try? from.applyToFetchRequest(
fetchRequest,
@@ -55,14 +58,15 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
applyAffectedStores: false
)
applyFetchClauses(fetchRequest)
self.typedFetchRequest = fetchRequest
self.reapplyAffectedStores = { fetchRequest, context in
try from.applyAffectedStoresForFetchedRequest(fetchRequest, context: context)
}
super.init(
fetchRequest: fetchRequest,
fetchRequest: fetchRequest.staticCast(),
managedObjectContext: context,
sectionNameKeyPath: sectionBy?.sectionKeyPath,
cacheName: nil
@@ -72,7 +76,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
@nonobjc
internal func performFetchFromSpecifiedStores() throws {
try self.reapplyAffectedStores(self.fetchRequest, self.managedObjectContext)
try self.reapplyAffectedStores(self.typedFetchRequest, self.managedObjectContext)
try self.performFetch()
}
@@ -91,5 +95,5 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
// MARK: Private
@nonobjc
private let reapplyAffectedStores: (_ fetchRequest: NSFetchRequest<NSManagedObject>, _ context: NSManagedObjectContext) throws -> Void
private let reapplyAffectedStores: (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>, _ context: NSManagedObjectContext) throws -> Void
}

View File

@@ -100,8 +100,7 @@ public final class Entity<O: CoreStoreObject>: DynamicEntity {
entityName,
isAbstract: isAbstract,
versionHashModifier: versionHashModifier,
indexes: indexes,
uniqueConstraints: []
indexes: indexes
)
}

View File

@@ -86,6 +86,14 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
return
}
if #available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *) {}
else {
self.deletedSections = []
self.insertedSections = []
}
self.handler?.controllerWillChangeContent(controller)
}
@@ -100,6 +108,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
return
}
self.handler?.controllerDidChangeContent(controller)
}
@@ -110,11 +119,102 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
return
}
if #available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *) {
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: indexPath,
forChangeType: type,
newIndexPath: newIndexPath
)
return
}
guard var actualType = NSFetchedResultsChangeType(rawValue: type.rawValue) else {
// This fix is for a bug where iOS passes 0 for NSFetchedResultsChangeType, but this is not a valid enum case.
// Swift will then always execute the first case of the switch causing strange behaviour.
// https://forums.developer.apple.com/thread/12184#31850
return
}
// This whole dance is a workaround for a nasty bug introduced in XCode 7 targeted at iOS 8 devices
// http://stackoverflow.com/questions/31383760/ios-9-attempt-to-delete-and-reload-the-same-index-path/31384014#31384014
// https://forums.developer.apple.com/message/9998#9998
// https://forums.developer.apple.com/message/31849#31849
if case .update = actualType,
indexPath != nil,
newIndexPath != nil {
actualType = .move
}
switch actualType {
case .update:
guard let section = indexPath?[0] else {
return
}
if self.deletedSections.contains(section)
|| self.insertedSections.contains(section) {
return
}
case .move:
guard let indexPath = indexPath, let newIndexPath = newIndexPath else {
return
}
guard indexPath == newIndexPath else {
break
}
if self.insertedSections.contains(indexPath[0]) {
// Observers that handle the .Move change are advised to delete then reinsert the object instead of just moving. This is especially true when indexPath and newIndexPath are equal. For example, calling tableView.moveRowAtIndexPath(_:toIndexPath) when both indexPaths are the same will crash the tableView.
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: indexPath,
forChangeType: .move,
newIndexPath: newIndexPath
)
return
}
if self.deletedSections.contains(indexPath[0]) {
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: nil,
forChangeType: .insert,
newIndexPath: indexPath
)
return
}
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: indexPath,
forChangeType: .update,
newIndexPath: nil
)
return
default:
break
}
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: indexPath,
forChangeType: type,
forChangeType: actualType,
newIndexPath: newIndexPath
)
}
@@ -126,6 +226,18 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
return
}
if #available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *) {}
else {
switch type {
case .delete: self.deletedSections.insert(sectionIndex)
case .insert: self.insertedSections.insert(sectionIndex)
default: break
}
}
self.handler?.controller(
controller,
didChangeSection: sectionInfo,
@@ -142,4 +254,13 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
sectionIndexTitleForSectionName: sectionName
)
}
// MARK: Private
@nonobjc
private var deletedSections = Set<Int>()
@nonobjc
private var insertedSections = Set<Int>()
}

View File

@@ -139,7 +139,7 @@ public struct From<D: DynamicObject> {
self.findPersistentStores = findPersistentStores
}
internal func applyToFetchRequest<U>(_ fetchRequest: NSFetchRequest<U>, context: NSManagedObjectContext, applyAffectedStores: Bool = true) throws {
internal func applyToFetchRequest<U>(_ fetchRequest: CoreStoreFetchRequest<U>, context: NSManagedObjectContext, applyAffectedStores: Bool = true) throws {
fetchRequest.entity = context.parentStack!.entityDescription(for: EntityIdentifier(self.entityClass))!
guard applyAffectedStores else {
@@ -164,7 +164,7 @@ public struct From<D: DynamicObject> {
}
}
internal func applyAffectedStoresForFetchedRequest<U>(_ fetchRequest: NSFetchRequest<U>, context: NSManagedObjectContext) throws {
internal func applyAffectedStoresForFetchedRequest<U>(_ fetchRequest: CoreStoreFetchRequest<U>, context: NSManagedObjectContext) throws {
let stores = self.findPersistentStores(context)
fetchRequest.affectedStores = stores

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>6.0.0</string>
<string>6.2.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@@ -628,7 +628,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
// MARK: Internal
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void) {
self.init(
context: dataStack.mainContext,
@@ -640,7 +640,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
)
}
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) {
internal convenience init(dataStack: DataStack, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) {
self.init(
context: dataStack.mainContext,
@@ -652,7 +652,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
)
}
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void) {
self.init(
context: unsafeTransaction.context,
@@ -664,7 +664,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
)
}
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) {
internal convenience init(unsafeTransaction: UnsafeDataTransaction, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void, createAsynchronously: @escaping (ListMonitor<ObjectType>) -> Void) {
self.init(
context: unsafeTransaction.context,
@@ -923,7 +923,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
cs_setAssociatedRetainedObject(nilValue, forKey: &self.didDeleteSectionKey, inObject: observer)
}
internal func refetch(_ applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
internal func refetch(_ applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void) {
CoreStore.assert(
Thread.isMainThread,
@@ -1022,7 +1022,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
private var observerForWillChangePersistentStore: NotificationObserver!
private var observerForDidChangePersistentStore: NotificationObserver!
private let transactionQueue: DispatchQueue
private var applyFetchClauses: (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void
private var applyFetchClauses: (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void
private var isPersistentStoreChanging: Bool = false {
@@ -1045,9 +1045,9 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
}
}
private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) -> (controller: CoreStoreFetchedResultsController, delegate: FetchedResultsControllerDelegate) {
private static func recreateFetchedResultsController(context: NSManagedObjectContext, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void) -> (controller: CoreStoreFetchedResultsController, delegate: FetchedResultsControllerDelegate) {
let fetchRequest = NSFetchRequest<NSManagedObject>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObject>()
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType
fetchRequest.fetchBatchSize = 20
@@ -1071,7 +1071,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
private let from: From<ObjectType>
private let sectionBy: SectionBy<ObjectType>?
private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void, createAsynchronously: ((ListMonitor<ObjectType>) -> Void)?) {
private init(context: NSManagedObjectContext, transactionQueue: DispatchQueue, from: From<ObjectType>, sectionBy: SectionBy<ObjectType>?, applyFetchClauses: @escaping (_ fetchRequest: CoreStoreFetchRequest<NSManagedObject>) -> Void, createAsynchronously: ((ListMonitor<ObjectType>) -> Void)?) {
self.isSectioned = (sectionBy != nil)
self.from = from
@@ -1114,7 +1114,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
self.isPersistentStoreChanging = true
guard let removedStores = (note.userInfo?[NSRemovedPersistentStoresKey] as? [NSPersistentStore]).flatMap(Set.init),
!Set(self.fetchedResultsController.fetchRequest.affectedStores ?? []).intersection(removedStores).isEmpty else {
!Set(self.fetchedResultsController.typedFetchRequest.safeAffectedStores() ?? []).intersection(removedStores).isEmpty else {
return
}
@@ -1135,7 +1135,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
if !self.isPendingRefetch {
let previousStores = Set(self.fetchedResultsController.fetchRequest.affectedStores ?? [])
let previousStores = Set(self.fetchedResultsController.typedFetchRequest.safeAffectedStores() ?? [])
let currentStores = previousStores
.subtracting(note.userInfo?[NSRemovedPersistentStoresKey] as? [NSPersistentStore] ?? [])
.union(note.userInfo?[NSAddedPersistentStoresKey] as? [NSPersistentStore] ?? [])

View File

@@ -205,12 +205,12 @@ fileprivate func createFRC<D: NSManagedObject>(fromContext context: NSManagedObj
let controller = CoreStoreFetchedResultsController(
context: context,
fetchRequest: NSFetchRequest<NSManagedObject>(),
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: sectionBy,
applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false,

View File

@@ -72,12 +72,12 @@ fileprivate func createFRC(fromContext context: NSManagedObjectContext, from: CS
let controller = CoreStoreFetchedResultsController(
context: context,
fetchRequest: NSFetchRequest<NSManagedObject>(),
fetchRequest: CoreStoreFetchRequest(),
from: from.bridgeToSwift,
sectionBy: sectionBy?.bridgeToSwift,
applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false,

View File

@@ -36,12 +36,12 @@ extension NSManagedObjectContext {
@nonobjc
internal func fetchOne(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> NSManagedObject? {
let fetchRequest = NSFetchRequest<NSManagedObject>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObject>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
fetchRequest.resultType = .managedObjectResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.fetchOne(fetchRequest)
}
@@ -49,12 +49,12 @@ extension NSManagedObjectContext {
@nonobjc
internal func fetchAll<T: NSManagedObject>(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> [T] {
let fetchRequest = NSFetchRequest<T>()
let fetchRequest = CoreStoreFetchRequest<T>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.fetchAll(fetchRequest)
}
@@ -62,11 +62,11 @@ extension NSManagedObjectContext {
@nonobjc
internal func fetchCount(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> Int {
let fetchRequest = NSFetchRequest<NSNumber>()
let fetchRequest = CoreStoreFetchRequest<NSNumber>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.resultType = .countResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.fetchCount(fetchRequest)
}
@@ -74,12 +74,12 @@ extension NSManagedObjectContext {
@nonobjc
internal func fetchObjectID(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> NSManagedObjectID? {
let fetchRequest = NSFetchRequest<NSManagedObjectID>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObjectID>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
fetchRequest.resultType = .managedObjectIDResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.fetchObjectID(fetchRequest)
}
@@ -87,12 +87,12 @@ extension NSManagedObjectContext {
@nonobjc
internal func fetchObjectIDs(_ from: CSFrom, _ fetchClauses: [CSFetchClause]) throws -> [NSManagedObjectID] {
let fetchRequest = NSFetchRequest<NSManagedObjectID>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObjectID>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectIDResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.fetchObjectIDs(fetchRequest)
}
@@ -100,14 +100,14 @@ extension NSManagedObjectContext {
@nonobjc
internal func deleteAll(_ from: CSFrom, _ deleteClauses: [CSDeleteClause]) throws -> Int {
let fetchRequest = NSFetchRequest<NSManagedObject>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObject>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType
fetchRequest.returnsObjectsAsFaults = true
fetchRequest.includesPropertyValues = false
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.deleteAll(fetchRequest)
}
@@ -115,13 +115,13 @@ extension NSManagedObjectContext {
@nonobjc
internal func queryValue(_ from: CSFrom, _ selectClause: CSSelect, _ queryClauses: [CSQueryClause]) throws -> Any? {
let fetchRequest = NSFetchRequest<NSDictionary>()
let fetchRequest = CoreStoreFetchRequest<NSDictionary>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.queryValue(selectClause.selectTerms, fetchRequest: fetchRequest)
}
@@ -129,13 +129,13 @@ extension NSManagedObjectContext {
@nonobjc
internal func queryAttributes(_ from: CSFrom, _ selectClause: CSSelect, _ queryClauses: [CSQueryClause]) throws -> [[String: Any]] {
let fetchRequest = NSFetchRequest<NSDictionary>()
let fetchRequest = CoreStoreFetchRequest<NSDictionary>()
try from.bridgeToSwift.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
selectClause.applyToFetchRequest(fetchRequest)
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.queryAttributes(fetchRequest)
}

View File

@@ -109,7 +109,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
public func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> D? {
let fetchRequest = NSFetchRequest<NSManagedObject>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObject>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
@@ -134,7 +134,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [D] {
let fetchRequest = NSFetchRequest<NSManagedObject>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObject>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
@@ -160,7 +160,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> Int {
let fetchRequest = NSFetchRequest<NSNumber>()
let fetchRequest = CoreStoreFetchRequest<NSNumber>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.resultType = .countResultType
@@ -184,7 +184,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> NSManagedObjectID? {
let fetchRequest = NSFetchRequest<NSManagedObjectID>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObjectID>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
@@ -209,7 +209,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [NSManagedObjectID] {
let fetchRequest = NSFetchRequest<NSManagedObjectID>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObjectID>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
@@ -226,7 +226,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
}
@nonobjc
internal func fetchObjectIDs(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) throws -> [NSManagedObjectID] {
internal func fetchObjectIDs(_ fetchRequest: CoreStoreFetchRequest<NSManagedObjectID>) throws -> [NSManagedObjectID] {
var fetchResults: [NSManagedObjectID]?
var fetchError: Error?
@@ -234,7 +234,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.fetch(fetchRequest.dynamicCast())
}
catch {
@@ -265,12 +265,12 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) throws -> U? {
let fetchRequest = NSFetchRequest<NSDictionary>()
let fetchRequest = CoreStoreFetchRequest<NSDictionary>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.applyToFetchRequest(fetchRequest)
selectClause.applyToFetchRequest(fetchRequest.staticCast())
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.queryValue(selectClause.selectTerms, fetchRequest: fetchRequest)
@@ -291,12 +291,12 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) throws -> [[String: Any]] {
let fetchRequest = NSFetchRequest<NSDictionary>()
let fetchRequest = CoreStoreFetchRequest<NSDictionary>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
selectClause.applyToFetchRequest(fetchRequest)
selectClause.applyToFetchRequest(fetchRequest.staticCast())
queryClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
return try self.queryAttributes(fetchRequest)
@@ -322,7 +322,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc
internal func deleteAll<D>(_ from: From<D>, _ deleteClauses: [FetchClause]) throws -> Int {
let fetchRequest = NSFetchRequest<NSManagedObject>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObject>()
try from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
@@ -352,7 +352,7 @@ extension NSManagedObjectContext {
// MARK: Fetching
@nonobjc
internal func fetchOne<D: NSManagedObject>(_ fetchRequest: NSFetchRequest<D>) throws -> D? {
internal func fetchOne<D: NSManagedObject>(_ fetchRequest: CoreStoreFetchRequest<D>) throws -> D? {
var fetchResults: [D]?
var fetchError: Error?
@@ -360,7 +360,7 @@ extension NSManagedObjectContext {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.fetch(fetchRequest.staticCast())
}
catch {
@@ -380,7 +380,7 @@ extension NSManagedObjectContext {
}
@nonobjc
internal func fetchAll<D: NSManagedObject>(_ fetchRequest: NSFetchRequest<D>) throws -> [D] {
internal func fetchAll<D: NSManagedObject>(_ fetchRequest: CoreStoreFetchRequest<D>) throws -> [D] {
var fetchResults: [D]?
var fetchError: Error?
@@ -388,7 +388,7 @@ extension NSManagedObjectContext {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.fetch(fetchRequest.staticCast())
}
catch {
@@ -408,7 +408,7 @@ extension NSManagedObjectContext {
}
@nonobjc
internal func fetchCount(_ fetchRequest: NSFetchRequest<NSNumber>) throws -> Int {
internal func fetchCount(_ fetchRequest: CoreStoreFetchRequest<NSNumber>) throws -> Int {
var count = 0
var countError: Error?
@@ -416,7 +416,7 @@ extension NSManagedObjectContext {
do {
count = try self.count(for: fetchRequest)
count = try self.count(for: fetchRequest.staticCast())
}
catch {
@@ -436,7 +436,7 @@ extension NSManagedObjectContext {
}
@nonobjc
internal func fetchObjectID(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) throws -> NSManagedObjectID? {
internal func fetchObjectID(_ fetchRequest: CoreStoreFetchRequest<NSManagedObjectID>) throws -> NSManagedObjectID? {
var fetchResults: [NSManagedObjectID]?
var fetchError: Error?
@@ -444,7 +444,7 @@ extension NSManagedObjectContext {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.fetch(fetchRequest.staticCast())
}
catch {
@@ -467,7 +467,7 @@ extension NSManagedObjectContext {
// MARK: Querying
@nonobjc
internal func queryValue<D, U: QueryableAttributeType>(_ selectTerms: [SelectTerm<D>], fetchRequest: NSFetchRequest<NSDictionary>) throws -> U? {
internal func queryValue<D, U: QueryableAttributeType>(_ selectTerms: [SelectTerm<D>], fetchRequest: CoreStoreFetchRequest<NSDictionary>) throws -> U? {
var fetchResults: [Any]?
var fetchError: Error?
@@ -475,7 +475,7 @@ extension NSManagedObjectContext {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.fetch(fetchRequest.staticCast())
}
catch {
@@ -500,7 +500,7 @@ extension NSManagedObjectContext {
}
@nonobjc
internal func queryValue<D>(_ selectTerms: [SelectTerm<D>], fetchRequest: NSFetchRequest<NSDictionary>) throws -> Any? {
internal func queryValue<D>(_ selectTerms: [SelectTerm<D>], fetchRequest: CoreStoreFetchRequest<NSDictionary>) throws -> Any? {
var fetchResults: [Any]?
var fetchError: Error?
@@ -508,7 +508,7 @@ extension NSManagedObjectContext {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.fetch(fetchRequest.staticCast())
}
catch {
@@ -533,7 +533,7 @@ extension NSManagedObjectContext {
}
@nonobjc
internal func queryAttributes(_ fetchRequest: NSFetchRequest<NSDictionary>) throws -> [[String: Any]] {
internal func queryAttributes(_ fetchRequest: CoreStoreFetchRequest<NSDictionary>) throws -> [[String: Any]] {
var fetchResults: [Any]?
var fetchError: Error?
@@ -541,7 +541,7 @@ extension NSManagedObjectContext {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.fetch(fetchRequest.staticCast())
}
catch {
@@ -564,7 +564,7 @@ extension NSManagedObjectContext {
// MARK: Deleting
@nonobjc
internal func deleteAll<D: NSManagedObject>(_ fetchRequest: NSFetchRequest<D>) throws -> Int {
internal func deleteAll<D: NSManagedObject>(_ fetchRequest: CoreStoreFetchRequest<D>) throws -> Int {
var numberOfDeletedObjects: Int?
var fetchError: Error?
@@ -574,7 +574,7 @@ extension NSManagedObjectContext {
do {
let fetchResults = try self.fetch(fetchRequest)
let fetchResults = try self.fetch(fetchRequest.staticCast())
for object in fetchResults {
self.delete(object)

View File

@@ -261,7 +261,7 @@ public final class ObjectMonitor<D: DynamicObject>: Equatable {
private init(context: NSManagedObjectContext, object: ObjectType) {
let objectID = object.cs_id()
let fetchRequest = NSFetchRequest<NSManagedObject>()
let fetchRequest = CoreStoreFetchRequest<NSManagedObject>()
fetchRequest.entity = objectID.entity
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType

View File

@@ -29,11 +29,24 @@ import CoreData
// MARK: - ~
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let owner = CoreStore.fetchOne(
From<Pet>().where(
(\.master ~ \.name) == "John"
)
)
```
*/
infix operator ~ : AdditionPrecedence
// MARK: - WhereExpressionTrait
/**
Used only for `Where.Expression` type constraints. Currently supports `SingleTarget` and `CollectionTarget`.
*/
public protocol WhereExpressionTrait {}
@@ -43,8 +56,20 @@ extension Where {
// MARK: - Expression
/**
Type-safe keyPath chain usable in query/fetch expressions.
```
let expression: Where<Pet>.Expression = (\.master ~ \.name)
let owner = CoreStore.fetchOne(
From<Pet>().where(expression == "John")
)
```
*/
public struct Expression<T: WhereExpressionTrait, V>: CustomStringConvertible, DynamicKeyPath {
/**
Currently supports `SingleTarget` and `CollectionTarget`.
*/
public typealias Trait = T
@@ -83,10 +108,17 @@ extension Where {
// MARK: - SingleTarget
/**
Used only for `Where.Expression` type constraints. Specifies that this `Where.Expression` type pertains to an attribute property expression.
*/
public enum SingleTarget: WhereExpressionTrait {}
// MARK: - CollectionTarget
/**
Used only for `Where.Expression` type constraints. Specifies that this `Where.Expression` type pertains to a to-many relationship expression.
*/
public enum CollectionTarget: WhereExpressionTrait {}
}
@@ -95,47 +127,101 @@ extension Where {
// MARK: ~ where D: NSManagedObject
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let owner = CoreStore.fetchOne(From<Pet>().where((\.master ~ \.name) == "John"))
```
*/
public func ~<D: NSManagedObject, O: NSManagedObject, V: AllowedObjectiveCKeyPathValue>(_ lhs: KeyPath<D, O>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.SingleTarget, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, V: AllowedObjectiveCKeyPathValue>(_ lhs: KeyPath<D, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.SingleTarget, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let owner = CoreStore.fetchOne(From<Pet>().where((\.master ~ \.name) == "John"))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, V: AllowedObjectiveCKeyPathValue>(_ lhs: KeyPath<D, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.SingleTarget, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: KeyPath<D, O>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let happyPets = CoreStore.fetchAll(From<Pet>().where((\.master ~ \.pets).count() > 1))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: KeyPath<D, O>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: KeyPath<D, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let happyPets = CoreStore.fetchAll(From<Pet>().where((\.master ~ \.pets).count() > 1))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: KeyPath<D, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<T, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let johnsSonInLaw = CoreStore.fetchOne(From<Person>().where((\.spouse ~ \.father ~ \.name) == "John"))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<T, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let johnsSonInLaw = CoreStore.fetchOne(From<Person>().where((\.spouse ~ \.father ~ \.name) == "John"))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<T, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<T, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let spouseHasSiblings = CoreStore.fetchOne(From<Person>().where((\.spouse ~ \.father ~ \.children).count() > 0))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let spouseHasSiblings = CoreStore.fetchOne(From<Person>().where((\.spouse ~ \.father ~ \.children).count() > 0))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, T, V: AllowedObjectiveCCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
public func ~<D: NSManagedObject, O: NSManagedObject, T, C: AllowedObjectiveCCollectionKeyPathValue, V: AllowedObjectiveCKeyPathValue>(_ lhs: Where<D>.Expression<T, C>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let spousesWithBadNamingSense = CoreStore.fetchAll(From<Person>().where((\.spouse ~ \.pets ~ \.name).any() == "Spot"))
```
*/
public func ~ <D: NSManagedObject, O: NSManagedObject, T, C: AllowedObjectiveCCollectionKeyPathValue, V: AllowedObjectiveCKeyPathValue>(_ lhs: Where<D>.Expression<T, C>, _ rhs: KeyPath<O, V>) -> Where<D>.Expression<Where<D>.CollectionTarget, V> {
return .init(lhs.cs_keyPathString, rhs.cs_keyPathString)
}
@@ -143,7 +229,13 @@ public func ~<D: NSManagedObject, O: NSManagedObject, T, C: AllowedObjectiveCCol
// MARK: - ~ where D: CoreStoreObject
public func ~<D: CoreStoreObject, O: CoreStoreObject, K: AllowedCoreStoreObjectKeyPathValue>(_ lhs: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.SingleTarget, K.ValueType> where K.ObjectType == O {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let owner = CoreStore.fetchOne(From<Pet>().where((\.master ~ \.name) == "John"))
```
*/
public func ~ <D: CoreStoreObject, O: CoreStoreObject, K: AllowedCoreStoreObjectKeyPathValue>(_ lhs: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.SingleTarget, K.ValueType> where K.ObjectType == O {
return .init(
D.meta[keyPath: lhs].cs_keyPathString,
@@ -151,7 +243,41 @@ public func ~<D: CoreStoreObject, O: CoreStoreObject, K: AllowedCoreStoreObjectK
)
}
public func ~<D: CoreStoreObject, O: CoreStoreObject, K: AllowedCoreStoreObjectCollectionKeyPathValue>(_ lhs: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.CollectionTarget, K.ValueType> where K.ObjectType == O {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let owner = CoreStore.fetchOne(From<Pet>().where((\.master ~ \.name) == "John"))
```
*/
public func ~ <D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<T, K.ValueType> where K.ObjectType == O {
return .init(
lhs.cs_keyPathString,
O.meta[keyPath: rhs].cs_keyPathString
)
}
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let owner = CoreStore.fetchOne(From<Pet>().where((\.master ~ \.name) == "John"))
```
*/
public func ~ <D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<T, K.ValueType> where K.ObjectType == O {
return .init(
lhs.cs_keyPathString,
O.meta[keyPath: rhs].cs_keyPathString
)
}
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let happyPets = CoreStore.fetchAll(From<Pet>().where((\.master ~ \.pets).count() > 1))
```
*/
public func ~ <D: CoreStoreObject, O: CoreStoreObject, K: AllowedCoreStoreObjectCollectionKeyPathValue>(_ lhs: KeyPath<D, RelationshipContainer<D>.ToOne<O>>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.CollectionTarget, K.ValueType> where K.ObjectType == O {
return .init(
D.meta[keyPath: lhs].cs_keyPathString,
@@ -159,7 +285,13 @@ public func ~<D: CoreStoreObject, O: CoreStoreObject, K: AllowedCoreStoreObjectC
)
}
public func ~<D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<T, K.ValueType> where K.ObjectType == O {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let happyPets = CoreStore.fetchAll(From<Pet>().where((\.master ~ \.pets).count() > 1))
```
*/
public func ~ <D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.CollectionTarget, K.ValueType> where K.ObjectType == O {
return .init(
lhs.cs_keyPathString,
@@ -167,7 +299,13 @@ public func ~<D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObje
)
}
public func ~<D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.CollectionTarget, K.ValueType> where K.ObjectType == O {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let happyPets = CoreStore.fetchAll(From<Pet>().where((\.master ~ \.pets).count() > 1))
```
*/
public func ~ <D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.CollectionTarget, K.ValueType> where K.ObjectType == O {
return .init(
lhs.cs_keyPathString,
@@ -175,23 +313,13 @@ public func ~<D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObje
)
}
public func ~<D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<T, K.ValueType> where K.ObjectType == O {
return .init(
lhs.cs_keyPathString,
O.meta[keyPath: rhs].cs_keyPathString
)
}
public func ~<D: CoreStoreObject, O: CoreStoreObject, T, K: AllowedCoreStoreObjectCollectionKeyPathValue>(_ lhs: Where<D>.Expression<T, O?>, _ rhs: KeyPath<O, K>) -> Where<D>.Expression<Where<D>.CollectionTarget, K.ValueType> where K.ObjectType == O {
return .init(
lhs.cs_keyPathString,
O.meta[keyPath: rhs].cs_keyPathString
)
}
public func ~<D: CoreStoreObject, O: CoreStoreObject, T, KC: AllowedCoreStoreObjectCollectionKeyPathValue, KV: AllowedCoreStoreObjectKeyPathValue>(_ lhs: Where<D>.Expression<T, KC>, _ rhs: KeyPath<O, KV>) -> Where<D>.Expression<Where<D>.CollectionTarget, KV.ValueType> where KC.ObjectType == D, KV.ObjectType == O {
/**
Connects multiple `DynamicKeyPath`s to create a type-safe chain usable in query/fetch expressions
```
let spousesWithBadNamingSense = CoreStore.fetchAll(From<Pet>().where((\.master ~ \.pets ~ \.name).any() == "Spot"))
```
*/
public func ~ <D: CoreStoreObject, O: CoreStoreObject, T, KC: AllowedCoreStoreObjectCollectionKeyPathValue, KV: AllowedCoreStoreObjectKeyPathValue>(_ lhs: Where<D>.Expression<T, KC>, _ rhs: KeyPath<O, KV>) -> Where<D>.Expression<Where<D>.CollectionTarget, KV.ValueType> where KC.ObjectType == D, KV.ObjectType == O {
return .init(
lhs.cs_keyPathString,
@@ -202,16 +330,34 @@ public func ~<D: CoreStoreObject, O: CoreStoreObject, T, KC: AllowedCoreStoreObj
// MARK: - Where.Expression where V: QueryableAttributeType
/**
Creates a `Where` clause by comparing if an expression is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.name) == "John"))
```
*/
public func == <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(lhs.cs_keyPathString, isEqualTo: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is not equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.name) != "John"))
```
*/
public func != <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return !Where<D>(lhs.cs_keyPathString, isEqualTo: rhs)
}
/**
Creates a `Where` clause by checking if a sequence contains a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(["John", "Joe"] ~= (\.master ~ \.name))
```
*/
public func ~= <D, T, V: QueryableAttributeType, S: Sequence>(_ sequence: S, _ expression: Where<D>.Expression<T, V>) -> Where<D> where S.Iterator.Element == V {
return Where<D>(expression.cs_keyPathString, isMemberOf: sequence)
@@ -220,21 +366,45 @@ public func ~= <D, T, V: QueryableAttributeType, S: Sequence>(_ sequence: S, _ e
// MARK: - Where.Expression where V: QueryableAttributeType & Comparable
/**
Creates a `Where` clause by comparing if an expression is less than a value
```
let lonelyDog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.pets).count() < 2))
```
*/
public func < <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: "<", operand: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is less than or equal to a value
```
let lonelyDog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.pets).count() <= 1)
```
*/
public func <= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: "<=", operand: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is greater than a value
```
let happyDog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.pets).count() > 1)
```
*/
public func > <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: ">", operand: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is greater than or equal to a value
```
let happyDog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.pets).count() >= 2)
```
*/
public func >= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: ">=", operand: rhs)
@@ -243,26 +413,56 @@ public func >= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Ex
// MARK: - Where.Expression where V: Optional<QueryableAttributeType>
/**
Creates a `Where` clause by comparing if an expression is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.name) == "John"))
```
*/
public func == <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> {
return Where<D>(lhs.cs_keyPathString, isEqualTo: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.name) == "John"))
```
*/
public func == <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V?) -> Where<D> {
return Where<D>(lhs.cs_keyPathString, isEqualTo: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.name) != "John"))
```
*/
public func != <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> {
return !Where<D>(lhs.cs_keyPathString, isEqualTo: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is equal to a value
```
let dog = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.name) != "John"))
```
*/
public func != <D, T, V: QueryableAttributeType>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V?) -> Where<D> {
return !Where<D>(lhs.cs_keyPathString, isEqualTo: rhs)
}
/**
Creates a `Where` clause by checking if a sequence contains a value
```
let dog = CoreStore.fetchOne(From<Dog>().where(["John", "Joe"] ~= (\.master ~ \.name))
```
*/
public func ~= <D, T, V: QueryableAttributeType, S: Sequence>(_ sequence: S, _ expression: Where<D>.Expression<T, V?>) -> Where<D> where S.Iterator.Element == V {
return Where<D>(expression.cs_keyPathString, isMemberOf: sequence)
@@ -271,21 +471,45 @@ public func ~= <D, T, V: QueryableAttributeType, S: Sequence>(_ sequence: S, _ e
// MARK: - Where.Expression where V: Optional<QueryableAttributeType & Comparable>
/**
Creates a `Where` clause by comparing if an expression is less than a value
```
let childsPet = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.age) < 10))
```
*/
public func < <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: "<", operand: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is less than or equal to a value
```
let childsPet = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.age) <= 10))
```
*/
public func <= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V?) -> Where<D> {
return Where<D>(expression: lhs, function: "<=", operand: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is greater than a value
```
let teensPet = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.age) > 10))
```
*/
public func > <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V) -> Where<D> {
return Where<D>(expression: lhs, function: ">", operand: rhs)
}
/**
Creates a `Where` clause by comparing if an expression is greater than or equal to a value
```
let teensPet = CoreStore.fetchOne(From<Dog>().where((\.master ~ \.age) >= 10))
```
*/
public func >= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Expression<T, V?>, _ rhs: V?) -> Where<D> {
return Where<D>(expression: lhs, function: ">=", operand: rhs)
@@ -296,6 +520,12 @@ public func >= <D, T, V: QueryableAttributeType & Comparable>(_ lhs: Where<D>.Ex
extension KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCCollectionKeyPathValue {
/**
Creates a `Where.Expression` clause for COUNT
```
let dogsWithPlaymates = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets).count() > 1))
```
*/
public func count() -> Where<Root>.Expression<Where<Root>.CollectionTarget, Int> {
return .init(self.cs_keyPathString, "@count")
@@ -306,6 +536,12 @@ extension KeyPath where Root: NSManagedObject, Value: AllowedObjectiveCCollectio
extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCCollectionKeyPathValue {
/**
Creates a `Where.Expression` clause for COUNT
```
let dogsWithPlaymates = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets).count() > 1))
```
*/
public func count() -> Where<D>.Expression<T, Int> {
return .init(self.cs_keyPathString, "@count")
@@ -317,16 +553,34 @@ extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTar
extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTarget, V: AllowedObjectiveCKeyPathValue {
/**
Creates a `Where.Expression` clause for ANY
```
let dogsWithBadNamingSense = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets ~ \.name).any() > "Spot"))
```
*/
public func any() -> Where<D>.Expression<T, V> {
return .init("ANY " + self.cs_keyPathString)
}
/**
Creates a `Where.Expression` clause for ALL
```
let allPlaymatePuppies = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets ~ \.age).all() > 5))
```
*/
public func all() -> Where<D>.Expression<T, V> {
return .init("ALL " + self.cs_keyPathString)
}
/**
Creates a `Where.Expression` clause for NONE
```
let dogs = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets ~ \.name).any() > "Spot"))
```
*/
public func none() -> Where<D>.Expression<T, V> {
return .init("NONE " + self.cs_keyPathString)
@@ -338,6 +592,12 @@ extension Where.Expression where D: NSManagedObject, T == Where<D>.CollectionTar
extension KeyPath where Root: CoreStoreObject, Value: AllowedCoreStoreObjectCollectionKeyPathValue {
/**
Creates a `Where.Expression` clause for COUNT
```
let dogsWithPlaymates = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets).count() > 1))
```
*/
public func count() -> Where<Root>.Expression<Where<Root>.CollectionTarget, Int> {
return .init(Root.meta[keyPath: self].cs_keyPathString, "@count")
@@ -349,21 +609,45 @@ extension KeyPath where Root: CoreStoreObject, Value: AllowedCoreStoreObjectColl
extension Where.Expression where D: CoreStoreObject, T == Where<D>.CollectionTarget {
/**
Creates a `Where.Expression` clause for COUNT
```
let dogsWithPlaymates = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets).count() > 1))
```
*/
public func count() -> Where<D>.Expression<T, Int> {
return .init(self.cs_keyPathString, "@count")
}
/**
Creates a `Where.Expression` clause for ANY
```
let dogsWithBadNamingSense = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets ~ \.name).any() > "Spot"))
```
*/
public func any() -> Where<D>.Expression<T, V> {
return .init("ANY " + self.cs_keyPathString)
}
/**
Creates a `Where.Expression` clause for ALL
```
let allPlaymatePuppies = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets ~ \.age).all() > 5))
```
*/
public func all() -> Where<D>.Expression<T, V> {
return .init("ALL " + self.cs_keyPathString)
}
/**
Creates a `Where.Expression` clause for NONE
```
let dogs = CoreStore.fetchAll(From<Dog>().where((\.master ~ \.pets ~ \.name).any() > "Spot"))
```
*/
public func none() -> Where<D>.Expression<T, V> {
return .init("NONE " + self.cs_keyPathString)

View File

@@ -29,7 +29,7 @@ import Foundation
// MARK: - WhereClauseType
/**
Abstracts the `Where` clause for protocol utilities.
Abstracts the `Where` clause for protocol utilities. Typically used only for utility method generic constraints.
*/
public protocol WhereClauseType: AnyWhereClause {