Compare commits

...

79 Commits
2.0.6 ... 3.0.0

Author SHA1 Message Date
John Estropia
6d83564a1a Swift 3 master candidate 2017-01-06 16:50:38 +09:00
John Estropia
c0d72799b4 Merge branch 'swift3_develop' into develop
# Conflicts:
#	.travis.yml
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	Sources/Info.plist
2017-01-06 16:03:28 +09:00
John Estropia
06a1919e91 minor fixes 2017-01-06 15:56:47 +09:00
John Rommel Estropia
16def2d84b disable tests on iOS 8.2 and 8.1 (keeps failing due to xcode bug) 2016-12-31 13:14:50 +08:00
John Rommel Estropia
e9a2c58f32 travis bug 2016-12-31 11:26:35 +08:00
John Rommel Estropia
1a3e0dd4c6 CoreStore 3 master candidate 2016-12-31 11:03:03 +08:00
John Rommel Estropia
518bb134f9 merge fix 2016-12-26 14:55:06 +08:00
John Estropia
4d7feca848 Merge pull request #139 from deanWombourne/swift3_develop
Add an override to cs_typeName which deals with String explicitly.
2016-12-26 14:53:51 +08:00
John Rommel Estropia
64a80bf401 Swift 3.0.1 support 2016-12-26 14:51:36 +08:00
John Rommel Estropia
4d63fc744a Add String overload for cs_typeName (fixes #138) 2016-12-26 14:51:23 +08:00
Sam Dean
9480e372f1 Add an override to cs_typeName which deals with String explicitly. 2016-12-23 11:06:09 +00:00
John Rommel Estropia
23df460c35 require transaction logs path from icloud stores 2016-12-10 18:39:53 +09:00
John Rommel Estropia
1c233b7302 don't access iCloud's ubiquitous cache file 2016-12-10 09:43:45 +09:00
John Estropia
f42288802c Merge branch 'swift3_develop' of github.com:JohnEstropia/CoreStore into swift3_develop
# Conflicts:
#	Sources/Convenience/NSManagedObject+Convenience.swift
2016-12-08 19:00:38 +09:00
John Estropia
a27556f294 minor Swift 3 cleanup 2016-12-08 18:59:41 +09:00
John Rommel Estropia
e330291e1b support generics for KVC accessors 2016-12-03 10:13:50 +09:00
John Rommel Estropia
4a282150f0 utilities for safer KVO access in objects 2016-12-03 09:59:17 +09:00
John Rommel Estropia
5d2956d674 Make RecreateStoreOnModelMismatch flag work again (fixes #126) 2016-11-26 16:19:12 +09:00
John Estropia
92756fec42 always dispatch completion right after adding a store to the coordinator (allow stores to fully complete their run loop) 2016-11-17 16:27:28 +09:00
John Estropia
2b37daefe0 minor documentation updates 2016-11-17 14:31:06 +09:00
John Estropia
5724d4599e Merge pull request #122 from ruslanskorb/rename-error-type-to-error
`ErrorType` has been renamed to `Error` in Swift 3.
2016-11-17 13:34:03 +09:00
Ruslan Skorb
4a882e6108 ErrorType has been renamed to Error in Swift 3. 2016-11-15 19:16:18 +02:00
John Estropia
b230ed6400 FetchableSource and QueryableSource protocols 2016-11-15 18:00:39 +09:00
John Estropia
33a5c123aa resurrect utilities for creating NSFetchedResultsController (fixes #119) 2016-11-11 17:32:13 +09:00
John Estropia
73637321ce xcode 8.1 (swift 3.0.1) update 2016-11-11 14:03:37 +09:00
John Estropia
088f1717f9 Merge pull request #115 from deville/import-unique-objects-order
Import unique objects in the same order as the array of import sources (with fix for potential duplicates)
2016-11-11 11:46:27 +09:00
John Estropia
cff2bb1740 version bump 2016-10-27 19:16:17 +09:00
John Estropia
d902d62172 Turn off whole-module-optimization to prevent Swift compiler bugs (#113) 2016-10-27 18:41:27 +09:00
John Estropia
b955495012 Turn off whole-module-optimization to prevent Swift compiler bugs (#113) 2016-10-27 18:30:35 +09:00
Andrii Chernenko
d2e78a70e1 add test for the order of unique object import 2016-10-23 16:22:26 +02:00
Andrii Chernenko
970957cbc2 Merge branch 'duplicate-import-fix' into import-unique-objects-order 2016-10-23 14:52:34 +02:00
John Rommel Estropia
2f9e5db89f Added comment (fixes #106) 2016-10-16 14:40:25 +09:00
John Estropia
1789eb7daf Merge pull request #112 from JohnEstropia/revert-109-import-unique-objects-order
Revert "Import unique objects in the same order as the array of import sources"
2016-10-14 17:46:27 +09:00
John Estropia
3999654ee7 Revert "Import unique objects in the same order as the array of import sources" 2016-10-14 17:45:31 +09:00
Andrii Chernenko
4c3bec287c fix duplication when using importUniqueObjects with non-unique import sources 2016-10-12 02:01:23 +02:00
John Estropia
2a2d9b3483 Merge pull request #109 from deville/import-unique-objects-order
Import unique objects in the same order as the array of import sources
2016-10-10 20:29:59 +09:00
Andrii Chernenko
32a388e0ca import unique objects in the same order as the array of import sources 2016-10-08 23:14:22 +02:00
John Rommel Estropia
1a6fbad3d4 force dynamic dispatch on generic types 2016-10-09 00:52:18 +09:00
John Estropia
ac55f20f5f Merge pull request #108 from deville/type-method-dispatch-fix
Fix type method dispatch when importing objects
2016-10-08 10:43:21 +09:00
Andrii Chernenko
910b5039fd fix type method dispatch when importing objects 2016-10-07 15:26:45 +02:00
John Estropia
ffea06ee7e try again 2016-09-30 19:16:14 +09:00
John Estropia
a92d6cac02 try again 2016-09-30 19:08:17 +09:00
John Estropia
de5d660257 try again 2016-09-30 17:53:15 +09:00
John Estropia
55b2e6eecd try again 2016-09-30 17:36:48 +09:00
John Estropia
b64c776335 try again 2016-09-30 17:28:02 +09:00
John Estropia
432af667e8 try again 2016-09-30 17:08:04 +09:00
John Estropia
cf60a4bc2e updated travis.yml 2016-09-30 17:00:11 +09:00
John Estropia
c620859899 run demo project on CI 2016-09-30 13:58:11 +09:00
John Estropia
65ac069a0b skip observer testing on macOS 2016-09-30 13:32:31 +09:00
John Estropia
862ef27374 version bump, cleanup, unit test 2016-09-30 13:28:19 +09:00
John Estropia
243b6a76d5 Merge pull request #104 from colinmorelli/feature/sync-transaction-async-merge
Fixes #98 (deadlock when merge happens while main queue is querying)
2016-09-30 12:38:28 +09:00
Colin Morelli
8be20370d5 Fixes #98 (deadlock when merge happens while main queue is querying) 2016-09-29 14:47:51 -04:00
John Estropia
a9c0feae46 NSFetchRequest.affectedStores bug workaround 2016-09-27 19:02:24 +09:00
John Estropia
2e44f86eb6 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Cartfile
#	Carthage/Checkouts/GCDKit
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj
#	CoreStoreTests/BaseTests/BaseTestCase.swift
#	CoreStoreTests/FromTests.swift
#	CoreStoreTests/GroupByTests.swift
#	CoreStoreTests/OrderByTests.swift
#	CoreStoreTests/StorageInterfaceTests.swift
#	CoreStoreTests/TweakTests.swift
#	CoreStoreTests/WhereTests.swift
#	README.md
#	Sources/Internal/CoreStoreFetchRequest.swift
#	Sources/Internal/NSManagedObjectContext+Querying.swift
#	Sources/Internal/NSManagedObjectModel+Setup.swift
#	Sources/Migrating/DataStack+Migration.swift
#	Sources/ObjectiveC/CSSQliteStore.swift
#	Sources/ObjectiveC/CSStorageInterface.swift
#	Sources/ObjectiveC/CoreStoreBridge.swift
#	Sources/Observing/ListMonitor.swift
#	Sources/Setup/DataStack.swift
#	Sources/Setup/StorageInterfaces/ICloudStore.swift
#	Sources/Setup/StorageInterfaces/LegacySQLiteStore.swift
#	Sources/Setup/StorageInterfaces/SQLiteStore.swift
#	Sources/Setup/StorageInterfaces/StorageInterface.swift
2016-09-27 18:55:37 +09:00
John Estropia
ed8c7b35e8 Reduce leaking (a little) on the workaround for NSFetchRequest.affectedStores ARC bug 2016-09-27 17:31:08 +09:00
John Rommel Estropia
4d2ebe4ea8 workaround #100 (NSFetchRequest.affectedStores ARC bug) 2016-09-27 02:39:28 +09:00
John Estropia
54be9d471c renamed ImportableObject and ImportableUniqueObject protocol methods to Swift 3 naming style 2016-09-21 12:00:48 +09:00
John Rommel Estropia
f18d62f643 travis yml update 2016-09-17 14:27:36 +09:00
John Rommel Estropia
af141d4a31 travis yml update 2016-09-17 14:26:33 +09:00
John Rommel Estropia
2da659a967 travis yml update 2016-09-17 14:14:29 +09:00
John Rommel Estropia
e5f162c5e1 minor readme edits 2016-09-17 13:59:04 +09:00
John Rommel Estropia
effa231719 fix travis 2016-09-17 13:37:00 +09:00
John Rommel Estropia
6cef8f4b4f updated travis yml 2016-09-17 13:23:56 +09:00
John Rommel Estropia
aa6bceaaf3 working for Swift 2.3! 2016-09-17 12:22:25 +09:00
John Estropia
a51ed1a007 WIP: Renaming to meet Swift 3 API guidelines 2016-09-09 18:30:08 +09:00
John Estropia
e5245a0e5b user #keyPath() for keys in demo app and in unit tests 2016-09-09 17:05:55 +09:00
John Estropia
0fa2a23461 workaround for iOS 10 regression in "affectedStores" retain bug 2016-09-09 13:09:13 +09:00
John Estropia
3f28198552 Magical NSFetchedResultsController bugfix.... 2016-09-09 12:49:10 +09:00
John Estropia
82de482191 WIP: broken generics 2016-09-06 20:16:46 +09:00
John Estropia
b502895d63 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Sources/Internal/NotificationObserver.swift
2016-09-06 12:05:40 +09:00
John Estropia
0ba63c6e72 WIP: Xcode 8 beta 6 2016-09-06 09:57:28 +09:00
John Rommel Estropia
e9be711d4c WIP: demo app 2016-07-25 08:21:22 +09:00
John Rommel Estropia
db5b8ca702 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Cartfile.resolved
#	Carthage/Checkouts/GCDKit
#	CoreStoreTests/ErrorTests.swift
#	Sources/Fetching and Querying/Concrete Clauses/Select.swift
#	Sources/ObjectiveC/CSError.swift
2016-07-22 00:47:03 +09:00
John Rommel Estropia
2f39f9188b WIP: the great renaming 2016-07-21 23:12:24 +09:00
John Rommel Estropia
872e69ddc6 WIP 2016-07-21 08:34:13 +09:00
John Rommel Estropia
f9e33101a0 WIP 2016-07-21 08:32:16 +09:00
John Rommel Estropia
0621c54868 WIP 2016-07-21 02:48:23 +09:00
John Rommel Estropia
a638620858 WIP 2016-07-21 02:45:42 +09:00
John Rommel Estropia
267c21063a WIP: segfault 2016-07-20 08:12:04 +09:00
171 changed files with 7086 additions and 6973 deletions

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "Carthage/Checkouts/GCDKit"]
path = Carthage/Checkouts/GCDKit
url = https://github.com/JohnEstropia/GCDKit.git

View File

@@ -1,5 +1,5 @@
language: objective-c
osx_image: xcode7.3
osx_image: xcode8.2
sudo: false
git:
submodules: false
@@ -10,20 +10,21 @@ env:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
matrix:
- DESTINATION="OS=9.3,name=iPhone 6s" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.2,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES"
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS7" SDK=iphonesimulator9.3 RUN_TESTS="YES" POD_LINT="YES"
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.11 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator2.2 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator9.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.12 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=3.1,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.1 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.1 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=10.1,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.1 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.1 RUN_TESTS="YES" POD_LINT="NO"
before_install:
- gem install cocoapods --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.11/Carthage.pkg"
- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.18/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg"
before_script:
@@ -36,8 +37,8 @@ script:
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
xcodebuild -workspace CoreStore.xcworkspace -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
fi
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator9.3" -destination "OS=9.3,name=iPhone 6s" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator10.2" -destination "OS=10.1,name=iPhone 7" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator10.2" -destination "OS=10.1,name=iPhone 7" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- if [ $POD_LINT == "YES" ]; then
pod lib lint --quick;
fi

View File

@@ -1 +0,0 @@
github "JohnEstropia/GCDKit" == 1.2.6

View File

@@ -1 +0,0 @@
github "JohnEstropia/GCDKit" "1.2.6"

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "2.0.6"
s.version = "3.0.0"
s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore"
@@ -19,6 +19,4 @@ Pod::Spec.new do |s|
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D USE_FRAMEWORKS -D DEBUG',
'OTHER_SWIFT_FLAGS[config=Release]' => '-D USE_FRAMEWORKS',
'GCC_PREPROCESSOR_DEFINITIONS' => 'USE_FRAMEWORKS=1' }
s.dependency "GCDKit", "1.2.6"
end

File diff suppressed because it is too large Load Diff

View File

@@ -10,10 +10,10 @@
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F347F55F-7F5C-4476-9148-6E902F06E4AD",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore"
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
"DVTSourceControlWorkspaceBlueprintVersion" : 203,
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -11,8 +11,7 @@
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES"
hideIssues = "NO">
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
@@ -26,8 +25,7 @@
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO"
hideIssues = "NO">
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@@ -7,7 +7,4 @@
<FileRef
location = "group:CoreStoreDemo/CoreStoreDemo.xcodeproj">
</FileRef>
<FileRef
location = "group:Carthage/Checkouts/GCDKit/GCDKit.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -36,8 +36,6 @@
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; };
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */; };
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; };
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; };
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25841B36E23C0000406B /* OrganismV1.swift */; };
@@ -54,7 +52,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */,
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
@@ -94,7 +91,6 @@
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryingResultsViewController.swift; sourceTree = "<group>"; };
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
B5BDC9211C202429008147CD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B5BDC9241C202429008147CD /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GCDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrganismTableViewCell.swift; path = "CoreStoreDemo/MIgrations Demo/OrganismTableViewCell.swift"; sourceTree = SOURCE_ROOT; };
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
B5EE25841B36E23C0000406B /* OrganismV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV1.swift; sourceTree = "<group>"; };
@@ -110,7 +106,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */,
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */,
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */,
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */,
@@ -146,7 +141,6 @@
children = (
B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
B5BDC9211C202429008147CD /* CoreStore.framework */,
B5BDC9241C202429008147CD /* GCDKit.framework */,
B52977DE1B120F83003D50A5 /* MapKit.framework */,
);
name = Frameworks;
@@ -272,11 +266,12 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = {
B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3;
LastSwiftMigration = 0800;
};
};
};
@@ -461,6 +456,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
@@ -473,6 +469,8 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -14,24 +14,10 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52"
BuildableName = "CoreStore_iOS7.framework"
BlueprintName = "CoreStore iOS7"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -42,24 +28,14 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
@@ -75,15 +51,16 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52"
BuildableName = "CoreStore_iOS7.framework"
BlueprintName = "CoreStore iOS7"
ReferencedContainer = "container:CoreStore.xcodeproj">
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
@@ -93,9 +70,19 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Release">
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"

View File

@@ -18,9 +18,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
application.statusBarStyle = .LightContent
application.statusBarStyle = .lightContent
return true
}

View File

@@ -19,27 +19,27 @@ private struct Static {
SQLiteStore(
fileName: "TimeZoneDemo.sqlite",
configuration: "FetchingAndQueryingDemo",
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
dataStack.beginSynchronous { (transaction) -> Void in
_ = dataStack.beginSynchronous { (transaction) -> Void in
transaction.deleteAll(From(TimeZone))
transaction.deleteAll(From<TimeZone>())
for name in NSTimeZone.knownTimeZoneNames() {
for name in NSTimeZone.knownTimeZoneNames {
let rawTimeZone = NSTimeZone(name: name)!
let cachedTimeZone = transaction.create(Into(TimeZone))
let cachedTimeZone = transaction.create(Into<TimeZone>())
cachedTimeZone.name = rawTimeZone.name
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT)
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.daylightSavingTime
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.isDaylightSavingTime
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
}
transaction.commitAndWait()
_ = transaction.commitAndWait()
}
return dataStack
@@ -53,7 +53,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UIViewController
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
@@ -67,27 +67,27 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
let alert = UIAlertController(
title: "Fetch and Query Demo",
message: "This demo shows how to execute fetches and queries.\n\nEach menu item executes and displays a preconfigured fetch/query.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepareForSegue(segue, sender: sender)
super.prepare(for: segue, sender: sender)
if let indexPath = sender as? NSIndexPath {
if let indexPath = sender as? IndexPath {
switch segue.destinationViewController {
switch segue.destination {
case let controller as FetchingResultsViewController:
let item = self.fetchingItems[indexPath.row]
controller.setTimeZones(item.fetch(), title: item.title)
controller.set(timeZones: item.fetch(), title: item.title)
case let controller as QueryingResultsViewController:
let item = self.queryingItems[indexPath.row]
controller.setValue(item.query(), title: item.title)
controller.set(value: item.query(), title: item.title)
default:
break
@@ -98,14 +98,14 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?:
case Section.fetching.rawValue?:
return self.fetchingItems.count
case Section.Querying.rawValue?:
case Section.querying.rawValue?:
return self.queryingItems.count
default:
@@ -113,16 +113,16 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?:
case Section.fetching.rawValue?:
cell.textLabel?.text = self.fetchingItems[indexPath.row].title
case Section.Querying.rawValue?:
case Section.querying.rawValue?:
cell.textLabel?.text = self.queryingItems[indexPath.row].title
default:
@@ -135,17 +135,17 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
// MARK: UITableViewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
switch self.segmentedControl?.selectedSegmentIndex {
case Section.Fetching.rawValue?:
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath)
case Section.fetching.rawValue?:
self.performSegue(withIdentifier: "FetchingResultsViewController", sender: indexPath)
case Section.Querying.rawValue?:
self.performSegueWithIdentifier("QueryingResultsViewController", sender: indexPath)
case Section.querying.rawValue?:
self.performSegue(withIdentifier: "QueryingResultsViewController", sender: indexPath)
default:
break
@@ -157,8 +157,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
private enum Section: Int {
case Fetching
case Querying
case fetching
case querying
}
private let fetchingItems = [
@@ -167,8 +167,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
OrderBy(.Ascending("name"))
From<TimeZone>(),
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
}
),
@@ -177,9 +177,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "Asia"),
OrderBy(.Ascending("secondsFromGMT"))
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Asia"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
}
),
@@ -188,10 +188,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "America")
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"),
OrderBy(.Ascending("secondsFromGMT"))
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America")
|| Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Europe"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
}
),
@@ -200,9 +200,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
!Where("%K BEGINSWITH[c] %@", "name", "America"),
OrderBy(.Ascending("secondsFromGMT"))
From<TimeZone>(),
!Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
}
),
@@ -211,9 +211,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From(TimeZone),
From<TimeZone>(),
Where("hasDaylightSavingTime", isEqualTo: true),
OrderBy(.Ascending("name"))
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
}
)
@@ -222,60 +222,60 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
private let queryingItems = [
(
title: "Number of Time Zones",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryValue(
From(TimeZone),
Select<NSNumber>(.Count("name"))
From<TimeZone>(),
Select<NSNumber>(.count(#keyPath(TimeZone.name)))
)!
}
),
(
title: "Abbreviation For Tokyo's Time Zone",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryValue(
From(TimeZone),
Select<String>("abbreviation"),
Where("%K ENDSWITH[c] %@", "name", "Tokyo")
From<TimeZone>(),
Select<String>(#keyPath(TimeZone.abbreviation)),
Where("%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
)!
}
),
(
title: "All Abbreviations",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
Select<NSDictionary>("name", "abbreviation"),
OrderBy(.Ascending("name"))
From<TimeZone>(),
Select<NSDictionary>(#keyPath(TimeZone.name), #keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
}
),
(
title: "Number of Countries per Time Zone",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"),
GroupBy("abbreviation"),
OrderBy(.Ascending("secondsFromGMT"), .Ascending("name"))
From<TimeZone>(),
Select<NSDictionary>(.count(#keyPath(TimeZone.abbreviation)), #keyPath(TimeZone.abbreviation)),
GroupBy(#keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)), .ascending(#keyPath(TimeZone.name)))
)!
}
),
(
title: "Number of Countries with Summer Time",
query: { () -> AnyObject in
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From(TimeZone),
From<TimeZone>(),
Select<NSDictionary>(
.Count("hasDaylightSavingTime", As: "numberOfCountries"),
"hasDaylightSavingTime"
.count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"),
#keyPath(TimeZone.hasDaylightSavingTime)
),
GroupBy("hasDaylightSavingTime"),
OrderBy(.Descending("hasDaylightSavingTime"))
GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)),
OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime)))
)!
}
)
@@ -286,7 +286,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBOutlet dynamic weak var tableView: UITableView?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
@IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
self.tableView?.reloadData()
}

View File

@@ -14,7 +14,7 @@ class FetchingResultsViewController: UITableViewController {
// MARK: Public
func setTimeZones(timeZones: [TimeZone]?, title: String) {
func set(timeZones: [TimeZone]?, title: String) {
self.timeZones += timeZones ?? []
self.sectionTitle = title
@@ -36,14 +36,14 @@ class FetchingResultsViewController: UITableViewController {
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.timeZones.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let timeZone = self.timeZones[indexPath.row]
cell.textLabel?.text = timeZone.name
@@ -55,7 +55,7 @@ class FetchingResultsViewController: UITableViewController {
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle
}

View File

@@ -12,23 +12,23 @@ class QueryingResultsViewController: UITableViewController {
// MARK: Public
func setValue(value: AnyObject?, title: String) {
func set(value: Any?, title: String) {
switch value {
case (let array as [AnyObject])?:
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
case (let array as [Any])?:
self.values = array.map { (item: Any) -> (title: String, detail: String) in
(
title: item.description,
detail: String(reflecting: item.dynamicType)
title: String(describing: item),
detail: String(reflecting: type(of: item))
)
}
case let item?:
self.values = [
(
title: item.description,
detail: String(reflecting: item.dynamicType)
title: String(describing: item),
detail: String(reflecting: type(of: item))
)
]
@@ -55,14 +55,14 @@ class QueryingResultsViewController: UITableViewController {
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.values.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let value = self.values[indexPath.row]
@@ -75,7 +75,7 @@ class QueryingResultsViewController: UITableViewController {
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sectionTitle
}

View File

@@ -14,17 +14,17 @@ private struct Static {
enum Filter: String {
case All = "All Colors"
case Light = "Light Colors"
case Dark = "Dark Colors"
case all = "All Colors"
case light = "Light Colors"
case dark = "Dark Colors"
func next() -> Filter {
switch self {
case All: return .Light
case Light: return .Dark
case Dark: return .All
case .all: return .light
case .light: return .dark
case .dark: return .all
}
}
@@ -32,14 +32,14 @@ private struct Static {
switch self {
case .All: return Where(true)
case .Light: return Where("brightness >= 0.9")
case .Dark: return Where("brightness <= 0.4")
case .all: return Where(true)
case .light: return Where("%K >= %@", #keyPath(Palette.brightness), 0.9)
case .dark: return Where("%K <= %@", #keyPath(Palette.brightness), 0.4)
}
}
}
static var filter = Filter.All {
static var filter = Filter.all {
didSet {
@@ -53,14 +53,14 @@ private struct Static {
SQLiteStore(
fileName: "ColorsDemo.sqlite",
configuration: "ObservingDemo",
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
return CoreStore.monitorSectionedList(
From(Palette),
SectionBy("colorName"),
OrderBy(.Ascending("hue"))
From<Palette>(),
SectionBy(#keyPath(Palette.colorName)),
OrderBy(.ascending(#keyPath(Palette.hue)))
)
}()
}
@@ -86,9 +86,9 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
let navigationItem = self.navigationItem
navigationItem.leftBarButtonItems = [
self.editButtonItem(),
self.editButtonItem,
UIBarButtonItem(
barButtonSystemItem: .Trash,
barButtonSystemItem: .trash,
target: self,
action: #selector(self.resetBarButtonItemTouched(_:))
)
@@ -96,13 +96,13 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
let filterBarButton = UIBarButtonItem(
title: Static.filter.rawValue,
style: .Plain,
style: .plain,
target: self,
action: #selector(self.filterBarButtonItemTouched(_:))
)
navigationItem.rightBarButtonItems = [
UIBarButtonItem(
barButtonSystemItem: .Add,
barButtonSystemItem: .add,
target: self,
action: #selector(self.addBarButtonItemTouched(_:))
),
@@ -112,14 +112,14 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
Static.palettes.addObserver(self)
self.setTableEnabled(!Static.palettes.isPendingRefetch)
self.setTable(enabled: !Static.palettes.isPendingRefetch)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepareForSegue(segue, sender: sender)
super.prepare(for: segue, sender: sender)
switch (segue.identifier, segue.destinationViewController, sender) {
switch (segue.identifier, segue.destination, sender) {
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
destinationViewController.palette = palette
@@ -132,19 +132,19 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
// MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
override func numberOfSections(in tableView: UITableView) -> Int {
return Static.palettes.numberOfSections()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Static.palettes.numberOfObjectsInSection(section)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PaletteTableViewCell") as! PaletteTableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
@@ -156,21 +156,21 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
self.performSegueWithIdentifier(
"ObjectObserverDemoViewController",
self.performSegue(
withIdentifier: "ObjectObserverDemoViewController",
sender: Static.palettes[indexPath]
)
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
switch editingStyle {
case .Delete:
case .delete:
let palette = Static.palettes[indexPath]
CoreStore.beginAsynchronous{ (transaction) -> Void in
@@ -183,7 +183,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
}
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Static.palettes.sectionInfoAtIndex(section).name
}
@@ -191,44 +191,44 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
// MARK: ListObserver
func listMonitorWillChange(monitor: ListMonitor<Palette>) {
func listMonitorWillChange(_ monitor: ListMonitor<Palette>) {
self.tableView.beginUpdates()
}
func listMonitorDidChange(monitor: ListMonitor<Palette>) {
func listMonitorDidChange(_ monitor: ListMonitor<Palette>) {
self.tableView.endUpdates()
}
func listMonitorWillRefetch(monitor: ListMonitor<Palette>) {
func listMonitorWillRefetch(_ monitor: ListMonitor<Palette>) {
self.setTableEnabled(false)
self.setTable(enabled: false)
}
func listMonitorDidRefetch(monitor: ListMonitor<Palette>) {
func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
self.filterBarButton?.title = Static.filter.rawValue
self.tableView.reloadData()
self.setTableEnabled(true)
self.setTable(enabled: true)
}
// MARK: ListObjectObserver
func listMonitor(monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: IndexPath) {
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
self.tableView.insertRows(at: [indexPath], with: .automatic)
}
func listMonitor(monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: IndexPath) {
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
func listMonitor(monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: IndexPath) {
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? PaletteTableViewCell {
if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell {
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
@@ -236,23 +236,24 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
}
}
func listMonitor(monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
self.tableView.deleteRowsAtIndexPaths([fromIndexPath], withRowAnimation: .Automatic)
self.tableView.insertRowsAtIndexPaths([toIndexPath], withRowAnimation: .Automatic)
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
}
// MARK: ListSectionObserver
func listMonitor(monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
}
func listMonitor(monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
}
@@ -260,43 +261,43 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
private var filterBarButton: UIBarButtonItem?
@IBAction private dynamic func resetBarButtonItemTouched(sender: AnyObject?) {
@IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in
transaction.deleteAll(From(Palette))
transaction.deleteAll(From<Palette>())
transaction.commit()
}
}
@IBAction private dynamic func filterBarButtonItemTouched(sender: AnyObject?) {
@IBAction private dynamic func filterBarButtonItemTouched(_ sender: AnyObject?) {
Static.filter = Static.filter.next()
}
@IBAction private dynamic func addBarButtonItemTouched(sender: AnyObject?) {
@IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) {
CoreStore.beginAsynchronous { (transaction) -> Void in
let palette = transaction.create(Into(Palette))
let palette = transaction.create(Into<Palette>())
palette.setInitialValues()
transaction.commit()
}
}
private func setTableEnabled(enabled: Bool) {
private func setTable(enabled: Bool) {
UIView.animateWithDuration(
0.2,
UIView.animate(
withDuration: 0.2,
delay: 0,
options: .BeginFromCurrentState,
options: .beginFromCurrentState,
animations: { () -> Void in
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.userInteractionEnabled = enabled
tableView.isUserInteractionEnabled = enabled
}
},
completion: nil

View File

@@ -50,7 +50,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
required init?(coder aDecoder: NSCoder) {
if let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue"))) {
if let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue)))) {
self.monitor = CoreStore.monitorObject(palette)
}
@@ -58,13 +58,13 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
CoreStore.beginSynchronous { (transaction) -> Void in
let palette = transaction.create(Into(Palette))
let palette = transaction.create(Into(Palette.self))
palette.setInitialValues()
transaction.commitAndWait()
_ = transaction.commitAndWait()
}
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))!
let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue))))!
self.monitor = CoreStore.monitorObject(palette)
}
@@ -85,24 +85,24 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
// MARK: ObjectObserver
func objectMonitor(monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) {
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
}
func objectMonitor(monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
self.navigationItem.rightBarButtonItem?.enabled = false
self.navigationItem.rightBarButtonItem?.isEnabled = false
self.colorNameLabel?.alpha = 0.3
self.colorView?.alpha = 0.3
self.hsbLabel?.text = "Deleted"
self.hsbLabel?.textColor = UIColor.redColor()
self.hsbLabel?.textColor = UIColor.red
self.hueSlider?.enabled = false
self.saturationSlider?.enabled = false
self.brightnessSlider?.enabled = false
self.hueSlider?.isEnabled = false
self.saturationSlider?.isEnabled = false
self.brightnessSlider?.isEnabled = false
}
@@ -118,7 +118,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
@IBOutlet weak var saturationSlider: UISlider?
@IBOutlet weak var brightnessSlider: UISlider?
@IBAction dynamic func hueSliderValueDidChange(sender: AnyObject?) {
@IBAction dynamic func hueSliderValueDidChange(_ sender: AnyObject?) {
let hue = self.hueSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
@@ -131,7 +131,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
}
}
@IBAction dynamic func saturationSliderValueDidChange(sender: AnyObject?) {
@IBAction dynamic func saturationSliderValueDidChange(_ sender: AnyObject?) {
let saturation = self.saturationSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
@@ -144,7 +144,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
}
}
@IBAction dynamic func brightnessSliderValueDidChange(sender: AnyObject?) {
@IBAction dynamic func brightnessSliderValueDidChange(_ sender: AnyObject?) {
let brightness = self.brightnessSlider?.value ?? 0
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
@@ -157,7 +157,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
}
}
@IBAction dynamic func deleteBarButtonTapped(sender: AnyObject?) {
@IBAction dynamic func deleteBarButtonTapped(_ sender: AnyObject?) {
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
@@ -166,7 +166,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
}
}
func reloadPaletteInfo(palette: Palette, changedKeys: Set<String>?) {
func reloadPaletteInfo(_ palette: Palette, changedKeys: Set<String>?) {
self.colorNameLabel?.text = palette.colorName
@@ -176,15 +176,15 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
self.hsbLabel?.text = palette.colorText
if changedKeys == nil || changedKeys?.contains("hue") == true {
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.hue)) == true {
self.hueSlider?.value = Float(palette.hue)
}
if changedKeys == nil || changedKeys?.contains("saturation") == true {
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.saturation)) == true {
self.saturationSlider?.value = palette.saturation
}
if changedKeys == nil || changedKeys?.contains("brightness") == true {
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.brightness)) == true {
self.brightnessSlider?.value = palette.brightness
}

View File

@@ -15,16 +15,16 @@ class ObserversViewController: UIViewController {
// MARK: UIViewController
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Observers Demo",
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ListMonitor\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ObjectMonitor\".",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}

View File

@@ -24,7 +24,7 @@ class Palette: NSManagedObject {
get {
let KVCKey = "colorName"
let KVCKey = #keyPath(Palette.colorName)
if let colorName = self.accessValueForKVCKey(KVCKey) as? String {
return colorName
@@ -49,7 +49,7 @@ class Palette: NSManagedObject {
}
set {
self.setValue(newValue, forKVCKey: "colorName")
self.setValue(newValue, forKVCKey: #keyPath(Palette.colorName))
}
}

View File

@@ -8,7 +8,6 @@
import UIKit
import CoreStore
import GCDKit
// MARK: - CustomLoggerViewController
@@ -34,47 +33,47 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
CoreStore.logger = self
}
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Logger Demo",
message: "This demo shows how to plug-in any logging framework to CoreStore.\n\nThe view controller implements CoreStoreLogger and appends all logs to the text view.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// MARK: CoreStoreLogger
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
GCDQueue.Main.async { [weak self] in
DispatchQueue.main.async { [weak self] in
let levelString: String
switch level {
case .Trace: levelString = "Trace"
case .Notice: levelString = "Notice"
case .Warning: levelString = "Warning"
case .Fatal: levelString = "Fatal"
case .trace: levelString = "Trace"
case .notice: levelString = "Notice"
case .warning: levelString = "Warning"
case .fatal: levelString = "Fatal"
}
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
}
}
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
GCDQueue.Main.async { [weak self] in
DispatchQueue.main.async { [weak self] in
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
}
}
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() {
@@ -82,9 +81,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
}
let messageString = message()
GCDQueue.Main.async { [weak self] in
DispatchQueue.main.async { [weak self] in
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
}
}
@@ -94,14 +93,14 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
@IBOutlet dynamic weak var textView: UITextView?
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
@IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
switch self.segmentedControl?.selectedSegmentIndex {
case 0?:
self.dataStack.beginAsynchronous { (transaction) -> Void in
transaction.create(Into(Palette))
_ = transaction.create(Into<Palette>())
}
case 1?:

View File

@@ -12,7 +12,7 @@ import CoreStore
// MARK: - MigrationsDemoViewController
class MigrationsDemoViewController: UIViewController {
class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewDataSource, UITableViewDelegate {
// MARK: UIViewController
@@ -22,28 +22,28 @@ class MigrationsDemoViewController: UIViewController {
if let segmentedControl = self.segmentedControl {
for (index, model) in self.models.enumerate() {
for (index, model) in self.models.enumerated() {
segmentedControl.setTitle(
model.label,
forSegmentAtIndex: index
forSegmentAt: index
)
}
}
self.setDataStack(nil, model: nil, scrollToSelection: false)
self.set(dataStack: nil, model: nil, scrollToSelection: false)
}
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Migrations Demo",
message: "This demo shows how to run progressive migrations and how to support multiple model versions in a single project.\n\nThe persistent store contains 10000 organisms, which gain/lose properties when the migration evolves/devolves them.\n\nYou can use the \"mutate\" button to change an organism's properties then migrate to a different model to see how its value gets affected.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
let modelMetadata = withExtendedLifetime(DataStack(modelName: "MigrationDemo")) {
@@ -72,6 +72,71 @@ class MigrationsDemoViewController: UIViewController {
self.selectModelVersion(modelMetadata)
}
// MARK: ListObserver
func listMonitorWillChange(_ monitor: ListMonitor<NSManagedObject>) { }
func listMonitorDidChange(_ monitor: ListMonitor<NSManagedObject>) {
if self.lastSelectedIndexPath == nil,
let numberOfObjectsInSection = self.listMonitor?.numberOfObjectsInSection(0),
numberOfObjectsInSection > 0 {
self.tableView?.reloadData()
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: false)
}
else {
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
}
}
// MARK: UITableViewDataSource
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
}
@objc dynamic func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "OrganismTableViewCell", for: indexPath) as! OrganismTableViewCell
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
cell.dnaLabel?.text = "DNA: \(dna)"
cell.mutateButtonHandler = { [weak self] _ -> Void in
guard let `self` = self,
let dataStack = self.dataStack,
let organism = self.listMonitor?[indexPath] else {
return
}
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
self.setEnabled(false)
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
let organism = transaction.edit(organism) as! OrganismProtocol
organism.mutate()
transaction.commit { _ -> Void in
self?.setEnabled(true)
}
}
}
return cell
}
// MARK: UITableViewDelegate
@objc dynamic func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
}
// MARK: Private
@@ -113,13 +178,13 @@ class MigrationsDemoViewController: UIViewController {
return self._dataStack
}
private var _lastSelectedIndexPath: NSIndexPath?
private var lastSelectedIndexPath: NSIndexPath? {
private var _lastSelectedIndexPath: IndexPath?
private var lastSelectedIndexPath: IndexPath? {
return self._lastSelectedIndexPath
}
private func setSelectedIndexPath(indexPath: NSIndexPath, scrollToSelection: Bool) {
private func setSelectedIndexPath(_ indexPath: IndexPath, scrollToSelection: Bool) {
self._lastSelectedIndexPath = indexPath
self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true)
@@ -132,7 +197,7 @@ class MigrationsDemoViewController: UIViewController {
@IBOutlet private dynamic weak var progressView: UIProgressView?
@IBOutlet private dynamic weak var tableView: UITableView?
@IBAction private dynamic func segmentedControlValueChanged(sender: AnyObject?) {
@IBAction private dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
guard let index = self.segmentedControl?.selectedSegmentIndex else {
@@ -142,14 +207,14 @@ class MigrationsDemoViewController: UIViewController {
self.selectModelVersion(self.models[index])
}
private func selectModelVersion(model: ModelMetadata) {
private func selectModelVersion(_ model: ModelMetadata) {
if self.dataStack?.modelVersion == model.version {
return
}
self.setDataStack(nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
self.set(dataStack: nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
let dataStack = DataStack(
modelName: "MigrationDemo",
@@ -166,18 +231,17 @@ class MigrationsDemoViewController: UIViewController {
return
}
guard case .Success = result else {
guard case .success = result else {
self.setEnabled(true)
return
}
self.setDataStack(dataStack, model: model, scrollToSelection: true)
self.set(dataStack: dataStack, model: model, scrollToSelection: true)
let count = dataStack.queryValue(
From(model.entityType),
Select<Int>(.Count("dna"))
)
Select<Int>(.count(#keyPath(OrganismV1.dna))))!
if count > 0 {
self.setEnabled(true)
@@ -218,39 +282,39 @@ class MigrationsDemoViewController: UIViewController {
}
}
private func setEnabled(enabled: Bool) {
private func setEnabled(_ enabled: Bool) {
UIView.animateWithDuration(
0.2,
UIView.animate(
withDuration: 0.2,
delay: 0,
options: .BeginFromCurrentState,
options: .beginFromCurrentState,
animations: { () -> Void in
let navigationItem = self.navigationItem
navigationItem.leftBarButtonItem?.enabled = enabled
navigationItem.rightBarButtonItem?.enabled = enabled
navigationItem.leftBarButtonItem?.isEnabled = enabled
navigationItem.rightBarButtonItem?.isEnabled = enabled
navigationItem.hidesBackButton = !enabled
self.segmentedControl?.enabled = enabled
self.segmentedControl?.isEnabled = enabled
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.userInteractionEnabled = enabled
tableView.isUserInteractionEnabled = enabled
}
},
completion: nil
)
}
private func setDataStack(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
private func set(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
if let dataStack = dataStack, let model = model {
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.indexOf(model.version)!
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.index(of: model.version)!
self._dataStack = dataStack
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.Descending("dna")))
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.descending("dna")))
listMonitor.addObserver(self)
self._listMonitor = listMonitor
@@ -258,7 +322,7 @@ class MigrationsDemoViewController: UIViewController {
if listMonitor.numberOfObjectsInSection(0) > 0 {
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: true)
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: true)
}
}
}
@@ -272,14 +336,14 @@ class MigrationsDemoViewController: UIViewController {
self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false)
}
private func reloadTableHeaderWithProgress(progress: NSProgress) {
private func reloadTableHeaderWithProgress(_ progress: Progress) {
self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
self.titleLabel?.text = "Migrating: \(progress.localizedDescription)"
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription)"
self.titleLabel?.text = "Migrating: \(progress.localizedDescription ?? "")"
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription ?? "")"
}
private func updateDisplay(reloadData reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
private func updateDisplay(reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
var lines = [String]()
var organismType = ""
@@ -287,14 +351,14 @@ class MigrationsDemoViewController: UIViewController {
for property in organism.entity.properties {
let value: AnyObject = organism.valueForKey(property.name) ?? NSNull()
let value = organism.value(forKey: property.name) ?? NSNull()
lines.append("\(property.name): \(value)")
}
organismType = organism.entity.managedObjectClassName
}
self.titleLabel?.text = organismType
self.organismLabel?.text = lines.joinWithSeparator("\n")
self.organismLabel?.text = lines.joined(separator: "\n")
self.progressView?.progress = 0
self.headerContainer?.setNeedsLayout()
@@ -311,87 +375,13 @@ class MigrationsDemoViewController: UIViewController {
tableView.layoutIfNeeded()
if let indexPath = self.lastSelectedIndexPath where indexPath.row < tableView.numberOfRowsInSection(0) {
if let indexPath = self.lastSelectedIndexPath,
indexPath.row < tableView.numberOfRows(inSection: 0) {
tableView.selectRowAtIndexPath(indexPath,
tableView.selectRow(at: indexPath,
animated: scrollToSelection && animated,
scrollPosition: scrollToSelection ? .Middle : .None
scrollPosition: scrollToSelection ? .middle : .none
)
}
}
}
// MARK: - MigrationsDemoViewController: ListObserver
extension MigrationsDemoViewController: ListObserver {
// MARK: ListObserver
func listMonitorWillChange(monitor: ListMonitor<NSManagedObject>) { }
func listMonitorDidChange(monitor: ListMonitor<NSManagedObject>) {
if self.lastSelectedIndexPath == nil && self.listMonitor?.numberOfObjectsInSection(0) > 0 {
self.tableView?.reloadData()
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: false)
}
else {
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
}
}
}
// MARK: - MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate
extension MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate {
// MARK: UITableViewDataSource
@objc dynamic func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
}
@objc dynamic func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("OrganismTableViewCell", forIndexPath: indexPath) as! OrganismTableViewCell
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
cell.dnaLabel?.text = "DNA: \(dna)"
cell.mutateButtonHandler = { [weak self] _ -> Void in
guard let `self` = self,
let dataStack = self.dataStack,
let organism = self.listMonitor?[indexPath] else {
return
}
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
self.setEnabled(false)
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
let organism = transaction.edit(organism) as! OrganismProtocol
organism.mutate()
transaction.commit { _ -> Void in
self?.setEnabled(true)
}
}
}
return cell
}
// MARK: UITableViewDelegate
@objc dynamic func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
}
}

View File

@@ -13,4 +13,4 @@ protocol OrganismProtocol: class {
var dna: Int64 { get set }
func mutate()
}
}

View File

@@ -15,7 +15,7 @@ class OrganismTableViewCell: UITableViewCell {
var mutateButtonHandler: (() -> Void)?
@IBAction dynamic func mutateButtonTouchUpInside(sender: UIButton?) {
@IBAction dynamic func mutateButtonTouchUpInside(_ sender: UIButton?) {
self.mutateButtonHandler?()
}

View File

@@ -10,14 +10,20 @@ import CoreData
class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager) throws {
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstancesForSourceInstance(sInstance, entityMapping: mapping, manager: manager)
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
for dInstance in manager.destinationInstancesForEntityMappingNamed(mapping.name, sourceInstances: [sInstance]) {
for dInstance in manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]) {
dInstance.setValue(false, forKey: "hasVertebrae")
dInstance.setValue(sInstance.valueForKey("numberOfFlippers"), forKey: "numberOfLimbs")
dInstance.setValue(
false,
forKey: #keyPath(OrganismV3.hasVertebrae)
)
dInstance.setValue(
sInstance.value(forKey: #keyPath(OrganismV2.numberOfFlippers)),
forKey: #keyPath(OrganismV3.numberOfLimbs)
)
}
}
}

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV1" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="hasHead" optional="YES" attributeType="Boolean" syncable="YES"/>
<attribute name="hasTail" optional="YES" attributeType="Boolean" syncable="YES"/>
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="90"/>

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV2" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="105"/>

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV3" syncable="YES">
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
<attribute name="hasVertebrae" attributeType="Boolean" syncable="YES"/>
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasVertebrae" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
</entity>
<elements>
<element name="Organism" positionX="-36" positionY="9" width="128" height="120"/>

View File

@@ -22,20 +22,20 @@ private struct Static {
SQLiteStore(
fileName: "AccountsDemo_FB_Male.sqlite",
configuration: maleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_FB_Female.sqlite",
configuration: femaleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
dataStack.beginSynchronous { (transaction) -> Void in
_ = dataStack.beginSynchronous { (transaction) -> Void in
transaction.deleteAll(From(UserAccount))
transaction.deleteAll(From<UserAccount>())
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.accountType = "Facebook"
@@ -47,7 +47,7 @@ private struct Static {
account2.name = "Jane Doe HCD"
account2.friends = 314
transaction.commitAndWait()
_ = transaction.commitAndWait()
}
return dataStack
@@ -60,20 +60,20 @@ private struct Static {
SQLiteStore(
fileName: "AccountsDemo_TW_Male.sqlite",
configuration: maleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
try! dataStack.addStorageAndWait(
SQLiteStore(
fileName: "AccountsDemo_TW_Female.sqlite",
configuration: femaleConfiguration,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
dataStack.beginSynchronous { (transaction) -> Void in
_ = dataStack.beginSynchronous { (transaction) -> Void in
transaction.deleteAll(From(UserAccount))
transaction.deleteAll(From<UserAccount>())
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
account1.accountType = "Twitter"
@@ -85,7 +85,7 @@ private struct Static {
account2.name = "#janedoe_hcd"
account2.friends = 100
transaction.commitAndWait()
_ = transaction.commitAndWait()
}
return dataStack
@@ -100,53 +100,53 @@ private struct Static {
class StackSetupDemoViewController: UITableViewController {
let accounts = [
Static.facebookStack.fetchAll(From(UserAccount)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount)) ?? []
Static.facebookStack.fetchAll(From(UserAccount.self)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount.self)) ?? []
]
// MARK: UIViewController
override func viewWillAppear(animated: Bool) {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
self.updateDetailsWithAccount(self.accounts[indexPath.section][indexPath.row])
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
self.updateDetails(account: self.accounts[indexPath.section][indexPath.row])
}
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Setup Demo",
message: "This demo shows how to initialize 2 DataStacks with 2 configurations each, for a total of 4 SQLite files, each with 1 instance of a \"UserAccount\" entity.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// MARK: UITableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
override func numberOfSections(in tableView: UITableView) -> Int {
return self.accounts.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.accounts[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
let account = self.accounts[indexPath.section][indexPath.row]
cell.textLabel?.text = account.name
@@ -158,13 +158,13 @@ class StackSetupDemoViewController: UITableViewController {
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let account = self.accounts[indexPath.section][indexPath.row]
self.updateDetailsWithAccount(account)
self.updateDetails(account: account)
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
@@ -188,7 +188,7 @@ class StackSetupDemoViewController: UITableViewController {
@IBOutlet private dynamic weak var nameLabel: UILabel?
@IBOutlet private dynamic weak var friendsLabel: UILabel?
private func updateDetailsWithAccount(account: UserAccount) {
private func updateDetails(account: UserAccount) {
self.accountTypeLabel?.text = account.accountType
self.nameLabel?.text = account.name

View File

@@ -11,7 +11,6 @@ import CoreLocation
import MapKit
import AddressBookUI
import CoreStore
import GCDKit
private struct Static {
@@ -22,21 +21,21 @@ private struct Static {
SQLiteStore(
fileName: "PlaceDemo.sqlite",
configuration: "TransactionsDemo",
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
var place = CoreStore.fetchOne(From(Place))
var place = CoreStore.fetchOne(From<Place>())
if place == nil {
CoreStore.beginSynchronous { (transaction) -> Void in
_ = CoreStore.beginSynchronous { (transaction) -> Void in
let place = transaction.create(Into(Place))
let place = transaction.create(Into<Place>())
place.setInitialValues()
transaction.commitAndWait()
_ = transaction.commitAndWait()
}
place = CoreStore.fetchOne(From(Place))
place = CoreStore.fetchOne(From<Place>())
}
return CoreStore.monitorObject(place!)
@@ -71,33 +70,33 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
Static.placeController.addObserver(self)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .Refresh,
barButtonSystemItem: .refresh,
target: self,
action: #selector(self.refreshButtonTapped(_:))
)
}
override func viewDidAppear(animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let alert = UIAlertController(
title: "Transactions Demo",
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and unsafe.\n\nTap and hold on the map to change the pin location.",
preferredStyle: .Alert
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
override func viewWillAppear(animated: Bool) {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let mapView = self.mapView, let place = Static.placeController.object {
mapView.addAnnotation(place)
mapView.setCenterCoordinate(place.coordinate, animated: false)
mapView.setCenter(place.coordinate, animated: false)
mapView.selectAnnotation(place, animated: false)
}
}
@@ -105,14 +104,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
// MARK: MKMapViewDelegate
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MKAnnotationView"
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView.enabled = true
annotationView.isEnabled = true
annotationView.canShowCallout = true
annotationView.animatesDrop = true
}
@@ -127,28 +126,28 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
// MARK: ObjectObserver
func objectMonitor(monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
func objectMonitor(_ monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
// none
}
func objectMonitor(monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
if let mapView = self.mapView {
mapView.removeAnnotations(mapView.annotations ?? [])
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotation(object)
mapView.setCenterCoordinate(object.coordinate, animated: true)
mapView.setCenter(object.coordinate, animated: true)
mapView.selectAnnotation(object, animated: true)
if changedPersistentKeys.contains("latitude") || changedPersistentKeys.contains("longitude") {
if changedPersistentKeys.contains(#keyPath(Place.latitude)) || changedPersistentKeys.contains(#keyPath(Place.longitude)) {
self.geocodePlace(object)
self.geocode(place: object)
}
}
}
func objectMonitor(monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
func objectMonitor(_ monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
// none
}
@@ -160,13 +159,15 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
@IBOutlet weak var mapView: MKMapView?
@IBAction dynamic func longPressGestureRecognized(sender: AnyObject?) {
@IBAction dynamic func longPressGestureRecognized(_ sender: AnyObject?) {
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began {
if let mapView = self.mapView,
let gesture = sender as? UILongPressGestureRecognizer,
gesture.state == .began {
let coordinate = mapView.convertPoint(
gesture.locationInView(mapView),
toCoordinateFromView: mapView
let coordinate = mapView.convert(
gesture.location(in: mapView),
toCoordinateFrom: mapView
)
CoreStore.beginAsynchronous { (transaction) -> Void in
@@ -177,17 +178,17 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
}
}
@IBAction dynamic func refreshButtonTapped(sender: AnyObject?) {
@IBAction dynamic func refreshButtonTapped(_ sender: AnyObject?) {
CoreStore.beginSynchronous { (transaction) -> Void in
_ = CoreStore.beginSynchronous { (transaction) -> Void in
let place = transaction.edit(Static.placeController.object)
place?.setInitialValues()
transaction.commitAndWait()
_ = transaction.commitAndWait()
}
}
func geocodePlace(place: Place) {
func geocode(place: Place) {
let transaction = CoreStore.beginUnsafe()

View File

@@ -36,11 +36,12 @@ class BaseTestCase: XCTestCase {
// MARK: Internal
@nonobjc
func prepareStack<T>(configurations configurations: [String?] = [nil], @noescape _ closure: (dataStack: DataStack) -> T) -> T {
@discardableResult
func prepareStack<T>(configurations: [String?] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T {
let stack = DataStack(
modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType)
bundle: Bundle(for: type(of: self))
)
do {
@@ -49,10 +50,10 @@ class BaseTestCase: XCTestCase {
try stack.addStorageAndWait(
SQLiteStore(
fileURL: SQLiteStore.defaultRootDirectory
.URLByAppendingPathComponent(NSUUID().UUIDString)
.URLByAppendingPathComponent("\(self.dynamicType)_\(($0 ?? "-null-")).sqlite"),
.appendingPathComponent(UUID().uuidString)
.appendingPathComponent("\(type(of: self))_\(($0 ?? "-null-")).sqlite"),
configuration: $0,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
)
}
@@ -61,11 +62,11 @@ class BaseTestCase: XCTestCase {
XCTFail(error.coreStoreDumpString)
}
return closure(dataStack: stack)
return closure(stack)
}
@nonobjc
func expectLogger<T>(expectations: [TestLogger.Expectation], @noescape closure: () -> T) -> T {
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () -> T) -> T {
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer {
@@ -77,18 +78,18 @@ class BaseTestCase: XCTestCase {
}
@nonobjc
func expectLogger(expectations: [TestLogger.Expectation: XCTestExpectation]) {
func expectLogger(_ expectations: [TestLogger.Expectation: XCTestExpectation]) {
CoreStore.logger = TestLogger(expectations)
}
@nonobjc
func prepareLoggerExpectations(expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:]
for expectation in expectations {
testExpectations[expectation] = self.expectationWithDescription("Logger Expectation: \(expectation)")
testExpectations[expectation] = self.expectation(description: "Logger Expectation: \(expectation)")
}
return testExpectations
}
@@ -96,13 +97,13 @@ class BaseTestCase: XCTestCase {
@nonobjc
func checkExpectationsImmediately() {
self.waitForExpectationsWithTimeout(0, handler: nil)
self.waitForExpectations(timeout: 0, handler: { _ in })
}
@nonobjc
func waitAndCheckExpectations() {
self.waitForExpectationsWithTimeout(10, handler: nil)
self.waitForExpectations(timeout: 10, handler: {_ in })
}
// MARK: XCTestCase
@@ -126,7 +127,7 @@ class BaseTestCase: XCTestCase {
private func deleteStores() {
_ = try? NSFileManager.defaultManager().removeItemAtURL(SQLiteStore.defaultRootDirectory)
_ = try? FileManager.default.removeItem(at: SQLiteStore.defaultRootDirectory)
}
}
@@ -137,11 +138,11 @@ class TestLogger: CoreStoreLogger {
enum Expectation {
case LogWarning
case LogFatal
case LogError
case AssertionFailure
case FatalError
case logWarning
case logFatal
case logError
case assertionFailure
case fatalError
}
init(_ expectations: [Expectation: XCTestExpectation]) {
@@ -152,33 +153,33 @@ class TestLogger: CoreStoreLogger {
// MARK: CoreStoreLogger
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
switch level {
case .Warning: self.fulfill(.LogWarning)
case .Fatal: self.fulfill(.LogFatal)
case .warning: self.fulfill(.logWarning)
case .fatal: self.fulfill(.logFatal)
default: break
}
}
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.LogError)
self.fulfill(.logError)
}
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() {
return
}
self.fulfill(.AssertionFailure)
self.fulfill(.assertionFailure)
}
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.FatalError)
self.fulfill(.fatalError)
}
@@ -186,7 +187,7 @@ class TestLogger: CoreStoreLogger {
private var expectations: [Expectation: XCTestExpectation]
private func fulfill(expectation: Expectation) {
private func fulfill(_ expectation: Expectation) {
if let instance = self.expectations[expectation] {

View File

@@ -17,22 +17,22 @@ import CoreStore
class BaseTestDataTestCase: BaseTestCase {
@nonobjc
let dateFormatter: NSDateFormatter = {
let dateFormatter: DateFormatter = {
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.timeZone = NSTimeZone(name: "UTC")
formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
return formatter
}()
@nonobjc
func prepareTestDataForStack(stack: DataStack, configurations: [String?] = [nil]) {
func prepareTestDataForStack(_ stack: DataStack, configurations: [String?] = [nil]) {
stack.beginSynchronous { (transaction) in
for (configurationIndex, configuration) in configurations.enumerate() {
for (configurationIndex, configuration) in configurations.enumerated() {
let configurationOrdinal = configurationIndex + 1
if configuration == nil || configuration == "Config1" {
@@ -40,16 +40,16 @@ class BaseTestDataTestCase: BaseTestCase {
for idIndex in 1 ... 5 {
let object = transaction.create(Into<TestEntity1>(configuration))
object.testEntityID = NSNumber(integer: (configurationOrdinal * 100) + idIndex)
object.testEntityID = NSNumber(value: (configurationOrdinal * 100) + idIndex)
object.testNumber = idIndex
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1
object.testNumber = NSNumber(value: idIndex)
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
object.testString = string
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
}
}
if configuration == nil || configuration == "Config2" {
@@ -57,20 +57,20 @@ class BaseTestDataTestCase: BaseTestCase {
for idIndex in 1 ... 5 {
let object = transaction.create(Into<TestEntity2>(configuration))
object.testEntityID = NSNumber(integer: (configurationOrdinal * 200) + idIndex)
object.testEntityID = NSNumber(value: (configurationOrdinal * 200) + idIndex)
object.testNumber = idIndex
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1
object.testNumber = NSNumber(value: idIndex)
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
object.testString = string
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
}
}
}
transaction.commitAndWait()
_ = transaction.commitAndWait()
}
}
}

View File

@@ -233,5 +233,37 @@
}
[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

View File

@@ -0,0 +1,94 @@
//
// ConvenienceTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
@testable
import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - ConvenienceTests
class ConvenienceTests: BaseTestCase {
@objc
dynamic func test_ThatDataStacks_CanCreateFetchedResultsControllers() {
self.prepareStack { (stack) in
let controller = stack.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, stack.mainContext)
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
@objc
dynamic func test_ThatUnsafeDataTransactions_CanCreateFetchedResultsControllers() {
self.prepareStack { (stack) in
_ = withExtendedLifetime(stack.beginUnsafe()) { (transaction: UnsafeDataTransaction) in
let controller = transaction.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, transaction.context)
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
}
}
#endif

View File

@@ -36,33 +36,33 @@ final class ErrorTests: XCTestCase {
@objc
dynamic func test_ThatUnknownErrors_BridgeCorrectly() {
let error = CoreStoreError.Unknown
let error = CoreStoreError.unknown
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.UnknownError.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.unknownError.rawValue)
let userInfo: NSDictionary = [:]
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.UnknownError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.UnknownError.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() {
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let error = CoreStoreError.DifferentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
let error = CoreStoreError.differentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
let userInfo: NSDictionary = [
"existingPersistentStoreURL": dummyURL
@@ -70,27 +70,27 @@ final class ErrorTests: XCTestCase {
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() {
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let model = NSManagedObjectModel.fromBundle(NSBundle(forClass: self.dynamicType), modelName: "Model")
let model = NSManagedObjectModel.fromBundle(Bundle(for: type(of: self)), modelName: "Model")
let version = "1.0.0"
let error = CoreStoreError.MappingModelNotFound(localStoreURL: dummyURL, targetModel: model, targetModelVersion: version)
let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: model, targetModelVersion: version)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
let userInfo: NSDictionary = [
"localStoreURL": dummyURL,
@@ -100,24 +100,24 @@ final class ErrorTests: XCTestCase {
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() {
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let error = CoreStoreError.ProgressiveMigrationRequired(localStoreURL: dummyURL)
let error = CoreStoreError.progressiveMigrationRequired(localStoreURL: dummyURL)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
let userInfo: NSDictionary = [
"localStoreURL": dummyURL
@@ -125,14 +125,14 @@ final class ErrorTests: XCTestCase {
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
@@ -144,12 +144,12 @@ final class ErrorTests: XCTestCase {
userInfo: [
"key1": "value1",
"key2": 2,
"key3": NSDate()
"key3": Date()
]
)
let error = CoreStoreError(internalError)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.InternalError.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.internalError.rawValue)
let userInfo: NSDictionary = [
"NSError": internalError
@@ -157,13 +157,13 @@ final class ErrorTests: XCTestCase {
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.InternalError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.InternalError.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -74,33 +74,33 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -115,102 +115,102 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config1")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -225,99 +225,99 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity2>("Config1")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -332,96 +332,96 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
do {
let from = From<TestEntity2>("Config1")
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.affectedStores)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
}

View File

@@ -66,10 +66,10 @@ final class GroupByTests: BaseTestCase {
self.prepareStack { (dataStack) in
let groupBy = GroupBy("testString")
let groupBy = GroupBy(#keyPath(TestEntity1.testString))
let request = NSFetchRequest()
_ = From(TestEntity1).applyToFetchRequest(request, context: dataStack.mainContext)
let request = CoreStoreFetchRequest()
_ = From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
groupBy.applyToFetchRequest(request)
XCTAssertNotNil(request.propertiesToGroupBy)

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ final class IntoTests: XCTestCase {
}
do {
let into = Into(TestEntity1)
let into = Into<TestEntity1>()
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
@@ -108,14 +108,14 @@ final class IntoTests: XCTestCase {
do {
let into = Into<TestEntity1>()
XCTAssertEqual(into, Into(TestEntity1))
XCTAssertEqual(into, Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass))
XCTAssertFalse(into == Into<TestEntity2>())
XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
}
do {
let into = Into(TestEntity1)
let into = Into<TestEntity1>()
XCTAssertEqual(into, Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass))
XCTAssertFalse(into == Into<TestEntity2>())
@@ -125,7 +125,7 @@ final class IntoTests: XCTestCase {
let into = Into(TestEntity1.self as AnyClass)
XCTAssert(into == Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1))
XCTAssertEqual(into, Into(TestEntity1.self))
XCTAssertFalse(into == Into<TestEntity2>())
XCTAssertFalse(into == Into<TestEntity1>("Config1"))
}

View File

@@ -42,9 +42,9 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
@@ -54,13 +54,13 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -68,14 +68,14 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let didInsertSectionExpectation = self.expectationForNotification(
"listMonitor:didInsertSection:toSectionIndex:",
let didInsertSectionExpectation = self.expectation(
forNotification: "listMonitor:didInsertSection:toSectionIndex:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
XCTAssertEqual(
(note.userInfo ?? [:]),
((note.userInfo as NSDictionary?) ?? [:]),
[
"sectionInfo": monitor.sectionInfoAtIndex(0),
"sectionIndex": 0
@@ -88,8 +88,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1
}
)
let didInsertObjectExpectation = self.expectationForNotification(
"listMonitor:didInsertObject:toIndexPath:",
let didInsertObjectExpectation = self.expectation(
forNotification: "listMonitor:didInsertObject:toIndexPath:",
object: observer,
handler: { (note) -> Bool in
@@ -98,7 +98,7 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
@@ -107,12 +107,12 @@ class ListObserverTests: BaseTestDataTestCase {
XCTAssertEqual(indexPath?.row, 0)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 1))
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!)
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!)
defer {
events += 1
@@ -120,12 +120,12 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2
}
)
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -133,26 +133,26 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let saveExpectation = self.expectationWithDescription("save")
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
let object = transaction.create(Into(TestEntity1))
object.testBoolean = NSNumber(bool: true)
object.testNumber = NSNumber(integer: 1)
let object = transaction.create(Into<TestEntity1>())
object.testBoolean = NSNumber(value: true)
object.testNumber = NSNumber(value: 1)
object.testDecimal = NSDecimalNumber(string: "1")
object.testString = "nil:TestEntity1:1"
object.testData = ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
case .success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
case .failure:
XCTFail()
}
}
@@ -170,9 +170,9 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
@@ -185,13 +185,13 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -201,8 +201,8 @@ class ListObserverTests: BaseTestDataTestCase {
)
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectationForNotification(
"listMonitor:didUpdateObject:atIndexPath:",
let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didUpdateObject:atIndexPath:",
object: observer,
handler: { (note) -> Bool in
@@ -211,7 +211,7 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
@@ -220,27 +220,27 @@ class ListObserverTests: BaseTestDataTestCase {
switch object?.testEntityID {
case NSNumber(integer: 101)?:
case NSNumber(value: 101)?:
XCTAssertEqual(indexPath?.section, 1)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 11))
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!)
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
case NSNumber(integer: 102)?:
case NSNumber(value: 102)?:
XCTAssertEqual(indexPath?.section, 0)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(bool: false))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 22))
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-22T00:00:00Z")!)
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
default:
XCTFail()
@@ -253,13 +253,13 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
}
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 3)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -267,32 +267,32 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let saveExpectation = self.expectationWithDescription("save")
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) {
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
object.testNumber = NSNumber(integer: 11)
object.testNumber = NSNumber(value: 11)
object.testDecimal = NSDecimalNumber(string: "11")
object.testString = "nil:TestEntity1:11"
object.testData = ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!
object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
}
else {
XCTFail()
}
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 102)) {
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
object.testNumber = NSNumber(integer: 22)
object.testNumber = NSNumber(value: 22)
object.testDecimal = NSDecimalNumber(string: "22")
object.testString = "nil:TestEntity1:22"
object.testData = ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("2000-01-22T00:00:00Z")!
object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
}
else {
@@ -302,11 +302,11 @@ class ListObserverTests: BaseTestDataTestCase {
switch result {
case .Success(let hasChanges):
case .success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
case .failure:
XCTFail()
}
}
@@ -324,21 +324,21 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
var events = 0
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -346,8 +346,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let didMoveObjectExpectation = self.expectationForNotification(
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
let didMoveObjectExpectation = self.expectation(
forNotification: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
object: observer,
handler: { (note) -> Bool in
@@ -356,7 +356,7 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["fromIndexPath", "toIndexPath", "object"]
)
@@ -369,8 +369,8 @@ class ListObserverTests: BaseTestDataTestCase {
XCTAssertEqual(toIndexPath?.row, 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
defer {
@@ -379,13 +379,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1
}
)
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 2)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -393,14 +393,14 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2
}
)
let saveExpectation = self.expectationWithDescription("save")
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 102)) {
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
object.testBoolean = NSNumber(bool: true)
object.testBoolean = NSNumber(value: true)
}
else {
@@ -410,11 +410,11 @@ class ListObserverTests: BaseTestDataTestCase {
switch result {
case .Success(let hasChanges):
case .success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
case .failure:
XCTFail()
}
}
@@ -432,21 +432,21 @@ class ListObserverTests: BaseTestDataTestCase {
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
var events = 0
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -456,8 +456,8 @@ class ListObserverTests: BaseTestDataTestCase {
)
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectationForNotification(
"listMonitor:didDeleteObject:fromIndexPath:",
let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didDeleteObject:fromIndexPath:",
object: observer,
handler: { (note) -> Bool in
@@ -466,7 +466,7 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
@@ -476,7 +476,7 @@ class ListObserverTests: BaseTestDataTestCase {
XCTAssert(indexPath?.row == 0 || indexPath?.row == 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.deleted, true)
XCTAssertEqual(object?.isDeleted, true)
defer {
@@ -486,8 +486,8 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
}
let didDeleteSectionExpectation = self.expectationForNotification(
"listMonitor:didDeleteSection:fromSectionIndex:",
let didDeleteSectionExpectation = self.expectation(
forNotification: "listMonitor:didDeleteSection:fromSectionIndex:",
object: observer,
handler: { (note) -> Bool in
@@ -496,16 +496,16 @@ class ListObserverTests: BaseTestDataTestCase {
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["sectionInfo", "sectionIndex"]
)
let sectionInfo = userInfo?["sectionInfo"]
let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
XCTAssertNotNil(sectionInfo)
XCTAssertEqual(sectionInfo?.name, "0")
let sectionIndex = userInfo?["sectionIndex"]
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(integer: 0))
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
defer {
@@ -514,13 +514,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 4)
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
@@ -528,22 +528,22 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 4
}
)
let saveExpectation = self.expectationWithDescription("save")
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
transaction.deleteAll(
From(TestEntity1),
Where("testBoolean", isEqualTo: false)
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
)
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
case .success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
case .failure:
XCTFail()
}
}
@@ -562,37 +562,37 @@ class TestListObserver: ListSectionObserver {
typealias ListEntityType = TestEntity1
func listMonitorWillChange(monitor: ListMonitor<TestEntity1>) {
func listMonitorWillChange(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorWillChange:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillChange:"),
object: self,
userInfo: [:]
)
}
func listMonitorDidChange(monitor: ListMonitor<TestEntity1>) {
func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorDidChange:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidChange:"),
object: self,
userInfo: [:]
)
}
func listMonitorWillRefetch(monitor: ListMonitor<TestEntity1>) {
func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorWillRefetch:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
object: self,
userInfo: [:]
)
}
func listMonitorDidRefetch(monitor: ListMonitor<TestEntity1>) {
func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorDidRefetch:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
object: self,
userInfo: [:]
)
@@ -601,10 +601,10 @@ class TestListObserver: ListSectionObserver {
// MARK: ListObjectObserver
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didInsertObject:toIndexPath:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: self,
userInfo: [
"object": object,
@@ -613,10 +613,10 @@ class TestListObserver: ListSectionObserver {
)
}
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didDeleteObject:fromIndexPath:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
object: self,
userInfo: [
"object": object,
@@ -625,10 +625,10 @@ class TestListObserver: ListSectionObserver {
)
}
func listMonitor(monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didUpdateObject:atIndexPath:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
object: self,
userInfo: [
"object": object,
@@ -638,10 +638,10 @@ class TestListObserver: ListSectionObserver {
}
func listMonitor(monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
object: self,
userInfo: [
"object": object,
@@ -654,10 +654,10 @@ class TestListObserver: ListSectionObserver {
// MARK: ListSectionObserver
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didInsertSection:toSectionIndex:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
object: self,
userInfo: [
"sectionInfo": sectionInfo,
@@ -666,10 +666,10 @@ class TestListObserver: ListSectionObserver {
)
}
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didDeleteSection:fromSectionIndex:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
object: self,
userInfo: [
"sectionInfo": sectionInfo,

View File

@@ -43,8 +43,8 @@ class ObjectObserverTests: BaseTestDataTestCase {
self.prepareTestDataForStack(stack)
guard let object = stack.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) else {
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
@@ -58,14 +58,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0
let willUpdateExpectation = self.expectationForNotification(
"objectMonitor:willUpdateObject:",
let willUpdateExpectation = self.expectation(
forNotification: "objectMonitor:willUpdateObject:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual(
(note.userInfo ?? [:]),
((note.userInfo as NSDictionary?) ?? [:]),
["object": object] as NSDictionary
)
defer {
@@ -75,26 +75,26 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let didUpdateExpectation = self.expectationForNotification(
"objectMonitor:didUpdateObject:changedPersistentKeys:",
let didUpdateExpectation = self.expectation(
forNotification: "objectMonitor:didUpdateObject:changedPersistentKeys:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
XCTAssertEqual(
(note.userInfo ?? [:]),
((note.userInfo as NSDictionary?) ?? [:]),
[
"object": object,
"changedPersistentKeys": Set(
[
"testNumber",
"testString"
#keyPath(TestEntity1.testNumber),
#keyPath(TestEntity1.testString)
]
)
] as NSDictionary
)
let object = note.userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testNumber, NSNumber(integer: 10))
XCTAssertEqual(object?.testNumber, NSNumber(value: 10))
XCTAssertEqual(object?.testString, "nil:TestEntity1:10")
defer {
@@ -104,7 +104,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 1
}
)
let saveExpectation = self.expectationWithDescription("save")
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
guard let object = transaction.edit(object) else {
@@ -112,18 +112,18 @@ class ObjectObserverTests: BaseTestDataTestCase {
XCTFail()
return
}
object.testNumber = NSNumber(integer: 10)
object.testNumber = NSNumber(value: 10)
object.testString = "nil:TestEntity1:10"
transaction.commit { (result) in
switch result {
case .Success(let hasChanges):
case .success(let hasChanges):
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
case .Failure:
case .failure:
XCTFail()
}
}
@@ -140,8 +140,8 @@ class ObjectObserverTests: BaseTestDataTestCase {
self.prepareTestDataForStack(stack)
guard let object = stack.fetchOne(
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) else {
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
@@ -155,14 +155,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0
let didDeleteExpectation = self.expectationForNotification(
"objectMonitor:didDeleteObject:",
let didDeleteExpectation = self.expectation(
forNotification: "objectMonitor:didDeleteObject:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual(
(note.userInfo ?? [:]),
((note.userInfo as NSDictionary?) ?? [:]),
["object": object] as NSDictionary
)
defer {
@@ -172,7 +172,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let saveExpectation = self.expectationWithDescription("save")
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
guard let object = transaction.edit(object) else {
@@ -186,12 +186,12 @@ class ObjectObserverTests: BaseTestDataTestCase {
switch result {
case .Success(let hasChanges):
case .success(let hasChanges):
XCTAssertTrue(hasChanges)
XCTAssertTrue(monitor.isObjectDeleted)
saveExpectation.fulfill()
case .Failure:
case .failure:
XCTFail()
}
}
@@ -208,10 +208,10 @@ class TestObjectObserver: ObjectObserver {
typealias ObjectEntityType = TestEntity1
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) {
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) {
NSNotificationCenter.defaultCenter().postNotificationName(
"objectMonitor:willUpdateObject:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "objectMonitor:willUpdateObject:"),
object: self,
userInfo: [
"object": object
@@ -219,10 +219,10 @@ class TestObjectObserver: ObjectObserver {
)
}
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<KeyPath>) {
NSNotificationCenter.defaultCenter().postNotificationName(
"objectMonitor:didUpdateObject:changedPersistentKeys:",
NotificationCenter.default.post(
name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
object: self,
userInfo: [
"object": object,
@@ -231,10 +231,10 @@ class TestObjectObserver: ObjectObserver {
)
}
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) {
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) {
NSNotificationCenter.defaultCenter().postNotificationName(
"objectMonitor:didDeleteObject:",
NotificationCenter.default.post(
name: Notification.Name(rawValue: "objectMonitor:didDeleteObject:"),
object: self,
userInfo: [
"object": object

View File

@@ -39,7 +39,7 @@ final class OrderByTests: XCTestCase {
do {
let orderBy = OrderBy()
XCTAssertEqual(orderBy, OrderBy([] as [NSSortDescriptor]))
XCTAssertEqual(orderBy, OrderBy([NSSortDescriptor]()))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key", ascending: false)))
XCTAssertTrue(orderBy.sortDescriptors.isEmpty)
}
@@ -48,9 +48,9 @@ final class OrderByTests: XCTestCase {
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
let orderBy = OrderBy(sortDescriptor)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Descending("key1")))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key1", ascending: false)))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
@@ -63,7 +63,7 @@ final class OrderByTests: XCTestCase {
]
let orderBy = OrderBy(sortDescriptors)
XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2")))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy(
@@ -73,30 +73,30 @@ final class OrderByTests: XCTestCase {
]
)
)
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
do {
let orderBy = OrderBy(.Ascending("key1"))
let orderBy = OrderBy(.ascending("key1"))
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key2")))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2")))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
}
do {
let orderBy = OrderBy(.Ascending("key1"), .Descending("key2"))
let orderBy = OrderBy(.ascending("key1"), .descending("key2"))
let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false)
]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2")))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy(
@@ -106,20 +106,20 @@ final class OrderByTests: XCTestCase {
]
)
)
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
do {
let sortKeys: [SortKey] = [.Ascending("key1"), .Descending("key2")]
let sortKeys: [SortKey] = [.ascending("key1"), .descending("key2")]
let orderBy = OrderBy(sortKeys)
let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false)
]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key2")))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy(
@@ -129,8 +129,8 @@ final class OrderByTests: XCTestCase {
]
)
)
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.Ascending("key1"), .Descending("key3")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
}
@@ -138,15 +138,15 @@ final class OrderByTests: XCTestCase {
@objc
dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() {
let orderBy1 = OrderBy(.Ascending("key1"))
let orderBy2 = OrderBy(.Descending("key2"))
let orderBy3 = OrderBy(.Ascending("key3"))
let orderBy1 = OrderBy(.ascending("key1"))
let orderBy2 = OrderBy(.descending("key2"))
let orderBy3 = OrderBy(.ascending("key3"))
do {
let plusOrderBy = orderBy1 + orderBy2 + orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2"), .Ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1")) + OrderBy(.Descending("key2"), .Ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.descending("key2"), .ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -158,14 +158,14 @@ final class OrderByTests: XCTestCase {
var plusOrderBy = orderBy1
plusOrderBy += orderBy2
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1")) + OrderBy(.Descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.descending("key2")))
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1)
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors)
plusOrderBy += orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2"), .Ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.Ascending("key1"), .Descending("key2")) + OrderBy(.Ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2")) + OrderBy(.ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -178,8 +178,8 @@ final class OrderByTests: XCTestCase {
@objc
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
let orderBy = OrderBy(.Ascending("key"))
let request = NSFetchRequest()
let orderBy = OrderBy(.ascending("key"))
let request = CoreStoreFetchRequest()
orderBy.applyToFetchRequest(request)
XCTAssertNotNil(request.sortDescriptors)
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)

File diff suppressed because it is too large Load Diff

View File

@@ -42,14 +42,14 @@ final class SectionByTests: XCTestCase {
let sectionBy = SectionBy("key")
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key")
}
do {
let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } }
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(sectionName: nil))
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
}
}
}

View File

@@ -39,17 +39,17 @@ final class SelectTests: XCTestCase {
do {
let term: SelectTerm = "attribute"
XCTAssertEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
XCTAssertEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Attribute(let key):
case ._attribute(let key):
XCTAssertEqual(key, "attribute")
default:
@@ -58,17 +58,17 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.Attribute("attribute")
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.attribute("attribute")
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Attribute(let key):
case ._attribute(let key):
XCTAssertEqual(key, "attribute")
default:
@@ -82,23 +82,23 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.Average("attribute")
XCTAssertEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.average("attribute")
XCTAssertEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "average:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "average(attribute)")
XCTAssertTrue(nativeType == .DecimalAttributeType)
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
@@ -106,23 +106,23 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.Average("attribute", As: "alias")
XCTAssertEqual(term, SelectTerm.Average("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute", As: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.average("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "average:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .DecimalAttributeType)
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
@@ -135,23 +135,23 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.Count("attribute")
XCTAssertEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.count("attribute")
XCTAssertEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "count:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "count(attribute)")
XCTAssertTrue(nativeType == .Integer64AttributeType)
XCTAssertTrue(nativeType == .integer64AttributeType)
default:
XCTFail()
@@ -159,23 +159,23 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.Count("attribute", As: "alias")
XCTAssertEqual(term, SelectTerm.Count("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute", As: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.count("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "count:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .Integer64AttributeType)
XCTAssertTrue(nativeType == .integer64AttributeType)
default:
XCTFail()
@@ -188,23 +188,23 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.Maximum("attribute")
XCTAssertEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.maximum("attribute")
XCTAssertEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "max:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "max(attribute)")
XCTAssertTrue(nativeType == .UndefinedAttributeType)
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
@@ -212,23 +212,23 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.Maximum("attribute", As: "alias")
XCTAssertEqual(term, SelectTerm.Maximum("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute", As: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.maximum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "max:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .UndefinedAttributeType)
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
@@ -241,23 +241,23 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.Minimum("attribute")
XCTAssertEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.minimum("attribute")
XCTAssertEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "min:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "min(attribute)")
XCTAssertTrue(nativeType == .UndefinedAttributeType)
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
@@ -265,23 +265,23 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.Minimum("attribute", As: "alias")
XCTAssertEqual(term, SelectTerm.Minimum("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute", As: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.minimum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "min:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .UndefinedAttributeType)
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
@@ -294,23 +294,23 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.Sum("attribute")
XCTAssertEqual(term, SelectTerm.Sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.sum("attribute")
XCTAssertEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "sum:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "sum(attribute)")
XCTAssertTrue(nativeType == .DecimalAttributeType)
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
@@ -318,23 +318,23 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.Sum("attribute", As: "alias")
XCTAssertEqual(term, SelectTerm.Sum("attribute", As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute", As: "alias2"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
let term = SelectTerm.sum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "sum:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .DecimalAttributeType)
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
@@ -347,20 +347,20 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.ObjectID()
XCTAssertEqual(term, SelectTerm.ObjectID())
XCTAssertNotEqual(term, SelectTerm.ObjectID(As: "alias"))
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
let term = SelectTerm.objectID()
XCTAssertEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
switch term {
case ._Identity(let alias, let nativeType):
case ._identity(let alias, let nativeType):
XCTAssertEqual(alias, "objectID")
XCTAssertTrue(nativeType == .ObjectIDAttributeType)
XCTAssertTrue(nativeType == .objectIDAttributeType)
default:
XCTFail()
@@ -368,21 +368,21 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.ObjectID(As: "alias")
XCTAssertEqual(term, SelectTerm.ObjectID(As: "alias"))
XCTAssertNotEqual(term, SelectTerm.ObjectID(As: "alias2"))
XCTAssertNotEqual(term, SelectTerm.ObjectID())
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
let term = SelectTerm.objectID(as: "alias")
XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
switch term {
case ._Identity(let alias, let nativeType):
case ._identity(let alias, let nativeType):
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .ObjectIDAttributeType)
XCTAssertTrue(nativeType == .objectIDAttributeType)
default:
XCTFail()
@@ -393,9 +393,9 @@ final class SelectTests: XCTestCase {
@objc
dynamic func test_ThatSelectClauses_ConfigureCorrectly() {
let term1 = SelectTerm.Attribute("attribute1")
let term2 = SelectTerm.Attribute("attribute2")
let term3 = SelectTerm.Attribute("attribute3")
let term1 = SelectTerm.attribute("attribute1")
let term2 = SelectTerm.attribute("attribute2")
let term3 = SelectTerm.attribute("attribute3")
do {
let select = Select<Int>(term1, term2, term3)

View File

@@ -29,20 +29,24 @@ import CoreStore
// MARK: - SetupTests
class SetupTests: BaseTestCase {
class SetupTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatDataStacks_ConfigureCorrectly() {
do {
let model = NSManagedObjectModel.mergedModelFromBundles([NSBundle(forClass: self.dynamicType)])!
let model = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!
let stack = DataStack(model: model, migrationChain: nil)
XCTAssertEqual(stack.coordinator.managedObjectModel, model)
XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator)
XCTAssertNil(stack.rootSavingContext.parentContext)
XCTAssertEqual(stack.mainContext.parentContext, stack.rootSavingContext)
XCTAssertNil(stack.rootSavingContext.parent)
XCTAssertFalse(stack.rootSavingContext.isDataStackContext)
XCTAssertFalse(stack.rootSavingContext.isTransactionContext)
XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
XCTAssertTrue(stack.mainContext.isDataStackContext)
XCTAssertFalse(stack.mainContext.isTransactionContext)
XCTAssertEqual(stack.model, model)
XCTAssertTrue(stack.migrationChain.valid)
XCTAssertTrue(stack.migrationChain.empty)
@@ -56,11 +60,11 @@ class SetupTests: BaseTestCase {
let migrationChain: MigrationChain = ["version1", "version2", "version3"]
let stack = self.expectLogger([.LogWarning]) {
let stack = self.expectLogger([.logWarning]) {
DataStack(
modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType),
bundle: Bundle(for: type(of: self)),
migrationChain: migrationChain
)
}
@@ -77,7 +81,7 @@ class SetupTests: BaseTestCase {
let stack = DataStack(
modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType)
bundle: Bundle(for: type(of: self))
)
do {
@@ -132,7 +136,7 @@ class SetupTests: BaseTestCase {
let stack = DataStack(
modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType)
bundle: Bundle(for: type(of: self))
)
do {
@@ -154,7 +158,7 @@ class SetupTests: BaseTestCase {
let sqliteStore = SQLiteStore(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
@@ -173,7 +177,7 @@ class SetupTests: BaseTestCase {
let sqliteStore = SQLiteStore(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
@@ -189,16 +193,72 @@ class SetupTests: BaseTestCase {
}
}
@objc
dynamic func test_ThatSQLiteStores_DeleteFilesCorrectly() {
let fileManager = FileManager.default
let sqliteStore = SQLiteStore()
func createStore() throws -> [String: Any] {
do {
let stack = DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self))
)
try! stack.addStorageAndWait(sqliteStore)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: sqliteStore).storeType,
at: sqliteStore.fileURL,
options: sqliteStore.storeOptions
)
}
do {
let metadata = try createStore()
let stack = DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self))
)
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: stack.model[metadata])
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
do {
let metadata = try createStore()
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
}
@objc
dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() {
let stack = DataStack(
modelName: "Model",
bundle: NSBundle(forClass: self.dynamicType)
bundle: Bundle(for: type(of: self))
)
do {
let sqliteStore = SQLiteStore()
let sqliteStore = LegacySQLiteStore()
do {
try stack.addStorageAndWait(sqliteStore)
@@ -213,10 +273,10 @@ class SetupTests: BaseTestCase {
}
do {
let sqliteStore = SQLiteStore(
let sqliteStore = LegacySQLiteStore(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
@@ -232,10 +292,10 @@ class SetupTests: BaseTestCase {
}
do {
let sqliteStore = SQLiteStore(
let sqliteStore = LegacySQLiteStore(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
@@ -250,4 +310,60 @@ class SetupTests: BaseTestCase {
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
}
}
@objc
dynamic func test_ThatLegacySQLiteStores_DeleteFilesCorrectly() {
let fileManager = FileManager.default
let sqliteStore = LegacySQLiteStore()
func createStore() throws -> [String: Any] {
do {
let stack = DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self))
)
try! stack.addStorageAndWait(sqliteStore)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: sqliteStore).storeType,
at: sqliteStore.fileURL,
options: sqliteStore.storeOptions
)
}
do {
let metadata = try createStore()
let stack = DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self))
)
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: stack.model[metadata])
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
do {
let metadata = try createStore()
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
}
}

View File

@@ -37,7 +37,7 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatDefaultInMemoryStores_ConfigureCorrectly() {
let store = InMemoryStore()
XCTAssertEqual(store.dynamicType.storeType, NSInMemoryStoreType)
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertNil(store.configuration)
XCTAssertNil(store.storeOptions)
}
@@ -46,7 +46,7 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatCustomInMemoryStores_ConfigureCorrectly() {
let store = InMemoryStore(configuration: "config1")
XCTAssertEqual(store.dynamicType.storeType, NSInMemoryStoreType)
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertNil(store.storeOptions)
}
@@ -55,24 +55,23 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatSQLiteStoreDefaultDirectories_AreCorrect() {
#if os(tvOS)
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif
let defaultSystemDirectory = NSFileManager
.defaultManager()
.URLsForDirectory(systemDirectorySearchPath, inDomains: .UserDomainMask).first!
let defaultSystemDirectory = FileManager.default
.urls(for: systemDirectorySearchPath, in: .userDomainMask).first!
let defaultRootDirectory = defaultSystemDirectory.URLByAppendingPathComponent(
NSBundle.mainBundle().bundleIdentifier ?? "com.CoreStore.DataStack",
let defaultRootDirectory = defaultSystemDirectory.appendingPathComponent(
Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
isDirectory: true
)
let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData"
let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
let defaultFileURL = defaultRootDirectory
.URLByAppendingPathComponent(applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
.appendingPathComponent(applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
XCTAssertEqual(SQLiteStore.defaultRootDirectory, defaultRootDirectory)
XCTAssertEqual(SQLiteStore.defaultFileURL, defaultFileURL)
@@ -82,77 +81,76 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatDefaultSQLiteStores_ConfigureCorrectly() {
let store = SQLiteStore()
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL)
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles())
XCTAssertEqual(store.localStorageOptions, [.None])
XCTAssertEqual(store.mappingModelBundles, Bundle.allBundles)
XCTAssertEqual(store.localStorageOptions, .none)
}
@objc
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false)
.URLByAppendingPathExtension("db")
let bundles = [NSBundle(forClass: self.dynamicType)]
.appendingPathComponent(NSUUID().uuidString, isDirectory: false)!
.appendingPathExtension("db")
let bundles = [Bundle(for: type(of: self))]
let store = SQLiteStore(
fileURL: fileURL,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, fileURL)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@objc
dynamic func test_ThatFileNameSQLiteStores_ConfigureCorrectly() {
let fileName = NSUUID().UUIDString + ".db"
let bundles = [NSBundle(forClass: self.dynamicType)]
let fileName = UUID().uuidString + ".db"
let bundles = [Bundle(for: type(of: self))]
let store = SQLiteStore(
fileName: fileName,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL.URLByDeletingLastPathComponent, SQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@objc
dynamic func test_ThatLegacySQLiteStoreDefaultDirectories_AreCorrect() {
#if os(tvOS)
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif
let legacyDefaultRootDirectory = NSFileManager.defaultManager().URLsForDirectory(
systemDirectorySearchPath,
inDomains: .UserDomainMask
).first!
let legacyDefaultRootDirectory = FileManager.default.urls(
for: systemDirectorySearchPath,
in: .userDomainMask).first!
let legacyDefaultFileURL = legacyDefaultRootDirectory
.URLByAppendingPathComponent(DataStack.applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
XCTAssertEqual(LegacySQLiteStore.defaultRootDirectory, legacyDefaultRootDirectory)
XCTAssertEqual(LegacySQLiteStore.defaultFileURL, legacyDefaultFileURL)
@@ -162,57 +160,57 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatDefaultLegacySQLiteStores_ConfigureCorrectly() {
let store = LegacySQLiteStore()
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, LegacySQLiteStore.defaultFileURL)
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles())
XCTAssertEqual(store.localStorageOptions, [.None])
XCTAssertEqual(store.mappingModelBundles, Bundle.allBundles)
XCTAssertEqual(store.localStorageOptions, .none)
}
@objc
dynamic func test_ThatFileURLLegacySQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false)
.URLByAppendingPathExtension("db")
let bundles = [NSBundle(forClass: self.dynamicType)]
.appendingPathComponent(NSUUID().uuidString, isDirectory: false)!
.appendingPathExtension("db")
let bundles = [Bundle(for: type(of: self))]
let store = LegacySQLiteStore(
fileURL: fileURL,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, fileURL)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@objc
dynamic func test_ThatFileNameLegacySQLiteStores_ConfigureCorrectly() {
let fileName = NSUUID().UUIDString + ".db"
let bundles = [NSBundle(forClass: self.dynamicType)]
let fileName = UUID().uuidString + ".db"
let bundles = [Bundle(for: type(of: self))]
let store = LegacySQLiteStore(
fileName: fileName,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .RecreateStoreOnModelMismatch
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL.URLByDeletingLastPathComponent, LegacySQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), LegacySQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
}

View File

@@ -31,9 +31,9 @@ class TestEntity1: NSManagedObject {
@NSManaged var testEntityID: NSNumber?
@NSManaged var testString: String?
@NSManaged var testNumber: NSNumber?
@NSManaged var testDate: NSDate?
@NSManaged var testDate: Date?
@NSManaged var testBoolean: NSNumber?
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: NSData?
@NSManaged var testData: Data?
@NSManaged var testNil: String?
}

View File

@@ -31,9 +31,9 @@ class TestEntity2: NSManagedObject {
@NSManaged var testEntityID: NSNumber?
@NSManaged var testString: String?
@NSManaged var testNumber: NSNumber?
@NSManaged var testDate: NSDate?
@NSManaged var testDate: Date?
@NSManaged var testBoolean: NSNumber?
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: NSData?
@NSManaged var testData: Data?
@NSManaged var testNil: String?
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -87,6 +87,211 @@ final class WhereTests: XCTestCase {
}
}
@objc
dynamic func test_ThatWhereClauses_BridgeArgumentsCorrectly() {
do {
let value: Int = 100
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", NSNumber(value: value))
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", NSNumber(value: value))
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
do {
let value = NSNumber(value: 100)
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", value.intValue)
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", value.intValue)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
do {
let value: Int64 = Int64.max
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", NSNumber(value: value))
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", NSNumber(value: value))
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
do {
let value = NSNumber(value: Int64.max)
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", value.int64Value)
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", value.int64Value)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
do {
let value: String = "value"
let whereClause1 = Where("%K == %s", "key", value)
let whereClause2 = Where("%K == %s", "key", value as AnyObject)
let whereClause3 = Where("%K == %s", "key", NSString(string: value))
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", NSString(string: value))
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
do {
let value = NSString(string: "value")
let whereClause1 = Where("%K == %s", "key", value)
let whereClause2 = Where("%K == %s", "key", value as String)
let whereClause3 = Where("%K == %s", "key", value as String as AnyObject)
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as String)
let whereClause6 = Where("%K == %@", "key", value as String as AnyObject)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
do {
let value: [Int] = [100, 200]
let whereClause1 = Where("%K == %@", "key", value)
let whereClause2 = Where("%K == %@", "key", value as AnyObject)
let whereClause3 = Where("%K == %@", "key", value as [AnyObject])
let whereClause4 = Where("%K == %@", "key", value as NSArray)
let whereClause5 = Where("%K == %@", "key", NSArray(array: value))
let whereClause6 = Where("%K == %@", "key", value as AnyObject as! NSArray)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
do {
let value: [Int64] = [Int64.min, 100, Int64.max]
let whereClause1 = Where("%K == %@", "key", value)
let whereClause2 = Where("%K == %@", "key", value as AnyObject)
let whereClause3 = Where("%K == %@", "key", value as [AnyObject])
let whereClause4 = Where("%K == %@", "key", value as NSArray)
let whereClause5 = Where("%K == %@", "key", NSArray(array: value))
let whereClause6 = Where("%K == %@", "key", value as AnyObject as! NSArray)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
}
}
@objc
dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() {
@@ -98,7 +303,7 @@ final class WhereTests: XCTestCase {
let notWhere = !whereClause1
let notPredicate = NSCompoundPredicate(
type: .NotPredicateType,
type: .not,
subpredicates: [whereClause1.predicate]
)
XCTAssertEqual(notWhere.predicate, notPredicate)
@@ -108,10 +313,10 @@ final class WhereTests: XCTestCase {
let andWhere = whereClause1 && whereClause2 && whereClause3
let andPredicate = NSCompoundPredicate(
type: .AndPredicateType,
type: .and,
subpredicates: [
NSCompoundPredicate(
type: .AndPredicateType,
type: .and,
subpredicates: [whereClause1.predicate, whereClause2.predicate]
),
whereClause3.predicate
@@ -124,10 +329,10 @@ final class WhereTests: XCTestCase {
let orWhere = whereClause1 || whereClause2 || whereClause3
let orPredicate = NSCompoundPredicate(
type: .OrPredicateType,
type: .or,
subpredicates: [
NSCompoundPredicate(
type: .OrPredicateType,
type: .or,
subpredicates: [whereClause1.predicate, whereClause2.predicate]
),
whereClause3.predicate
@@ -142,7 +347,7 @@ final class WhereTests: XCTestCase {
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where("key", isEqualTo: "value")
let request = NSFetchRequest()
let request = CoreStoreFetchRequest()
whereClause.applyToFetchRequest(request)
XCTAssertNotNil(request.predicate)
XCTAssertEqual(request.predicate, whereClause.predicate)

View File

@@ -41,11 +41,5 @@ targets = []
let package = Package(
name: "CoreStore",
targets: targets,
dependencies: [
.Package(
url: "https://github.com/JohnEstropia/GCDKit.git",
"1.2.6"
)
],
exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"]
)

259
README.md
View File

@@ -17,11 +17,10 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
<a href="https://twitter.com/JohnEstropia"><img alt="Reach me on Twitter!" src="https://img.shields.io/badge/twitter-%40JohnEstropia-3498db.svg" /></a>
<br />
</p>
* Swift 2.2 (Xcode 7.3)
* iOS 7+ / macOS 10.10+ / watchOS 2.0+ / tvOS 9.0+
* **New in CoreStore 2.0:** Objective-C support! All CoreStore types now have their corresponding Objective-C "bridging classes". Perfect for projects transitioning from Objective-C to Swift!
Upgrading from CoreStore 1.x to 2.x? Check out the [new features](#new-in-corestore-20) and make sure to read the [Migration guide](#upgrading-from-1xx-to-2xx).
* **Swift 3.0.1:** iOS 8+ / macOS 10.10+ / watchOS 2.0+ / tvOS 9.0+
Upgrading from CoreStore 2.x to 3.x? Check out the [new features](#features) and make sure to read the [Migration guide](#upgrading-from-2xx-to-3xx).
## Why use CoreStore?
@@ -40,12 +39,10 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
- **Efficient importing utilities.** Map your entities once with their corresponding import source (JSON for example), and importing from *transactions* becomes elegant. Uniquing is also done with an efficient find-and-replace algorithm. *(See [Importing data](#importing-data))*
- **Tight design around Swifts code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features.
- **Full Documentation.** No magic here; all public classes, functions, properties, etc. have detailed *Apple Docs*. This *README* also introduces a lot of concepts and explains a lot of CoreStore's behavior.
### New in CoreStore 2.0
- **Informative (and pretty) logs.** All CoreStore and Core Data-related types now have very informative and pretty print outputs! *(See [Logging and error reporting](#logging-and-error-reporting))*
- **Objective-C support!** Is your project transitioning from Objective-C to Swift but still can't quite fully convert some huge classes to Swift yet? CoreStore 2.0 is the answer to the ever-increasing Swift adoption. While still written in pure Swift, all CoreStore types now have their corresponding Objective-C-visible "bridging classes". *(See [Objective-C support](#objective-c-support))*
- **iCloud storage (beta) support.** CoreStore now allows creation of iCloud persistent stores, as well as observing of iCloud-related events through the `ICloudStoreObserver`. *(See [iCloud storage](#icloud-storages))*
- **More extensive Unit Tests.** Extending CoreStore is now safer without having to worry about breaking old behavior.
- **Objective-C support!** Is your project transitioning from Objective-C to Swift but still can't quite fully convert some huge classes to Swift yet? CoreStore adjusts to the ever-increasing Swift adoption. While still written in pure Swift, all CoreStore types have their corresponding Objective-C-visible "bridging classes". *(See [Objective-C support](#objective-c-support))*
- **iCloud storage (beta) support.** CoreStore allows creation of iCloud persistent stores, as well as observing of iCloud-related events through the `ICloudStoreObserver`. *(See [iCloud storage](#icloud-storages))*
- **More extensive Unit Tests.** Extending CoreStore is safe without having to worry about breaking old behavior.
*Have ideas that may benefit other Core Data users? [Feature Request](https://github.com/JohnEstropia/CoreStore/issues)s are welcome!*
@@ -88,6 +85,7 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
- [Roadmap](#roadmap)
- [Installation](#installation)
- [Changesets](#changesets)
- [Upgrading from 2.x.x to 3.x.x](#upgrading-from-2xx-to-3xx)
- [Upgrading from 1.x.x to 2.x.x](#upgrading-from-1xx-to-2xx)
- [Contact](#contact)
- [Who uses CoreStore?](#who-uses-corestore)
@@ -118,14 +116,14 @@ CoreStore.addStorage(
Starting transactions:
```swift
CoreStore.beginAsynchronous { (transaction) -> Void in
let person = transaction.create(Into(MyPersonEntity))
let person = transaction.create(Into<MyPersonEntity>())
person.name = "John Smith"
person.age = 42
transaction.commit { (result) -> Void in
switch result {
case .Success(let hasChanges): print("success!")
case .Failure(let error): print(error)
case .success(let hasChanges): print("success!")
case .failure(let error): print(error)
}
}
}
@@ -133,15 +131,15 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
Fetching objects (simple):
```swift
let people = CoreStore.fetchAll(From(MyPersonEntity))
let people = CoreStore.fetchAll(From<MyPersonEntity>())
```
Fetching objects (complex):
```swift
let people = CoreStore.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where("age > 30"),
OrderBy(.Ascending("name"), .Descending("age")),
OrderBy(.ascending("name"), .descending("age")),
Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false
}
@@ -151,8 +149,8 @@ let people = CoreStore.fetchAll(
Querying values:
```swift
let maxAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Maximum("age"))
From<MyPersonEntity>(),
Select<Int>(.maximum("age"))
)
```
@@ -206,13 +204,13 @@ let migrationProgress = dataStack.addStorage(
SQLiteStore(
fileURL: sqliteFileURL, // set the target file URL for the sqlite file
configuration: "Config2", // use entities from the "Config2" configuration in the .xcdatamodeld file
localStorageOptions: .RecreateStoreOnModelMismatch // if migration paths cannot be resolved, recreate the sqlite file
localStorageOptions: .recreateStoreOnModelMismatch // if migration paths cannot be resolved, recreate the sqlite file
),
completion: { (result) -> Void in
switch result {
case .Success(let storage):
case .success(let storage):
print("Successfully added sqlite store: \(storage)"
case .Failure(let error):
case .failure(let error):
print("Failed adding sqlite store with error: \(error)"
}
}
@@ -231,7 +229,7 @@ class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
try self.dataStack.addStorageAndWait(SQLiteStore)
try self.dataStack.addStorageAndWait(SQLiteStore.self)
}
catch { // ...
}
@@ -249,7 +247,7 @@ class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
try CoreStore.addStorageAndWait(SQLiteStore)
try CoreStore.addStorageAndWait(SQLiteStore.self)
}
catch { // ...
}
@@ -274,7 +272,7 @@ try CoreStore.addStorageAndWait(
```
`InMemoryStore`s also implement the `DefaultInitializableStore` sugar protocol which tells CoreStore that this store can initialize without any arguments (`init()`). This lets us provide just the type instead of an instance:
```swift
try CoreStore.addStorageAndWait(InMemoryStore)
try CoreStore.addStorageAndWait(InMemoryStore.self)
```
### Local Store
@@ -285,7 +283,7 @@ let migrationProgress = CoreStore.addStorage(
fileName: "MyStore.sqlite",
configuration: "Config2", // optional. Use entities from the "Config2" configuration in the .xcdatamodeld file
mappingModelBundles: [NSBundle.mainBundle()], // optional. The bundles that contain required .xcmappingmodel files, if any
localStorageOptions: .RecreateStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store
localStorageOptions: .recreateStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store
),
completion: { /* ... */ }
)
@@ -294,7 +292,7 @@ Refer to the *SQLiteStore.swift* source documentation for detailed explanations
CoreStore can decide the default values for these properties, so `SQLiteStore`s also implement the `DefaultInitializableStore` sugar protocol which lets us write:
```swift
try CoreStore.addStorageAndWait(SQLiteStore)
try CoreStore.addStorageAndWait(SQLiteStore.self)
```
or
```swift
@@ -307,8 +305,8 @@ public protocol LocalStorage: StorageInterface {
var fileURL: NSURL { get }
var mappingModelBundles: [NSBundle] { get }
var localStorageOptions: LocalStorageOptions { get }
func storeOptionsForOptions(options: LocalStorageOptions) -> [String: AnyObject]?
func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws
func dictionary(forOptions: LocalStorageOptions) -> [String: AnyObject]?
func eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws
}
```
If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`.
@@ -324,7 +322,7 @@ guard let storage = ICloudStore(
ubiquitousContainerID: "iCloud.com.mycompany.myapp.containername", // optional. The container if your app has multiple ubiquity container identifiers in its entitlements
ubiquitousPeerToken: "9614d658014f4151a95d8048fb717cf0", // optional. A per-application salt to allow multiple apps on the same device to share a Core Data store integrated with iCloud
configuration: "Config1", // optional. Use entities from the "Config1" configuration in the .xcdatamodeld file
cloudStorageOptions: .RecreateLocalStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store
cloudStorageOptions: .recreateLocalStoreOnModelMismatch // optional. Provides settings that tells the DataStack how to setup the persistent store
) else {
// The iCloud container could not be located or if iCloud is not available on the device.
// Handle appropriately
@@ -334,8 +332,8 @@ CoreStore.addStorage(,
storage,
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
@@ -365,8 +363,8 @@ CoreStore.addStorage(,
storage,
completion: { result in
switch result {
case .Success(let storage): // ... You may also call storage.addObserver(_:) here
case .Failure(let error): // ...
case .success(let storage): // ... You may also call storage.addObserver(_:) here
case .failure(let error): // ...
}
}
)
@@ -375,12 +373,12 @@ The `ICloudStore` only keeps weak references of the registered observers. You ma
## Migrations
We have seen `addStorageAndWait(...)` used to initialize our persistent store. As the method name's "AndWait" suffix suggests though, this method blocks so it should not do long tasks such as store migrations. In fact CoreStore will only attempt a synchronous **lightweight** migration if you explicitly provide the `.AllowSynchronousLightweightMigration` option:
We have seen `addStorageAndWait(...)` used to initialize our persistent store. As the method name's "AndWait" suffix suggests though, this method blocks so it should not do long tasks such as store migrations. In fact CoreStore will only attempt a synchronous **lightweight** migration if you explicitly provide the `.allowSynchronousLightweightMigration` option:
```swift
try dataStack.addStorageAndWait(
SQLiteStore(
fileURL: sqliteFileURL,
localStorageOptions: .AllowSynchronousLightweightMigration
localStorageOptions: .allowSynchronousLightweightMigration
)
}
```
@@ -388,16 +386,16 @@ if you do so, any model mismatch will be thrown as an error.
In general though, if migrations are expected the asynchronous variant `addStorage(_:completion:)` method is recommended instead:
```swift
let migrationProgress: NSProgress? = try dataStack.addStorage(
let migrationProgress: Progress? = try dataStack.addStorage(
SQLiteStore(
fileName: "MyStore.sqlite",
configuration: "Config2"
),
completion: { (result) -> Void in
switch result {
case .Success(let storage):
case .success(let storage):
print("Successfully added sqlite store: \(storage)")
case .Failure(let error):
case .failure(let error):
print("Failed adding sqlite store with error: \(error)")
}
}
@@ -405,7 +403,7 @@ let migrationProgress: NSProgress? = try dataStack.addStorage(
```
The `completion` block reports a `SetupResult` that indicates success or failure.
Notice that this method also returns an optional `NSProgress`. If `nil`, no migrations are needed, thus progress reporting is unnecessary as well. If not `nil`, you can use this to track migration progress by using standard KVO on the `"fractionCompleted"` key, or by using a closure-based utility exposed in *NSProgress+Convenience.swift*:
Notice that this method also returns an optional `Progress`. If `nil`, no migrations are needed, thus progress reporting is unnecessary as well. If not `nil`, you can use this to track migration progress by using standard KVO on the `"fractionCompleted"` key, or by using a closure-based utility exposed in *Progress+Convenience.swift*:
```swift
migrationProgress?.setProgressHandler { [weak self] (progress) -> Void in
self?.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
@@ -555,7 +553,7 @@ You've seen how to create transactions, but we have yet to see how to make *crea
The `create(...)` method accepts an `Into` clause which specifies the entity for the object you want to create:
```swift
let person = transaction.create(Into(MyPersonEntity))
let person = transaction.create(Into<MyPersonEntity>())
```
While the syntax is straightforward, CoreStore does not just naively insert a new object. This single line does the following:
- Checks that the entity type exists in any of the transaction's parent persistent store
@@ -578,7 +576,7 @@ Note that if you do explicitly specify the configuration name, CoreStore will on
After creating an object from the transaction, you can simply update its properties as normal:
```swift
CoreStore.beginAsynchronous { (transaction) -> Void in
let person = transaction.create(Into(MyPersonEntity))
let person = transaction.create(Into<MyPersonEntity>())
person.name = "John Smith"
person.age = 30
transaction.commit()
@@ -588,7 +586,7 @@ To update an existing object, fetch the object's instance from the transaction:
```swift
CoreStore.beginAsynchronous { (transaction) -> Void in
let person = transaction.fetchOne(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where("name", isEqualTo: "Jane Smith")
)
person.age = person.age + 1
@@ -650,7 +648,7 @@ If you do not have references yet to the objects to be deleted, transactions hav
```swift
CoreStore.beginAsynchronous { (transaction) -> Void in
transaction.deleteAll(
From(MyPersonEntity)
From<MyPersonEntity>(),
Where("age > 30")
)
transaction.commit()
@@ -688,7 +686,7 @@ var peopleIDs: [NSManagedObjectID] = // ...
CoreStore.beginAsynchronous { (transaction) -> Void in
let jane = transaction.fetchOne(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where("name", isEqualTo: "Jane Smith")
)
jane.friends = NSSet(array: transaction.fetchExisting(peopleIDs)!)
@@ -710,7 +708,7 @@ If you have many attributes, you don't want to keep repeating this mapping every
CoreStore.beginAsynchronous { (transaction) -> Void in
let json: [String: AnyObject] = // ...
try! transaction.importObject(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
source: json
)
transaction.commit()
@@ -737,8 +735,8 @@ You can even use external types from popular 3rd-party JSON libraries ([SwiftyJS
```swift
public protocol ImportableObject: class {
typealias ImportSource
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
}
```
First, set `ImportSource` to the expected type of the data source:
@@ -750,15 +748,15 @@ This lets us call `importObject(_:source:)` with any `[String: AnyObject]` type
CoreStore.beginAsynchronous { (transaction) -> Void in
let json: [String: AnyObject] = // ...
try! transaction.importObject(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
source: json
)
// ...
}
```
The actual extraction and assignment of values should be implemented in the `didInsertFromImportSource(...)` method of the `ImportableObject` protocol:
The actual extraction and assignment of values should be implemented in the `didInsert(from:in:)` method of the `ImportableObject` protocol:
```swift
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws {
self.name = source["name"] as? NSString
self.age = source["age"] as? NSNumber
// ...
@@ -769,17 +767,17 @@ Transactions also let you import multiple objects at once using the `importObjec
CoreStore.beginAsynchronous { (transaction) -> Void in
let jsonArray: [[String: AnyObject]] = // ...
try! transaction.importObjects(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
sourceArray: jsonArray
)
// ...
}
```
Doing so tells the transaction to iterate through the array of import sources and calls `shouldInsertFromImportSource(...)` on the `ImportableObject` to determine which instances should be created. You can do validations and return `false` from `shouldInsertFromImportSource(...)` if you want to skip importing from a source and continue on with the other sources in the array.
Doing so tells the transaction to iterate through the array of import sources and calls `shouldInsert(from:in:)` on the `ImportableObject` to determine which instances should be created. You can do validations and return `false` from `shouldInsert(from:in:)` if you want to skip importing from a source and continue on with the other sources in the array.
If on the other hand, your validation in one of the sources failed in such a manner that all other sources should also be cancelled, you can `throw` from within `didInsertFromImportSource(...)`:
If on the other hand, your validation in one of the sources failed in such a manner that all other sources should also be cancelled, you can `throw` from within `didInsert(from:in:)`:
```swift
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws {
self.name = source["name"] as? NSString
self.age = source["age"] as? NSNumber
// ...
@@ -794,7 +792,7 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
let jsonArray: [[String: AnyObject]] = // ...
do {
try transaction.importObjects(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
sourceArray: jsonArray
)
}
@@ -817,11 +815,11 @@ public protocol ImportableUniqueObject: ImportableObject {
static var uniqueIDKeyPath: String { get }
var uniqueIDValue: UniqueIDType { get set }
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
static func shouldUpdateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
static func uniqueIDFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType?
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
func updateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
static func shouldInsert(from source: ImportSource, inn transaction: BaseDataTransaction) -> Bool
static func shouldUpdate(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
static func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> UniqueIDType?
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
func update(from source: ImportSource, in transaction: BaseDataTransaction) throws
}
```
Notice that it has the same insert methods as `ImportableObject`, with additional methods for updates and for specifying the unique ID:
@@ -833,18 +831,18 @@ var uniqueIDValue: NSNumber {
get { return self.personID }
set { self.personID = newValue }
}
class func uniqueIDFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> NSNumber? {
class func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> NSNumber? {
return source["id"] as? NSNumber
}
```
For `ImportableUniqueObject`, the extraction and assignment of values should be implemented from the `updateFromImportSource(...)` method. The `didInsertFromImportSource(...)` by default calls `updateFromImportSource(...)`, but you can separate the implementation for inserts and updates if needed.
For `ImportableUniqueObject`, the extraction and assignment of values should be implemented from the `update(from:in:)` method. The `didInsert(from:in:)` by default calls `update(from:in:)`, but you can separate the implementation for inserts and updates if needed.
You can then create/update an object by calling a transaction's `importUniqueObject(...)` method:
```swift
CoreStore.beginAsynchronous { (transaction) -> Void in
let json: [String: AnyObject] = // ...
try! transaction.importUniqueObject(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
source: json
)
// ...
@@ -856,14 +854,14 @@ or multiple objects at once with the `importUniqueObjects(...)` method:
CoreStore.beginAsynchronous { (transaction) -> Void in
let jsonArray: [[String: AnyObject]] = // ...
try! transaction.importUniqueObjects(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
sourceArray: jsonArray
)
// ...
}
```
As with `ImportableObject`, you can control wether to skip importing an object by implementing
`shouldInsertFromImportSource(...)` and `shouldUpdateFromImportSource(...)`, or to cancel all objects by `throw`ing an error from the `uniqueIDFromImportSource(...)`, `didInsertFromImportSource(...)` or `updateFromImportSource(...)` methods.
`shouldInsert(from:in:)` and `shouldUpdate(from:in:)`, or to cancel all objects by `throw`ing an error from the `uniqueID(from:in:)`, `didInsert(from:in:)` or `update(from:in:)` methods.
## Fetching and Querying
@@ -880,10 +878,10 @@ Before we dive in, be aware that CoreStore distinguishes between *fetching* and
#### `From` clause
The search conditions for fetches and queries are specified using *clauses*. All fetches and queries require a `From` clause that indicates the target entity type:
```swift
let people = CoreStore.fetchAll(From(MyPersonEntity))
let people = CoreStore.fetchAll(From<MyPersonEntity>())
// CoreStore.fetchAll(From<MyPersonEntity>()) works as well
```
`people` in the example above will be of type `[MyPersonEntity]`. The `From(MyPersonEntity)` clause indicates a fetch to all persistent stores that `MyPersonEntity` belong to.
`people` in the example above will be of type `[MyPersonEntity]`. The `From<MyPersonEntity>()` clause indicates a fetch to all persistent stores that `MyPersonEntity` belong to.
If the entity exists in multiple configurations and you need to only search from a particular configuration, indicate in the `From` clause the configuration name for the destination persistent store:
```swift
@@ -912,11 +910,11 @@ Each method's purpose is straightforward, but we need to understand how to set t
The `Where` clause is CoreStore's `NSPredicate` wrapper. It specifies the search filter to use when fetching (or querying). It implements all initializers that `NSPredicate` does (except for `-predicateWithBlock:`, which Core Data does not support):
```swift
var people = CoreStore.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where("%K > %d", "age", 30) // string format initializer
)
people = CoreStore.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where(true) // boolean initializer
)
```
@@ -924,14 +922,14 @@ If you do have an existing `NSPredicate` instance already, you can pass that to
```swift
let predicate = NSPredicate(...)
var people = CoreStore.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where(predicate) // predicate initializer
)
```
`Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings:
```swift
var people = CoreStore.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where("age > %d", 30) && Where("gender == %@", "M")
)
```
@@ -942,20 +940,20 @@ If you do not provide a `Where` clause, all objects that belong to the specified
The `OrderBy` clause is CoreStore's `NSSortDescriptor` wrapper. Use it to specify attribute keys in which to sort the fetch (or query) results with.
```swift
var mostValuablePeople = CoreStore.fetchAll(
From(MyPersonEntity),
OrderBy(.Descending("rating"), .Ascending("surname"))
From<MyPersonEntity>(),
OrderBy(.descending("rating"), .ascending("surname"))
)
```
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.Ascending` or `.Descending`.
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.ascending` or `.descending`.
You can use the `+` and `+=` operator to append `OrderBy`s together. This is useful when sorting conditionally:
```swift
var orderBy = OrderBy(.Descending("rating"))
var orderBy = OrderBy(.descending("rating"))
if sortFromYoungest {
orderBy += OrderBy(.Ascending("age"))
orderBy += OrderBy(.ascending("age"))
}
var mostValuablePeople = CoreStore.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
orderBy
)
```
@@ -965,9 +963,9 @@ var mostValuablePeople = CoreStore.fetchAll(
The `Tweak` clause lets you, uh, *tweak* the fetch (or query). `Tweak` exposes the `NSFetchRequest` in a closure where you can make changes to its properties:
```swift
var people = CoreStore.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where("age > %d", 30),
OrderBy(.Ascending("surname")),
OrderBy(.ascending("surname")),
Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false
fetchRequest.returnsObjectsAsFaults = false
@@ -996,7 +994,7 @@ Setting up the `From`, `Where`, `OrderBy`, and `Tweak` clauses is similar to how
The `Select<T>` clause specifies the target attribute/aggregate key, as well as the expected return type:
```swift
let johnsAge = CoreStore.queryValue(
From(MyPersonEntity),
From<MyPersonEntity>(),
Select<Int>("age"),
Where("name == %@", "John Smith")
)
@@ -1021,29 +1019,29 @@ The example above queries the "age" property for the first object that matches t
For `queryAttributes(...)`, only `NSDictionary` is valid for `Select`, thus you are allowed to omit the generic type:
```swift
let allAges = CoreStore.queryAttributes(
From(MyPersonEntity),
From<MyPersonEntity>(),
Select("age")
)
```
If you only need a value for a particular attribute, you can just specify the key name (like we did with `Select<Int>("age")`), but several aggregate functions can also be used as parameter to `Select`:
- `.Average(...)`
- `.Count(...)`
- `.Maximum(...)`
- `.Minimum(...)`
- `.Sum(...)`
- `.average(...)`
- `.count(...)`
- `.maximum(...)`
- `.minimum(...)`
- `.sum(...)`
```swift
let oldestAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Maximum("age"))
From<MyPersonEntity>(),
Select<Int>(.maximum("age"))
)
```
For `queryAttributes(...)` which returns an array of dictionaries, you can specify multiple attributes/aggregates to `Select`:
```swift
let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity),
From<MyPersonEntity>(),
Select("name", "age")
)
```
@@ -1063,8 +1061,8 @@ let personJSON = CoreStore.queryAttributes(
You can also include an aggregate as well:
```swift
let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity),
Select("name", .Count("friends"))
From<MyPersonEntity>(),
Select("name", .count("friends"))
)
```
which returns:
@@ -1083,8 +1081,8 @@ which returns:
The `"count(friends)"` key name was automatically used by CoreStore, but you can specify your own key alias if you need:
```swift
let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity),
Select("name", .Count("friends", As: "friendsCount"))
From<MyPersonEntity>(),
Select("name", .count("friends", as: "friendsCount"))
)
```
which now returns:
@@ -1106,8 +1104,8 @@ which now returns:
The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value.
```swift
let personJSON = CoreStore.queryAttributes(
From(MyPersonEntity),
Select("age", .Count("age", As: "count")),
From<MyPersonEntity>(),
Select("age", .count("age", as: "count")),
GroupBy("age")
)
```
@@ -1153,7 +1151,7 @@ A couple of examples, `ListMonitor`:
<img width="369" alt="screen shot 2016-07-10 at 22 56 44" src="https://cloud.githubusercontent.com/assets/3029684/16713994/ae06e702-46f1-11e6-83a8-dee48b480bab.png" />
`CoreStoreError.MappingModelNotFoundError`:
`CoreStoreError.mappingModelNotFoundError`:
<img width="506" alt="MappingModelNotFoundError" src="https://cloud.githubusercontent.com/assets/3029684/16713962/e021f548-46f0-11e6-8100-f9b5ea6b4a08.png" />
@@ -1232,9 +1230,9 @@ Including `ListObserver`, there are 3 observer protocols you can implement depen
We then need to create a `ListMonitor` instance and register our `ListObserver` as an observer:
```swift
self.monitor = CoreStore.monitorList(
From(MyPersonEntity),
From<MyPersonEntity>(),
Where("age > 30"),
OrderBy(.Ascending("name")),
OrderBy(.ascending("name")),
Tweak { (fetchRequest) -> Void in
fetchRequest.fetchBatchSize = 20
}
@@ -1253,10 +1251,10 @@ let firstPerson = self.monitor[0]
If the list needs to be grouped into sections, create the `ListMonitor` instance with the `monitorSectionedList(...)` method and a `SectionBy` clause:
```swift
self.monitor = CoreStore.monitorSectionedList(
From(MyPersonEntity),
From<MyPersonEntity>(),
SectionBy("age"),
Where("gender", isEqualTo: "M"),
OrderBy(.Ascending("age"), .Ascending("name")),
OrderBy(.ascending("age"), .ascending("name")),
Tweak { (fetchRequest) -> Void in
fetchRequest.fetchBatchSize = 20
}
@@ -1267,11 +1265,11 @@ A list controller created this way will group the objects by the attribute key i
The `SectionBy` clause can also be passed a closure to transform the section name into a displayable string:
```swift
self.monitor = CoreStore.monitorSectionedList(
From(MyPersonEntity),
From<MyPersonEntity>(),
SectionBy("age") { (sectionName) -> String? in
"\(sectionName) years old"
},
OrderBy(.Ascending("age"), .Ascending("name"))
OrderBy(.ascending("age"), .ascending("name"))
)
```
This is useful when implementing a `UITableViewDelegate`'s section header:
@@ -1300,7 +1298,7 @@ With 2.0, all CoreStore types are still written in pure Swift, but they now have
<tr><th>Swift</th><th>Objective-C</th></tr>
<tr>
<td><pre lang=swift>
try CoreStore.addStorageAndWait(SQLiteStore)
try CoreStore.addStorageAndWait(SQLiteStore.self)
</pre></td>
<td><pre lang=objc>
NSError *error
@@ -1313,8 +1311,8 @@ CoreStore.beginAsynchronous { (transaction) in
// ...
transaction.commit { (result) in
switch result {
case .Success(let hasChanges): print(hasChanges)
case .Failure(let error): print(error)
case .success(let hasChanges): print(hasChanges)
case .failure(let error): print(error)
}
}
}
@@ -1411,13 +1409,7 @@ NSArray<MYPerson *> *objects =
CSSortAscending(CSKeyPath(MYPerson, firstName)), nil)]];
```
To use these syntax sugars, include *CoreStoreBridge.h* in your Objective-C source files. For projects that support iOS 7 (and thus cannot build CoreStore as a module), you will need to add
```
SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME)
```
to your target's `GCC_PREPROCESSOR_DEFINITIONS` build setting.
<img width="797" alt="GCC_PREPROCESSOR_DEFINITIONS" src="https://cloud.githubusercontent.com/assets/3029684/16714547/92497fc4-4701-11e6-81db-6b1a11743cc5.png" />
To use these syntax sugars, include *CoreStoreBridge.h* in your Objective-C source files.
# Roadmap
@@ -1429,14 +1421,14 @@ to your target's `GCC_PREPROCESSOR_DEFINITIONS` build setting.
# Installation
- Requires:
- iOS 7 SDK and above
- Swift 2.2 (Xcode 7.3)
- iOS 8 SDK and above
- Swift 3.0.1 (Xcode 8.2)
- Dependencies:
- [GCDKit](https://github.com/JohnEstropia/GCDKit)
- *None*
- Other notes:
- The `com.apple.CoreData.ConcurrencyDebug` debug argument should be turned off for the app. CoreStore already guarantees safety for you by making the main context read-only, and by only executing transactions serially.
### Install with CocoaPods (iOS 7 not supported)
### Install with CocoaPods
```
pod 'CoreStore'
```
@@ -1445,8 +1437,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
### Install with Carthage
In your `Cartfile`, add
```
github "JohnEstropia/CoreStore" >= 2.0.0
github "JohnEstropia/GCDKit" >= 1.2.5
github "JohnEstropia/CoreStore" >= 3.0.0
```
and run
```
@@ -1459,7 +1450,7 @@ git submodule add https://github.com/JohnEstropia/CoreStore.git <destination dir
```
Drag and drop **CoreStore.xcodeproj** to your project.
#### To install as a framework (iOS 7 not supported):
#### To install as a framework:
Drag and drop **CoreStore.xcodeproj** to your project.
#### To include directly in your app module:
@@ -1470,16 +1461,30 @@ Add all *.swift* files to your project.
To use the Objective-C syntax sugars, import *CoreStoreBridge.h* in your *.m* source files.
For projects that support iOS 7 (and thus cannot build CoreStore as a module), you will need to add
```
SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME)
```
to your target's `GCC_PREPROCESSOR_DEFINITIONS` build setting:
<img width="797" alt="GCC_PREPROCESSOR_DEFINITIONS" src="https://cloud.githubusercontent.com/assets/3029684/16714547/92497fc4-4701-11e6-81db-6b1a11743cc5.png" />
# Changesets
### Upgrading from 2.x.x to 3.x.x
**Obsoleted**
- `UnsageDataTransaction.internalContext` was removed. Accessing the internal context (or more specifically, accessing context-level methods such as fetches) are now available through the `FetchableSource` and `QueryableProtocol` protocols, which are retrievable with `NSManagedObject.fetchSource()` and `NSManagedObject.querySource()` respectively. These protocols are implemented by `DataStack` and `BaseDataTransaction`.
**Deprecated**
Methods have been renamed to better fit the [Swift 3 naming conventions](https://swift.org/documentation/api-design-guidelines/).
- `entityDescriptionForType(_:)``entityDescription(for:)`
- `objectIDForURIRepresentation(_:)``objectID(for:)`
- `ImportableObject` and `ImportableUniqueObject` protocol methods (and their variants) have been renamed. The old methods are still available, but will be removed in a future update.
- `shouldInsertFromImportSource(_:inTransaction:)``shouldInsert(from:in:)`
- `didInsertFromImportSource(_:inTransaction:)``didInsert(from:in:)`
- `shouldUpdateFromImportSource(_:inTransaction :)``shouldUpdate(from:in:)`
- `uniqueIDFromImportSource(_:inTransaction :)``uniqueID(from:in:)`
- `updateFromImportSource(_:inTransaction:)``update(from:in:)`
**Miscellaneous**
- APIs obsoleted from 2.0.0 have been removed.
- CoreStore does not depend on [GCDKit](https://github.com/JohnEstropia/GCDKit) anymore, thanks to Swift 3's better Grand Central Dispatch API.
- All enum cases are now lowercased
- `CoreStoreError` now implements the new Swift `CustomNSError` protocol for better Objective-C
bridging.
- Some methods may emit warnings for unused return values. `@discardableResult` annotations have been set to better reflect the responsibility of API users to use/inspect return values.
### Upgrading from 1.x.x to 2.x.x
**Obsoleted**
- `AsynchronousDataTransaction.rollback()` was removed. Undo and rollback functionality are now only allowed on `UnsafeDataTransaction`s

View File

@@ -26,28 +26,26 @@
import Foundation
import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - NSFetchedResultsController
// MARK: - DataStack
public extension NSFetchedResultsController {
public extension DataStack {
/**
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
Utility for creating an `NSFetchedResultsController` from the `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter dataStack: the `DataStack` to observe objects from
- 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 fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: an `NSFetchedResultsController` that observes a `DataStack`
- returns: an `NSFetchedResultsController` that observes the `DataStack`
*/
@nonobjc
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
return createFRC(
fromContext: self.mainContext,
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
@@ -56,19 +54,18 @@ public extension NSFetchedResultsController {
/**
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter dataStack: the `DataStack` to observe objects from
- 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 fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: an `NSFetchedResultsController` that observes a `DataStack`
- returns: an `NSFetchedResultsController` that observes the `DataStack`
*/
@nonobjc
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
return createFRC(
fromContext: self.mainContext,
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
@@ -76,19 +73,18 @@ public extension NSFetchedResultsController {
}
/**
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
Utility for creating an `NSFetchedResultsController` from the `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter dataStack: the `DataStack` to observe objects from
- 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.
- returns: an `NSFetchedResultsController` that observes a `DataStack`
- returns: an `NSFetchedResultsController` that observes the `DataStack`
*/
@nonobjc
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
return createFRC(
fromContext: self.mainContext,
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
@@ -96,128 +92,131 @@ public extension NSFetchedResultsController {
}
/**
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
Utility for creating an `NSFetchedResultsController` from the `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- parameter dataStack: the `DataStack` to observe objects from
- 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.
- returns: an `NSFetchedResultsController` that observes a `DataStack`
- returns: an `NSFetchedResultsController` that observes the `DataStack`
*/
@nonobjc
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
public func createFetchedResultsController<T: NSManagedObject>(forDataStack dataStack: DataStack, _ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
return createFRC(
fromContext: self.mainContext,
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
)
}
/**
Utility for creating an `NSFetchedResultsController` from an `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- parameter transaction: the `UnsafeDataTransaction` to observe objects from
- 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 fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: an `NSFetchedResultsController` that observes an `UnsafeDataTransaction`
*/
@nonobjc
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
return self.createFromContext(
transaction.context,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
)
}
/**
Utility for creating an `NSFetchedResultsController` from an `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- parameter transaction: the `UnsafeDataTransaction` to observe objects from
- 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 fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: an `NSFetchedResultsController` that observes an `UnsafeDataTransaction`
*/
@nonobjc
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return self.createFromContext(
transaction.context,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
)
}
/**
Utility for creating an `NSFetchedResultsController` from an `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- parameter transaction: the `UnsafeDataTransaction` to observe objects from
- 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.
- returns: an `NSFetchedResultsController` that observes an `UnsafeDataTransaction`
*/
@nonobjc
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
return self.createFromContext(
transaction.context,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
)
}
/**
Utility for creating an `NSFetchedResultsController` from an `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- parameter transaction: the `UnsafeDataTransaction` to observe objects from
- 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.
*/
@nonobjc
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return self.createFromContext(
transaction.context,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
)
}
// MARK: Internal
@nonobjc
internal static func createFromContext<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return CoreStoreFetchedResultsController(
context: context,
fetchRequest: fetchRequest,
from: from,
sectionBy: sectionBy,
applyFetchClauses: { fetchRequest in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false,
"An \(cs_typeName(NSFetchedResultsController)) requires a sort information. Specify from a \(cs_typeName(OrderBy)) clause or any custom \(cs_typeName(FetchClause)) that provides a sort descriptor."
)
}
)
}
}
// MARK: - UnsafeDataTransaction
public extension UnsafeDataTransaction {
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- 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 fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
return createFRC(
fromContext: self.context,
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
)
}
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- 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 fetchClauses: a series of `FetchClause` instances for fetching the object list. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
return createFRC(
fromContext: self.context,
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
)
}
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- 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.
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
return createFRC(
fromContext: self.context,
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
)
}
/**
Utility for creating an `NSFetchedResultsController` from the `UnsafeDataTransaction`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- Note: It is the caller's responsibility to call `performFetch()` on the created `NSFetchedResultsController`.
- 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.
- returns: an `NSFetchedResultsController` that observes the `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
return createFRC(
fromContext: self.context,
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
)
}
}
// MARK: - Private
fileprivate func createFRC<T: NSManagedObject>(fromContext context: NSManagedObjectContext, from: From<T>? = nil, sectionBy: SectionBy? = nil, fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
let controller = CoreStoreFetchedResultsController(
context: context,
fetchRequest: CoreStoreFetchRequest().dynamicCast(),
from: from,
sectionBy: sectionBy,
applyFetchClauses: { (fetchRequest) in
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) }
CoreStore.assert(
fetchRequest.sortDescriptors?.isEmpty == false,
"An \(cs_typeName(NSFetchedResultsController<NSManagedObject>.self)) requires a sort information. Specify from a \(cs_typeName(OrderBy.self)) clause or any custom \(cs_typeName(FetchClause.self)) that provides a sort descriptor."
)
}
)
return controller.dynamicCast()
}
#endif

View File

@@ -31,6 +31,52 @@ import CoreData
public extension NSManagedObject {
/**
Exposes a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `fetchSource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `FetchableSource.internalContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
- returns: a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
*/
@nonobjc
public func fetchSource() -> FetchableSource? {
guard let context = self.managedObjectContext else {
return nil
}
if context.isTransactionContext {
return context.parentTransaction
}
if context.isDataStackContext {
return context.parentStack
}
return context
}
/**
Exposes a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `querySource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `QueryableSource.internalContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
- returns: a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
*/
@nonobjc
public func querySource() -> QueryableSource? {
guard let context = self.managedObjectContext else {
return nil
}
if context.isTransactionContext {
return context.parentTransaction
}
if context.isDataStackContext {
return context.parentStack
}
return context
}
/**
Provides a convenience wrapper for accessing `primitiveValueForKey(...)` with proper calls to `willAccessValueForKey(...)` and `didAccessValueForKey(...)`. This is useful when implementing accessor methods for transient attributes.
@@ -38,14 +84,33 @@ public extension NSManagedObject {
- returns: the primitive value for the KVC key
*/
@nonobjc
@warn_unused_result
public func accessValueForKVCKey(KVCKey: KeyPath) -> AnyObject? {
public func accessValueForKVCKey(_ KVCKey: KeyPath) -> Any? {
self.willAccessValueForKey(KVCKey)
let primitiveValue: AnyObject? = self.primitiveValueForKey(KVCKey)
self.didAccessValueForKey(KVCKey)
self.willAccessValue(forKey: KVCKey)
defer {
self.didAccessValue(forKey: KVCKey)
}
return self.primitiveValue(forKey: KVCKey)
}
/**
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
*/
@discardableResult
@nonobjc
public func accessValueForKVCKey<T>(_ KVCKey: KeyPath, _ didAccessPrimitiveValue: (Any?) throws -> T) rethrows -> T {
return primitiveValue
self.willAccessValue(forKey: KVCKey)
defer {
self.didAccessValue(forKey: KVCKey)
}
return try didAccessPrimitiveValue(self.primitiveValue(forKey: KVCKey))
}
/**
@@ -55,11 +120,34 @@ public extension NSManagedObject {
- parameter KVCKey: the KVC key
*/
@nonobjc
public func setValue(value: AnyObject?, forKVCKey KVCKey: KeyPath) {
public func setValue(_ value: Any?, forKVCKey KVCKey: KeyPath) {
self.willChangeValueForKey(KVCKey)
self.willChangeValue(forKey: KVCKey)
defer {
self.didChangeValue(forKey: KVCKey)
}
self.setPrimitiveValue(value, forKey: KVCKey)
self.didChangeValueForKey(KVCKey)
}
/**
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(...)`
*/
@discardableResult
@nonobjc
public func setValue<T>(_ value: Any?, forKVCKey KVCKey: KeyPath, _ didSetPrimitiveValue: (Any?) throws -> T) rethrows -> T {
self.willChangeValue(forKey: KVCKey)
defer {
self.didChangeValue(forKey: KVCKey)
}
self.setPrimitiveValue(value, forKey: KVCKey)
return try didSetPrimitiveValue(value)
}
/**
@@ -68,7 +156,7 @@ public extension NSManagedObject {
@nonobjc
public func refreshAsFault() {
self.managedObjectContext?.refreshObject(self, mergeChanges: false)
self.managedObjectContext?.refresh(self, mergeChanges: false)
}
/**
@@ -77,6 +165,6 @@ public extension NSManagedObject {
@nonobjc
public func refreshAndMerge() {
self.managedObjectContext?.refreshObject(self, mergeChanges: true)
self.managedObjectContext?.refresh(self, mergeChanges: true)
}
}

View File

@@ -1,5 +1,5 @@
//
// NSProgress+Convenience.swift
// Progress+Convenience.swift
// CoreStore
//
// Copyright © 2015 John Rommel Estropia
@@ -24,22 +24,19 @@
//
import Foundation
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - NSProgress
// MARK: - Progress
public extension NSProgress {
public extension Progress {
/**
Sets a closure that the `NSProgress` calls whenever its `fractionCompleted` changes. You can use this instead of setting up KVO.
Sets a closure that the `Progress` calls whenever its `fractionCompleted` changes. You can use this instead of setting up KVO.
- parameter closure: the closure to execute on progress change
*/
@nonobjc
public func setProgressHandler(closure: ((progress: NSProgress) -> Void)?) {
public func setProgressHandler(_ closure: ((_ progress: Progress) -> Void)?) {
self.progressObserver.progressHandler = closure
}
@@ -81,8 +78,9 @@ public extension NSProgress {
@objc
private final class ProgressObserver: NSObject {
private unowned let progress: NSProgress
private var progressHandler: ((progress: NSProgress) -> Void)? {
private unowned let progress: Progress
fileprivate var progressHandler: ((_ progress: Progress) -> Void)? {
didSet {
@@ -96,19 +94,19 @@ private final class ProgressObserver: NSObject {
self.progress.addObserver(
self,
forKeyPath: "fractionCompleted",
options: [.Initial, .New],
forKeyPath: #keyPath(Progress.fractionCompleted),
options: [.initial, .new],
context: nil
)
}
else {
self.progress.removeObserver(self, forKeyPath: "fractionCompleted")
self.progress.removeObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted))
}
}
}
private init(_ progress: NSProgress) {
fileprivate init(_ progress: Progress) {
self.progress = progress
super.init()
@@ -119,20 +117,22 @@ private final class ProgressObserver: NSObject {
if let _ = self.progressHandler {
self.progressHandler = nil
self.progress.removeObserver(self, forKeyPath: "fractionCompleted")
self.progress.removeObserver(self, forKeyPath: #keyPath(Progress.fractionCompleted))
}
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let progress = object as? NSProgress where progress == self.progress && keyPath == "fractionCompleted" else {
return
guard let progress = object as? Progress,
progress == self.progress,
keyPath == #keyPath(Progress.fractionCompleted) else {
return
}
GCDQueue.Main.async { [weak self] () -> Void in
DispatchQueue.main.async { [weak self] () -> Void in
self?.progressHandler?(progress: progress)
self?.progressHandler?(progress)
}
}
}

View File

@@ -24,9 +24,6 @@
//
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - CoreStore
@@ -45,10 +42,10 @@ public enum CoreStore {
get {
self.defaultStackBarrierQueue.barrierSync {
self.defaultStackBarrierQueue.sync(flags: .barrier) {
if self.defaultStackInstance == nil {
self.defaultStackInstance = DataStack()
}
}
@@ -56,7 +53,7 @@ public enum CoreStore {
}
set {
self.defaultStackBarrierQueue.barrierAsync {
self.defaultStackBarrierQueue.async(flags: .barrier) {
self.defaultStackInstance = newValue
}
@@ -66,7 +63,7 @@ public enum CoreStore {
// MARK: Private
private static let defaultStackBarrierQueue = GCDQueue.createConcurrent("com.coreStore.defaultStackBarrierQueue")
private static let defaultStackBarrierQueue = DispatchQueue.concurrent("com.coreStore.defaultStackBarrierQueue")
private static var defaultStackInstance: DataStack?
}

View File

@@ -32,59 +32,117 @@ import CoreData
/**
All errors thrown from CoreStore are expressed in `CoreStoreError` enum values.
*/
public enum CoreStoreError: ErrorType, Hashable {
public enum CoreStoreError: Error, CustomNSError, Hashable {
/**
A failure occured because of an unknown error.
*/
case Unknown
case unknown
/**
The `NSPersistentStore` could not be initialized because another store existed at the specified `NSURL`.
*/
case DifferentStorageExistsAtURL(existingPersistentStoreURL: NSURL)
case differentStorageExistsAtURL(existingPersistentStoreURL: URL)
/**
An `NSMappingModel` could not be found for a specific source and destination model versions.
*/
case MappingModelNotFound(localStoreURL: NSURL, targetModel: NSManagedObjectModel, targetModelVersion: String)
case mappingModelNotFound(localStoreURL: URL, targetModel: NSManagedObjectModel, targetModelVersion: String)
/**
Progressive migrations are disabled for a store, but an `NSMappingModel` could not be found for a specific source and destination model versions.
*/
case ProgressiveMigrationRequired(localStoreURL: NSURL)
case progressiveMigrationRequired(localStoreURL: URL)
/**
An internal SDK call failed with the specified `NSError`.
*/
case InternalError(NSError: NSError)
case internalError(NSError: NSError)
// MARK: ErrorType
// MARK: CustomNSError
public var _domain: String {
public static var errorDomain: String {
return CoreStoreErrorDomain
}
public var _code: Int {
public var errorCode: Int {
switch self {
case .Unknown:
return CoreStoreErrorCode.UnknownError.rawValue
case .unknown:
return CoreStoreErrorCode.unknownError.rawValue
case .DifferentStorageExistsAtURL:
return CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue
case .differentStorageExistsAtURL:
return CoreStoreErrorCode.differentStorageExistsAtURL.rawValue
case .MappingModelNotFound:
return CoreStoreErrorCode.MappingModelNotFound.rawValue
case .mappingModelNotFound:
return CoreStoreErrorCode.mappingModelNotFound.rawValue
case .ProgressiveMigrationRequired:
return CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue
case .progressiveMigrationRequired:
return CoreStoreErrorCode.progressiveMigrationRequired.rawValue
case .InternalError:
return CoreStoreErrorCode.InternalError.rawValue
case .internalError:
return CoreStoreErrorCode.internalError.rawValue
}
}
public var errorUserInfo: [String : Any] {
switch self {
case .unknown:
return [:]
case .differentStorageExistsAtURL(let existingPersistentStoreURL):
return [
"existingPersistentStoreURL": existingPersistentStoreURL
]
case .mappingModelNotFound(let localStoreURL, let targetModel, let targetModelVersion):
return [
"localStoreURL": localStoreURL,
"targetModel": targetModel,
"targetModelVersion": targetModelVersion
]
case .progressiveMigrationRequired(let localStoreURL):
return [
"localStoreURL": localStoreURL
]
case .internalError(let NSError):
return [
"NSError": NSError
]
}
}
// MARK: Equatable
public static func == (lhs: CoreStoreError, rhs: CoreStoreError) -> Bool {
switch (lhs, rhs) {
case (.unknown, .unknown):
return true
case (.differentStorageExistsAtURL(let url1), .differentStorageExistsAtURL(let url2)):
return url1 == url2
case (.mappingModelNotFound(let url1, let model1, let version1), .mappingModelNotFound(let url2, let model2, let version2)):
return url1 == url2 && model1 == model2 && version1 == version2
case (.progressiveMigrationRequired(let url1), .progressiveMigrationRequired(let url2)):
return url1 == url2
case (.internalError(let NSError1), .internalError(let NSError2)):
return NSError1 == NSError2
default:
return false
}
}
@@ -96,19 +154,19 @@ public enum CoreStoreError: ErrorType, Hashable {
let code = self._code
switch self {
case .Unknown:
case .unknown:
return code.hashValue
case .DifferentStorageExistsAtURL(let existingPersistentStoreURL):
case .differentStorageExistsAtURL(let existingPersistentStoreURL):
return code.hashValue ^ existingPersistentStoreURL.hashValue
case .MappingModelNotFound(let localStoreURL, let targetModel, let targetModelVersion):
case .mappingModelNotFound(let localStoreURL, let targetModel, let targetModelVersion):
return code.hashValue ^ localStoreURL.hashValue ^ targetModel.hashValue ^ targetModelVersion.hashValue
case .ProgressiveMigrationRequired(let localStoreURL):
case .progressiveMigrationRequired(let localStoreURL):
return code.hashValue ^ localStoreURL.hashValue
case .InternalError(let NSError):
case .internalError(let NSError):
return code.hashValue ^ NSError.hashValue
}
}
@@ -116,37 +174,9 @@ public enum CoreStoreError: ErrorType, Hashable {
// MARK: Internal
internal init(_ error: ErrorType?) {
internal init(_ error: Error?) {
self = error.flatMap { $0.bridgeToSwift } ?? .Unknown
}
}
// MARK: - CoreStoreError: Equatable
@warn_unused_result
public func == (lhs: CoreStoreError, rhs: CoreStoreError) -> Bool {
switch (lhs, rhs) {
case (.Unknown, .Unknown):
return true
case (.DifferentStorageExistsAtURL(let url1), .DifferentStorageExistsAtURL(let url2)):
return url1 == url2
case (.MappingModelNotFound(let url1, let model1, let version1), .MappingModelNotFound(let url2, let model2, let version2)):
return url1 == url2 && model1 == model2 && version1 == version2
case (.ProgressiveMigrationRequired(let url1), .ProgressiveMigrationRequired(let url2)):
return url1 == url2
case (.InternalError(let NSError1), .InternalError(let NSError2)):
return NSError1 == NSError2
default:
return false
self = error.flatMap { $0.bridgeToSwift } ?? .unknown
}
}
@@ -170,27 +200,27 @@ public enum CoreStoreErrorCode: Int {
/**
A failure occured because of an unknown error.
*/
case UnknownError
case unknownError
/**
The `NSPersistentStore` could note be initialized because another store existed at the specified `NSURL`.
*/
case DifferentPersistentStoreExistsAtURL
case differentStorageExistsAtURL
/**
An `NSMappingModel` could not be found for a specific source and destination model versions.
*/
case MappingModelNotFound
case mappingModelNotFound
/**
Progressive migrations are disabled for a store, but an `NSMappingModel` could not be found for a specific source and destination model versions.
*/
case ProgressiveMigrationRequired
case progressiveMigrationRequired
/**
An internal SDK call failed with the specified "NSError" userInfo key.
*/
case InternalError
case internalError
}
@@ -208,20 +238,4 @@ public extension NSError {
|| code == NSMigrationError)
&& self.domain == NSCocoaErrorDomain
}
// MARK: Deprecated
/**
Deprecated. Use `CoreStoreError` enum values instead.
If the error's domain is equal to `CoreStoreErrorDomain`, returns the associated `CoreStoreErrorCode`. For other domains, returns `nil`.
*/
@available(*, deprecated=2.0.0, message="Use CoreStoreError enum values instead.")
public var coreStoreErrorCode: CoreStoreErrorCode? {
return (self.domain == CoreStoreErrorDomain
? CoreStoreErrorCode(rawValue: self.code)
: nil)
}
}

View File

@@ -29,7 +29,46 @@ import CoreData
// MARK: - DataTransaction
public extension BaseDataTransaction {
extension BaseDataTransaction: FetchableSource, QueryableSource {
/**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the number of `NSManagedObject`s deleted
*/
@discardableResult
public func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.deleteAll(from, deleteClauses)
}
/**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the number of `NSManagedObject`s deleted
*/
@discardableResult
public func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.deleteAll(from, deleteClauses)
}
// 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.
@@ -37,17 +76,9 @@ public extension BaseDataTransaction {
- 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.
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(object: T) -> T? {
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
do {
return (try self.context.existingObjectWithID(object.objectID) as! T)
}
catch _ {
return nil
}
return self.context.fetchExisting(object)
}
/**
@@ -56,17 +87,9 @@ public extension BaseDataTransaction {
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(objectID: NSManagedObjectID) -> T? {
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
do {
return (try self.context.existingObjectWithID(objectID) as! T)
}
catch _ {
return nil
}
return self.context.fetchExisting(objectID)
}
/**
@@ -75,10 +98,9 @@ public extension BaseDataTransaction {
- parameter objects: an array of `NSManagedObject`s created/fetched outside the transaction
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == T>(objects: S) -> [T] {
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return objects.flatMap { (try? self.context.existingObjectWithID($0.objectID)) as? T }
return self.context.fetchExisting(objects)
}
/**
@@ -87,10 +109,9 @@ public extension BaseDataTransaction {
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == NSManagedObjectID>(objectIDs: S) -> [T] {
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return objectIDs.flatMap { (try? self.context.existingObjectWithID($0)) as? T }
return self.context.fetchExisting(objectIDs)
}
/**
@@ -100,10 +121,13 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.fetchOne(from, fetchClauses)
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchOne(from, fetchClauses)
}
/**
@@ -113,8 +137,7 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -130,10 +153,13 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.fetchAll(from, fetchClauses)
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchAll(from, fetchClauses)
}
/**
@@ -143,8 +169,7 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -160,10 +185,13 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses)
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(from, fetchClauses)
}
/**
@@ -173,14 +201,12 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchCount(from, fetchClauses)
}
@@ -191,10 +217,13 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses)
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectID(from, fetchClauses)
}
/**
@@ -204,8 +233,7 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -221,21 +249,7 @@ public extension BaseDataTransaction {
- 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
*/
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses)
}
/**
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -245,38 +259,23 @@ public extension BaseDataTransaction {
}
/**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
Fetches the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the number of `NSManagedObject`s deleted
- 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
*/
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.deleteAll(from, deleteClauses)
return self.context.fetchObjectIDs(from, fetchClauses)
}
/**
Deletes all `NSManagedObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the number of `NSManagedObject`s deleted
*/
public func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.deleteAll(from, deleteClauses)
}
// MARK: QueryableSource
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -288,14 +287,12 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryValue(from, selectClause, queryClauses)
}
@@ -309,14 +306,12 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryValue(from, selectClause, queryClauses)
}
@@ -330,14 +325,12 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryAttributes(from, selectClause, queryClauses)
}
@@ -351,14 +344,23 @@ public extension BaseDataTransaction {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryAttributes(from, selectClause, queryClauses)
}
// MARK: FetchableSource, QueryableSource
/**
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
public func internalContext() -> NSManagedObjectContext {
return self.context
}
}

View File

@@ -32,7 +32,7 @@ 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:
```
let person = transaction.fetchOne(From(MyPersonEntity))
let person = transaction.fetchOne(From<MyPersonEntity>())
```
For cases where multiple `NSPersistentStore`s contain the same entity, the source configuration's name needs to be specified as well:
```
@@ -58,7 +58,7 @@ public struct From<T: NSManagedObject> {
let people = transaction.fetchAll(From<MyPersonEntity>())
```
*/
public init(){
public init() {
self.init(entityClass: T.self, configurations: nil)
}
@@ -68,7 +68,6 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From<MyPersonEntity>())
```
- parameter entity: the associated `NSManagedObject` type
*/
public init(_ entity: T.Type) {
@@ -81,14 +80,13 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From<MyPersonEntity>())
```
- parameter entityClass: the associated `NSManagedObject` entity class
*/
public init(_ entityClass: AnyClass) {
CoreStore.assert(
entityClass is T.Type,
"Attempted to create generic type \(cs_typeName(From<T>)) with entity class \(cs_typeName(entityClass))"
"Attempted to create generic type \(cs_typeName(From<T>.self)) with entity class \(cs_typeName(entityClass))"
)
self.init(entityClass: entityClass, configurations: nil)
}
@@ -98,7 +96,6 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From<MyPersonEntity>(nil, "Configuration1"))
```
- 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 `nil` to use the default configuration.
- parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter)
*/
@@ -112,7 +109,6 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From<MyPersonEntity>(["Configuration1", "Configuration2"]))
```
- parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/
public init(_ configurations: [String?]) {
@@ -125,7 +121,6 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From(MyPersonEntity.self, nil, "Configuration1"))
```
- parameter entity: the associated `NSManagedObject` type
- 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 `nil` to use the default configuration.
- parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter)
@@ -140,7 +135,6 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From(MyPersonEntity.self, ["Configuration1", "Configuration1"]))
```
- parameter entity: the associated `NSManagedObject` type
- parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/
@@ -154,7 +148,6 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From(MyPersonEntity.self, nil, "Configuration1"))
```
- parameter entity: 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 `nil` to use the default configuration.
- parameter otherConfigurations: an optional list of other configuration names to associate objects from (see `configuration` parameter)
@@ -163,7 +156,7 @@ public struct From<T: NSManagedObject> {
CoreStore.assert(
entityClass is T.Type,
"Attempted to create generic type \(cs_typeName(From<T>)) with entity class \(cs_typeName(entityClass))"
"Attempted to create generic type \(cs_typeName(From<T>.self)) with entity class \(cs_typeName(entityClass))"
)
self.init(entityClass: entityClass, configurations: [configuration] + otherConfigurations)
}
@@ -173,7 +166,6 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From(MyPersonEntity.self, ["Configuration1", "Configuration1"]))
```
- parameter entity: the associated `NSManagedObject` entity class
- parameter configurations: a list of `NSPersistentStore` configuration names to associate objects from. This parameter is required if multiple configurations contain the created `NSManagedObject`'s entity type. Set to `nil` to use the default configuration.
*/
@@ -181,7 +173,7 @@ public struct From<T: NSManagedObject> {
CoreStore.assert(
entityClass is T.Type,
"Attempted to create generic type \(cs_typeName(From<T>)) with entity class \(cs_typeName(entityClass))"
"Attempted to create generic type \(cs_typeName(From<T>.self)) with entity class \(cs_typeName(entityClass))"
)
self.init(entityClass: entityClass, configurations: configurations)
}
@@ -189,8 +181,7 @@ public struct From<T: NSManagedObject> {
// MARK: Internal
@warn_unused_result
internal func applyToFetchRequest(fetchRequest: NSFetchRequest, context: NSManagedObjectContext, applyAffectedStores: Bool = true) -> Bool {
internal func applyToFetchRequest<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>, context: NSManagedObjectContext, applyAffectedStores: Bool = true) -> Bool {
fetchRequest.entity = context.entityDescriptionForEntityClass(self.entityClass)
guard applyAffectedStores else {
@@ -202,15 +193,15 @@ public struct From<T: NSManagedObject> {
return true
}
CoreStore.log(
.Warning,
.warning,
message: "Attempted to perform a fetch but could not find any persistent store for the entity \(cs_typeName(fetchRequest.entityName))"
)
return false
}
internal func applyAffectedStoresForFetchedRequest(fetchRequest: NSFetchRequest, context: NSManagedObjectContext) -> Bool {
internal func applyAffectedStoresForFetchedRequest<U: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<U>, context: NSManagedObjectContext) -> Bool {
let stores = self.findPersistentStores(context: context)
let stores = self.findPersistentStores(context)
fetchRequest.affectedStores = stores
return stores?.isEmpty == false
}
@@ -227,7 +218,7 @@ public struct From<T: NSManagedObject> {
// MARK: Private
private let findPersistentStores: (context: NSManagedObjectContext) -> [NSPersistentStore]?
private let findPersistentStores: (_ context: NSManagedObjectContext) -> [NSPersistentStore]?
private init(entityClass: AnyClass, configurations: [String?]?) {
@@ -253,121 +244,10 @@ public struct From<T: NSManagedObject> {
}
}
private init(entityClass: AnyClass, configurations: [String?]?, findPersistentStores: (context: NSManagedObjectContext) -> [NSPersistentStore]?) {
private init(entityClass: AnyClass, configurations: [String?]?, findPersistentStores: @escaping (_ context: NSManagedObjectContext) -> [NSPersistentStore]?) {
self.entityClass = entityClass
self.configurations = configurations
self.findPersistentStores = findPersistentStores
}
// MARK: Obsolete
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ storeURL: NSURL, _ otherStoreURLs: NSURL...) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ storeURLs: [NSURL]) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entity: T.Type, _ storeURL: NSURL, _ otherStoreURLs: NSURL...) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entity: T.Type, _ storeURLs: [NSURL]) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entityClass: AnyClass, _ storeURL: NSURL, _ otherStoreURLs: NSURL...) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entityClass: AnyClass, _ storeURLs: [NSURL]) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ persistentStore: NSPersistentStore, _ otherPersistentStores: NSPersistentStore...) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ persistentStores: [NSPersistentStore]) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entity: T.Type, _ persistentStore: NSPersistentStore, _ otherPersistentStores: NSPersistentStore...) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entity: T.Type, _ persistentStores: [NSPersistentStore]) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entityClass: AnyClass, _ persistentStore: NSPersistentStore, _ otherPersistentStores: NSPersistentStore...) {
CoreStore.abort("Use initializers that accept configuration names.")
}
/**
Obsolete. Use initializers that accept configuration names.
*/
@available(*, obsoleted=2.0.0, message="Use initializers that accept configuration names.")
public init(_ entityClass: AnyClass, _ persistentStores: [NSPersistentStore]) {
CoreStore.abort("Use initializers that accept configuration names.")
}
}

View File

@@ -71,13 +71,13 @@ public struct GroupBy: QueryClause, Hashable {
// MARK: QueryClause
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
public func applyToFetchRequest<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
if let keyPaths = fetchRequest.propertiesToGroupBy as? [String] where keyPaths != self.keyPaths {
if let keyPaths = fetchRequest.propertiesToGroupBy as? [String], keyPaths != self.keyPaths {
CoreStore.log(
.Warning,
message: "An existing \"propertiesToGroupBy\" for the \(cs_typeName(NSFetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
.warning,
message: "An existing \"propertiesToGroupBy\" for the \(cs_typeName(NSFetchRequest<ResultType>.self)) was overwritten by \(cs_typeName(self)) query clause."
)
}
@@ -85,6 +85,14 @@ public struct GroupBy: QueryClause, Hashable {
}
// MARK: Equatable
public static func == (lhs: GroupBy, rhs: GroupBy) -> Bool {
return lhs.keyPaths == rhs.keyPaths
}
// MARK: Hashable
public var hashValue: Int {
@@ -92,12 +100,3 @@ public struct GroupBy: QueryClause, Hashable {
return (self.keyPaths as NSArray).hashValue
}
}
// MARK: - GroupBy: Equatable
@warn_unused_result
public func == (lhs: GroupBy, rhs: GroupBy) -> Bool {
return lhs.keyPaths == rhs.keyPaths
}

View File

@@ -27,12 +27,12 @@ import Foundation
import CoreData
public func +(left: OrderBy, right: OrderBy) -> OrderBy {
public func + (left: OrderBy, right: OrderBy) -> OrderBy {
return OrderBy(left.sortDescriptors + right.sortDescriptors)
}
public func +=(inout left: OrderBy, right: OrderBy) {
public func += (left: inout OrderBy, right: OrderBy) {
left = left + right
}
@@ -53,12 +53,12 @@ public enum SortKey {
/**
Indicates that the `KeyPath` should be sorted in ascending order
*/
case Ascending(KeyPath)
case ascending(KeyPath)
/**
Indicates that the `KeyPath` should be sorted in descending order
*/
case Descending(KeyPath)
case descending(KeyPath)
}
@@ -114,10 +114,10 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
switch sortKey {
case .Ascending(let keyPath):
case .ascending(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: true)
case .Descending(let keyPath):
case .descending(let keyPath):
return NSSortDescriptor(key: keyPath, ascending: false)
}
}
@@ -138,13 +138,13 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
// MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
public func applyToFetchRequest<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
if let sortDescriptors = fetchRequest.sortDescriptors where sortDescriptors != self.sortDescriptors {
if let sortDescriptors = fetchRequest.sortDescriptors, sortDescriptors != self.sortDescriptors {
CoreStore.log(
.Warning,
message: "Existing sortDescriptors for the \(cs_typeName(NSFetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
.warning,
message: "Existing sortDescriptors for the \(cs_typeName(fetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
)
}
@@ -152,6 +152,14 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
}
// MARK: Equatable
public static func == (lhs: OrderBy, rhs: OrderBy) -> Bool {
return lhs.sortDescriptors == rhs.sortDescriptors
}
// MARK: Hashable
public var hashValue: Int {
@@ -159,12 +167,3 @@ public struct OrderBy: FetchClause, QueryClause, DeleteClause, Hashable {
return (self.sortDescriptors as NSArray).hashValue
}
}
// MARK: - OrderBy: Equatable
@warn_unused_result
public func == (lhs: OrderBy, rhs: OrderBy) -> Bool {
return lhs.sortDescriptors == rhs.sortDescriptors
}

View File

@@ -44,7 +44,7 @@ public protocol SelectValueResultType: SelectResultType {
static var attributeType: NSAttributeType { get }
static func fromResultObject(result: AnyObject) -> Self?
static func fromResultObject(_ result: Any) -> Self?
}
@@ -55,7 +55,7 @@ public protocol SelectValueResultType: SelectResultType {
*/
public protocol SelectAttributesResultType: SelectResultType {
static func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]]
static func fromResultObjects(_ result: [Any]) -> [[String: Any]]
}
@@ -64,54 +64,52 @@ public protocol SelectAttributesResultType: SelectResultType {
/**
The `SelectTerm` is passed to the `Select` clause to indicate the attributes/aggregate keys to be queried.
*/
public enum SelectTerm: StringLiteralConvertible, Hashable {
public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
/**
Provides a `SelectTerm` to a `Select` clause for querying an entity attribute. A shorter way to do the same is to assign from the string keypath directly:
```
let fullName = CoreStore.queryValue(
From(MyPersonEntity),
Select<String>(.Attribute("fullName")),
From<MyPersonEntity>(),
Select<String>(.attribute("fullName")),
Where("employeeID", isEqualTo: 1111)
)
```
is equivalent to:
```
let fullName = CoreStore.queryValue(
From(MyPersonEntity),
From<MyPersonEntity>(),
Select<String>("fullName"),
Where("employeeID", isEqualTo: 1111)
)
```
- parameter keyPath: the attribute name
- returns: a `SelectTerm` to a `Select` clause for querying an entity attribute
*/
public static func Attribute(keyPath: KeyPath) -> SelectTerm {
public static func attribute(_ keyPath: KeyPath) -> SelectTerm {
return ._Attribute(keyPath)
return ._attribute(keyPath)
}
/**
Provides a `SelectTerm` to a `Select` clause for querying the average value of an attribute.
```
let averageAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Average("age"))
From<MyPersonEntity>(),
Select<Int>(.average("age"))
)
```
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "average(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the average value of an attribute
*/
public static func Average(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
public static func average(_ keyPath: KeyPath, as alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
return ._aggregate(
function: "average:",
keyPath: keyPath,
alias: alias ?? "average(\(keyPath))",
nativeType: .DecimalAttributeType
nativeType: .decimalAttributeType
)
}
@@ -119,22 +117,21 @@ public enum SelectTerm: StringLiteralConvertible, Hashable {
Provides a `SelectTerm` to a `Select` clause for a count query.
```
let numberOfEmployees = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Count("employeeID"))
From<MyPersonEntity>(),
Select<Int>(.count("employeeID"))
)
```
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "count(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for a count query
*/
public static func Count(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
public static func count(_ keyPath: KeyPath, as alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
return ._aggregate(
function: "count:",
keyPath: keyPath,
alias: alias ?? "count(\(keyPath))",
nativeType: .Integer64AttributeType
nativeType: .integer64AttributeType
)
}
@@ -142,22 +139,21 @@ public enum SelectTerm: StringLiteralConvertible, Hashable {
Provides a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute.
```
let maximumAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Maximum("age"))
From<MyPersonEntity>(),
Select<Int>(.maximum("age"))
)
```
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the maximum value for an attribute
*/
public static func Maximum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
public static func maximum(_ keyPath: KeyPath, as alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
return ._aggregate(
function: "max:",
keyPath: keyPath,
alias: alias ?? "max(\(keyPath))",
nativeType: .UndefinedAttributeType
nativeType: .undefinedAttributeType
)
}
@@ -165,22 +161,21 @@ public enum SelectTerm: StringLiteralConvertible, Hashable {
Provides a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute.
```
let minimumAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Minimum("age"))
From<MyPersonEntity>(),
Select<Int>(.minimum("age"))
)
```
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "min(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the minimum value for an attribute
*/
public static func Minimum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
public static func minimum(_ keyPath: KeyPath, as alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
return ._aggregate(
function: "min:",
keyPath: keyPath,
alias: alias ?? "min(\(keyPath))",
nativeType: .UndefinedAttributeType
nativeType: .undefinedAttributeType
)
}
@@ -188,22 +183,21 @@ public enum SelectTerm: StringLiteralConvertible, Hashable {
Provides a `SelectTerm` to a `Select` clause for querying the sum value for an attribute.
```
let totalAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Sum("age"))
From<MyPersonEntity>(),
Select<Int>(.sum("age"))
)
```
- parameter keyPath: the attribute name
- parameter alias: the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "sum(<attributeName>)" is used
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func Sum(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
public static func sum(_ keyPath: KeyPath, as alias: KeyPath? = nil) -> SelectTerm {
return ._Aggregate(
return ._aggregate(
function: "sum:",
keyPath: keyPath,
alias: alias ?? "sum(\(keyPath))",
nativeType: .DecimalAttributeType
nativeType: .decimalAttributeType
)
}
@@ -211,40 +205,64 @@ public enum SelectTerm: StringLiteralConvertible, Hashable {
Provides a `SelectTerm` to a `Select` clause for querying the `NSManagedObjectID`.
```
let objectID = CoreStore.queryValue(
From(MyPersonEntity),
From<MyPersonEntity>(),
Select<NSManagedObjectID>(),
Where("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
- returns: a `SelectTerm` to a `Select` clause for querying the sum value for an attribute
*/
public static func ObjectID(As alias: KeyPath? = nil) -> SelectTerm {
public static func objectID(as alias: KeyPath? = nil) -> SelectTerm {
return ._Identity(
return ._identity(
alias: alias ?? "objectID",
nativeType: .ObjectIDAttributeType
nativeType: .objectIDAttributeType
)
}
// MARK: StringLiteralConvertible
// MARK: ExpressibleByStringLiteral
public init(stringLiteral value: KeyPath) {
self = ._Attribute(value)
self = ._attribute(value)
}
public init(unicodeScalarLiteral value: KeyPath) {
self = ._Attribute(value)
self = ._attribute(value)
}
public init(extendedGraphemeClusterLiteral value: KeyPath) {
self = ._Attribute(value)
self = ._attribute(value)
}
// MARK: Equatable
public static func == (lhs: SelectTerm, rhs: SelectTerm) -> Bool {
switch (lhs, rhs) {
case (._attribute(let keyPath1), ._attribute(let keyPath2)):
return keyPath1 == keyPath2
case (._aggregate(let function1, let keyPath1, let alias1, let nativeType1),
._aggregate(let function2, let keyPath2, let alias2, let nativeType2)):
return function1 == function2
&& keyPath1 == keyPath2
&& alias1 == alias2
&& nativeType1 == nativeType2
case (._identity(let alias1, let nativeType1), ._identity(let alias2, let nativeType2)):
return alias1 == alias2 && nativeType1 == nativeType2
default:
return false
}
}
@@ -254,13 +272,13 @@ public enum SelectTerm: StringLiteralConvertible, Hashable {
switch self {
case ._Attribute(let keyPath):
case ._attribute(let keyPath):
return 0 ^ keyPath.hashValue
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
return 1 ^ function.hashValue ^ keyPath.hashValue ^ alias.hashValue ^ nativeType.hashValue
case ._Identity(let alias, let nativeType):
case ._identity(let alias, let nativeType):
return 3 ^ alias.hashValue ^ nativeType.hashValue
}
}
@@ -268,35 +286,9 @@ public enum SelectTerm: StringLiteralConvertible, Hashable {
// MARK: Internal
case _Attribute(KeyPath)
case _Aggregate(function: String, keyPath: KeyPath, alias: String, nativeType: NSAttributeType)
case _Identity(alias: String, nativeType: NSAttributeType)
}
// MARK: - SelectTerm: Equatable
@warn_unused_result
public func == (lhs: SelectTerm, rhs: SelectTerm) -> Bool {
switch (lhs, rhs) {
case (._Attribute(let keyPath1), ._Attribute(let keyPath2)):
return keyPath1 == keyPath2
case (._Aggregate(let function1, let keyPath1, let alias1, let nativeType1),
._Aggregate(let function2, let keyPath2, let alias2, let nativeType2)):
return function1 == function2
&& keyPath1 == keyPath2
&& alias1 == alias2
&& nativeType1 == nativeType2
case (._Identity(let alias1, let nativeType1), ._Identity(let alias2, let nativeType2)):
return alias1 == alias2 && nativeType1 == nativeType2
default:
return false
}
case _attribute(KeyPath)
case _aggregate(function: String, keyPath: KeyPath, alias: String, nativeType: NSAttributeType)
case _identity(alias: String, nativeType: NSAttributeType)
}
@@ -308,15 +300,15 @@ public func == (lhs: SelectTerm, rhs: SelectTerm) -> Bool {
You can bind the return type by specializing the initializer:
```
let maximumAge = CoreStore.queryValue(
From(MyPersonEntity),
Select<Int>(.Maximum("age"))
From<MyPersonEntity>(),
Select<Int>(.maximum("age"))
)
```
or by casting the type of the return value:
```
let maximumAge: Int = CoreStore.queryValue(
From(MyPersonEntity),
Select(.Maximum("age"))
From<MyPersonEntity>(),
Select(.maximum("age"))
)
```
Valid return types depend on the query:
@@ -330,13 +322,14 @@ public func == (lhs: SelectTerm, rhs: SelectTerm) -> Bool {
- `Double`
- `Float`
- `String`
- `Date`
- `Data`
- `NSNumber`
- `NSString`
- `NSDecimalNumber`
- `NSDate`
- `NSData`
- `NSManagedObjectID`
- `NSString`
- for `queryAttributes(...)` methods:
- `NSDictionary`
@@ -371,11 +364,19 @@ public struct Select<T: SelectResultType>: Hashable {
}
// MARK: Equatable
public static func == <T: SelectResultType, U: SelectResultType>(lhs: Select<T>, rhs: Select<U>) -> Bool {
return lhs.selectTerms == rhs.selectTerms
}
// MARK: Hashable
public var hashValue: Int {
return self.selectTerms.map { $0.hashValue }.reduce(0, combine: ^)
return self.selectTerms.map { $0.hashValue }.reduce(0, ^)
}
@@ -388,36 +389,27 @@ public extension Select where T: NSManagedObjectID {
public init() {
self.init(.ObjectID())
self.init(.objectID())
}
}
// MARK: - Select: Equatable
@warn_unused_result
public func == <T: SelectResultType, U: SelectResultType>(lhs: Select<T>, rhs: Select<U>) -> Bool {
return lhs.selectTerms == rhs.selectTerms
}
// MARK: - Bool: SelectValueResultType
extension Bool: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .BooleanAttributeType
return .booleanAttributeType
}
public static func fromResultObject(result: AnyObject) -> Bool? {
public static func fromResultObject(_ result: Any) -> Bool? {
switch result {
case let decimal as NSDecimalNumber:
// iOS: NSDecimalNumber(string: "0.5").boolValue // true
// OSX: NSDecimalNumber(string: "0.5").boolValue // false
return NSNumber(double: decimal.doubleValue).boolValue
return NSNumber(value: decimal.doubleValue).boolValue
case let number as NSNumber:
return number.boolValue
@@ -435,12 +427,12 @@ extension Int8: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
return .integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int8? {
public static func fromResultObject(_ result: Any) -> Int8? {
guard let value = (result as? NSNumber)?.longLongValue else {
guard let value = (result as? NSNumber)?.int64Value else {
return nil
}
@@ -455,12 +447,12 @@ extension Int16: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
return .integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int16? {
public static func fromResultObject(_ result: Any) -> Int16? {
guard let value = (result as? NSNumber)?.longLongValue else {
guard let value = (result as? NSNumber)?.int64Value else {
return nil
}
@@ -475,12 +467,12 @@ extension Int32: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
return .integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int32? {
public static func fromResultObject(_ result: Any) -> Int32? {
guard let value = (result as? NSNumber)?.longLongValue else {
guard let value = (result as? NSNumber)?.int64Value else {
return nil
}
@@ -495,12 +487,12 @@ extension Int64: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
return .integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int64? {
public static func fromResultObject(_ result: Any) -> Int64? {
return (result as? NSNumber)?.longLongValue
return (result as? NSNumber)?.int64Value
}
}
@@ -511,12 +503,12 @@ extension Int: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .Integer64AttributeType
return .integer64AttributeType
}
public static func fromResultObject(result: AnyObject) -> Int? {
public static func fromResultObject(_ result: Any) -> Int? {
guard let value = (result as? NSNumber)?.longLongValue else {
guard let value = (result as? NSNumber)?.int64Value else {
return nil
}
@@ -531,10 +523,10 @@ extension Double: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .DoubleAttributeType
return .doubleAttributeType
}
public static func fromResultObject(result: AnyObject) -> Double? {
public static func fromResultObject(_ result: Any) -> Double? {
return (result as? NSNumber)?.doubleValue
}
@@ -547,10 +539,10 @@ extension Float: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .FloatAttributeType
return .floatAttributeType
}
public static func fromResultObject(result: AnyObject) -> Float? {
public static func fromResultObject(_ result: Any) -> Float? {
return (result as? NSNumber)?.floatValue
}
@@ -563,12 +555,44 @@ extension String: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .StringAttributeType
return .stringAttributeType
}
public static func fromResultObject(result: AnyObject) -> String? {
public static func fromResultObject(_ result: Any) -> String? {
return result as? NSString as? String
return result as? String
}
}
// MARK: - Date: SelectValueResultType
extension Date: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .dateAttributeType
}
public static func fromResultObject(_ result: Any) -> Date? {
return result as? Date
}
}
// MARK: - Data: SelectValueResultType
extension Data: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .binaryDataAttributeType
}
public static func fromResultObject(_ result: Any) -> Data? {
return result as? Data
}
}
@@ -579,12 +603,12 @@ extension NSNumber: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .Integer64AttributeType
return .integer64AttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
public class func fromResultObject(_ result: Any) -> Self? {
func forceCast<T: NSNumber>(object: AnyObject) -> T? {
func forceCast<T: NSNumber>(_ object: Any) -> T? {
return (object as? T)
}
@@ -599,12 +623,12 @@ extension NSString: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .StringAttributeType
return .stringAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
public class func fromResultObject(_ result: Any) -> Self? {
func forceCast<T: NSString>(object: AnyObject) -> T? {
func forceCast<T: NSString>(_ object: Any) -> T? {
return (object as? T)
}
@@ -619,12 +643,12 @@ extension NSDecimalNumber {
public override class var attributeType: NSAttributeType {
return .DecimalAttributeType
return .decimalAttributeType
}
public override class func fromResultObject(result: AnyObject) -> Self? {
public override class func fromResultObject(_ result: Any) -> Self? {
func forceCast<T: NSDecimalNumber>(object: AnyObject) -> T? {
func forceCast<T: NSDecimalNumber>(_ object: Any) -> T? {
return (object as? T)
}
@@ -637,14 +661,14 @@ extension NSDecimalNumber {
extension NSDate: SelectValueResultType {
public class var attributeType: NSAttributeType {
public static var attributeType: NSAttributeType {
return .DateAttributeType
return .dateAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
public class func fromResultObject(_ result: Any) -> Self? {
func forceCast<T: NSDate>(object: AnyObject) -> T? {
func forceCast<T: NSDate>(_ object: Any) -> T? {
return (object as? T)
}
@@ -657,14 +681,14 @@ extension NSDate: SelectValueResultType {
extension NSData: SelectValueResultType {
public class var attributeType: NSAttributeType {
public static var attributeType: NSAttributeType {
return .BinaryDataAttributeType
return .binaryDataAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
public class func fromResultObject(_ result: Any) -> Self? {
func forceCast<T: NSData>(object: AnyObject) -> T? {
func forceCast<T: NSData>(_ object: Any) -> T? {
return (object as? T)
}
@@ -679,12 +703,12 @@ extension NSManagedObjectID: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .ObjectIDAttributeType
return .objectIDAttributeType
}
public class func fromResultObject(result: AnyObject) -> Self? {
public class func fromResultObject(_ result: Any) -> Self? {
func forceCast<T: NSManagedObjectID>(object: AnyObject) -> T? {
func forceCast<T: NSManagedObjectID>(_ object: Any) -> T? {
return (object as? T)
}
@@ -699,25 +723,25 @@ extension NSDictionary: SelectAttributesResultType {
// MARK: SelectAttributesResultType
public class func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]] {
public class func fromResultObjects(_ result: [Any]) -> [[String: Any]] {
return result as! [[NSString: AnyObject]]
return result as! [[String: Any]]
}
}
// MARK: - Internal
internal extension CollectionType where Generator.Element == SelectTerm {
internal extension Collection where Iterator.Element == SelectTerm {
internal func applyToFetchRequest<T>(fetchRequest: NSFetchRequest, owner: T) {
internal func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>, owner: T) {
fetchRequest.includesPendingChanges = false
fetchRequest.resultType = .DictionaryResultType
fetchRequest.resultType = .dictionaryResultType
func attributeDescriptionForKeyPath(keyPath: String, inEntity entity: NSEntityDescription) -> NSAttributeDescription? {
func attributeDescription(for keyPath: String, in entity: NSEntityDescription) -> NSAttributeDescription? {
let components = keyPath.componentsSeparatedByString(".")
let components = keyPath.components(separatedBy: ".")
switch components.count {
case 0:
@@ -731,39 +755,39 @@ internal extension CollectionType where Generator.Element == SelectTerm {
return nil
}
return attributeDescriptionForKeyPath(
components.dropFirst().joinWithSeparator("."),
inEntity: relationship.entity
return attributeDescription(
for: components.dropFirst().joined(separator: "."),
in: relationship.entity
)
}
}
var propertiesToFetch = [AnyObject]()
var propertiesToFetch = [Any]()
for term in self {
switch term {
case ._Attribute(let keyPath):
case ._attribute(let keyPath):
let entityDescription = fetchRequest.entity!
if let attributeDescription = attributeDescriptionForKeyPath(keyPath, inEntity: entityDescription) {
if let attributeDescription = attributeDescription(for: keyPath, in: entityDescription) {
propertiesToFetch.append(attributeDescription)
}
else {
CoreStore.log(
.Warning,
.warning,
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(owner)) query clause."
)
}
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
let entityDescription = fetchRequest.entity!
if let attributeDescription = attributeDescriptionForKeyPath(keyPath, inEntity: entityDescription) {
if let attributeDescription = attributeDescription(for: keyPath, in: entityDescription) {
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .UndefinedAttributeType {
if nativeType == .undefinedAttributeType {
expressionDescription.expressionResultType = attributeDescription.attributeType
}
@@ -780,17 +804,17 @@ internal extension CollectionType where Generator.Element == SelectTerm {
else {
CoreStore.log(
.Warning,
.warning,
message: "The key path \"\(keyPath)\" could not be resolved in entity \(cs_typeName(entityDescription.managedObjectClassName)) as an attribute and will be ignored by \(cs_typeName(owner)) query clause."
)
}
case ._Identity(let alias, let nativeType):
case ._identity(let alias, let nativeType):
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .UndefinedAttributeType {
if nativeType == .undefinedAttributeType {
expressionDescription.expressionResultType = .ObjectIDAttributeType
expressionDescription.expressionResultType = .objectIDAttributeType
}
else {
@@ -809,13 +833,13 @@ internal extension CollectionType where Generator.Element == SelectTerm {
switch self.first! {
case ._Attribute(let keyPath):
case ._attribute(let keyPath):
return keyPath
case ._Aggregate(_, _, let alias, _):
case ._aggregate(_, _, let alias, _):
return alias
case ._Identity(let alias, _):
case ._identity(let alias, _):
return alias
}
}

View File

@@ -34,7 +34,7 @@ import CoreData
Sample usage:
```
let employees = transaction.fetchAll(
From(MyPersonEntity),
From<MyPersonEntity>(),
Tweak { (fetchRequest) -> Void in
fetchRequest.includesPendingChanges = false
fetchRequest.fetchLimit = 5
@@ -47,7 +47,7 @@ public struct Tweak: FetchClause, QueryClause, DeleteClause {
/**
The block to customize the `NSFetchRequest`
*/
public let closure: (fetchRequest: NSFetchRequest) -> Void
public let closure: (_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Void
/**
Initializes a `Tweak` clause with a closure where the `NSFetchRequest` may be configured.
@@ -55,7 +55,7 @@ public struct Tweak: FetchClause, QueryClause, DeleteClause {
- Important: `Tweak`'s closure is executed only just before the fetch occurs, so make sure that any values captured by the closure is not prone to race conditions. Also, some utilities (such as `ListMonitor`s) may keep `FetchClause`s in memory and may thus introduce retain cycles if reference captures are not handled properly.
- parameter closure: the block to customize the `NSFetchRequest`
*/
public init(_ closure: (fetchRequest: NSFetchRequest) -> Void) {
public init(_ closure: @escaping (_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Void) {
self.closure = closure
}
@@ -63,8 +63,8 @@ public struct Tweak: FetchClause, QueryClause, DeleteClause {
// MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
public func applyToFetchRequest<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
self.closure(fetchRequest: fetchRequest)
self.closure(fetchRequest as! NSFetchRequest<NSFetchRequestResult>)
}
}

View File

@@ -27,19 +27,19 @@ import Foundation
import CoreData
public func &&(left: Where, right: Where) -> Where {
public func && (left: Where, right: Where) -> Where {
return Where(NSCompoundPredicate(type: .AndPredicateType, subpredicates: [left.predicate, right.predicate]))
return Where(NSCompoundPredicate(type: .and, subpredicates: [left.predicate, right.predicate]))
}
public func ||(left: Where, right: Where) -> Where {
public func || (left: Where, right: Where) -> Where {
return Where(NSCompoundPredicate(type: .OrPredicateType, subpredicates: [left.predicate, right.predicate]))
return Where(NSCompoundPredicate(type: .or, subpredicates: [left.predicate, right.predicate]))
}
public prefix func !(clause: Where) -> Where {
public prefix func ! (clause: Where) -> Where {
return Where(NSCompoundPredicate(type: .NotPredicateType, subpredicates: [clause.predicate]))
return Where(NSCompoundPredicate(type: .not, subpredicates: [clause.predicate]))
}
@@ -79,7 +79,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter format: the format string for the predicate
- parameter args: the arguments for `format`
*/
public init(_ format: String, _ args: NSObject...) {
public init(_ format: String, _ args: Any...) {
self.init(NSPredicate(format: format, argumentArray: args))
}
@@ -90,7 +90,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter format: the format string for the predicate
- parameter argumentArray: the arguments for `format`
*/
public init(_ format: String, argumentArray: [NSObject]?) {
public init(_ format: String, argumentArray: [Any]?) {
self.init(NSPredicate(format: format, argumentArray: argumentArray))
}
@@ -101,7 +101,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter keyPath: the keyPath to compare with
- parameter value: the arguments for the `==` operator
*/
public init(_ keyPath: KeyPath, isEqualTo value: NSObject?) {
public init(_ keyPath: KeyPath, isEqualTo value: Any?) {
self.init(value == nil
? NSPredicate(format: "\(keyPath) == nil")
@@ -114,7 +114,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter keyPath: the keyPath to compare with
- parameter list: the array to check membership of
*/
public init(_ keyPath: KeyPath, isMemberOf list: [NSObject]) {
public init(_ keyPath: KeyPath, isMemberOf list: [Any]) {
self.init(NSPredicate(format: "\(keyPath) IN %@", list))
}
@@ -125,7 +125,7 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
- parameter keyPath: the keyPath to compare with
- parameter list: the sequence to check membership of
*/
public init<S: SequenceType where S.Generator.Element: NSObject>(_ keyPath: KeyPath, isMemberOf list: S) {
public init<S: Sequence>(_ keyPath: KeyPath, isMemberOf list: S) where S.Iterator.Element: Any {
self.init(NSPredicate(format: "\(keyPath) IN %@", Array(list) as NSArray))
}
@@ -143,13 +143,13 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
// MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
public func applyToFetchRequest<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
if let predicate = fetchRequest.predicate where predicate != self.predicate {
if let predicate = fetchRequest.predicate, predicate != self.predicate {
CoreStore.log(
.Warning,
message: "An existing predicate for the \(cs_typeName(NSFetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
.warning,
message: "An existing predicate for the \(cs_typeName(fetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
)
}
@@ -157,6 +157,14 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
}
// MARK: Equatable
public static func == (lhs: Where, rhs: Where) -> Bool {
return lhs.predicate == rhs.predicate
}
// MARK: Hashable
public var hashValue: Int {
@@ -164,12 +172,3 @@ public struct Where: FetchClause, QueryClause, DeleteClause, Hashable {
return self.predicate.hashValue
}
}
// MARK: - Where: Equatable
@warn_unused_result
public func == (lhs: Where, rhs: Where) -> Bool {
return lhs.predicate == rhs.predicate
}

View File

@@ -37,8 +37,7 @@ public extension CoreStore {
- 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.
*/
@warn_unused_result
public static func fetchExisting<T: NSManagedObject>(object: T) -> T? {
public static func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
return self.defaultStack.fetchExisting(object)
}
@@ -49,8 +48,7 @@ public extension CoreStore {
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/
@warn_unused_result
public static func fetchExisting<T: NSManagedObject>(objectID: NSManagedObjectID) -> T? {
public static func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
return self.defaultStack.fetchExisting(objectID)
}
@@ -61,8 +59,7 @@ public extension CoreStore {
- parameter objects: an array of `NSManagedObject`s created/fetched outside the `DataStack`
- returns: the `NSManagedObject` array for objects that exists in the `DataStack`
*/
@warn_unused_result
public static func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == T>(objects: S) -> [T] {
public static func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return self.defaultStack.fetchExisting(objects)
}
@@ -73,8 +70,7 @@ public extension CoreStore {
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `DataStack`
*/
@warn_unused_result
public static func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == NSManagedObjectID>(objectIDs: S) -> [T] {
public static func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return self.defaultStack.fetchExisting(objectIDs)
}
@@ -86,8 +82,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
public static func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.defaultStack.fetchOne(from, fetchClauses)
}
@@ -99,8 +94,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
public static func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
return self.defaultStack.fetchOne(from, fetchClauses)
}
@@ -112,8 +106,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
public static func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.defaultStack.fetchAll(from, fetchClauses)
}
@@ -125,8 +118,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
public static func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
return self.defaultStack.fetchAll(from, fetchClauses)
}
@@ -138,8 +130,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
public static func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses)
}
@@ -151,8 +142,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
public static func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses)
}
@@ -164,8 +154,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
public static func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses)
}
@@ -177,8 +166,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
public static func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses)
}
@@ -190,8 +178,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
public static func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
}
@@ -203,8 +190,7 @@ public extension CoreStore {
- 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
*/
@warn_unused_result
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
public static func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
}
@@ -219,8 +205,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses)
}
@@ -235,8 +220,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses)
}
@@ -251,8 +235,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
public static func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}
@@ -267,8 +250,7 @@ public extension CoreStore {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
public static func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}

View File

@@ -25,14 +25,13 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - DataStack
public extension DataStack {
extension DataStack: FetchableSource, QueryableSource {
// 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.
@@ -40,17 +39,9 @@ public extension 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.
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(object: T) -> T? {
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
do {
return (try self.mainContext.existingObjectWithID(object.objectID) as! T)
}
catch _ {
return nil
}
return self.mainContext.fetchExisting(object)
}
/**
@@ -59,17 +50,9 @@ public extension DataStack {
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(objectID: NSManagedObjectID) -> T? {
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
do {
return (try self.mainContext.existingObjectWithID(objectID) as! T)
}
catch _ {
return nil
}
return self.mainContext.fetchExisting(objectID)
}
/**
@@ -78,10 +61,9 @@ public extension DataStack {
- parameter objects: an array of `NSManagedObject`s created/fetched outside the `DataStack`
- returns: the `NSManagedObject` array for objects that exists in the `DataStack`
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == T>(objects: S) -> [T] {
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return objects.flatMap { (try? self.mainContext.existingObjectWithID($0.objectID)) as? T }
return self.mainContext.fetchExisting(objects)
}
/**
@@ -90,10 +72,9 @@ public extension DataStack {
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `DataStack`
*/
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == NSManagedObjectID>(objectIDs: S) -> [T] {
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return objectIDs.flatMap { (try? self.mainContext.existingObjectWithID($0)) as? T }
return self.mainContext.fetchExisting(objectIDs)
}
/**
@@ -103,11 +84,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchOne(from, fetchClauses)
@@ -120,11 +100,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchOne(from, fetchClauses)
@@ -137,11 +116,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchAll(from, fetchClauses)
@@ -154,11 +132,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchAll(from, fetchClauses)
@@ -171,11 +148,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchCount(from, fetchClauses)
@@ -188,11 +164,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchCount(from, fetchClauses)
@@ -205,11 +180,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectID(from, fetchClauses)
@@ -222,11 +196,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectID(from, fetchClauses)
@@ -239,11 +212,10 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectIDs(from, fetchClauses)
@@ -256,16 +228,18 @@ public extension DataStack {
- 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
*/
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectIDs(from, fetchClauses)
}
// MARK: QueryableSource
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -276,11 +250,10 @@ public extension DataStack {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryValue(from, selectClause, queryClauses)
@@ -296,11 +269,10 @@ public extension DataStack {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryValue(from, selectClause, queryClauses)
@@ -316,11 +288,10 @@ public extension DataStack {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
@@ -336,13 +307,23 @@ public extension DataStack {
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
CoreStore.assert(
NSThread.isMainThread(),
Thread.isMainThread,
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
}
// MARK: FetchableSource, QueryableSource
/**
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
public func internalContext() -> NSManagedObjectContext {
return self.mainContext
}
}

View File

@@ -0,0 +1,163 @@
//
// FetchableSource.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - FetchableSource
/**
Encapsulates containers which manages an internal `NSManagedObjectContext`, such as `DataStack`s and transactions, that can be used for fetching objects. CoreStore provides implementations for this protocol and should be used as a read-only abstraction.
*/
public protocol FetchableSource: class {
/**
Fetches the `NSManagedObject` 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
- returns: the `NSManagedObject` instance if the object exists in the `FetchableSource`'s context, or `nil` if not found.
*/
func fetchExisting<T: NSManagedObject>(_ object: T) -> T?
/**
Fetches the `NSManagedObject` instance in the `FetchableSource`'s context from an `NSManagedObjectID`.
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `FetchableSource`, or `nil` if not found.
*/
func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T?
/**
Fetches the `NSManagedObject` 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
- returns: the `NSManagedObject` array for objects that exists in the `FetchableSource`
*/
func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T
/**
Fetches the `NSManagedObject` instances in the `FetchableSource`'s context from a list of `NSManagedObjectID`.
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `FetchableSource`'s context
*/
func fetchExisting<T: NSManagedObject, 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.
- 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.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T?
/**
Fetches the first `NSManagedObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the first `NSManagedObject` instance that satisfies the specified `FetchClause`s
*/
func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T?
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]?
/**
Fetches all `NSManagedObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: all `NSManagedObject` instances that satisfy the specified `FetchClause`s
*/
func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]?
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int?
/**
Fetches the number of `NSManagedObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
- 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.
- returns: the number `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchCount<T: NSManagedObject>(_ 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.
- 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.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
func fetchObjectID<T: NSManagedObject>(_ 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.
- 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.
- returns: the `NSManagedObjectID` for the first `NSManagedObject` that satisfies the specified `FetchClause`s
*/
func fetchObjectID<T: NSManagedObject>(_ 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.
- 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.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchObjectIDs<T: NSManagedObject>(_ 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.
- 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.
- returns: the `NSManagedObjectID` for all `NSManagedObject`s that satisfy the specified `FetchClause`s
*/
func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]?
/**
The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
*/
func internalContext() -> NSManagedObjectContext
}

View File

@@ -34,7 +34,7 @@ import CoreData
*/
public protocol FetchClause {
func applyToFetchRequest(fetchRequest: NSFetchRequest)
func applyToFetchRequest<T: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<T>)
}
@@ -45,7 +45,7 @@ public protocol FetchClause {
*/
public protocol QueryClause {
func applyToFetchRequest(fetchRequest: NSFetchRequest)
func applyToFetchRequest<T: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<T>)
}
@@ -56,5 +56,5 @@ public protocol QueryClause {
*/
public protocol DeleteClause {
func applyToFetchRequest(fetchRequest: NSFetchRequest)
func applyToFetchRequest<T: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<T>)
}

View File

@@ -0,0 +1,89 @@
//
// QueryableSource.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - QueryableSource
/**
Encapsulates containers which manages an internal `NSManagedObjectContext`, such as `DataStack`s and transactions, that can be used for querying values. CoreStore provides implementations for this protocol and should be used as a read-only abstraction.
*/
public protocol QueryableSource: class {
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U?
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U?
/**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]?
/**
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
- parameter from: a `From` clause indicating the entity type
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
*/
func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]?
/**
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 internalContext() -> NSManagedObjectContext
}

View File

@@ -36,27 +36,29 @@ public extension BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type
- parameter source: the object to import values from
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods
- throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the created `ImportableObject` instance, or `nil` if the import was ignored
*/
public func importObject<T where T: NSManagedObject, T: ImportableObject>(
into: Into<T>,
source: T.ImportSource) throws -> T? {
public func importObject<T>(
_ into: Into<T>,
source: T.ImportSource) throws -> T? where T: NSManagedObject, T: ImportableObject {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
)
return try cs_autoreleasepool {
return try autoreleasepool {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
let entityType = into.entityClass as! T.Type
guard entityType.shouldInsert(from: source, in: self) else {
return nil
}
let object = self.create(into)
try object.didInsertFromImportSource(source, inTransaction: self)
try object.didInsert(from: source, in: self)
return object
}
}
@@ -66,25 +68,25 @@ public extension BaseDataTransaction {
- parameter object: the `NSManagedObject` to update
- parameter source: the object to import values from
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods
- throws: an `Error` thrown from any of the `ImportableObject` methods
*/
public func importObject<T where T: NSManagedObject, T: ImportableObject>(
object: T,
source: T.ImportSource) throws {
public func importObject<T>(
_ object: T,
source: T.ImportSource) throws where T: NSManagedObject, T: ImportableObject {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(object)) outside the transaction's designated queue."
)
try cs_autoreleasepool {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
try autoreleasepool {
let entityType = type(of: object)
guard entityType.shouldInsert(from: source, in: self) else {
return
}
try object.didInsertFromImportSource(source, inTransaction: self)
try object.didInsert(from: source, in: self)
}
}
@@ -93,31 +95,31 @@ public extension BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type
- parameter sourceArray: the array of objects to import values from
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods
- throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the array of created `ImportableObject` instances
*/
public func importObjects<T, S: SequenceType where T: NSManagedObject, T: ImportableObject, S.Generator.Element == T.ImportSource>(
into: Into<T>,
sourceArray: S) throws -> [T] {
public func importObjects<T, S: Sequence>(
_ into: Into<T>,
sourceArray: S) throws -> [T] where T: NSManagedObject, T: ImportableObject, S.Iterator.Element == T.ImportSource {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
)
return try cs_autoreleasepool {
return try autoreleasepool {
return try sourceArray.flatMap { (source) -> T? in
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
let entityType = into.entityClass as! T.Type
guard entityType.shouldInsert(from: source, in: self) else {
return nil
}
return try cs_autoreleasepool {
return try autoreleasepool {
let object = self.create(into)
try object.didInsertFromImportSource(source, inTransaction: self)
try object.didInsert(from: source, in: self)
return object
}
}
@@ -129,46 +131,45 @@ public extension BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type
- parameter source: the object to import values from
- throws: an `ErrorType` thrown from any of the `ImportableUniqueObject` methods
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored
*/
public func importUniqueObject<T where T: NSManagedObject, T: ImportableUniqueObject>(
into: Into<T>,
source: T.ImportSource) throws -> T? {
public func importUniqueObject<T>(
_ into: Into<T>,
source: T.ImportSource) throws -> T? where T: NSManagedObject, T: ImportableUniqueObject {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
)
return try cs_autoreleasepool {
let uniqueIDKeyPath = T.uniqueIDKeyPath
guard let uniqueIDValue = try T.uniqueIDFromImportSource(source, inTransaction: self) else {
return try autoreleasepool {
let entityType = into.entityClass as! T.Type
let uniqueIDKeyPath = entityType.uniqueIDKeyPath
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
return nil
}
if let object = self.fetchOne(From(T), Where(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
if let object = self.fetchOne(From(entityType), Where(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
guard T.shouldUpdateFromImportSource(source, inTransaction: self) else {
guard entityType.shouldUpdate(from: source, in: self) else {
return nil
}
try object.updateFromImportSource(source, inTransaction: self)
try object.update(from: source, in: self)
return object
}
else {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
guard entityType.shouldInsert(from: source, in: self) else {
return nil
}
let object = self.create(into)
object.uniqueIDValue = uniqueIDValue
try object.didInsertFromImportSource(source, inTransaction: self)
try object.didInsert(from: source, in: self)
return object
}
}
@@ -176,79 +177,79 @@ public extension BaseDataTransaction {
/**
Updates existing `ImportableUniqueObject`s or creates them by importing from the specified array of import sources.
- Warning: While the array returned from `importUniqueObjects(...)` correctly maps to the order of `sourceArray`, the order of objects called with `ImportableUniqueObject` methods is arbitrary. Do not make assumptions that any particular object will be imported ahead or after another object.
`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.
- parameter into: an `Into` clause specifying the entity type
- parameter sourceArray: the array of objects to import values from
- parameter preProcess: a closure that lets the caller tweak the internal `UniqueIDType`-to-`ImportSource` mapping to be used for importing. Callers can remove from/add to/update `mapping` and return the updated array from the closure.
- throws: an `ErrorType` thrown from any of the `ImportableUniqueObject` methods
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the array of created/updated `ImportableUniqueObject` instances
*/
public func importUniqueObjects<T, S: SequenceType where T: NSManagedObject, T: ImportableUniqueObject, S.Generator.Element == T.ImportSource>(
into: Into<T>,
public func importUniqueObjects<T, S: Sequence>(
_ into: Into<T>,
sourceArray: S,
@noescape preProcess: (mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] {
preProcess: @escaping (_ mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] where T: NSManagedObject, T: ImportableUniqueObject, S.Iterator.Element == T.ImportSource {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
)
return try cs_autoreleasepool {
var mapping = Dictionary<T.UniqueIDType, T.ImportSource>()
let sortedIDs = try cs_autoreleasepool {
return try autoreleasepool {
let entityType = into.entityClass as! T.Type
var importSourceByID = Dictionary<T.UniqueIDType, T.ImportSource>()
let sortedIDs = try autoreleasepool {
return try sourceArray.flatMap { (source) -> T.UniqueIDType? in
guard let uniqueIDValue = try T.uniqueIDFromImportSource(source, inTransaction: self) else {
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
return nil
}
mapping[uniqueIDValue] = source
importSourceByID[uniqueIDValue] = source // effectively replaces duplicate with the latest
return uniqueIDValue
}
}
mapping = try cs_autoreleasepool { try preProcess(mapping: mapping) }
var objects = Dictionary<T.UniqueIDType, T>()
for object in self.fetchAll(From(T), Where(T.uniqueIDKeyPath, isMemberOf: sortedIDs)) ?? [] {
importSourceByID = try autoreleasepool { try preProcess(importSourceByID) }
var existingObjectsByID = Dictionary<T.UniqueIDType, T>()
self.fetchAll(From(entityType), Where(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))?
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
var processedObjectIDs = Set<T.UniqueIDType>()
var result = [T]()
for objectID in sortedIDs where !processedObjectIDs.contains(objectID) {
try cs_autoreleasepool {
guard let source = importSourceByID[objectID] else {
let uniqueIDValue = object.uniqueIDValue
guard let source = mapping.removeValueForKey(uniqueIDValue)
where T.shouldUpdateFromImportSource(source, inTransaction: self) else {
continue
}
try autoreleasepool {
if let object = existingObjectsByID[objectID] {
guard entityType.shouldUpdate(from: source, in: self) else {
return
}
try object.update(from: source, in: self)
result.append(object)
}
try object.updateFromImportSource(source, inTransaction: self)
objects[uniqueIDValue] = object
}
}
for (uniqueIDValue, source) in mapping {
try cs_autoreleasepool {
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
else if entityType.shouldInsert(from: source, in: self) {
return
let object = self.create(into)
object.uniqueIDValue = objectID
try object.didInsert(from: source, in: self)
result.append(object)
}
let object = self.create(into)
object.uniqueIDValue = uniqueIDValue
try object.didInsertFromImportSource(source, inTransaction: self)
objects[uniqueIDValue] = object
processedObjectIDs.insert(objectID)
}
}
return sortedIDs.flatMap { objects[$0] }
return result
}
}
}

View File

@@ -40,7 +40,7 @@ import CoreData
CoreStore.beginAsynchronous { (transaction) -> Void in
let json: NSDictionary = // ...
let person = try! transaction.importObject(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
source: json
)
// ...
@@ -62,15 +62,24 @@ public protocol ImportableObject: class {
- parameter transaction: the transaction that invoked the import. Use the transaction to fetch or create related objects if needed.
- returns: `true` if an object should be created from `source`. Return `false` to ignore.
*/
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
/**
Implements the actual importing of data from `source`. Implementers should pull values from `source` and assign them to the receiver's attributes. Note that throwing from this method will cause subsequent imports that are part of the same `importObjects(:sourceArray:)` call to be cancelled.
- parameter source: the object to import from
- parameter transaction: the transaction that invoked the import. Use the transaction to fetch or create related objects if needed.
*/
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
*/
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
// MARK: Deprecated
@available(*, deprecated: 3.0.0, renamed: "shouldInsert(from:in:)")
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
@available(*, deprecated: 3.0.0, renamed: "didInsert(from:in:)")
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
}
@@ -78,8 +87,21 @@ public protocol ImportableObject: class {
public extension ImportableObject {
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool {
return true
}
// MARK: Deprecated
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
return Self.shouldInsert(from: source, in: transaction)
}
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
try self.didInsert(from: source, in: transaction)
}
}

View File

@@ -41,7 +41,7 @@ import CoreData
CoreStore.beginAsynchronous { (transaction) -> Void in
let json: NSDictionary = // ...
let person = try! transaction.importUniqueObject(
Into(MyPersonEntity),
Into<MyPersonEntity>(),
source: json
)
// ...
@@ -72,13 +72,13 @@ public protocol ImportableUniqueObject: ImportableObject {
var uniqueIDValue: UniqueIDType { get set }
/**
Return `true` if an object should be created from `source`. Return `false` to ignore and skip `source`. The default implementation returns the value returned by the `shouldUpdateFromImportSource(:inTransaction:)` implementation.
Return `true` if an object should be created from `source`. Return `false` to ignore and skip `source`. The default implementation returns the value returned by the `shouldUpdate(from:in:)` implementation.
- parameter source: the object to import from
- parameter transaction: the transaction that invoked the import. Use the transaction to fetch or create related objects if needed.
- returns: `true` if an object should be created from `source`. Return `false` to ignore.
*/
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
/**
Return `true` if an object should be updated from `source`. Return `false` to ignore and skip `source`. The default implementation returns `true`.
@@ -87,24 +87,24 @@ public protocol ImportableUniqueObject: ImportableObject {
- parameter transaction: the transaction that invoked the import. Use the transaction to fetch or create related objects if needed.
- returns: `true` if an object should be updated from `source`. Return `false` to ignore.
*/
static func shouldUpdateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
static func shouldUpdate(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
/**
Return the unique ID as extracted from `source`. This method is called before `shouldInsertFromImportSource(...)` or `shouldUpdateFromImportSource(...)`. Return `nil` to skip importing from `source`. Note that throwing from this method will cause subsequent imports that are part of the same `importUniqueObjects(:sourceArray:)` call to be cancelled.
Return the unique ID as extracted from `source`. This method is called before `shouldInsert(from:in:)` or `shouldUpdate(from:in:)`. Return `nil` to skip importing from `source`. Note that throwing from this method will cause subsequent imports that are part of the same `importUniqueObjects(:sourceArray:)` call to be cancelled.
- parameter source: the object to import from
- parameter transaction: the transaction that invoked the import. Use the transaction to fetch or create related objects if needed.
- returns: the unique ID as extracted from `source`, or `nil` to skip importing from `source`.
*/
static func uniqueIDFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType?
static func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> UniqueIDType?
/**
Implements the actual importing of data from `source`. This method is called just after the object is created and assigned its unique ID as returned from `uniqueIDFromImportSource(...)`. Implementers should pull values from `source` and assign them to the receiver's attributes. Note that throwing from this method will cause subsequent imports that are part of the same `importUniqueObjects(:sourceArray:)` call to be cancelled. The default implementation simply calls `updateFromImportSource(...)`.
Implements the actual importing of data from `source`. This method is called just after the object is created and assigned its unique ID as returned from `uniqueID(from:in:)`. Implementers should pull values from `source` and assign them to the receiver's attributes. Note that throwing from this method will cause subsequent imports that are part of the same `importUniqueObjects(:sourceArray:)` call to be cancelled. The default implementation simply calls `update(from:in:)`.
- parameter source: the object to import from
- parameter transaction: the transaction that invoked the import. Use the transaction to fetch or create related objects if needed.
*/
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
/**
Implements the actual importing of data from `source`. This method is called just after the existing object is fetched using its unique ID. Implementers should pull values from `source` and assign them to the receiver's attributes. Note that throwing from this method will cause subsequent imports that are part of the same `importUniqueObjects(:sourceArray:)` call to be cancelled.
@@ -112,7 +112,25 @@ public protocol ImportableUniqueObject: ImportableObject {
- parameter source: the object to import from
- parameter transaction: the transaction that invoked the import. Use the transaction to fetch or create related objects if needed.
*/
func updateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
func update(from source: ImportSource, in transaction: BaseDataTransaction) throws
// MARK: Deprecated
@available(*, deprecated: 3.0.0, renamed: "shouldInsert(from:in:)")
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
@available(*, deprecated: 3.0.0, renamed: "shouldUpdate(from:in:)")
static func shouldUpdateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
@available(*, deprecated: 3.0.0, renamed: "uniqueID(from:in:)")
static func uniqueIDFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType?
@available(*, deprecated: 3.0.0, renamed: "didInsert(from:in:)")
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
@available(*, deprecated: 3.0.0, renamed: "update(from:in:)")
func updateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
}
@@ -120,18 +138,46 @@ public protocol ImportableUniqueObject: ImportableObject {
public extension ImportableUniqueObject {
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool {
return self.shouldUpdateFromImportSource(source, inTransaction: transaction)
return Self.shouldUpdate(from: source, in: transaction)
}
static func shouldUpdateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
static func shouldUpdate(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool{
return true
}
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
func didInsert(from source: Self.ImportSource, in transaction: BaseDataTransaction) throws {
try self.updateFromImportSource(source, inTransaction: transaction)
try self.update(from: source, in: transaction)
}
// MARK: Deprecated
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
return Self.shouldInsert(from: source, in: transaction)
}
static func shouldUpdateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
return Self.shouldUpdate(from: source, in: transaction)
}
static func uniqueIDFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType? {
return try Self.uniqueID(from: source, in: transaction)
}
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
try self.didInsert(from: source, in: transaction)
}
func updateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
try self.update(from: source, in: transaction)
}
}

View File

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

View File

@@ -1,5 +1,5 @@
//
// CoreStoreFetchRequest.swift
// CoreStoreFetchRequest+CoreStore.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
@@ -29,14 +29,13 @@ import CoreData
// MARK: - CoreStoreFetchRequest
// Bugfix for NSFetchRequest messing up memory management for `affectedStores`
// http://stackoverflow.com/questions/14396375/nsfetchedresultscontroller-crashes-in-ios-6-if-affectedstores-is-specified
internal final class CoreStoreFetchRequest: NSFetchRequest {
internal extension CoreStoreFetchRequest {
@objc
override var affectedStores: [NSPersistentStore]? {
// MARK: Internal
@nonobjc
internal func dynamicCast<U: NSFetchRequestResult>() -> NSFetchRequest<U> {
get { return super.affectedStores }
set { super.affectedStores = newValue }
return unsafeBitCast(self, to: NSFetchRequest<U>.self)
}
}

View File

@@ -31,12 +31,12 @@ import CoreData
// MARK: - CoreStoreFetchedResultsController
internal final class CoreStoreFetchedResultsController: NSFetchedResultsController {
internal final class CoreStoreFetchedResultsController: NSFetchedResultsController<NSManagedObject> {
// MARK: Internal
@nonobjc
internal convenience init<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: (fetchRequest: NSFetchRequest) -> Void) {
internal convenience init<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
self.init(
context: dataStack.mainContext,
@@ -48,14 +48,14 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
}
@nonobjc
internal init<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: (fetchRequest: NSFetchRequest) -> Void) {
internal init<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
_ = from?.applyToFetchRequest(
fetchRequest,
context: context,
applyAffectedStores: false
)
applyFetchClauses(fetchRequest: fetchRequest)
applyFetchClauses(fetchRequest)
if let from = from {
@@ -68,7 +68,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
guard let from = (fetchRequest.entity.flatMap { $0.managedObjectClassName }).flatMap(NSClassFromString).flatMap(From.init) else {
CoreStore.abort("Attempted to create an \(cs_typeName(NSFetchedResultsController)) without a \(cs_typeName(From)) clause or an \(cs_typeName(NSEntityDescription)).")
CoreStore.abort("Attempted to create a \(CoreStoreFetchedResultsController.self) without a \(cs_typeName(From<T>.self)) clause or an \(cs_typeName(NSEntityDescription.self)).")
}
self.reapplyAffectedStores = { fetchRequest, context in
@@ -88,16 +88,22 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
@nonobjc
internal func performFetchFromSpecifiedStores() throws {
if !self.reapplyAffectedStores(fetchRequest: self.fetchRequest, context: self.managedObjectContext) {
if !self.reapplyAffectedStores(self.fetchRequest, self.managedObjectContext) {
CoreStore.log(
.Warning,
message: "Attempted to perform a fetch on an \(cs_typeName(NSFetchedResultsController)) but could not find any persistent store for the entity \(cs_typeName(self.fetchRequest.entityName))"
.warning,
message: "Attempted to perform a fetch on an \(cs_typeName(self)) but could not find any persistent store for the entity \(cs_typeName(self.fetchRequest.entityName))"
)
}
try self.performFetch()
}
@nonobjc
internal func dynamicCast<U: NSFetchRequestResult>() -> NSFetchedResultsController<U> {
return unsafeBitCast(self, to: NSFetchedResultsController<U>.self)
}
deinit {
self.delegate = nil
@@ -107,7 +113,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
// MARK: Private
@nonobjc
private let reapplyAffectedStores: (fetchRequest: NSFetchRequest, context: NSManagedObjectContext) -> Bool
private let reapplyAffectedStores: (_ fetchRequest: NSFetchRequest<NSManagedObject>, _ context: NSManagedObjectContext) -> Bool
}
#endif

View File

@@ -0,0 +1,97 @@
//
// DispatchQueue+CoreStore.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - DispatchQueue
internal extension DispatchQueue {
@nonobjc
internal static func serial(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
return DispatchQueue(
label: label,
qos: qos,
attributes: [],
autoreleaseFrequency: .inherit,
target: nil
)
}
@nonobjc
internal static func concurrent(_ label: String, qos: DispatchQoS = .default) -> DispatchQueue {
return DispatchQueue(
label: label,
qos: qos,
attributes: .concurrent,
autoreleaseFrequency: .inherit,
target: nil
)
}
@nonobjc
internal func cs_isCurrentExecutionContext() -> Bool {
let specific = ObjectIdentifier(self)
self.setSpecific(key: Static.specificKey, value: specific)
return DispatchQueue.getSpecific(key: Static.specificKey) == specific
}
@nonobjc
internal func cs_sync<T>(_ closure: () throws -> T) rethrows -> T {
return try self.sync { try autoreleasepool(invoking: closure) }
}
@nonobjc
internal func cs_async(_ closure: @escaping () -> Void) {
self.async { autoreleasepool(invoking: closure) }
}
@nonobjc
internal func cs_barrierSync<T>(_ closure: () throws -> T) rethrows -> T {
return try self.sync(flags: .barrier) { try autoreleasepool(invoking: closure) }
}
@nonobjc
internal func cs_barrierAsync(_ closure: @escaping () -> Void) {
self.async(flags: .barrier) { autoreleasepool(invoking: closure) }
}
// MARK: Private
private enum Static {
static let specificKey = DispatchSpecificKey<ObjectIdentifier>()
}
}

View File

@@ -33,21 +33,21 @@ import CoreData
internal protocol FetchedResultsControllerHandler: class {
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeObject anObject: Any, atIndexPath indexPath: IndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
func controllerWillChangeContent(controller: NSFetchedResultsController)
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
func controllerDidChangeContent(controller: NSFetchedResultsController)
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String?
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String?) -> String?
}
// MARK: - FetchedResultsControllerDelegate
internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {
internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObject>: NSObject, NSFetchedResultsControllerDelegate {
// MARK: Internal
@@ -58,7 +58,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
internal weak var handler: FetchedResultsControllerHandler?
@nonobjc
internal weak var fetchedResultsController: NSFetchedResultsController? {
internal weak var fetchedResultsController: CoreStoreFetchedResultsController? {
didSet {
@@ -76,7 +76,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
// MARK: NSFetchedResultsControllerDelegate
@objc
dynamic func controllerWillChangeContent(controller: NSFetchedResultsController) {
dynamic func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
guard self.enabled else {
@@ -90,7 +90,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
}
@objc
dynamic func controllerDidChangeContent(controller: NSFetchedResultsController) {
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
guard self.enabled else {
@@ -101,14 +101,14 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
}
@objc
dynamic func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
guard self.enabled else {
return
}
guard let actualType = NSFetchedResultsChangeType(rawValue: type.rawValue) else {
guard var actualType = NSFetchedResultsChangeType(rawValue: type.rawValue) else {
// This fix is for a bug where iOS passes 0 for NSFetchedResultsChangeType, but this is not a valid enum case.
// Swift will then always execute the first case of the switch causing strange behaviour.
@@ -120,21 +120,42 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
// http://stackoverflow.com/questions/31383760/ios-9-attempt-to-delete-and-reload-the-same-index-path/31384014#31384014
// https://forums.developer.apple.com/message/9998#9998
// https://forums.developer.apple.com/message/31849#31849
if #available(iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
// I don't know if iOS 10 even attempted to fix this mess...
if case .update = actualType,
indexPath != nil,
newIndexPath != nil {
actualType = .move
}
}
if #available(iOS 10.0, tvOS 10.0, watchOS 3.0, *) {
// I don't know if iOS 10 even attempted to fix this mess...
if case .update = actualType,
indexPath != nil && newIndexPath != nil {
actualType = .move
}
}
switch actualType {
case .Update:
guard let section = indexPath?.indexAtPosition(0) else {
case .update:
guard let section = indexPath?[0] else {
return
}
if self.deletedSections.contains(section)
|| self.insertedSections.contains(section) {
return
return
}
case .Move:
case .move:
guard let indexPath = indexPath, let newIndexPath = newIndexPath else {
return
@@ -143,25 +164,25 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
break
}
if self.insertedSections.contains(indexPath.indexAtPosition(0)) {
if self.insertedSections.contains(indexPath[0]) {
// Observers that handle the .Move change are advised to delete then reinsert the object instead of just moving. This is especially true when indexPath and newIndexPath are equal. For example, calling tableView.moveRowAtIndexPath(_:toIndexPath) when both indexPaths are the same will crash the tableView.
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: indexPath,
forChangeType: .Move,
forChangeType: .move,
newIndexPath: newIndexPath
)
return
}
if self.deletedSections.contains(indexPath.indexAtPosition(0)) {
if self.deletedSections.contains(indexPath[0]) {
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: nil,
forChangeType: .Insert,
forChangeType: .insert,
newIndexPath: indexPath
)
return
@@ -170,7 +191,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
controller,
didChangeObject: anObject,
atIndexPath: indexPath,
forChangeType: .Update,
forChangeType: .update,
newIndexPath: nil
)
return
@@ -189,7 +210,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
}
@objc
dynamic func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
guard self.enabled else {
@@ -198,8 +219,8 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
switch type {
case .Delete: self.deletedSections.insert(sectionIndex)
case .Insert: self.insertedSections.insert(sectionIndex)
case .delete: self.deletedSections.insert(sectionIndex)
case .insert: self.insertedSections.insert(sectionIndex)
default: break
}
@@ -212,7 +233,7 @@ internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResult
}
@objc
dynamic func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String) -> String? {
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String) -> String? {
return self.handler?.controller(
controller,

View File

@@ -25,70 +25,9 @@
import Foundation
// MARK: Associated Objects
// MARK: - Custom AutoreleasePool
internal func cs_autoreleasepool(@noescape closure: () -> Void) {
autoreleasepool(closure)
}
internal func cs_autoreleasepool<T>(@noescape closure: () -> T) -> T {
var closureValue: T!
autoreleasepool {
closureValue = closure()
}
return closureValue
}
internal func cs_autoreleasepool<T>(@noescape closure: () throws -> T) throws -> T {
var closureValue: T!
var closureError: ErrorType?
autoreleasepool {
do {
closureValue = try closure()
}
catch {
closureError = error
}
}
if let closureError = closureError {
throw closureError
}
return closureValue
}
internal func cs_autoreleasepool(@noescape closure: () throws -> Void) throws {
var closureError: ErrorType?
autoreleasepool {
do {
try closure()
}
catch {
closureError = error
}
}
if let closureError = closureError {
throw closureError
}
}
internal func cs_getAssociatedObjectForKey<T: AnyObject>(key: UnsafePointer<Void>, inObject object: AnyObject) -> T? {
internal func cs_getAssociatedObjectForKey<T: AnyObject>(_ key: UnsafeRawPointer, inObject object: Any) -> T? {
switch objc_getAssociatedObject(object, key) {
@@ -103,17 +42,17 @@ internal func cs_getAssociatedObjectForKey<T: AnyObject>(key: UnsafePointer<Void
}
}
internal func cs_setAssociatedRetainedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
internal func cs_setAssociatedRetainedObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
internal func cs_setAssociatedCopiedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
internal func cs_setAssociatedCopiedObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
internal func cs_setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
internal func cs_setAssociatedWeakObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
if let associatedObject = associatedObject {
@@ -128,22 +67,27 @@ internal func cs_setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, for
// MARK: Printing Utilities
internal func cs_typeName<T>(value: T) -> String {
internal func cs_typeName<T>(_ value: T) -> String {
return "'\(String(reflecting: value.dynamicType))'"
return "'\(String(reflecting: type(of: value)))'"
}
internal func cs_typeName<T>(value: T.Type) -> String {
internal func cs_typeName<T>(_ value: T.Type) -> String {
return "'\(value)'"
}
internal func cs_typeName(value: AnyClass) -> String {
internal func cs_typeName(_ value: AnyClass) -> String {
return "'\(value)'"
}
internal func cs_typeName(name: String?) -> String {
internal func cs_typeName(_ name: String) -> String {
return "<\(name)>"
}
internal func cs_typeName(_ name: String?) -> String {
return "<\(name ?? "unknown")>"
}

View File

@@ -29,15 +29,15 @@ import CoreData
// MARK: - MigrationManager
internal final class MigrationManager: NSMigrationManager, NSProgressReporting {
internal final class MigrationManager: NSMigrationManager, ProgressReporting {
// MARK: NSObject
override func didChangeValueForKey(key: String) {
override func didChangeValue(forKey key: String) {
super.didChangeValueForKey(key)
super.didChangeValue(forKey: key)
guard key == "migrationProgress" else {
guard key == #keyPath(NSMigrationManager.migrationProgress) else {
return
}
@@ -48,7 +48,7 @@ internal final class MigrationManager: NSMigrationManager, NSProgressReporting {
// MARK: NSMigrationManager
init(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, progress: NSProgress) {
init(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, progress: Progress) {
self.progress = progress
@@ -56,7 +56,7 @@ internal final class MigrationManager: NSMigrationManager, NSProgressReporting {
}
// MARK: NSProgressReporting
// MARK: ProgressReporting
let progress: NSProgress
let progress: Progress
}

View File

@@ -25,9 +25,6 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - NSManagedObjectContext
@@ -50,7 +47,7 @@ internal extension NSManagedObjectContext {
set {
cs_setAssociatedCopiedObject(
NSNumber(bool: newValue),
NSNumber(value: newValue),
forKey: &PropertyKeys.shouldCascadeSavesToParent,
inObject: self
)
@@ -58,40 +55,30 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func entityDescriptionForEntityType(entity: NSManagedObject.Type) -> NSEntityDescription? {
internal func entityDescriptionForEntityType(_ entity: NSManagedObject.Type) -> NSEntityDescription? {
return self.entityDescriptionForEntityClass(entity)
}
@nonobjc
internal func entityDescriptionForEntityClass(entity: AnyClass) -> NSEntityDescription? {
internal func entityDescriptionForEntityClass(_ entity: AnyClass) -> NSEntityDescription? {
guard let entityName = self.parentStack?.entityNameForEntityClass(entity) else {
return nil
}
return NSEntityDescription.entityForName(
entityName,
inManagedObjectContext: self
return NSEntityDescription.entity(
forEntityName: entityName,
in: self
)
}
@nonobjc
internal func setupForCoreStoreWithContextName(contextName: String) {
#if USE_FRAMEWORKS
self.name = contextName
#else
if #available(iOS 8.0, *) {
self.name = contextName
}
#endif
internal func setupForCoreStoreWithContextName(_ contextName: String) {
self.name = contextName
self.observerForWillSaveNotification = NotificationObserver(
notificationName: NSManagedObjectContextWillSaveNotification,
notificationName: NSNotification.Name.NSManagedObjectContextWillSave,
object: self,
closure: { (note) -> Void in
@@ -105,7 +92,7 @@ internal extension NSManagedObjectContext {
do {
try context.obtainPermanentIDsForObjects(Array(insertedObjects))
try context.obtainPermanentIDs(for: Array(insertedObjects))
}
catch {

View File

@@ -29,20 +29,20 @@ import CoreData
// MARK: - NSManagedObjectContext
internal extension NSManagedObjectContext {
extension NSManagedObjectContext: FetchableSource, QueryableSource {
// MARK: Internal: Fetch Existing
// MARK: FetchableSource
@nonobjc
internal func fetchExisting<T: NSManagedObject>(object: T) -> T? {
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
if object.objectID.temporaryID {
if object.objectID.isTemporaryID {
do {
try withExtendedLifetime(self) { (context: NSManagedObjectContext) -> Void in
try context.obtainPermanentIDsForObjects([object])
try context.obtainPermanentIDs(for: [object])
}
}
catch {
@@ -54,10 +54,9 @@ internal extension NSManagedObjectContext {
return nil
}
}
do {
let existingObject = try self.existingObjectWithID(object.objectID)
let existingObject = try self.existingObject(with: object.objectID)
return (existingObject as! T)
}
catch {
@@ -70,125 +69,86 @@ internal extension NSManagedObjectContext {
}
}
// MARK: Internal: Fetch One
@nonobjc
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
do {
return (try self.existingObject(with: objectID) as! T)
}
catch _ {
return nil
}
}
@nonobjc
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
return objects.flatMap { (try? self.existingObject(with: $0.objectID)) as? T }
}
@nonobjc
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
return objectIDs.flatMap { (try? self.existingObject(with: $0)) as? T }
}
@nonobjc
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.fetchOne(from, fetchClauses)
}
@nonobjc
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
fetchRequest.resultType = .ManagedObjectResultType
fetchRequest.resultType = .managedObjectResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchOne(fetchRequest)
return self.fetchOne(fetchRequest.dynamicCast())
}
@nonobjc
internal func fetchOne<T: NSManagedObject>(fetchRequest: NSFetchRequest) -> T? {
var fetchResults: [T]?
var fetchError: ErrorType?
self.performBlockAndWait {
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [T]
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
// MARK: Internal: Fetch All
@nonobjc
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.fetchAll(from, fetchClauses)
}
@nonobjc
internal func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectResultType
fetchRequest.resultType = .managedObjectResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchAll(fetchRequest)
return self.fetchAll(fetchRequest.dynamicCast())
}
@nonobjc
internal func fetchAll<T: NSManagedObject>(fetchRequest: NSFetchRequest) -> [T]? {
var fetchResults: [T]?
var fetchError: ErrorType?
self.performBlockAndWait {
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [T]
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults
}
// MARK: Internal: Count
@nonobjc
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses)
}
@nonobjc
internal func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -198,120 +158,65 @@ internal extension NSManagedObjectContext {
return nil
}
return self.fetchCount(fetchRequest)
return self.fetchCount(fetchRequest.dynamicCast())
}
@nonobjc
internal func fetchCount(fetchRequest: NSFetchRequest) -> Int? {
var count = 0
var error: NSError?
self.performBlockAndWait {
count = self.countForFetchRequest(fetchRequest, error: &error)
}
if count == NSNotFound {
CoreStore.log(
CoreStoreError(error),
"Failed executing fetch request."
)
return nil
}
return count
}
// MARK: Internal: Object ID
@nonobjc
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses)
}
@nonobjc
internal func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 1
fetchRequest.resultType = .ManagedObjectIDResultType
fetchRequest.resultType = .managedObjectIDResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchObjectID(fetchRequest)
return self.fetchObjectID(fetchRequest.dynamicCast())
}
@nonobjc
internal func fetchObjectID(fetchRequest: NSFetchRequest) -> NSManagedObjectID? {
var fetchResults: [NSManagedObjectID]?
var fetchError: ErrorType?
self.performBlockAndWait {
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObjectID]
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
// MARK: Internal: Object IDs
@nonobjc
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses)
}
@nonobjc
internal func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectIDResultType
fetchRequest.resultType = .managedObjectIDResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchObjectIDs(fetchRequest)
return self.fetchObjectIDs(fetchRequest.dynamicCast())
}
@nonobjc
internal func fetchObjectIDs(fetchRequest: NSFetchRequest) -> [NSManagedObjectID]? {
internal func fetchObjectIDs(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> [NSManagedObjectID]? {
var fetchResults: [NSManagedObjectID]?
var fetchError: ErrorType?
self.performBlockAndWait {
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObjectID]
fetchResults = try self.fetch(fetchRequest)
}
catch {
@@ -326,85 +231,20 @@ internal extension NSManagedObjectContext {
)
return nil
}
return fetchResults
}
// MARK: Internal: Delete All
// MARK: QueryableSource
@nonobjc
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
return self.deleteAll(from, deleteClauses)
}
@nonobjc
internal func deleteAll<T: NSManagedObject>(from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectResultType
fetchRequest.returnsObjectsAsFaults = true
fetchRequest.includesPropertyValues = false
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.deleteAll(fetchRequest)
}
@nonobjc
internal func deleteAll(fetchRequest: NSFetchRequest) -> Int? {
var numberOfDeletedObjects: Int?
var fetchError: ErrorType?
self.performBlockAndWait {
cs_autoreleasepool {
do {
let fetchResults = try self.executeFetchRequest(fetchRequest) as? [NSManagedObject] ?? []
for object in fetchResults {
self.deleteObject(object)
}
numberOfDeletedObjects = fetchResults.count
}
catch {
fetchError = error
}
}
}
if numberOfDeletedObjects == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return numberOfDeletedObjects
}
// MARK: Internal: Value
@nonobjc
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
return self.queryValue(from, selectClause, queryClauses)
}
@nonobjc
internal func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -423,82 +263,13 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func queryValue<U: SelectValueResultType>(selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> U? {
var fetchResults: [AnyObject]?
var fetchError: ErrorType?
self.performBlockAndWait {
do {
fetchResults = try self.executeFetchRequest(fetchRequest)
}
catch {
fetchError = error
}
}
if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary,
let rawObject: AnyObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
return Select<U>.ReturnType.fromResultObject(rawObject)
}
return nil
}
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
@nonobjc
internal func queryValue(selectTerms: [SelectTerm], fetchRequest: NSFetchRequest) -> AnyObject? {
var fetchResults: [AnyObject]?
var fetchError: ErrorType?
self.performBlockAndWait {
do {
fetchResults = try self.executeFetchRequest(fetchRequest)
}
catch {
fetchError = error
}
}
if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary,
let rawObject: AnyObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
return rawObject
}
return nil
}
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
// MARK: Internal: Attributes
@nonobjc
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
return self.queryAttributes(from, selectClause, queryClauses)
}
@nonobjc
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -515,16 +286,210 @@ internal extension NSManagedObjectContext {
return self.queryAttributes(fetchRequest)
}
// MARK: FetchableSource, QueryableSource
@nonobjc
internal func queryAttributes(fetchRequest: NSFetchRequest) -> [[NSString: AnyObject]]? {
public func internalContext() -> NSManagedObjectContext {
var fetchResults: [AnyObject]?
var fetchError: ErrorType?
self.performBlockAndWait {
return self
}
}
// MARK: - NSManagedObjectContext (Internal)
internal extension NSManagedObjectContext {
// MARK: Fetching
@nonobjc
internal func fetchOne<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> T? {
var fetchResults: [T]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.executeFetchRequest(fetchRequest)
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
@nonobjc
internal func fetchAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> [T]? {
var fetchResults: [T]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults
}
@nonobjc
internal func fetchCount(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Int? {
var count = 0
var countError: Error?
self.performAndWait {
do {
count = try self.count(for: fetchRequest)
}
catch {
countError = error
}
}
if count == NSNotFound {
CoreStore.log(
CoreStoreError(countError),
"Failed executing count request."
)
return nil
}
return count
}
@nonobjc
internal func fetchObjectID(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> NSManagedObjectID? {
var fetchResults: [NSManagedObjectID]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if fetchResults == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return fetchResults?.first
}
// MARK: Querying
@nonobjc
internal func queryValue<U: SelectValueResultType>(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> U? {
var fetchResults: [Any]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary,
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
return Select<U>.ReturnType.fromResultObject(rawObject)
}
return nil
}
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
@nonobjc
internal func queryValue(_ selectTerms: [SelectTerm], fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Any? {
var fetchResults: [Any]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
fetchError = error
}
}
if let fetchResults = fetchResults {
if let rawResult = fetchResults.first as? NSDictionary,
let rawObject = rawResult[selectTerms.keyPathForFirstSelectTerm()] {
return rawObject
}
return nil
}
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
@nonobjc
internal func queryAttributes(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> [[String: Any]]? {
var fetchResults: [Any]?
var fetchError: Error?
self.performAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
}
catch {
@@ -542,4 +507,67 @@ internal extension NSManagedObjectContext {
)
return nil
}
// MARK: Deleting
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
return self.deleteAll(from, deleteClauses)
}
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .managedObjectResultType
fetchRequest.returnsObjectsAsFaults = true
fetchRequest.includesPropertyValues = false
deleteClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.deleteAll(fetchRequest.dynamicCast())
}
@nonobjc
internal func deleteAll<T: NSManagedObject>(_ fetchRequest: NSFetchRequest<T>) -> Int? {
var numberOfDeletedObjects: Int?
var fetchError: Error?
self.performAndWait {
autoreleasepool {
do {
let fetchResults = try self.fetch(fetchRequest)
for object in fetchResults {
self.delete(object)
}
numberOfDeletedObjects = fetchResults.count
}
catch {
fetchError = error
}
}
}
if numberOfDeletedObjects == nil {
CoreStore.log(
CoreStoreError(fetchError),
"Failed executing fetch request."
)
return nil
}
return numberOfDeletedObjects
}
}

View File

@@ -38,7 +38,7 @@ internal extension NSManagedObjectContext {
get {
if let parentContext = self.parentContext {
if let parentContext = self.parent {
return parentContext.parentStack
}
@@ -47,7 +47,7 @@ internal extension NSManagedObjectContext {
}
set {
guard self.parentContext == nil else {
guard self.parent == nil else {
return
}
@@ -61,9 +61,9 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal static func rootSavingContextForCoordinator(coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
internal static func rootSavingContextForCoordinator(_ coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
context.undoManager = nil
@@ -72,18 +72,20 @@ internal extension NSManagedObjectContext {
#if os(iOS) || os(OSX)
context.observerForDidImportUbiquitousContentChangesNotification = NotificationObserver(
notificationName: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
notificationName: NSNotification.Name.NSPersistentStoreDidImportUbiquitousContentChanges,
object: coordinator,
closure: { [weak context] (note) -> Void in
context?.performBlock { () -> Void in
context?.perform { () -> Void in
let updatedObjectIDs = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObjectID>) ?? []
for objectID in updatedObjectIDs {
if let updatedObjectIDs = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObjectID>) {
context?.objectWithID(objectID).willAccessValueForKey(nil)
for objectID in updatedObjectIDs {
context?.object(with: objectID).willAccessValue(forKey: nil)
}
}
context?.mergeChangesFromContextDidSaveNotification(note)
context?.mergeChanges(fromContextDidSave: note)
}
}
)
@@ -94,15 +96,15 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal static func mainContextForRootContext(rootContext: NSManagedObjectContext) -> NSManagedObjectContext {
internal static func mainContextForRootContext(_ rootContext: NSManagedObjectContext) -> NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.parentContext = rootContext
let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.parent = rootContext
context.mergePolicy = NSRollbackMergePolicy
context.undoManager = nil
context.setupForCoreStoreWithContextName("com.corestore.maincontext")
context.observerForDidSaveNotification = NotificationObserver(
notificationName: NSManagedObjectContextDidSaveNotification,
notificationName: NSNotification.Name.NSManagedObjectContextDidSave,
object: rootContext,
closure: { [weak context] (note) -> Void in
@@ -113,21 +115,22 @@ internal extension NSManagedObjectContext {
}
let mergeChanges = { () -> Void in
let updatedObjects = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>) ?? []
for object in updatedObjects {
if let updatedObjects = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>) {
context.objectWithID(object.objectID).willAccessValueForKey(nil)
for object in updatedObjects {
context.object(with: object.objectID).willAccessValue(forKey: nil)
}
}
context.mergeChangesFromContextDidSaveNotification(note)
context.mergeChanges(fromContextDidSave: note)
}
if rootContext.isSavingSynchronously == true {
context.performBlockAndWait(mergeChanges)
context.performAndWait(mergeChanges)
}
else {
context.performBlock(mergeChanges)
context.perform(mergeChanges)
}
}
)

View File

@@ -25,9 +25,6 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - NSManagedObjectContext
@@ -70,13 +67,55 @@ internal extension NSManagedObjectContext {
set {
cs_setAssociatedWeakObject(
newValue.flatMap { NSNumber(bool: $0) },
newValue.flatMap { NSNumber(value: $0) },
forKey: &PropertyKeys.isSavingSynchronously,
inObject: self
)
}
}
@nonobjc
internal var isTransactionContext: Bool {
get {
let value: NSNumber? = cs_getAssociatedObjectForKey(
&PropertyKeys.isTransactionContext,
inObject: self
)
return value?.boolValue == true
}
set {
cs_setAssociatedCopiedObject(
NSNumber(value: newValue),
forKey: &PropertyKeys.isTransactionContext,
inObject: self
)
}
}
@nonobjc
internal var isDataStackContext: Bool {
get {
let value: NSNumber? = cs_getAssociatedObjectForKey(
&PropertyKeys.isDataStackContext,
inObject: self
)
return value?.boolValue == true
}
set {
cs_setAssociatedCopiedObject(
NSNumber(value: newValue),
forKey: &PropertyKeys.isDataStackContext,
inObject: self
)
}
}
@nonobjc
internal func isRunningInAllowedQueue() -> Bool {
@@ -88,10 +127,10 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func temporaryContextInTransactionWithConcurrencyType(concurrencyType: NSManagedObjectContextConcurrencyType) -> NSManagedObjectContext {
internal func temporaryContextInTransactionWithConcurrencyType(_ concurrencyType: NSManagedObjectContextConcurrencyType) -> NSManagedObjectContext {
let context = NSManagedObjectContext(concurrencyType: concurrencyType)
context.parentContext = self
context.parent = self
context.parentStack = self.parentStack
context.setupForCoreStoreWithContextName("com.corestore.temporarycontext")
context.shouldCascadeSavesToParent = (self.parentStack?.rootSavingContext == self)
@@ -101,11 +140,11 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func saveSynchronously() -> SaveResult {
internal func saveSynchronously(waitForMerge: Bool) -> SaveResult {
var result = SaveResult(hasChanges: false)
self.performBlockAndWait {
self.performAndWait {
guard self.hasChanges else {
@@ -114,7 +153,7 @@ internal extension NSManagedObjectContext {
do {
self.isSavingSynchronously = true
self.isSavingSynchronously = waitForMerge
try self.save()
self.isSavingSynchronously = nil
}
@@ -123,20 +162,20 @@ internal extension NSManagedObjectContext {
let saveError = CoreStoreError(error)
CoreStore.log(
saveError,
"Failed to save \(cs_typeName(NSManagedObjectContext))."
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
)
result = SaveResult(saveError)
return
}
if let parentContext = self.parentContext where self.shouldCascadeSavesToParent {
if let parentContext = self.parent, self.shouldCascadeSavesToParent {
switch parentContext.saveSynchronously() {
switch parentContext.saveSynchronously(waitForMerge: waitForMerge) {
case .Success:
case .success:
result = SaveResult(hasChanges: true)
case .Failure(let error):
case .failure(let error):
result = SaveResult(error)
}
}
@@ -150,15 +189,15 @@ internal extension NSManagedObjectContext {
}
@nonobjc
internal func saveAsynchronouslyWithCompletion(completion: ((result: SaveResult) -> Void) = { _ in }) {
internal func saveAsynchronouslyWithCompletion(_ completion: @escaping ((_ result: SaveResult) -> Void) = { _ in }) {
self.performBlock {
self.perform {
guard self.hasChanges else {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(result: SaveResult(hasChanges: false))
completion(SaveResult(hasChanges: false))
}
return
}
@@ -174,24 +213,24 @@ internal extension NSManagedObjectContext {
let saveError = CoreStoreError(error)
CoreStore.log(
saveError,
"Failed to save \(cs_typeName(NSManagedObjectContext))."
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(result: SaveResult(saveError))
completion(SaveResult(saveError))
}
return
}
if let parentContext = self.parentContext where self.shouldCascadeSavesToParent {
if self.shouldCascadeSavesToParent, let parentContext = self.parent {
parentContext.saveAsynchronouslyWithCompletion(completion)
}
else {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(result: SaveResult(hasChanges: true))
completion(SaveResult(hasChanges: true))
}
}
}
@@ -206,7 +245,7 @@ internal extension NSManagedObjectContext {
}
else {
self.registeredObjects.forEach { self.refreshObject($0, mergeChanges: true) }
self.registeredObjects.forEach { self.refresh($0, mergeChanges: true) }
}
}
@@ -217,5 +256,7 @@ internal extension NSManagedObjectContext {
static var parentTransaction: Void?
static var isSavingSynchronously: Void?
static var isTransactionContext: Void?
static var isDataStackContext: Void?
}
}

View File

@@ -34,32 +34,34 @@ internal extension NSManagedObjectModel {
// MARK: Internal
@nonobjc
internal static func fromBundle(bundle: NSBundle, modelName: String, modelVersionHints: Set<String> = []) -> NSManagedObjectModel {
internal static func fromBundle(_ bundle: Bundle, modelName: String, modelVersionHints: Set<String> = []) -> NSManagedObjectModel {
guard let modelFilePath = bundle.pathForResource(modelName, ofType: "momd") else {
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.
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle. \(bundle)")
}
let modelFileURL = NSURL(fileURLWithPath: modelFilePath)
let versionInfoPlistURL = modelFileURL.URLByAppendingPathComponent("VersionInfo.plist", isDirectory: false)
let modelFileURL = URL(fileURLWithPath: modelFilePath)
let versionInfoPlistURL = modelFileURL.appendingPathComponent("VersionInfo.plist", isDirectory: false)
guard let versionInfo = NSDictionary(contentsOfURL: versionInfoPlistURL),
guard let versionInfo = NSDictionary(contentsOf: versionInfoPlistURL),
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel)) metadata from path \"\(versionInfoPlistURL)\".")
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel.self)) metadata from path \"\(versionInfoPlistURL)\".")
}
let modelVersions = Set(versionHashes.keys)
let currentModelVersion: String
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String where modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String,
modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
currentModelVersion = plistModelVersion
}
else if let resolvedVersion = modelVersions.intersect(modelVersionHints).first {
else if let resolvedVersion = modelVersions.intersection(modelVersionHints).first {
CoreStore.log(
.Warning,
.warning,
message: "The MigrationChain leaf versions do not include the model file's current version. Resolving to version \"\(resolvedVersion)\"."
)
currentModelVersion = resolvedVersion
@@ -69,7 +71,7 @@ internal extension NSManagedObjectModel {
if !modelVersionHints.isEmpty {
CoreStore.log(
.Warning,
.warning,
message: "The MigrationChain leaf versions do not include any of the model file's embedded versions. Resolving to version \"\(resolvedVersion)\"."
)
}
@@ -80,10 +82,10 @@ internal extension NSManagedObjectModel {
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
}
var modelVersionFileURL: NSURL?
var modelVersionFileURL: URL?
for modelVersion in modelVersions {
let fileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)
let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
if modelVersion == currentModelVersion {
@@ -92,13 +94,13 @@ internal extension NSManagedObjectModel {
}
precondition(
NSManagedObjectModel(contentsOfURL: fileURL) != nil,
NSManagedObjectModel(contentsOf: fileURL) != nil,
"Could not find the \"\(modelVersion).mom\" version file for the model at URL \"\(modelFileURL)\"."
)
}
if let modelVersionFileURL = modelVersionFileURL,
let rootModel = NSManagedObjectModel(contentsOfURL: modelVersionFileURL) {
let rootModel = NSManagedObjectModel(contentsOf: modelVersionFileURL) {
rootModel.modelVersionFileURL = modelVersionFileURL
rootModel.modelVersions = modelVersions
@@ -106,7 +108,7 @@ internal extension NSManagedObjectModel {
return rootModel
}
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel)) from the model at URL \"\(modelFileURL)\".")
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel.self)) from the model at URL \"\(modelFileURL)\".")
}
@nonobjc
@@ -152,7 +154,7 @@ internal extension NSManagedObjectModel {
}
@nonobjc
internal func entityNameForClass(entityClass: AnyClass) -> String {
internal func entityNameForClass(_ entityClass: AnyClass) -> String {
return self.entityNameMapping[NSStringFromClass(entityClass)]!
}
@@ -183,14 +185,14 @@ internal extension NSManagedObjectModel {
}
guard let modelFileURL = self.modelFileURL,
let modelVersions = self.modelVersions
where modelVersions.contains(modelVersion) else {
let modelVersions = self.modelVersions,
modelVersions.contains(modelVersion) else {
return nil
}
let versionModelFileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)
guard let model = NSManagedObjectModel(contentsOfURL: versionModelFileURL) else {
let versionModelFileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
guard let model = NSManagedObjectModel(contentsOf: versionModelFileURL) else {
return nil
}
@@ -202,15 +204,15 @@ internal extension NSManagedObjectModel {
}
@nonobjc
internal subscript(metadata: [String: AnyObject]) -> NSManagedObjectModel? {
internal subscript(metadata: [String: Any]) -> NSManagedObjectModel? {
guard let modelHashes = metadata[NSStoreModelVersionHashesKey] as? [String : NSData] else {
guard let modelHashes = metadata[NSStoreModelVersionHashesKey] as? [String : Data] else {
return nil
}
for modelVersion in self.modelVersions ?? [] {
if let versionModel = self[modelVersion] where modelHashes == versionModel.entityVersionHashesByName {
if let versionModel = self[modelVersion], modelHashes == versionModel.entityVersionHashesByName {
return versionModel
}
@@ -222,16 +224,16 @@ internal extension NSManagedObjectModel {
// MARK: Private
@nonobjc
private var modelFileURL: NSURL? {
private var modelFileURL: URL? {
get {
return self.modelVersionFileURL?.URLByDeletingLastPathComponent
return self.modelVersionFileURL?.deletingLastPathComponent()
}
}
@nonobjc
private var modelVersionFileURL: NSURL? {
private var modelVersionFileURL: URL? {
get {
@@ -239,12 +241,12 @@ internal extension NSManagedObjectModel {
&PropertyKeys.modelVersionFileURL,
inObject: self
)
return value
return value as URL?
}
set {
cs_setAssociatedCopiedObject(
newValue,
newValue as NSURL?,
forKey: &PropertyKeys.modelVersionFileURL,
inObject: self
)
@@ -270,7 +272,7 @@ internal extension NSManagedObjectModel {
}
let className = $0.managedObjectClassName
mapping[className] = entityName
mapping[className!] = entityName
}
cs_setAssociatedCopiedObject(
mapping as NSDictionary,

View File

@@ -66,15 +66,15 @@ internal extension NSPersistentStore {
// MARK: - StorageObject
private class StorageObject: NSObject {
fileprivate class StorageObject: NSObject {
// MARK: Private
@nonobjc
private let storageInterface: StorageInterface?
fileprivate let storageInterface: StorageInterface?
@nonobjc
private init(_ storage: StorageInterface?) {
fileprivate init(_ storage: StorageInterface?) {
self.storageInterface = storage
}

View File

@@ -26,134 +26,53 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - NSPersistentStoreCoordinator
internal extension NSPersistentStoreCoordinator {
@nonobjc
internal func performAsynchronously(closure: () -> Void) {
internal func performAsynchronously(_ closure: @escaping () -> Void) {
#if USE_FRAMEWORKS
self.performBlock(closure)
#else
if #available(iOS 8.0, *) {
self.performBlock(closure)
}
else {
self.lock()
GCDQueue.Default.async {
closure()
self.unlock()
}
}
#endif
self.perform(closure)
}
@nonobjc
internal func performSynchronously<T>(closure: () -> T) -> T {
internal func performSynchronously<T>(_ closure: @escaping () -> T) -> T {
var result: T?
#if USE_FRAMEWORKS
self.performAndWait {
self.performBlockAndWait {
result = closure()
}
#else
if #available(iOS 8.0, *) {
self.performBlockAndWait {
result = closure()
}
}
else {
self.lock()
cs_autoreleasepool {
result = closure()
}
self.unlock()
}
#endif
result = closure()
}
return result!
}
@nonobjc
internal func performSynchronously<T>(closure: () throws -> T) throws -> T {
internal func performSynchronously<T>(_ closure: @escaping () throws -> T) throws -> T {
var closureError: ErrorType?
var closureError: Error?
var result: T?
#if USE_FRAMEWORKS
self.performAndWait {
self.performBlockAndWait {
do {
do {
result = try closure()
}
catch {
closureError = error
}
result = try closure()
}
#else
if #available(iOS 8.0, *) {
catch {
self.performBlockAndWait {
do {
result = try closure()
}
catch {
closureError = error
}
}
closureError = error
}
else {
self.lock()
cs_autoreleasepool {
do {
result = try closure()
}
catch {
closureError = error
}
}
self.unlock()
}
#endif
}
if let closureError = closureError {
throw closureError
}
return result!
}
@nonobjc
internal func addPersistentStoreSynchronously(storeType: String, configuration: String?, URL storeURL: NSURL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore {
internal func addPersistentStoreSynchronously(_ storeType: String, configuration: String?, URL storeURL: URL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore {
var store: NSPersistentStore?
var storeError: NSError?
@@ -161,10 +80,10 @@ internal extension NSPersistentStoreCoordinator {
do {
store = try self.addPersistentStoreWithType(
storeType,
configuration: configuration,
URL: storeURL,
store = try self.addPersistentStore(
ofType: storeType,
configurationName: configuration,
at: storeURL,
options: options
)
}
@@ -173,12 +92,10 @@ internal extension NSPersistentStoreCoordinator {
storeError = error as NSError
}
}
if let store = store {
return store
}
throw CoreStoreError(storeError)
}
}
}

View File

@@ -34,18 +34,18 @@ internal final class NotificationObserver {
let observer: NSObjectProtocol
init(notificationName: String, object: AnyObject?, queue: NSOperationQueue? = nil, closure: (note: NSNotification) -> Void) {
init(notificationName: Notification.Name, object: Any?, queue: OperationQueue? = nil, closure: @escaping (_ note: Notification) -> Void) {
self.observer = NSNotificationCenter.defaultCenter().addObserverForName(
notificationName,
self.observer = NotificationCenter.default.addObserver(
forName: notificationName,
object: object,
queue: queue,
usingBlock: closure
using: closure
)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self.observer)
NotificationCenter.default.removeObserver(self.observer)
}
}

View File

@@ -49,7 +49,7 @@ extension AsynchronousDataTransaction: CustomDebugStringConvertible, CoreStoreDe
("supportsUndo", self.supportsUndo),
("bypassesQueueing", self.bypassesQueueing),
("isCommitted", self.isCommitted),
("result", self.result)
("result", self.result as Any)
)
}
}
@@ -72,27 +72,27 @@ extension CloudStorageOptions: CustomDebugStringConvertible, CoreStoreDebugStrin
public var coreStoreDumpString: String {
var flags = [String]()
if self.contains(.RecreateLocalStoreOnModelMismatch) {
if self.contains(.recreateLocalStoreOnModelMismatch) {
flags.append(".RecreateLocalStoreOnModelMismatch")
flags.append(".recreateLocalStoreOnModelMismatch")
}
if self.contains(.AllowSynchronousLightweightMigration) {
if self.contains(.allowSynchronousLightweightMigration) {
flags.append(".AllowSynchronousLightweightMigration")
flags.append(".allowSynchronousLightweightMigration")
}
switch flags.count {
case 0:
return "[.None]"
return "[.none]"
case 1:
return "[.\(flags[0])]"
default:
var string = "[\n"
string.appendContentsOf(flags.joinWithSeparator(",\n"))
string.append(flags.joined(separator: ",\n"))
string.indent(1)
string.appendContentsOf("\n]")
string.append("\n]")
return string
}
}
@@ -117,30 +117,30 @@ extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConv
let firstLine: String
var info: DumpInfo = [
("_domain", self._domain),
("_code", self._code),
("errorDomain", type(of: self).errorDomain),
("errorCode", self.errorCode),
]
switch self {
case .Unknown:
firstLine = ".Unknown"
case .unknown:
firstLine = ".unknown"
case .DifferentStorageExistsAtURL(let existingPersistentStoreURL):
firstLine = ".DifferentStorageExistsAtURL"
case .differentStorageExistsAtURL(let existingPersistentStoreURL):
firstLine = ".differentStorageExistsAtURL"
info.append(("existingPersistentStoreURL", existingPersistentStoreURL))
case .MappingModelNotFound(let localStoreURL, let targetModel, let targetModelVersion):
firstLine = ".MappingModelNotFound"
case .mappingModelNotFound(let localStoreURL, let targetModel, let targetModelVersion):
firstLine = ".mappingModelNotFound"
info.append(("localStoreURL", localStoreURL))
info.append(("targetModel", targetModel))
info.append(("targetModelVersion", targetModelVersion))
case .ProgressiveMigrationRequired(let localStoreURL):
firstLine = ".ProgressiveMigrationRequired"
case .progressiveMigrationRequired(let localStoreURL):
firstLine = ".progressiveMigrationRequired"
info.append(("localStoreURL", localStoreURL))
case .InternalError(let NSError):
firstLine = ".InternalError"
case .internalError(let NSError):
firstLine = ".internalError"
info.append(("NSError", NSError))
}
@@ -254,8 +254,8 @@ extension ICloudStore: CustomDebugStringConvertible, CoreStoreDebugStringConvert
return createFormattedString(
"(", ")",
("configuration", self.configuration),
("storeOptions", self.storeOptions),
("configuration", self.configuration as Any),
("storeOptions", self.storeOptions as Any),
("cacheFileURL", self.cacheFileURL),
("cloudStorageOptions", self.cloudStorageOptions)
)
@@ -283,8 +283,8 @@ extension InMemoryStore: CustomDebugStringConvertible, CoreStoreDebugStringConve
return createFormattedString(
"(", ")",
("configuration", self.configuration),
("storeOptions", self.storeOptions)
("configuration", self.configuration as Any),
("storeOptions", self.storeOptions as Any)
)
}
}
@@ -309,7 +309,7 @@ extension Into: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("entityClass", self.entityClass),
("configuration", self.configuration),
("configuration", self.configuration as Any),
("inferStoreIfPossible", self.inferStoreIfPossible)
)
}
@@ -334,8 +334,8 @@ extension LegacySQLiteStore: CustomDebugStringConvertible, CoreStoreDebugStringC
return createFormattedString(
"(", ")",
("configuration", self.configuration),
("storeOptions", self.storeOptions),
("configuration", self.configuration as Any),
("storeOptions", self.storeOptions as Any),
("fileURL", self.fileURL),
("mappingModelBundles", self.mappingModelBundles),
("localStorageOptions", self.localStorageOptions)
@@ -357,7 +357,7 @@ private struct CoreStoreFetchedSectionInfoWrapper: CoreStoreDebugStringConvertib
return createFormattedString(
"\"\(self.sectionInfo.name)\" (", ")",
("numberOfObjects", self.sectionInfo.numberOfObjects),
("indexTitle", self.sectionInfo.indexTitle)
("indexTitle", self.sectionInfo.indexTitle as Any)
)
}
}
@@ -404,31 +404,31 @@ extension LocalStorageOptions: CustomDebugStringConvertible, CoreStoreDebugStrin
public var coreStoreDumpString: String {
var flags = [String]()
if self.contains(.RecreateStoreOnModelMismatch) {
if self.contains(.recreateStoreOnModelMismatch) {
flags.append(".RecreateStoreOnModelMismatch")
flags.append(".recreateStoreOnModelMismatch")
}
if self.contains(.PreventProgressiveMigration) {
if self.contains(.preventProgressiveMigration) {
flags.append(".PreventProgressiveMigration")
flags.append(".preventProgressiveMigration")
}
if self.contains(.AllowSynchronousLightweightMigration) {
if self.contains(.allowSynchronousLightweightMigration) {
flags.append(".AllowSynchronousLightweightMigration")
flags.append(".allowSynchronousLightweightMigration")
}
switch flags.count {
case 0:
return "[.None]"
return "[.none]"
case 1:
return "[.\(flags[0])]"
default:
var string = "[\n"
string.appendContentsOf(flags.joinWithSeparator(",\n"))
string.append(flags.joined(separator: ",\n"))
string.indent(1)
string.appendContentsOf("\n]")
string.append("\n]")
return string
}
}
@@ -465,7 +465,7 @@ extension MigrationChain: CustomDebugStringConvertible, CoreStoreDebugStringConv
steps.append(nextVersion)
version = nextVersion
}
paths.append(steps.joinWithSeparator(""))
paths.append(steps.joined(separator: ""))
}
switch paths.count {
@@ -479,10 +479,10 @@ extension MigrationChain: CustomDebugStringConvertible, CoreStoreDebugStringConv
var string = "["
paths.forEach {
string.appendContentsOf("\n\($0);")
string.append("\n\($0);")
}
string.indent(1)
string.appendContentsOf("\n]")
string.append("\n]")
return string
}
}
@@ -507,15 +507,15 @@ extension MigrationResult: CustomDebugStringConvertible, CoreStoreDebugStringCon
switch self {
case .Success(let migrationTypes):
case .success(let migrationTypes):
return createFormattedString(
".Success (", ")",
".success (", ")",
("migrationTypes", migrationTypes)
)
case .Failure(let error):
case .failure(let error):
return createFormattedString(
".Failure (", ")",
".failure (", ")",
("error", error)
)
}
@@ -541,14 +541,14 @@ extension MigrationType: CustomDebugStringConvertible, CoreStoreDebugStringConve
switch self {
case .None(let version):
return ".None (\"\(version)\")"
case .none(let version):
return ".none (\"\(version)\")"
case .Lightweight(let sourceVersion, let destinationVersion):
return ".Lightweight (\"\(sourceVersion)\"\"\(destinationVersion)\")"
case .lightweight(let sourceVersion, let destinationVersion):
return ".lightweight (\"\(sourceVersion)\"\"\(destinationVersion)\")"
case .Heavyweight(let sourceVersion, let destinationVersion):
return ".Heavyweight (\"\(sourceVersion)\"\"\(destinationVersion)\")"
case .heavyweight(let sourceVersion, let destinationVersion):
return ".heavyweight (\"\(sourceVersion)\"\"\(destinationVersion)\")"
}
}
}
@@ -575,7 +575,7 @@ extension ObjectMonitor: CustomDebugStringConvertible, CoreStoreDebugStringConve
return createFormattedString(
"(", ")",
("isObjectDeleted", self.isObjectDeleted),
("object", self.object)
("object", self.object as Any)
)
}
}
@@ -623,15 +623,15 @@ extension SaveResult: CustomDebugStringConvertible, CoreStoreDebugStringConverti
switch self {
case .Success(let hasChanges):
case .success(let hasChanges):
return createFormattedString(
".Success (", ")",
".success (", ")",
("hasChanges", hasChanges)
)
case .Failure(let error):
case .failure(let error):
return createFormattedString(
".Failure (", ")",
".failure (", ")",
("error", error)
)
}
@@ -708,24 +708,24 @@ extension SelectTerm: CustomDebugStringConvertible, CoreStoreDebugStringConverti
switch self {
case ._Attribute(let keyPath):
case ._attribute(let keyPath):
return createFormattedString(
".Attribute (", ")",
".attribute (", ")",
("keyPath", keyPath)
)
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
case ._aggregate(let function, let keyPath, let alias, let nativeType):
return createFormattedString(
".Aggregate (", ")",
".aggregate (", ")",
("function", function),
("keyPath", keyPath),
("alias", alias),
("nativeType", nativeType)
)
case ._Identity(let alias, let nativeType):
case ._identity(let alias, let nativeType):
return createFormattedString(
".Identity (", ")",
".identity (", ")",
("alias", alias),
("nativeType", nativeType)
)
@@ -752,15 +752,15 @@ extension SetupResult: CustomDebugStringConvertible, CoreStoreDebugStringConvert
switch self {
case .Success(let storage):
case .success(let storage):
return createFormattedString(
".Success (", ")",
".success (", ")",
("storage", storage)
)
case .Failure(let error):
case .failure(let error):
return createFormattedString(
".Failure (", ")",
".failure (", ")",
("error", error)
)
}
@@ -786,8 +786,8 @@ extension SQLiteStore: CustomDebugStringConvertible, CoreStoreDebugStringConvert
return createFormattedString(
"(", ")",
("configuration", self.configuration),
("storeOptions", self.storeOptions),
("configuration", self.configuration as Any),
("storeOptions", self.storeOptions as Any),
("fileURL", self.fileURL),
("mappingModelBundles", self.mappingModelBundles),
("localStorageOptions", self.localStorageOptions)
@@ -818,7 +818,7 @@ extension SynchronousDataTransaction: CustomDebugStringConvertible, CoreStoreDeb
("supportsUndo", self.supportsUndo),
("bypassesQueueing", self.bypassesQueueing),
("isCommitted", self.isCommitted),
("result", self.result)
("result", self.result as Any)
)
}
}
@@ -898,7 +898,7 @@ extension Where: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
private typealias DumpInfo = [(key: String, value: Any)]
private func formattedValue(any: Any) -> String {
private func formattedValue(_ any: Any) -> String {
switch any {
@@ -910,19 +910,19 @@ private func formattedValue(any: Any) -> String {
}
}
private func formattedDebugDescription(any: Any) -> String {
private func formattedDebugDescription(_ any: Any) -> String {
var string = "(\(String(reflecting: any.dynamicType))) "
string.appendContentsOf(formattedValue(any))
var string = "(\(String(reflecting: type(of: any)))) "
string.append(formattedValue(any))
return string
}
private func createFormattedString(firstLine: String, _ lastLine: String, _ info: (key: String, value: Any)...) -> String {
private func createFormattedString(_ firstLine: String, _ lastLine: String, _ info: (key: String, value: Any)...) -> String {
return createFormattedString(firstLine, lastLine, info)
}
private func createFormattedString(firstLine: String, _ lastLine: String, _ info: [(key: String, value: Any)]) -> String {
private func createFormattedString(_ firstLine: String, _ lastLine: String, _ info: [(key: String, value: Any)]) -> String {
var string = firstLine
for (key, value) in info {
@@ -930,34 +930,34 @@ private func createFormattedString(firstLine: String, _ lastLine: String, _ info
string.appendDumpInfo(key, value)
}
string.indent(1)
string.appendContentsOf("\n\(lastLine)")
string.append("\n\(lastLine)")
return string
}
private extension String {
fileprivate extension String {
private static func indention(level: Int = 1) -> String {
fileprivate static func indention(_ level: Int = 1) -> String {
return String(count: level * 4, repeatedValue: Character(" "))
return String(repeating: " ", count: level * 4)
}
private func trimSwiftModuleName() -> String {
fileprivate func trimSwiftModuleName() -> String {
if self.hasPrefix("Swift.") {
return self.substringFromIndex("Swift.".endIndex)
return self.substring(from: "Swift.".endIndex)
}
return self
}
private mutating func indent(level: Int) {
fileprivate mutating func indent(_ level: Int) {
self = self.stringByReplacingOccurrencesOfString("\n", withString: "\n\(String.indention(level))")
self = self.replacingOccurrences(of: "\n", with: "\n\(String.indention(level))")
}
private mutating func appendDumpInfo(key: String, _ value: Any) {
fileprivate mutating func appendDumpInfo(_ key: String, _ value: Any) {
self.appendContentsOf("\n.\(key) = \(formattedValue(value));")
self.append("\n.\(key) = \(formattedValue(value));")
}
}
@@ -979,17 +979,17 @@ extension Array: CoreStoreDebugStringConvertible {
var string = "\(self.count) item(s) ["
if self.isEmpty {
string.appendContentsOf("]")
string.append("]")
return string
}
else {
for (index, item) in self.enumerate() {
for (index, item) in self.enumerated() {
string.appendContentsOf("\n\(index) = \(formattedValue(item));")
string.append("\n\(index) = \(formattedValue(item));")
}
string.indent(1)
string.appendContentsOf("\n]")
string.append("\n]")
return string
}
}
@@ -1002,17 +1002,17 @@ extension Dictionary: CoreStoreDebugStringConvertible {
var string = "\(self.count) key-value(s) ["
if self.isEmpty {
string.appendContentsOf("]")
string.append("]")
return string
}
else {
for (key, value) in self {
string.appendContentsOf("\n\(formattedValue(key)) = \(formattedValue(value));")
string.append("\n\(formattedValue(key)) = \(formattedValue(value));")
}
string.indent(1)
string.appendContentsOf("\n]")
string.append("\n]")
return string
}
}
@@ -1025,21 +1025,21 @@ extension NSAttributeDescription: CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("attributeType", self.attributeType),
("attributeValueClassName", self.attributeValueClassName),
("defaultValue", self.defaultValue),
("valueTransformerName", self.valueTransformerName),
("attributeValueClassName", self.attributeValueClassName as Any),
("defaultValue", self.defaultValue as Any),
("valueTransformerName", self.valueTransformerName as Any),
("allowsExternalBinaryDataStorage", self.allowsExternalBinaryDataStorage),
("entity.name", self.entity.name),
("entity.name", self.entity.name as Any),
("name", self.name),
("optional", self.optional),
("transient", self.transient),
("userInfo", self.userInfo),
("indexed", self.indexed),
("isOptional", self.isOptional),
("isTransient", self.isTransient),
("userInfo", self.userInfo as Any),
("isIndexed", self.isIndexed),
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier),
("indexedBySpotlight", self.indexedBySpotlight),
("storedInExternalRecord", self.storedInExternalRecord),
("renamingIdentifier", self.renamingIdentifier)
("versionHashModifier", self.versionHashModifier as Any),
("isIndexedBySpotlight", self.isIndexedBySpotlight),
("isStoredInExternalRecord", self.isStoredInExternalRecord),
("renamingIdentifier", self.renamingIdentifier as Any)
)
}
}
@@ -1050,28 +1050,28 @@ extension NSAttributeType: CoreStoreDebugStringConvertible {
switch self {
case .UndefinedAttributeType: return ".UndefinedAttributeType"
case .Integer16AttributeType: return ".Integer16AttributeType"
case .Integer32AttributeType: return ".Integer32AttributeType"
case .Integer64AttributeType: return ".Integer64AttributeType"
case .DecimalAttributeType: return ".DecimalAttributeType"
case .DoubleAttributeType: return ".DoubleAttributeType"
case .FloatAttributeType: return ".FloatAttributeType"
case .StringAttributeType: return ".StringAttributeType"
case .BooleanAttributeType: return ".BooleanAttributeType"
case .DateAttributeType: return ".DateAttributeType"
case .BinaryDataAttributeType: return ".BinaryDataAttributeType"
case .TransformableAttributeType: return ".TransformableAttributeType"
case .ObjectIDAttributeType: return ".ObjectIDAttributeType"
case .undefinedAttributeType: return ".undefinedAttributeType"
case .integer16AttributeType: return ".integer16AttributeType"
case .integer32AttributeType: return ".integer32AttributeType"
case .integer64AttributeType: return ".integer64AttributeType"
case .decimalAttributeType: return ".decimalAttributeType"
case .doubleAttributeType: return ".doubleAttributeType"
case .floatAttributeType: return ".floatAttributeType"
case .stringAttributeType: return ".stringAttributeType"
case .booleanAttributeType: return ".booleanAttributeType"
case .dateAttributeType: return ".dateAttributeType"
case .binaryDataAttributeType: return ".binaryDataAttributeType"
case .transformableAttributeType: return ".transformableAttributeType"
case .objectIDAttributeType: return ".objectIDAttributeType"
}
}
}
extension NSBundle: CoreStoreDebugStringConvertible {
extension Bundle: CoreStoreDebugStringConvertible {
public var coreStoreDumpString: String {
return "\(self.bundleIdentifier.flatMap({ "\"\($0)\"" }) ?? "<unknown bundle identifier>") (\(self.bundleURL.lastPathComponent ?? "<unknown bundle URL>"))"
return "\(self.bundleIdentifier.flatMap({ "\"\($0)\"" }) ?? "<unknown bundle identifier>") (\(self.bundleURL.lastPathComponent))"
}
}
@@ -1081,10 +1081,10 @@ extension NSDeleteRule: CoreStoreDebugStringConvertible {
switch self {
case .NoActionDeleteRule: return ".NoActionDeleteRule"
case .NullifyDeleteRule: return ".NullifyDeleteRule"
case .CascadeDeleteRule: return ".CascadeDeleteRule"
case .DenyDeleteRule: return ".DenyDeleteRule"
case .noActionDeleteRule: return ".noActionDeleteRule"
case .nullifyDeleteRule: return ".nullifyDeleteRule"
case .cascadeDeleteRule: return ".cascadeDeleteRule"
case .denyDeleteRule: return ".denyDeleteRule"
}
}
}
@@ -1095,15 +1095,15 @@ extension NSEntityDescription: CoreStoreDebugStringConvertible {
var info: DumpInfo = [
("managedObjectClassName", self.managedObjectClassName!),
("name", self.name),
("abstract", self.abstract),
("superentity?.name", self.superentity?.name),
("name", self.name as Any),
("isAbstract", self.isAbstract),
("superentity?.name", self.superentity?.name as Any),
("subentities", self.subentities.map({ $0.name })),
("properties", self.properties),
("userInfo", self.userInfo),
("userInfo", self.userInfo as Any),
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier),
("renamingIdentifier", self.renamingIdentifier),
("versionHashModifier", self.versionHashModifier as Any),
("renamingIdentifier", self.renamingIdentifier as Any),
("compoundIndexes", self.compoundIndexes)
]
if #available(iOS 9.0, OSXApplicationExtension 10.11, OSX 10.11, *) {
@@ -1147,10 +1147,10 @@ extension NSManagedObjectID: CoreStoreDebugStringConvertible {
public var coreStoreDumpString: String {
return createFormattedString(
"\(self.URIRepresentation().coreStoreDumpString) (", ")",
("entity.name", self.entity.name),
("temporaryID", self.temporaryID),
("persistentStore?.URL", self.persistentStore?.URL)
"\(self.uriRepresentation().coreStoreDumpString) (", ")",
("entity.name", self.entity.name as Any),
("isTemporaryID", self.isTemporaryID as Any),
("persistentStore?.url", self.persistentStore?.url as Any)
)
}
}
@@ -1177,24 +1177,24 @@ extension NSRelationshipDescription: CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("destinationEntity?.name", self.destinationEntity?.name),
("inverseRelationship?.name", self.inverseRelationship?.name),
("destinationEntity?.name", self.destinationEntity?.name as Any),
("inverseRelationship?.name", self.inverseRelationship?.name as Any),
("minCount", self.minCount),
("maxCount", self.maxCount),
("deleteRule", self.deleteRule),
("toMany", self.toMany),
("ordered", self.ordered),
("entity.name", self.entity.name),
("isToMany", self.isToMany),
("isOrdered", self.isOrdered),
("entity.name", self.entity.name as Any),
("name", self.name),
("optional", self.optional),
("transient", self.transient),
("userInfo", self.userInfo),
("indexed", self.indexed),
("isOptional", self.isOptional),
("isTransient", self.isTransient),
("userInfo", self.userInfo as Any),
("isIndexed", self.isIndexed),
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier),
("indexedBySpotlight", self.indexedBySpotlight),
("storedInExternalRecord", self.storedInExternalRecord),
("renamingIdentifier", self.renamingIdentifier)
("versionHashModifier", self.versionHashModifier as Any),
("isIndexedBySpotlight", self.isIndexedBySpotlight),
("isStoredInExternalRecord", self.isStoredInExternalRecord),
("renamingIdentifier", self.renamingIdentifier as Any)
)
}
}
@@ -1205,14 +1205,14 @@ extension NSSortDescriptor: CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("key", self.key),
("key", self.key as Any),
("ascending", self.ascending),
("selector", self.selector)
("selector", self.selector as Any)
)
}
}
extension NSURL: CoreStoreDebugStringConvertible {
extension URL: CoreStoreDebugStringConvertible {
public var coreStoreDumpString: String {
@@ -1236,7 +1236,7 @@ extension Selector: CoreStoreDebugStringConvertible {
public var coreStoreDumpString: String {
return self == nil ? "nil" : "\"\(self)\""
return "\"\(self)\""
}
}

View File

@@ -38,7 +38,7 @@ public extension CoreStore {
// MARK: Internal
internal static func log(level: LogLevel, message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
internal static func log(_ level: LogLevel, message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.log(
level: level,
@@ -49,7 +49,7 @@ public extension CoreStore {
)
}
internal static func log(error: CoreStoreError, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
internal static func log(_ error: CoreStoreError, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.log(
error: error,
@@ -60,7 +60,7 @@ public extension CoreStore {
)
}
internal static func assert(@autoclosure condition: () -> Bool, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
internal static func assert( _ condition: @autoclosure () -> Bool, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.assert(
condition,
@@ -71,8 +71,7 @@ public extension CoreStore {
)
}
@noreturn
internal static func abort(message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
internal static func abort(_ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) -> Never {
self.logger.abort(
message,

View File

@@ -33,17 +33,17 @@ import Foundation
*/
public enum LogLevel {
case Trace
case Notice
case Warning
case Fatal
case trace
case notice
case warning
case fatal
}
// MARK: - CoreStoreLogger
/**
Custom loggers should implement the `CoreStoreLogger` protocol and pass its instance to `CoreStore.logger`. Calls to `log(...)`, `handleError(...)`, and `assert(...)` are not tied to a specific queue/thread, so it is the implementer's job to handle thread-safety.
Custom loggers should implement the `CoreStoreLogger` protocol and pass its instance to `CoreStore.logger`. Calls to `log(...)`, `assert(...)`, and `abort(...)` are not tied to a specific queue/thread, so it is the implementer's job to handle thread-safety.
*/
public protocol CoreStoreLogger {
@@ -56,7 +56,7 @@ public protocol CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles errors sent by the `CoreStore` framework.
@@ -67,7 +67,7 @@ public protocol CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles assertions made throughout the `CoreStore` framework.
@@ -78,41 +78,23 @@ public protocol CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles fatal errors made throughout the `CoreStore` framework. The app wil terminate after this method is called.
- Important: Implementers may guarantee that the function doesn't return, either by calling another `@noreturn` function such as `fatalError()` or `abort()`, or by raising an exception. If the implementation does not terminate the app, CoreStore will call an internal `fatalError()` to do so.
- Important: Implementers may guarantee that the function doesn't return, either by calling another `Never` function such as `fatalError()` or `abort()`, or by raising an exception. If the implementation does not terminate the app, CoreStore will call an internal `fatalError()` to do so.
- parameter message: the fatal error message
- parameter fileName: the source file name
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
// MARK: Deprecated
/**
Deprecated. Use `log(error:message:fileName:lineNumber:functionName:)` instead.
*/
@available(*, deprecated=2.0.0, message="Use log(error:message:fileName:lineNumber:functionName:) instead.")
func handleError(error error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
}
extension CoreStoreLogger {
/**
Deprecated. Use `log(error:message:fileName:lineNumber:functionName:)` instead.
*/
@available(*, deprecated=2.0.0, message="Use log(error:message:fileName:lineNumber:functionName:) instead.")
public func handleError(error error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.log(error: error.bridgeToSwift, message: message, fileName: fileName, lineNumber: lineNumber, functionName: functionName)
}
public func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
Swift.fatalError(message, file: fileName, line: UInt(lineNumber))
}

View File

@@ -30,10 +30,6 @@ import Foundation
/**
The `DefaultLogger` is a basic implementation of the `CoreStoreLogger` protocol.
- The `log(...)` method calls `print(...)` to print the level, source file name, line number, function name, and the log message.
- The `handleError(...)` method calls `print(...)` to print the source file name, line number, function name, and the error message.
- The `assert(...)` method calls `assert(...)` on the arguments.
*/
public final class DefaultLogger: CoreStoreLogger {
@@ -51,30 +47,30 @@ public final class DefaultLogger: CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
let icon: String
let levelString: String
switch level {
case .Trace:
case .trace:
icon = "🔹"
levelString = "Trace"
case .Notice:
case .notice:
icon = "🔸"
levelString = "Notice"
case .Warning:
case .warning:
icon = "⚠️"
levelString = "Warning"
case .Fatal:
case .fatal:
icon = ""
levelString = "Fatal"
}
Swift.print("\(icon) [CoreStore: \(levelString)] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
Swift.print("\(icon) [CoreStore: \(levelString)] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
#endif
}
@@ -87,10 +83,10 @@ public final class DefaultLogger: CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
Swift.print("⚠️ [CoreStore: Error] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n \(error)\n")
Swift.print("⚠️ [CoreStore: Error] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n \(error)\n")
#endif
}
@@ -103,30 +99,30 @@ public final class DefaultLogger: CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
if condition() {
return
}
Swift.print("❗ [CoreStore: Assertion Failure] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message())\n")
Swift.print("❗ [CoreStore: Assertion Failure] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message())\n")
Swift.fatalError(file: fileName, line: UInt(lineNumber))
#endif
}
/**
Handles fatal errors made throughout the `CoreStore` framework.
- Important: This method should be marked `@noreturn` and implementers should guarantee that the function doesn't, either by calling another `@noreturn` function such as `fatalError()` or `abort()`, or by raising an exception.
- Important: Implementers should guarantee that this function doesn't return, either by calling another `Never` function such as `fatalError()` or `abort()`, or by raising an exception.
- parameter message: the fatal error message
- parameter fileName: the source file name
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
Swift.print("❗ [CoreStore: Fatal Error] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
Swift.print("❗ [CoreStore: Fatal Error] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
Swift.fatalError(file: fileName, line: UInt(lineNumber))
}
}

View File

@@ -25,9 +25,6 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - CoreStore
@@ -41,17 +38,16 @@ public extension CoreStore {
InMemoryStore.self,
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storeType: the storage type
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
*/
public static func addStorage<T: StorageInterface where T: DefaultInitializableStore>(storeType: T.Type, completion: (SetupResult<T>) -> Void) {
public static func addStorage<T: StorageInterface>(_ storeType: T.Type, completion: @escaping (SetupResult<T>) -> Void) where T: DefaultInitializableStore {
self.defaultStack.addStorage(storeType.init(), completion: completion)
}
@@ -63,17 +59,16 @@ public extension CoreStore {
InMemoryStore(configuration: "Config1"),
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storage: the storage
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
*/
public static func addStorage<T: StorageInterface>(storage: T, completion: (SetupResult<T>) -> Void) {
public static func addStorage<T: StorageInterface>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) {
self.defaultStack.addStorage(storage, completion: completion)
}
@@ -85,18 +80,17 @@ public extension CoreStore {
SQLiteStore.self,
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storeType: the local storage type
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: an `NSProgress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: a `Progress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
*/
public static func addStorage<T: LocalStorage where T: DefaultInitializableStore>(storeType: T.Type, completion: (SetupResult<T>) -> Void) -> NSProgress? {
public static func addStorage<T: LocalStorage>(_ storeType: T.Type, completion: @escaping (SetupResult<T>) -> Void) -> Progress? where T: DefaultInitializableStore {
return self.defaultStack.addStorage(storeType.init(), completion: completion)
}
@@ -108,18 +102,17 @@ public extension CoreStore {
SQLiteStore(fileName: "core_data.sqlite", configuration: "Config1"),
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storage: the local storage
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: an `NSProgress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: a `Progress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
*/
public static func addStorage<T: LocalStorage>(storage: T, completion: (SetupResult<T>) -> Void) -> NSProgress? {
public static func addStorage<T: LocalStorage>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) -> Progress? {
return self.defaultStack.addStorage(storage, completion: completion)
}
@@ -133,7 +126,7 @@ public extension CoreStore {
ubiquitousContainerID: "iCloud.com.mycompany.myapp.containername",
ubiquitousPeerToken: "9614d658014f4151a95d8048fb717cf0",
configuration: "Config1",
cloudStorageOptions: .RecreateLocalStoreOnModelMismatch
cloudStorageOptions: .recreateLocalStoreOnModelMismatch
) else {
// iCloud is not available on the device
return
@@ -142,17 +135,16 @@ public extension CoreStore {
storage,
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storage: the cloud storage
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `CloudStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `CloudStorage` was already added at the same URL and with the same configuration.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `CloudStorage` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `CloudStorage` was already added at the same URL and with the same configuration.
*/
public static func addStorage<T: CloudStorage>(storage: T, completion: (SetupResult<T>) -> Void) {
public static func addStorage<T: CloudStorage>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) {
self.defaultStack.addStorage(storage, completion: completion)
}
@@ -161,11 +153,11 @@ public extension CoreStore {
Migrates a local storage to match the `defaultStack`'s managed object model version. This method does NOT add the migrated store to the data stack.
- parameter storage: the local storage
- parameter completion: the closure to be executed on the main queue when the migration completes, either due to success or failure. The closure's `MigrationResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.Failure` result if an error occurs asynchronously.
- parameter completion: the closure to be executed on the main queue when the migration completes, either due to success or failure. The closure's `MigrationResult` argument indicates the result. This closure is NOT executed if an error is thrown, but will be executed with a `.failure` result if an error occurs asynchronously.
- throws: a `CoreStoreError` value indicating the failure
- returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required
- returns: a `Progress` instance if a migration has started, or `nil` is no migrations are required
*/
public static func upgradeStorageIfNeeded<T: LocalStorage>(storage: T, completion: (MigrationResult) -> Void) throws -> NSProgress? {
public static func upgradeStorageIfNeeded<T: LocalStorage>(_ storage: T, completion: @escaping (MigrationResult) -> Void) throws -> Progress? {
return try self.defaultStack.upgradeStorageIfNeeded(storage, completion: completion)
}
@@ -177,110 +169,8 @@ public extension CoreStore {
- throws: a `CoreStoreError` value indicating the failure
- returns: a `MigrationType` array indicating the migration steps required for the store, or an empty array if the file does not exist yet. Otherwise, an error is thrown if either inspection of the store failed, or if no mapping model was found/inferred.
*/
@warn_unused_result
public static func requiredMigrationsForStorage<T: LocalStorage>(storage: T) throws -> [MigrationType] {
public static func requiredMigrationsForStorage<T: LocalStorage>(_ storage: T) throws -> [MigrationType] {
return try self.defaultStack.requiredMigrationsForStorage(storage)
}
// MARK: Deprecated
/**
Deprecated. Use `addSQLiteStore(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addSQLiteStore(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public static func addSQLiteStore(fileName fileName: String, configuration: String? = nil, mappingModelBundles: [NSBundle]? = nil, resetStoreOnModelMismatch: Bool = false, completion: (PersistentStoreResult) -> Void) throws -> NSProgress? {
return try self.defaultStack.addSQLiteStore(
fileName: fileName,
configuration: configuration,
mappingModelBundles: mappingModelBundles,
resetStoreOnModelMismatch: resetStoreOnModelMismatch,
completion: completion
)
}
/**
Deprecated. Use `addSQLiteStore(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addSQLiteStore(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public static func addSQLiteStore(fileURL fileURL: NSURL = LegacySQLiteStore.defaultFileURL, configuration: String? = nil, mappingModelBundles: [NSBundle]? = NSBundle.allBundles(), resetStoreOnModelMismatch: Bool = false, completion: (PersistentStoreResult) -> Void) throws -> NSProgress? {
return try self.defaultStack.addSQLiteStore(
fileURL: fileURL,
configuration: configuration,
mappingModelBundles: mappingModelBundles,
resetStoreOnModelMismatch: resetStoreOnModelMismatch,
completion: completion
)
}
/**
Deprecated. Use `upgradeStorageIfNeeded(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use upgradeStorageIfNeeded(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public static func upgradeSQLiteStoreIfNeeded(fileName fileName: String, configuration: String? = nil, mappingModelBundles: [NSBundle]? = nil, completion: (MigrationResult) -> Void) throws -> NSProgress? {
return try self.defaultStack.upgradeSQLiteStoreIfNeeded(
fileName: fileName,
configuration: configuration,
mappingModelBundles: mappingModelBundles ?? NSBundle.allBundles(),
completion: completion
)
}
/**
Deprecated. Use `upgradeStorageIfNeeded(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use upgradeStorageIfNeeded(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public static func upgradeSQLiteStoreIfNeeded(fileURL fileURL: NSURL = LegacySQLiteStore.defaultFileURL, configuration: String? = nil, mappingModelBundles: [NSBundle]? = nil, completion: (MigrationResult) -> Void) throws -> NSProgress? {
return try self.defaultStack.upgradeSQLiteStoreIfNeeded(
fileURL: fileURL,
configuration: configuration,
mappingModelBundles: mappingModelBundles ?? NSBundle.allBundles(),
completion: completion
)
}
/**
Deprecated. Use `requiredMigrationsForStorage(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use requiredMigrationsForStorage(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
@warn_unused_result
public static func requiredMigrationsForSQLiteStore(fileName fileName: String, configuration: String? = nil, mappingModelBundles: [NSBundle] = NSBundle.allBundles() as [NSBundle]) throws -> [MigrationType] {
return try self.defaultStack.requiredMigrationsForSQLiteStore(
fileName: fileName,
configuration: configuration,
mappingModelBundles: mappingModelBundles
)
}
/**
Deprecated. Use `requiredMigrationsForStorage(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use requiredMigrationsForStorage(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
@warn_unused_result
public static func requiredMigrationsForSQLiteStore(fileURL fileURL: NSURL = LegacySQLiteStore.defaultFileURL, configuration: String? = nil, mappingModelBundles: [NSBundle] = NSBundle.allBundles() as [NSBundle]) throws -> [MigrationType] {
return try self.defaultStack.requiredMigrationsForSQLiteStore(
fileURL: fileURL,
configuration: configuration,
mappingModelBundles: mappingModelBundles
)
}
}

View File

@@ -25,9 +25,6 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - DataStack
@@ -41,17 +38,16 @@ public extension DataStack {
InMemoryStore.self,
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storeType: the storage type
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
*/
public func addStorage<T: StorageInterface where T: DefaultInitializableStore>(storeType: T.Type, completion: (SetupResult<T>) -> Void) {
public func addStorage<T: StorageInterface>(_ storeType: T.Type, completion: @escaping (SetupResult<T>) -> Void) where T: DefaultInitializableStore {
self.addStorage(storeType.init(), completion: completion)
}
@@ -63,23 +59,22 @@ public extension DataStack {
InMemoryStore(configuration: "Config1"),
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storage: the storage
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `StorageInterface` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `StorageInterface` was already added at the same URL and with the same configuration.
*/
public func addStorage<T: StorageInterface>(storage: T, completion: (SetupResult<T>) -> Void) {
public func addStorage<T: StorageInterface>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) {
self.coordinator.performAsynchronously {
if let _ = self.persistentStoreForStorage(storage) {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
@@ -88,13 +83,13 @@ public extension DataStack {
do {
try self.createPersistentStoreFromStorage(
_ = try self.createPersistentStoreFromStorage(
storage,
finalURL: nil,
finalStoreOptions: storage.storeOptions
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
@@ -106,7 +101,7 @@ public extension DataStack {
storeError,
"Failed to add \(cs_typeName(storage)) to the stack."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storeError))
}
@@ -121,20 +116,19 @@ public extension DataStack {
SQLiteStore.self,
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storeType: the local storage type
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: an `NSProgress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: a `Progress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
*/
public func addStorage<T: LocalStorage where T: DefaultInitializableStore>(storeType: T.Type, completion: (SetupResult<T>) -> Void) -> NSProgress? {
public func addStorage<T: LocalStorage>(_ storeType: T.Type, completion: @escaping (SetupResult<T>) -> Void) -> Progress? where T: DefaultInitializableStore {
return self.addStorage(storeType.init(), completion: completion)
return self.addStorage(storeType.init() as! T.Type, completion: completion)
}
/**
@@ -144,22 +138,21 @@ public extension DataStack {
SQLiteStore(fileName: "core_data.sqlite", configuration: "Config1"),
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storage: the local storage
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: an `NSProgress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `LocalStorage` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `LocalStorage` was already added at the same URL and with the same configuration.
- returns: a `Progress` instance if a migration has started, or `nil` if either no migrations are required or if a failure occured.
*/
public func addStorage<T: LocalStorage>(storage: T, completion: (SetupResult<T>) -> Void) -> NSProgress? {
public func addStorage<T: LocalStorage>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) -> Progress? {
let fileURL = storage.fileURL
CoreStore.assert(
fileURL.fileURL,
fileURL.isFileURL,
"The specified URL for the \(cs_typeName(storage)) is invalid: \"\(fileURL)\""
)
@@ -167,31 +160,31 @@ public extension DataStack {
if let _ = self.persistentStoreForStorage(storage) {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
return nil
}
if let persistentStore = self.coordinator.persistentStoreForURL(fileURL) {
if let persistentStore = self.coordinator.persistentStore(for: fileURL as URL) {
if let existingStorage = persistentStore.storageInterface as? T
where storage.matchesPersistentStore(persistentStore) {
if let existingStorage = persistentStore.storageInterface as? T,
storage.matchesPersistentStore(persistentStore) {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(existingStorage))
}
return nil
}
let error = CoreStoreError.DifferentStorageExistsAtURL(existingPersistentStoreURL: fileURL)
let error = CoreStoreError.differentStorageExistsAtURL(existingPersistentStoreURL: fileURL)
CoreStore.log(
error,
"Failed to add \(cs_typeName(storage)) at \"\(fileURL)\" because a different \(cs_typeName(NSPersistentStore)) at that URL already exists."
"Failed to add \(cs_typeName(storage)) at \"\(fileURL)\" because a different \(cs_typeName(NSPersistentStore.self)) at that URL already exists."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(error))
}
@@ -200,15 +193,15 @@ public extension DataStack {
do {
try NSFileManager.defaultManager().createDirectoryAtURL(
fileURL.URLByDeletingLastPathComponent!,
try FileManager.default.createDirectory(
at: fileURL.deletingLastPathComponent(),
withIntermediateDirectories: true,
attributes: nil
)
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
storage.dynamicType.storeType,
URL: fileURL,
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: storage).storeType,
at: fileURL as URL,
options: storage.storeOptions
)
@@ -217,16 +210,19 @@ public extension DataStack {
metadata: metadata,
completion: { (result) -> Void in
if case .Failure(.InternalError(let error)) = result {
if case .failure(.internalError(let error)) = result {
if storage.localStorageOptions.contains(.RecreateStoreOnModelMismatch) && error.isCoreDataMigrationError {
if storage.localStorageOptions.contains(.recreateStoreOnModelMismatch) && error.isCoreDataMigrationError {
do {
_ = try storage.eraseStorageAndWait(soureModel: self.model[metadata])
try self.addStorageAndWait(storage)
try storage.eraseStorageAndWait(
metadata: metadata,
soureModelHint: self.model[metadata]
)
_ = try self.addStorageAndWait(storage)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
@@ -244,9 +240,12 @@ public extension DataStack {
do {
try self.addStorageAndWait(storage)
_ = try self.addStorageAndWait(storage)
completion(SetupResult(storage))
DispatchQueue.main.async {
completion(SetupResult(storage))
}
}
catch {
@@ -260,16 +259,16 @@ public extension DataStack {
do {
try self.addStorageAndWait(storage)
_ = try self.addStorageAndWait(storage)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
}
catch {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(error))
}
@@ -281,9 +280,9 @@ public extension DataStack {
let storeError = CoreStoreError(error)
CoreStore.log(
storeError,
"Failed to load SQLite \(cs_typeName(NSPersistentStore)) metadata."
"Failed to load SQLite \(cs_typeName(NSPersistentStore.self)) metadata."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storeError))
}
@@ -301,7 +300,7 @@ public extension DataStack {
ubiquitousContainerID: "iCloud.com.mycompany.myapp.containername",
ubiquitousPeerToken: "9614d658014f4151a95d8048fb717cf0",
configuration: "Config1",
cloudStorageOptions: .RecreateLocalStoreOnModelMismatch
cloudStorageOptions: .recreateLocalStoreOnModelMismatch
) else {
// iCloud is not available on the device
return
@@ -310,48 +309,47 @@ public extension DataStack {
storage,
completion: { result in
switch result {
case .Success(let storage): // ...
case .Failure(let error): // ...
case .success(let storage): // ...
case .failure(let error): // ...
}
}
)
```
- parameter storage: the cloud storage
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `CloudStorage` associated to the `SetupResult.Success` may not always be the same instance as the parameter argument if a previous `CloudStorage` was already added at the same URL and with the same configuration.
- parameter completion: the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `SetupResult` argument indicates the result. Note that the `CloudStorage` associated to the `SetupResult.success` may not always be the same instance as the parameter argument if a previous `CloudStorage` was already added at the same URL and with the same configuration.
*/
public func addStorage<T: CloudStorage>(storage: T, completion: (SetupResult<T>) -> Void) {
public func addStorage<T: CloudStorage>(_ storage: T, completion: @escaping (SetupResult<T>) -> Void) {
let cacheFileURL = storage.cacheFileURL
self.coordinator.performSynchronously {
if let _ = self.persistentStoreForStorage(storage) {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
return
}
if let persistentStore = self.coordinator.persistentStoreForURL(cacheFileURL) {
if let persistentStore = self.coordinator.persistentStore(for: cacheFileURL as URL) {
if let existingStorage = persistentStore.storageInterface as? T
where storage.matchesPersistentStore(persistentStore) {
if let existingStorage = persistentStore.storageInterface as? T,
storage.matchesPersistentStore(persistentStore) {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(existingStorage))
}
return
}
let error = CoreStoreError.DifferentStorageExistsAtURL(existingPersistentStoreURL: cacheFileURL)
let error = CoreStoreError.differentStorageExistsAtURL(existingPersistentStoreURL: cacheFileURL)
CoreStore.log(
error,
"Failed to add \(cs_typeName(storage)) at \"\(cacheFileURL)\" because a different \(cs_typeName(NSPersistentStore)) at that URL already exists."
"Failed to add \(cs_typeName(storage)) at \"\(cacheFileURL)\" because a different \(cs_typeName(NSPersistentStore.self)) at that URL already exists."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(error))
}
@@ -361,39 +359,34 @@ public extension DataStack {
do {
var cloudStorageOptions = storage.cloudStorageOptions
cloudStorageOptions.remove(.RecreateLocalStoreOnModelMismatch)
cloudStorageOptions.remove(.recreateLocalStoreOnModelMismatch)
let storeOptions = storage.storeOptionsForOptions(cloudStorageOptions)
let storeOptions = storage.dictionary(forOptions: cloudStorageOptions)
do {
try NSFileManager.defaultManager().createDirectoryAtURL(
cacheFileURL.URLByDeletingLastPathComponent!,
withIntermediateDirectories: true,
attributes: nil
)
try self.createPersistentStoreFromStorage(
_ = try self.createPersistentStoreFromStorage(
storage,
finalURL: cacheFileURL,
finalStoreOptions: storeOptions
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
}
catch let error as NSError where storage.cloudStorageOptions.contains(.RecreateLocalStoreOnModelMismatch) && error.isCoreDataMigrationError {
catch let error as NSError where storage.cloudStorageOptions.contains(.recreateLocalStoreOnModelMismatch) && error.isCoreDataMigrationError {
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
storage.dynamicType.storeType,
URL: cacheFileURL,
let finalStoreOptions = storage.dictionary(forOptions: storage.cloudStorageOptions)
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: storage).storeType,
at: cacheFileURL,
options: storeOptions
)
_ = try storage.eraseStorageAndWait(soureModel: self.model[metadata])
try self.createPersistentStoreFromStorage(
_ = try self.model[metadata].flatMap(storage.eraseStorageAndWait)
_ = try self.createPersistentStoreFromStorage(
storage,
finalURL: cacheFileURL,
finalStoreOptions: storeOptions
finalStoreOptions: finalStoreOptions
)
}
}
@@ -402,16 +395,16 @@ public extension DataStack {
do {
try self.addStorageAndWait(storage)
_ = try self.addStorageAndWait(storage)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storage))
}
}
catch {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(error))
}
@@ -422,9 +415,9 @@ public extension DataStack {
let storeError = CoreStoreError(error)
CoreStore.log(
storeError,
"Failed to load \(cs_typeName(NSPersistentStore)) metadata."
"Failed to load \(cs_typeName(NSPersistentStore.self)) metadata."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(SetupResult(storeError))
}
@@ -438,9 +431,9 @@ public extension DataStack {
- parameter storage: the local storage
- parameter completion: the closure to be executed on the main queue when the migration completes, either due to success or failure. The closure's `MigrationResult` argument indicates the result.
- throws: a `CoreStoreError` value indicating the failure
- returns: an `NSProgress` instance if a migration has started, or `nil` is no migrations are required
- returns: a `Progress` instance if a migration has started, or `nil` is no migrations are required
*/
public func upgradeStorageIfNeeded<T: LocalStorage>(storage: T, completion: (MigrationResult) -> Void) throws -> NSProgress? {
public func upgradeStorageIfNeeded<T: LocalStorage>(_ storage: T, completion: @escaping (MigrationResult) -> Void) throws -> Progress? {
return try self.coordinator.performSynchronously {
@@ -452,9 +445,9 @@ public extension DataStack {
"Attempted to migrate an already added \(cs_typeName(storage)) at URL \"\(fileURL)\""
)
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
storage.dynamicType.storeType,
URL: fileURL,
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: storage).storeType,
at: fileURL as URL,
options: storage.storeOptions
)
return self.upgradeStorageIfNeeded(
@@ -482,8 +475,7 @@ public extension DataStack {
- throws: a `CoreStoreError` value indicating the failure
- returns: a `MigrationType` array indicating the migration steps required for the store, or an empty array if the file does not exist yet. Otherwise, an error is thrown if either inspection of the store failed, or if no mapping model was found/inferred.
*/
@warn_unused_result
public func requiredMigrationsForStorage<T: LocalStorage>(storage: T) throws -> [MigrationType] {
public func requiredMigrationsForStorage<T: LocalStorage>(_ storage: T) throws -> [MigrationType] {
return try self.coordinator.performSynchronously {
@@ -495,15 +487,15 @@ public extension DataStack {
)
do {
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
storage.dynamicType.storeType,
URL: fileURL,
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: storage).storeType,
at: fileURL as URL,
options: storage.storeOptions
)
guard let migrationSteps = self.computeMigrationFromStorage(storage, metadata: metadata) else {
let error = CoreStoreError.MappingModelNotFound(
let error = CoreStoreError.mappingModelNotFound(
localStoreURL: fileURL,
targetModel: self.model,
targetModelVersion: self.modelVersion
@@ -515,9 +507,9 @@ public extension DataStack {
throw error
}
if migrationSteps.count > 1 && storage.localStorageOptions.contains(.PreventProgressiveMigration) {
if migrationSteps.count > 1 && storage.localStorageOptions.contains(.preventProgressiveMigration) {
let error = CoreStoreError.ProgressiveMigrationRequired(localStoreURL: fileURL)
let error = CoreStoreError.progressiveMigrationRequired(localStoreURL: fileURL)
CoreStore.log(
error,
"Failed to find migration mapping from the \(cs_typeName(storage)) at URL \"\(fileURL)\" to version model \"\(self.modelVersion)\" without requiring progessive migrations."
@@ -547,11 +539,11 @@ public extension DataStack {
// MARK: Private
private func upgradeStorageIfNeeded<T: LocalStorage>(storage: T, metadata: [String: AnyObject], completion: (MigrationResult) -> Void) -> NSProgress? {
private func upgradeStorageIfNeeded<T: LocalStorage>(_ storage: T, metadata: [String: Any], completion: @escaping (MigrationResult) -> Void) -> Progress? {
guard let migrationSteps = self.computeMigrationFromStorage(storage, metadata: metadata) else {
let error = CoreStoreError.MappingModelNotFound(
let error = CoreStoreError.mappingModelNotFound(
localStoreURL: storage.fileURL,
targetModel: self.model,
targetModelVersion: self.modelVersion
@@ -561,7 +553,7 @@ public extension DataStack {
"Failed to find migration steps from \(cs_typeName(storage)) at URL \"\(storage.fileURL)\" to version model \"\(self.model)\"."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(MigrationResult(error))
}
@@ -571,21 +563,21 @@ public extension DataStack {
let numberOfMigrations: Int64 = Int64(migrationSteps.count)
if numberOfMigrations == 0 {
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(MigrationResult([]))
return
}
return nil
}
else if numberOfMigrations > 1 && storage.localStorageOptions.contains(.PreventProgressiveMigration) {
else if numberOfMigrations > 1 && storage.localStorageOptions.contains(.preventProgressiveMigration) {
let error = CoreStoreError.ProgressiveMigrationRequired(localStoreURL: storage.fileURL)
let error = CoreStoreError.progressiveMigrationRequired(localStoreURL: storage.fileURL)
CoreStore.log(
error,
"Failed to find migration mapping from the \(cs_typeName(storage)) at URL \"\(storage.fileURL)\" to version model \"\(self.modelVersion)\" without requiring progessive migrations."
)
GCDQueue.Main.async {
DispatchQueue.main.async {
completion(MigrationResult(error))
}
@@ -594,28 +586,28 @@ public extension DataStack {
let migrationTypes = migrationSteps.map { $0.migrationType }
var migrationResult: MigrationResult?
var operations = [NSOperation]()
var operations = [Operation]()
var cancelled = false
let progress = NSProgress(parent: nil, userInfo: nil)
let progress = Progress(parent: nil, userInfo: nil)
progress.totalUnitCount = numberOfMigrations
for (sourceModel, destinationModel, mappingModel, _) in migrationSteps {
progress.becomeCurrentWithPendingUnitCount(1)
progress.becomeCurrent(withPendingUnitCount: 1)
let childProgress = NSProgress(parent: progress, userInfo: nil)
let childProgress = Progress(parent: progress, userInfo: nil)
childProgress.totalUnitCount = 100
operations.append(
NSBlockOperation { [weak self] in
BlockOperation { [weak self] in
guard let `self` = self where !cancelled else {
guard let `self` = self, !cancelled else {
return
}
cs_autoreleasepool {
autoreleasepool {
do {
@@ -634,9 +626,9 @@ public extension DataStack {
}
}
GCDQueue.Main.async {
DispatchQueue.main.async {
_ = withExtendedLifetime(childProgress) { (_: NSProgress) -> Void in }
_ = withExtendedLifetime(childProgress) { (_: Progress) -> Void in }
}
}
)
@@ -644,21 +636,12 @@ public extension DataStack {
progress.resignCurrent()
}
let migrationOperation = NSBlockOperation()
#if USE_FRAMEWORKS
migrationOperation.qualityOfService = .Utility
#else
if #available(iOS 8.0, *) {
migrationOperation.qualityOfService = .Utility
}
#endif
let migrationOperation = BlockOperation()
migrationOperation.qualityOfService = .utility
operations.forEach { migrationOperation.addDependency($0) }
migrationOperation.addExecutionBlock { () -> Void in
GCDQueue.Main.async {
DispatchQueue.main.async {
progress.setProgressHandler(nil)
completion(migrationResult ?? MigrationResult(migrationTypes))
@@ -673,10 +656,10 @@ public extension DataStack {
return progress
}
private func computeMigrationFromStorage<T: LocalStorage>(storage: T, metadata: [String: AnyObject]) -> [(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType)]? {
private func computeMigrationFromStorage<T: LocalStorage>(_ storage: T, metadata: [String: Any]) -> [(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, migrationType: MigrationType)]? {
let model = self.model
if model.isConfiguration(storage.configuration, compatibleWithStoreMetadata: metadata) {
if model.isConfiguration(withName: storage.configuration, compatibleWithStoreMetadata: metadata) {
return []
}
@@ -695,10 +678,11 @@ public extension DataStack {
while let nextVersion = migrationChain.nextVersionFrom(currentVersion),
let sourceModel = model[currentVersion],
let destinationModel = model[nextVersion] where sourceModel != model {
sourceModel != model,
let destinationModel = model[nextVersion] {
if let mappingModel = NSMappingModel(
fromBundles: storage.mappingModelBundles,
from: storage.mappingModelBundles,
forSourceModel: sourceModel,
destinationModel: destinationModel) {
@@ -707,7 +691,7 @@ public extension DataStack {
sourceModel: sourceModel,
destinationModel: destinationModel,
mappingModel: mappingModel,
migrationType: .Heavyweight(
migrationType: .heavyweight(
sourceVersion: currentVersion,
destinationVersion: nextVersion
)
@@ -718,8 +702,8 @@ public extension DataStack {
do {
let mappingModel = try NSMappingModel.inferredMappingModelForSourceModel(
sourceModel,
let mappingModel = try NSMappingModel.inferredMappingModel(
forSourceModel: sourceModel,
destinationModel: destinationModel
)
@@ -728,7 +712,7 @@ public extension DataStack {
sourceModel: sourceModel,
destinationModel: destinationModel,
mappingModel: mappingModel,
migrationType: .Lightweight(
migrationType: .lightweight(
sourceVersion: currentVersion,
destinationVersion: nextVersion
)
@@ -751,23 +735,23 @@ public extension DataStack {
return nil
}
private func startMigrationForStorage<T: LocalStorage>(storage: T, sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, progress: NSProgress) throws {
private func startMigrationForStorage<T: LocalStorage>(_ storage: T, sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, mappingModel: NSMappingModel, progress: Progress) throws {
let fileURL = storage.fileURL
let temporaryDirectoryURL = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.URLByAppendingPathComponent(NSBundle.mainBundle().bundleIdentifier ?? "com.CoreStore.DataStack")
.URLByAppendingPathComponent(NSProcessInfo().globallyUniqueString)
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.appendingPathComponent(Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack")
.appendingPathComponent(ProcessInfo().globallyUniqueString)
let fileManager = NSFileManager.defaultManager()
try! fileManager.createDirectoryAtURL(
temporaryDirectoryURL,
let fileManager = FileManager.default
try! fileManager.createDirectory(
at: temporaryDirectoryURL,
withIntermediateDirectories: true,
attributes: nil
)
let temporaryFileURL = temporaryDirectoryURL.URLByAppendingPathComponent(
fileURL.lastPathComponent!,
let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(
fileURL.lastPathComponent,
isDirectory: false
)
@@ -779,13 +763,13 @@ public extension DataStack {
do {
try migrationManager.migrateStoreFromURL(
fileURL,
type: storage.dynamicType.storeType,
try migrationManager.migrateStore(
from: fileURL,
sourceType: type(of: storage).storeType,
options: nil,
withMappingModel: mappingModel,
with: mappingModel,
toDestinationURL: temporaryFileURL,
destinationType: storage.dynamicType.storeType,
destinationType: type(of: storage).storeType,
destinationOptions: nil
)
}
@@ -793,7 +777,7 @@ public extension DataStack {
do {
try fileManager.removeItemAtURL(temporaryFileURL)
try fileManager.removeItem(at: temporaryFileURL)
}
catch _ { }
@@ -810,9 +794,9 @@ public extension DataStack {
do {
try fileManager.replaceItemAtURL(
fileURL,
withItemAtURL: temporaryFileURL,
try fileManager.replaceItem(
at: fileURL as URL,
withItemAt: temporaryFileURL,
backupItemName: nil,
options: [],
resultingItemURL: nil
@@ -824,7 +808,7 @@ public extension DataStack {
do {
try fileManager.removeItemAtURL(temporaryFileURL)
try fileManager.removeItem(at: temporaryFileURL)
}
catch _ { }
@@ -839,159 +823,4 @@ public extension DataStack {
throw fileError
}
}
// MARK: Deprecated
/**
Deprecated. Use `addStorage(_:completion:)` by passing a `InMemoryStore` instance.
*/
@available(*, deprecated=2.0.0, message="Use addStorage(_:completion:) by passing a InMemoryStore instance.")
public func addInMemoryStore(configuration configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
self.addStorage(
InMemoryStore(configuration: configuration),
completion: { result in
switch result {
case .Success(let storage):
completion(PersistentStoreResult(self.persistentStoreForStorage(storage)!))
case .Failure(let error):
completion(PersistentStoreResult(error as NSError))
}
}
)
}
/**
Deprecated. Use `addStorage(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addStorage(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public func addSQLiteStore(fileName fileName: String, configuration: String? = nil, mappingModelBundles: [NSBundle]? = nil, resetStoreOnModelMismatch: Bool = false, completion: (PersistentStoreResult) -> Void) throws -> NSProgress? {
return self.addStorage(
LegacySQLiteStore(
fileName: fileName,
configuration: configuration,
mappingModelBundles: mappingModelBundles ?? NSBundle.allBundles(),
localStorageOptions: resetStoreOnModelMismatch ? .RecreateStoreOnModelMismatch : .None
),
completion: { result in
switch result {
case .Success(let storage):
completion(PersistentStoreResult(self.persistentStoreForStorage(storage)!))
case .Failure(let error):
completion(PersistentStoreResult(error as NSError))
}
}
)
}
/**
Deprecated. Use `addSQLiteStore(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addSQLiteStore(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public func addSQLiteStore(fileURL fileURL: NSURL = LegacySQLiteStore.defaultFileURL, configuration: String? = nil, mappingModelBundles: [NSBundle]? = NSBundle.allBundles(), resetStoreOnModelMismatch: Bool = false, completion: (PersistentStoreResult) -> Void) throws -> NSProgress? {
return self.addStorage(
LegacySQLiteStore(
fileURL: fileURL,
configuration: configuration,
mappingModelBundles: mappingModelBundles ?? NSBundle.allBundles(),
localStorageOptions: resetStoreOnModelMismatch ? .RecreateStoreOnModelMismatch : .None
),
completion: { result in
switch result {
case .Success(let storage):
completion(PersistentStoreResult(self.persistentStoreForStorage(storage)!))
case .Failure(let error):
completion(PersistentStoreResult(error as NSError))
}
}
)
}
/**
Deprecated. Use `upgradeStorageIfNeeded(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use upgradeStorageIfNeeded(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public func upgradeSQLiteStoreIfNeeded(fileName fileName: String, configuration: String? = nil, mappingModelBundles: [NSBundle] = NSBundle.allBundles(), completion: (MigrationResult) -> Void) throws -> NSProgress? {
return try self.upgradeStorageIfNeeded(
LegacySQLiteStore(
fileName: fileName,
configuration: configuration,
mappingModelBundles: mappingModelBundles
),
completion: completion
)
}
/**
Deprecated. Use `upgradeStorageIfNeeded(_:completion:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use upgradeStorageIfNeeded(_:completion:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public func upgradeSQLiteStoreIfNeeded(fileURL fileURL: NSURL = LegacySQLiteStore.defaultFileURL, configuration: String? = nil, mappingModelBundles: [NSBundle] = NSBundle.allBundles(), completion: (MigrationResult) -> Void) throws -> NSProgress? {
return try self.upgradeStorageIfNeeded(
LegacySQLiteStore(
fileURL: fileURL,
configuration: configuration,
mappingModelBundles: mappingModelBundles
),
completion: completion
)
}
/**
Deprecated. Use `requiredMigrationsForStorage(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use requiredMigrationsForStorage(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
@warn_unused_result
public func requiredMigrationsForSQLiteStore(fileName fileName: String, configuration: String? = nil, mappingModelBundles: [NSBundle] = NSBundle.allBundles() as [NSBundle]) throws -> [MigrationType] {
return try self.requiredMigrationsForStorage(
LegacySQLiteStore(
fileName: fileName,
configuration: configuration,
mappingModelBundles: mappingModelBundles
)
)
}
/**
Deprecated. Use `requiredMigrationsForStorage(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use requiredMigrationsForStorage(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
@warn_unused_result
public func requiredMigrationsForSQLiteStore(fileURL fileURL: NSURL = LegacySQLiteStore.defaultFileURL, configuration: String? = nil, mappingModelBundles: [NSBundle] = NSBundle.allBundles() as [NSBundle]) throws -> [MigrationType] {
return try self.requiredMigrationsForStorage(
LegacySQLiteStore(
fileURL: fileURL,
configuration: configuration,
mappingModelBundles: mappingModelBundles
)
)
}
}

View File

@@ -60,7 +60,7 @@ import CoreData
- a version appears twice as a key in a dictionary literal
- a loop is found in any of the paths
*/
public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, DictionaryLiteralConvertible, ArrayLiteralConvertible, Equatable {
public struct MigrationChain: ExpressibleByNilLiteral, ExpressibleByStringLiteral, ExpressibleByDictionaryLiteral, ExpressibleByArrayLiteral, Equatable {
/**
Initializes the `MigrationChain` with empty values, which instructs the `DataStack` to use the .xcdatamodel's current version as the final version, and to disable progressive migrations.
@@ -87,9 +87,9 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
/**
Initializes the `MigrationChain` with a linear order of versions, which becomes the order of the `DataStack`'s progressive migrations.
*/
public init<T: CollectionType where T.Generator.Element == String, T.Index: BidirectionalIndexType>(_ elements: T) {
public init<T: Collection>(_ elements: T) where T.Iterator.Element == String, T.SubSequence.Iterator.Element == String, T.Index: Comparable {
CoreStore.assert(Set(elements).count == Array(elements).count, "\(cs_typeName(MigrationChain))'s migration chain could not be created due to duplicate version strings.")
CoreStore.assert(Set(elements).count == Array(elements).count, "\(cs_typeName(MigrationChain.self))'s migration chain could not be created due to duplicate version strings.")
var lastVersion: String?
var versionTree = [String: String]()
@@ -105,8 +105,8 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
}
self.versionTree = versionTree
self.rootVersions = Set([elements.first].flatMap { $0 == nil ? [] : [$0!] })
self.leafVersions = Set([elements.last].flatMap { $0 == nil ? [] : [$0!] })
self.rootVersions = Set(elements.prefix(1))
self.leafVersions = Set(elements.suffix(1))
self.valid = valid
}
@@ -124,7 +124,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
return
}
CoreStore.assert(false, "\(cs_typeName(MigrationChain))'s migration chain could not be created due to ambiguous version paths.")
CoreStore.assert(false, "\(cs_typeName(MigrationChain.self))'s migration chain could not be created due to ambiguous version paths.")
valid = false
}
@@ -138,11 +138,11 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
var checklist: Set<String> = [start]
var version = start
while let nextVersion = versionTree[version] where nextVersion != version {
while let nextVersion = versionTree[version], nextVersion != version {
if checklist.contains(nextVersion) {
CoreStore.assert(false, "\(cs_typeName(MigrationChain))'s migration chain could not be created due to looping version paths.")
CoreStore.assert(false, "\(cs_typeName(MigrationChain.self))'s migration chain could not be created due to looping version paths.")
return true
}
@@ -154,7 +154,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
}
self.versionTree = versionTree
self.rootVersions = Set(versionTree.keys).subtract(versionTree.values)
self.rootVersions = Set(versionTree.keys).subtracting(versionTree.values)
self.leafVersions = leafVersions
self.valid = valid && Set(versionTree.keys).union(versionTree.values).filter { isVersionAmbiguous($0) }.count <= 0
}
@@ -168,7 +168,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
}
// MARK: NilLiteralConvertible
// MARK: ExpressibleByNilLiteral
public init(nilLiteral: ()) {
@@ -176,7 +176,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
}
// MARK: StringLiteralConvertible
// MARK: ExpressibleByStringLiteral
public init(stringLiteral value: String) {
@@ -200,7 +200,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
}
// MARK: DictionaryLiteralConvertible
// MARK: ExpressibleByDictionaryLiteral
public init(dictionaryLiteral elements: (String, String)...) {
@@ -208,7 +208,7 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
}
// MARK: ArrayLiteralConvertible
// MARK: ExpressibleByArrayLiteral
public init(arrayLiteral elements: String...) {
@@ -216,6 +216,17 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
}
// MARK: Equatable
public static func == (lhs: MigrationChain, rhs: MigrationChain) -> Bool {
return lhs.versionTree == rhs.versionTree
&& lhs.rootVersions == rhs.rootVersions
&& lhs.leafVersions == rhs.leafVersions
&& lhs.valid == rhs.valid
}
// MARK: Internal
internal let rootVersions: Set<String>
@@ -227,16 +238,16 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
return self.versionTree.count <= 0
}
internal func contains(version: String) -> Bool {
internal func contains(_ version: String) -> Bool {
return self.rootVersions.contains(version)
|| self.leafVersions.contains(version)
|| self.versionTree[version] != nil
}
internal func nextVersionFrom(version: String) -> String? {
internal func nextVersionFrom(_ version: String) -> String? {
guard let nextVersion = self.versionTree[version] where nextVersion != version else {
guard let nextVersion = self.versionTree[version], nextVersion != version else {
return nil
}
@@ -246,18 +257,6 @@ public struct MigrationChain: NilLiteralConvertible, StringLiteralConvertible, D
// MARK: Private
private let versionTree: [String: String]
}
// MARK: - MigrationChain: Equatable
@warn_unused_result
public func == (lhs: MigrationChain, rhs: MigrationChain) -> Bool {
return lhs.versionTree == rhs.versionTree
&& lhs.rootVersions == rhs.rootVersions
&& lhs.leafVersions == rhs.leafVersions
&& lhs.valid == rhs.valid
fileprivate let versionTree: [String: String]
}

Some files were not shown because too many files have changed in this diff Show More