Compare commits

..

22 Commits

Author SHA1 Message Date
John Estropia
981b560d53 test travis ci 2017-05-30 11:14:57 +09:00
John Estropia
c4c4dd55cd test travis build 2017-05-30 11:06:30 +09:00
John Rommel Estropia
1ddbe20c86 Updated README, fixed demo app, and bumped to 4.0.1 2017-05-28 11:37:40 +09:00
John Rommel Estropia
da9e8c1550 disallow "empty" default values on some ImportableAttributeTypes 2017-05-28 10:50:25 +09:00
John Estropia
ef0937fec4 make unit tests happy 2017-05-24 12:15:55 +09:00
John Estropia
35885b40de README done! Welcome to CoreStore 4.0! 2017-05-24 12:05:34 +09:00
John Rommel Estropia
d669569196 WIP: readme 2017-05-24 00:37:32 +09:00
John Rommel Estropia
ae919ff3c8 WIP: readme 2017-05-24 00:35:25 +09:00
John Rommel Estropia
1a7a4690d1 WIP: readme 2017-05-24 00:33:43 +09:00
John Rommel Estropia
b9b96d1a35 WIP: Updating README and other docs. Some minor fixes 2017-05-22 01:27:38 +09:00
John Rommel Estropia
da3a9590ac accept optionals in setValue 2017-05-21 09:38:56 +09:00
John Rommel Estropia
6b3d75bea1 fix fixits 2017-05-21 09:29:34 +09:00
John Rommel Estropia
d44721fef0 fix xcode hints 2017-05-21 09:11:34 +09:00
John Rommel Estropia
3f268e8376 added NSManagedObject.setValue(_:forKvcKey:willSetValue:didSetValue:) 2017-05-21 09:06:29 +09:00
John Rommel Estropia
303fea4ebe fix warnings 2017-05-21 08:51:38 +09:00
John Estropia
77173cdad0 minor fix 2017-05-18 21:10:43 +09:00
John Estropia
1e24a7d739 ListObserver's listMonitorDidChange(_:) and listMonitorDidRefetch(_:) handlers are now required. 2017-05-18 12:59:58 +09:00
John Estropia
a3b33bedb8 added more migration error types 2017-05-18 12:59:02 +09:00
John Estropia
eaf7544c50 fix error when CoreStoreObject types have deep namespaces 2017-05-17 15:55:33 +09:00
John Estropia
67863120e0 WIP: readme 2017-05-15 11:03:21 +09:00
John Estropia
1b0e305d9a beta bump 2017-05-15 10:23:55 +09:00
John Rommel Estropia
91fda01071 WIP: readme 2017-05-15 08:51:31 +09:00
89 changed files with 2750 additions and 1814 deletions

View File

@@ -25,7 +25,7 @@ matrix:
before_install: before_install:
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet - gem install cocoapods --no-rdoc --no-ri --no-document --quiet
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.20.1/Carthage.pkg" - curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.23.0/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target / - sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg" - rm "Carthage.pkg"
before_script: before_script:

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "CoreStore" s.name = "CoreStore"
s.version = "4.0.0-beta" s.version = "4.0.1"
s.license = "MIT" s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift" s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore" s.homepage = "https://github.com/JohnEstropia/CoreStore"

View File

@@ -214,10 +214,10 @@
B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; }; B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; };
B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; }; B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; };
B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; }; B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */; };
B52F74411E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift */; }; B52F74411E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* UnsafeDataModelSchema.swift */; };
B52F74421E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift */; }; B52F74421E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* UnsafeDataModelSchema.swift */; };
B52F74431E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift */; }; B52F74431E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* UnsafeDataModelSchema.swift */; };
B52F74441E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift */; }; B52F74441E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743B1E9B8724005F3DAC /* UnsafeDataModelSchema.swift */; };
B52F74451E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */; }; B52F74451E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */; };
B52F74461E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */; }; B52F74461E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */; };
B52F74471E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */; }; B52F74471E9B8724005F3DAC /* XcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */; };
@@ -426,10 +426,10 @@
B56923FB1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */; }; B56923FB1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */; };
B56923FC1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */; }; B56923FC1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */; };
B56923FD1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */; }; B56923FD1EB82956007C4DC9 /* CSXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */; };
B56923FF1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift */; }; B56923FF1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */; };
B56924001EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift */; }; B56924001EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */; };
B56924011EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift */; }; B56924011EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */; };
B56924021EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift */; }; B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */; };
B56964D41B22FFAD0075EE4A /* DataStack+Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */; }; B56964D41B22FFAD0075EE4A /* DataStack+Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */; };
B56965241B356B820075EE4A /* MigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965231B356B820075EE4A /* MigrationResult.swift */; }; B56965241B356B820075EE4A /* MigrationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965231B356B820075EE4A /* MigrationResult.swift */; };
B57D27BE1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; }; B57D27BE1D0BBE8200539C58 /* BaseTestDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */; };
@@ -746,7 +746,7 @@
B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaHistory.swift; sourceTree = "<group>"; }; B52F742E1E9B50D0005F3DAC /* SchemaHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaHistory.swift; sourceTree = "<group>"; };
B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicSchema.swift; sourceTree = "<group>"; }; B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicSchema.swift; sourceTree = "<group>"; };
B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyXcodeDataModelSchema.swift; sourceTree = "<group>"; }; B52F743B1E9B8724005F3DAC /* UnsafeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnsafeDataModelSchema.swift; sourceTree = "<group>"; };
B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeDataModelSchema.swift; sourceTree = "<group>"; }; B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeDataModelSchema.swift; sourceTree = "<group>"; };
B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreSchema.swift; sourceTree = "<group>"; }; B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreSchema.swift; sourceTree = "<group>"; };
B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Logging.swift"; sourceTree = "<group>"; }; B52FD3A91E3B3EF10001D919 /* NSManagedObject+Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Logging.swift"; sourceTree = "<group>"; };
@@ -800,7 +800,7 @@
B56923DF1EB827F5007C4DC9 /* XcodeSchemaMappingProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeSchemaMappingProvider.swift; sourceTree = "<group>"; }; B56923DF1EB827F5007C4DC9 /* XcodeSchemaMappingProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeSchemaMappingProvider.swift; sourceTree = "<group>"; };
B56923F41EB828BF007C4DC9 /* CSDynamicSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSDynamicSchema.swift; sourceTree = "<group>"; }; B56923F41EB828BF007C4DC9 /* CSDynamicSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSDynamicSchema.swift; sourceTree = "<group>"; };
B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSXcodeDataModelSchema.swift; sourceTree = "<group>"; }; B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSXcodeDataModelSchema.swift; sourceTree = "<group>"; };
B56923FE1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSLegacyXcodeDataModelSchema.swift; sourceTree = "<group>"; }; B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSUnsafeDataModelSchema.swift; sourceTree = "<group>"; };
B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "DataStack+Migration.swift"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "DataStack+Migration.swift"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
B56965231B356B820075EE4A /* MigrationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationResult.swift; sourceTree = "<group>"; }; B56965231B356B820075EE4A /* MigrationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationResult.swift; sourceTree = "<group>"; };
B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestDataTestCase.swift; sourceTree = "<group>"; }; B57D27BD1D0BBE8200539C58 /* BaseTestDataTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestDataTestCase.swift; sourceTree = "<group>"; };
@@ -1108,7 +1108,7 @@
B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */, B52F743A1E9B8724005F3DAC /* DynamicSchema.swift */,
B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */, B52F74491E9B8740005F3DAC /* CoreStoreSchema.swift */,
B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */, B52F743C1E9B8724005F3DAC /* XcodeDataModelSchema.swift */,
B52F743B1E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift */, B52F743B1E9B8724005F3DAC /* UnsafeDataModelSchema.swift */,
); );
name = "Dynamic Schema"; name = "Dynamic Schema";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1190,7 +1190,7 @@
children = ( children = (
B56923F41EB828BF007C4DC9 /* CSDynamicSchema.swift */, B56923F41EB828BF007C4DC9 /* CSDynamicSchema.swift */,
B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */, B56923F91EB82956007C4DC9 /* CSXcodeDataModelSchema.swift */,
B56923FE1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift */, B56923FE1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift */,
); );
name = "Dynamic Schema"; name = "Dynamic Schema";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1788,7 +1788,7 @@
B5E1B5981CAA0C23007FD580 /* CSObjectObserver.swift in Sources */, B5E1B5981CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
B5519A5F1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */, B5519A5F1CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
B52FD3AA1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B52FD3AA1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
B52F74411E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */, B52F74411E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */,
B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, B51FE5AB1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
B5A9921F1EA898710091A2E3 /* UserInfo.swift in Sources */, B5A9921F1EA898710091A2E3 /* UserInfo.swift in Sources */,
B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */, B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */,
@@ -1900,7 +1900,7 @@
B5A991EC1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5A991EC1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */, B5FE4DA71C84FB4400FA6A91 /* InMemoryStore.swift in Sources */,
B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, B52F743D1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B56923FF1EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */, B56923FF1EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5ECDBEC1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B5ECDBEC1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B56923EC1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923EC1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */, B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */,
@@ -1972,7 +1972,7 @@
B5E1B59A1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */, B5E1B59A1CAA0C23007FD580 /* CSObjectObserver.swift in Sources */,
B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */, B5519A601CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B52FD3AB1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
B52F74421E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */, B52F74421E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */,
B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, B51FE5AD1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
B5A992201EA898720091A2E3 /* UserInfo.swift in Sources */, B5A992201EA898720091A2E3 /* UserInfo.swift in Sources */,
B5FE4DAD1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */, B5FE4DAD1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
@@ -2084,7 +2084,7 @@
B5A991ED1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5A991ED1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B5ECDBEE1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, B52F743E1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B56924001EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */, B56924001EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */, 82BA18D61C4BBD7100A0916E /* NSManagedObjectContext+Transaction.swift in Sources */,
B56923ED1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923ED1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
82BA18B91C4BBD4A00A0916E /* From.swift in Sources */, 82BA18B91C4BBD4A00A0916E /* From.swift in Sources */,
@@ -2156,7 +2156,7 @@
B5ECDC211CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */, B5ECDC211CA81A2100C7F112 /* CSDataStack+Querying.swift in Sources */,
B52DD1C21BE1F94600949AFE /* MigrationManager.swift in Sources */, B52DD1C21BE1F94600949AFE /* MigrationManager.swift in Sources */,
B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B52FD3AD1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
B52F74441E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */, B52F74441E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */,
B5ECDC2D1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */, B5ECDC2D1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
B5A992221EA898720091A2E3 /* UserInfo.swift in Sources */, B5A992221EA898720091A2E3 /* UserInfo.swift in Sources */,
B5D7A5BA1CA3BF8F005C752B /* CSInto.swift in Sources */, B5D7A5BA1CA3BF8F005C752B /* CSInto.swift in Sources */,
@@ -2268,7 +2268,7 @@
B5A991EF1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5A991EF1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
B5220E201D130813009BC71E /* CSObjectMonitor.swift in Sources */, B5220E201D130813009BC71E /* CSObjectMonitor.swift in Sources */,
B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */, B52F74401E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B56924021EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */, B56924021EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */, B5220E171D1306DF009BC71E /* UnsafeDataTransaction+Observing.swift in Sources */,
B56923EF1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923EF1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
B53FBA081CAB300C00F0D40A /* CSMigrationType.swift in Sources */, B53FBA081CAB300C00F0D40A /* CSMigrationType.swift in Sources */,
@@ -2340,7 +2340,7 @@
B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */, B5519A611CA21954002BEF78 /* CSAsynchronousDataTransaction.swift in Sources */,
B5FE4DAE1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */, B5FE4DAE1C85D44E00FA6A91 /* SQLiteStore.swift in Sources */,
B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */, B52FD3AC1E3B3EF10001D919 /* NSManagedObject+Logging.swift in Sources */,
B52F74431E9B8724005F3DAC /* LegacyXcodeDataModelSchema.swift in Sources */, B52F74431E9B8724005F3DAC /* UnsafeDataModelSchema.swift in Sources */,
B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */, B51FE5AE1CD4D00300E54258 /* CoreStore+CustomDebugStringConvertible.swift in Sources */,
B5A992211EA898720091A2E3 /* UserInfo.swift in Sources */, B5A992211EA898720091A2E3 /* UserInfo.swift in Sources */,
B563218C1BD65216006C9394 /* DataStack+Transaction.swift in Sources */, B563218C1BD65216006C9394 /* DataStack+Transaction.swift in Sources */,
@@ -2452,7 +2452,7 @@
B5A991EE1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */, B5A991EE1E9DC2CE0091A2E3 /* VersionLock.swift in Sources */,
B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */, B5ECDBEF1CA6BF2000C7F112 /* CSFrom.swift in Sources */,
B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */, B52F743F1E9B8724005F3DAC /* DynamicSchema.swift in Sources */,
B56924011EB82976007C4DC9 /* CSLegacyXcodeDataModelSchema.swift in Sources */, B56924011EB82976007C4DC9 /* CSUnsafeDataModelSchema.swift in Sources */,
B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */, B56321B41BD6521C006C9394 /* NSManagedObjectContext+Transaction.swift in Sources */,
B56923EE1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */, B56923EE1EB827F6007C4DC9 /* SchemaMappingProvider.swift in Sources */,
B56321861BD65216006C9394 /* CoreStoreLogger.swift in Sources */, B56321861BD65216006C9394 /* CoreStoreLogger.swift in Sources */,
@@ -2501,6 +2501,7 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
@@ -2559,6 +2560,7 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;

View File

@@ -8,7 +8,6 @@
import UIKit import UIKit
import CoreStore
// MARK: - AppDelegate // MARK: - AppDelegate

View File

@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.1</string> <string>4.0.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>4</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>

View File

@@ -91,6 +91,11 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
} }
} }
func listMonitorDidRefetch(_ monitor: ListMonitor<NSManagedObject>) {
self.listMonitorDidChange(monitor)
}
// MARK: UITableViewDataSource // MARK: UITableViewDataSource
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { @objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -148,27 +153,39 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
label: "Model V1", label: "Model V1",
entityType: OrganismV1.self, entityType: OrganismV1.self,
schemaHistory: SchemaHistory( schemaHistory: SchemaHistory(
XcodeDataModelSchema.from(
modelName: "MigrationDemo", modelName: "MigrationDemo",
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"] migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
),
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
) )
), ),
( (
label: "Model V2", label: "Model V2",
entityType: OrganismV2.self, entityType: OrganismV2.self,
schemaHistory: SchemaHistory( schemaHistory: SchemaHistory(
XcodeDataModelSchema.from(
modelName: "MigrationDemo", modelName: "MigrationDemo",
migrationChain: [ migrationChain: [
"MigrationDemo": "MigrationDemoV2", "MigrationDemo": "MigrationDemoV2",
"MigrationDemoV3": "MigrationDemoV2" "MigrationDemoV3": "MigrationDemoV2"
] ]
),
migrationChain: [
"MigrationDemo": "MigrationDemoV2",
"MigrationDemoV3": "MigrationDemoV2"
]
) )
), ),
( (
label: "Model V3", label: "Model V3",
entityType: OrganismV3.self, entityType: OrganismV3.self,
schemaHistory: SchemaHistory( schemaHistory: SchemaHistory(
XcodeDataModelSchema.from(
modelName: "MigrationDemo", modelName: "MigrationDemo",
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"] migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
),
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
) )
) )
] ]

View File

@@ -40,7 +40,7 @@ class BaseTestCase: XCTestCase {
func prepareStack<T>(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T { func prepareStack<T>(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
do { do {

View File

@@ -163,7 +163,7 @@
- (void)test_ThatDataStacks_BridgeCorrectly { - (void)test_ThatDataStacks_BridgeCorrectly {
CSDataStack *dataStack = [[CSDataStack alloc] CSDataStack *dataStack = [[CSDataStack alloc]
initWithModelName:@"Model" initWithXcodeModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]] bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]; versionChain:nil];
XCTAssertNotNil(dataStack); XCTAssertNotNil(dataStack);
@@ -201,7 +201,7 @@
[CSCoreStore [CSCoreStore
setDefaultStack:[[CSDataStack alloc] setDefaultStack:[[CSDataStack alloc]
initWithModelName:@"Model" initWithXcodeModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]] bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]]; versionChain:nil]];
[CSCoreStore [CSCoreStore
@@ -254,36 +254,4 @@
[self waitForExpectationsWithTimeout:10 handler:nil]; [self waitForExpectationsWithTimeout:10 handler:nil];
} }
#if TARGET_OS_IOS || TARGET_OS_WATCHOS || TARGET_OS_TV
- (void)test_ThatDataStacks_CanCreateCustomFetchedResultsControllers {
[CSCoreStore
setDefaultStack:[[CSDataStack alloc]
initWithModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]];
[CSCoreStore
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:nil];
NSFetchedResultsController *controller =
[[CSCoreStore defaultStack]
createFetchedResultsControllerFrom:CSFromClass([TestEntity1 class])
sectionBy:[CSSectionBy keyPath:CSKeyPath(TestEntity1, testString)]
fetchClauses:@[CSWhereFormat(@"%K > %d", CSKeyPath(TestEntity1, testEntityID), 100),
CSOrderByKeys(CSSortAscending(CSKeyPath(TestEntity1, testString)), nil),
CSTweakRequest(^(NSFetchRequest *fetchRequest) { fetchRequest.fetchLimit = 10; })]];
XCTAssertNotNil(controller);
XCTAssertEqualObjects(controller.fetchRequest.entity.managedObjectClassName, [[TestEntity1 class] description]);
XCTAssertEqualObjects(controller.sectionNameKeyPath, CSKeyPath(TestEntity1, testString));
XCTAssertEqualObjects(controller.fetchRequest.predicate,
CSWhereFormat(@"%K > %d", CSKeyPath(TestEntity1, testEntityID), 100).predicate);
XCTAssertEqualObjects(controller.fetchRequest.sortDescriptors,
CSOrderByKeys(CSSortAscending(CSKeyPath(TestEntity1, testString)), nil).sortDescriptors);
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10);
}
#endif
@end @end

View File

@@ -28,12 +28,18 @@ import XCTest
@testable @testable
import CoreStore import CoreStore
#if os(OSX)
typealias Color = NSColor
#else
typealias Color = UIColor
#endif
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species", default: "Swift") let species = Value.Required<String>("species", default: "Swift")
let master = Relationship.ToOne<Person>("master") let master = Relationship.ToOne<Person>("master")
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<Color>("color")
} }
class Dog: Animal { class Dog: Animal {
@@ -102,7 +108,7 @@ class DynamicModelTests: BaseTestDataTestCase {
XCTAssertEqual(animal.species.value, "Sparrow") XCTAssertEqual(animal.species.value, "Sparrow")
animal.color .= .yellow animal.color .= .yellow
XCTAssertEqual(animal.color.value, UIColor.yellow) XCTAssertEqual(animal.color.value, Color.yellow)
let dog = transaction.create(Into<Dog>()) let dog = transaction.create(Into<Dog>())
XCTAssertEqual(dog.species.value, "Swift") XCTAssertEqual(dog.species.value, "Swift")
@@ -168,7 +174,6 @@ class DynamicModelTests: BaseTestDataTestCase {
success: { success: {
fetchDone.fulfill() fetchDone.fulfill()
withExtendedLifetime(stack, {})
}, },
failure: { _ in failure: { _ in

View File

@@ -86,9 +86,11 @@ final class ErrorTests: XCTestCase {
let dummyURL = URL(string: "file:///test1/test2.sqlite")! let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let schemaHistory = SchemaHistory( let schemaHistory = SchemaHistory(
XcodeDataModelSchema.from(
modelName: "Model", modelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
)
let version = "1.0.0" let version = "1.0.0"
let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: schemaHistory.rawModel, targetModelVersion: version) let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: schemaHistory.rawModel, targetModelVersion: version)

View File

@@ -37,9 +37,10 @@ class SetupTests: BaseTestDataTestCase {
do { do {
let schemaHistory = SchemaHistory( let schemaHistory = SchemaHistory(
XcodeDataModelSchema.from(
modelName: "Model", modelName: "Model",
bundle: Bundle(for: type(of: self)), bundle: Bundle(for: type(of: self))
migrationChain: nil )
) )
let stack = DataStack(schemaHistory: schemaHistory) let stack = DataStack(schemaHistory: schemaHistory)
XCTAssertEqual(stack.coordinator.managedObjectModel, schemaHistory.rawModel) XCTAssertEqual(stack.coordinator.managedObjectModel, schemaHistory.rawModel)
@@ -66,7 +67,7 @@ class SetupTests: BaseTestDataTestCase {
let stack = self.expectLogger([.logWarning]) { let stack = self.expectLogger([.logWarning]) {
DataStack( DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)), bundle: Bundle(for: type(of: self)),
migrationChain: migrationChain migrationChain: migrationChain
) )
@@ -83,7 +84,7 @@ class SetupTests: BaseTestDataTestCase {
dynamic func test_ThatInMemoryStores_SetupCorrectly() { dynamic func test_ThatInMemoryStores_SetupCorrectly() {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -138,7 +139,7 @@ class SetupTests: BaseTestDataTestCase {
dynamic func test_ThatSQLiteStores_SetupCorrectly() { dynamic func test_ThatSQLiteStores_SetupCorrectly() {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -206,7 +207,7 @@ class SetupTests: BaseTestDataTestCase {
do { do {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
try! stack.addStorageAndWait(sqliteStore) try! stack.addStorageAndWait(sqliteStore)
@@ -225,10 +226,10 @@ class SetupTests: BaseTestDataTestCase {
let metadata = try createStore() let metadata = try createStore()
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
try sqliteStore.eraseStorageAndWait( try sqliteStore.cs_eraseStorageAndWait(
metadata: metadata, metadata: metadata,
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel() soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
) )
@@ -243,7 +244,7 @@ class SetupTests: BaseTestDataTestCase {
do { do {
let metadata = try createStore() let metadata = try createStore()
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: nil) try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path)) XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal"))) XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm"))) XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
@@ -258,7 +259,7 @@ class SetupTests: BaseTestDataTestCase {
dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() { dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
do { do {
@@ -326,7 +327,7 @@ class SetupTests: BaseTestDataTestCase {
do { do {
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
try! stack.addStorageAndWait(sqliteStore) try! stack.addStorageAndWait(sqliteStore)
@@ -345,10 +346,10 @@ class SetupTests: BaseTestDataTestCase {
let metadata = try createStore() let metadata = try createStore()
let stack = DataStack( let stack = DataStack(
modelName: "Model", xcodeModelName: "Model",
bundle: Bundle(for: type(of: self)) bundle: Bundle(for: type(of: self))
) )
try sqliteStore.eraseStorageAndWait( try sqliteStore.cs_eraseStorageAndWait(
metadata: metadata, metadata: metadata,
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel() soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
) )
@@ -363,7 +364,7 @@ class SetupTests: BaseTestDataTestCase {
do { do {
let metadata = try createStore() let metadata = try createStore()
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: nil) try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path)) XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal"))) XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm"))) XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))

748
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -30,17 +30,43 @@ import CoreData
// MARK: - AsynchronousDataTransaction // MARK: - AsynchronousDataTransaction
/** /**
The `AsynchronousDataTransaction` provides an interface for `NSManagedObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.beginAsynchronous(_:)`, or from `CoreStore.beginAsynchronous(_:)`. The `AsynchronousDataTransaction` provides an interface for `DynamicObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.perform(asynchronous:...)`, or from `CoreStore.perform(synchronous:...)`.
*/ */
public final class AsynchronousDataTransaction: BaseDataTransaction { public final class AsynchronousDataTransaction: BaseDataTransaction {
/**
Cancels a transaction by throwing `CoreStoreError.userCancelled`.
```
try transaction.cancel()
```
- Important: Never use `try?` or `try!` on a `cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error.
*/
public func cancel() throws -> Never {
throw CoreStoreError.userCancelled
}
// MARK: - Result // MARK: - Result
/**
The `Result` contains the success or failure information for a completed transaction
*/
public enum Result<T> { public enum Result<T> {
/**
`Result<T>.success` indicates that the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated `userInfo` is the value returned from the transaction closure.
*/
case success(userInfo: T) case success(userInfo: T)
/**
`Result<T>.failure` indicates that the transaction either failed or was cancelled. The associated object for this value is a `CoreStoreError` enum value.
*/
case failure(error: CoreStoreError) case failure(error: CoreStoreError)
/**
Returns `true` if the result indicates `.success`, `false` if the result is `.failure`.
*/
public var boolValue: Bool { public var boolValue: Bool {
switch self { switch self {
@@ -64,22 +90,8 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
} }
} }
// MARK: - // MARK: -
/**
Cancels a transaction by throwing `CoreStoreError.userCancelled`.
```
try transaction.cancel()
```
- Important: Never use `try?` or `try!` on a `cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error.
*/
public func cancel() throws -> Never {
throw CoreStoreError.userCancelled
}
// MARK: BaseDataTransaction // MARK: BaseDataTransaction
/** /**
@@ -99,10 +111,10 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Returns an editable proxy of a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once. Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` type to be edited - parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T: DynamicObject>(_ object: T?) -> T? { public override func edit<T: DynamicObject>(_ object: T?) -> T? {
@@ -115,11 +127,11 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Returns an editable proxy of the object with the specified `NSManagedObjectID`. This method should not be used after the `commit()` method was already called once. Returns an editable proxy of the object with the specified `NSManagedObjectID`.
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter objectID: the `NSManagedObjectID` for the object to be edited - parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? { public override func edit<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
@@ -132,9 +144,9 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Deletes a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once. Deletes a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` type to be deleted - parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object: T?) { public override func delete<T: DynamicObject>(_ object: T?) {
@@ -147,11 +159,11 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `DynamicObject`s.
- parameter object1: the `NSManagedObject` type to be deleted - parameter object1: the `DynamicObject` to be deleted
- parameter object2: another `NSManagedObject` type to be deleted - parameter object2: another `DynamicObject` to be deleted
- parameter objects: other `NSManagedObject`s type to be deleted - parameter objects: other `DynamicObject`s to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) { public override func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) {
@@ -164,11 +176,11 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `DynamicObject`s.
- parameter objects: the `NSManagedObject`s type to be deleted - parameter objects: the `DynamicObject`s to be deleted
*/ */
public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: NSManagedObject { public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
CoreStore.assert( CoreStore.assert(
!self.isCommitted, !self.isCommitted,
@@ -203,11 +215,6 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
// MARK: Deprecated // MARK: Deprecated
/**
Saves the transaction changes. This method should not be used after the `commit()` method was already called once.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `SaveResult` argument of the block.
*/
@available(*, deprecated, message: "Use the new auto-commiting methods `DataStack.perform(asynchronous:completion:)` or `DataStack.perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.") @available(*, deprecated, message: "Use the new auto-commiting methods `DataStack.perform(asynchronous:completion:)` or `DataStack.perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
public func commit(_ completion: @escaping (_ result: SaveResult) -> Void = { _ in }) { public func commit(_ completion: @escaping (_ result: SaveResult) -> Void = { _ in }) {
@@ -229,12 +236,6 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
} }
} }
/**
Begins a child transaction synchronously where NSManagedObject creates, updates, and deletes can be made. This method should not be used after the `commit()` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ") @available(*, deprecated, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ")
@discardableResult @discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? { public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {

View File

@@ -177,7 +177,7 @@ public extension BaseDataTransaction {
/** /**
Updates existing `ImportableUniqueObject`s or creates them by importing from the specified array of import sources. Updates existing `ImportableUniqueObject`s or creates them by importing from the specified array of import sources.
`ImportableUniqueObject` methods are called on the objects in the same order as they are in the `sourceArray`, and are returned in an array with that same order. `ImportableUniqueObject` methods are called on the objects in the same order as they are in the `sourceArray`, and are returned in an array with that same order.
- Warning: If `sourceArray` contains multiple import sources with same ID, no merging will occur and ONLY THE LAST duplicate will be imported. - Warning: If `sourceArray` contains multiple import sources with same ID, only the last `ImportSource` of the duplicates will be imported.
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter sourceArray: the array of objects to import values from - parameter sourceArray: the array of objects to import values from

View File

@@ -32,11 +32,11 @@ import CoreData
extension BaseDataTransaction: FetchableSource, QueryableSource { extension BaseDataTransaction: FetchableSource, QueryableSource {
/** /**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Deletes all `DynamicObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number of `NSManagedObject`s deleted - returns: the number of `DynamicObject`s deleted
*/ */
@discardableResult @discardableResult
public func deleteAll<T: DynamicObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? { public func deleteAll<T: DynamicObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
@@ -50,11 +50,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Deletes all `DynamicObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number of `NSManagedObject`s deleted - returns: the number of `DynamicObject`s deleted
*/ */
@discardableResult @discardableResult
public func deleteAll<T: DynamicObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? { public func deleteAll<T: DynamicObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
@@ -71,10 +71,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
// MARK: FetchableSource // MARK: FetchableSource
/** /**
Fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context. Fetches the `DynamicObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
- parameter object: a reference to the object created/fetched outside the transaction - parameter object: a reference to the object created/fetched outside the transaction
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ object: T) -> T? { public func fetchExisting<T: DynamicObject>(_ object: T) -> T? {
@@ -82,10 +82,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObject` instance in the transaction's context from an `NSManagedObjectID`. Fetches the `DynamicObject` instance in the transaction's context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? { public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? {
@@ -93,10 +93,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObject` instances in the transaction's context from references created from a transaction or from a different managed object context. Fetches the `DynamicObject` instances in the transaction's context from references created from a transaction or from a different managed object context.
- parameter objects: an array of `NSManagedObject`s created/fetched outside the transaction - parameter objects: an array of `DynamicObject`s created/fetched outside the transaction
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `DynamicObject` array for objects that exists in the transaction
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
@@ -104,10 +104,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObject` instances in the transaction's context from a list of `NSManagedObjectID`. Fetches the `DynamicObject` instances in the transaction's context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the transaction - returns: the `DynamicObject` array for objects that exists in the transaction
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID { public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
@@ -115,11 +115,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? { public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
@@ -131,11 +131,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? { public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
@@ -147,11 +147,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? { public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
@@ -163,11 +163,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? { public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
@@ -179,11 +179,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? { public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
@@ -195,11 +195,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? { public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
@@ -211,11 +211,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? { public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
@@ -227,11 +227,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? { public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
@@ -243,11 +243,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? { public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
@@ -259,11 +259,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
@@ -365,11 +365,11 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
} }
// MARK: Deprecated // MARK: Obsoleted
@available(*, deprecated, renamed: "unsafeContext()") @available(*, obsoleted: 3.1, renamed: "unsafeContext()")
public func internalContext() -> NSManagedObjectContext { public func internalContext() -> NSManagedObjectContext {
return self.unsafeContext() fatalError()
} }
} }

View File

@@ -215,11 +215,12 @@ public /*abstract*/ class BaseDataTransaction {
// MARK: Inspecting Pending Objects // MARK: Inspecting Pending Objects
/** /**
Returns all pending `NSManagedObject`s that were inserted to the transaction. This method should not be called after the `commit()` method was called. Returns all pending `DynamicObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
- returns: a `Set` of pending `NSManagedObject`s that were inserted to the transaction. - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were inserted to the transaction.
*/ */
public func insertedObjects() -> Set<NSManagedObject> { public func insertedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -229,26 +230,7 @@ public /*abstract*/ class BaseDataTransaction {
!self.isCommitted, !self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))." "Attempted to access inserted objects from an already committed \(cs_typeName(self))."
) )
return self.context.insertedObjects return Set(self.context.insertedObjects.flatMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
}
/**
Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were inserted to the transaction.
*/
public func insertedObjects<T: NSManagedObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.insertedObjects.flatMap { $0 as? T })
} }
/** /**
@@ -272,10 +254,10 @@ public /*abstract*/ class BaseDataTransaction {
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction.
*/ */
public func insertedObjectIDs<T: NSManagedObject>(_ entity: T.Type) -> Set<NSManagedObjectID> { public func insertedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -285,15 +267,16 @@ public /*abstract*/ class BaseDataTransaction {
!self.isCommitted, !self.isCommitted,
"Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))." "Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.insertedObjects.filter { $0.isKind(of: entity) }.map { $0.objectID }) return Set(self.context.insertedObjects.flatMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
} }
/** /**
Returns all pending `NSManagedObject`s that were updated in the transaction. This method should not be called after the `commit()` method was called. Returns all pending `DynamicObject`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
- returns: a `Set` of pending `NSManagedObject`s that were updated to the transaction. - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were updated in the transaction.
*/ */
public func updatedObjects() -> Set<NSManagedObject> { public func updatedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -303,26 +286,7 @@ public /*abstract*/ class BaseDataTransaction {
!self.isCommitted, !self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))." "Attempted to access updated objects from an already committed \(cs_typeName(self))."
) )
return self.context.updatedObjects return Set(self.context.updatedObjects.flatMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
}
/**
Returns all pending `NSManagedObject`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were updated in the transaction.
*/
public func updatedObjects<T: NSManagedObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.updatedObjects.filter { $0.isKind(of: entity) }.map { $0 as! T })
} }
/** /**
@@ -346,10 +310,10 @@ public /*abstract*/ class BaseDataTransaction {
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction.
*/ */
public func updatedObjectIDs<T: NSManagedObject>(_ entity: T.Type) -> Set<NSManagedObjectID> { public func updatedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -359,15 +323,16 @@ public /*abstract*/ class BaseDataTransaction {
!self.isCommitted, !self.isCommitted,
"Attempted to access updated object IDs from an already committed \(cs_typeName(self))." "Attempted to access updated object IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.updatedObjects.filter { $0.isKind(of: entity) }.map { $0.objectID }) return Set(self.context.updatedObjects.flatMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
} }
/** /**
Returns all pending `NSManagedObject`s that were deleted from the transaction. This method should not be called after the `commit()` method was called. Returns all pending `DynamicObject`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- returns: a `Set` of pending `NSManagedObject`s that were deleted from the transaction. - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `DynamicObject`s of the specified type that were deleted from the transaction.
*/ */
public func deletedObjects() -> Set<NSManagedObject> { public func deletedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -377,32 +342,13 @@ public /*abstract*/ class BaseDataTransaction {
!self.isCommitted, !self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))." "Attempted to access deleted objects from an already committed \(cs_typeName(self))."
) )
return self.context.deletedObjects return Set(self.context.deletedObjects.flatMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
}
/**
Returns all pending `NSManagedObject`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were deleted from the transaction.
*/
public func deletedObjects<T: NSManagedObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.deletedObjects.filter { $0.isKind(of: entity) }.map { $0 as! T })
} }
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
public func deletedObjectIDs() -> Set<NSManagedObjectID> { public func deletedObjectIDs() -> Set<NSManagedObjectID> {
@@ -421,10 +367,10 @@ public /*abstract*/ class BaseDataTransaction {
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
- parameter entity: the `NSManagedObject` subclass to filter - parameter entity: the `DynamicObject` subclass to filter
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
public func deletedObjectIDs<T: NSManagedObject>(_ entity: T.Type) -> Set<NSManagedObjectID> { public func deletedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
CoreStore.assert( CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(), self.transactionQueue.cs_isCurrentExecutionContext(),
@@ -434,7 +380,7 @@ public /*abstract*/ class BaseDataTransaction {
!self.isCommitted, !self.isCommitted,
"Attempted to access deleted object IDs from an already committed \(cs_typeName(self))." "Attempted to access deleted object IDs from an already committed \(cs_typeName(self))."
) )
return Set(self.context.deletedObjects.filter { $0.isKind(of: entity) }.map { $0.objectID }) return Set(self.context.deletedObjects.flatMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
} }
@@ -450,7 +396,7 @@ public /*abstract*/ class BaseDataTransaction {
``` ```
- Important: Do not use this method to store thread-sensitive data. - Important: Do not use this method to store thread-sensitive data.
*/ */
private let userInfo = UserInfo() public let userInfo = UserInfo()
// MARK: Internal // MARK: Internal
@@ -491,4 +437,49 @@ public /*abstract*/ class BaseDataTransaction {
return self.bypassesQueueing || self.transactionQueue.cs_isCurrentExecutionContext() return self.bypassesQueueing || self.transactionQueue.cs_isCurrentExecutionContext()
} }
// MARK: Deprecated
@available(*, deprecated, message: "Use insertedObjects(_:) and pass the specific entity type")
public func insertedObjects() -> Set<NSManagedObject> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
)
return self.context.insertedObjects
}
@available(*, deprecated, message: "Use updatedObjects(_:) and pass the specific entity type")
public func updatedObjects() -> Set<NSManagedObject> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
)
return self.context.updatedObjects
}
@available(*, deprecated, message: "Use deletedObjects(_:) and pass the specific entity type")
public func deletedObjects() -> Set<NSManagedObject> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
)
return self.context.deletedObjects
}
} }

View File

@@ -40,7 +40,8 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
/** /**
Saves the transaction changes. This method should not be used after the `-commitWithCompletion:` method was already called once. Saves the transaction changes. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block. - parameter success: the block executed if the save succeeds.
- parameter failure: the block executed if the save fails. A `CSError` is reported as the argument of the block.
*/ */
@objc @objc
public func commitWithSuccess(_ success: (() -> Void)?, failure: ((CSError) -> Void)?) { public func commitWithSuccess(_ success: (() -> Void)?, failure: ((CSError) -> Void)?) {
@@ -156,11 +157,6 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
// MARK: Deprecated // MARK: Deprecated
/**
Saves the transaction changes. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
*/
@available(*, deprecated, message: "Use the new -[CSAsynchronousDataTransaction commitWithSuccess:failure:] method.") @available(*, deprecated, message: "Use the new -[CSAsynchronousDataTransaction commitWithSuccess:failure:] method.")
@objc @objc
public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) { public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) {
@@ -179,12 +175,6 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
} }
} }
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ") @available(*, deprecated, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ")
@objc @objc
@discardableResult @discardableResult

View File

@@ -119,17 +119,6 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
// MARK: Inspecting Pending Objects // MARK: Inspecting Pending Objects
/**
Returns all pending `NSManagedObject`s that were inserted to the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were inserted to the transaction.
*/
@objc
public func insertedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.insertedObjects()
}
/** /**
Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `-commit*:` method was called. Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `-commit*:` method was called.
@@ -165,17 +154,6 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
return self.bridgeToSwift.insertedObjectIDs(entity) return self.bridgeToSwift.insertedObjectIDs(entity)
} }
/**
Returns all pending `NSManagedObject`s that were updated in the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were updated to the transaction.
*/
@objc
public func updatedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.updatedObjects()
}
/** /**
Returns all pending `NSManagedObject`s of the specified type that were updated in the transaction. This method should not be called after the `-commit*:` method was called. Returns all pending `NSManagedObject`s of the specified type that were updated in the transaction. This method should not be called after the `-commit*:` method was called.
@@ -211,17 +189,6 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
return self.bridgeToSwift.updatedObjectIDs(entity) return self.bridgeToSwift.updatedObjectIDs(entity)
} }
/**
Returns all pending `NSManagedObject`s that were deleted from the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were deleted from the transaction.
*/
@objc
public func deletedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.deletedObjects()
}
/** /**
Returns all pending `NSManagedObject`s of the specified type that were deleted from the transaction. This method should not be called after the `-commit*:` method was called. Returns all pending `NSManagedObject`s of the specified type that were deleted from the transaction. This method should not be called after the `-commit*:` method was called.
@@ -237,7 +204,6 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
/** /**
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `-commit*:` method was called. Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `-commit*:` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. - returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/ */
@objc @objc
@@ -293,4 +259,28 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
// MARK: Private // MARK: Private
private let swiftTransaction: BaseDataTransaction private let swiftTransaction: BaseDataTransaction
// MARK: Deprecated
@available(*, deprecated, message: "Use -[insertedObjectsOfType:] and pass the specific entity class")
@objc
public func insertedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.insertedObjects()
}
@available(*, deprecated, message: "Use -[updatedObjectsOfType:] and pass the specific entity class")
@objc
public func updatedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.updatedObjects()
}
@available(*, deprecated, message: "Use -[deletedObjectsOfType:] and pass the specific entity class")
@objc
public func deletedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.deletedObjects()
}
} }

View File

@@ -129,23 +129,14 @@ public extension CSCoreStore {
// MARK: Deprecated // MARK: Deprecated
/** @available(*, deprecated, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
Returns the entity name-to-class type mapping from the `defaultStack`'s model.
*/
@available(*, deprecated: 3.1, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc @objc
public static var entityClassesByName: [EntityName: NSManagedObject.Type] { public static var entityClassesByName: [EntityName: NSManagedObject.Type] {
return CoreStore.entityTypesByName return CoreStore.entityTypesByName
} }
/** @available(*, deprecated, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
Returns the entity class for the given entity name from the `defaultStack`'s model.
- parameter name: the entity name
- returns: the `NSManagedObject` class for the given entity name, or `nil` if not found
*/
@available(*, deprecated: 3.1, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc @objc
public static func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? { public static func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? {

View File

@@ -95,12 +95,6 @@ public extension CSCoreStore {
// MARK: Deprecated // MARK: Deprecated
/**
Using the `defaultStack`, begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Use the new +[CSCoreStore beginSynchronous:error:] API that reports failure using an error instance.") @available(*, deprecated, message: "Use the new +[CSCoreStore beginSynchronous:error:] API that reports failure using an error instance.")
@objc @objc
@discardableResult @discardableResult

View File

@@ -135,12 +135,6 @@ public extension CSDataStack {
// MARK: Deprecated // MARK: Deprecated
/**
Begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Use the new -[CSDataStack beginSynchronous:error:] API that reports failure using an error instance.") @available(*, deprecated, message: "Use the new -[CSDataStack beginSynchronous:error:] API that reports failure using an error instance.")
@objc @objc
@discardableResult @discardableResult

View File

@@ -49,41 +49,22 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
/** /**
Initializes a `CSDataStack` from the model with the specified `modelName` in the specified `bundle`. Initializes a `CSDataStack` from the model with the specified `modelName` in the specified `bundle`.
- parameter modelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set. - parameter xcodeModelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set.
- parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used. - parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used.
- parameter versionChain: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. - parameter versionChain: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/ */
@objc @objc
public convenience init(modelName: XcodeDataModelFileName?, bundle: Bundle?, versionChain: [String]?) { public convenience init(xcodeModelName: XcodeDataModelFileName?, bundle: Bundle?, versionChain: [String]?) {
self.init( self.init(
DataStack( DataStack(
modelName: modelName ?? DataStack.applicationName, xcodeModelName: xcodeModelName ?? DataStack.applicationName,
bundle: bundle ?? Bundle.main, bundle: bundle ?? Bundle.main,
migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil
) )
) )
} }
/**
Initializes a `CSDataStack` from the model with the specified `modelName` in the specified `bundle`.
- parameter modelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set.
- parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used.
- parameter versionTree: the version strings that indicate the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/
@objc
public convenience init(modelName: XcodeDataModelFileName?, bundle: Bundle?, versionTree: [String: String]?) {
self.init(
DataStack(
modelName: modelName ?? DataStack.applicationName,
bundle: bundle ?? Bundle.main,
migrationChain: versionTree.flatMap { MigrationChain($0) } ?? nil
)
)
}
/** /**
Returns the stack's model version. The version string is the same as the name of the version-specific .xcdatamodeld file. Returns the stack's model version. The version string is the same as the name of the version-specific .xcdatamodeld file.
*/ */
@@ -227,13 +208,20 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
// MARK: Deprecated // MARK: Deprecated
/** @available(*, deprecated, message: "Use the -[initWithXcodeModelName:bundle:versionChain:] initializer.")
Initializes a `DataStack` from an `NSManagedObjectModel`. @objc
public convenience init(modelName: XcodeDataModelFileName?, bundle: Bundle?, versionChain: [String]?) {
- parameter model: the `NSManagedObjectModel` for the stack self.init(
- parameter versionChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. DataStack(
*/ xcodeModelName: modelName ?? DataStack.applicationName,
@available(*, deprecated: 3.1, message: "Use the -[initWithModelName:bundle:versionChain:] initializer.") bundle: bundle ?? Bundle.main,
migrationChain: versionChain.flatMap { MigrationChain($0) } ?? nil
)
)
}
@available(*, deprecated, message: "Use the -[initWithModelName:bundle:versionChain:] initializer.")
@objc @objc
public convenience init(model: NSManagedObjectModel, versionChain: [String]?) { public convenience init(model: NSManagedObjectModel, versionChain: [String]?) {
@@ -245,13 +233,7 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
) )
} }
/** @available(*, deprecated, message: "Use the -[initWithModelName:bundle:versionTree:] initializer.")
Initializes a `DataStack` from an `NSManagedObjectModel`.
- parameter model: the `NSManagedObjectModel` for the stack
- parameter versionTree: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/
@available(*, deprecated: 3.1, message: "Use the -[initWithModelName:bundle:versionTree:] initializer.")
@objc @objc
public convenience init(model: NSManagedObjectModel, versionTree: [String]?) { public convenience init(model: NSManagedObjectModel, versionTree: [String]?) {
@@ -263,22 +245,14 @@ public final class CSDataStack: NSObject, CoreStoreObjectiveCType {
) )
} }
/** @available(*, deprecated, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
Returns the entity name-to-class type mapping from the stack's model.
*/
@available(*, deprecated: 3.1, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc @objc
public var entityClassesByName: [EntityName: NSManagedObject.Type] { public var entityClassesByName: [EntityName: NSManagedObject.Type] {
return self.bridgeToSwift.entityTypesByName return self.bridgeToSwift.entityTypesByName
} }
/** @available(*, deprecated, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
Returns the entity class for the given entity name from the stack's's model.
- parameter name: the entity name
- returns: the `NSManagedObject` class for the given entity name, or `nil` if not found
*/
@available(*, deprecated: 3.1, message: "Use the new -entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
@objc @objc
public func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? { public func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? {

View File

@@ -82,6 +82,7 @@ public final class CSFrom: NSObject {
MyPersonEntity *people = [transaction fetchAllFrom: MyPersonEntity *people = [transaction fetchAllFrom:
CSFromClass([MyPersonEntity class], @"Config1")]; CSFromClass([MyPersonEntity class], @"Config1")];
``` ```
- parameter entityClass: the associated `NSManagedObject` entity class
- parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. - parameter configuration: the `NSPersistentStore` configuration name to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration.
*/ */
@objc @objc
@@ -107,7 +108,7 @@ public final class CSFrom: NSObject {
CSFromClass([MyPersonEntity class], CSFromClass([MyPersonEntity class],
@[[NSNull null], @"Config1"])]; @[[NSNull null], @"Config1"])];
``` ```
- parameter entity: the associated `NSManagedObject` entity class - parameter entityClass: the associated `NSManagedObject` entity class
- parameter configurations: an array of the `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration. - parameter configurations: an array of the `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `[NSNull null]` to use the default configuration.
*/ */
@objc @objc

View File

@@ -78,7 +78,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
} }
/** /**
Initializes an `CSSQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `[CSLocalStorageOptions none]`. Initializes an `CSSQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, and `localStorageOptions` set to `[CSLocalStorageOptions none]`.
- Important: Initializing `CSSQLiteStore`s with custom migration mapping models is currently not supported. Create an `SQLiteStore` instance from Swift code and bridge the instance to Objective-C using its `SQLiteStore.bridgeToObjectiveC` property. - Important: Initializing `CSSQLiteStore`s with custom migration mapping models is currently not supported. Create an `SQLiteStore` instance from Swift code and bridge the instance to Objective-C using its `SQLiteStore.bridgeToObjectiveC` property.
*/ */
@@ -151,11 +151,11 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `CSSQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `CSSQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
@objc @objc
public func eraseStorageAndWait(metadata: NSDictionary, soureModelHint: NSManagedObjectModel?, error: NSErrorPointer) -> Bool { public func cs_eraseStorageAndWait(metadata: NSDictionary, soureModelHint: NSManagedObjectModel?, error: NSErrorPointer) -> Bool {
return bridge(error) { return bridge(error) {
try self.bridgeToSwift.eraseStorageAndWait(metadata: metadata as! [String: Any], soureModelHint: soureModelHint) try self.bridgeToSwift.cs_eraseStorageAndWait(metadata: metadata as! [String: Any], soureModelHint: soureModelHint)
} }
} }
@@ -193,52 +193,20 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
} }
// MARK: Deprecated // MARK: Obsoleted
/** @available(*, obsoleted: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new -[CSSQLiteStore initWithFileURL:configuration:localStorageOptions:]) initializer instead.")
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `CSDataStack`'s `-addStorage*:` methods, a new SQLite file will be created if it does not exist.
- Important: Initializing `CSSQLiteStore`s with custom migration mapping models is currently not supported. Create an `SQLiteStore` instance from Swift code and bridge the instance to Objective-C using its `SQLiteStore.bridgeToObjectiveC` property.
- parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration.
- parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `CSLocalStorageOptionsNone`.
*/
@available(*, deprecated: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new -[CSSQLiteStore initWithFileURL:configuration:localStorageOptions:]) initializer instead.")
@objc @objc
public convenience init(fileURL: URL, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) { public convenience init(fileURL: URL, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) {
self.init( fatalError()
SQLiteStore(
fileURL: fileURL,
configuration: configuration,
mappingModelBundles: mappingModelBundles ?? Bundle.allBundles,
localStorageOptions: LocalStorageOptions(rawValue: localStorageOptions)
)
)
} }
/** @available(*, obsoleted: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new -[CSSQLiteStore initWithFileName:configuration:localStorageOptions:]) initializer instead.")
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `CSDataStack`'s `-addStorage*:` methods, a new SQLite file will be created if it does not exist.
- Important: Initializing `CSSQLiteStore`s with custom migration mapping models is currently not supported. Create an `SQLiteStore` instance from Swift code and bridge the instance to Objective-C using its `SQLiteStore.bridgeToObjectiveC` property.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration
- parameter localStorageOptions: When the `CSSQLiteStore` is passed to the `CSDataStack`'s `addStorage()` methods, tells the `CSDataStack` how to setup the persistent store. Defaults to `[CSLocalStorageOptions none]`.
*/
@available(*, deprecated: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new -[CSSQLiteStore initWithFileName:configuration:localStorageOptions:]) initializer instead.")
@objc @objc
public convenience init(fileName: String, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) { public convenience init(fileName: String, configuration: ModelConfiguration, mappingModelBundles: [Bundle]?, localStorageOptions: Int) {
self.init( fatalError()
SQLiteStore(
fileName: fileName,
configuration: configuration,
mappingModelBundles: mappingModelBundles ?? Bundle.allBundles,
localStorageOptions: LocalStorageOptions(rawValue: localStorageOptions)
)
)
} }
} }

View File

@@ -29,36 +29,22 @@ import CoreData
// MARK: - CSSaveResult // MARK: - CSSaveResult
/**
The `CSSaveResult` serves as the Objective-C bridging type for `SaveResult`.
- SeeAlso: `SaveResult`
*/
@available(*, deprecated, message: "Use APIs that report failures with `CSError`s instead.") @available(*, deprecated, message: "Use APIs that report failures with `CSError`s instead.")
@objc @objc
public final class CSSaveResult: NSObject, CoreStoreObjectiveCType { public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
/**
`YES` if the `commit` operation for the transaction succeeded, either because the save succeeded or because there were no changes to save. Returns `NO` to indicate failure.
*/
@objc @objc
public var isSuccess: Bool { public var isSuccess: Bool {
return self.bridgeToSwift.boolValue return self.bridgeToSwift.boolValue
} }
/**
`YES` if the `commit` operation for the transaction failed, or `NO` otherwise. When `YES`, the `error` property returns the actual `NSError` for the failure.
*/
@objc @objc
public var isFailure: Bool { public var isFailure: Bool {
return !self.bridgeToSwift.boolValue return !self.bridgeToSwift.boolValue
} }
/**
`YES` if the `commit` operation for the transaction succeeded and if there was an actual change made. Returns `NO` otherwise.
*/
@objc @objc
public var hasChanges: Bool { public var hasChanges: Bool {
@@ -69,9 +55,6 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
return hasChanges return hasChanges
} }
/**
The `NSError` for a failed `commit` operation, or `nil` if the `commit` succeeded
*/
@objc @objc
public var error: NSError? { public var error: NSError? {
@@ -82,14 +65,6 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
return error.bridgeToObjectiveC return error.bridgeToObjectiveC
} }
/**
If the result was a success, the `success` block is executed with a `BOOL` argument that indicates if there were any changes made. If the result was a failure, the `failure` block is executed with an `NSError` argument pertaining to the actual error.
The blocks are executed immediately as `@noescape` and will not be retained.
- parameter success: the block to execute on success. The block passes a `BOOL` argument that indicates if there were any changes made.
- parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error.
*/
@objc @objc
public func handleSuccess(_ success: (_ hasChanges: Bool) -> Void, failure: (_ error: NSError) -> Void) { public func handleSuccess(_ success: (_ hasChanges: Bool) -> Void, failure: (_ error: NSError) -> Void) {
@@ -103,13 +78,6 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
} }
} }
/**
If the result was a success, the `success` block is executed with a `BOOL` argument that indicates if there were any changes made. If the result was a failure, this method does nothing.
The block is executed immediately as `@noescape` and will not be retained.
- parameter success: the block to execute on success. The block passes a `BOOL` argument that indicates if there were any changes made.
*/
@objc @objc
public func handleSuccess(_ success: (_ hasChanges: Bool) -> Void) { public func handleSuccess(_ success: (_ hasChanges: Bool) -> Void) {
@@ -120,13 +88,6 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
success(hasChanges) success(hasChanges)
} }
/**
If the result was a failure, the `failure` block is executed with an `NSError` argument pertaining to the actual error. If the result was a success, this method does nothing.
The block is executed immediately as `@noescape` and will not be retained.
- parameter failure: the block to execute on failure. The block passes an `NSError` argument that pertains to the actual error.
*/
@objc @objc
public func handleFailure(_ failure: (_ error: NSError) -> Void) { public func handleFailure(_ failure: (_ error: NSError) -> Void) {

View File

@@ -146,7 +146,6 @@ public final class CSSelectTerm: NSObject, CoreStoreObjectiveCType {
select:[CSSelect objectIDForTerm:[CSSelectTerm objectIDAs:nil]] select:[CSSelect objectIDForTerm:[CSSelectTerm objectIDAs:nil]]
fetchClauses:@[[CSWhere keyPath:@"employeeID" isEqualTo: @1111]]]; fetchClauses:@[[CSWhere keyPath:@"employeeID" isEqualTo: @1111]]];
``` ```
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "objecID" is used - parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "objecID" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute - returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/ */
@@ -217,7 +216,7 @@ public final class CSSelect: NSObject {
select:CSSelectNumber(CSAggregateMax(@"age")) select:CSSelectNumber(CSAggregateMax(@"age"))
// ... // ...
``` ```
- parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter numberTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
public convenience init(numberTerm: CSSelectTerm) { public convenience init(numberTerm: CSSelectTerm) {
@@ -232,7 +231,7 @@ public final class CSSelect: NSObject {
select:CSSelectDecimal(CSAggregateAverage(@"price")) select:CSSelectDecimal(CSAggregateAverage(@"price"))
// ... // ...
``` ```
- parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter decimalTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
public convenience init(decimalTerm: CSSelectTerm) { public convenience init(decimalTerm: CSSelectTerm) {
@@ -247,7 +246,7 @@ public final class CSSelect: NSObject {
select:CSSelectString(CSAttribute(@"fullname")) select:CSSelectString(CSAttribute(@"fullname"))
// ... // ...
``` ```
- parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter stringTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
public convenience init(stringTerm: CSSelectTerm) { public convenience init(stringTerm: CSSelectTerm) {
@@ -262,7 +261,7 @@ public final class CSSelect: NSObject {
select:CSSelectDate(CSAggregateMax(@"updatedDate")) select:CSSelectDate(CSAggregateMax(@"updatedDate"))
// ... // ...
``` ```
- parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter dateTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
public convenience init(dateTerm: CSSelectTerm) { public convenience init(dateTerm: CSSelectTerm) {
@@ -277,7 +276,7 @@ public final class CSSelect: NSObject {
select:CSSelectData(CSAttribute(@"imageData")) select:CSSelectData(CSAttribute(@"imageData"))
// ... // ...
``` ```
- parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query - parameter dataTerm: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
public convenience init(dataTerm: CSSelectTerm) { public convenience init(dataTerm: CSSelectTerm) {
@@ -292,7 +291,6 @@ public final class CSSelect: NSObject {
select:CSSelectObjectID() select:CSSelectObjectID()
// ... // ...
``` ```
- parameter term: the `CSSelectTerm` specifying the attribute/aggregate value to query
*/ */
public convenience init(objectIDTerm: ()) { public convenience init(objectIDTerm: ()) {

View File

@@ -121,5 +121,5 @@ public protocol CSLocalStorage: CSStorageInterface {
Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting) Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting)
*/ */
@objc @objc
func eraseStorageAndWait(metadata: NSDictionary, soureModelHint: NSManagedObjectModel?, error: NSErrorPointer) -> Bool func cs_eraseStorageAndWait(metadata: NSDictionary, soureModelHint: NSManagedObjectModel?, error: NSErrorPointer) -> Bool
} }

View File

@@ -147,11 +147,6 @@ public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
// MARK: Deprecated // MARK: Deprecated
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `-commitAndWait` method was already called once.
- returns: a `CSSaveResult` containing the success or failure information
*/
@available(*, deprecated, message: "Use the new -[CSSynchronousDataTransaction commitAndWaitWithError:] method") @available(*, deprecated, message: "Use the new -[CSSynchronousDataTransaction commitAndWaitWithError:] method")
@objc @objc
public func commitAndWait() -> CSSaveResult { public func commitAndWait() -> CSSaveResult {
@@ -162,12 +157,6 @@ public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
} }
} }
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitAndWait` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ") @available(*, deprecated, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ")
@objc @objc
@discardableResult @discardableResult

View File

@@ -1,5 +1,5 @@
// //
// CSLegacyXcodeDataModelSchema.swift // CSUnsafeDataModelSchema.swift
// CoreStore // CoreStore
// //
// Copyright © 2017 John Rommel Estropia // Copyright © 2017 John Rommel Estropia
@@ -27,20 +27,26 @@ import CoreData
import Foundation import Foundation
// MARK: - CSLegacyXcodeDataModelSchema // MARK: - CSUnsafeDataModelSchema
/** /**
The `CSLegacyXcodeDataModelSchema` serves as the Objective-C bridging type for `LegacyXcodeDataModelSchema`. The `CSUnsafeDataModelSchema` serves as the Objective-C bridging type for `UnsafeDataModelSchema`.
- SeeAlso: `LegacyXcodeDataModelSchema` - SeeAlso: `UnsafeDataModelSchema`
*/ */
@objc @objc
public final class CSLegacyXcodeDataModelSchema: NSObject, CSDynamicSchema, CoreStoreObjectiveCType { public final class CSUnsafeDataModelSchema: NSObject, CSDynamicSchema, CoreStoreObjectiveCType {
/**
Initializes a `CSUnsafeDataModelSchema` from an `NSManagedObjectModel`.
- parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension)
- parameter model: the `NSManagedObjectModel`
*/
@objc @objc
public required init(modelName: ModelVersion, model: NSManagedObjectModel) { public required init(modelName: ModelVersion, model: NSManagedObjectModel) {
self.bridgeToSwift = LegacyXcodeDataModelSchema( self.bridgeToSwift = UnsafeDataModelSchema(
modelName: modelName, modelName: modelName,
model: model model: model
) )
@@ -56,7 +62,7 @@ public final class CSLegacyXcodeDataModelSchema: NSObject, CSDynamicSchema, Core
public override func isEqual(_ object: Any?) -> Bool { public override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? CSLegacyXcodeDataModelSchema else { guard let object = object as? CSUnsafeDataModelSchema else {
return false return false
} }
@@ -86,9 +92,9 @@ public final class CSLegacyXcodeDataModelSchema: NSObject, CSDynamicSchema, Core
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public let bridgeToSwift: LegacyXcodeDataModelSchema public let bridgeToSwift: UnsafeDataModelSchema
public required init(_ swiftValue: LegacyXcodeDataModelSchema) { public required init(_ swiftValue: UnsafeDataModelSchema) {
self.bridgeToSwift = swiftValue self.bridgeToSwift = swiftValue
super.init() super.init()
@@ -96,14 +102,14 @@ public final class CSLegacyXcodeDataModelSchema: NSObject, CSDynamicSchema, Core
} }
// MARK: - LegacyXcodeDataModelSchema // MARK: - UnsafeDataModelSchema
extension LegacyXcodeDataModelSchema: CoreStoreSwiftType { extension UnsafeDataModelSchema: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
public var bridgeToObjectiveC: CSLegacyXcodeDataModelSchema { public var bridgeToObjectiveC: CSUnsafeDataModelSchema {
return CSLegacyXcodeDataModelSchema(self) return CSUnsafeDataModelSchema(self)
} }
} }

View File

@@ -39,13 +39,18 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
/** /**
Saves the transaction changes asynchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread. Saves the transaction changes asynchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `error` argument of the block. - parameter success: the block executed if the save succeeds.
- parameter failure: the block executed if the save fails. A `CSError` is reported as the argument of the block.
*/ */
@objc @objc
public func commitWithSuccess(_ success: (() -> Void)?, _ failure: ((CSError) -> Void)?) { public func commitWithSuccess(_ success: (() -> Void)?, _ failure: ((CSError) -> Void)?) {
self.bridgeToSwift.context.saveAsynchronouslyWithCompletion { (_, error) in self.bridgeToSwift.context.saveAsynchronouslyWithCompletion { (_, error) in
defer {
withExtendedLifetime(self, {})
}
if let error = error { if let error = error {
failure?(error.bridgeToObjectiveC) failure?(error.bridgeToObjectiveC)
@@ -54,7 +59,6 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
success?() success?()
} }
withExtendedLifetime(self, {})
} }
} }
@@ -118,7 +122,7 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
Flushes all pending changes to the transaction's observers at the end of the `closure`'s execution. This is useful in conjunction with `ListMonitor`s and `ObjectMonitor`s created from `UnsafeDataTransaction`s used to manage temporary "scratch" data. Flushes all pending changes to the transaction's observers at the end of the `closure`'s execution. This is useful in conjunction with `ListMonitor`s and `ObjectMonitor`s created from `UnsafeDataTransaction`s used to manage temporary "scratch" data.
- Important: Note that unlike `commit()`, `flush()` does not propagate/save updates to the `DataStack` and the persistent store. However, the flushed changes will be seen by children transactions created further from the current transaction (i.e. through `transaction.beginUnsafe()`) - Important: Note that unlike `commit()`, `flush()` does not propagate/save updates to the `DataStack` and the persistent store. However, the flushed changes will be seen by children transactions created further from the current transaction (i.e. through `transaction.beginUnsafe()`)
- parameter closure: the closure where changes can be made prior to the flush - parameter block: the block where changes can be made prior to the flush
*/ */
@objc @objc
public func flush(_ block: () -> Void) { public func flush(_ block: () -> Void) {
@@ -210,17 +214,16 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
return self.bridgeToSwift.context return self.bridgeToSwift.context
} }
/**
Saves the transaction changes asynchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
*/
@available(*, deprecated, message: "Use the new -[CSUnsafeDataTransaction commitWithSuccess:failure:] method") @available(*, deprecated, message: "Use the new -[CSUnsafeDataTransaction commitWithSuccess:failure:] method")
@objc @objc
public func commit(_ completion: ((_ result: CSSaveResult) -> Void)?) { public func commit(_ completion: ((_ result: CSSaveResult) -> Void)?) {
self.bridgeToSwift.context.saveAsynchronouslyWithCompletion { (hasChanges, error) in self.bridgeToSwift.context.saveAsynchronouslyWithCompletion { (hasChanges, error) in
defer {
withExtendedLifetime(self, {})
}
if let error = error { if let error = error {
completion?(SaveResult(error).bridgeToObjectiveC) completion?(SaveResult(error).bridgeToObjectiveC)
@@ -229,15 +232,9 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
completion?(SaveResult(hasChanges: hasChanges).bridgeToObjectiveC) completion?(SaveResult(hasChanges: hasChanges).bridgeToObjectiveC)
} }
withExtendedLifetime(self, {})
} }
} }
/**
Saves the transaction changes and waits for completion synchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- returns: a `CSSaveResult` containing the success or failure information
*/
@available(*, deprecated, message: "Use the new -[CSUnsafeDataTransaction commitAndWaitWithError:] method") @available(*, deprecated, message: "Use the new -[CSUnsafeDataTransaction commitAndWaitWithError:] method")
@objc @objc
public func commitAndWait() -> CSSaveResult { public func commitAndWait() -> CSSaveResult {

View File

@@ -37,6 +37,12 @@ import Foundation
@objc @objc
public final class CSXcodeDataModelSchema: NSObject, CSDynamicSchema, CoreStoreObjectiveCType { public final class CSXcodeDataModelSchema: NSObject, CSDynamicSchema, CoreStoreObjectiveCType {
/**
Initializes an `CSXcodeDataModelSchema` from an *.xcdatamodeld file URL.
- parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension)
- parameter modelVersionFileURL: the file URL that points to the .xcdatamodeld's "momd" file.
*/
@objc @objc
public required init(modelName: ModelVersion, modelVersionFileURL: URL) { public required init(modelName: ModelVersion, modelVersionFileURL: URL) {

View File

@@ -231,7 +231,9 @@ extension Entity: CustomDebugStringConvertible, CoreStoreDebugStringConvertible
return createFormattedString( return createFormattedString(
"(", ")", "(", ")",
("type", self.type), ("type", self.type),
("entityName", self.entityName) ("entityName", self.entityName),
("isAbstract", self.isAbstract),
("versionHashModifier", self.versionHashModifier as Any)
) )
} }
} }
@@ -372,9 +374,9 @@ extension Into: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
} }
// MARK: - LegacyXcodeDataModelSchema // MARK: - UnsafeDataModelSchema
extension LegacyXcodeDataModelSchema: CustomDebugStringConvertible, CoreStoreDebugStringConvertible { extension UnsafeDataModelSchema: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
// MARK: CustomDebugStringConvertible // MARK: CustomDebugStringConvertible
@@ -983,7 +985,7 @@ extension VersionLock: CustomStringConvertible, CustomDebugStringConvertible, Co
string.append(":]") string.append(":]")
return string return string
} }
for (index, keyValue) in self.hashesByEntityName.enumerated() { for (index, keyValue) in self.hashesByEntityName.sorted(by: { $0.key < $1.key }).enumerated() {
let data = keyValue.value let data = keyValue.value
let count = data.count let count = data.count

View File

@@ -33,9 +33,9 @@ import CoreData
public extension CoreStore { public extension CoreStore {
/** /**
Using the `defaultStack`, creates an `ObjectMonitor` for the specified `NSManagedObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `NSManagedObject`. Using the `defaultStack`, creates an `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`.
- parameter object: the `NSManagedObject` to observe changes from - parameter object: the `DynamicObject` to observe changes from
- returns: a `ObjectMonitor` that monitors changes to `object` - returns: a `ObjectMonitor` that monitors changes to `object`
*/ */
public static func monitorObject<T: DynamicObject>(_ object: T) -> ObjectMonitor<T> { public static func monitorObject<T: DynamicObject>(_ object: T) -> ObjectMonitor<T> {
@@ -44,7 +44,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Using the `defaultStack`, creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -56,7 +56,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Using the `defaultStack`, creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -68,7 +68,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -80,7 +80,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Using the `defaultStack`, asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -92,7 +92,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
@@ -105,7 +105,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Using the `defaultStack`, creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
@@ -118,7 +118,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -131,7 +131,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Using the `defaultStack`, asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type

View File

@@ -32,10 +32,10 @@ import CoreData
public extension CoreStore { public extension CoreStore {
/** /**
Using the `defaultStack`, fetches the `NSManagedObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context. Using the `defaultStack`, fetches the `DynamicObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context.
- parameter object: a reference to the object created/fetched outside the `DataStack` - parameter object: a reference to the object created/fetched outside the `DataStack`
- returns: the `NSManagedObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public static func fetchExisting<T: DynamicObject>(_ object: T) -> T? { public static func fetchExisting<T: DynamicObject>(_ object: T) -> T? {
@@ -43,10 +43,10 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the `NSManagedObject` instance in the `DataStack`'s context from an `NSManagedObjectID`. Using the `defaultStack`, fetches the `DynamicObject` instance in the `DataStack`'s context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public static func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? { public static func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? {
@@ -54,10 +54,10 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the `NSManagedObject` instances in the `DataStack`'s context from references created from a transaction or from a different managed object context. Using the `defaultStack`, fetches the `DynamicObject` instances in the `DataStack`'s context from references created from a transaction or from a different managed object context.
- parameter objects: an array of `NSManagedObject`s created/fetched outside the `DataStack` - parameter objects: an array of `DynamicObject`s created/fetched outside the `DataStack`
- returns: the `NSManagedObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public static func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public static func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
@@ -65,10 +65,10 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the `NSManagedObject` instances in the `DataStack`'s context from a list of `NSManagedObjectID`. Using the `defaultStack`, fetches the `DynamicObject` instances in the `DataStack`'s context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public static func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID { public static func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
@@ -76,11 +76,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public static func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? { public static func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
@@ -88,11 +88,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public static func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? { public static func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
@@ -100,11 +100,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public static func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? { public static func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
@@ -112,11 +112,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public static func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? { public static func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
@@ -124,11 +124,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? { public static func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
@@ -136,11 +136,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? { public static func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
@@ -148,11 +148,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public static func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? { public static func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
@@ -160,11 +160,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public static func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? { public static func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
@@ -172,11 +172,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? { public static func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
@@ -184,11 +184,11 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Using the `defaultStack`, fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public static func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { public static func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {

View File

@@ -143,10 +143,7 @@ public extension CoreStore {
// MARK: Deprecated // MARK: Deprecated
/** @available(*, deprecated, message: "Use the new CoreStore.entityTypesByName(for:) method passing `NSManagedObject.self` as argument.")
Returns the entity name-to-class type mapping from the `defaultStack`'s model.
*/
@available(*, deprecated: 3.1, message: "Use the new CoreStore.entityTypesByName(for:) method passing `NSManagedObject.self` as argument.")
public static var entityTypesByName: [EntityName: NSManagedObject.Type] { public static var entityTypesByName: [EntityName: NSManagedObject.Type] {
return self.defaultStack.entityTypesByName return self.defaultStack.entityTypesByName

View File

@@ -31,10 +31,10 @@ import Foundation
public extension CoreStore { public extension CoreStore {
/** /**
Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `TransactionResult.success(userInfo: T)` in the `completion`'s `TransactionResult<T>`. Any errors thrown from inside the `task` will be reported as `TransactionResult.failure(error: Error)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`. Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `.success(userInfo: T)` in the `completion`'s `Result<T>`. Any errors thrown from inside the `task` will be reported as `.failure(error: CoreStoreError)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
- parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`. - parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- parameter completion: the closure executed after the save completes. The `TransactionResult` argument of the closure will either wrap the return value of `task`, or any uncaught errors thrown from within `task`. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`. - parameter completion: the closure executed after the save completes. The `Result` argument of the closure will either wrap the return value of `task`, or any uncaught errors thrown from within `task`. Cancelled `task`s will be indicated by `.failure(error: CoreStoreError.userCancelled)`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
*/ */
public static func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (AsynchronousDataTransaction.Result<T>) -> Void) { public static func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (AsynchronousDataTransaction.Result<T>) -> Void) {
@@ -42,7 +42,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`. Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
- parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`. - parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- parameter success: the closure executed after the save succeeds. The `T` argument of the closure will be the value returned from `task`. - parameter success: the closure executed after the save succeeds. The `T` argument of the closure will be the value returned from `task`.
@@ -54,7 +54,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, performs a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be rethrown from `perform(synchronous:)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`. Using the `defaultStack`, performs a transaction synchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be rethrown from `perform(synchronous:)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
- parameter task: the synchronous non-escaping closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`. - parameter task: the synchronous non-escaping closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- parameter waitForAllObservers: When `true`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks. When `false`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning. Defaults to `true`. - parameter waitForAllObservers: When `true`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks. When `false`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning. Defaults to `true`.
@@ -67,7 +67,7 @@ public extension CoreStore {
} }
/** /**
Using the `defaultStack`, begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. An unsafe transaction object should typically be only used from the main queue. Using the `defaultStack`, begins a non-contiguous transaction where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
- prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited. - prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made. - returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
@@ -78,7 +78,7 @@ public extension CoreStore {
} }
/** /**
Refreshes all registered objects `NSManagedObject`s in the `defaultStack`. Refreshes all registered objects `NSManagedObject`s or `CoreStoreObject`s in the `defaultStack`.
*/ */
public static func refreshAndMergeAllObjects() { public static func refreshAndMergeAllObjects() {
@@ -88,23 +88,12 @@ public extension CoreStore {
// MARK: Deprecated // MARK: Deprecated
/**
Using the `defaultStack`, begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
*/
@available(*, deprecated, message: "Use the new auto-commiting methods `perform(asynchronous:completion:)` or `perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.") @available(*, deprecated, message: "Use the new auto-commiting methods `perform(asynchronous:completion:)` or `perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
public static func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) { public static func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) {
self.defaultStack.beginAsynchronous(closure) self.defaultStack.beginAsynchronous(closure)
} }
/**
Using the `defaultStack`, begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Use the new auto-commiting method `perform(synchronous:)`. Please read the documentation on the behavior of the new methods.") @available(*, deprecated, message: "Use the new auto-commiting method `perform(synchronous:)`. Please read the documentation on the behavior of the new methods.")
@discardableResult @discardableResult
public static func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? { public static func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {

View File

@@ -156,7 +156,7 @@ CSFrom *_Nonnull CSFromClass(Class _Nonnull entityClass, NSArray<id> *_Nonnull c
@abstract @abstract
Initializes a <tt>CSGroupBy</tt> clause with a key path string Initializes a <tt>CSGroupBy</tt> clause with a key path string
@param keyPaths @param keyPath
a key path string to group results with a key path string to group results with
@result @result
@@ -169,7 +169,7 @@ CSGroupBy *_Nonnull CSGroupByKeyPath(NSString *_Nonnull keyPath) CORESTORE_RETUR
@abstract @abstract
Initializes a <tt>CSGroupBy</tt> clause with a list of key path strings Initializes a <tt>CSGroupBy</tt> clause with a list of key path strings
@param keyPaths @param keyPath
a nil-terminated list of key path strings to group results with a nil-terminated list of key path strings to group results with
@result @result
@@ -328,7 +328,7 @@ CSOrderBy *_Nonnull CSOrderByKey(NSSortDescriptor *_Nonnull sortDescriptor) CORE
fetchClauses:@[CSOrderByKeys(CSSortAscending(@"fullname"), CSSortDescending(@"age"), nil))]]]; fetchClauses:@[CSOrderByKeys(CSSortAscending(@"fullname"), CSSortDescending(@"age"), nil))]]];
@endcode @endcode
@param sortDescriptors @param sortDescriptor
a nil-terminated array of <tt>NSSortDescriptor</tt>s a nil-terminated array of <tt>NSSortDescriptor</tt>s
@result @result
@@ -473,9 +473,6 @@ CSSelect *_Nonnull CSSelectData(CSSelectTerm *_Nonnull selectTerm) CORESTORE_RET
// ... // ...
@endcode @endcode
@param selectTerm
the <tt>CSSelectTerm</tt> specifying the attribute/aggregate value to query
@result @result
a <tt>CSSelect</tt> clause for querying an <tt>NSManagedObjectID</tt> value a <tt>CSSelect</tt> clause for querying an <tt>NSManagedObjectID</tt> value
*/ */
@@ -538,10 +535,7 @@ CSWhere *_Nonnull CSWhereValue(BOOL value) CORESTORE_RETURNS_RETAINED;
@endcode @endcode
@param format @param format
the format string for the predicate the format string for the predicate, followed by an optional comma-separated argument list
@param argumentArray
the arguments for <tt>format</tt>
@result @result
a <tt>CSWhere</tt> clause with a predicate using the specified string format and arguments a <tt>CSWhere</tt> clause with a predicate using the specified string format and arguments

View File

@@ -294,7 +294,8 @@ public extension NSError {
} }
switch CocoaError.Code(rawValue: self.code) { switch CocoaError.Code(rawValue: self.code) {
case CocoaError.Code.persistentStoreIncompatibleVersionHash, case CocoaError.Code.persistentStoreIncompatibleSchema,
CocoaError.Code.persistentStoreIncompatibleVersionHash,
CocoaError.Code.migrationMissingSourceModel, CocoaError.Code.migrationMissingSourceModel,
CocoaError.Code.migration: CocoaError.Code.migration:
return true return true

View File

@@ -31,26 +31,56 @@ import Foundation
public extension DynamicObject where Self: CoreStoreObject { public extension DynamicObject where Self: CoreStoreObject {
/**
Extracts the keyPath string from a `CoreStoreObject.Value` property.
```
let keyPath: String = Person.keyPath { $0.nickname }
```
*/
public static func keyPath<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Required<V>) -> String { public static func keyPath<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Required<V>) -> String {
return attribute(self.meta).keyPath return attribute(self.meta).keyPath
} }
/**
Extracts the keyPath string from a `CoreStoreObject.Value` property.
```
let keyPath: String = Person.keyPath { $0.nickname }
```
*/
public static func keyPath<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> String { public static func keyPath<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> String {
return attribute(self.meta).keyPath return attribute(self.meta).keyPath
} }
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname == "John" })
```
*/
public static func `where`(_ condition: (Self) -> Where) -> Where { public static func `where`(_ condition: (Self) -> Where) -> Where {
return condition(self.meta) return condition(self.meta)
} }
/**
Creates an `OrderBy` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchAll(From<Person>(), Person.ascending { $0.age })
```
*/
public static func ascending<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy { public static func ascending<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy {
return OrderBy(.ascending(attribute(self.meta).keyPath)) return OrderBy(.ascending(attribute(self.meta).keyPath))
} }
/**
Creates an `OrderBy` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchAll(From<Person>(), Person.descending { $0.age })
```
*/
public static func descending<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy { public static func descending<O: CoreStoreObject, V: ImportableAttributeType>(_ attribute: (Self) -> ValueContainer<O>.Optional<V>) -> OrderBy {
return OrderBy(.descending(attribute(self.meta).keyPath)) return OrderBy(.descending(attribute(self.meta).keyPath))
@@ -62,41 +92,77 @@ public extension DynamicObject where Self: CoreStoreObject {
public extension ValueContainer.Required { public extension ValueContainer.Required {
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname == "John" })
```
*/
@inline(__always) @inline(__always)
public static func == (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where { public static func == (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where(attribute.keyPath, isEqualTo: value) return Where(attribute.keyPath, isEqualTo: value)
} }
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname != "John" })
```
*/
@inline(__always)
public static func != (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return !Where(attribute.keyPath, isEqualTo: value)
}
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age < 20 })
```
*/
@inline(__always) @inline(__always)
public static func < (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where { public static func < (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K < %@", attribute.keyPath, value) return Where("%K < %@", attribute.keyPath, value)
} }
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age > 20 })
```
*/
@inline(__always) @inline(__always)
public static func > (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where { public static func > (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K > %@", attribute.keyPath, value) return Where("%K > %@", attribute.keyPath, value)
} }
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age <= 20 })
```
*/
@inline(__always) @inline(__always)
public static func <= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where { public static func <= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K <= %@", attribute.keyPath, value) return Where("%K <= %@", attribute.keyPath, value)
} }
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.age >= 20 })
```
*/
@inline(__always) @inline(__always)
public static func >= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where { public static func >= (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return Where("%K >= %@", attribute.keyPath, value) return Where("%K >= %@", attribute.keyPath, value)
} }
@inline(__always)
public static func != (_ attribute: ValueContainer<O>.Required<V>, _ value: V) -> Where {
return !Where(attribute.keyPath, isEqualTo: value)
}
} }
@@ -104,12 +170,24 @@ public extension ValueContainer.Required {
public extension ValueContainer.Optional { public extension ValueContainer.Optional {
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname == "John" })
```
*/
@inline(__always) @inline(__always)
public static func == (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where { public static func == (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {
return Where(attribute.keyPath, isEqualTo: value) return Where(attribute.keyPath, isEqualTo: value)
} }
/**
Creates a `Where` clause from a `CoreStoreObject.Value` property.
```
let person = CoreStore.fetchOne(From<Person>(), Person.where { $0.nickname != "John" })
```
*/
@inline(__always) @inline(__always)
public static func != (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where { public static func != (_ attribute: ValueContainer<O>.Optional<V>, _ value: V?) -> Where {

View File

@@ -187,7 +187,7 @@ public final class CoreStoreSchema: DynamicSchema {
#if DEBUG #if DEBUG
CoreStore.log( CoreStore.log(
.notice, .notice,
message: "These are hashes for the \(cs_typeName(CoreStoreSchema.self)) with version name \"\(modelVersion)\". Copy the dictionary below and pass it to the \(cs_typeName(CoreStoreSchema.self)) initializer's \"versionLock\" argument:\n\(VersionLock(entityVersionHashesByName: self.rawModel().entityVersionHashesByName))" message: "These are hashes for the \(cs_typeName(CoreStoreSchema.self)) with version name \"\(modelVersion)\". Copy the dictionary below and pass it to the \(cs_typeName(CoreStoreSchema.self)) initializer's \"versionLock\" argument:\nversionLock: \(VersionLock(entityVersionHashesByName: self.rawModel().entityVersionHashesByName))"
) )
#endif #endif
} }

View File

@@ -29,11 +29,28 @@ import Foundation
// MARK: - CustomSchemaMappingProvider // MARK: - CustomSchemaMappingProvider
/**
A `SchemaMappingProvider` that accepts custom mappings for some entities. Mappings of entities with no `CustomMapping` provided will be automatically calculated if possible.
*/
open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider { open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
/**
The source model version for the mapping.
*/
public let sourceVersion: ModelVersion public let sourceVersion: ModelVersion
/**
The destination model version for the mapping.
*/
public let destinationVersion: ModelVersion public let destinationVersion: ModelVersion
/**
Creates a `CustomSchemaMappingProvider`
- parameter sourceVersion: the source model version for the mapping
- parameter destinationVersion: the destination model version for the mapping
- parameter entityMappings: a list of `CustomMapping`s. Mappings of entities with no `CustomMapping` provided will be automatically calculated if possible. Any conflicts or ambiguity will raise an assertion.
*/
public required init(from sourceVersion: ModelVersion, to destinationVersion: ModelVersion, entityMappings: Set<CustomMapping> = []) { public required init(from sourceVersion: ModelVersion, to destinationVersion: ModelVersion, entityMappings: Set<CustomMapping> = []) {
CoreStore.assert( CoreStore.assert(
@@ -54,16 +71,42 @@ open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: - CustomMapping // MARK: - CustomMapping
/**
Provides the type of mapping for an entity. Mappings of entities with no `CustomMapping` provided will be automatically calculated if possible. Any conflicts or ambiguity will raise an assertion.
*/
public enum CustomMapping: Hashable { public enum CustomMapping: Hashable {
public typealias Transformer = (_ sourceObject: UnsafeSourceObject, _ createDestinationObject: () -> UnsafeDestinationObject) throws -> Void /**
The `sourceEntity` is meant to be removed from the source `DynamicSchema` and should not be migrated to the destination `DynamicSchema`.
*/
case deleteEntity(sourceEntity: EntityName) case deleteEntity(sourceEntity: EntityName)
/**
The `destinationEntity` is newly added to the destination `DynamicSchema` and has no mapping from the source `DynamicSchema`.
*/
case insertEntity(destinationEntity: EntityName) case insertEntity(destinationEntity: EntityName)
/**
The `DynamicSchema`s entity has no changes and can be copied directly from `sourceEntity` to `destinationEntity`.
*/
case copyEntity(sourceEntity: EntityName, destinationEntity: EntityName) case copyEntity(sourceEntity: EntityName, destinationEntity: EntityName)
/**
The `DynamicSchema`s entity needs transformations from `sourceEntity` to `destinationEntity`. The `transformer` closure will be used to apply the changes. The `CustomMapping.inferredTransformation` method can be used directly as the `transformer` if the changes can be inferred (i.e. lightweight).
*/
case transformEntity(sourceEntity: EntityName, destinationEntity: EntityName, transformer: Transformer) case transformEntity(sourceEntity: EntityName, destinationEntity: EntityName, transformer: Transformer)
static func inferredTransformation(_ sourceObject: UnsafeSourceObject, _ createDestinationObject: () -> UnsafeDestinationObject) throws -> Void { /**
The closure type for `CustomMapping.transformEntity`.
- parameter sourceObject: a proxy object representing the source entity. The properties can be accessed via keyPath.
- parameter createDestinationObject: the closure to create the object for the destination entity. The `CustomMapping.inferredTransformation` method can be used directly as the `transformer` if the changes can be inferred (i.e. lightweight). The object is created lazily and executing the closure multiple times will return the same instance. The destination object's properties can be accessed and updated via keyPath.
*/
public typealias Transformer = (_ sourceObject: UnsafeSourceObject, _ createDestinationObject: () -> UnsafeDestinationObject) throws -> Void
/**
The `CustomMapping.inferredTransformation` method can be used directly as the `transformer` if the changes can be inferred (i.e. lightweight).
*/
public static func inferredTransformation(_ sourceObject: UnsafeSourceObject, _ createDestinationObject: () -> UnsafeDestinationObject) throws -> Void {
let destinationObject = createDestinationObject() let destinationObject = createDestinationObject()
destinationObject.enumerateAttributes { (attribute, sourceAttribute) in destinationObject.enumerateAttributes { (attribute, sourceAttribute) in
@@ -75,34 +118,6 @@ open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
} }
} }
var entityMappingSourceEntity: EntityName? {
switch self {
case .deleteEntity(let sourceEntity),
.copyEntity(let sourceEntity, _),
.transformEntity(let sourceEntity, _, _):
return sourceEntity
case .insertEntity:
return nil
}
}
var entityMappingDestinationEntity: EntityName? {
switch self {
case .insertEntity(let destinationEntity),
.copyEntity(_, let destinationEntity),
.transformEntity(_, let destinationEntity, _):
return destinationEntity
case .deleteEntity:
return nil
}
}
// MARK: Equatable // MARK: Equatable
@@ -151,30 +166,81 @@ open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
^ destinationEntity.hashValue ^ destinationEntity.hashValue
} }
} }
// MARK: FilePrivate
fileprivate var entityMappingSourceEntity: EntityName? {
switch self {
case .deleteEntity(let sourceEntity),
.copyEntity(let sourceEntity, _),
.transformEntity(let sourceEntity, _, _):
return sourceEntity
case .insertEntity:
return nil
}
}
fileprivate var entityMappingDestinationEntity: EntityName? {
switch self {
case .insertEntity(let destinationEntity),
.copyEntity(_, let destinationEntity),
.transformEntity(_, let destinationEntity, _):
return destinationEntity
case .deleteEntity:
return nil
}
}
} }
// MARK: - UnsafeSourceObject // MARK: - UnsafeSourceObject
/**
The read-only proxy object used for the source object in a mapping's `Transformer` closure. Properties can be accessed either by keyPath string or by `NSAttributeDescription`.
*/
public final class UnsafeSourceObject { public final class UnsafeSourceObject {
/**
Accesses the property value via its keyPath.
*/
public subscript(attribute: KeyPath) -> Any? { public subscript(attribute: KeyPath) -> Any? {
return self.rawObject.cs_accessValueForKVCKey(attribute) return self.rawObject.cs_accessValueForKVCKey(attribute)
} }
/**
Accesses the property value via its `NSAttributeDescription`, which can be accessed from the `enumerateAttributes(_:)` method.
*/
public subscript(attribute: NSAttributeDescription) -> Any? { public subscript(attribute: NSAttributeDescription) -> Any? {
return self.rawObject.cs_accessValueForKVCKey(attribute.name) return self.rawObject.cs_accessValueForKVCKey(attribute.name)
} }
/**
Enumerates the all `NSAttributeDescription`s. The `attribute` argument can be used as the subscript key to access the property.
*/
public func enumerateAttributes(_ closure: (_ attribute: NSAttributeDescription) -> Void) { public func enumerateAttributes(_ closure: (_ attribute: NSAttributeDescription) -> Void) {
for case let attribute as NSAttributeDescription in self.rawObject.entity.properties { func enumerate(_ entity: NSEntityDescription, _ closure: (NSAttributeDescription) -> Void) {
if let superEntity = entity.superentity {
enumerate(superEntity, closure)
}
for case let attribute as NSAttributeDescription in entity.properties {
closure(attribute) closure(attribute)
} }
} }
enumerate(self.rawObject.entity, closure)
}
// MARK: Internal // MARK: Internal
@@ -193,27 +259,47 @@ open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: - UnsafeDestinationObject // MARK: - UnsafeDestinationObject
/**
The read-write proxy object used for the destination object that can be created in a mapping's `Transformer` closure. Properties can be accessed and mutated either through keyPath string or by `NSAttributeDescription`.
*/
public final class UnsafeDestinationObject { public final class UnsafeDestinationObject {
/**
Accesses or mutates the property value via its keyPath.
*/
public subscript(attribute: KeyPath) -> Any? { public subscript(attribute: KeyPath) -> Any? {
get { return self.rawObject.cs_accessValueForKVCKey(attribute) } get { return self.rawObject.cs_accessValueForKVCKey(attribute) }
set { self.rawObject.cs_setValue(newValue, forKVCKey: attribute) } set { self.rawObject.cs_setValue(newValue, forKVCKey: attribute) }
} }
/**
Accesses or mutates the property value via its `NSAttributeDescription`, which can be accessed from the `enumerateAttributes(_:)` method.
*/
public subscript(attribute: NSAttributeDescription) -> Any? { public subscript(attribute: NSAttributeDescription) -> Any? {
get { return self.rawObject.cs_accessValueForKVCKey(attribute.name) } get { return self.rawObject.cs_accessValueForKVCKey(attribute.name) }
set { self.rawObject.cs_setValue(newValue, forKVCKey: attribute.name) } set { self.rawObject.cs_setValue(newValue, forKVCKey: attribute.name) }
} }
/**
Enumerates the all `NSAttributeDescription`s. The `attribute` argument can be used as the subscript key to access and mutate the property. The `sourceAttribute` can be used to access properties from the source `UnsafeSourceObject`.
*/
public func enumerateAttributes(_ closure: (_ attribute: NSAttributeDescription, _ sourceAttribute: NSAttributeDescription?) -> Void) { public func enumerateAttributes(_ closure: (_ attribute: NSAttributeDescription, _ sourceAttribute: NSAttributeDescription?) -> Void) {
for case let attribute as NSAttributeDescription in self.rawObject.entity.properties { func enumerate(_ entity: NSEntityDescription, _ closure: (_ attribute: NSAttributeDescription, _ sourceAttribute: NSAttributeDescription?) -> Void) {
if let superEntity = entity.superentity {
enumerate(superEntity, closure)
}
for case let attribute as NSAttributeDescription in entity.properties {
closure(attribute, self.sourceAttributesByDestinationKey[attribute.name]) closure(attribute, self.sourceAttributesByDestinationKey[attribute.name])
} }
} }
enumerate(self.rawObject.entity, closure)
}
// MARK: Internal // MARK: Internal
@@ -225,10 +311,10 @@ open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
} }
// MARK: Private // MARK: FilePrivate
private let rawObject: NSManagedObject fileprivate let rawObject: NSManagedObject
private let sourceAttributesByDestinationKey: [KeyPath: NSAttributeDescription] fileprivate let sourceAttributesByDestinationKey: [KeyPath: NSAttributeDescription]
} }
@@ -253,7 +339,7 @@ open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: SchemaMappingProvider // MARK: SchemaMappingProvider
public func createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) { public func cs_createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) {
let sourceModel = sourceSchema.rawModel() let sourceModel = sourceSchema.rawModel()
let destinationModel = destinationSchema.rawModel() let destinationModel = destinationSchema.rawModel()
@@ -441,19 +527,23 @@ open class CustomSchemaMappingProvider: Hashable, SchemaMappingProvider {
let transformer = userInfo[CustomEntityMigrationPolicy.UserInfoKey.transformer]! as! CustomMapping.Transformer let transformer = userInfo[CustomEntityMigrationPolicy.UserInfoKey.transformer]! as! CustomMapping.Transformer
let sourceAttributesByDestinationKey = userInfo[CustomEntityMigrationPolicy.UserInfoKey.sourceAttributesByDestinationKey] as! [KeyPath: NSAttributeDescription] let sourceAttributesByDestinationKey = userInfo[CustomEntityMigrationPolicy.UserInfoKey.sourceAttributesByDestinationKey] as! [KeyPath: NSAttributeDescription]
var dInstance: NSManagedObject? var destinationObject: UnsafeDestinationObject?
try transformer( try transformer(
UnsafeSourceObject(sInstance), UnsafeSourceObject(sInstance),
{ {
if let destinationObject = destinationObject {
return destinationObject
}
let rawObject = NSEntityDescription.insertNewObject( let rawObject = NSEntityDescription.insertNewObject(
forEntityName: mapping.destinationEntityName!, forEntityName: mapping.destinationEntityName!,
into: manager.destinationContext into: manager.destinationContext
) )
dInstance = rawObject destinationObject = UnsafeDestinationObject(rawObject, sourceAttributesByDestinationKey)
return UnsafeDestinationObject(rawObject, sourceAttributesByDestinationKey) return destinationObject!
} }
) )
if let dInstance = dInstance { if let dInstance = destinationObject?.rawObject {
manager.associate( manager.associate(
sourceInstance: sInstance, sourceInstance: sInstance,

View File

@@ -173,7 +173,7 @@ public extension DataStack {
do { do {
try storage.eraseStorageAndWait( try storage.cs_eraseStorageAndWait(
metadata: metadata, metadata: metadata,
soureModelHint: self.schemaHistory.schema(for: metadata)?.rawModel() soureModelHint: self.schemaHistory.schema(for: metadata)?.rawModel()
) )
@@ -341,7 +341,7 @@ public extension DataStack {
) )
_ = try self.schemaHistory _ = try self.schemaHistory
.schema(for: metadata) .schema(for: metadata)
.flatMap({ try storage.eraseStorageAndWait(soureModel: $0.rawModel()) }) .flatMap({ try storage.cs_eraseStorageAndWait(soureModel: $0.rawModel()) })
_ = try self.createPersistentStoreFromStorage( _ = try self.createPersistentStoreFromStorage(
storage, storage,
finalURL: cacheFileURL, finalURL: cacheFileURL,
@@ -756,17 +756,17 @@ fileprivate extension Array where Element == SchemaMappingProvider {
case let element as CustomSchemaMappingProvider case let element as CustomSchemaMappingProvider
where element.sourceVersion == sourceSchema.modelVersion && element.destinationVersion == destinationSchema.modelVersion: where element.sourceVersion == sourceSchema.modelVersion && element.destinationVersion == destinationSchema.modelVersion:
return try element.createMappingModel(from: sourceSchema, to: destinationSchema, storage: storage) return try element.cs_createMappingModel(from: sourceSchema, to: destinationSchema, storage: storage)
case let element as XcodeSchemaMappingProvider case let element as XcodeSchemaMappingProvider
where element.sourceVersion == sourceSchema.modelVersion && element.destinationVersion == destinationSchema.modelVersion: where element.sourceVersion == sourceSchema.modelVersion && element.destinationVersion == destinationSchema.modelVersion:
return try element.createMappingModel(from: sourceSchema, to: destinationSchema, storage: storage) return try element.cs_createMappingModel(from: sourceSchema, to: destinationSchema, storage: storage)
default: default:
continue continue
} }
} }
return try InferredSchemaMappingProvider() return try InferredSchemaMappingProvider()
.createMappingModel(from: sourceSchema, to: destinationSchema, storage: storage) .cs_createMappingModel(from: sourceSchema, to: destinationSchema, storage: storage)
} }
} }

View File

@@ -33,9 +33,9 @@ import CoreData
public extension DataStack { public extension DataStack {
/** /**
Creates an `ObjectMonitor` for the specified `NSManagedObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `NSManagedObject`. Creates an `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`.
- parameter object: the `NSManagedObject` to observe changes from - parameter object: the `DynamicObject` to observe changes from
- returns: a `ObjectMonitor` that monitors changes to `object` - returns: a `ObjectMonitor` that monitors changes to `object`
*/ */
public func monitorObject<T: DynamicObject>(_ object: T) -> ObjectMonitor<T> { public func monitorObject<T: DynamicObject>(_ object: T) -> ObjectMonitor<T> {
@@ -48,7 +48,7 @@ public extension DataStack {
} }
/** /**
Creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -60,7 +60,7 @@ public extension DataStack {
} }
/** /**
Creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -89,7 +89,7 @@ public extension DataStack {
} }
/** /**
Asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -101,7 +101,7 @@ public extension DataStack {
} }
/** /**
Asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -131,7 +131,7 @@ public extension DataStack {
} }
/** /**
Creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
@@ -144,7 +144,7 @@ public extension DataStack {
} }
/** /**
Creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
@@ -175,7 +175,7 @@ public extension DataStack {
} }
/** /**
Asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -188,7 +188,7 @@ public extension DataStack {
} }
/** /**
Asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type

View File

@@ -34,10 +34,10 @@ extension DataStack: FetchableSource, QueryableSource {
// MARK: FetchableSource // MARK: FetchableSource
/** /**
Fetches the `NSManagedObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context. Fetches the `DynamicObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context.
- parameter object: a reference to the object created/fetched outside the `DataStack` - parameter object: a reference to the object created/fetched outside the `DataStack`
- returns: the `NSManagedObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ object: T) -> T? { public func fetchExisting<T: DynamicObject>(_ object: T) -> T? {
@@ -45,10 +45,10 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObject` instance in the `DataStack`'s context from an `NSManagedObjectID`. Fetches the `DynamicObject` instance in the `DataStack`'s context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `DataStack`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/ */
public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? { public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? {
@@ -56,10 +56,10 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObject` instances in the `DataStack`'s context from references created from a transaction or from a different managed object context. Fetches the `DynamicObject` instances in the `DataStack`'s context from references created from a transaction or from a different managed object context.
- parameter objects: an array of `NSManagedObject`s created/fetched outside the `DataStack` - parameter objects: an array of `DynamicObject`s created/fetched outside the `DataStack`
- returns: the `NSManagedObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
@@ -67,10 +67,10 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObject` instances in the `DataStack`'s context from a list of `NSManagedObjectID`. Fetches the `DynamicObject` instances in the `DataStack`'s context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `DataStack` - returns: the `DynamicObject` array for objects that exists in the `DataStack`
*/ */
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID { public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
@@ -78,11 +78,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? { public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
@@ -94,11 +94,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? { public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
@@ -110,11 +110,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? { public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
@@ -126,11 +126,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? { public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
@@ -142,11 +142,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? { public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
@@ -158,11 +158,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? { public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
@@ -174,11 +174,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? { public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
@@ -190,11 +190,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? { public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
@@ -206,11 +206,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? { public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
@@ -222,11 +222,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? { public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
@@ -328,11 +328,11 @@ extension DataStack: FetchableSource, QueryableSource {
} }
// MARK: Deprecated // MARK: Obsoleted
@available(*, deprecated, renamed: "unsafeContext()") @available(*, obsoleted: 3.1, renamed: "unsafeContext()")
public func internalContext() -> NSManagedObjectContext { public func internalContext() -> NSManagedObjectContext {
return self.unsafeContext() fatalError()
} }
} }

View File

@@ -32,10 +32,10 @@ import CoreData
public extension DataStack { public extension DataStack {
/** /**
Performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `TransactionResult.success(userInfo: T)` in the `completion`'s `TransactionResult<T>`. Any errors thrown from inside the `task` will be reported as `TransactionResult.failure(error: Error)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`. Performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `.success(userInfo: T)` in the `completion`'s `Result<T>`. Any errors thrown from inside the `task` will be reported as `.failure(error: CoreStoreError)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
- parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`. - parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- parameter completion: the closure executed after the save completes. The `TransactionResult` argument of the closure will either wrap the return value of `task`, or any uncaught errors thrown from within `task`. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`. - parameter completion: the closure executed after the save completes. The `Result` argument of the closure will either wrap the return value of `task`, or any uncaught errors thrown from within `task`. Cancelled `task`s will be indicated by `.failure(error: CoreStoreError.userCancelled)`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
*/ */
public func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (AsynchronousDataTransaction.Result<T>) -> Void) { public func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (AsynchronousDataTransaction.Result<T>) -> Void) {
@@ -47,7 +47,7 @@ public extension DataStack {
} }
/** /**
Performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`. Performs a transaction asynchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
- parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`. - parameter task: the asynchronous closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- parameter success: the closure executed after the save succeeds. The `T` argument of the closure will be the value returned from `task`. - parameter success: the closure executed after the save succeeds. The `T` argument of the closure will be the value returned from `task`.
@@ -61,6 +61,10 @@ public extension DataStack {
) )
transaction.transactionQueue.cs_async { transaction.transactionQueue.cs_async {
defer {
withExtendedLifetime((self, transaction), {})
}
let userInfo: T let userInfo: T
do { do {
@@ -91,7 +95,7 @@ public extension DataStack {
} }
/** /**
Performs a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be rethrown from `perform(synchronous:)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`. Performs a transaction synchronously where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be rethrown from `perform(synchronous:)`. To cancel/rollback changes, call `try transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
- parameter task: the synchronous non-escaping closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`. - parameter task: the synchronous non-escaping closure where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- parameter waitForAllObservers: When `true`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks. When `false`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning. Defaults to `true`. - parameter waitForAllObservers: When `true`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks. When `false`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning. Defaults to `true`.
@@ -106,6 +110,10 @@ public extension DataStack {
) )
return try transaction.transactionQueue.cs_sync { return try transaction.transactionQueue.cs_sync {
defer {
withExtendedLifetime((self, transaction), {})
}
let userInfo: T let userInfo: T
do { do {
@@ -131,7 +139,7 @@ public extension DataStack {
} }
/** /**
Begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. Begins a non-contiguous transaction where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
- prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited. - prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made. - returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
@@ -146,7 +154,7 @@ public extension DataStack {
} }
/** /**
Refreshes all registered objects `NSManagedObject`s in the `DataStack`. Refreshes all registered objects `NSManagedObject`s or `CoreStoreObject`s in the `DataStack`.
*/ */
public func refreshAndMergeAllObjects() { public func refreshAndMergeAllObjects() {
@@ -160,11 +168,6 @@ public extension DataStack {
// MARK: Deprecated // MARK: Deprecated
/**
Begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
*/
@available(*, deprecated, message: "Use the new auto-commiting methods `perform(asynchronous:completion:)` or `perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.") @available(*, deprecated, message: "Use the new auto-commiting methods `perform(asynchronous:completion:)` or `perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
public func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) { public func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) {
@@ -186,12 +189,6 @@ public extension DataStack {
} }
} }
/**
Begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Use the new auto-commiting method `perform(synchronous:)`. Please read the documentation on the behavior of the new methods.") @available(*, deprecated, message: "Use the new auto-commiting method `perform(synchronous:)`. Please read the documentation on the behavior of the new methods.")
@discardableResult @discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? { public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {

View File

@@ -37,17 +37,20 @@ public final class DataStack: Equatable {
/** /**
Convenience initializer for `DataStack` that creates a `SchemaHistory` from the model with the specified `modelName` in the specified `bundle`. Convenience initializer for `DataStack` that creates a `SchemaHistory` from the model with the specified `modelName` in the specified `bundle`.
- parameter modelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set (e.g. in Unit Tests). - parameter xcodeModelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set (e.g. in Unit Tests).
- parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used. - parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used.
- parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. - parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/ */
public convenience init(modelName: XcodeDataModelFileName = DataStack.applicationName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) { public convenience init(xcodeModelName: XcodeDataModelFileName = DataStack.applicationName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) {
self.init( self.init(
schemaHistory: SchemaHistory( schemaHistory: SchemaHistory(
modelName: modelName, XcodeDataModelSchema.from(
modelName: xcodeModelName,
bundle: bundle, bundle: bundle,
migrationChain: migrationChain migrationChain: migrationChain
),
migrationChain: migrationChain
) )
) )
} }
@@ -328,7 +331,7 @@ public final class DataStack: Equatable {
at: fileURL, at: fileURL,
options: storeOptions options: storeOptions
) )
try storage.eraseStorageAndWait( try storage.cs_eraseStorageAndWait(
metadata: metadata, metadata: metadata,
soureModelHint: self.schemaHistory.schema(for: metadata)?.rawModel() soureModelHint: self.schemaHistory.schema(for: metadata)?.rawModel()
) )
@@ -425,7 +428,7 @@ public final class DataStack: Equatable {
) )
_ = try self.schemaHistory _ = try self.schemaHistory
.schema(for: metadata) .schema(for: metadata)
.flatMap({ try storage.eraseStorageAndWait(soureModel: $0.rawModel()) }) .flatMap({ try storage.cs_eraseStorageAndWait(soureModel: $0.rawModel()) })
_ = try self.createPersistentStoreFromStorage( _ = try self.createPersistentStoreFromStorage(
storage, storage,
finalURL: cacheFileURL, finalURL: cacheFileURL,
@@ -459,7 +462,7 @@ public final class DataStack: Equatable {
``` ```
- Important: Do not use this method to store thread-sensitive data. - Important: Do not use this method to store thread-sensitive data.
*/ */
private let userInfo = UserInfo() public let userInfo = UserInfo()
// MARK: Equatable // MARK: Equatable
@@ -570,7 +573,7 @@ public final class DataStack: Equatable {
self.finalConfigurationsByEntityIdentifier[entityIdentifier]?.insert(configurationName) self.finalConfigurationsByEntityIdentifier[entityIdentifier]?.insert(configurationName)
} }
} }
storage.didAddToDataStack(self) storage.cs_didAddToDataStack(self)
return persistentStore return persistentStore
} }
@@ -610,20 +613,25 @@ public final class DataStack: Equatable {
// MARK: Deprecated // MARK: Deprecated
/** @available(*, deprecated, renamed: "init(xcodeModelName:bundle:migrationChain:)")
Initializes a `DataStack` from an `NSManagedObjectModel`. public convenience init(modelName: XcodeDataModelFileName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) {
- parameter model: the `NSManagedObjectModel` for the stack self.init(
- parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. xcodeModelName: modelName,
*/ bundle: bundle,
@available(*, deprecated: 3.1, message: "Use the new DataStack.init(schemaHistory:) initializer passing a LegacyXcodeDataModelSchema instance as argument") migrationChain: migrationChain
)
}
@available(*, deprecated, message: "Use the new DataStack.init(schemaHistory:) initializer passing an UnsafeDataModelSchema instance as argument")
public convenience init(model: NSManagedObjectModel, migrationChain: MigrationChain = nil) { public convenience init(model: NSManagedObjectModel, migrationChain: MigrationChain = nil) {
let modelVersion = migrationChain.leafVersions.first! let modelVersion = migrationChain.leafVersions.first!
self.init( self.init(
schemaHistory: SchemaHistory( schemaHistory: SchemaHistory(
allSchema: [ allSchema: [
LegacyXcodeDataModelSchema( UnsafeDataModelSchema(
modelName: modelVersion, modelName: modelVersion,
model: model model: model
) )
@@ -634,10 +642,7 @@ public final class DataStack: Equatable {
) )
} }
/** @available(*, deprecated, message: "Use the new DataStack.entityTypesByName(for:) method passing `NSManagedObject.self` as argument.")
Returns the entity name-to-class type mapping from the `DataStack`'s model.
*/
@available(*, deprecated: 3.1, message: "Use the new DataStack.entityTypesByName(for:) method passing `NSManagedObject.self` as argument.")
public var entityTypesByName: [EntityName: NSManagedObject.Type] { public var entityTypesByName: [EntityName: NSManagedObject.Type] {
return self.entityTypesByName(for: NSManagedObject.self) return self.entityTypesByName(for: NSManagedObject.self)

View File

@@ -43,6 +43,16 @@ public protocol DynamicObject: class {
*/ */
static func cs_fromRaw(object: NSManagedObject) -> Self static func cs_fromRaw(object: NSManagedObject) -> Self
/**
Used internally by CoreStore. Do not call directly.
*/
static func cs_matches(object: NSManagedObject) -> Bool
/**
Used internally by CoreStore. Do not call directly.
*/
func cs_id() -> NSManagedObjectID
/** /**
Used internally by CoreStore. Do not call directly. Used internally by CoreStore. Do not call directly.
*/ */
@@ -76,6 +86,16 @@ extension NSManagedObject: DynamicObject {
return forceCast(object) return forceCast(object)
} }
public static func cs_matches(object: NSManagedObject) -> Bool {
return object.isKind(of: self)
}
public func cs_id() -> NSManagedObjectID {
return self.objectID
}
public func cs_toRaw() -> NSManagedObject { public func cs_toRaw() -> NSManagedObject {
return self return self
@@ -116,6 +136,20 @@ extension CoreStoreObject {
return coreStoreObject return coreStoreObject
} }
public static func cs_matches(object: NSManagedObject) -> Bool {
guard let type = object.entity.coreStoreEntity?.type else {
return false
}
return (self as AnyClass).isSubclass(of: type as AnyClass)
}
public func cs_id() -> NSManagedObjectID {
return self.rawObject!.objectID
}
public func cs_toRaw() -> NSManagedObject { public func cs_toRaw() -> NSManagedObject {
return self.rawObject! return self.rawObject!

View File

@@ -31,6 +31,12 @@ import Foundation
public extension DynamicSchema { public extension DynamicSchema {
/**
Prints the `DynamicSchema` as their corresponding `CoreStoreObject` Swift declarations. This is useful for converting current `XcodeDataModelSchema`-based models into the new `CoreStoreSchema` framework. Additional adjustments may need to be done to the generated source code; for example: `Transformable` concrete types need to be provided, as well as `default` values.
- Important: After transitioning to the new `CoreStoreSchema` framework, it is recommended to add the new schema as a new version that the existing versions' `XcodeDataModelSchema` can migrate to. It is discouraged to load existing SQLite files created with `XcodeDataModelSchema` directly into a `CoreStoreSchema`.
- returns: a string that represents the source code for the `DynamicSchema` as their corresponding `CoreStoreObject` Swift declarations.
*/
public func printCoreStoreSchema() -> String { public func printCoreStoreSchema() -> String {
let model = self.rawModel() let model = self.rawModel()
@@ -147,8 +153,7 @@ public extension DynamicSchema {
} }
case .dateAttributeType: case .dateAttributeType:
valueType = Date.self valueType = Date.self
if let defaultValue = (attribute.defaultValue as! Date.ImportableNativeType?).flatMap(Date.cs_fromImportableNativeType), if let defaultValue = (attribute.defaultValue as! Date.ImportableNativeType?).flatMap(Date.cs_fromImportableNativeType) {
defaultValue != Date.cs_emptyValue() {
defaultString = ", default: Date(timeIntervalSinceReferenceDate: \(defaultValue.timeIntervalSinceReferenceDate))" defaultString = ", default: Date(timeIntervalSinceReferenceDate: \(defaultValue.timeIntervalSinceReferenceDate))"
} }
@@ -188,9 +193,11 @@ public extension DynamicSchema {
let indexedString = attribute.isIndexed ? ", isIndexed: true" : "" let indexedString = attribute.isIndexed ? ", isIndexed: true" : ""
let transientString = attribute.isTransient ? ", isTransient: true" : "" let transientString = attribute.isTransient ? ", isTransient: true" : ""
// TODO: escape strings // TODO: escape strings
let versionHashModifierString = attribute.versionHashModifier.flatMap({ ", versionHashModifier: \"\($0)\"" }) ?? "" let versionHashModifierString = attribute.versionHashModifier
.flatMap({ ", versionHashModifier: \"\($0)\"" }) ?? ""
// TODO: escape strings // TODO: escape strings
let renamingIdentifierString = attribute.renamingIdentifier.flatMap({ ", renamingIdentifier: \"\($0)\"" }) ?? "" let renamingIdentifierString = attribute.renamingIdentifier
.flatMap({ ($0 == attributeName ? "" : ", renamingIdentifier: \"\($0)\"") as String }) ?? ""
output.append(" let \(attributeName) = \(containerType)<\(String(describing: valueType))>(\"\(attributeName)\"\(indexedString)\(defaultString)\(transientString)\(versionHashModifierString)\(renamingIdentifierString))\n") output.append(" let \(attributeName) = \(containerType)<\(String(describing: valueType))>(\"\(attributeName)\"\(indexedString)\(defaultString)\(transientString)\(versionHashModifierString)\(renamingIdentifierString))\n")
} }
} }
@@ -255,8 +262,10 @@ public extension DynamicSchema {
fatalError("Unsupported delete rule \((relationship.deleteRule)) for relationship \"\(relationshipQualifier)\"") fatalError("Unsupported delete rule \((relationship.deleteRule)) for relationship \"\(relationshipQualifier)\"")
} }
} }
let versionHashModifierString = relationship.versionHashModifier.flatMap({ ", versionHashModifier: \"\($0)\"" }) ?? "" let versionHashModifierString = relationship.versionHashModifier
let renamingIdentifierString = relationship.renamingIdentifier.flatMap({ ", renamingIdentifier: \"\($0)\"" }) ?? "" .flatMap({ ", versionHashModifier: \"\($0)\"" }) ?? ""
let renamingIdentifierString = relationship.renamingIdentifier
.flatMap({ ($0 == relationshipName ? "" : ", renamingIdentifier: \"\($0)\"") as String }) ?? ""
output.append(" let \(relationshipName) = \(containerType)<\(relationship.destinationEntity!.name!)>(\"\(relationshipName)\"\(inverseString)\(deleteRuleString)\(minCountString)\(maxCountString)\(versionHashModifierString)\(renamingIdentifierString))\n") output.append(" let \(relationshipName) = \(containerType)<\(relationship.destinationEntity!.name!)>(\"\(relationshipName)\"\(inverseString)\(deleteRuleString)\(minCountString)\(maxCountString)\(versionHashModifierString)\(renamingIdentifierString))\n")
} }
} }

View File

@@ -32,7 +32,7 @@ import Foundation
/** /**
`DynamicSchema` are types that provide `NSManagedObjectModel` instances for a single model version. CoreStore currently supports the following concrete types: `DynamicSchema` are types that provide `NSManagedObjectModel` instances for a single model version. CoreStore currently supports the following concrete types:
- `XcodeDataModelSchema`: describes models loaded from a .xcdatamodeld file. - `XcodeDataModelSchema`: describes models loaded from a .xcdatamodeld file.
- `LegacyXcodeDataModelSchema`: describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore. - `UnsafeDataModelSchema`: describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore.
- `CoreStoreSchema`: describes models written for `CoreStoreObject` Swift class declarations. - `CoreStoreSchema`: describes models written for `CoreStoreObject` Swift class declarations.
*/ */
public protocol DynamicSchema { public protocol DynamicSchema {

View File

@@ -54,7 +54,7 @@ internal struct EntityIdentifier: Hashable {
internal init(_ type: CoreStoreObject.Type) { internal init(_ type: CoreStoreObject.Type) {
self.category = .coreStore self.category = .coreStore
self.interfacedClassName = String(reflecting: type) self.interfacedClassName = NSStringFromClass(type)
} }
internal init(_ type: DynamicObject.Type) { internal init(_ type: DynamicObject.Type) {

View File

@@ -35,124 +35,124 @@ import CoreData
public protocol FetchableSource: class { public protocol FetchableSource: class {
/** /**
Fetches the `NSManagedObject` instance in the `FetchableSource`'s context from a reference created from another managed object context. Fetches the `DynamicObject` instance in the `FetchableSource`'s context from a reference created from another managed object context.
- parameter object: a reference to the object created/fetched outside the `FetchableSource`'s context - parameter object: a reference to the object created/fetched outside the `FetchableSource`'s context
- returns: the `NSManagedObject` instance if the object exists in the `FetchableSource`'s context, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `FetchableSource`'s context, or `nil` if not found.
*/ */
func fetchExisting<T: DynamicObject>(_ object: T) -> T? func fetchExisting<T: DynamicObject>(_ object: T) -> T?
/** /**
Fetches the `NSManagedObject` instance in the `FetchableSource`'s context from an `NSManagedObjectID`. Fetches the `DynamicObject` instance in the `FetchableSource`'s context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object - parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `FetchableSource`, or `nil` if not found. - returns: the `DynamicObject` instance if the object exists in the `FetchableSource`, or `nil` if not found.
*/ */
func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T?
/** /**
Fetches the `NSManagedObject` instances in the `FetchableSource`'s context from references created from another managed object context. Fetches the `DynamicObject` instances in the `FetchableSource`'s context from references created from another managed object context.
- parameter objects: an array of `NSManagedObject`s created/fetched outside the `FetchableSource`'s context - parameter objects: an array of `DynamicObject`s created/fetched outside the `FetchableSource`'s context
- returns: the `NSManagedObject` array for objects that exists in the `FetchableSource` - returns: the `DynamicObject` array for objects that exists in the `FetchableSource`
*/ */
func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T
/** /**
Fetches the `NSManagedObject` instances in the `FetchableSource`'s context from a list of `NSManagedObjectID`. Fetches the `DynamicObject` instances in the `FetchableSource`'s context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects - parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `FetchableSource`'s context - returns: the `DynamicObject` array for objects that exists in the `FetchableSource`'s context
*/ */
func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID
/** /**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T?
/** /**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s - returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s
*/ */
func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T?
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]?
/** /**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s - returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s
*/ */
func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]?
/** /**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int?
/** /**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the number `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int?
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID?
/** /**
Fetches the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s - returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s
*/ */
func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID?
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]?
/** /**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses. Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s - returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s
*/ */
func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]?
@@ -160,10 +160,4 @@ public protocol FetchableSource: class {
The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases. The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/ */
func unsafeContext() -> NSManagedObjectContext func unsafeContext() -> NSManagedObjectContext
// MARK: Deprecated
@available(*, deprecated, renamed: "unsafeContext()")
func internalContext() -> NSManagedObjectContext
} }

View File

@@ -32,11 +32,11 @@ import CoreData
/** /**
A `From` clause specifies the source entity and source persistent store for fetch and query methods. A common usage is to just indicate the entity: A `From` clause specifies the source entity and source persistent store for fetch and query methods. A common usage is to just indicate the entity:
``` ```
let person = transaction.fetchOne(From<MyPersonEntity>()) let person = transaction.fetchOne(From<Person>())
``` ```
For cases where multiple `NSPersistentStore`s contain the same entity, the source configuration's name needs to be specified as well: For cases where multiple `NSPersistentStore`s contain the same entity, the source configuration's name needs to be specified as well:
``` ```
let person = transaction.fetchOne(From<MyPersonEntity>("Configuration1")) let person = transaction.fetchOne(From<Person>("Configuration1"))
``` ```
*/ */
public struct From<T: DynamicObject> { public struct From<T: DynamicObject> {

View File

@@ -62,7 +62,6 @@ public final class ICloudStore: CloudStorage {
- parameter ubiquitousContainerID: a container if your app has multiple ubiquity container identifiers in its entitlements - parameter ubiquitousContainerID: a container if your app has multiple ubiquity container identifiers in its entitlements
- parameter ubiquitousPeerToken: a per-application salt to allow multiple apps on the same device to share a Core Data store integrated with iCloud - parameter ubiquitousPeerToken: a per-application salt to allow multiple apps on the same device to share a Core Data store integrated with iCloud
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `ubiquitousContentName` explicitly for each of them. - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `ubiquitousContentName` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration.
- parameter cloudStorageOptions: When the `ICloudStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. - parameter cloudStorageOptions: When the `ICloudStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/ */
public required init?(ubiquitousContentName: String, ubiquitousContentTransactionLogsSubdirectory: String, ubiquitousContainerID: String? = nil, ubiquitousPeerToken: String? = nil, configuration: ModelConfiguration = nil, cloudStorageOptions: CloudStorageOptions = nil) { public required init?(ubiquitousContentName: String, ubiquitousContentTransactionLogsSubdirectory: String, ubiquitousContainerID: String? = nil, ubiquitousPeerToken: String? = nil, configuration: ModelConfiguration = nil, cloudStorageOptions: CloudStorageOptions = nil) {
@@ -271,9 +270,9 @@ public final class ICloudStore: CloudStorage {
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
public func didAddToDataStack(_ dataStack: DataStack) { public func cs_didAddToDataStack(_ dataStack: DataStack) {
self.didRemoveFromDataStack(dataStack) self.cs_didRemoveFromDataStack(dataStack)
self.dataStack = dataStack self.dataStack = dataStack
let coordinator = dataStack.coordinator let coordinator = dataStack.coordinator
@@ -367,7 +366,7 @@ public final class ICloudStore: CloudStorage {
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
public func didRemoveFromDataStack(_ dataStack: DataStack) { public func cs_didRemoveFromDataStack(_ dataStack: DataStack) {
let coordinator = dataStack.coordinator let coordinator = dataStack.coordinator
let nilValue: AnyObject? = nil let nilValue: AnyObject? = nil
@@ -424,7 +423,7 @@ public final class ICloudStore: CloudStorage {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
public func eraseStorageAndWait(soureModel: NSManagedObjectModel) throws { public func cs_eraseStorageAndWait(soureModel: NSManagedObjectModel) throws {
// TODO: check if attached to persistent store // TODO: check if attached to persistent store

View File

@@ -31,7 +31,7 @@ import CoreGraphics
// MARK: - ImportableAttributeType // MARK: - ImportableAttributeType
/** /**
Types supported by CoreStore as `NSManagedObject` attribute types. Types supported by CoreStore as `NSManagedObject` and `CoreStoreObject` property types.
Supported default types: Supported default types:
- Bool - Bool
- CGFloat - CGFloat
@@ -54,34 +54,55 @@ import CoreGraphics
- String - String
- URL - URL
- UUID - UUID
In addition, `RawRepresentable` types whose `RawValue` already implements `ImportableAttributeType` only need to declare conformance to `ImportableAttributeType`.
*/ */
public protocol ImportableAttributeType: QueryableAttributeType { public protocol ImportableAttributeType: QueryableAttributeType {
/**
The `CoreDataNativeType` for this type.
*/
associatedtype ImportableNativeType: QueryableNativeType associatedtype ImportableNativeType: QueryableNativeType
@inline(__always) /**
static func cs_emptyValue() -> Self Creates an instance of this type from its `ImportableNativeType` value.
*/
@inline(__always) @inline(__always)
static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self?
/**
Creates `ImportableNativeType` value from this instance.
*/
@inline(__always) @inline(__always)
func cs_toImportableNativeType() -> ImportableNativeType func cs_toImportableNativeType() -> ImportableNativeType
} }
// MARK: - EmptyableAttributeType
/**
`ImportableAttributeType`s that have a natural "empty" value. Example: `0` for `Int`, `""` for `String`.
- Discussion: Not all `ImportableAttributeType`s can have empty values. `URL`s and `Date`s for example have no obvious empty values.
*/
public protocol EmptyableAttributeType: ImportableAttributeType {
/**
Returns the default "empty" value for this type.
*/
@inline(__always)
static func cs_emptyValue() -> Self
}
// MARK: - Bool // MARK: - Bool
extension Bool: ImportableAttributeType { extension Bool: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Bool {
return false
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Bool? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Bool? {
@@ -93,21 +114,26 @@ extension Bool: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Bool {
return false
}
} }
// MARK: - CGFloat // MARK: - CGFloat
extension CGFloat: ImportableAttributeType { extension CGFloat: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> CGFloat {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> CGFloat? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> CGFloat? {
@@ -119,21 +145,26 @@ extension CGFloat: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> CGFloat {
return 0
}
} }
// MARK: - Data // MARK: - Data
extension Data: ImportableAttributeType { extension Data: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSData public typealias ImportableNativeType = NSData
@inline(__always)
public static func cs_emptyValue() -> Data {
return Data()
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Data? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Data? {
@@ -145,6 +176,15 @@ extension Data: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Data {
return Data()
}
} }
@@ -152,14 +192,10 @@ extension Data: ImportableAttributeType {
extension Date: ImportableAttributeType { extension Date: ImportableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSDate public typealias ImportableNativeType = NSDate
@inline(__always)
public static func cs_emptyValue() -> Date {
return Date(timeIntervalSinceReferenceDate: 0)
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Date? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Date? {
@@ -176,16 +212,12 @@ extension Date: ImportableAttributeType {
// MARK: - Double // MARK: - Double
extension Double: ImportableAttributeType { extension Double: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Double {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Double? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Double? {
@@ -197,21 +229,26 @@ extension Double: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Double {
return 0
}
} }
// MARK: - Float // MARK: - Float
extension Float: ImportableAttributeType { extension Float: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Float {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Float? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Float? {
@@ -223,21 +260,26 @@ extension Float: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Float {
return 0
}
} }
// MARK: - Int // MARK: - Int
extension Int: ImportableAttributeType { extension Int: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Int {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int? {
@@ -249,21 +291,26 @@ extension Int: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Int {
return 0
}
} }
// MARK: - Int8 // MARK: - Int8
extension Int8: ImportableAttributeType { extension Int8: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Int8 {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int8? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int8? {
@@ -275,21 +322,26 @@ extension Int8: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Int8 {
return 0
}
} }
// MARK: - Int16 // MARK: - Int16
extension Int16: ImportableAttributeType { extension Int16: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Int16 {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int16? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int16? {
@@ -301,21 +353,26 @@ extension Int16: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Int16 {
return 0
}
} }
// MARK: - Int32 // MARK: - Int32
extension Int32: ImportableAttributeType { extension Int32: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Int32 {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int32? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int32? {
@@ -327,21 +384,26 @@ extension Int32: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Int32 {
return 0
}
} }
// MARK: - Int64 // MARK: - Int64
extension Int64: ImportableAttributeType { extension Int64: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@inline(__always)
public static func cs_emptyValue() -> Int64 {
return 0
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int64? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Int64? {
@@ -353,21 +415,26 @@ extension Int64: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> Int64 {
return 0
}
} }
// MARK: - NSData // MARK: - NSData
extension NSData: ImportableAttributeType { extension NSData: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSData public typealias ImportableNativeType = NSData
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init()
}
@nonobjc @inline(__always) @nonobjc @inline(__always)
public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? { public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? {
@@ -379,6 +446,15 @@ extension NSData: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init()
}
} }
@@ -386,14 +462,10 @@ extension NSData: ImportableAttributeType {
extension NSDate: ImportableAttributeType { extension NSDate: ImportableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSDate public typealias ImportableNativeType = NSDate
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init(timeIntervalSinceReferenceDate: 0)
}
@nonobjc @inline(__always) @nonobjc @inline(__always)
public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? { public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? {
@@ -410,16 +482,12 @@ extension NSDate: ImportableAttributeType {
// MARK: - NSNumber // MARK: - NSNumber
extension NSNumber: ImportableAttributeType { extension NSNumber: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSNumber public typealias ImportableNativeType = NSNumber
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init()
}
@nonobjc @inline(__always) @nonobjc @inline(__always)
public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? { public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? {
@@ -431,21 +499,26 @@ extension NSNumber: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init()
}
} }
// MARK: - NSString // MARK: - NSString
extension NSString: ImportableAttributeType { extension NSString: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSString public typealias ImportableNativeType = NSString
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init()
}
@nonobjc @inline(__always) @nonobjc @inline(__always)
public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? { public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? {
@@ -457,6 +530,15 @@ extension NSString: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init()
}
} }
@@ -464,14 +546,10 @@ extension NSString: ImportableAttributeType {
extension NSURL: ImportableAttributeType { extension NSURL: ImportableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSString public typealias ImportableNativeType = NSString
@nonobjc @inline(__always)
public class func cs_emptyValue() -> Self {
return self.init(string: "")!
}
@nonobjc @inline(__always) @nonobjc @inline(__always)
public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? { public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? {
@@ -490,17 +568,10 @@ extension NSURL: ImportableAttributeType {
extension NSUUID: ImportableAttributeType { extension NSUUID: ImportableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSString public typealias ImportableNativeType = NSString
public class func cs_emptyValue() -> Self {
enum Static {
static var zero = Array<UInt8>(repeating: 0, count: 16)
}
return self.init(uuidBytes: &Static.zero)
}
@nonobjc @inline(__always) @nonobjc @inline(__always)
public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? { public class func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? {
@@ -517,16 +588,12 @@ extension NSUUID: ImportableAttributeType {
// MARK: - String // MARK: - String
extension String: ImportableAttributeType { extension String: ImportableAttributeType, EmptyableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSString public typealias ImportableNativeType = NSString
@inline(__always)
public static func cs_emptyValue() -> String {
return ""
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> String? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> String? {
@@ -538,6 +605,15 @@ extension String: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
// MARK: EmptyableAttributeType
@inline(__always)
public static func cs_emptyValue() -> String {
return ""
}
} }
@@ -545,17 +621,10 @@ extension String: ImportableAttributeType {
extension URL: ImportableAttributeType { extension URL: ImportableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSString public typealias ImportableNativeType = NSString
public static func cs_emptyValue() -> URL {
enum Static {
static let empty = URL(string: "")!
}
return Static.empty
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> URL? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> URL? {
@@ -574,21 +643,10 @@ extension URL: ImportableAttributeType {
extension UUID: ImportableAttributeType { extension UUID: ImportableAttributeType {
// MARK: ImportableAttributeType
public typealias ImportableNativeType = NSString public typealias ImportableNativeType = NSString
public static func cs_emptyValue() -> UUID {
enum Static {
static let empty: UUID = cs_lazy {
var zero = Array<UInt8>(repeating: 0, count: 16)
return NSUUID(uuidBytes: &zero) as UUID
}
}
return Static.empty
}
@inline(__always) @inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> UUID? { public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> UUID? {
@@ -601,3 +659,23 @@ extension UUID: ImportableAttributeType {
return self.cs_toQueryableNativeType() return self.cs_toQueryableNativeType()
} }
} }
// MARK: - RawRepresentable
extension RawRepresentable where RawValue: ImportableAttributeType {
public typealias ImportableNativeType = RawValue.ImportableNativeType
@inline(__always)
public static func cs_fromImportableNativeType(_ value: ImportableNativeType) -> Self? {
return RawValue.cs_fromImportableNativeType(value).flatMap({ self.init(rawValue: $0) })
}
@inline(__always)
public func cs_toImportableNativeType() -> ImportableNativeType {
return self.rawValue.cs_toImportableNativeType()
}
}

View File

@@ -30,28 +30,32 @@ import CoreData
// MARK: - ImportableObject // MARK: - ImportableObject
/** /**
`NSManagedObject` subclasses that conform to the `ImportableObject` protocol can be imported from a specified `ImportSource`. This allows transactions to create and insert instances this way: `NSManagedObject` and `CoreStoreObject` subclasses that conform to the `ImportableObject` protocol can be imported from a specified `ImportSource`. This allows transactions to create and insert instances this way:
``` ```
class MyPersonEntity: NSManagedObject, ImportableObject { class Person: NSManagedObject, ImportableObject {
typealias ImportSource = NSDictionary typealias ImportSource = NSDictionary
// ... // ...
} }
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.perform(
asynchronous: { (transaction) -> Void in
let json: NSDictionary = // ... let json: NSDictionary = // ...
let person = try! transaction.importObject( let person = try transaction.importObject(
Into<MyPersonEntity>(), Into<Person>(),
source: json source: json
) )
// ... // ...
transaction.commit() },
completion: { (result) in
// ...
} }
)
``` ```
*/ */
public protocol ImportableObject: class { public protocol ImportableObject: DynamicObject {
/** /**
The data type for the import source. This is most commonly an `NSDictionary` or another external source such as an `NSUserDefaults`. The data type for the import source. This is most commonly an json type, `NSDictionary`, or another external source such as `NSUserDefaults`.
*/ */
associatedtype ImportSource associatedtype ImportSource

View File

@@ -32,27 +32,31 @@ import CoreData
/** /**
`NSManagedObject` subclasses that conform to the `ImportableUniqueObject` protocol can be imported from a specified `ImportSource`. This allows transactions to either update existing objects or create new instances this way: `NSManagedObject` subclasses that conform to the `ImportableUniqueObject` protocol can be imported from a specified `ImportSource`. This allows transactions to either update existing objects or create new instances this way:
``` ```
class MyPersonEntity: NSManagedObject, ImportableUniqueObject { class Person: NSManagedObject, ImportableObject {
typealias ImportSource = NSDictionary typealias ImportSource = NSDictionary
typealias UniqueIDType = NSString typealias UniqueIDType = NSString
// ... // ...
} }
CoreStore.beginAsynchronous { (transaction) -> Void in CoreStore.perform(
asynchronous: { (transaction) -> Void in
let json: NSDictionary = // ... let json: NSDictionary = // ...
let person = try! transaction.importUniqueObject( let person = try transaction.importUniqueObject(
Into<MyPersonEntity>(), Into<Person>(),
source: json source: json
) )
// ... // ...
transaction.commit() },
completion: { (result) in
// ...
} }
)
``` ```
*/ */
public protocol ImportableUniqueObject: ImportableObject { public protocol ImportableUniqueObject: ImportableObject {
/** /**
The data type for the import source. This is most commonly an `NSDictionary` or another external source such as an `NSUserDefaults`. The data type for the import source. This is most commonly an json type, `NSDictionary`, or another external source such as `NSUserDefaults`.
*/ */
associatedtype ImportSource associatedtype ImportSource
@@ -139,31 +143,31 @@ public extension ImportableUniqueObject {
// MARK: Obsolete // MARK: Obsolete
@available(*, obsoleted: 3.0.0, renamed: "shouldInsert(from:in:)") @available(*, obsoleted: 3.1, renamed: "shouldInsert(from:in:)")
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool { static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
return Self.shouldInsert(from: source, in: transaction) return Self.shouldInsert(from: source, in: transaction)
} }
@available(*, obsoleted: 3.0.0, renamed: "shouldUpdate(from:in:)") @available(*, obsoleted: 3.1, renamed: "shouldUpdate(from:in:)")
static func shouldUpdateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool { static func shouldUpdateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
return Self.shouldUpdate(from: source, in: transaction) return Self.shouldUpdate(from: source, in: transaction)
} }
@available(*, obsoleted: 3.0.0, renamed: "uniqueID(from:in:)") @available(*, obsoleted: 3.1, renamed: "uniqueID(from:in:)")
static func uniqueIDFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType? { static func uniqueIDFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType? {
return try Self.uniqueID(from: source, in: transaction) return try Self.uniqueID(from: source, in: transaction)
} }
@available(*, obsoleted: 3.0.0, renamed: "didInsert(from:in:)") @available(*, obsoleted: 3.1, renamed: "didInsert(from:in:)")
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws { func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
try self.didInsert(from: source, in: transaction) try self.didInsert(from: source, in: transaction)
} }
@available(*, obsoleted: 3.0.0, renamed: "update(from:in:)") @available(*, obsoleted: 3.1, renamed: "update(from:in:)")
func updateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws { func updateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
try self.update(from: source, in: transaction) try self.update(from: source, in: transaction)

View File

@@ -29,7 +29,7 @@ import CoreData
// MARK: - InMemoryStore // MARK: - InMemoryStore
/** /**
A storage interface that is backed only by memory. A storage interface that is backed only in memory.
*/ */
public final class InMemoryStore: StorageInterface { public final class InMemoryStore: StorageInterface {
@@ -71,7 +71,7 @@ public final class InMemoryStore: StorageInterface {
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
public func didAddToDataStack(_ dataStack: DataStack) { public func cs_didAddToDataStack(_ dataStack: DataStack) {
self.dataStack = dataStack self.dataStack = dataStack
} }
@@ -79,7 +79,7 @@ public final class InMemoryStore: StorageInterface {
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
public func didRemoveFromDataStack(_ dataStack: DataStack) { public func cs_didRemoveFromDataStack(_ dataStack: DataStack) {
self.dataStack = nil self.dataStack = nil
} }

View File

@@ -29,6 +29,9 @@ import Foundation
// MARK: - InferredSchemaMappingProvider // MARK: - InferredSchemaMappingProvider
/**
A `SchemaMappingProvider` that tries to infer model migration between two `DynamicSchema` versions by searching all `xcmappingmodel`s from `Bundle.allBundles` or by relying on lightweight migration if possible. Throws an error if lightweight migration is impossible for the two `DynamicSchema`. This mapping is automatically used as a fallback mapping provider, even if no mapping providers are explicitly declared in the `StorageInterface`.
*/
final class InferredSchemaMappingProvider: Hashable, SchemaMappingProvider { final class InferredSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: Equatable // MARK: Equatable
@@ -49,7 +52,7 @@ final class InferredSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: SchemaMappingProvider // MARK: SchemaMappingProvider
public func createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) { public func cs_createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) {
let sourceModel = sourceSchema.rawModel() let sourceModel = sourceSchema.rawModel()
let destinationModel = destinationSchema.rawModel() let destinationModel = destinationSchema.rawModel()

View File

@@ -31,47 +31,23 @@ import CoreData
/** /**
A storage interface backed by an SQLite database that was created before CoreStore 2.0.0. A storage interface backed by an SQLite database that was created before CoreStore 2.0.0.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
*/ */
@available(*, obsoleted: 3.1, message: "`LegacySQLiteStore` previous users should now use `SQLiteStore`'s new SQLiteStore.legacy(fileName:configuration:migrationMappingProviders:localStorageOptions:) or SQLiteStore.legacy() methods to create an `SQLiteStore` with legacy paths.") @available(*, obsoleted: 3.1, message: "`LegacySQLiteStore` previous users should now use `SQLiteStore`'s new SQLiteStore.legacy(fileName:configuration:migrationMappingProviders:localStorageOptions:) or SQLiteStore.legacy() methods to create an `SQLiteStore` with legacy paths.")
public final class LegacySQLiteStore: LocalStorage { public final class LegacySQLiteStore: LocalStorage {
/** @available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.init(fileURL:configuration:migrationMappingProviders:localStorageOptions:) initializer.")
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.init(fileURL:configuration:migrationMappingProviders:localStorageOptions:) initializer")
public init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { public init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) {
fatalError() fatalError()
} }
/** @available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.legacy(fileName:configuration:migrationMappingProviders:localStorageOptions:) factory method.")
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support" directory (or the "Caches" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.legacy(fileName:configuration:migrationMappingProviders:localStorageOptions:) method.")
public init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) { public init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle] = Bundle.allBundles, localStorageOptions: LocalStorageOptions = nil) {
fatalError() fatalError()
} }
/** @available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.legacy(...) factory method.")
Initializes an `LegacySQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support" directory (or the "Caches" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `.AllowProgresiveMigration`.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
*/
@available(*, obsoleted: 3.1, message: "Use `SQLiteStore`'s new SQLiteStore.legacy() method.")
public init() { public init() {
fatalError() fatalError()
@@ -80,143 +56,39 @@ public final class LegacySQLiteStore: LocalStorage {
// MARK: StorageInterface // MARK: StorageInterface
/**
The string identifier for the `NSPersistentStore`'s `type` property. For `SQLiteStore`s, this is always set to `NSSQLiteStoreType`.
*/
public static let storeType = NSSQLiteStoreType public static let storeType = NSSQLiteStoreType
/**
The options dictionary for the specified `LocalStorageOptions`
*/
public func dictionary(forOptions options: LocalStorageOptions) -> [AnyHashable: Any]? { public func dictionary(forOptions options: LocalStorageOptions) -> [AnyHashable: Any]? {
if options == .none { fatalError()
return self.storeOptions
} }
var storeOptions = self.storeOptions ?? [:]
if options.contains(.allowSynchronousLightweightMigration) {
storeOptions[NSMigratePersistentStoresAutomaticallyOption] = true
storeOptions[NSInferMappingModelAutomaticallyOption] = true
}
return storeOptions
}
/**
The configuration name in the model file
*/
public let configuration: ModelConfiguration public let configuration: ModelConfiguration
/**
The options dictionary for the `NSPersistentStore`. For `SQLiteStore`s, this is always set to
```
[NSSQLitePragmasOption: ["journal_mode": "WAL"]]
```
*/
public let storeOptions: [AnyHashable: Any]? = [NSSQLitePragmasOption: ["journal_mode": "WAL"]] public let storeOptions: [AnyHashable: Any]? = [NSSQLitePragmasOption: ["journal_mode": "WAL"]]
/** public func cs_didAddToDataStack(_ dataStack: DataStack) {
Do not call directly. Used by the `DataStack` internally.
*/
public func didAddToDataStack(_ dataStack: DataStack) {
self.dataStack = dataStack fatalError()
} }
/** public func cs_didRemoveFromDataStack(_ dataStack: DataStack) {
Do not call directly. Used by the `DataStack` internally.
*/
public func didRemoveFromDataStack(_ dataStack: DataStack) {
self.dataStack = nil fatalError()
} }
// MAKR: LocalStorage // MAKR: LocalStorage
/**
The `NSURL` that points to the SQLite file
*/
public let fileURL: URL public let fileURL: URL
/**
An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations.
*/
public let migrationMappingProviders: [SchemaMappingProvider] public let migrationMappingProviders: [SchemaMappingProvider]
/**
Options that tell the `DataStack` how to setup the persistent store
*/
public var localStorageOptions: LocalStorageOptions public var localStorageOptions: LocalStorageOptions
/** public func cs_eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws {
Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/
public func eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws {
// TODO: check if attached to persistent store fatalError()
func deleteFiles(storeURL: URL, extraFiles: [String] = []) throws {
let fileManager = FileManager.default
let extraFiles: [String] = [
storeURL.path.appending("-wal"),
storeURL.path.appending("-shm")
]
do {
let trashURL = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!)
.appendingPathComponent(Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack", isDirectory: true)
.appendingPathComponent("trash", isDirectory: true)
try fileManager.createDirectory(
at: trashURL,
withIntermediateDirectories: true,
attributes: nil
)
let temporaryFileURL = trashURL.appendingPathComponent(UUID().uuidString, isDirectory: false)
try fileManager.moveItem(at: storeURL, to: temporaryFileURL)
let extraTemporaryFiles = extraFiles.map { (extraFile) -> String in
let temporaryFile = trashURL.appendingPathComponent(UUID().uuidString, isDirectory: false).path
if let _ = try? fileManager.moveItem(atPath: extraFile, toPath: temporaryFile) {
return temporaryFile
}
return extraFile
}
DispatchQueue.global(qos: .background).async {
_ = try? fileManager.removeItem(at: temporaryFileURL)
extraTemporaryFiles.forEach({ _ = try? fileManager.removeItem(atPath: $0) })
}
}
catch {
try fileManager.removeItem(at: storeURL)
extraFiles.forEach({ _ = try? fileManager.removeItem(atPath: $0) })
}
}
let fileURL = self.fileURL
try autoreleasepool {
if let soureModel = soureModelHint ?? NSManagedObjectModel.mergedModel(from: nil, forStoreMetadata: metadata) {
let journalUpdatingCoordinator = NSPersistentStoreCoordinator(managedObjectModel: soureModel)
let store = try journalUpdatingCoordinator.addPersistentStore(
ofType: type(of: self).storeType,
configurationName: self.configuration,
at: fileURL,
options: [NSSQLitePragmasOption: ["journal_mode": "DELETE"]]
)
try journalUpdatingCoordinator.remove(store)
}
try deleteFiles(storeURL: fileURL)
}
} }

View File

@@ -30,10 +30,10 @@ import CoreData
// MARK: - ListMonitor // MARK: - ListMonitor
/** /**
The `ListMonitor` monitors changes to a list of `NSManagedObject` instances. Observers that implement the `ListObserver` protocol may then register themselves to the `ListMonitor`'s `addObserver(_:)` method: The `ListMonitor` monitors changes to a list of `DynamicObject` instances. Observers that implement the `ListObserver` protocol may then register themselves to the `ListMonitor`'s `addObserver(_:)` method:
``` ```
let monitor = CoreStore.monitorList( let monitor = CoreStore.monitorList(
From<MyPersonEntity>(), From<Person>(),
Where("title", isEqualTo: "Engineer"), Where("title", isEqualTo: "Engineer"),
OrderBy(.ascending("lastName")) OrderBy(.ascending("lastName"))
) )
@@ -51,16 +51,16 @@ import CoreData
Creating a sectioned-list is also possible with the `monitorSectionedList(...)` method: Creating a sectioned-list is also possible with the `monitorSectionedList(...)` method:
``` ```
let monitor = CoreStore.monitorSectionedList( let monitor = CoreStore.monitorSectionedList(
From<MyPersonEntity>(), From<Person>(),
SectionBy("age") { "Age \($0)" }, SectionBy("age") { "Age \($0)" },
Where("title", isEqualTo: "Engineer"), Where("title", isEqualTo: "Engineer"),
OrderBy(.ascending("lastName")) OrderBy(.ascending("lastName"))
) )
monitor.addObserver(self) monitor.addObserver(self)
``` ```
Objects from `ListMonitor`s created this way can be accessed either by an `NSIndexPath` or a tuple: Objects from `ListMonitor`s created this way can be accessed either by an `IndexPath` or a tuple:
``` ```
let indexPath = NSIndexPath(forItem: 3, inSection: 2) let indexPath = IndexPath(forItem: 3, inSection: 2)
let person1 = monitor[indexPath] let person1 = monitor[indexPath]
let person2 = monitor[2, 3] let person2 = monitor[2, 3]
``` ```
@@ -80,7 +80,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
Returns the object at the given index within the first section. This subscript indexer is typically used for `ListMonitor`s created with `monitorList(_:)`. Returns the object at the given index within the first section. This subscript indexer is typically used for `ListMonitor`s created with `monitorList(_:)`.
- parameter index: the index of the object. Using an index above the valid range will raise an exception. - parameter index: the index of the object. Using an index above the valid range will raise an exception.
- returns: the `NSManagedObject` at the specified index - returns: the `DynamicObject` at the specified index
*/ */
public subscript(index: Int) -> ObjectType { public subscript(index: Int) -> ObjectType {
@@ -99,7 +99,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
Returns the object at the given index, or `nil` if out of bounds. This subscript indexer is typically used for `ListMonitor`s created with `monitorList(_:)`. Returns the object at the given index, or `nil` if out of bounds. This subscript indexer is typically used for `ListMonitor`s created with `monitorList(_:)`.
- parameter index: the index for the object. Using an index above the valid range will return `nil`. - parameter index: the index for the object. Using an index above the valid range will return `nil`.
- returns: the `NSManagedObject` at the specified index, or `nil` if out of bounds - returns: the `DynamicObject` at the specified index, or `nil` if out of bounds
*/ */
public subscript(safeIndex index: Int) -> ObjectType? { public subscript(safeIndex index: Int) -> ObjectType? {
@@ -120,11 +120,11 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
- parameter sectionIndex: the section index for the object. Using a `sectionIndex` with an invalid range will raise an exception. - parameter sectionIndex: the section index for the object. Using a `sectionIndex` with an invalid range will raise an exception.
- parameter itemIndex: the index for the object within the section. Using an `itemIndex` with an invalid range will raise an exception. - parameter itemIndex: the index for the object within the section. Using an `itemIndex` with an invalid range will raise an exception.
- returns: the `NSManagedObject` at the specified section and item index - returns: the `DynamicObject` at the specified section and item index
*/ */
public subscript(sectionIndex: Int, itemIndex: Int) -> ObjectType { public subscript(sectionIndex: Int, itemIndex: Int) -> ObjectType {
return self[NSIndexPath(indexes: [sectionIndex, itemIndex], length: 2) as IndexPath] return self[IndexPath(indexes: [sectionIndex, itemIndex])]
} }
/** /**
@@ -132,7 +132,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
- parameter sectionIndex: the section index for the object. Using a `sectionIndex` with an invalid range will return `nil`. - parameter sectionIndex: the section index for the object. Using a `sectionIndex` with an invalid range will return `nil`.
- parameter itemIndex: the index for the object within the section. Using an `itemIndex` with an invalid range will return `nil`. - parameter itemIndex: the index for the object within the section. Using an `itemIndex` with an invalid range will return `nil`.
- returns: the `NSManagedObject` at the specified section and item index, or `nil` if out of bounds - returns: the `DynamicObject` at the specified section and item index, or `nil` if out of bounds
*/ */
public subscript(safeSectionIndex sectionIndex: Int, safeItemIndex itemIndex: Int) -> ObjectType? { public subscript(safeSectionIndex sectionIndex: Int, safeItemIndex itemIndex: Int) -> ObjectType? {
@@ -148,10 +148,10 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
/** /**
Returns the object at the given `NSIndexPath`. This subscript indexer is typically used for `ListMonitor`s created with `monitorSectionedList(_:)`. Returns the object at the given `IndexPath`. This subscript indexer is typically used for `ListMonitor`s created with `monitorSectionedList(_:)`.
- parameter indexPath: the `NSIndexPath` for the object. Using an `indexPath` with an invalid range will raise an exception. - parameter indexPath: the `IndexPath` for the object. Using an `indexPath` with an invalid range will raise an exception.
- returns: the `NSManagedObject` at the specified index path - returns: the `DynamicObject` at the specified index path
*/ */
public subscript(indexPath: IndexPath) -> ObjectType { public subscript(indexPath: IndexPath) -> ObjectType {
@@ -163,10 +163,10 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
/** /**
Returns the object at the given `NSIndexPath`, or `nil` if out of bounds. This subscript indexer is typically used for `ListMonitor`s created with `monitorSectionedList(_:)`. Returns the object at the given `IndexPath`, or `nil` if out of bounds. This subscript indexer is typically used for `ListMonitor`s created with `monitorSectionedList(_:)`.
- parameter indexPath: the `NSIndexPath` for the object. Using an `indexPath` with an invalid range will return `nil`. - parameter indexPath: the `IndexPath` for the object. Using an `indexPath` with an invalid range will return `nil`.
- returns: the `NSManagedObject` at the specified index path, or `nil` if out of bounds - returns: the `DynamicObject` at the specified index path, or `nil` if out of bounds
*/ */
public subscript(safeIndexPath indexPath: IndexPath) -> ObjectType? { public subscript(safeIndexPath indexPath: IndexPath) -> ObjectType? {
@@ -340,10 +340,10 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
/** /**
Returns the index of the `NSManagedObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found. Returns the index of the `DynamicObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found.
- parameter object: the `NSManagedObject` to search the index of - parameter object: the `DynamicObject` to search the index of
- returns: the index of the `NSManagedObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found. - returns: the index of the `DynamicObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found.
*/ */
public func indexOf(_ object: ObjectType) -> Int? { public func indexOf(_ object: ObjectType) -> Int? {
@@ -359,10 +359,10 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
} }
/** /**
Returns the `NSIndexPath` of the `NSManagedObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found. Returns the `IndexPath` of the `DynamicObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found.
- parameter object: the `NSManagedObject` to search the index of - parameter object: the `DynamicObject` to search the index of
- returns: the `NSIndexPath` of the `NSManagedObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found. - returns: the `IndexPath` of the `DynamicObject` if it exists in the `ListMonitor`'s fetched objects, or `nil` if not found.
*/ */
public func indexPathOf(_ object: ObjectType) -> IndexPath? { public func indexPathOf(_ object: ObjectType) -> IndexPath? {
@@ -590,7 +590,7 @@ public final class ListMonitor<D: DynamicObject>: Hashable {
``` ```
- Important: Do not use this method to store thread-sensitive data. - Important: Do not use this method to store thread-sensitive data.
*/ */
private let userInfo = UserInfo() public let userInfo = UserInfo()
// MARK: Equatable // MARK: Equatable

View File

@@ -33,7 +33,7 @@ import CoreData
Implement the `ListObserver` protocol to observe changes to a list of `NSManagedObject`s. `ListObserver`s may register themselves to a `ListMonitor`'s `addObserver(_:)` method: Implement the `ListObserver` protocol to observe changes to a list of `NSManagedObject`s. `ListObserver`s may register themselves to a `ListMonitor`'s `addObserver(_:)` method:
``` ```
let monitor = CoreStore.monitorList( let monitor = CoreStore.monitorList(
From<MyPersonEntity>(), From<Person>(),
OrderBy(.ascending("lastName")) OrderBy(.ascending("lastName"))
) )
monitor.addObserver(self) monitor.addObserver(self)
@@ -56,8 +56,7 @@ public protocol ListObserver: class {
func listMonitorWillChange(_ monitor: ListMonitor<ListEntityType>) func listMonitorWillChange(_ monitor: ListMonitor<ListEntityType>)
/** /**
Handles processing right after a change to the observed list occurs. (Optional) Handles processing right after a change to the observed list occurs. (Required)
The default implementation does nothing.
- parameter monitor: the `ListMonitor` monitoring the object being observed - parameter monitor: the `ListMonitor` monitoring the object being observed
*/ */
@@ -65,17 +64,16 @@ public protocol ListObserver: class {
/** /**
This method is broadcast from within the `ListMonitor`'s `refetch(...)` method to let observers prepare for the internal `NSFetchedResultsController`'s pending change to its predicate, sort descriptors, etc. (Optional) This method is broadcast from within the `ListMonitor`'s `refetch(...)` method to let observers prepare for the internal `NSFetchedResultsController`'s pending change to its predicate, sort descriptors, etc. (Optional)
The default implementation does nothing.
- Note: The actual refetch will happen after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes
- Important: All `ListMonitor` access between `listMonitorWillRefetch(_:)` and `listMonitorDidRefetch(_:)` will raise and assertion. The actual refetch will happen after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes.
- parameter monitor: the `ListMonitor` monitoring the object being observed - parameter monitor: the `ListMonitor` monitoring the object being observed
*/ */
func listMonitorWillRefetch(_ monitor: ListMonitor<ListEntityType>) func listMonitorWillRefetch(_ monitor: ListMonitor<ListEntityType>)
/** /**
After the `ListMonitor`'s `refetch(...)` method is called, this method is broadcast after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes. (Optional) After the `ListMonitor`'s `refetch(...)` method is called, this method is broadcast after the `NSFetchedResultsController`'s last `controllerDidChangeContent(_:)` notification completes. (Required)
The default implementation does nothing.
- Important: When `listMonitorDidRefetch(_:)` is called it should be assumed that all `ListMonitor`'s previous data have been reset, including counts, objects, and persistent stores.
- parameter monitor: the `ListMonitor` monitoring the object being observed - parameter monitor: the `ListMonitor` monitoring the object being observed
*/ */
func listMonitorDidRefetch(_ monitor: ListMonitor<ListEntityType>) func listMonitorDidRefetch(_ monitor: ListMonitor<ListEntityType>)
@@ -89,11 +87,7 @@ public extension ListObserver {
public func listMonitorWillChange(_ monitor: ListMonitor<ListEntityType>) { } public func listMonitorWillChange(_ monitor: ListMonitor<ListEntityType>) { }
public func listMonitorDidChange(_ monitor: ListMonitor<ListEntityType>) { }
public func listMonitorWillRefetch(_ monitor: ListMonitor<ListEntityType>) { } public func listMonitorWillRefetch(_ monitor: ListMonitor<ListEntityType>) { }
public func listMonitorDidRefetch(_ monitor: ListMonitor<ListEntityType>) { }
} }

View File

@@ -30,7 +30,7 @@ import CoreData
// MARK: - MigrationChain // MARK: - MigrationChain
/** /**
A `MigrationChain` indicates the sequence of model versions to be used as the order for progressive migrations. This is typically passed to the `DataStack` initializer and will be applied to all stores added to the `DataStack` with `addSQLiteStore(...)` and its variants. A `MigrationChain` indicates the sequence of model versions to be used as the order for progressive migrations. This is typically passed to the `SchemaHistory` or the `DataStack` initializer and will be applied to all stores added to the `DataStack` with `addStorage(...)` and its variants.
Initializing with empty values (either `nil`, `[]`, or `[:]`) instructs the `DataStack` to use the .xcdatamodel's current version as the final version, and to disable progressive migrations: Initializing with empty values (either `nil`, `[]`, or `[:]`) instructs the `DataStack` to use the .xcdatamodel's current version as the final version, and to disable progressive migrations:
``` ```

View File

@@ -32,27 +32,12 @@ import Foundation
The `MigrationResult` indicates the result of a migration. The `MigrationResult` indicates the result of a migration.
The `MigrationResult` can be treated as a boolean: The `MigrationResult` can be treated as a boolean:
``` ```
CoreStore.upgradeSQLiteStoreIfNeeded { transaction in CoreStore.upgradeStorageIfNeeded(SQLiteStorage(fileName: "data.sqlite")) { (result) in
// ...
let result = transaction.commit()
if result {
// succeeded
}
else {
// failed
}
}
```
or as an `enum`, where the resulting associated object can also be inspected:
```
CoreStore.beginAsynchronous { transaction in
// ...
let result = transaction.commit()
switch result { switch result {
case .success(let hasChanges): case .success(let migrationSteps):
// hasChanges indicates if there were changes or not // ...
case .failure(let error): case .failure(let error):
// error is a CoreStoreError enum value // ...
} }
} }
``` ```

View File

@@ -36,22 +36,22 @@ public enum MigrationType: Hashable {
/** /**
Indicates that the persistent store matches the latest model version and no migration is needed Indicates that the persistent store matches the latest model version and no migration is needed
*/ */
case none(version: String) case none(version: ModelVersion)
/** /**
Indicates that the persistent store does not match the latest model version but Core Data can infer the mapping model, so a lightweight migration is needed Indicates that the persistent store does not match the latest model version but Core Data can infer the mapping model, so a lightweight migration is needed
*/ */
case lightweight(sourceVersion: String, destinationVersion: String) case lightweight(sourceVersion: ModelVersion, destinationVersion: ModelVersion)
/** /**
Indicates that the persistent store does not match the latest model version and Core Data could not infer a mapping model, so a custom migration is needed Indicates that the persistent store does not match the latest model version and Core Data could not infer a mapping model, so a custom migration is needed
*/ */
case heavyweight(sourceVersion: String, destinationVersion: String) case heavyweight(sourceVersion: ModelVersion, destinationVersion: ModelVersion)
/** /**
Returns the source model version for the migration type. If no migration is required, `sourceVersion` will be equal to the `destinationVersion`. Returns the source model version for the migration type. If no migration is required, `sourceVersion` will be equal to the `destinationVersion`.
*/ */
public var sourceVersion: String { public var sourceVersion: ModelVersion {
switch self { switch self {
@@ -69,7 +69,7 @@ public enum MigrationType: Hashable {
/** /**
Returns the destination model version for the migration type. If no migration is required, `destinationVersion` will be equal to the `sourceVersion`. Returns the destination model version for the migration type. If no migration is required, `destinationVersion` will be equal to the `sourceVersion`.
*/ */
public var destinationVersion: String { public var destinationVersion: ModelVersion {
switch self { switch self {

View File

@@ -32,15 +32,7 @@ import CoreData
@available(OSX 10.12, *) @available(OSX 10.12, *)
public extension CSDataStack { public extension CSDataStack {
/** @available(*, deprecated, message: "CoreStore will obsolete NSFetchedResultsController support in the future in favor of CSListMonitor")
Utility for creating an `NSFetchedResultsController` from the `CSDataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `CSListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `-performFetch:` on the created `NSFetchedResultsController`.
- parameter from: a `CSFrom` clause indicating the entity type
- parameter sectionBy: a `CSSectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
- parameter fetchClauses: a series of `CSFetchClause` instances for fetching the object list. Accepts `CSWhere`, `CSOrderBy`, and `CSTweak` clauses.
- returns: an `NSFetchedResultsController` that observes the `CSDataStack`
*/
@objc @objc
public func createFetchedResultsControllerFrom(_ from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> NSFetchedResultsController<NSManagedObject> { public func createFetchedResultsControllerFrom(_ from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> NSFetchedResultsController<NSManagedObject> {
@@ -59,15 +51,7 @@ public extension CSDataStack {
@available(OSX 10.12, *) @available(OSX 10.12, *)
public extension CSUnsafeDataTransaction { public extension CSUnsafeDataTransaction {
/** @available(*, deprecated, message: "CoreStore will obsolete NSFetchedResultsController support in the future in favor of CSListMonitor")
Utility for creating an `NSFetchedResultsController` from the `CSUnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `CSListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `-performFetch:` on the created `NSFetchedResultsController`.
- parameter from: a `CSFrom` clause indicating the entity type
- parameter sectionBy: a `CSSectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: an `NSFetchedResultsController` that observes an `CSUnsafeDataTransaction`
*/
@objc @objc
public func createFetchedResultsControllerFrom(_ from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> NSFetchedResultsController<NSManagedObject> { public func createFetchedResultsControllerFrom(_ from: CSFrom, sectionBy: CSSectionBy, fetchClauses: [CSFetchClause]) -> NSFetchedResultsController<NSManagedObject> {

View File

@@ -77,6 +77,12 @@ public extension NSManagedObject {
return context return context
} }
/**
Provides a convenience wrapper for accessing `primitiveValue(forKey:)` with proper calls to `willAccessValue(forKey:)` and `didAccessValue(forKey:)`. This is useful when implementing accessor methods for transient attributes.
- parameter kvcKey: the KVC key
- returns: the primitive value for the KVC key
*/
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func getValue(forKvcKey kvcKey: KeyPath) -> Any? { public func getValue(forKvcKey kvcKey: KeyPath) -> Any? {
@@ -88,6 +94,13 @@ public extension NSManagedObject {
return self.primitiveValue(forKey: kvcKey) return self.primitiveValue(forKey: kvcKey)
} }
/**
Provides a convenience wrapper for accessing `primitiveValue(forKey:)` with proper calls to `willAccessValue(forKey:)` and `didAccessValue(forKey:)`. This is useful when implementing accessor methods for transient attributes.
- parameter kvcKey: the KVC key
- parameter didGetValue: a closure to transform the primitive value
- returns: the primitive value transformed by the `didGetValue` closure
*/
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func getValue<T>(forKvcKey kvcKey: KeyPath, didGetValue: (Any?) throws -> T) rethrows -> T { public func getValue<T>(forKvcKey kvcKey: KeyPath, didGetValue: (Any?) throws -> T) rethrows -> T {
@@ -99,6 +112,14 @@ public extension NSManagedObject {
return try didGetValue(self.primitiveValue(forKey: kvcKey)) return try didGetValue(self.primitiveValue(forKey: kvcKey))
} }
/**
Provides a convenience wrapper for accessing `primitiveValue(forKey:)` with proper calls to `willAccessValue(forKey:)` and `didAccessValue(forKey:)`. This is useful when implementing accessor methods for transient attributes.
- parameter kvcKey: the KVC key
- parameter willGetValue: called before accessing `primitiveValue(forKey:)`. Callers are allowed to cancel the access by throwing an error.
- parameter didGetValue: a closure to transform the primitive value
- returns: the primitive value transformed by the `didGetValue` closure
*/
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func getValue<T>(forKvcKey kvcKey: KeyPath, willGetValue: () throws -> Void, didGetValue: (Any?) throws -> T) rethrows -> T { public func getValue<T>(forKvcKey kvcKey: KeyPath, willGetValue: () throws -> Void, didGetValue: (Any?) throws -> T) rethrows -> T {
@@ -111,6 +132,12 @@ public extension NSManagedObject {
return try didGetValue(self.primitiveValue(forKey: kvcKey)) return try didGetValue(self.primitiveValue(forKey: kvcKey))
} }
/**
Provides a convenience wrapper for setting `setPrimitiveValue(_:forKey:)` with proper calls to `willChangeValue(forKey:)` and `didChangeValue(forKey:)`. This is useful when implementing mutator methods for transient attributes.
- parameter value: the value to set the KVC key with
- parameter KVCKey: the KVC key
*/
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func setValue(_ value: Any?, forKvcKey KVCKey: KeyPath) { public func setValue(_ value: Any?, forKvcKey KVCKey: KeyPath) {
@@ -122,15 +149,44 @@ public extension NSManagedObject {
self.setPrimitiveValue(value, forKey: KVCKey) self.setPrimitiveValue(value, forKey: KVCKey)
} }
/**
Provides a convenience wrapper for setting `setPrimitiveValue(_:forKey:)` with proper calls to `willChangeValue(forKey:)` and `didChangeValue(forKey:)`.
- parameter value: the value to set the KVC key with
- parameter KVCKey: the KVC key
- parameter didSetValue: called after executing `setPrimitiveValue(forKey:)`.
*/
@nonobjc @inline(__always) @nonobjc @inline(__always)
public func setValue<T>(_ value: T, forKvcKey KVCKey: KeyPath, willSetValue: (T) throws -> Any?) rethrows { public func setValue(_ value: Any?, forKvcKey KVCKey: KeyPath, didSetValue: () -> Void) {
self.willChangeValue(forKey: KVCKey) self.willChangeValue(forKey: KVCKey)
defer { defer {
self.didChangeValue(forKey: KVCKey) self.didChangeValue(forKey: KVCKey)
} }
self.setPrimitiveValue(try willSetValue(value), forKey: KVCKey) self.setPrimitiveValue(value, forKey: KVCKey)
didSetValue()
}
/**
Provides a convenience wrapper for setting `setPrimitiveValue(_:forKey:)` with proper calls to `willChangeValue(forKey:)` and `didChangeValue(forKey:)`. This is useful when implementing mutator methods for transient attributes.
- parameter value: the value to set the KVC key with
- parameter KVCKey: the KVC key
- parameter willSetValue: called before accessing `setPrimitiveValue(forKey:)`. Callers are allowed to cancel the mutation by throwing an error, for example, for custom validations.
- parameter didSetValue: called after executing `setPrimitiveValue(forKey:)`.
*/
@nonobjc @inline(__always)
public func setValue<T>(_ value: T, forKvcKey KVCKey: KeyPath, willSetValue: (T) throws -> Any?, didSetValue: (Any?) -> Void = { _ in }) rethrows {
self.willChangeValue(forKey: KVCKey)
defer {
self.didChangeValue(forKey: KVCKey)
}
let transformedValue = try willSetValue(value)
self.setPrimitiveValue(transformedValue, forKey: KVCKey)
didSetValue(transformedValue)
} }
/** /**
@@ -154,13 +210,7 @@ public extension NSManagedObject {
// MARK: Deprecated // MARK: Deprecated
/** @available(*, deprecated, renamed: "getValue(forKvcKey:)")
Provides a convenience wrapper for accessing `primitiveValueForKey(...)` with proper calls to `willAccessValueForKey(...)` and `didAccessValueForKey(...)`. This is useful when implementing accessor methods for transient attributes.
- parameter KVCKey: the KVC key
- returns: the primitive value for the KVC key
*/
@available(*, deprecated: 3.1, renamed: "getValue(forKvcKey:)")
@nonobjc @nonobjc
public func accessValueForKVCKey(_ KVCKey: KeyPath) -> Any? { public func accessValueForKVCKey(_ KVCKey: KeyPath) -> Any? {
@@ -172,14 +222,7 @@ public extension NSManagedObject {
return self.primitiveValue(forKey: KVCKey) return self.primitiveValue(forKey: KVCKey)
} }
/** @available(*, deprecated, renamed: "getValue(forKvcKey:didGetValue:)")
Provides a convenience wrapper for accessing `primitiveValueForKey(...)` with proper calls to `willAccessValueForKey(...)` and `didAccessValueForKey(...)`. This is useful when implementing accessor methods for transient attributes.
- parameter KVCKey: the KVC key
- parameter didAccessPrimitiveValue: the closure to access the value. This is called between `willAccessValueForKey(...)` and `didAccessValueForKey(...)`
- returns: the primitive value for the KVC key
*/
@available(*, deprecated: 3.1, renamed: "getValue(forKvcKey:didGetValue:)")
@discardableResult @discardableResult
@nonobjc @nonobjc
public func accessValueForKVCKey<T>(_ KVCKey: KeyPath, _ didAccessPrimitiveValue: (Any?) throws -> T) rethrows -> T { public func accessValueForKVCKey<T>(_ KVCKey: KeyPath, _ didAccessPrimitiveValue: (Any?) throws -> T) rethrows -> T {
@@ -192,13 +235,7 @@ public extension NSManagedObject {
return try didAccessPrimitiveValue(self.primitiveValue(forKey: KVCKey)) return try didAccessPrimitiveValue(self.primitiveValue(forKey: KVCKey))
} }
/** @available(*, deprecated, renamed: "setValue(_:forKvcKey:)")
Provides a convenience wrapper for setting `setPrimitiveValue(...)` with proper calls to `willChangeValueForKey(...)` and `didChangeValueForKey(...)`. This is useful when implementing mutator methods for transient attributes.
- parameter value: the value to set the KVC key with
- parameter KVCKey: the KVC key
*/
@available(*, deprecated: 3.1, renamed: "setValue(_:forKvcKey:)")
@nonobjc @nonobjc
public func setValue(_ value: Any?, forKVCKey KVCKey: KeyPath) { public func setValue(_ value: Any?, forKVCKey KVCKey: KeyPath) {
@@ -210,14 +247,7 @@ public extension NSManagedObject {
self.setPrimitiveValue(value, forKey: KVCKey) self.setPrimitiveValue(value, forKey: KVCKey)
} }
/** @available(*, deprecated, renamed: "setValue(_:forKvcKey:didSetValue:)")
Provides a convenience wrapper for setting `setPrimitiveValue(...)` with proper calls to `willChangeValueForKey(...)` and `didChangeValueForKey(...)`. This is useful when implementing mutator methods for transient attributes.
- parameter value: the value to set the KVC key with
- parameter KVCKey: the KVC key
- parameter didSetPrimitiveValue: the closure called between `willChangeValueForKey(...)` and `didChangeValueForKey(...)`
*/
@available(*, deprecated: 3.1, renamed: "setValue(_:forKvcKey:didSetValue:)")
@discardableResult @discardableResult
@nonobjc @nonobjc
public func setValue<T>(_ value: Any?, forKVCKey KVCKey: KeyPath, _ didSetPrimitiveValue: (Any?) throws -> T) rethrows -> T { public func setValue<T>(_ value: Any?, forKVCKey KVCKey: KeyPath, _ didSetPrimitiveValue: (Any?) throws -> T) rethrows -> T {

View File

@@ -38,9 +38,9 @@ public extension NSManagedObject {
- returns: the primitive value for the KVC key - returns: the primitive value for the KVC key
*/ */
@objc @objc
public func cs_accessValueForKVCKey(_ kvcKey: KeyPath) -> Any? { public func cs_accessValueForKVCKey(_ KVCKey: KeyPath) -> Any? {
return self.getValue(forKvcKey: kvcKey) return self.getValue(forKvcKey: KVCKey)
} }
/** /**

View File

@@ -91,7 +91,7 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
@nonobjc @nonobjc
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T { public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return objects.flatMap({ self.fetchExisting($0.cs_toRaw().objectID) }) return objects.flatMap({ self.fetchExisting($0.cs_id()) })
} }
@nonobjc @nonobjc

View File

@@ -30,7 +30,7 @@ import CoreData
// MARK: - ObjectMonitor // MARK: - ObjectMonitor
/** /**
The `ObjectMonitor` monitors changes to a single `NSManagedObject` instance. Observers that implement the `ObjectObserver` protocol may then register themselves to the `ObjectMonitor`'s `addObserver(_:)` method: The `ObjectMonitor` monitors changes to a single `DynamicObject` instance. Observers that implement the `ObjectObserver` protocol may then register themselves to the `ObjectMonitor`'s `addObserver(_:)` method:
``` ```
let monitor = CoreStore.monitorObject(object) let monitor = CoreStore.monitorObject(object)
monitor.addObserver(self) monitor.addObserver(self)
@@ -48,7 +48,7 @@ public final class ObjectMonitor<D: DynamicObject>: Equatable {
public typealias ObjectType = D public typealias ObjectType = D
/** /**
Returns the `NSManagedObject` instance being observed, or `nil` if the object was already deleted. Returns the `DynamicObject` instance being observed, or `nil` if the object was already deleted.
*/ */
public var object: ObjectType? { public var object: ObjectType? {
@@ -59,7 +59,7 @@ public final class ObjectMonitor<D: DynamicObject>: Equatable {
} }
/** /**
Returns `true` if the `NSManagedObject` instance being observed still exists, or `false` if the object was already deleted. Returns `true` if the `DynamicObject` instance being observed still exists, or `false` if the object was already deleted.
*/ */
public var isObjectDeleted: Bool { public var isObjectDeleted: Bool {
@@ -122,7 +122,7 @@ public final class ObjectMonitor<D: DynamicObject>: Equatable {
``` ```
- Important: Do not use this method to store thread-sensitive data. - Important: Do not use this method to store thread-sensitive data.
*/ */
private let userInfo = UserInfo() public let userInfo = UserInfo()
// MARK: Equatable // MARK: Equatable
@@ -260,16 +260,15 @@ public final class ObjectMonitor<D: DynamicObject>: Equatable {
private init(context: NSManagedObjectContext, object: ObjectType) { private init(context: NSManagedObjectContext, object: ObjectType) {
let rawObject = object.cs_toRaw() let objectID = object.cs_id()
let fetchRequest = CoreStoreFetchRequest() let fetchRequest = CoreStoreFetchRequest()
fetchRequest.entity = rawObject.entity fetchRequest.entity = objectID.entity
fetchRequest.fetchLimit = 0 fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType fetchRequest.resultType = .managedObjectResultType
fetchRequest.sortDescriptors = [] fetchRequest.sortDescriptors = []
fetchRequest.includesPendingChanges = false fetchRequest.includesPendingChanges = false
fetchRequest.shouldRefreshRefetchedObjects = true fetchRequest.shouldRefreshRefetchedObjects = true
let objectID = rawObject.objectID
let fetchedResultsController = CoreStoreFetchedResultsController( let fetchedResultsController = CoreStoreFetchedResultsController(
context: context, context: context,
fetchRequest: fetchRequest.dynamicCast(), fetchRequest: fetchRequest.dynamicCast(),

View File

@@ -30,7 +30,7 @@ import CoreData
// MARK: - ObjectObserver // MARK: - ObjectObserver
/** /**
Implement the `ObjectObserver` protocol to observe changes to a single `NSManagedObject` instance. `ObjectObserver`s may register themselves to a `ObjectMonitor`'s `addObserver(_:)` method: Implement the `ObjectObserver` protocol to observe changes to a single `DynamicObject` instance. `ObjectObserver`s may register themselves to a `ObjectMonitor`'s `addObserver(_:)` method:
``` ```
let monitor = CoreStore.monitorObject(object) let monitor = CoreStore.monitorObject(object)
monitor.addObserver(self) monitor.addObserver(self)
@@ -40,7 +40,7 @@ import CoreData
public protocol ObjectObserver: class { public protocol ObjectObserver: class {
/** /**
The `NSManagedObject` type for the observed object The `DynamicObject` type for the observed object
*/ */
associatedtype ObjectEntityType: DynamicObject associatedtype ObjectEntityType: DynamicObject
@@ -49,7 +49,7 @@ public protocol ObjectObserver: class {
The default implementation does nothing. The default implementation does nothing.
- parameter monitor: the `ObjectMonitor` monitoring the object being observed - parameter monitor: the `ObjectMonitor` monitoring the object being observed
- parameter object: the `NSManagedObject` instance being observed - parameter object: the `DynamicObject` instance being observed
*/ */
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, willUpdateObject object: ObjectEntityType) func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, willUpdateObject object: ObjectEntityType)
@@ -58,7 +58,7 @@ public protocol ObjectObserver: class {
The default implementation does nothing. The default implementation does nothing.
- parameter monitor: the `ObjectMonitor` monitoring the object being observed - parameter monitor: the `ObjectMonitor` monitoring the object being observed
- parameter object: the `NSManagedObject` instance being observed - parameter object: the `DynamicObject` instance being observed
- parameter changedPersistentKeys: a `Set` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported. - parameter changedPersistentKeys: a `Set` of key paths for the attributes that were changed. Note that `changedPersistentKeys` only contains keys for attributes/relationships present in the persistent store, thus transient properties will not be reported.
*/ */
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<KeyPath>) func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didUpdateObject object: ObjectEntityType, changedPersistentKeys: Set<KeyPath>)
@@ -68,7 +68,7 @@ public protocol ObjectObserver: class {
The default implementation does nothing. The default implementation does nothing.
- parameter monitor: the `ObjectMonitor` monitoring the object being observed - parameter monitor: the `ObjectMonitor` monitoring the object being observed
- parameter object: the `NSManagedObject` instance being observed - parameter object: the `DynamicObject` instance being observed
*/ */
func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didDeleteObject object: ObjectEntityType) func objectMonitor(_ monitor: ObjectMonitor<ObjectEntityType>, didDeleteObject object: ObjectEntityType)
} }

View File

@@ -30,15 +30,56 @@ import CoreGraphics
// MARK: - QueryableAttributeType // MARK: - QueryableAttributeType
/**
Types supported by CoreStore for querying, especially as generic type for `Select` clauses.
Supported default types:
- `Bool`
- `CGFloat`
- `Data`
- `Date`
- `Double`
- `Float`
- `Int`
- `Int8`
- `Int16`
- `Int32`
- `Int64`
- `NSData`
- `NSDate`
- `NSDecimalNumber`
- `NSManagedObjectID`
- `NSNull`
- `NSNumber`
- `NSString`
- `NSURL`
- `NSUUID`
- `String`
- `URL`
- `UUID`
In addition, `RawRepresentable` types whose `RawValue` already implements `QueryableAttributeType` only need to declare conformance to `QueryableAttributeType`.
*/
public protocol QueryableAttributeType: Hashable, SelectResultType { public protocol QueryableAttributeType: Hashable, SelectResultType {
/**
The `CoreDataNativeType` for this type when used in `Select` clauses.
*/
associatedtype QueryableNativeType: CoreDataNativeType associatedtype QueryableNativeType: CoreDataNativeType
/**
The `NSAttributeType` for this type when used in `Select` clauses.
*/
static var cs_rawAttributeType: NSAttributeType { get } static var cs_rawAttributeType: NSAttributeType { get }
/**
Creates an instance of this type from its `QueryableNativeType` value.
*/
@inline(__always) @inline(__always)
static func cs_fromQueryableNativeType(_ value: QueryableNativeType) -> Self? static func cs_fromQueryableNativeType(_ value: QueryableNativeType) -> Self?
/**
Creates `QueryableNativeType` value from this instance.
*/
@inline(__always) @inline(__always)
func cs_toQueryableNativeType() -> QueryableNativeType func cs_toQueryableNativeType() -> QueryableNativeType
} }
@@ -574,3 +615,28 @@ extension UUID: QueryableAttributeType {
return self.uuidString.lowercased() as QueryableNativeType return self.uuidString.lowercased() as QueryableNativeType
} }
} }
// MARK: - RawRepresentable
extension RawRepresentable where RawValue: QueryableAttributeType {
public typealias QueryableNativeType = RawValue.QueryableNativeType
public static var cs_rawAttributeType: NSAttributeType {
return RawValue.cs_rawAttributeType
}
@inline(__always)
public static func cs_fromQueryableNativeType(_ value: QueryableNativeType) -> Self? {
return RawValue.cs_fromQueryableNativeType(value).flatMap({ self.init(rawValue: $0) })
}
@inline(__always)
public func cs_toQueryableNativeType() -> QueryableNativeType {
return self.rawValue.cs_toQueryableNativeType()
}
}

View File

@@ -86,10 +86,4 @@ public protocol QueryableSource: class {
The internal `NSManagedObjectContext` managed by this `QueryableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases. The internal `NSManagedObjectContext` managed by this `QueryableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/ */
func unsafeContext() -> NSManagedObjectContext func unsafeContext() -> NSManagedObjectContext
// MARK: Deprecated
@available(*, deprecated, renamed: "unsafeContext()")
func internalContext() -> NSManagedObjectContext
} }

View File

@@ -31,68 +31,148 @@ import Foundation
public extension DynamicObject where Self: CoreStoreObject { public extension DynamicObject where Self: CoreStoreObject {
/**
The containing type for relationships. `Relationship`s can be any `CoreStoreObject` subclass.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
- Important: `Relationship` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/
public typealias Relationship = RelationshipContainer<Self> public typealias Relationship = RelationshipContainer<Self>
} }
// MARK: - RelationshipContainer // MARK: - RelationshipContainer
/**
The containing type for relationships. Use the `DynamicObject.Relationship` typealias instead for shorter syntax.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
*/
public enum RelationshipContainer<O: CoreStoreObject> { public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: - ToOne // MARK: - ToOne
/**
The containing type for to-one relationships. Any `CoreStoreObject` subclass can be a destination type. Inverse relationships should be declared from the destination type as well, using the `inverse:` argument for the relationship.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
- Important: `Relationship.ToOne` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/
public final class ToOne<D: CoreStoreObject>: RelationshipProtocol { public final class ToOne<D: CoreStoreObject>: RelationshipProtocol {
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
The relationship destination object.
*/
public var value: D? { public var value: D? {
get { get {
let object = self.parentObject() as! O return self.nativeValue.flatMap(D.cs_fromRaw)
CoreStore.assert(
object.rawObject!.isRunningInAllowedQueue() == true,
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
)
return object.rawObject!.getValue(
forKvcKey: self.keyPath,
didGetValue: { $0.flatMap({ D.cs_fromRaw(object: $0 as! NSManagedObject) }) }
)
} }
set { set {
let object = self.parentObject() as! O self.nativeValue = newValue?.rawObject
CoreStore.assert(
object.rawObject!.isRunningInAllowedQueue() == true,
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
)
CoreStore.assert(
object.rawObject!.isEditableInContext() == true,
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
)
object.rawObject!.setValue(
newValue,
forKvcKey: self.keyPath,
willSetValue: { $0?.rawObject }
)
} }
} }
@@ -115,6 +195,38 @@ public enum RelationshipContainer<O: CoreStoreObject> {
CoreStore.abort("Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types.") CoreStore.abort("Attempted to access values from a \(cs_typeName(O.self)) meta object. Meta objects are only used for querying keyPaths and infering types.")
} }
internal var nativeValue: NSManagedObject? {
get {
let object = self.parentObject() as! O
CoreStore.assert(
object.rawObject!.isRunningInAllowedQueue() == true,
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
)
return object.rawObject!.getValue(
forKvcKey: self.keyPath,
didGetValue: { $0 as! NSManagedObject? }
)
}
set {
let object = self.parentObject() as! O
CoreStore.assert(
object.rawObject!.isRunningInAllowedQueue() == true,
"Attempted to access \(cs_typeName(O.self))'s value outside it's designated queue."
)
CoreStore.assert(
object.rawObject!.isEditableInContext() == true,
"Attempted to update a \(cs_typeName(O.self))'s value from outside a transaction."
)
object.rawObject!.setValue(
newValue,
forKvcKey: self.keyPath
)
}
}
// MARK: Private // MARK: Private
@@ -131,28 +243,114 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: - ToManyOrdered // MARK: - ToManyOrdered
/**
The containing type for to-many ordered relationships. Any `CoreStoreObject` subclass can be a destination type. Inverse relationships should be declared from the destination type as well, using the `inverse:` argument for the relationship.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- Important: `Relationship.ToManyOrdered` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/
public final class ToManyOrdered<D: CoreStoreObject>: RelationshipProtocol { public final class ToManyOrdered<D: CoreStoreObject>: RelationshipProtocol {
public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { /**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, minCount: Int = 0, maxCount: Int = 0, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, minCount: minCount, maxCount: maxCount, inverseKeyPath: { nil }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { /**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, minCount: Int = 0, maxCount: Int = 0, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, minCount: minCount, maxCount: maxCount, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { /**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, minCount: Int = 0, maxCount: Int = 0, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, minCount: minCount, maxCount: maxCount, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { /**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, minCount: Int = 0, maxCount: Int = 0, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, minCount: minCount, maxCount: maxCount, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
The relationship ordered objects.
*/
public var value: [D] { public var value: [D] {
get { get {
@@ -220,7 +418,7 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: Private // MARK: Private
private init(keyPath: String, inverseKeyPath: @escaping () -> String?, deleteRule: DeleteRule, minCount: Int, maxCount: Int, versionHashModifier: String?, renamingIdentifier: String?) { private init(keyPath: String, minCount: Int, maxCount: Int, inverseKeyPath: @escaping () -> String?, deleteRule: DeleteRule, versionHashModifier: String?, renamingIdentifier: String?) {
self.keyPath = keyPath self.keyPath = keyPath
self.deleteRule = deleteRule.nativeValue self.deleteRule = deleteRule.nativeValue
@@ -237,28 +435,115 @@ public enum RelationshipContainer<O: CoreStoreObject> {
// MARK: - ToManyUnordered // MARK: - ToManyUnordered
/**
The containing type for to-many unordered relationships. Any `CoreStoreObject` subclass can be a destination type. Inverse relationships should be declared from the destination type as well, using the `inverse:` argument for the relationship.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
}
```
- Important: `Relationship.ToManyUnordered` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/
public final class ToManyUnordered<D: CoreStoreObject>: RelationshipProtocol { public final class ToManyUnordered<D: CoreStoreObject>: RelationshipProtocol {
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { nil }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToOne<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyOrdered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
Initializes the metadata for the relationship. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object. Make sure to declare this relationship's inverse relationship on its destination object. Due to Swift's compiler limitation, only one of the relationship and its inverse can declare an `inverse:` argument.
```
class Dog: CoreStoreObject {
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let pets = Relationship.ToManyOrdered<Dog>("pets", inverse: { $0.master })
}
```
- parameter keyPath: the permanent name for this relationship.
- parameter minCount: the minimum number of objects in this relationship UNLESS THE RELATIONSHIP IS EMPTY. This means there might be zero objects in the relationship, which might be less than `minCount`. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter maxCount: the maximum number of objects in this relationship. If the number of objects in the relationship do not satisfy `minCount` and `maxCount`, the transaction's commit (or auto-commit) would fail with a validation error.
- parameter inverse: the inverse relationship that is declared for the destination object. All relationships require an "inverse", so updates to to this object's relationship are also reflected on its destination object.
- parameter deleteRule: defines what happens to relationship when an object is deleted. Valid values are `.nullify`, `.cascade`, and `.delete`. Defaults to `.nullify`.
- parameter versionHashModifier: used to mark or denote a relationship as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
*/
public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) { public convenience init(_ keyPath: KeyPath, inverse: @escaping (D) -> RelationshipContainer<D>.ToManyUnordered<O>, deleteRule: DeleteRule = .nullify, minCount: Int = 0, maxCount: Int = 0, versionHashModifier: String? = nil, renamingIdentifier: String? = nil) {
self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier) self.init(keyPath: keyPath, inverseKeyPath: { inverse(D.meta).keyPath }, deleteRule: deleteRule, minCount: minCount, maxCount: maxCount, versionHashModifier: versionHashModifier, renamingIdentifier: renamingIdentifier)
} }
/**
The relationship unordered objects.
*/
public var value: Set<D> { public var value: Set<D> {
get { get {
@@ -404,11 +689,17 @@ extension RelationshipContainer.ToManyOrdered: RandomAccessCollection {
extension RelationshipContainer.ToManyUnordered: Sequence { extension RelationshipContainer.ToManyUnordered: Sequence {
/**
The number of elements in the set.
*/
public var count: Int { public var count: Int {
return self.nativeValue.count return self.nativeValue.count
} }
/**
A Boolean value indicating whether the range contains no elements.
*/
public var isEmpty: Bool { public var isEmpty: Bool {
return self.nativeValue.count == 0 return self.nativeValue.count == 0
@@ -434,44 +725,124 @@ infix operator .== : ComparisonPrecedence
extension RelationshipContainer.ToOne { extension RelationshipContainer.ToOne {
public static func .= (_ relationship: RelationshipContainer<O>.ToOne<D>, _ newValue: D?) { /**
Assigns an object to the relationship. The operation
```
dog.master .= person
```
is equivalent to
```
dog.master.value = person
```
*/
public static func .= (_ relationship: RelationshipContainer<O>.ToOne<D>, _ newObject: D?) {
relationship.value = newValue relationship.nativeValue = newObject?.cs_toRaw()
} }
/**
Assigns an object from another relationship. The operation
```
dog.master .= anotherDog.master
```
is equivalent to
```
dog.master.value = anotherDog.master.value
```
*/
public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToOne<D>, _ relationship2: RelationshipContainer<O2>.ToOne<D>) { public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToOne<D>, _ relationship2: RelationshipContainer<O2>.ToOne<D>) {
relationship.value = relationship2.value relationship.nativeValue = relationship2.nativeValue
} }
public static func .== (_ relationship: RelationshipContainer<O>.ToOne<D>, _ value: D?) -> Bool { /**
Compares equality between a relationship's object and another object
```
if dog.master .== person { ... }
```
is equivalent to
```
if dog.master.value == person { ... }
```
*/
public static func .== (_ relationship: RelationshipContainer<O>.ToOne<D>, _ object: D?) -> Bool {
return relationship.value == value return relationship.nativeValue == object?.cs_toRaw()
} }
public static func .== (_ value: D?, _ relationship: RelationshipContainer<O>.ToOne<D>) -> Bool { /**
Compares equality between an object and a relationship's object
```
if dog.master .== person { ... }
```
is equivalent to
```
if dog.master.value == person { ... }
```
*/
public static func .== (_ object: D?, _ relationship: RelationshipContainer<O>.ToOne<D>) -> Bool {
return value == relationship.value return object?.cs_toRaw() == relationship.nativeValue
} }
/**
Compares equality between a relationship's object and another relationship's object
```
if dog.master .== person { ... }
```
is equivalent to
```
if dog.master.value == person { ... }
```
*/
public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToOne<D>, _ relationship2: RelationshipContainer<O2>.ToOne<D>) -> Bool { public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToOne<D>, _ relationship2: RelationshipContainer<O2>.ToOne<D>) -> Bool {
return relationship.value == relationship2.value return relationship.nativeValue == relationship2.nativeValue
} }
} }
extension RelationshipContainer.ToManyOrdered { extension RelationshipContainer.ToManyOrdered {
/**
Assigns a sequence of objects to the relationship. The operation
```
person.pets .= [dog, cat]
```
is equivalent to
```
person.pets.value = [dog, cat]
```
*/
public static func .= <S: Sequence>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ newValue: S) where S.Iterator.Element == D { public static func .= <S: Sequence>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ newValue: S) where S.Iterator.Element == D {
relationship.nativeValue = NSOrderedSet(array: newValue.map({ $0.rawObject! })) relationship.nativeValue = NSOrderedSet(array: newValue.map({ $0.rawObject! }))
} }
/**
Assigns a sequence of objects to the relationship. The operation
```
person.pets .= anotherPerson.pets
```
is equivalent to
```
person.pets.value = anotherPerson.pets.value
```
*/
public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ relationship2: RelationshipContainer<O2>.ToManyOrdered<D>) { public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ relationship2: RelationshipContainer<O2>.ToManyOrdered<D>) {
relationship.nativeValue = relationship2.nativeValue relationship.nativeValue = relationship2.nativeValue
} }
/**
Compares equality between a relationship's objects and a collection of objects
```
if person.pets .== [dog, cat] { ... }
```
is equivalent to
```
if person.pets.value == [dog, cat] { ... }
```
*/
public static func .== <C: Collection>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ collection: C) -> Bool where C.Iterator.Element == D { public static func .== <C: Collection>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ collection: C) -> Bool where C.Iterator.Element == D {
return relationship.nativeValue.elementsEqual( return relationship.nativeValue.elementsEqual(
@@ -480,6 +851,16 @@ extension RelationshipContainer.ToManyOrdered {
) )
} }
/**
Compares equality between a collection of objects and a relationship's objects
```
if [dog, cat] .== person.pets { ... }
```
is equivalent to
```
if [dog, cat] == person.pets.value { ... }
```
*/
public static func .== <C: Collection>(_ collection: C, _ relationship: RelationshipContainer<O>.ToManyOrdered<D>) -> Bool where C.Iterator.Element == D { public static func .== <C: Collection>(_ collection: C, _ relationship: RelationshipContainer<O>.ToManyOrdered<D>) -> Bool where C.Iterator.Element == D {
return relationship.nativeValue.elementsEqual( return relationship.nativeValue.elementsEqual(
@@ -488,6 +869,16 @@ extension RelationshipContainer.ToManyOrdered {
) )
} }
/**
Compares equality between a relationship's objects and a collection of objects
```
if person.pets .== anotherPerson.pets { ... }
```
is equivalent to
```
if person.pets.value == anotherPerson.pets.value { ... }
```
*/
public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ relationship2: RelationshipContainer<O2>.ToManyOrdered<D>) -> Bool { public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ relationship2: RelationshipContainer<O2>.ToManyOrdered<D>) -> Bool {
return relationship.nativeValue == relationship2.nativeValue return relationship.nativeValue == relationship2.nativeValue
@@ -496,44 +887,94 @@ extension RelationshipContainer.ToManyOrdered {
extension RelationshipContainer.ToManyUnordered { extension RelationshipContainer.ToManyUnordered {
/**
Assigns a sequence of objects to the relationship. The operation
```
person.pets .= [dog, cat]
```
is equivalent to
```
person.pets.value = [dog, cat]
```
*/
public static func .= <S: Sequence>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ newValue: S) where S.Iterator.Element == D { public static func .= <S: Sequence>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ newValue: S) where S.Iterator.Element == D {
relationship.nativeValue = NSSet(array: newValue.map({ $0.rawObject! })) relationship.nativeValue = NSSet(array: newValue.map({ $0.rawObject! }))
} }
/**
Assigns a sequence of objects to the relationship. The operation
```
person.pets .= anotherPerson.pets
```
is equivalent to
```
person.pets.value = anotherPerson.pets.value
```
*/
public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ relationship2: RelationshipContainer<O2>.ToManyUnordered<D>) { public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ relationship2: RelationshipContainer<O2>.ToManyUnordered<D>) {
relationship.nativeValue = relationship2.nativeValue relationship.nativeValue = relationship2.nativeValue
} }
/**
Assigns a sequence of objects to the relationship. The operation
```
person.pets .= anotherPerson.pets
```
is equivalent to
```
person.pets.value = anotherPerson.pets.value
```
*/
public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ relationship2: RelationshipContainer<O2>.ToManyOrdered<D>) { public static func .= <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ relationship2: RelationshipContainer<O2>.ToManyOrdered<D>) {
relationship.nativeValue = NSSet(set: relationship2.nativeValue.set) relationship.nativeValue = NSSet(set: relationship2.nativeValue.set)
} }
public static func .== <S: Sequence>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ sequence: S) -> Bool where S.Iterator.Element == D { /**
Compares the if the relationship's objects and a set of objects have the same elements.
```
if person.pets .== Set<Animal>([dog, cat]) { ... }
```
is equivalent to
```
if person.pets.value == Set<Animal>([dog, cat]) { ... }
```
*/
public static func .== (_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ set: Set<D>) -> Bool {
return relationship.nativeValue.isEqual(to: Set(sequence.map({ $0.rawObject! }))) return relationship.nativeValue.isEqual(to: Set(set.map({ $0.rawObject! })))
} }
public static func .== <S: Sequence>(_ sequence: S, _ relationship: RelationshipContainer<O>.ToManyUnordered<D>) -> Bool where S.Iterator.Element == D { /**
Compares if a set of objects and a relationship's objects have the same elements.
```
if Set<Animal>([dog, cat]) .== person.pets { ... }
```
is equivalent to
```
if Set<Animal>([dog, cat]) == person.pets.value { ... }
```
*/
public static func .== (_ set: Set<D>, _ relationship: RelationshipContainer<O>.ToManyUnordered<D>) -> Bool {
return relationship.nativeValue.isEqual(to: Set(sequence.map({ $0.rawObject! }))) return relationship.nativeValue.isEqual(to: Set(set.map({ $0.rawObject! })))
} }
/**
Compares if a relationship's objects and another relationship's objects have the same elements.
```
if person.pets .== anotherPerson.pets { ... }
```
is equivalent to
```
if person.pets.value == anotherPerson.pets.value { ... }
```
*/
public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ relationship2: RelationshipContainer<O2>.ToManyUnordered<D>) -> Bool { public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ relationship2: RelationshipContainer<O2>.ToManyUnordered<D>) -> Bool {
return relationship.nativeValue == relationship2.nativeValue return relationship.nativeValue.isEqual(relationship2.nativeValue)
}
public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyUnordered<D>, _ relationship2: RelationshipContainer<O2>.ToManyOrdered<D>) -> Bool {
return relationship.nativeValue == NSSet(set: relationship2.nativeValue.set)
}
public static func .== <O2: CoreStoreObject>(_ relationship: RelationshipContainer<O>.ToManyOrdered<D>, _ relationship2: RelationshipContainer<O2>.ToManyUnordered<D>) -> Bool {
return NSSet(set: relationship.nativeValue.set) == relationship2.nativeValue
} }
} }

View File

@@ -31,7 +31,7 @@ import CoreData
/** /**
A storage interface that is backed by an SQLite database. A storage interface that is backed by an SQLite database.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`. - Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use the `SQLiteStore.legacy(...)` factory methods to create the `SQLiteStore` instead of using initializers directly.
*/ */
public final class SQLiteStore: LocalStorage { public final class SQLiteStore: LocalStorage {
@@ -40,8 +40,8 @@ public final class SQLiteStore: LocalStorage {
- parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them. - parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them. - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter migrationMappingProviders: An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array. - parameter migrationMappingProviders: an array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. - parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.none`.
*/ */
public init(fileURL: URL, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) { public init(fileURL: URL, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) {
@@ -54,10 +54,10 @@ public final class SQLiteStore: LocalStorage {
/** /**
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist. Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`. - Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use the `SQLiteStore.legacy(...)` factory methods to create the `SQLiteStore` instead of using initializers directly.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them. - parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them. - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter migrationMappingProviders: An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array. - parameter migrationMappingProviders: an array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. - parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/ */
public init(fileName: String, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) { public init(fileName: String, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) {
@@ -70,9 +70,9 @@ public final class SQLiteStore: LocalStorage {
} }
/** /**
Initializes an `SQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `.AllowProgresiveMigration`. Initializes an `SQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `migrationMappingProviders` set to empty, and `localStorageOptions` set to `.AllowProgresiveMigration`.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`. - Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use the `SQLiteStore.legacy(...)` factory methods to create the `SQLiteStore` instead of using initializers directly.
*/ */
public init() { public init() {
@@ -85,10 +85,10 @@ public final class SQLiteStore: LocalStorage {
/** /**
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist. Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`. - Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use the `SQLiteStore.legacy(...)` factory methods to create the `SQLiteStore` instead of using initializers directly.
- parameter legacyFileName: the local filename for the SQLite persistent store in the "Application Support" directory (or the "Caches" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them. - parameter legacyFileName: the local filename for the SQLite persistent store in the "Application Support" directory (or the "Caches" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them. - parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter migrationMappingProviders: An array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array. - parameter migrationMappingProviders: an array of `SchemaMappingProviders` that provides the complete mapping models for custom migrations. All lightweight inferred mappings and/or migration mappings provided by *xcmappingmodel files are automatically used as fallback (as `InferredSchemaMappingProvider`) and may be omitted from the array.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`. - parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/ */
public static func legacy(fileName: String, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) -> SQLiteStore { public static func legacy(fileName: String, configuration: ModelConfiguration = nil, migrationMappingProviders: [SchemaMappingProvider] = [], localStorageOptions: LocalStorageOptions = nil) -> SQLiteStore {
@@ -103,9 +103,9 @@ public final class SQLiteStore: LocalStorage {
} }
/** /**
Initializes an `LegacySQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support" directory (or the "Caches" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `mappingModelBundles` set to search all `NSBundle`s, and `localStorageOptions` set to `.AllowProgresiveMigration`. Initializes an `LegacySQLiteStore` with an all-default settings: a `fileURL` pointing to a "<Application name>.sqlite" file in the "Application Support" directory (or the "Caches" directory on tvOS), a `nil` `configuration` pertaining to the "Default" configuration, a `migrationMappingProviders` set to empty, and `localStorageOptions` set to `.AllowProgresiveMigration`.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`. - Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use the `SQLiteStore.legacy(...)` factory methods to create the `SQLiteStore` instead of using initializers directly.
*/ */
public static func legacy() -> SQLiteStore { public static func legacy() -> SQLiteStore {
@@ -141,7 +141,7 @@ public final class SQLiteStore: LocalStorage {
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
public func didAddToDataStack(_ dataStack: DataStack) { public func cs_didAddToDataStack(_ dataStack: DataStack) {
self.dataStack = dataStack self.dataStack = dataStack
} }
@@ -149,7 +149,7 @@ public final class SQLiteStore: LocalStorage {
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
public func didRemoveFromDataStack(_ dataStack: DataStack) { public func cs_didRemoveFromDataStack(_ dataStack: DataStack) {
self.dataStack = nil self.dataStack = nil
} }
@@ -194,7 +194,7 @@ public final class SQLiteStore: LocalStorage {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
public func eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws { public func cs_eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws {
// TODO: check if attached to persistent store // TODO: check if attached to persistent store
@@ -313,34 +313,17 @@ public final class SQLiteStore: LocalStorage {
private weak var dataStack: DataStack? private weak var dataStack: DataStack?
// MARK: Deprecated // MARK: Obsoleted
/** @available(*, obsoleted: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new SQLiteStore.init(fileURL:configuration:migrationMappingProviders:localStorageOptions:) initializer instead.")
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- parameter fileURL: the local file URL for the target SQLite persistent store. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, deprecated: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new SQLiteStore.init(fileURL:configuration:migrationMappingProviders:localStorageOptions:) initializer instead.")
public convenience init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle], localStorageOptions: LocalStorageOptions = nil) { public convenience init(fileURL: URL, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle], localStorageOptions: LocalStorageOptions = nil) {
self.init(fileURL: fileURL, configuration: configuration, migrationMappingProviders: [], localStorageOptions: localStorageOptions) fatalError()
} }
/** @available(*, obsoleted: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new SQLiteStore.init(fileName:configuration:migrationMappingProviders:localStorageOptions:) initializer instead.")
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was depending on CoreStore's default directories prior to 2.0.0, make sure to use `LegacySQLiteStore` instead of `SQLiteStore`.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter mappingModelBundles: a list of `NSBundle`s from which to search mapping models (*.xcmappingmodel) for migration.
- parameter localStorageOptions: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, tells the `DataStack` how to setup the persistent store. Defaults to `.None`.
*/
@available(*, deprecated: 3.1, message: "The `mappingModelBundles` argument of this method is ignored. Use the new SQLiteStore.init(fileName:configuration:migrationMappingProviders:localStorageOptions:) initializer instead.")
public convenience init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle], localStorageOptions: LocalStorageOptions = nil) { public convenience init(fileName: String, configuration: ModelConfiguration = nil, mappingModelBundles: [Bundle], localStorageOptions: LocalStorageOptions = nil) {
self.init(fileName: fileName, configuration: configuration, migrationMappingProviders: [], localStorageOptions: localStorageOptions) fatalError()
} }
} }

View File

@@ -28,52 +28,12 @@ import Foundation
// MARK: - SaveResult // MARK: - SaveResult
/**
The `SaveResult` indicates the result of a `commit(...)` for a transaction.
The `SaveResult` can be treated as a boolean:
```
CoreStore.beginAsynchronous { transaction in
// ...
let result = transaction.commit()
if result {
// succeeded
}
else {
// failed
}
}
```
or as an `enum`, where the resulting associated object can also be inspected:
```
CoreStore.beginAsynchronous { transaction in
// ...
let result = transaction.commit()
switch result {
case .success(let hasChanges):
// hasChanges indicates if there were changes or not
case .failure(let error):
// error is a CoreStoreError enum value
}
}
```
*/
@available(*, deprecated, message: "Use the new DataStack.perform(asynchronous:...) and DataStack.perform(synchronous:...) family of APIs") @available(*, deprecated, message: "Use the new DataStack.perform(asynchronous:...) and DataStack.perform(synchronous:...) family of APIs")
public enum SaveResult: Hashable { public enum SaveResult: Hashable {
/**
`SaveResult.success` indicates that the `commit()` for the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated value `hasChanges` indicates if there were saved changes or not.
*/
case success(hasChanges: Bool) case success(hasChanges: Bool)
/**
`SaveResult.failure` indicates that the `commit()` for the transaction failed. The associated object for this value is a `CoreStoreError` enum value.
*/
case failure(CoreStoreError) case failure(CoreStoreError)
/**
Returns `true` if the result indicates `.success`, `false` if the result is `.failure`.
*/
public var boolValue: Bool { public var boolValue: Bool {
switch self { switch self {

View File

@@ -53,73 +53,16 @@ public final class SchemaHistory: ExpressibleByArrayLiteral {
public let migrationChain: MigrationChain public let migrationChain: MigrationChain
/** /**
Initializes a `SchemaHistory` with all models declared in the specified (.xcdatamodeld) model file. Convenience initializer for a `SchemaHistory` created from a single xcdatamodeld file.
- Important: Use this initializer only if all model versions are either `XcodeDataModelSchema`s or `LegacyXcodeDataModelSchema`s. Do not use this initializer if even one of the model versions is a `CoreStoreSchema`; use the `SchemaHistory.init(allSchema:migrationChain:exactCurrentModelVersion:)` initializer instead. - parameter xcodeDataModeld: a tuple returned from the `XcodeDataModelSchema.from(modelName:bundle:migrationChain:)` method.
- parameter modelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set.
- parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used.
- parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack. - parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
*/ */
public convenience init(modelName: XcodeDataModelFileName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) { public convenience init(_ xcodeDataModeld: (allSchema: [XcodeDataModelSchema], currentModelVersion: ModelVersion), migrationChain: MigrationChain = nil) {
guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else {
// For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model.
let foundModels = bundle
.paths(forResourcesOfType: "momd", inDirectory: nil)
.map({ ($0 as NSString).lastPathComponent })
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle \"\(bundle.bundleIdentifier ?? "<nil>")\". Other model files in bundle: \(foundModels.coreStoreDumpString)")
}
let modelFileURL = URL(fileURLWithPath: modelFilePath)
let versionInfoPlistURL = modelFileURL.appendingPathComponent("VersionInfo.plist", isDirectory: false)
guard let versionInfo = NSDictionary(contentsOf: versionInfoPlistURL),
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel.self)) metadata from path \"\(versionInfoPlistURL)\".")
}
let modelVersions = Set(versionHashes.keys)
let modelVersionHints = migrationChain.leafVersions
let currentModelVersion: String
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String,
modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
currentModelVersion = plistModelVersion
}
else if let resolvedVersion = modelVersions.intersection(modelVersionHints).first {
CoreStore.log(
.warning,
message: "The \(cs_typeName(MigrationChain.self)) leaf versions do not include the model file's current version. Resolving to version \"\(resolvedVersion)\"."
)
currentModelVersion = resolvedVersion
}
else if let resolvedVersion = modelVersions.first ?? modelVersionHints.first {
if !modelVersionHints.isEmpty {
CoreStore.log(
.warning,
message: "The \(cs_typeName(MigrationChain.self)) leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"."
)
}
currentModelVersion = resolvedVersion
}
else {
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
}
var allSchema: [DynamicSchema] = []
for modelVersion in modelVersions {
let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
allSchema.append(XcodeDataModelSchema(modelName: modelVersion, modelVersionFileURL: fileURL))
}
self.init( self.init(
allSchema: allSchema, allSchema: xcodeDataModeld.allSchema,
migrationChain: migrationChain, migrationChain: migrationChain,
exactCurrentModelVersion: currentModelVersion exactCurrentModelVersion: xcodeDataModeld.currentModelVersion
) )
} }

View File

@@ -29,7 +29,13 @@ import Foundation
// MARK: - SchemaMappingProvider // MARK: - SchemaMappingProvider
/**
The `SchemaMappingProvider` provides migration mapping information between two `DynamicSchema` versions.
*/
public protocol SchemaMappingProvider { public protocol SchemaMappingProvider {
func createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) /**
Do not call directly.
*/
func cs_createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType)
} }

View File

@@ -33,7 +33,7 @@ import CoreData
The `SectionBy` clause indicates the key path to use to group the `ListMonitor` objects into sections. An optional closure can also be provided to transform the value into an appropriate section name: The `SectionBy` clause indicates the key path to use to group the `ListMonitor` objects into sections. An optional closure can also be provided to transform the value into an appropriate section name:
``` ```
let monitor = CoreStore.monitorSectionedList( let monitor = CoreStore.monitorSectionedList(
From<MyPersonEntity>(), From<Person>(),
SectionBy("age") { "Age \($0)" }, SectionBy("age") { "Age \($0)" },
OrderBy(.ascending("lastName")) OrderBy(.ascending("lastName"))
) )

View File

@@ -302,22 +302,7 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
Valid return types depend on the query: Valid return types depend on the query:
- for `queryValue(...)` methods: - for `queryValue(...)` methods:
- `Bool` - all types that conform to `QueryableAttributeType` protocol
- `Int8`
- `Int16`
- `Int32`
- `Int64`
- `Double`
- `Float`
- `String`
- `Date`
- `Data`
- `NSNumber`
- `NSString`
- `NSDecimalNumber`
- `NSDate`
- `NSData`
- `NSManagedObjectID`
- for `queryAttributes(...)` methods: - for `queryAttributes(...)` methods:
- `NSDictionary` - `NSDictionary`

View File

@@ -54,12 +54,12 @@ public protocol StorageInterface: class {
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
func didAddToDataStack(_ dataStack: DataStack) func cs_didAddToDataStack(_ dataStack: DataStack)
/** /**
Do not call directly. Used by the `DataStack` internally. Do not call directly. Used by the `DataStack` internally.
*/ */
func didRemoveFromDataStack(_ dataStack: DataStack) func cs_didRemoveFromDataStack(_ dataStack: DataStack)
} }
@@ -127,7 +127,7 @@ public protocol LocalStorage: StorageInterface {
var fileURL: URL { get } var fileURL: URL { get }
/** /**
An array of `SchemaMappingProvider`s that provides the complete mapping models for custom migrations. An array of `SchemaMappingProvider`s that provide the complete mapping models for custom migrations.
*/ */
var migrationMappingProviders: [SchemaMappingProvider] { get } var migrationMappingProviders: [SchemaMappingProvider] { get }
@@ -144,7 +144,7 @@ public protocol LocalStorage: StorageInterface {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting) Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting)
*/ */
func eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws func cs_eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws
} }
internal extension LocalStorage { internal extension LocalStorage {
@@ -228,9 +228,12 @@ public protocol CloudStorage: StorageInterface {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (Cloud stores for example, can set the NSPersistentStoreRemoveUbiquitousMetadataOption option before deleting) Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (Cloud stores for example, can set the NSPersistentStoreRemoveUbiquitousMetadataOption option before deleting)
*/ */
func eraseStorageAndWait(soureModel: NSManagedObjectModel) throws func cs_eraseStorageAndWait(soureModel: NSManagedObjectModel) throws
} }
// MARK: - Internal
internal extension CloudStorage { internal extension CloudStorage {
internal func matchesPersistentStore(_ persistentStore: NSPersistentStore) -> Bool { internal func matchesPersistentStore(_ persistentStore: NSPersistentStore) -> Bool {

View File

@@ -30,7 +30,7 @@ import CoreData
// MARK: - SynchronousDataTransaction // MARK: - SynchronousDataTransaction
/** /**
The `SynchronousDataTransaction` provides an interface for `NSManagedObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.beginSynchronous(_:)`, or from `CoreStore.beginSynchronous(_:)`. The `SynchronousDataTransaction` provides an interface for `DynamicObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.beginSynchronous(_:)`, or from `CoreStore.beginSynchronous(_:)`.
*/ */
public final class SynchronousDataTransaction: BaseDataTransaction { public final class SynchronousDataTransaction: BaseDataTransaction {
@@ -39,7 +39,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
``` ```
try transaction.cancel() try transaction.cancel()
``` ```
- Important: Never use `try?` or `try!` on a `cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error. - Important: Always use plain `try` on a `cancel()` call. Never use `try?` or `try!`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error.
*/ */
public func cancel() throws -> Never { public func cancel() throws -> Never {
@@ -66,10 +66,10 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Returns an editable proxy of a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once. Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` type to be edited - parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T: DynamicObject>(_ object: T?) -> T? { public override func edit<T: DynamicObject>(_ object: T?) -> T? {
@@ -82,11 +82,11 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Returns an editable proxy of the object with the specified `NSManagedObjectID`. This method should not be used after the `commit()` method was already called once. Returns an editable proxy of the object with the specified `NSManagedObjectID`.
- parameter into: an `Into` clause specifying the entity type - parameter into: an `Into` clause specifying the entity type
- parameter objectID: the `NSManagedObjectID` for the object to be edited - parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject`. - returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/ */
public override func edit<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? { public override func edit<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
@@ -99,9 +99,9 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Deletes a specified `NSManagedObject`. This method should not be used after the `commit()` method was already called once. Deletes a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` type to be deleted - parameter object: the `NSManagedObject` or `CoreStoreObject` type to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object: T?) { public override func delete<T: DynamicObject>(_ object: T?) {
@@ -114,11 +114,11 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `DynamicObject`s.
- parameter object1: the `NSManagedObject` to be deleted - parameter object1: the `DynamicObject` to be deleted
- parameter object2: another `NSManagedObject` to be deleted - parameter object2: another `DynamicObject` to be deleted
- parameter objects: other `NSManagedObject`s to be deleted - parameter objects: other `DynamicObject`s to be deleted
*/ */
public override func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) { public override func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) {
@@ -131,9 +131,9 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
} }
/** /**
Deletes the specified `NSManagedObject`s. Deletes the specified `DynamicObject`s.
- parameter objects: the `NSManagedObject`s to be deleted - parameter objects: the `DynamicObject`s to be deleted
*/ */
public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject { public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
@@ -164,12 +164,6 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
// MARK: Deprecated // MARK: Deprecated
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` or `commitAndWait()` method was already called once.
- Important: Unlike `SynchronousDataTransaction.commit()`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks.
- returns: a `SaveResult` containing the success or failure information
*/
@available(*, deprecated, message: "Use the new auto-commit method DataStack.perform(synchronous:waitForAllObservers:)") @available(*, deprecated, message: "Use the new auto-commit method DataStack.perform(synchronous:waitForAllObservers:)")
public func commitAndWait() -> SaveResult { public func commitAndWait() -> SaveResult {
@@ -188,12 +182,6 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
} }
} }
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` or `commitAndWait()` method was already called once.
- Important: Unlike `SynchronousDataTransaction.commitAndWait()`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning.
- returns: a `SaveResult` containing the success or failure information
*/
@available(*, deprecated, message: "Use the new auto-commit method DataStack.perform(synchronous:waitForAllObservers:)") @available(*, deprecated, message: "Use the new auto-commit method DataStack.perform(synchronous:waitForAllObservers:)")
public func commit() -> SaveResult { public func commit() -> SaveResult {
@@ -212,12 +200,6 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
} }
} }
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `commit()` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ") @available(*, deprecated, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ")
@discardableResult @discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? { public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {

View File

@@ -1,5 +1,5 @@
// //
// LegacyXcodeDataModelSchema.swift // UnsafeDataModelSchema.swift
// CoreStore // CoreStore
// //
// Copyright © 2017 John Rommel Estropia // Copyright © 2017 John Rommel Estropia
@@ -27,18 +27,18 @@ import CoreData
import Foundation import Foundation
// MARK: - LegacyXcodeDataModelSchema // MARK: - UnsafeDataModelSchema
/** /**
The `LegacyXcodeDataModelSchema` describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore. The `UnsafeDataModelSchema` describes models loaded directly from an existing `NSManagedObjectModel`. It is not advisable to continue using this model as its metadata are not available to CoreStore.
*/ */
public final class LegacyXcodeDataModelSchema: DynamicSchema { public final class UnsafeDataModelSchema: DynamicSchema {
/** /**
Initializes a `LegacyXcodeDataModelSchema` from an `NSManagedObjectModel`. Initializes a `UnsafeDataModelSchema` from an `NSManagedObjectModel`.
``` ```
CoreStore.defaultStack = DataStack( CoreStore.defaultStack = DataStack(
LegacyXcodeDataModelSchema(modelName: "MyAppV1", model: model) UnsafeDataModelSchema(modelName: "MyAppV1", model: model)
) )
``` ```
- parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension) - parameter modelName: the model version, typically the file name of an *.xcdatamodeld file (without the file extension)

View File

@@ -33,9 +33,9 @@ import CoreData
public extension UnsafeDataTransaction { public extension UnsafeDataTransaction {
/** /**
Creates a `ObjectMonitor` for the specified `NSManagedObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `NSManagedObject`. Creates a `ObjectMonitor` for the specified `DynamicObject`. Multiple `ObjectObserver`s may then register themselves to be notified when changes are made to the `DynamicObject`.
- parameter object: the `NSManagedObject` to observe changes from - parameter object: the `DynamicObject` to observe changes from
- returns: a `ObjectMonitor` that monitors changes to `object` - returns: a `ObjectMonitor` that monitors changes to `object`
*/ */
public func monitorObject<T: DynamicObject>(_ object: T) -> ObjectMonitor<T> { public func monitorObject<T: DynamicObject>(_ object: T) -> ObjectMonitor<T> {
@@ -47,7 +47,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -59,7 +59,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses. - parameter fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
@@ -84,7 +84,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -96,7 +96,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Asynchronously creates a `ListMonitor` for a list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -122,7 +122,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
@@ -135,7 +135,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list.
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
- parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections. - parameter sectionBy: a `SectionBy` clause indicating the keyPath for the attribute to use when sorting the list into sections.
@@ -161,7 +161,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type
@@ -174,7 +174,7 @@ public extension UnsafeDataTransaction {
} }
/** /**
Asynchronously creates a `ListMonitor` for a sectioned list of `NSManagedObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed. Asynchronously creates a `ListMonitor` for a sectioned list of `DynamicObject`s that satisfy the specified fetch clauses. Multiple `ListObserver`s may then register themselves to be notified when changes are made to the list. Since `NSFetchedResultsController` greedily locks the persistent store on initial fetch, you may prefer this method instead of the synchronous counterpart to avoid deadlocks while background updates/saves are being executed.
- parameter createAsynchronously: the closure that receives the created `ListMonitor` instance - parameter createAsynchronously: the closure that receives the created `ListMonitor` instance
- parameter from: a `From` clause indicating the entity type - parameter from: a `From` clause indicating the entity type

View File

@@ -30,7 +30,7 @@ import CoreData
// MARK: - UnsafeDataTransaction // MARK: - UnsafeDataTransaction
/** /**
The `UnsafeDataTransaction` provides an interface for non-contiguous `NSManagedObject` creates, updates, and deletes. This is useful for making temporary changes, such as partially filled forms. An unsafe transaction object should typically be only used from the main queue. The `UnsafeDataTransaction` provides an interface for non-contiguous `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes. This is useful for making temporary changes, such as partially filled forms. An unsafe transaction object should typically be only used from the main queue.
*/ */
public final class UnsafeDataTransaction: BaseDataTransaction { public final class UnsafeDataTransaction: BaseDataTransaction {
@@ -124,7 +124,7 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
} }
/** /**
Begins a child transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. Begins a child transaction where `NSManagedObject` or `CoreStoreObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
- prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited. - prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited.
- returns: an `UnsafeDataTransaction` instance where creates, updates, and deletes can be made. - returns: an `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.

View File

@@ -32,7 +32,7 @@ import Foundation
public extension DynamicObject where Self: CoreStoreObject { public extension DynamicObject where Self: CoreStoreObject {
/** /**
The containing type for value attributes. `Value` attributes support any type that conforms to `ImportableAttributeType`. The containing type for value propertiess. `Value` properties support any type that conforms to `ImportableAttributeType`.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -40,11 +40,12 @@ public extension DynamicObject where Self: CoreStoreObject {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- Important: `Value` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/ */
public typealias Value = ValueContainer<Self> public typealias Value = ValueContainer<Self>
/** /**
The containing type for transformable attributes. `Transformable` attributes support types that conforms to `NSCoding & NSCopying`. The containing type for transformable properties. `Transformable` properties support types that conforms to `NSCoding & NSCopying`.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -52,6 +53,7 @@ public extension DynamicObject where Self: CoreStoreObject {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- Important: `Transformable` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/ */
public typealias Transformable = TransformableContainer<Self> public typealias Transformable = TransformableContainer<Self>
} }
@@ -60,7 +62,7 @@ public extension DynamicObject where Self: CoreStoreObject {
// MARK: - ValueContainer // MARK: - ValueContainer
/** /**
The containing type for value attributes. Use the `DynamicObject.Value` typealias instead for shorter syntax. The containing type for value properties. Use the `DynamicObject.Value` typealias instead for shorter syntax.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -74,7 +76,7 @@ public enum ValueContainer<O: CoreStoreObject> {
// MARK: - Required // MARK: - Required
/** /**
The containing type for required value attributes. Any type that conforms to `ImportableAttributeType` are supported. The containing type for required value properties. Any type that conforms to `ImportableAttributeType` are supported.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -82,11 +84,12 @@ public enum ValueContainer<O: CoreStoreObject> {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- Important: `Value.Required` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/ */
public final class Required<V: ImportableAttributeType>: AttributeProtocol { public final class Required<V: ImportableAttributeType>: AttributeProtocol {
/** /**
Initializes the metadata for the attribute. Initializes the metadata for the property.
``` ```
class Person: CoreStoreObject { class Person: CoreStoreObject {
let title = Value.Required<String>("title", default: "Mr.") let title = Value.Required<String>("title", default: "Mr.")
@@ -98,11 +101,11 @@ public enum ValueContainer<O: CoreStoreObject> {
) )
} }
``` ```
- parameter keyPath: the permanent attribute name for this attribute. - parameter keyPath: the permanent attribute name for this property.
- parameter default: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified. - parameter default: the initial value for the property when the object is first created. For types that implement `EmptyableAttributeType`s, this argument may be omitted and the type's "empty" value will be used instead (e.g. `false` for `Bool`, `0` for `Int`, `""` for `String`, etc.)
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified. - parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on. - parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the attributes of a property are unchanged but the format or content of its data are changed.) - parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name. - parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
- parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter. - parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter.
- parameter self: the `CoreStoreObject` - parameter self: the `CoreStoreObject`
@@ -112,7 +115,7 @@ public enum ValueContainer<O: CoreStoreObject> {
- parameter finalNewValue: the transformed new value - parameter finalNewValue: the transformed new value
- parameter originalNewValue: the original new value - parameter originalNewValue: the original new value
*/ */
public init(_ keyPath: KeyPath, `default`: V = V.cs_emptyValue(), isIndexed: Bool = false, isTransient: Bool = false, versionHashModifier: String? = nil, renamingIdentifier: String? = nil, customGetter: @escaping (_ `self`: O, _ getValue: () -> V) -> V = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (_ finalNewValue: V) -> Void, _ originalNewValue: V) -> Void = { $1($2) }) { public init(_ keyPath: KeyPath, `default`: V, isIndexed: Bool = false, isTransient: Bool = false, versionHashModifier: String? = nil, renamingIdentifier: String? = nil, customGetter: @escaping (_ `self`: O, _ getValue: () -> V) -> V = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (_ finalNewValue: V) -> Void, _ originalNewValue: V) -> Void = { $1($2) }) {
self.keyPath = keyPath self.keyPath = keyPath
self.isIndexed = isIndexed self.isIndexed = isIndexed
@@ -206,7 +209,7 @@ public enum ValueContainer<O: CoreStoreObject> {
// MARK: - Optional // MARK: - Optional
/** /**
The containing type for optional value attributes. Any type that conforms to `ImportableAttributeType` are supported. The containing type for optional value properties. Any type that conforms to `ImportableAttributeType` are supported.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -214,11 +217,12 @@ public enum ValueContainer<O: CoreStoreObject> {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- Important: `Value.Optional` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/ */
public final class Optional<V: ImportableAttributeType>: AttributeProtocol { public final class Optional<V: ImportableAttributeType>: AttributeProtocol {
/** /**
Initializes the metadata for the attribute. Initializes the metadata for the property.
``` ```
class Person: CoreStoreObject { class Person: CoreStoreObject {
let title = Value.Required<String>("title", default: "Mr.") let title = Value.Required<String>("title", default: "Mr.")
@@ -230,11 +234,11 @@ public enum ValueContainer<O: CoreStoreObject> {
) )
} }
``` ```
- parameter keyPath: the permanent attribute name for this attribute. - parameter keyPath: the permanent attribute name for this property.
- parameter default: the initial value for the property when the object is first created. Defaults to `nil` if not specified. - parameter default: the initial value for the property when the object is first created. Defaults to `nil` if not specified.
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified. - parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on. - parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the attributes of a property are unchanged but the format or content of its data are changed.) - parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name. - parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
- parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter. - parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter.
- parameter self: the `CoreStoreObject` - parameter self: the `CoreStoreObject`
@@ -334,11 +338,48 @@ public enum ValueContainer<O: CoreStoreObject> {
} }
} }
public extension ValueContainer.Required where V: EmptyableAttributeType {
/**
Initializes the metadata for the property. This convenience initializer uses the `EmptyableAttributeType`'s "empty" value as the initial value for the property when the object is first created (e.g. `false` for `Bool`, `0` for `Int`, `""` for `String`, etc.)
```
class Person: CoreStoreObject {
let title = Value.Required<String>("title") // initial value defaults to empty string
}
```
- parameter keyPath: the permanent attribute name for this property.
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
- parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter.
- parameter self: the `CoreStoreObject`
- parameter getValue: the original getter for the property
- parameter customSetter: use this closure to make final transformations to the new value before assigning to the property.
- parameter setValue: the original setter for the property
- parameter finalNewValue: the transformed new value
- parameter originalNewValue: the original new value
*/
public convenience init(_ keyPath: KeyPath, isIndexed: Bool = false, isTransient: Bool = false, versionHashModifier: String? = nil, renamingIdentifier: String? = nil, customGetter: @escaping (_ `self`: O, _ getValue: () -> V) -> V = { $1() }, customSetter: @escaping (_ `self`: O, _ setValue: (_ finalNewValue: V) -> Void, _ originalNewValue: V) -> Void = { $1($2) }) {
self.init(
keyPath,
default: V.cs_emptyValue(),
isIndexed: isIndexed,
isTransient: isTransient,
versionHashModifier: versionHashModifier,
renamingIdentifier: renamingIdentifier,
customGetter: customGetter,
customSetter: customSetter
)
}
}
// MARK: - TransformableContainer // MARK: - TransformableContainer
/** /**
The containing type for transformable attributes. Use the `DynamicObject.Transformable` typealias instead for shorter syntax. The containing type for transformable properties. Use the `DynamicObject.Transformable` typealias instead for shorter syntax.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -352,7 +393,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
// MARK: - Required // MARK: - Required
/** /**
The containing type for transformable attributes. Any type that conforms to `NSCoding & NSCopying` are supported. The containing type for transformable properties. Any type that conforms to `NSCoding & NSCopying` are supported.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -360,21 +401,22 @@ public enum TransformableContainer<O: CoreStoreObject> {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- Important: `Transformable.Required` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/ */
public final class Required<V: NSCoding & NSCopying>: AttributeProtocol { public final class Required<V: NSCoding & NSCopying>: AttributeProtocol {
/** /**
Initializes the metadata for the attribute. Initializes the metadata for the property.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- parameter keyPath: the permanent attribute name for this attribute. - parameter keyPath: the permanent attribute name for this property.
- parameter default: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified. - parameter default: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified. - parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on. - parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the attributes of a property are unchanged but the format or content of its data are changed.) - parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name. - parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
- parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter. - parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter.
- parameter self: the `CoreStoreObject` - parameter self: the `CoreStoreObject`
@@ -477,7 +519,7 @@ public enum TransformableContainer<O: CoreStoreObject> {
// MARK: - Optional // MARK: - Optional
/** /**
The containing type for optional transformable attributes. Any type that conforms to `NSCoding & NSCopying` are supported. The containing type for optional transformable properties. Any type that conforms to `NSCoding & NSCopying` are supported.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let species = Value.Required<String>("species") let species = Value.Required<String>("species")
@@ -485,21 +527,22 @@ public enum TransformableContainer<O: CoreStoreObject> {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- Important: `Transformable.Optional` properties are required to be stored properties. Computed properties will be ignored, including `lazy` and `weak` properties.
*/ */
public final class Optional<V: NSCoding & NSCopying>: AttributeProtocol { public final class Optional<V: NSCoding & NSCopying>: AttributeProtocol {
/** /**
Initializes the metadata for the attribute. Initializes the metadata for the property.
``` ```
class Animal: CoreStoreObject { class Animal: CoreStoreObject {
let color = Transformable.Optional<UIColor>("color") let color = Transformable.Optional<UIColor>("color")
} }
``` ```
- parameter keyPath: the permanent attribute name for this attribute. - parameter keyPath: the permanent attribute name for this property.
- parameter default: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified. - parameter default: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
- parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified. - parameter isIndexed: `true` if the property should be indexed for searching, otherwise `false`. Defaults to `false` if not specified.
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on. - parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the attributes of a property are unchanged but the format or content of its data are changed.) - parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name. - parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
- parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter. - parameter customGetter: use this closure to make final transformations to the property's value before returning from the getter.
- parameter self: the `CoreStoreObject` - parameter self: the `CoreStoreObject`
@@ -608,7 +651,7 @@ infix operator .== : ComparisonPrecedence
extension ValueContainer.Required { extension ValueContainer.Required {
/** /**
Assigns a value to the attribute. The operation Assigns a value to the property. The operation
``` ```
animal.species .= "Swift" animal.species .= "Swift"
``` ```
@@ -617,13 +660,13 @@ extension ValueContainer.Required {
animal.species.value = "Swift" animal.species.value = "Swift"
``` ```
*/ */
public static func .= (_ attribute: ValueContainer<O>.Required<V>, _ newValue: V) { public static func .= (_ property: ValueContainer<O>.Required<V>, _ newValue: V) {
attribute.value = newValue property.value = newValue
} }
/** /**
Assigns a value from another attribute. The operation Assigns a value from another property. The operation
``` ```
animal.species .= anotherAnimal.species animal.species .= anotherAnimal.species
``` ```
@@ -632,16 +675,76 @@ extension ValueContainer.Required {
animal.species.value = anotherAnimal.species.value animal.species.value = anotherAnimal.species.value
``` ```
*/ */
public static func .= <O2: CoreStoreObject>(_ attribute: ValueContainer<O>.Required<V>, _ attribute2: ValueContainer<O2>.Required<V>) { public static func .= <O2: CoreStoreObject>(_ property: ValueContainer<O>.Required<V>, _ property2: ValueContainer<O2>.Required<V>) {
attribute.value = attribute2.value property.value = property2.value
}
/**
Compares equality between a property's value and another value
```
if animal.species .== "Swift" { ... }
```
is equivalent to
```
if animal.species.value == "Swift" { ... }
```
*/
public static func .== (_ property: ValueContainer<O>.Required<V>, _ value: V?) -> Bool {
return property.value == value
}
/**
Compares equality between a value and a property's value
```
if "Swift" .== animal.species { ... }
```
is equivalent to
```
if "Swift" == animal.species.value { ... }
```
*/
public static func .== (_ value: V?, _ property: ValueContainer<O>.Required<V>) -> Bool {
return value == property.value
}
/**
Compares equality between a property's value and another property's value
```
if animal.species .== anotherAnimal.species { ... }
```
is equivalent to
```
if animal.species.value == anotherAnimal.species.value { ... }
```
*/
public static func .== (_ property: ValueContainer<O>.Required<V>, _ property2: ValueContainer<O>.Required<V>) -> Bool {
return property.value == property2.value
}
/**
Compares equality between a property's value and another property's value
```
if animal.species .== anotherAnimal.species { ... }
```
is equivalent to
```
if animal.species.value == anotherAnimal.species.value { ... }
```
*/
public static func .== (_ property: ValueContainer<O>.Required<V>, _ property2: ValueContainer<O>.Optional<V>) -> Bool {
return property.value == property2.value
} }
} }
extension ValueContainer.Optional { extension ValueContainer.Optional {
/** /**
Assigns an optional value to the attribute. The operation Assigns an optional value to the property. The operation
``` ```
animal.nickname .= "Taylor" animal.nickname .= "Taylor"
``` ```
@@ -650,13 +753,13 @@ extension ValueContainer.Optional {
animal.nickname.value = "Taylor" animal.nickname.value = "Taylor"
``` ```
*/ */
public static func .= (_ attribute: ValueContainer<O>.Optional<V>, _ newValue: V?) { public static func .= (_ property: ValueContainer<O>.Optional<V>, _ newValue: V?) {
attribute.value = newValue property.value = newValue
} }
/** /**
Assigns an optional value from another attribute. The operation Assigns an optional value from another property. The operation
``` ```
animal.nickname .= anotherAnimal.nickname animal.nickname .= anotherAnimal.nickname
``` ```
@@ -665,13 +768,13 @@ extension ValueContainer.Optional {
animal.nickname.value = anotherAnimal.nickname.value animal.nickname.value = anotherAnimal.nickname.value
``` ```
*/ */
public static func .= <O2: CoreStoreObject>(_ attribute: ValueContainer<O>.Optional<V>, _ attribute2: ValueContainer<O2>.Optional<V>) { public static func .= <O2: CoreStoreObject>(_ property: ValueContainer<O>.Optional<V>, _ property2: ValueContainer<O2>.Optional<V>) {
attribute.value = attribute2.value property.value = property2.value
} }
/** /**
Assigns a value from another attribute. The operation Assigns a value from another property. The operation
``` ```
animal.nickname .= anotherAnimal.species animal.nickname .= anotherAnimal.species
``` ```
@@ -680,16 +783,76 @@ extension ValueContainer.Optional {
animal.nickname.value = anotherAnimal.species.value animal.nickname.value = anotherAnimal.species.value
``` ```
*/ */
public static func .= <O2: CoreStoreObject>(_ attribute: ValueContainer<O>.Optional<V>, _ attribute2: ValueContainer<O2>.Required<V>) { public static func .= <O2: CoreStoreObject>(_ property: ValueContainer<O>.Optional<V>, _ property2: ValueContainer<O2>.Required<V>) {
attribute.value = attribute2.value property.value = property2.value
}
/**
Compares equality between a property's value and another value
```
if animal.species .== "Swift" { ... }
```
is equivalent to
```
if animal.species.value == "Swift" { ... }
```
*/
public static func .== (_ property: ValueContainer<O>.Optional<V>, _ value: V?) -> Bool {
return property.value == value
}
/**
Compares equality between a property's value and another property's value
```
if "Swift" .== animal.species { ... }
```
is equivalent to
```
if "Swift" == animal.species.value { ... }
```
*/
public static func .== (_ value: V?, _ property: ValueContainer<O>.Optional<V>) -> Bool {
return value == property.value
}
/**
Compares equality between a property's value and another property's value
```
if animal.species .== anotherAnimal.species { ... }
```
is equivalent to
```
if animal.species.value == anotherAnimal.species.value { ... }
```
*/
public static func .== (_ property: ValueContainer<O>.Optional<V>, _ property2: ValueContainer<O>.Optional<V>) -> Bool {
return property.value == property2.value
}
/**
Compares equality between a property's value and another property's value
```
if animal.species .== anotherAnimal.species { ... }
```
is equivalent to
```
if animal.species.value == anotherAnimal.species.value { ... }
```
*/
public static func .== (_ property: ValueContainer<O>.Optional<V>, _ property2: ValueContainer<O>.Required<V>) -> Bool {
return property.value == property2.value
} }
} }
extension TransformableContainer.Required { extension TransformableContainer.Required {
/** /**
Assigns a transformable value to the attribute. The operation Assigns a transformable value to the property. The operation
``` ```
animal.color .= UIColor.red animal.color .= UIColor.red
``` ```
@@ -698,13 +861,13 @@ extension TransformableContainer.Required {
animal.color.value = UIColor.red animal.color.value = UIColor.red
``` ```
*/ */
public static func .= (_ attribute: TransformableContainer<O>.Required<V>, _ newValue: V) { public static func .= (_ property: TransformableContainer<O>.Required<V>, _ newValue: V) {
attribute.value = newValue property.value = newValue
} }
/** /**
Assigns a transformable value from another attribute. The operation Assigns a transformable value from another property. The operation
``` ```
animal.nickname .= anotherAnimal.species animal.nickname .= anotherAnimal.species
``` ```
@@ -713,16 +876,16 @@ extension TransformableContainer.Required {
animal.nickname.value = anotherAnimal.species.value animal.nickname.value = anotherAnimal.species.value
``` ```
*/ */
public static func .= <O2: CoreStoreObject>(_ attribute: TransformableContainer<O>.Required<V>, _ attribute2: TransformableContainer<O2>.Required<V>) { public static func .= <O2: CoreStoreObject>(_ property: TransformableContainer<O>.Required<V>, _ property2: TransformableContainer<O2>.Required<V>) {
attribute.value = attribute2.value property.value = property2.value
} }
} }
extension TransformableContainer.Optional { extension TransformableContainer.Optional {
/** /**
Assigns an optional transformable value to the attribute. The operation Assigns an optional transformable value to the property. The operation
``` ```
animal.color .= UIColor.red animal.color .= UIColor.red
``` ```
@@ -731,13 +894,13 @@ extension TransformableContainer.Optional {
animal.color.value = UIColor.red animal.color.value = UIColor.red
``` ```
*/ */
public static func .= (_ attribute: TransformableContainer<O>.Optional<V>, _ newValue: V?) { public static func .= (_ property: TransformableContainer<O>.Optional<V>, _ newValue: V?) {
attribute.value = newValue property.value = newValue
} }
/** /**
Assigns an optional transformable value from another attribute. The operation Assigns an optional transformable value from another property. The operation
``` ```
animal.color .= anotherAnimal.color animal.color .= anotherAnimal.color
``` ```
@@ -746,13 +909,13 @@ extension TransformableContainer.Optional {
animal.color.value = anotherAnimal.color.value animal.color.value = anotherAnimal.color.value
``` ```
*/ */
public static func .= <O2: CoreStoreObject>(_ attribute: TransformableContainer<O>.Optional<V>, _ attribute2: TransformableContainer<O2>.Optional<V>) { public static func .= <O2: CoreStoreObject>(_ property: TransformableContainer<O>.Optional<V>, _ property2: TransformableContainer<O2>.Optional<V>) {
attribute.value = attribute2.value property.value = property2.value
} }
/** /**
Assigns a transformable value from another attribute. The operation Assigns a transformable value from another property. The operation
``` ```
animal.color .= anotherAnimal.color animal.color .= anotherAnimal.color
``` ```
@@ -761,9 +924,9 @@ extension TransformableContainer.Optional {
animal.color.value = anotherAnimal.color.value animal.color.value = anotherAnimal.color.value
``` ```
*/ */
public static func .= <O2: CoreStoreObject>(_ attribute: TransformableContainer<O>.Optional<V>, _ attribute2: TransformableContainer<O2>.Required<V>) { public static func .= <O2: CoreStoreObject>(_ property: TransformableContainer<O>.Optional<V>, _ property2: TransformableContainer<O2>.Required<V>) {
attribute.value = attribute2.value property.value = property2.value
} }
} }

View File

@@ -28,12 +28,49 @@ import Foundation
// MARK: - VersionLock // MARK: - VersionLock
/**
The `VersionLock` contains the version hashes for entities. This is then passed to the `CoreStoreSchema`, which contains all entities for the store. An assertion will be raised if any `Entity` doesn't match the version hash.
```
class Animal: CoreStoreObject {
let species = Value.Required<String>("species")
let nickname = Value.Optional<String>("nickname")
let master = Relationship.ToOne<Person>("master")
}
class Person: CoreStoreObject {
let name = Value.Required<String>("name")
let pet = Relationship.ToOne<Animal>("pet", inverse: { $0.master })
}
CoreStore.defaultStack = DataStack(
CoreStoreSchema(
modelVersion: "V1",
entities: [
Entity<Animal>("Animal"),
Entity<Person>("Person")
],
versionLock: [
"Animal": [0x2698c812ebbc3b97, 0x751e3fa3f04cf9, 0x51fd460d3babc82, 0x92b4ba735b5a3053],
"Person": [0xae4060a59f990ef0, 0x8ac83a6e1411c130, 0xa29fea58e2e38ab6, 0x2071bb7e33d77887]
]
)
)
```
*/
public struct VersionLock: ExpressibleByDictionaryLiteral, Equatable { public struct VersionLock: ExpressibleByDictionaryLiteral, Equatable {
/**
The value type for the dictionary initializer, which is `UInt64`
*/
public typealias HashElement = UInt64 public typealias HashElement = UInt64
/**
The `Data` hash for each entity name.
*/
public let hashesByEntityName: [EntityName: Data] public let hashesByEntityName: [EntityName: Data]
/**
Initializes a `VersionLock` with the version hash for each entity name.
*/
public init(_ intArrayByEntityName: [EntityName: [HashElement]]) { public init(_ intArrayByEntityName: [EntityName: [HashElement]]) {
self.init(keyValues: intArrayByEntityName.map({ $0 })) self.init(keyValues: intArrayByEntityName.map({ $0 }))

View File

@@ -148,7 +148,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
self.init(NSPredicate(format: "\(keyPath) == nil")) self.init(NSPredicate(format: "\(keyPath) == nil"))
case let object?: case let object?:
self.init(NSPredicate(format: "\(keyPath) == %@", argumentArray: [object.cs_toRaw().objectID])) self.init(NSPredicate(format: "\(keyPath) == %@", argumentArray: [object.cs_id()]))
} }
} }
@@ -171,7 +171,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
*/ */
public init<S: Sequence>(_ keyPath: KeyPath, isMemberOf list: S) where S.Iterator.Element: DynamicObject { public init<S: Sequence>(_ keyPath: KeyPath, isMemberOf list: S) where S.Iterator.Element: DynamicObject {
self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_toRaw().objectID }) as NSArray)) self.init(NSPredicate(format: "\(keyPath) IN %@", list.map({ $0.cs_id() }) as NSArray))
} }
/** /**

View File

@@ -39,6 +39,73 @@ import Foundation
*/ */
public final class XcodeDataModelSchema: DynamicSchema { public final class XcodeDataModelSchema: DynamicSchema {
/**
Creates a `XcodeDataModelSchema` for each of the models declared in the specified (.xcdatamodeld) model file.
- parameter modelName: the name of the (.xcdatamodeld) model file. If not specified, the application name (CFBundleName) will be used if it exists, or "CoreData" if it the bundle name was not set.
- parameter bundle: an optional bundle to load models from. If not specified, the main bundle will be used.
- parameter migrationChain: the `MigrationChain` that indicates the sequence of model versions to be used as the order for progressive migrations. If not specified, will default to a non-migrating data stack.
- returns: a tuple containing all `XcodeDataModelSchema` for the models declared in the specified .xcdatamodeld file, and the current model version string declared or inferred from the file.
*/
public static func from(modelName: XcodeDataModelFileName, bundle: Bundle = Bundle.main, migrationChain: MigrationChain = nil) -> (allSchema: [XcodeDataModelSchema], currentModelVersion: ModelVersion) {
guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else {
// For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model.
let foundModels = bundle
.paths(forResourcesOfType: "momd", inDirectory: nil)
.map({ ($0 as NSString).lastPathComponent })
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle \"\(bundle.bundleIdentifier ?? "<nil>")\". Other model files in bundle: \(foundModels.coreStoreDumpString)")
}
let modelFileURL = URL(fileURLWithPath: modelFilePath)
let versionInfoPlistURL = modelFileURL.appendingPathComponent("VersionInfo.plist", isDirectory: false)
guard let versionInfo = NSDictionary(contentsOf: versionInfoPlistURL),
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel.self)) metadata from path \"\(versionInfoPlistURL)\".")
}
let modelVersions = Set(versionHashes.keys)
let modelVersionHints = migrationChain.leafVersions
let currentModelVersion: String
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String,
modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
currentModelVersion = plistModelVersion
}
else if let resolvedVersion = modelVersions.intersection(modelVersionHints).first {
CoreStore.log(
.warning,
message: "The \(cs_typeName(MigrationChain.self)) leaf versions do not include the model file's current version. Resolving to version \"\(resolvedVersion)\"."
)
currentModelVersion = resolvedVersion
}
else if let resolvedVersion = modelVersions.first ?? modelVersionHints.first {
if !modelVersionHints.isEmpty {
CoreStore.log(
.warning,
message: "The \(cs_typeName(MigrationChain.self)) leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"."
)
}
currentModelVersion = resolvedVersion
}
else {
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
}
var allSchema: [XcodeDataModelSchema] = []
for modelVersion in modelVersions {
let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
allSchema.append(XcodeDataModelSchema(modelName: modelVersion, modelVersionFileURL: fileURL))
}
return (allSchema, currentModelVersion)
}
/** /**
Initializes an `XcodeDataModelSchema` from an *.xcdatamodeld version name and its containing `Bundle`. Initializes an `XcodeDataModelSchema` from an *.xcdatamodeld version name and its containing `Bundle`.
``` ```

View File

@@ -29,12 +29,33 @@ import Foundation
// MARK: - XcodeSchemaMappingProvider // MARK: - XcodeSchemaMappingProvider
/**
A `SchemaMappingProvider` that tries to infer model migration between two `DynamicSchema` versions by loading an xcmappingmodel file from the specified `Bundle`. Throws `CoreStoreError.mappingModelNotFound` if the xcmappingmodel file cannot be found, or if the xcmappingmodel doesn't resolve the source and destination `DynamicSchema`.
*/
final class XcodeSchemaMappingProvider: Hashable, SchemaMappingProvider { final class XcodeSchemaMappingProvider: Hashable, SchemaMappingProvider {
/**
The source model version for the mapping.
*/
public let sourceVersion: ModelVersion public let sourceVersion: ModelVersion
/**
The destination model version for the mapping.
*/
public let destinationVersion: ModelVersion public let destinationVersion: ModelVersion
/**
The `Bundle` that contains the xcmappingmodel file.
*/
public let mappingModelBundle: Bundle public let mappingModelBundle: Bundle
/**
Creates an `XcodeSchemaMappingProvider`
- parameter sourceVersion: the source model version for the mapping
- parameter destinationVersion: the destination model version for the mapping
- parameter mappingModelBundle: the `Bundle` that contains the xcmappingmodel file
*/
public required init(from sourceVersion: ModelVersion, to destinationVersion: ModelVersion, mappingModelBundle: Bundle) { public required init(from sourceVersion: ModelVersion, to destinationVersion: ModelVersion, mappingModelBundle: Bundle) {
self.sourceVersion = sourceVersion self.sourceVersion = sourceVersion
@@ -64,7 +85,7 @@ final class XcodeSchemaMappingProvider: Hashable, SchemaMappingProvider {
// MARK: SchemaMappingProvider // MARK: SchemaMappingProvider
public func createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) { public func cs_createMappingModel(from sourceSchema: DynamicSchema, to destinationSchema: DynamicSchema, storage: LocalStorage) throws -> (mappingModel: NSMappingModel, migrationType: MigrationType) {
let sourceModel = sourceSchema.rawModel() let sourceModel = sourceSchema.rawModel()
let destinationModel = destinationSchema.rawModel() let destinationModel = destinationSchema.rawModel()