Compare commits

..

1 Commits

Author SHA1 Message Date
John Estropia
81c5b0c650 fix iOS 10 NSFetchedResultsController bug for iOS 7-supporting branch 2016-11-08 10:04:49 +09:00
174 changed files with 7045 additions and 7842 deletions

3
.gitmodules vendored
View File

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

View File

@@ -1 +0,0 @@
3.0.1

View File

@@ -1,5 +1,5 @@
language: objective-c
osx_image: xcode8.2
osx_image: xcode7.3
sudo: false
git:
submodules: false
@@ -10,21 +10,20 @@ env:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
matrix:
- 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"
- 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"
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.18/Carthage.pkg"
- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.11/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg"
before_script:
@@ -37,8 +36,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 "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;
- 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;
- if [ $POD_LINT == "YES" ]; then
pod lib lint --quick;
fi

View File

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

View File

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

1
Carthage/Checkouts/GCDKit vendored Submodule

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "3.0.2"
s.version = "2.0.7"
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,4 +19,6 @@ 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" : 204,
"DVTSourceControlWorkspaceBlueprintVersion" : 203,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -14,10 +14,24 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
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">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -28,14 +42,24 @@
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 = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
@@ -51,16 +75,15 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
BuildableName = "CoreStoreDemo.app"
BlueprintName = "CoreStoreDemo"
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
BlueprintIdentifier = "B5D9E2ED1CA2C317007A9D52"
BuildableName = "CoreStore_iOS7.framework"
BlueprintName = "CoreStore iOS7"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
@@ -70,19 +93,9 @@
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 = "Debug">
buildConfiguration = "Release">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"

View File

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

View File

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

View File

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

View File

@@ -36,6 +36,8 @@
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 */; };
@@ -52,6 +54,7 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */,
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
@@ -91,6 +94,7 @@
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>"; };
@@ -106,6 +110,7 @@
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 */,
@@ -141,6 +146,7 @@
children = (
B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
B5BDC9211C202429008147CD /* CoreStore.framework */,
B5BDC9241C202429008147CD /* GCDKit.framework */,
B52977DE1B120F83003D50A5 /* MapKit.framework */,
);
name = Frameworks;
@@ -266,12 +272,11 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = {
B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3;
LastSwiftMigration = 0800;
};
};
};
@@ -456,7 +461,6 @@
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;
};
@@ -469,8 +473,6 @@
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

@@ -18,9 +18,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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.isDaylightSavingTime
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.daylightSavingTime
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.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepare(for: segue, sender: sender)
super.prepareForSegue(segue, sender: sender)
if let indexPath = sender as? IndexPath {
if let indexPath = sender as? NSIndexPath {
switch segue.destination {
switch segue.destinationViewController {
case let controller as FetchingResultsViewController:
let item = self.fetchingItems[indexPath.row]
controller.set(timeZones: item.fetch(), title: item.title)
controller.setTimeZones(item.fetch(), title: item.title)
case let controller as QueryingResultsViewController:
let item = self.queryingItems[indexPath.row]
controller.set(value: item.query(), title: item.title)
controller.setValue(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, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
let cell = tableView.dequeueReusableCellWithIdentifier("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, didSelectRowAt indexPath: IndexPath) {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
switch self.segmentedControl?.selectedSegmentIndex {
case Section.fetching.rawValue?:
self.performSegue(withIdentifier: "FetchingResultsViewController", sender: indexPath)
case Section.Fetching.rawValue?:
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath)
case Section.querying.rawValue?:
self.performSegue(withIdentifier: "QueryingResultsViewController", sender: indexPath)
case Section.Querying.rawValue?:
self.performSegueWithIdentifier("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(#keyPath(TimeZone.name)))
From(TimeZone),
OrderBy(.Ascending("name"))
)!
}
),
@@ -177,9 +177,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Asia"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "Asia"),
OrderBy(.Ascending("secondsFromGMT"))
)!
}
),
@@ -188,10 +188,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America")
|| Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Europe"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
From(TimeZone),
Where("%K BEGINSWITH[c] %@", "name", "America")
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"),
OrderBy(.Ascending("secondsFromGMT"))
)!
}
),
@@ -200,9 +200,9 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
!Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
From(TimeZone),
!Where("%K BEGINSWITH[c] %@", "name", "America"),
OrderBy(.Ascending("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(#keyPath(TimeZone.name)))
OrderBy(.Ascending("name"))
)!
}
)
@@ -222,60 +222,60 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
private let queryingItems = [
(
title: "Number of Time Zones",
query: { () -> Any in
query: { () -> AnyObject in
return Static.timeZonesStack.queryValue(
From<TimeZone>(),
Select<NSNumber>(.count(#keyPath(TimeZone.name)))
From(TimeZone),
Select<NSNumber>(.Count("name"))
)!
}
),
(
title: "Abbreviation For Tokyo's Time Zone",
query: { () -> Any in
query: { () -> AnyObject in
return Static.timeZonesStack.queryValue(
From<TimeZone>(),
Select<String>(#keyPath(TimeZone.abbreviation)),
Where("%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
From(TimeZone),
Select<String>("abbreviation"),
Where("%K ENDSWITH[c] %@", "name", "Tokyo")
)!
}
),
(
title: "All Abbreviations",
query: { () -> Any in
query: { () -> AnyObject in
return Static.timeZonesStack.queryAttributes(
From<TimeZone>(),
Select<NSDictionary>(#keyPath(TimeZone.name), #keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.name)))
From(TimeZone),
Select<NSDictionary>("name", "abbreviation"),
OrderBy(.Ascending("name"))
)!
}
),
(
title: "Number of Countries per Time Zone",
query: { () -> Any in
query: { () -> AnyObject in
return Static.timeZonesStack.queryAttributes(
From<TimeZone>(),
Select<NSDictionary>(.count(#keyPath(TimeZone.abbreviation)), #keyPath(TimeZone.abbreviation)),
GroupBy(#keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)), .ascending(#keyPath(TimeZone.name)))
From(TimeZone),
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"),
GroupBy("abbreviation"),
OrderBy(.Ascending("secondsFromGMT"), .Ascending("name"))
)!
}
),
(
title: "Number of Countries with Summer Time",
query: { () -> Any in
query: { () -> AnyObject in
return Static.timeZonesStack.queryAttributes(
From<TimeZone>(),
From(TimeZone),
Select<NSDictionary>(
.count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"),
#keyPath(TimeZone.hasDaylightSavingTime)
.Count("hasDaylightSavingTime", As: "numberOfCountries"),
"hasDaylightSavingTime"
),
GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)),
OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime)))
GroupBy("hasDaylightSavingTime"),
OrderBy(.Descending("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 set(timeZones: [TimeZone]?, title: String) {
func setTimeZones(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, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: 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 set(value: Any?, title: String) {
func setValue(value: AnyObject?, title: String) {
switch value {
case (let array as [Any])?:
self.values = array.map { (item: Any) -> (title: String, detail: String) in
case (let array as [AnyObject])?:
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
(
title: String(describing: item),
detail: String(reflecting: type(of: item))
title: item.description,
detail: String(reflecting: item.dynamicType)
)
}
case let item?:
self.values = [
(
title: String(describing: item),
detail: String(reflecting: type(of: item))
title: item.description,
detail: String(reflecting: item.dynamicType)
)
]
@@ -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, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: 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("%K >= %@", #keyPath(Palette.brightness), 0.9)
case .dark: return Where("%K <= %@", #keyPath(Palette.brightness), 0.4)
case .All: return Where(true)
case .Light: return Where("brightness >= 0.9")
case .Dark: return Where("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(#keyPath(Palette.colorName)),
OrderBy(.ascending(#keyPath(Palette.hue)))
From(Palette),
SectionBy("colorName"),
OrderBy(.Ascending("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.setTable(enabled: !Static.palettes.isPendingRefetch)
self.setTableEnabled(!Static.palettes.isPendingRefetch)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepare(for: segue, sender: sender)
super.prepareForSegue(segue, sender: sender)
switch (segue.identifier, segue.destination, sender) {
switch (segue.identifier, segue.destinationViewController, 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 numberOfSections(in tableView: UITableView) -> Int {
override func numberOfSectionsInTableView(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, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("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, didSelectRowAt indexPath: IndexPath) {
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.performSegue(
withIdentifier: "ObjectObserverDemoViewController",
self.performSegueWithIdentifier(
"ObjectObserverDemoViewController",
sender: Static.palettes[indexPath]
)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
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.setTable(enabled: false)
self.setTableEnabled(false)
}
func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
func listMonitorDidRefetch(monitor: ListMonitor<Palette>) {
self.filterBarButton?.title = Static.filter.rawValue
self.tableView.reloadData()
self.setTable(enabled: true)
self.setTableEnabled(true)
}
// MARK: ListObjectObserver
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) {
self.tableView.insertRows(at: [indexPath], with: .automatic)
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) {
self.tableView.deleteRows(at: [indexPath], with: .automatic)
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func listMonitor(_ monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) {
if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell {
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? PaletteTableViewCell {
let palette = Static.palettes[indexPath]
cell.colorView?.backgroundColor = palette.color
@@ -236,24 +236,23 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
}
}
func listMonitor(_ monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
self.tableView.deleteRowsAtIndexPaths([fromIndexPath], withRowAnimation: .Automatic)
self.tableView.insertRowsAtIndexPaths([toIndexPath], withRowAnimation: .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(IndexSet(integer: sectionIndex), with: .automatic)
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .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(IndexSet(integer: sectionIndex), with: .automatic)
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
}
@@ -261,43 +260,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 setTable(enabled: Bool) {
private func setTableEnabled(enabled: Bool) {
UIView.animate(
withDuration: 0.2,
UIView.animateWithDuration(
0.2,
delay: 0,
options: .beginFromCurrentState,
options: .BeginFromCurrentState,
animations: { () -> Void in
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.isUserInteractionEnabled = enabled
tableView.userInteractionEnabled = 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(#keyPath(Palette.hue)))) {
if let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("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.self))
let palette = transaction.create(Into(Palette))
palette.setInitialValues()
_ = transaction.commitAndWait()
transaction.commitAndWait()
}
let palette = CoreStore.fetchOne(From<Palette>(), OrderBy(.ascending(#keyPath(Palette.hue))))!
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("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?.isEnabled = false
self.navigationItem.rightBarButtonItem?.enabled = false
self.colorNameLabel?.alpha = 0.3
self.colorView?.alpha = 0.3
self.hsbLabel?.text = "Deleted"
self.hsbLabel?.textColor = UIColor.red
self.hsbLabel?.textColor = UIColor.redColor()
self.hueSlider?.isEnabled = false
self.saturationSlider?.isEnabled = false
self.brightnessSlider?.isEnabled = false
self.hueSlider?.enabled = false
self.saturationSlider?.enabled = false
self.brightnessSlider?.enabled = 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(#keyPath(Palette.hue)) == true {
if changedKeys == nil || changedKeys?.contains("hue") == true {
self.hueSlider?.value = Float(palette.hue)
}
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.saturation)) == true {
if changedKeys == nil || changedKeys?.contains("saturation") == true {
self.saturationSlider?.value = palette.saturation
}
if changedKeys == nil || changedKeys?.contains(#keyPath(Palette.brightness)) == true {
if changedKeys == nil || changedKeys?.contains("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.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}

View File

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

View File

@@ -8,6 +8,7 @@
import UIKit
import CoreStore
import GCDKit
// MARK: - CustomLoggerViewController
@@ -33,47 +34,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.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
// MARK: CoreStoreLogger
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
DispatchQueue.main.async { [weak self] in
GCDQueue.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("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
}
}
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
DispatchQueue.main.async { [weak self] in
GCDQueue.Main.async { [weak self] in
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
}
}
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() {
@@ -81,9 +82,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
}
let messageString = message()
DispatchQueue.main.async { [weak self] in
GCDQueue.Main.async { [weak self] in
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
}
}
@@ -93,14 +94,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, ListObserver, UITableViewDataSource, UITableViewDelegate {
class MigrationsDemoViewController: UIViewController {
// MARK: UIViewController
@@ -22,28 +22,28 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
if let segmentedControl = self.segmentedControl {
for (index, model) in self.models.enumerated() {
for (index, model) in self.models.enumerate() {
segmentedControl.setTitle(
model.label,
forSegmentAt: index
forSegmentAtIndex: index
)
}
}
self.set(dataStack: nil, model: nil, scrollToSelection: false)
self.setDataStack(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.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
let modelMetadata = withExtendedLifetime(DataStack(modelName: "MigrationDemo")) {
@@ -72,71 +72,6 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
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
@@ -178,13 +113,13 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
return self._dataStack
}
private var _lastSelectedIndexPath: IndexPath?
private var lastSelectedIndexPath: IndexPath? {
private var _lastSelectedIndexPath: NSIndexPath?
private var lastSelectedIndexPath: NSIndexPath? {
return self._lastSelectedIndexPath
}
private func setSelectedIndexPath(_ indexPath: IndexPath, scrollToSelection: Bool) {
private func setSelectedIndexPath(indexPath: NSIndexPath, scrollToSelection: Bool) {
self._lastSelectedIndexPath = indexPath
self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true)
@@ -197,7 +132,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
@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 {
@@ -207,14 +142,14 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
self.selectModelVersion(self.models[index])
}
private func selectModelVersion(_ model: ModelMetadata) {
private func selectModelVersion(model: ModelMetadata) {
if self.dataStack?.modelVersion == model.version {
return
}
self.set(dataStack: nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
self.setDataStack(nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
let dataStack = DataStack(
modelName: "MigrationDemo",
@@ -231,17 +166,18 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
return
}
guard case .success = result else {
guard case .Success = result else {
self.setEnabled(true)
return
}
self.set(dataStack: dataStack, model: model, scrollToSelection: true)
self.setDataStack(dataStack, model: model, scrollToSelection: true)
let count = dataStack.queryValue(
From(model.entityType),
Select<Int>(.count(#keyPath(OrganismV1.dna))))!
Select<Int>(.Count("dna"))
)
if count > 0 {
self.setEnabled(true)
@@ -282,39 +218,39 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
}
}
private func setEnabled(_ enabled: Bool) {
private func setEnabled(enabled: Bool) {
UIView.animate(
withDuration: 0.2,
UIView.animateWithDuration(
0.2,
delay: 0,
options: .beginFromCurrentState,
options: .BeginFromCurrentState,
animations: { () -> Void in
let navigationItem = self.navigationItem
navigationItem.leftBarButtonItem?.isEnabled = enabled
navigationItem.rightBarButtonItem?.isEnabled = enabled
navigationItem.leftBarButtonItem?.enabled = enabled
navigationItem.rightBarButtonItem?.enabled = enabled
navigationItem.hidesBackButton = !enabled
self.segmentedControl?.isEnabled = enabled
self.segmentedControl?.enabled = enabled
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.isUserInteractionEnabled = enabled
tableView.userInteractionEnabled = enabled
}
},
completion: nil
)
}
private func set(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
private func setDataStack(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
if let dataStack = dataStack, let model = model {
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.index(of: model.version)!
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.indexOf(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
@@ -322,7 +258,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
if listMonitor.numberOfObjectsInSection(0) > 0 {
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: true)
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: true)
}
}
}
@@ -336,14 +272,14 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false)
}
private func reloadTableHeaderWithProgress(_ progress: Progress) {
private func reloadTableHeaderWithProgress(progress: NSProgress) {
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: Bool, scrollToSelection: Bool, animated: Bool) {
private func updateDisplay(reloadData reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
var lines = [String]()
var organismType = ""
@@ -351,14 +287,14 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
for property in organism.entity.properties {
let value = organism.value(forKey: property.name) ?? NSNull()
let value: AnyObject = organism.valueForKey(property.name) ?? NSNull()
lines.append("\(property.name): \(value)")
}
organismType = organism.entity.managedObjectClassName
}
self.titleLabel?.text = organismType
self.organismLabel?.text = lines.joined(separator: "\n")
self.organismLabel?.text = lines.joinWithSeparator("\n")
self.progressView?.progress = 0
self.headerContainer?.setNeedsLayout()
@@ -375,13 +311,87 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
tableView.layoutIfNeeded()
if let indexPath = self.lastSelectedIndexPath,
indexPath.row < tableView.numberOfRows(inSection: 0) {
if let indexPath = self.lastSelectedIndexPath where indexPath.row < tableView.numberOfRowsInSection(0) {
tableView.selectRow(at: indexPath,
tableView.selectRowAtIndexPath(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,20 +10,14 @@ import CoreData
class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
override func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager) throws {
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
try super.createDestinationInstancesForSourceInstance(sInstance, entityMapping: mapping, manager: manager)
for dInstance in manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]) {
for dInstance in manager.destinationInstancesForEntityMappingNamed(mapping.name, sourceInstances: [sInstance]) {
dInstance.setValue(
false,
forKey: #keyPath(OrganismV3.hasVertebrae)
)
dInstance.setValue(
sInstance.value(forKey: #keyPath(OrganismV2.numberOfFlippers)),
forKey: #keyPath(OrganismV3.numberOfLimbs)
)
dInstance.setValue(false, forKey: "hasVertebrae")
dInstance.setValue(sInstance.valueForKey("numberOfFlippers"), forKey: "numberOfLimbs")
}
}
}

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV1" 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"/>
<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"/>
</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 type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV2" 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"/>
<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"/>
</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 type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV3" 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"/>
<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"/>
</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.self)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount.self)) ?? []
Static.facebookStack.fetchAll(From(UserAccount)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount)) ?? []
]
// MARK: UIViewController
override func viewWillAppear(_ animated: Bool) {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
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])
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
self.updateDetailsWithAccount(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.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
// MARK: UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
override func numberOfSectionsInTableView(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, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
let cell = tableView.dequeueReusableCellWithIdentifier("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, didSelectRowAt indexPath: IndexPath) {
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let account = self.accounts[indexPath.section][indexPath.row]
self.updateDetails(account: account)
self.updateDetailsWithAccount(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 updateDetails(account: UserAccount) {
private func updateDetailsWithAccount(account: UserAccount) {
self.accountTypeLabel?.text = account.accountType
self.nameLabel?.text = account.name

View File

@@ -11,6 +11,7 @@ import CoreLocation
import MapKit
import AddressBookUI
import CoreStore
import GCDKit
private struct Static {
@@ -21,21 +22,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!)
@@ -70,33 +71,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.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
self.presentViewController(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.setCenter(place.coordinate, animated: false)
mapView.setCenterCoordinate(place.coordinate, animated: false)
mapView.selectAnnotation(place, animated: false)
}
}
@@ -104,14 +105,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
// MARK: MKMapViewDelegate
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MKAnnotationView"
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView.isEnabled = true
annotationView.enabled = true
annotationView.canShowCallout = true
annotationView.animatesDrop = true
}
@@ -126,28 +127,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.setCenter(object.coordinate, animated: true)
mapView.setCenterCoordinate(object.coordinate, animated: true)
mapView.selectAnnotation(object, animated: true)
if changedPersistentKeys.contains(#keyPath(Place.latitude)) || changedPersistentKeys.contains(#keyPath(Place.longitude)) {
if changedPersistentKeys.contains("latitude") || changedPersistentKeys.contains("longitude") {
self.geocode(place: object)
self.geocodePlace(object)
}
}
}
func objectMonitor(_ monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
func objectMonitor(monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
// none
}
@@ -159,15 +160,13 @@ 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,
gesture.state == .began {
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began {
let coordinate = mapView.convert(
gesture.location(in: mapView),
toCoordinateFrom: mapView
let coordinate = mapView.convertPoint(
gesture.locationInView(mapView),
toCoordinateFromView: mapView
)
CoreStore.beginAsynchronous { (transaction) -> Void in
@@ -178,17 +177,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 geocode(place: Place) {
func geocodePlace(place: Place) {
let transaction = CoreStore.beginUnsafe()

View File

@@ -36,12 +36,11 @@ class BaseTestCase: XCTestCase {
// MARK: Internal
@nonobjc
@discardableResult
func prepareStack<T>(configurations: [String?] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T {
func prepareStack<T>(configurations configurations: [String?] = [nil], @noescape _ closure: (dataStack: DataStack) -> T) -> T {
let stack = DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self))
bundle: NSBundle(forClass: self.dynamicType)
)
do {
@@ -50,10 +49,10 @@ class BaseTestCase: XCTestCase {
try stack.addStorageAndWait(
SQLiteStore(
fileURL: SQLiteStore.defaultRootDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathComponent("\(type(of: self))_\(($0 ?? "-null-")).sqlite"),
.URLByAppendingPathComponent(NSUUID().UUIDString)
.URLByAppendingPathComponent("\(self.dynamicType)_\(($0 ?? "-null-")).sqlite"),
configuration: $0,
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
)
}
@@ -62,11 +61,11 @@ class BaseTestCase: XCTestCase {
XCTFail(error.coreStoreDumpString)
}
return closure(stack)
return closure(dataStack: stack)
}
@nonobjc
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () -> T) -> T {
func expectLogger<T>(expectations: [TestLogger.Expectation], @noescape closure: () -> T) -> T {
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer {
@@ -78,18 +77,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.expectation(description: "Logger Expectation: \(expectation)")
testExpectations[expectation] = self.expectationWithDescription("Logger Expectation: \(expectation)")
}
return testExpectations
}
@@ -97,13 +96,13 @@ class BaseTestCase: XCTestCase {
@nonobjc
func checkExpectationsImmediately() {
self.waitForExpectations(timeout: 0, handler: { _ in })
self.waitForExpectationsWithTimeout(0, handler: nil)
}
@nonobjc
func waitAndCheckExpectations() {
self.waitForExpectations(timeout: 10, handler: {_ in })
self.waitForExpectationsWithTimeout(10, handler: nil)
}
// MARK: XCTestCase
@@ -127,7 +126,7 @@ class BaseTestCase: XCTestCase {
private func deleteStores() {
_ = try? FileManager.default.removeItem(at: SQLiteStore.defaultRootDirectory)
_ = try? NSFileManager.defaultManager().removeItemAtURL(SQLiteStore.defaultRootDirectory)
}
}
@@ -138,11 +137,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]) {
@@ -153,35 +152,33 @@ class TestLogger: CoreStoreLogger {
// MARK: CoreStoreLogger
var enableObjectConcurrencyDebugging: Bool = true
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(level 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: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.logError)
self.fulfill(.LogError)
}
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> 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)
}
@@ -189,7 +186,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: DateFormatter = {
let dateFormatter: NSDateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.timeZone = NSTimeZone(name: "UTC")
formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
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.enumerated() {
for (configurationIndex, configuration) in configurations.enumerate() {
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(value: (configurationOrdinal * 100) + idIndex)
object.testEntityID = NSNumber(integer: (configurationOrdinal * 100) + idIndex)
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.testNumber = idIndex
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
object.testString = string
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
}
}
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(value: (configurationOrdinal * 200) + idIndex)
object.testEntityID = NSNumber(integer: (configurationOrdinal * 200) + idIndex)
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.testNumber = idIndex
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
object.testBoolean = (idIndex % 2) == 1
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
object.testString = string
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
}
}
}
_ = transaction.commitAndWait()
transaction.commitAndWait()
}
}
}

View File

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

@@ -1,94 +0,0 @@
//
// 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 as NSDictionary, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.UnknownError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.UnknownError.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let dummyURL = NSURL(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.differentStorageExistsAtURL.rawValue)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.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.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
let model = NSManagedObjectModel.fromBundle(Bundle(for: type(of: self)), modelName: "Model")
let model = NSManagedObjectModel.fromBundle(NSBundle(forClass: self.dynamicType), 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 as NSDictionary, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let dummyURL = NSURL(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 as NSDictionary, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo, userInfo)
}
@objc
@@ -144,12 +144,12 @@ final class ErrorTests: XCTestCase {
userInfo: [
"key1": "value1",
"key2": 2,
"key3": Date()
"key3": NSDate()
]
)
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 as NSDictionary, userInfo)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.InternalError.rawValue)
XCTAssertEqual(objcError.userInfo, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.InternalError.rawValue)
XCTAssertEqual(objcError2.userInfo, 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 = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -115,102 +115,102 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -225,99 +225,99 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity2>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -332,96 +332,96 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
do {
let from = From<TestEntity2>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = NSFetchRequest()
let storesFound = self.expectLogger([.LogWarning]) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.affectedStores)
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
}

View File

@@ -66,10 +66,10 @@ final class GroupByTests: BaseTestCase {
self.prepareStack { (dataStack) in
let groupBy = GroupBy(#keyPath(TestEntity1.testString))
let groupBy = GroupBy("testString")
let request = CoreStoreFetchRequest()
_ = From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
let request = NSFetchRequest()
_ = 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.self))
XCTAssertEqual(into, Into(TestEntity1))
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(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
)
monitor.addObserver(observer)
@@ -54,13 +54,13 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -68,14 +68,14 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let didInsertSectionExpectation = self.expectation(
forNotification: "listMonitor:didInsertSection:toSectionIndex:",
let didInsertSectionExpectation = self.expectationForNotification(
"listMonitor:didInsertSection:toSectionIndex:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
(note.userInfo ?? [:]),
[
"sectionInfo": monitor.sectionInfoAtIndex(0),
"sectionIndex": 0
@@ -88,8 +88,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1
}
)
let didInsertObjectExpectation = self.expectation(
forNotification: "listMonitor:didInsertObject:toIndexPath:",
let didInsertObjectExpectation = self.expectationForNotification(
"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?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["indexPath", "object"]
)
@@ -107,12 +107,12 @@ class ListObserverTests: BaseTestDataTestCase {
XCTAssertEqual(indexPath?.row, 0)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 1))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
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")!)
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!)
defer {
events += 1
@@ -120,12 +120,12 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2
}
)
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -133,26 +133,26 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let saveExpectation = self.expectation(description: "save")
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
let object = transaction.create(Into<TestEntity1>())
object.testBoolean = NSNumber(value: true)
object.testNumber = NSNumber(value: 1)
let object = transaction.create(Into(TestEntity1))
object.testBoolean = NSNumber(bool: true)
object.testNumber = NSNumber(integer: 1)
object.testDecimal = NSDecimalNumber(string: "1")
object.testString = "nil:TestEntity1:1"
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
object.testData = ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("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(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
)
monitor.addObserver(observer)
@@ -185,13 +185,13 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -201,8 +201,8 @@ class ListObserverTests: BaseTestDataTestCase {
)
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didUpdateObject:atIndexPath:",
let didUpdateObjectExpectation = self.expectationForNotification(
"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?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["indexPath", "object"]
)
@@ -220,27 +220,27 @@ class ListObserverTests: BaseTestDataTestCase {
switch object?.testEntityID {
case NSNumber(value: 101)?:
case NSNumber(integer: 101)?:
XCTAssertEqual(indexPath?.section, 1)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 11))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
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")!)
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!)
case NSNumber(value: 102)?:
case NSNumber(integer: 102)?:
XCTAssertEqual(indexPath?.section, 0)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: false))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 22))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
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")!)
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-22T00:00:00Z")!)
default:
XCTFail()
@@ -253,13 +253,13 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
}
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 3)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -267,32 +267,32 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let saveExpectation = self.expectation(description: "save")
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) {
object.testNumber = NSNumber(value: 11)
object.testNumber = NSNumber(integer: 11)
object.testDecimal = NSDecimalNumber(string: "11")
object.testString = "nil:TestEntity1:11"
object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
object.testData = ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!
}
else {
XCTFail()
}
if let object = transaction.fetchOne(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
From(TestEntity1),
Where("testEntityID", isEqualTo: 102)) {
object.testNumber = NSNumber(value: 22)
object.testNumber = NSNumber(integer: 22)
object.testDecimal = NSDecimalNumber(string: "22")
object.testString = "nil:TestEntity1:22"
object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
object.testData = ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
object.testDate = self.dateFormatter.dateFromString("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(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
)
monitor.addObserver(observer)
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -346,8 +346,8 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let didMoveObjectExpectation = self.expectation(
forNotification: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
let didMoveObjectExpectation = self.expectationForNotification(
"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?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["fromIndexPath", "toIndexPath", "object"]
)
@@ -369,8 +369,8 @@ class ListObserverTests: BaseTestDataTestCase {
XCTAssertEqual(toIndexPath?.row, 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
defer {
@@ -379,13 +379,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 1
}
)
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 2)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -393,14 +393,14 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 2
}
)
let saveExpectation = self.expectation(description: "save")
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
From(TestEntity1),
Where("testEntityID", isEqualTo: 102)) {
object.testBoolean = NSNumber(value: true)
object.testBoolean = NSNumber(bool: 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(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
From(TestEntity1),
SectionBy("testBoolean"),
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
)
monitor.addObserver(observer)
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
let willChangeExpectation = self.expectationForNotification(
"listMonitorWillChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -456,8 +456,8 @@ class ListObserverTests: BaseTestDataTestCase {
)
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didDeleteObject:fromIndexPath:",
let didUpdateObjectExpectation = self.expectationForNotification(
"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?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["indexPath", "object"]
)
@@ -476,7 +476,7 @@ class ListObserverTests: BaseTestDataTestCase {
XCTAssert(indexPath?.row == 0 || indexPath?.row == 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.isDeleted, true)
XCTAssertEqual(object?.deleted, true)
defer {
@@ -486,8 +486,8 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
}
let didDeleteSectionExpectation = self.expectation(
forNotification: "listMonitor:didDeleteSection:fromSectionIndex:",
let didDeleteSectionExpectation = self.expectationForNotification(
"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?.keys.map({ $0 as! String }) ?? []),
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
["sectionInfo", "sectionIndex"]
)
let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
let sectionInfo = userInfo?["sectionInfo"]
XCTAssertNotNil(sectionInfo)
XCTAssertEqual(sectionInfo?.name, "0")
let sectionIndex = userInfo?["sectionIndex"]
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(integer: 0))
defer {
@@ -514,13 +514,13 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 3
}
)
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
let didChangeExpectation = self.expectationForNotification(
"listMonitorDidChange:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 4)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
defer {
events += 1
@@ -528,22 +528,22 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 4
}
)
let saveExpectation = self.expectation(description: "save")
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
transaction.deleteAll(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
From(TestEntity1),
Where("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>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillChange:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorWillChange:",
object: self,
userInfo: [:]
)
}
func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
func listMonitorDidChange(monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidChange:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorDidChange:",
object: self,
userInfo: [:]
)
}
func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
func listMonitorWillRefetch(monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorWillRefetch:",
object: self,
userInfo: [:]
)
}
func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
func listMonitorDidRefetch(monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitorDidRefetch:",
object: self,
userInfo: [:]
)
@@ -601,10 +601,10 @@ class TestListObserver: ListSectionObserver {
// MARK: ListObjectObserver
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"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: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"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: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"listMonitor:didUpdateObject:atIndexPath:",
object: self,
userInfo: [
"object": object,
@@ -638,10 +638,10 @@ class TestListObserver: ListSectionObserver {
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
func listMonitor(monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"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) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"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) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"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(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) else {
XCTFail()
return
@@ -58,14 +58,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0
let willUpdateExpectation = self.expectation(
forNotification: "objectMonitor:willUpdateObject:",
let willUpdateExpectation = self.expectationForNotification(
"objectMonitor:willUpdateObject:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
(note.userInfo ?? [:]),
["object": object] as NSDictionary
)
defer {
@@ -75,26 +75,26 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let didUpdateExpectation = self.expectation(
forNotification: "objectMonitor:didUpdateObject:changedPersistentKeys:",
let didUpdateExpectation = self.expectationForNotification(
"objectMonitor:didUpdateObject:changedPersistentKeys:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
(note.userInfo ?? [:]),
[
"object": object,
"changedPersistentKeys": Set(
[
#keyPath(TestEntity1.testNumber),
#keyPath(TestEntity1.testString)
"testNumber",
"testString"
]
)
] as NSDictionary
)
let object = note.userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testNumber, NSNumber(value: 10))
XCTAssertEqual(object?.testNumber, NSNumber(integer: 10))
XCTAssertEqual(object?.testString, "nil:TestEntity1:10")
defer {
@@ -104,7 +104,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 1
}
)
let saveExpectation = self.expectation(description: "save")
let saveExpectation = self.expectationWithDescription("save")
stack.beginAsynchronous { (transaction) in
guard let object = transaction.edit(object) else {
@@ -112,18 +112,18 @@ class ObjectObserverTests: BaseTestDataTestCase {
XCTFail()
return
}
object.testNumber = NSNumber(value: 10)
object.testNumber = NSNumber(integer: 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(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
From(TestEntity1),
Where("testEntityID", isEqualTo: 101)) else {
XCTFail()
return
@@ -155,14 +155,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0
let didDeleteExpectation = self.expectation(
forNotification: "objectMonitor:didDeleteObject:",
let didDeleteExpectation = self.expectationForNotification(
"objectMonitor:didDeleteObject:",
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
(note.userInfo ?? [:]),
["object": object] as NSDictionary
)
defer {
@@ -172,7 +172,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
return events == 0
}
)
let saveExpectation = self.expectation(description: "save")
let saveExpectation = self.expectationWithDescription("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) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "objectMonitor:willUpdateObject:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"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>) {
NotificationCenter.default.post(
name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"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) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "objectMonitor:didDeleteObject:"),
NSNotificationCenter.defaultCenter().postNotificationName(
"objectMonitor:didDeleteObject:",
object: self,
userInfo: [
"object": object

View File

@@ -39,7 +39,7 @@ final class OrderByTests: XCTestCase {
do {
let orderBy = OrderBy()
XCTAssertEqual(orderBy, OrderBy([NSSortDescriptor]()))
XCTAssertEqual(orderBy, OrderBy([] as [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 = CoreStoreFetchRequest()
let orderBy = OrderBy(.Ascending("key"))
let request = NSFetchRequest()
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("key"), "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key")
}
do {
let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } }
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(sectionName: 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,24 +29,20 @@ import CoreStore
// MARK: - SetupTests
class SetupTests: BaseTestDataTestCase {
class SetupTests: BaseTestCase {
@objc
dynamic func test_ThatDataStacks_ConfigureCorrectly() {
do {
let model = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!
let model = NSManagedObjectModel.mergedModelFromBundles([NSBundle(forClass: self.dynamicType)])!
let stack = DataStack(model: model, migrationChain: nil)
XCTAssertEqual(stack.coordinator.managedObjectModel, model)
XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator)
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)
XCTAssertNil(stack.rootSavingContext.parentContext)
XCTAssertEqual(stack.mainContext.parentContext, stack.rootSavingContext)
XCTAssertEqual(stack.model, model)
XCTAssertTrue(stack.migrationChain.valid)
XCTAssertTrue(stack.migrationChain.empty)
@@ -60,11 +56,11 @@ class SetupTests: BaseTestDataTestCase {
let migrationChain: MigrationChain = ["version1", "version2", "version3"]
let stack = self.expectLogger([.logWarning]) {
let stack = self.expectLogger([.LogWarning]) {
DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self)),
bundle: NSBundle(forClass: self.dynamicType),
migrationChain: migrationChain
)
}
@@ -81,7 +77,7 @@ class SetupTests: BaseTestDataTestCase {
let stack = DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self))
bundle: NSBundle(forClass: self.dynamicType)
)
do {
@@ -136,7 +132,7 @@ class SetupTests: BaseTestDataTestCase {
let stack = DataStack(
modelName: "Model",
bundle: Bundle(for: type(of: self))
bundle: NSBundle(forClass: self.dynamicType)
)
do {
@@ -158,7 +154,7 @@ class SetupTests: BaseTestDataTestCase {
let sqliteStore = SQLiteStore(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
do {
@@ -177,7 +173,7 @@ class SetupTests: BaseTestDataTestCase {
let sqliteStore = SQLiteStore(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
do {
@@ -193,72 +189,16 @@ class SetupTests: BaseTestDataTestCase {
}
}
@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: Bundle(for: type(of: self))
bundle: NSBundle(forClass: self.dynamicType)
)
do {
let sqliteStore = LegacySQLiteStore()
let sqliteStore = SQLiteStore()
do {
try stack.addStorageAndWait(sqliteStore)
@@ -273,10 +213,10 @@ class SetupTests: BaseTestDataTestCase {
}
do {
let sqliteStore = LegacySQLiteStore(
let sqliteStore = SQLiteStore(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
do {
@@ -292,10 +232,10 @@ class SetupTests: BaseTestDataTestCase {
}
do {
let sqliteStore = LegacySQLiteStore(
let sqliteStore = SQLiteStore(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
do {
@@ -310,60 +250,4 @@ class SetupTests: BaseTestDataTestCase {
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(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertEqual(store.dynamicType.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(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertEqual(store.dynamicType.storeType, NSInMemoryStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertNil(store.storeOptions)
}
@@ -55,23 +55,24 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatSQLiteStoreDefaultDirectories_AreCorrect() {
#if os(tvOS)
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
#else
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
#endif
let defaultSystemDirectory = FileManager.default
.urls(for: systemDirectorySearchPath, in: .userDomainMask).first!
let defaultSystemDirectory = NSFileManager
.defaultManager()
.URLsForDirectory(systemDirectorySearchPath, inDomains: .UserDomainMask).first!
let defaultRootDirectory = defaultSystemDirectory.appendingPathComponent(
Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
let defaultRootDirectory = defaultSystemDirectory.URLByAppendingPathComponent(
NSBundle.mainBundle().bundleIdentifier ?? "com.CoreStore.DataStack",
isDirectory: true
)
let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData"
let defaultFileURL = defaultRootDirectory
.appendingPathComponent(applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
.URLByAppendingPathComponent(applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
XCTAssertEqual(SQLiteStore.defaultRootDirectory, defaultRootDirectory)
XCTAssertEqual(SQLiteStore.defaultFileURL, defaultFileURL)
@@ -81,76 +82,77 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatDefaultSQLiteStores_ConfigureCorrectly() {
let store = SQLiteStore()
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL)
XCTAssertEqual(store.mappingModelBundles, Bundle.allBundles)
XCTAssertEqual(store.localStorageOptions, .none)
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles())
XCTAssertEqual(store.localStorageOptions, [.None])
}
@objc
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(NSUUID().uuidString, isDirectory: false)!
.appendingPathExtension("db")
let bundles = [Bundle(for: type(of: self))]
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false)
.URLByAppendingPathExtension("db")
let bundles = [NSBundle(forClass: self.dynamicType)]
let store = SQLiteStore(
fileURL: fileURL,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions, [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 = UUID().uuidString + ".db"
let bundles = [Bundle(for: type(of: self))]
let fileName = NSUUID().UUIDString + ".db"
let bundles = [NSBundle(forClass: self.dynamicType)]
let store = SQLiteStore(
fileName: fileName,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.URLByDeletingLastPathComponent, 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 = FileManager.SearchPathDirectory.cachesDirectory
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
#else
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
#endif
let legacyDefaultRootDirectory = FileManager.default.urls(
for: systemDirectorySearchPath,
in: .userDomainMask).first!
let legacyDefaultRootDirectory = NSFileManager.defaultManager().URLsForDirectory(
systemDirectorySearchPath,
inDomains: .UserDomainMask
).first!
let legacyDefaultFileURL = legacyDefaultRootDirectory
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
.URLByAppendingPathComponent(DataStack.applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
XCTAssertEqual(LegacySQLiteStore.defaultRootDirectory, legacyDefaultRootDirectory)
XCTAssertEqual(LegacySQLiteStore.defaultFileURL, legacyDefaultFileURL)
@@ -160,57 +162,57 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatDefaultLegacySQLiteStores_ConfigureCorrectly() {
let store = LegacySQLiteStore()
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, LegacySQLiteStore.defaultFileURL)
XCTAssertEqual(store.mappingModelBundles, Bundle.allBundles)
XCTAssertEqual(store.localStorageOptions, .none)
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles())
XCTAssertEqual(store.localStorageOptions, [.None])
}
@objc
dynamic func test_ThatFileURLLegacySQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(NSUUID().uuidString, isDirectory: false)!
.appendingPathExtension("db")
let bundles = [Bundle(for: type(of: self))]
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false)
.URLByAppendingPathExtension("db")
let bundles = [NSBundle(forClass: self.dynamicType)]
let store = LegacySQLiteStore(
fileURL: fileURL,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions, [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 = UUID().uuidString + ".db"
let bundles = [Bundle(for: type(of: self))]
let fileName = NSUUID().UUIDString + ".db"
let bundles = [NSBundle(forClass: self.dynamicType)]
let store = LegacySQLiteStore(
fileName: fileName,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .recreateStoreOnModelMismatch
localStorageOptions: .RecreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), LegacySQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.URLByDeletingLastPathComponent, 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: Date?
@NSManaged var testDate: NSDate?
@NSManaged var testBoolean: NSNumber?
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: Data?
@NSManaged var testData: NSData?
@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: Date?
@NSManaged var testDate: NSDate?
@NSManaged var testBoolean: NSNumber?
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: Data?
@NSManaged var testData: NSData?
@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 = CoreStoreFetchRequest()
let request = NSFetchRequest()
tweak.applyToFetchRequest(request)
XCTAssertEqual(request.fetchOffset, 100)
XCTAssertEqual(request.fetchLimit, 200)

View File

@@ -87,211 +87,6 @@ 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() {
@@ -303,7 +98,7 @@ final class WhereTests: XCTestCase {
let notWhere = !whereClause1
let notPredicate = NSCompoundPredicate(
type: .not,
type: .NotPredicateType,
subpredicates: [whereClause1.predicate]
)
XCTAssertEqual(notWhere.predicate, notPredicate)
@@ -313,10 +108,10 @@ final class WhereTests: XCTestCase {
let andWhere = whereClause1 && whereClause2 && whereClause3
let andPredicate = NSCompoundPredicate(
type: .and,
type: .AndPredicateType,
subpredicates: [
NSCompoundPredicate(
type: .and,
type: .AndPredicateType,
subpredicates: [whereClause1.predicate, whereClause2.predicate]
),
whereClause3.predicate
@@ -329,10 +124,10 @@ final class WhereTests: XCTestCase {
let orWhere = whereClause1 || whereClause2 || whereClause3
let orPredicate = NSCompoundPredicate(
type: .or,
type: .OrPredicateType,
subpredicates: [
NSCompoundPredicate(
type: .or,
type: .OrPredicateType,
subpredicates: [whereClause1.predicate, whereClause2.predicate]
),
whereClause3.predicate
@@ -347,7 +142,7 @@ final class WhereTests: XCTestCase {
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where("key", isEqualTo: "value")
let request = CoreStoreFetchRequest()
let request = NSFetchRequest()
whereClause.applyToFetchRequest(request)
XCTAssertNotNil(request.predicate)
XCTAssertEqual(request.predicate, whereClause.predicate)

View File

@@ -41,5 +41,11 @@ 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,10 +17,11 @@ 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!
* **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).
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).
## Why use CoreStore?
@@ -39,10 +40,12 @@ 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 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.
- **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.
*Have ideas that may benefit other Core Data users? [Feature Request](https://github.com/JohnEstropia/CoreStore/issues)s are welcome!*
@@ -85,7 +88,6 @@ 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)
@@ -116,14 +118,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)
}
}
}
@@ -131,15 +133,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
}
@@ -149,8 +151,8 @@ let people = CoreStore.fetchAll(
Querying values:
```swift
let maxAge = CoreStore.queryValue(
From<MyPersonEntity>(),
Select<Int>(.maximum("age"))
From(MyPersonEntity),
Select<Int>(.Maximum("age"))
)
```
@@ -204,13 +206,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)"
}
}
@@ -229,7 +231,7 @@ class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
try self.dataStack.addStorageAndWait(SQLiteStore.self)
try self.dataStack.addStorageAndWait(SQLiteStore)
}
catch { // ...
}
@@ -247,7 +249,7 @@ class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
try CoreStore.addStorageAndWait(SQLiteStore.self)
try CoreStore.addStorageAndWait(SQLiteStore)
}
catch { // ...
}
@@ -272,7 +274,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.self)
try CoreStore.addStorageAndWait(InMemoryStore)
```
### Local Store
@@ -283,7 +285,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: { /* ... */ }
)
@@ -292,7 +294,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.self)
try CoreStore.addStorageAndWait(SQLiteStore)
```
or
```swift
@@ -305,8 +307,8 @@ public protocol LocalStorage: StorageInterface {
var fileURL: NSURL { get }
var mappingModelBundles: [NSBundle] { get }
var localStorageOptions: LocalStorageOptions { get }
func dictionary(forOptions: LocalStorageOptions) -> [String: AnyObject]?
func eraseStorageAndWait(metadata: [String: Any], soureModelHint: NSManagedObjectModel?) throws
func storeOptionsForOptions(options: LocalStorageOptions) -> [String: AnyObject]?
func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws
}
```
If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`.
@@ -322,7 +324,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
@@ -332,8 +334,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): // ...
}
}
)
@@ -363,8 +365,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): // ...
}
}
)
@@ -373,12 +375,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
)
}
```
@@ -386,16 +388,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: Progress? = try dataStack.addStorage(
let migrationProgress: NSProgress? = 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)")
}
}
@@ -403,7 +405,7 @@ let migrationProgress: Progress? = try dataStack.addStorage(
```
The `completion` block reports a `SetupResult` that indicates success or failure.
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*:
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*:
```swift
migrationProgress?.setProgressHandler { [weak self] (progress) -> Void in
self?.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
@@ -553,7 +555,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
@@ -576,7 +578,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()
@@ -586,7 +588,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
@@ -648,7 +650,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()
@@ -686,7 +688,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)!)
@@ -708,7 +710,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()
@@ -735,8 +737,8 @@ You can even use external types from popular 3rd-party JSON libraries ([SwiftyJS
```swift
public protocol ImportableObject: class {
typealias ImportSource
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
}
```
First, set `ImportSource` to the expected type of the data source:
@@ -748,15 +750,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 `didInsert(from:in:)` method of the `ImportableObject` protocol:
The actual extraction and assignment of values should be implemented in the `didInsertFromImportSource(...)` method of the `ImportableObject` protocol:
```swift
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws {
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
self.name = source["name"] as? NSString
self.age = source["age"] as? NSNumber
// ...
@@ -767,17 +769,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 `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.
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.
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:)`:
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(...)`:
```swift
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws {
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
self.name = source["name"] as? NSString
self.age = source["age"] as? NSNumber
// ...
@@ -792,7 +794,7 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
let jsonArray: [[String: AnyObject]] = // ...
do {
try transaction.importObjects(
Into<MyPersonEntity>(),
Into(MyPersonEntity),
sourceArray: jsonArray
)
}
@@ -815,11 +817,11 @@ public protocol ImportableUniqueObject: ImportableObject {
static var uniqueIDKeyPath: String { get }
var uniqueIDValue: UniqueIDType { get set }
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
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
}
```
Notice that it has the same insert methods as `ImportableObject`, with additional methods for updates and for specifying the unique ID:
@@ -831,18 +833,18 @@ var uniqueIDValue: NSNumber {
get { return self.personID }
set { self.personID = newValue }
}
class func uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> NSNumber? {
class func uniqueIDFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> NSNumber? {
return source["id"] as? NSNumber
}
```
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.
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.
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
)
// ...
@@ -854,14 +856,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
`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.
`shouldInsertFromImportSource(...)` and `shouldUpdateFromImportSource(...)`, or to cancel all objects by `throw`ing an error from the `uniqueIDFromImportSource(...)`, `didInsertFromImportSource(...)` or `updateFromImportSource(...)` methods.
## Fetching and Querying
@@ -878,10 +880,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
@@ -910,11 +912,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
)
```
@@ -922,14 +924,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")
)
```
@@ -940,20 +942,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
)
```
@@ -963,9 +965,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
@@ -994,7 +996,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")
)
@@ -1019,29 +1021,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")
)
```
@@ -1061,8 +1063,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:
@@ -1081,8 +1083,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:
@@ -1104,8 +1106,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")
)
```
@@ -1151,7 +1153,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" />
@@ -1230,9 +1232,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
}
@@ -1251,10 +1253,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
}
@@ -1265,11 +1267,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:
@@ -1298,7 +1300,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.self)
try CoreStore.addStorageAndWait(SQLiteStore)
</pre></td>
<td><pre lang=objc>
NSError *error
@@ -1311,8 +1313,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)
}
}
}
@@ -1409,7 +1411,13 @@ NSArray<MYPerson *> *objects =
CSSortAscending(CSKeyPath(MYPerson, firstName)), nil)]];
```
To use these syntax sugars, include *CoreStoreBridge.h* in your Objective-C source files.
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" />
# Roadmap
@@ -1421,14 +1429,14 @@ To use these syntax sugars, include *CoreStoreBridge.h* in your Objective-C sour
# Installation
- Requires:
- iOS 8 SDK and above
- Swift 3.0.1 (Xcode 8.2)
- iOS 7 SDK and above
- Swift 2.2 (Xcode 7.3)
- Dependencies:
- *None*
- [GCDKit](https://github.com/JohnEstropia/GCDKit)
- 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
### Install with CocoaPods (iOS 7 not supported)
```
pod 'CoreStore'
```
@@ -1437,7 +1445,8 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
### Install with Carthage
In your `Cartfile`, add
```
github "JohnEstropia/CoreStore" >= 3.0.0
github "JohnEstropia/CoreStore" >= 2.0.0
github "JohnEstropia/GCDKit" >= 1.2.5
```
and run
```
@@ -1450,7 +1459,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:
#### To install as a framework (iOS 7 not supported):
Drag and drop **CoreStore.xcodeproj** to your project.
#### To include directly in your app module:
@@ -1461,30 +1470,16 @@ 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,26 +26,28 @@
import Foundation
import CoreData
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - DataStack
// MARK: - NSFetchedResultsController
public extension DataStack {
public extension NSFetchedResultsController {
/**
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`.
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- 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 the `DataStack`
- returns: an `NSFetchedResultsController` that observes a `DataStack`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
return createFRC(
fromContext: self.mainContext,
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
@@ -54,18 +56,19 @@ 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.
- 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 the `DataStack`
- returns: an `NSFetchedResultsController` that observes a `DataStack`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return createFRC(
fromContext: self.mainContext,
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
@@ -73,18 +76,19 @@ public extension DataStack {
}
/**
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`.
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- 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 the `DataStack`
- returns: an `NSFetchedResultsController` that observes a `DataStack`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
return createFRC(
fromContext: self.mainContext,
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
@@ -92,44 +96,40 @@ public extension DataStack {
}
/**
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`.
Utility for creating an `NSFetchedResultsController` from a `DataStack`. This is useful when an `NSFetchedResultsController` is preferred over the overhead of `ListMonitor`s abstraction.
- 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 the `DataStack`
- returns: an `NSFetchedResultsController` that observes a `DataStack`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(forDataStack dataStack: DataStack, _ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(dataStack: DataStack, _ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return createFRC(
fromContext: self.mainContext,
return self.createFromContext(
dataStack.mainContext,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
)
}
}
// 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`.
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 the `UnsafeDataTransaction`
- returns: an `NSFetchedResultsController` that observes an `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
return createFRC(
fromContext: self.context,
return self.createFromContext(
transaction.context,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
@@ -137,19 +137,20 @@ 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`.
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 the `UnsafeDataTransaction`
- returns: an `NSFetchedResultsController` that observes an `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ sectionBy: SectionBy, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return createFRC(
fromContext: self.context,
return self.createFromContext(
transaction.context,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: sectionBy,
fetchClauses: fetchClauses
@@ -157,18 +158,19 @@ 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`.
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 the `UnsafeDataTransaction`
- returns: an `NSFetchedResultsController` that observes an `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ fetchClauses: FetchClause...) -> NSFetchedResultsController {
return createFRC(
fromContext: self.context,
return self.createFromContext(
transaction.context,
fetchRequest: CoreStoreFetchRequest(),
from: from,
sectionBy: nil,
fetchClauses: fetchClauses
@@ -176,47 +178,46 @@ 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`.
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 the `UnsafeDataTransaction`
*/
@nonobjc
public func createFetchedResultsController<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController<T> {
public static func createFor<T: NSManagedObject>(transaction: UnsafeDataTransaction, _ from: From<T>, _ fetchClauses: [FetchClause]) -> NSFetchedResultsController {
return createFRC(
fromContext: self.context,
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: - 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,52 +31,6 @@ 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.
@@ -84,33 +38,14 @@ public extension NSManagedObject {
- returns: the primitive value for the KVC key
*/
@nonobjc
public func accessValueForKVCKey(_ KVCKey: KeyPath) -> Any? {
@warn_unused_result
public func accessValueForKVCKey(KVCKey: KeyPath) -> AnyObject? {
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 {
self.willAccessValueForKey(KVCKey)
let primitiveValue: AnyObject? = self.primitiveValueForKey(KVCKey)
self.didAccessValueForKey(KVCKey)
self.willAccessValue(forKey: KVCKey)
defer {
self.didAccessValue(forKey: KVCKey)
}
return try didAccessPrimitiveValue(self.primitiveValue(forKey: KVCKey))
return primitiveValue
}
/**
@@ -120,34 +55,11 @@ public extension NSManagedObject {
- parameter KVCKey: the KVC key
*/
@nonobjc
public func setValue(_ value: Any?, forKVCKey KVCKey: KeyPath) {
public func setValue(value: AnyObject?, forKVCKey KVCKey: KeyPath) {
self.willChangeValue(forKey: KVCKey)
defer {
self.didChangeValue(forKey: KVCKey)
}
self.willChangeValueForKey(KVCKey)
self.setPrimitiveValue(value, forKey: 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)
self.didChangeValueForKey(KVCKey)
}
/**
@@ -156,7 +68,7 @@ public extension NSManagedObject {
@nonobjc
public func refreshAsFault() {
self.managedObjectContext?.refresh(self, mergeChanges: false)
self.managedObjectContext?.refreshObject(self, mergeChanges: false)
}
/**
@@ -165,6 +77,6 @@ public extension NSManagedObject {
@nonobjc
public func refreshAndMerge() {
self.managedObjectContext?.refresh(self, mergeChanges: true)
self.managedObjectContext?.refreshObject(self, mergeChanges: true)
}
}

View File

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

View File

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

View File

@@ -32,117 +32,59 @@ import CoreData
/**
All errors thrown from CoreStore are expressed in `CoreStoreError` enum values.
*/
public enum CoreStoreError: Error, CustomNSError, Hashable {
public enum CoreStoreError: ErrorType, 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: URL)
case DifferentStorageExistsAtURL(existingPersistentStoreURL: NSURL)
/**
An `NSMappingModel` could not be found for a specific source and destination model versions.
*/
case mappingModelNotFound(localStoreURL: URL, targetModel: NSManagedObjectModel, targetModelVersion: String)
case MappingModelNotFound(localStoreURL: NSURL, 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: URL)
case ProgressiveMigrationRequired(localStoreURL: NSURL)
/**
An internal SDK call failed with the specified `NSError`.
*/
case internalError(NSError: NSError)
case InternalError(NSError: NSError)
// MARK: CustomNSError
// MARK: ErrorType
public static var errorDomain: String {
public var _domain: String {
return CoreStoreErrorDomain
}
public var errorCode: Int {
public var _code: Int {
switch self {
case .unknown:
return CoreStoreErrorCode.unknownError.rawValue
case .Unknown:
return CoreStoreErrorCode.UnknownError.rawValue
case .differentStorageExistsAtURL:
return CoreStoreErrorCode.differentStorageExistsAtURL.rawValue
case .DifferentStorageExistsAtURL:
return CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.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
}
}
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
case .InternalError:
return CoreStoreErrorCode.InternalError.rawValue
}
}
@@ -154,19 +96,19 @@ public enum CoreStoreError: Error, CustomNSError, 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
}
}
@@ -174,9 +116,37 @@ public enum CoreStoreError: Error, CustomNSError, Hashable {
// MARK: Internal
internal init(_ error: Error?) {
internal init(_ error: ErrorType?) {
self = error.flatMap { $0.bridgeToSwift } ?? .unknown
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
}
}
@@ -200,27 +170,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 differentStorageExistsAtURL
case DifferentPersistentStoreExistsAtURL
/**
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
}
@@ -238,4 +208,20 @@ 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,46 +29,7 @@ import CoreData
// MARK: - DataTransaction
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
public extension BaseDataTransaction {
/**
Fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
@@ -76,9 +37,17 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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.
*/
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(object: T) -> T? {
return self.context.fetchExisting(object)
do {
return (try self.context.existingObjectWithID(object.objectID) as! T)
}
catch _ {
return nil
}
}
/**
@@ -87,9 +56,17 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the transaction, or `nil` if not found.
*/
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(objectID: NSManagedObjectID) -> T? {
return self.context.fetchExisting(objectID)
do {
return (try self.context.existingObjectWithID(objectID) as! T)
}
catch _ {
return nil
}
}
/**
@@ -98,9 +75,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter objects: an array of `NSManagedObject`s created/fetched outside the transaction
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == T>(objects: S) -> [T] {
return self.context.fetchExisting(objects)
return objects.flatMap { (try? self.context.existingObjectWithID($0.objectID)) as? T }
}
/**
@@ -109,9 +87,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the transaction
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == NSManagedObjectID>(objectIDs: S) -> [T] {
return self.context.fetchExisting(objectIDs)
return objectIDs.flatMap { (try? self.context.existingObjectWithID($0)) as? T }
}
/**
@@ -121,13 +100,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchOne(from, fetchClauses)
return self.fetchOne(from, fetchClauses)
}
/**
@@ -137,7 +113,8 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -153,13 +130,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchAll(from, fetchClauses)
return self.fetchAll(from, fetchClauses)
}
/**
@@ -169,7 +143,8 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -185,13 +160,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
@warn_unused_result
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)
return self.fetchCount(from, fetchClauses)
}
/**
@@ -201,12 +173,14 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
@warn_unused_result
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)
}
@@ -217,13 +191,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectID(from, fetchClauses)
return self.fetchObjectID(from, fetchClauses)
}
/**
@@ -233,7 +204,8 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -249,13 +221,10 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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 fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.fetchObjectIDs(from, fetchClauses)
return self.fetchObjectIDs(from, fetchClauses)
}
/**
@@ -265,7 +234,8 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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 fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -274,8 +244,39 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
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
/**
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)
}
/**
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
@@ -287,12 +288,14 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
@warn_unused_result
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)
}
@@ -306,12 +309,14 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
@warn_unused_result
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)
}
@@ -325,12 +330,14 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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.
*/
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.context.queryAttributes(from, selectClause, queryClauses)
}
@@ -344,23 +351,14 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
- 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.
*/
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
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,6 +68,7 @@ public struct From<T: NSManagedObject> {
```
let people = transaction.fetchAll(From<MyPersonEntity>())
```
- parameter entity: the associated `NSManagedObject` type
*/
public init(_ entity: T.Type) {
@@ -80,13 +81,14 @@ 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>.self)) with entity class \(cs_typeName(entityClass))"
"Attempted to create generic type \(cs_typeName(From<T>)) with entity class \(cs_typeName(entityClass))"
)
self.init(entityClass: entityClass, configurations: nil)
}
@@ -96,6 +98,7 @@ 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)
*/
@@ -109,6 +112,7 @@ 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?]) {
@@ -121,6 +125,7 @@ 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)
@@ -135,6 +140,7 @@ 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.
*/
@@ -148,6 +154,7 @@ 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)
@@ -156,7 +163,7 @@ public struct From<T: NSManagedObject> {
CoreStore.assert(
entityClass is T.Type,
"Attempted to create generic type \(cs_typeName(From<T>.self)) with entity class \(cs_typeName(entityClass))"
"Attempted to create generic type \(cs_typeName(From<T>)) with entity class \(cs_typeName(entityClass))"
)
self.init(entityClass: entityClass, configurations: [configuration] + otherConfigurations)
}
@@ -166,6 +173,7 @@ 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.
*/
@@ -173,7 +181,7 @@ public struct From<T: NSManagedObject> {
CoreStore.assert(
entityClass is T.Type,
"Attempted to create generic type \(cs_typeName(From<T>.self)) with entity class \(cs_typeName(entityClass))"
"Attempted to create generic type \(cs_typeName(From<T>)) with entity class \(cs_typeName(entityClass))"
)
self.init(entityClass: entityClass, configurations: configurations)
}
@@ -181,7 +189,8 @@ public struct From<T: NSManagedObject> {
// MARK: Internal
internal func applyToFetchRequest<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>, context: NSManagedObjectContext, applyAffectedStores: Bool = true) -> Bool {
@warn_unused_result
internal func applyToFetchRequest(fetchRequest: NSFetchRequest, context: NSManagedObjectContext, applyAffectedStores: Bool = true) -> Bool {
fetchRequest.entity = context.entityDescriptionForEntityClass(self.entityClass)
guard applyAffectedStores else {
@@ -193,20 +202,20 @@ 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<U: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<U>, context: NSManagedObjectContext) -> Bool {
internal func applyAffectedStoresForFetchedRequest(fetchRequest: NSFetchRequest, context: NSManagedObjectContext) -> Bool {
let stores = self.findPersistentStores(context)
let stores = self.findPersistentStores(context: context)
fetchRequest.affectedStores = stores
return stores?.isEmpty == false
}
internal func downcast() -> From<NSManagedObject> {
internal func upcast() -> From<NSManagedObject> {
return From<NSManagedObject>(
entityClass: self.entityClass,
@@ -218,7 +227,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?]?) {
@@ -244,10 +253,121 @@ public struct From<T: NSManagedObject> {
}
}
private init(entityClass: AnyClass, configurations: [String?]?, findPersistentStores: @escaping (_ context: NSManagedObjectContext) -> [NSPersistentStore]?) {
private init(entityClass: AnyClass, configurations: [String?]?, findPersistentStores: (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<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
if let keyPaths = fetchRequest.propertiesToGroupBy as? [String], keyPaths != self.keyPaths {
if let keyPaths = fetchRequest.propertiesToGroupBy as? [String] where keyPaths != self.keyPaths {
CoreStore.log(
.warning,
message: "An existing \"propertiesToGroupBy\" for the \(cs_typeName(NSFetchRequest<ResultType>.self)) was overwritten by \(cs_typeName(self)) query clause."
.Warning,
message: "An existing \"propertiesToGroupBy\" for the \(cs_typeName(NSFetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
)
}
@@ -85,14 +85,6 @@ 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 {
@@ -100,3 +92,12 @@ 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 += (left: inout OrderBy, right: OrderBy) {
public func +=(inout left: 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<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
if let sortDescriptors = fetchRequest.sortDescriptors, sortDescriptors != self.sortDescriptors {
if let sortDescriptors = fetchRequest.sortDescriptors where sortDescriptors != self.sortDescriptors {
CoreStore.log(
.warning,
message: "Existing sortDescriptors for the \(cs_typeName(fetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
.Warning,
message: "Existing sortDescriptors for the \(cs_typeName(NSFetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
)
}
@@ -152,14 +152,6 @@ 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 {
@@ -167,3 +159,12 @@ 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: Any) -> Self?
static func fromResultObject(result: AnyObject) -> Self?
}
@@ -55,7 +55,7 @@ public protocol SelectValueResultType: SelectResultType {
*/
public protocol SelectAttributesResultType: SelectResultType {
static func fromResultObjects(_ result: [Any]) -> [[String: Any]]
static func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]]
}
@@ -64,52 +64,54 @@ public protocol SelectAttributesResultType: SelectResultType {
/**
The `SelectTerm` is passed to the `Select` clause to indicate the attributes/aggregate keys to be queried.
*/
public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
public enum SelectTerm: StringLiteralConvertible, 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
)
}
@@ -117,21 +119,22 @@ public enum SelectTerm: ExpressibleByStringLiteral, 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
)
}
@@ -139,21 +142,22 @@ public enum SelectTerm: ExpressibleByStringLiteral, 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
)
}
@@ -161,21 +165,22 @@ public enum SelectTerm: ExpressibleByStringLiteral, 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
)
}
@@ -183,21 +188,22 @@ public enum SelectTerm: ExpressibleByStringLiteral, 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
)
}
@@ -205,64 +211,40 @@ public enum SelectTerm: ExpressibleByStringLiteral, 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: ExpressibleByStringLiteral
// MARK: StringLiteralConvertible
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)
}
// 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
}
self = ._Attribute(value)
}
@@ -272,13 +254,13 @@ public enum SelectTerm: ExpressibleByStringLiteral, 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
}
}
@@ -286,9 +268,35 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
// MARK: Internal
case _attribute(KeyPath)
case _aggregate(function: String, keyPath: KeyPath, alias: String, nativeType: NSAttributeType)
case _identity(alias: String, nativeType: NSAttributeType)
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
}
}
@@ -300,15 +308,15 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
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:
@@ -322,14 +330,13 @@ public enum SelectTerm: ExpressibleByStringLiteral, Hashable {
- `Double`
- `Float`
- `String`
- `Date`
- `Data`
- `NSNumber`
- `NSString`
- `NSDecimalNumber`
- `NSDate`
- `NSData`
- `NSManagedObjectID`
- `NSString`
- for `queryAttributes(...)` methods:
- `NSDictionary`
@@ -364,19 +371,11 @@ 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, ^)
return self.selectTerms.map { $0.hashValue }.reduce(0, combine: ^)
}
@@ -389,27 +388,36 @@ 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: Any) -> Bool? {
public static func fromResultObject(result: AnyObject) -> Bool? {
switch result {
case let decimal as NSDecimalNumber:
// iOS: NSDecimalNumber(string: "0.5").boolValue // true
// OSX: NSDecimalNumber(string: "0.5").boolValue // false
return NSNumber(value: decimal.doubleValue).boolValue
return NSNumber(double: decimal.doubleValue).boolValue
case let number as NSNumber:
return number.boolValue
@@ -427,12 +435,12 @@ extension Int8: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .integer64AttributeType
return .Integer64AttributeType
}
public static func fromResultObject(_ result: Any) -> Int8? {
public static func fromResultObject(result: AnyObject) -> Int8? {
guard let value = (result as? NSNumber)?.int64Value else {
guard let value = (result as? NSNumber)?.longLongValue else {
return nil
}
@@ -447,12 +455,12 @@ extension Int16: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .integer64AttributeType
return .Integer64AttributeType
}
public static func fromResultObject(_ result: Any) -> Int16? {
public static func fromResultObject(result: AnyObject) -> Int16? {
guard let value = (result as? NSNumber)?.int64Value else {
guard let value = (result as? NSNumber)?.longLongValue else {
return nil
}
@@ -467,12 +475,12 @@ extension Int32: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .integer64AttributeType
return .Integer64AttributeType
}
public static func fromResultObject(_ result: Any) -> Int32? {
public static func fromResultObject(result: AnyObject) -> Int32? {
guard let value = (result as? NSNumber)?.int64Value else {
guard let value = (result as? NSNumber)?.longLongValue else {
return nil
}
@@ -487,12 +495,12 @@ extension Int64: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .integer64AttributeType
return .Integer64AttributeType
}
public static func fromResultObject(_ result: Any) -> Int64? {
public static func fromResultObject(result: AnyObject) -> Int64? {
return (result as? NSNumber)?.int64Value
return (result as? NSNumber)?.longLongValue
}
}
@@ -503,12 +511,12 @@ extension Int: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .integer64AttributeType
return .Integer64AttributeType
}
public static func fromResultObject(_ result: Any) -> Int? {
public static func fromResultObject(result: AnyObject) -> Int? {
guard let value = (result as? NSNumber)?.int64Value else {
guard let value = (result as? NSNumber)?.longLongValue else {
return nil
}
@@ -523,10 +531,10 @@ extension Double: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .doubleAttributeType
return .DoubleAttributeType
}
public static func fromResultObject(_ result: Any) -> Double? {
public static func fromResultObject(result: AnyObject) -> Double? {
return (result as? NSNumber)?.doubleValue
}
@@ -539,10 +547,10 @@ extension Float: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .floatAttributeType
return .FloatAttributeType
}
public static func fromResultObject(_ result: Any) -> Float? {
public static func fromResultObject(result: AnyObject) -> Float? {
return (result as? NSNumber)?.floatValue
}
@@ -555,44 +563,12 @@ extension String: SelectValueResultType {
public static var attributeType: NSAttributeType {
return .stringAttributeType
return .StringAttributeType
}
public static func fromResultObject(_ result: Any) -> String? {
public static func fromResultObject(result: AnyObject) -> 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
return result as? NSString as? String
}
}
@@ -603,12 +579,12 @@ extension NSNumber: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .integer64AttributeType
return .Integer64AttributeType
}
public class func fromResultObject(_ result: Any) -> Self? {
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSNumber>(_ object: Any) -> T? {
func forceCast<T: NSNumber>(object: AnyObject) -> T? {
return (object as? T)
}
@@ -623,12 +599,12 @@ extension NSString: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .stringAttributeType
return .StringAttributeType
}
public class func fromResultObject(_ result: Any) -> Self? {
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSString>(_ object: Any) -> T? {
func forceCast<T: NSString>(object: AnyObject) -> T? {
return (object as? T)
}
@@ -643,12 +619,12 @@ extension NSDecimalNumber {
public override class var attributeType: NSAttributeType {
return .decimalAttributeType
return .DecimalAttributeType
}
public override class func fromResultObject(_ result: Any) -> Self? {
public override class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSDecimalNumber>(_ object: Any) -> T? {
func forceCast<T: NSDecimalNumber>(object: AnyObject) -> T? {
return (object as? T)
}
@@ -661,14 +637,14 @@ extension NSDecimalNumber {
extension NSDate: SelectValueResultType {
public static var attributeType: NSAttributeType {
public class var attributeType: NSAttributeType {
return .dateAttributeType
return .DateAttributeType
}
public class func fromResultObject(_ result: Any) -> Self? {
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSDate>(_ object: Any) -> T? {
func forceCast<T: NSDate>(object: AnyObject) -> T? {
return (object as? T)
}
@@ -681,14 +657,14 @@ extension NSDate: SelectValueResultType {
extension NSData: SelectValueResultType {
public static var attributeType: NSAttributeType {
public class var attributeType: NSAttributeType {
return .binaryDataAttributeType
return .BinaryDataAttributeType
}
public class func fromResultObject(_ result: Any) -> Self? {
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSData>(_ object: Any) -> T? {
func forceCast<T: NSData>(object: AnyObject) -> T? {
return (object as? T)
}
@@ -703,12 +679,12 @@ extension NSManagedObjectID: SelectValueResultType {
public class var attributeType: NSAttributeType {
return .objectIDAttributeType
return .ObjectIDAttributeType
}
public class func fromResultObject(_ result: Any) -> Self? {
public class func fromResultObject(result: AnyObject) -> Self? {
func forceCast<T: NSManagedObjectID>(_ object: Any) -> T? {
func forceCast<T: NSManagedObjectID>(object: AnyObject) -> T? {
return (object as? T)
}
@@ -723,25 +699,25 @@ extension NSDictionary: SelectAttributesResultType {
// MARK: SelectAttributesResultType
public class func fromResultObjects(_ result: [Any]) -> [[String: Any]] {
public class func fromResultObjects(result: [AnyObject]) -> [[NSString: AnyObject]] {
return result as! [[String: Any]]
return result as! [[NSString: AnyObject]]
}
}
// MARK: - Internal
internal extension Collection where Iterator.Element == SelectTerm {
internal extension CollectionType where Generator.Element == SelectTerm {
internal func applyToFetchRequest<T>(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>, owner: T) {
internal func applyToFetchRequest<T>(fetchRequest: NSFetchRequest, owner: T) {
fetchRequest.includesPendingChanges = false
fetchRequest.resultType = .dictionaryResultType
fetchRequest.resultType = .DictionaryResultType
func attributeDescription(for keyPath: String, in entity: NSEntityDescription) -> NSAttributeDescription? {
func attributeDescriptionForKeyPath(keyPath: String, inEntity entity: NSEntityDescription) -> NSAttributeDescription? {
let components = keyPath.components(separatedBy: ".")
let components = keyPath.componentsSeparatedByString(".")
switch components.count {
case 0:
@@ -755,39 +731,39 @@ internal extension Collection where Iterator.Element == SelectTerm {
return nil
}
return attributeDescription(
for: components.dropFirst().joined(separator: "."),
in: relationship.entity
return attributeDescriptionForKeyPath(
components.dropFirst().joinWithSeparator("."),
inEntity: relationship.entity
)
}
}
var propertiesToFetch = [Any]()
var propertiesToFetch = [AnyObject]()
for term in self {
switch term {
case ._attribute(let keyPath):
case ._Attribute(let keyPath):
let entityDescription = fetchRequest.entity!
if let attributeDescription = attributeDescription(for: keyPath, in: entityDescription) {
if let attributeDescription = attributeDescriptionForKeyPath(keyPath, inEntity: 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 = attributeDescription(for: keyPath, in: entityDescription) {
if let attributeDescription = attributeDescriptionForKeyPath(keyPath, inEntity: entityDescription) {
let expressionDescription = NSExpressionDescription()
expressionDescription.name = alias
if nativeType == .undefinedAttributeType {
if nativeType == .UndefinedAttributeType {
expressionDescription.expressionResultType = attributeDescription.attributeType
}
@@ -804,17 +780,17 @@ internal extension Collection where Iterator.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 {
@@ -833,13 +809,13 @@ internal extension Collection where Iterator.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<NSFetchRequestResult>) -> Void
public let closure: (fetchRequest: NSFetchRequest) -> 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: @escaping (_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) -> Void) {
public init(_ closure: (fetchRequest: NSFetchRequest) -> Void) {
self.closure = closure
}
@@ -63,8 +63,8 @@ public struct Tweak: FetchClause, QueryClause, DeleteClause {
// MARK: FetchClause, QueryClause, DeleteClause
public func applyToFetchRequest<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
self.closure(fetchRequest as! NSFetchRequest<NSFetchRequestResult>)
self.closure(fetchRequest: fetchRequest)
}
}

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: .and, subpredicates: [left.predicate, right.predicate]))
return Where(NSCompoundPredicate(type: .AndPredicateType, subpredicates: [left.predicate, right.predicate]))
}
public func || (left: Where, right: Where) -> Where {
public func ||(left: Where, right: Where) -> Where {
return Where(NSCompoundPredicate(type: .or, subpredicates: [left.predicate, right.predicate]))
return Where(NSCompoundPredicate(type: .OrPredicateType, subpredicates: [left.predicate, right.predicate]))
}
public prefix func ! (clause: Where) -> Where {
public prefix func !(clause: Where) -> Where {
return Where(NSCompoundPredicate(type: .not, subpredicates: [clause.predicate]))
return Where(NSCompoundPredicate(type: .NotPredicateType, 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: Any...) {
public init(_ format: String, _ args: NSObject...) {
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: [Any]?) {
public init(_ format: String, argumentArray: [NSObject]?) {
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: Any?) {
public init(_ keyPath: KeyPath, isEqualTo value: NSObject?) {
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: [Any]) {
public init(_ keyPath: KeyPath, isMemberOf list: [NSObject]) {
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: Sequence>(_ keyPath: KeyPath, isMemberOf list: S) where S.Iterator.Element: Any {
public init<S: SequenceType where S.Generator.Element: NSObject>(_ keyPath: KeyPath, isMemberOf list: S) {
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<ResultType: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<ResultType>) {
public func applyToFetchRequest(fetchRequest: NSFetchRequest) {
if let predicate = fetchRequest.predicate, predicate != self.predicate {
if let predicate = fetchRequest.predicate where predicate != self.predicate {
CoreStore.log(
.warning,
message: "An existing predicate for the \(cs_typeName(fetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
.Warning,
message: "An existing predicate for the \(cs_typeName(NSFetchRequest)) was overwritten by \(cs_typeName(self)) query clause."
)
}
@@ -157,14 +157,6 @@ 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 {
@@ -172,3 +164,12 @@ 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,7 +37,8 @@ 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.
*/
public static func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
@warn_unused_result
public static func fetchExisting<T: NSManagedObject>(object: T) -> T? {
return self.defaultStack.fetchExisting(object)
}
@@ -48,7 +49,8 @@ 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.
*/
public static func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
@warn_unused_result
public static func fetchExisting<T: NSManagedObject>(objectID: NSManagedObjectID) -> T? {
return self.defaultStack.fetchExisting(objectID)
}
@@ -59,7 +61,8 @@ 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`
*/
public static func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
@warn_unused_result
public static func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == T>(objects: S) -> [T] {
return self.defaultStack.fetchExisting(objects)
}
@@ -70,7 +73,8 @@ public extension CoreStore {
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `DataStack`
*/
public static func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
@warn_unused_result
public static func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == NSManagedObjectID>(objectIDs: S) -> [T] {
return self.defaultStack.fetchExisting(objectIDs)
}
@@ -82,7 +86,8 @@ 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
*/
public static func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
@warn_unused_result
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.defaultStack.fetchOne(from, fetchClauses)
}
@@ -94,7 +99,8 @@ 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
*/
public static func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
@warn_unused_result
public static func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
return self.defaultStack.fetchOne(from, fetchClauses)
}
@@ -106,7 +112,8 @@ 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
*/
public static func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
@warn_unused_result
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
return self.defaultStack.fetchAll(from, fetchClauses)
}
@@ -118,7 +125,8 @@ 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
*/
public static func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
@warn_unused_result
public static func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
return self.defaultStack.fetchAll(from, fetchClauses)
}
@@ -130,7 +138,8 @@ 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
*/
public static func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
@warn_unused_result
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses)
}
@@ -142,7 +151,8 @@ 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
*/
public static func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
@warn_unused_result
public static func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
return self.defaultStack.fetchCount(from, fetchClauses)
}
@@ -154,7 +164,8 @@ 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
*/
public static func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
@warn_unused_result
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses)
}
@@ -166,7 +177,8 @@ 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
*/
public static func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
@warn_unused_result
public static func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
return self.defaultStack.fetchObjectID(from, fetchClauses)
}
@@ -178,7 +190,8 @@ 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
*/
public static func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
@warn_unused_result
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
}
@@ -190,7 +203,8 @@ 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
*/
public static func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
@warn_unused_result
public static func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
return self.defaultStack.fetchObjectIDs(from, fetchClauses)
}
@@ -205,7 +219,8 @@ 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.
*/
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
@warn_unused_result
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
return self.defaultStack.queryValue(from, selectClause, queryClauses)
}
@@ -220,7 +235,8 @@ 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.
*/
public static func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
@warn_unused_result
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,7 +251,8 @@ 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.
*/
public static func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
@warn_unused_result
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}
@@ -250,7 +267,8 @@ 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.
*/
public static func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
@warn_unused_result
public static func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
return self.defaultStack.queryAttributes(from, selectClause, queryClauses)
}

View File

@@ -25,13 +25,14 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - DataStack
extension DataStack: FetchableSource, QueryableSource {
// MARK: FetchableSource
public extension DataStack {
/**
Fetches the `NSManagedObject` instance in the `DataStack`'s context from a reference created from a transaction or from a different managed object context.
@@ -39,9 +40,17 @@ extension DataStack: FetchableSource, QueryableSource {
- 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.
*/
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(object: T) -> T? {
return self.mainContext.fetchExisting(object)
do {
return (try self.mainContext.existingObjectWithID(object.objectID) as! T)
}
catch _ {
return nil
}
}
/**
@@ -50,9 +59,17 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter objectID: the `NSManagedObjectID` for the object
- returns: the `NSManagedObject` instance if the object exists in the `DataStack`, or `nil` if not found.
*/
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
@warn_unused_result
public func fetchExisting<T: NSManagedObject>(objectID: NSManagedObjectID) -> T? {
return self.mainContext.fetchExisting(objectID)
do {
return (try self.mainContext.existingObjectWithID(objectID) as! T)
}
catch _ {
return nil
}
}
/**
@@ -61,9 +78,10 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter objects: an array of `NSManagedObject`s created/fetched outside the `DataStack`
- returns: the `NSManagedObject` array for objects that exists in the `DataStack`
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == T>(objects: S) -> [T] {
return self.mainContext.fetchExisting(objects)
return objects.flatMap { (try? self.mainContext.existingObjectWithID($0.objectID)) as? T }
}
/**
@@ -72,9 +90,10 @@ extension DataStack: FetchableSource, QueryableSource {
- parameter objectIDs: the `NSManagedObjectID` array for the objects
- returns: the `NSManagedObject` array for objects that exists in the `DataStack`
*/
public func fetchExisting<T: NSManagedObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
@warn_unused_result
public func fetchExisting<T: NSManagedObject, S: SequenceType where S.Generator.Element == NSManagedObjectID>(objectIDs: S) -> [T] {
return self.mainContext.fetchExisting(objectIDs)
return objectIDs.flatMap { (try? self.mainContext.existingObjectWithID($0)) as? T }
}
/**
@@ -84,10 +103,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchOne(from, fetchClauses)
@@ -100,10 +120,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
@warn_unused_result
public func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchOne(from, fetchClauses)
@@ -116,10 +137,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchAll(from, fetchClauses)
@@ -132,10 +154,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
@warn_unused_result
public func fetchAll<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchAll(from, fetchClauses)
@@ -148,10 +171,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
@warn_unused_result
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchCount(from, fetchClauses)
@@ -164,10 +188,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
@warn_unused_result
public func fetchCount<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchCount(from, fetchClauses)
@@ -180,10 +205,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectID(from, fetchClauses)
@@ -196,10 +222,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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
*/
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
@warn_unused_result
public func fetchObjectID<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectID(from, fetchClauses)
@@ -212,10 +239,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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 fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to fetch from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.fetchObjectIDs(from, fetchClauses)
@@ -228,18 +256,16 @@ extension DataStack: FetchableSource, QueryableSource {
- 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 fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
@warn_unused_result
public func fetchObjectIDs<T: NSManagedObject>(from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
CoreStore.assert(
Thread.isMainThread,
NSThread.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.
@@ -250,10 +276,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
@warn_unused_result
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryValue(from, selectClause, queryClauses)
@@ -269,10 +296,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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.
*/
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
@warn_unused_result
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryValue(from, selectClause, queryClauses)
@@ -288,10 +316,11 @@ extension DataStack: FetchableSource, QueryableSource {
- 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.
*/
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? {
CoreStore.assert(
Thread.isMainThread,
NSThread.isMainThread(),
"Attempted to query from a \(cs_typeName(self)) outside the main thread."
)
return self.mainContext.queryAttributes(from, selectClause, queryClauses)
@@ -307,23 +336,13 @@ extension DataStack: FetchableSource, QueryableSource {
- 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.
*/
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
@warn_unused_result
public func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
CoreStore.assert(
Thread.isMainThread,
NSThread.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

@@ -1,163 +0,0 @@
//
// 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<T: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<T>)
func applyToFetchRequest(fetchRequest: NSFetchRequest)
}
@@ -45,7 +45,7 @@ public protocol FetchClause {
*/
public protocol QueryClause {
func applyToFetchRequest<T: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<T>)
func applyToFetchRequest(fetchRequest: NSFetchRequest)
}
@@ -56,5 +56,5 @@ public protocol QueryClause {
*/
public protocol DeleteClause {
func applyToFetchRequest<T: NSFetchRequestResult>(_ fetchRequest: NSFetchRequest<T>)
func applyToFetchRequest(fetchRequest: NSFetchRequest)
}

View File

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

View File

@@ -1,316 +0,0 @@
//
// CoreDataNativeType.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - CoreDataNativeType
public protocol CoreDataNativeType: class, NSObjectProtocol, AnyObject {}
extension NSNumber: CoreDataNativeType {}
extension NSString: CoreDataNativeType {}
extension NSDate: CoreDataNativeType {}
extension NSData: CoreDataNativeType {}
extension NSSet: CoreDataNativeType {}
extension NSOrderedSet: CoreDataNativeType {}
public protocol CoreStoreSupportedAttributeType {
associatedtype CoreStoreNativeType: CoreDataNativeType
static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self?
func cs_toNativeType() -> CoreStoreNativeType
}
extension NSNumber: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSNumber
public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? {
func forceCast<T: NSNumber>(_ value: Any) -> T? {
return value as? T
}
return forceCast(value)
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self
}
}
extension NSString: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSString
public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? {
func forceCast<T: NSString>(_ value: Any) -> T? {
return value as? T
}
return forceCast(value)
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self
}
}
extension NSDate: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSDate
public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? {
func forceCast<T: NSDate>(_ value: Any) -> T? {
return value as? T
}
return forceCast(value)
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self
}
}
extension NSData: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSData
public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? {
func forceCast<T: NSData>(_ value: Any) -> T? {
return value as? T
}
return forceCast(value)
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self
}
}
extension NSSet: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSSet
public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? {
func forceCast<T: NSSet>(_ value: Any) -> T? {
return value as? T
}
return forceCast(value)
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self
}
}
extension NSOrderedSet: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSOrderedSet
public class func cs_fromNativeType(_ value: CoreStoreNativeType) -> Self? {
func forceCast<T: NSOrderedSet>(_ value: Any) -> T? {
return value as? T
}
return forceCast(value)
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self
}
}
extension Bool: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSNumber
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Bool? {
return value.boolValue
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSNumber
}
}
extension Int16: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSNumber
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Int16? {
return value.int16Value
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSNumber
}
}
extension Int32: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSNumber
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Int32? {
return value.int32Value
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSNumber
}
}
extension Int64: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSNumber
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Int64? {
return value.int64Value
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSNumber
}
}
extension Double: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSNumber
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Double? {
return value.doubleValue
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSNumber
}
}
extension Float: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSNumber
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Float? {
return value.floatValue
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSNumber
}
}
extension Date: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSDate
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Date? {
return value as Date
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSDate
}
}
extension String: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSString
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> String? {
return value as String
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSString
}
}
extension Data: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSData
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Data? {
return value as Data
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSData
}
}
extension Set: CoreStoreSupportedAttributeType {
public typealias CoreStoreNativeType = NSSet
public static func cs_fromNativeType(_ value: CoreStoreNativeType) -> Set? {
return value as? Set
}
public func cs_toNativeType() -> CoreStoreNativeType {
return self as NSSet
}
}

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
)
// ...
@@ -48,7 +48,7 @@ import CoreData
}
```
*/
public protocol ImportableObject: class, NSObjectProtocol, AnyObject {
public protocol ImportableObject: class {
/**
The data type for the import source. This is most commonly an `NSDictionary` or another external source such as an `NSUserDefaults`.
@@ -62,24 +62,15 @@ public protocol ImportableObject: class, NSObjectProtocol, AnyObject {
- 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 shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
static func shouldInsertFromImportSource(source: ImportSource, inTransaction 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 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
*/
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
}
@@ -87,21 +78,8 @@ public protocol ImportableObject: class, NSObjectProtocol, AnyObject {
public extension ImportableObject {
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool {
static func shouldInsertFromImportSource(source: ImportSource, inTransaction 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
)
// ...
@@ -59,7 +59,7 @@ public protocol ImportableUniqueObject: ImportableObject {
/**
The data type for the entity's unique ID attribute
*/
associatedtype UniqueIDType: CoreStoreSupportedAttributeType
associatedtype UniqueIDType: NSObject
/**
The keyPath to the entity's unique ID attribute
@@ -67,19 +67,18 @@ public protocol ImportableUniqueObject: ImportableObject {
static var uniqueIDKeyPath: String { get }
/**
The object's unique ID value. The default implementation returns the value of the attribute pertained to by `uniqueIDKeyPath`
- Important: It is the developer's responsibility to ensure that the attribute value pertained by `uniqueIDKeyPath` is not `nil` during the call to `uniqueIDValue`.
The object's unique ID value
*/
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 `shouldUpdate(from:in:)` 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 `shouldUpdateFromImportSource(:inTransaction:)` 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 shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
static func shouldInsertFromImportSource(source: ImportSource, inTransaction 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`.
@@ -88,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 shouldUpdate(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
static func shouldUpdateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
/**
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.
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.
- 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 uniqueID(from source: ImportSource, in transaction: BaseDataTransaction) throws -> UniqueIDType?
static func uniqueIDFromImportSource(source: ImportSource, inTransaction 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 `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:)`.
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(...)`.
- 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 didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
func didInsertFromImportSource(source: ImportSource, inTransaction 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.
@@ -113,25 +112,7 @@ 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 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
func updateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws
}
@@ -139,69 +120,18 @@ public protocol ImportableUniqueObject: ImportableObject {
public extension ImportableUniqueObject {
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool {
static func shouldInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
return Self.shouldUpdate(from: source, in: transaction)
return self.shouldUpdateFromImportSource(source, inTransaction: transaction)
}
static func shouldUpdate(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool{
static func shouldUpdateFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
return true
}
func didInsert(from source: Self.ImportSource, in transaction: BaseDataTransaction) throws {
func didInsertFromImportSource(source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
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)
}
}
// MARK: - ImportableUniqueObject (Default Implementations)
public extension ImportableUniqueObject where Self: NSManagedObject {
var uniqueIDValue: UniqueIDType {
get {
return UniqueIDType.cs_fromNativeType(
self.value(forKey: type(of: self).uniqueIDKeyPath) as! UniqueIDType.CoreStoreNativeType
)!
}
set {
self.setValue(
newValue.cs_toNativeType(),
forKey: type(of: self).uniqueIDKeyPath
)
}
try self.updateFromImportSource(source, inTransaction: transaction)
}
}

View File

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

View File

@@ -1,5 +1,5 @@
//
// CoreStoreFetchRequest+CoreStore.swift
// CoreStoreFetchRequest.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
@@ -29,13 +29,14 @@ import CoreData
// MARK: - CoreStoreFetchRequest
internal extension 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 {
// MARK: Internal
@nonobjc
internal func dynamicCast<U: NSFetchRequestResult>() -> NSFetchRequest<U> {
@objc
override var affectedStores: [NSPersistentStore]? {
return unsafeBitCast(self, to: NSFetchRequest<U>.self)
get { return super.affectedStores }
set { super.affectedStores = newValue }
}
}

View File

@@ -31,12 +31,12 @@ import CoreData
// MARK: - CoreStoreFetchedResultsController
internal final class CoreStoreFetchedResultsController: NSFetchedResultsController<NSManagedObject> {
internal final class CoreStoreFetchedResultsController: NSFetchedResultsController {
// MARK: Internal
@nonobjc
internal convenience init<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
internal convenience init<T: NSManagedObject>(dataStack: DataStack, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: (fetchRequest: NSFetchRequest) -> Void) {
self.init(
context: dataStack.mainContext,
@@ -48,14 +48,14 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
}
@nonobjc
internal init<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest<NSManagedObject>, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: @escaping (_ fetchRequest: NSFetchRequest<NSManagedObject>) -> Void) {
internal init<T: NSManagedObject>(context: NSManagedObjectContext, fetchRequest: NSFetchRequest, from: From<T>? = nil, sectionBy: SectionBy? = nil, applyFetchClauses: (fetchRequest: NSFetchRequest) -> Void) {
_ = from?.applyToFetchRequest(
fetchRequest,
context: context,
applyAffectedStores: false
)
applyFetchClauses(fetchRequest)
applyFetchClauses(fetchRequest: 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 a \(CoreStoreFetchedResultsController.self) without a \(cs_typeName(From<T>.self)) clause or an \(cs_typeName(NSEntityDescription.self)).")
CoreStore.abort("Attempted to create an \(cs_typeName(NSFetchedResultsController)) without a \(cs_typeName(From)) clause or an \(cs_typeName(NSEntityDescription)).")
}
self.reapplyAffectedStores = { fetchRequest, context in
@@ -88,22 +88,16 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
@nonobjc
internal func performFetchFromSpecifiedStores() throws {
if !self.reapplyAffectedStores(self.fetchRequest, self.managedObjectContext) {
if !self.reapplyAffectedStores(fetchRequest: self.fetchRequest, context: self.managedObjectContext) {
CoreStore.log(
.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))"
.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))"
)
}
try self.performFetch()
}
@nonobjc
internal func dynamicCast<U: NSFetchRequestResult>() -> NSFetchedResultsController<U> {
return unsafeBitCast(self, to: NSFetchedResultsController<U>.self)
}
deinit {
self.delegate = nil
@@ -113,7 +107,7 @@ internal final class CoreStoreFetchedResultsController: NSFetchedResultsControll
// MARK: Private
@nonobjc
private let reapplyAffectedStores: (_ fetchRequest: NSFetchRequest<NSManagedObject>, _ context: NSManagedObjectContext) -> Bool
private let reapplyAffectedStores: (fetchRequest: NSFetchRequest, context: NSManagedObjectContext) -> Bool
}
#endif

View File

@@ -1,97 +0,0 @@
//
// 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<NSFetchRequestResult>, didChangeObject anObject: Any, atIndexPath indexPath: IndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
func controllerWillChangeContent(controller: NSFetchedResultsController)
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
func controllerDidChangeContent(controller: NSFetchedResultsController)
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String?) -> String?
func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String?
}
// MARK: - FetchedResultsControllerDelegate
internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObject>: NSObject, NSFetchedResultsControllerDelegate {
internal final class FetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {
// MARK: Internal
@@ -58,7 +58,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
internal weak var handler: FetchedResultsControllerHandler?
@nonobjc
internal weak var fetchedResultsController: CoreStoreFetchedResultsController? {
internal weak var fetchedResultsController: NSFetchedResultsController? {
didSet {
@@ -76,7 +76,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
// MARK: NSFetchedResultsControllerDelegate
@objc
dynamic func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
dynamic func controllerWillChangeContent(controller: NSFetchedResultsController) {
guard self.enabled else {
@@ -90,7 +90,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
}
@objc
dynamic func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
dynamic func controllerDidChangeContent(controller: NSFetchedResultsController) {
guard self.enabled else {
@@ -101,7 +101,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
}
@objc
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
dynamic func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
guard self.enabled else {
@@ -120,42 +120,31 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
// 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 {
if case .Update = actualType
where indexPath != nil && newIndexPath != nil {
actualType = .move
actualType = .Move
}
}
switch actualType {
case .update:
guard let section = indexPath?[0] else {
case .Update:
guard let section = indexPath?.indexAtPosition(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
@@ -164,25 +153,25 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
break
}
if self.insertedSections.contains(indexPath[0]) {
if self.insertedSections.contains(indexPath.indexAtPosition(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[0]) {
if self.deletedSections.contains(indexPath.indexAtPosition(0)) {
self.handler?.controller(
controller,
didChangeObject: anObject,
atIndexPath: nil,
forChangeType: .insert,
forChangeType: .Insert,
newIndexPath: indexPath
)
return
@@ -191,7 +180,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
controller,
didChangeObject: anObject,
atIndexPath: indexPath,
forChangeType: .update,
forChangeType: .Update,
newIndexPath: nil
)
return
@@ -210,7 +199,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
}
@objc
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
dynamic func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
guard self.enabled else {
@@ -219,8 +208,8 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
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
}
@@ -233,7 +222,7 @@ internal final class FetchedResultsControllerDelegate<EntityType: NSManagedObjec
}
@objc
dynamic func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, sectionIndexTitleForSectionName sectionName: String) -> String? {
dynamic func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String) -> String? {
return self.handler?.controller(
controller,

View File

@@ -25,9 +25,70 @@
import Foundation
// MARK: Associated Objects
internal func cs_getAssociatedObjectForKey<T: AnyObject>(_ key: UnsafeRawPointer, inObject object: Any) -> T? {
// 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? {
switch objc_getAssociatedObject(object, key) {
@@ -42,17 +103,17 @@ internal func cs_getAssociatedObjectForKey<T: AnyObject>(_ key: UnsafeRawPointer
}
}
internal func cs_setAssociatedRetainedObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
internal func cs_setAssociatedRetainedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
internal func cs_setAssociatedCopiedObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
internal func cs_setAssociatedCopiedObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
objc_setAssociatedObject(object, key, associatedObject, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
internal func cs_setAssociatedWeakObject<T: AnyObject>(_ associatedObject: T?, forKey key: UnsafeRawPointer, inObject object: Any) {
internal func cs_setAssociatedWeakObject<T: AnyObject>(associatedObject: T?, forKey key: UnsafePointer<Void>, inObject object: AnyObject) {
if let associatedObject = associatedObject {
@@ -67,27 +128,22 @@ internal func cs_setAssociatedWeakObject<T: AnyObject>(_ associatedObject: T?, f
// MARK: Printing Utilities
internal func cs_typeName<T>(_ value: T) -> String {
internal func cs_typeName<T>(value: T) -> String {
return "'\(String(reflecting: type(of: value)))'"
return "'\(String(reflecting: value.dynamicType))'"
}
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 {
return "<\(name)>"
}
internal func cs_typeName(_ name: String?) -> String {
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, ProgressReporting {
internal final class MigrationManager: NSMigrationManager, NSProgressReporting {
// MARK: NSObject
override func didChangeValue(forKey key: String) {
override func didChangeValueForKey(key: String) {
super.didChangeValue(forKey: key)
super.didChangeValueForKey(key)
guard key == #keyPath(NSMigrationManager.migrationProgress) else {
guard key == "migrationProgress" else {
return
}
@@ -48,7 +48,7 @@ internal final class MigrationManager: NSMigrationManager, ProgressReporting {
// MARK: NSMigrationManager
init(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, progress: Progress) {
init(sourceModel: NSManagedObjectModel, destinationModel: NSManagedObjectModel, progress: NSProgress) {
self.progress = progress
@@ -56,7 +56,7 @@ internal final class MigrationManager: NSMigrationManager, ProgressReporting {
}
// MARK: ProgressReporting
// MARK: NSProgressReporting
let progress: Progress
let progress: NSProgress
}

View File

@@ -1,240 +0,0 @@
//
// NSManagedObject+Logging.swift
// CoreStore
//
// Copyright © 2017 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - NSManagedObject
internal extension NSManagedObject {
@nonobjc
internal static func cs_swizzleMethodsForLogging() {
struct Static {
static let isSwizzled = Static.swizzle()
private static func swizzle() -> Bool {
NSManagedObject.cs_swizzle(
original: #selector(NSManagedObject.willAccessValue(forKey:)),
proxy: #selector(NSManagedObject.cs_willAccessValue(forKey:))
)
NSManagedObject.cs_swizzle(
original: #selector(NSManagedObject.willChangeValue(forKey:)),
proxy: #selector(NSManagedObject.cs_willChangeValue(forKey:))
)
NSManagedObject.cs_swizzle(
original: #selector(NSManagedObject.willChangeValue(forKey:withSetMutation:using:)),
proxy: #selector(NSManagedObject.cs_willChangeValue(forKey:withSetMutation:using:))
)
return true
}
}
assert(Static.isSwizzled)
}
@nonobjc
private static func cs_swizzle(original originalSelector: Selector, proxy swizzledSelector: Selector) {
let originalMethod = class_getInstanceMethod(NSManagedObject.self, originalSelector)
let swizzledMethod = class_getInstanceMethod(NSManagedObject.self, swizzledSelector)
let didAddMethod = class_addMethod(
NSManagedObject.self,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod)
)
if didAddMethod {
class_replaceMethod(
NSManagedObject.self,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod)
)
}
else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
private dynamic func cs_willAccessValue(forKey key: String?) {
self.cs_willAccessValue(forKey: key)
guard CoreStore.logger.enableObjectConcurrencyDebugging else {
return
}
guard let context = self.managedObjectContext else {
CoreStore.log(
.warning,
message: "Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(NSManagedObjectContext.self))."
)
return
}
if context.isTransactionContext {
guard let transaction = context.parentTransaction else {
CoreStore.log(
.warning,
message: "Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) after has been deleted from its transaction."
)
return
}
CoreStore.assert(
transaction.isRunningInAllowedQueue(),
"Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) outside its transaction's designated queue."
)
return
}
if context.isDataStackContext {
guard context.parentStack != nil else {
CoreStore.log(
.warning,
message: "Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(DataStack.self)).")
return
}
CoreStore.assert(
Thread.isMainThread,
"Attempted to access the \"\(key ?? "")\" key of an object of type \(cs_typeName(self)) outside the main thread."
)
return
}
}
private dynamic func cs_willChangeValue(forKey key: String?) {
self.cs_willChangeValue(forKey: key)
guard CoreStore.logger.enableObjectConcurrencyDebugging else {
return
}
guard let context = self.managedObjectContext else {
CoreStore.log(
.warning,
message: "Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(NSManagedObjectContext.self))."
)
return
}
if context.isTransactionContext {
guard let transaction = context.parentTransaction else {
CoreStore.log(
.warning,
message: "Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) after has been deleted from its transaction."
)
return
}
CoreStore.assert(
transaction.isRunningInAllowedQueue(),
"Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) outside its transaction's designated queue."
)
return
}
if context.isDataStackContext {
guard context.parentStack != nil else {
CoreStore.log(
.warning,
message: "Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(DataStack.self)).")
return
}
CoreStore.assert(
Thread.isMainThread,
"Attempted to change the \"\(key ?? "")\" of an object of type \(cs_typeName(self)) outside the main thread."
)
return
}
}
private dynamic func cs_willChangeValue(forKey inKey: String, withSetMutation inMutationKind: NSKeyValueSetMutationKind, using inObjects: Set<AnyHashable>) {
self.cs_willChangeValue(
forKey: inKey,
withSetMutation: inMutationKind,
using: inObjects
)
guard CoreStore.logger.enableObjectConcurrencyDebugging else {
return
}
guard let context = self.managedObjectContext else {
CoreStore.log(
.warning,
message: "Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(NSManagedObjectContext.self))."
)
return
}
if context.isTransactionContext {
guard let transaction = context.parentTransaction else {
CoreStore.log(
.warning,
message: "Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) after has been deleted from its transaction."
)
return
}
CoreStore.assert(
transaction.isRunningInAllowedQueue(),
"Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) outside its transaction's designated queue."
)
return
}
if context.isDataStackContext {
guard context.parentStack != nil else {
CoreStore.log(
.warning,
message: "Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) after has been deleted from its \(cs_typeName(DataStack.self)).")
return
}
CoreStore.assert(
Thread.isMainThread,
"Attempted to mutate the \"\(inKey)\" of an object of type \(cs_typeName(self)) outside the main thread."
)
return
}
}
}

View File

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

View File

@@ -29,20 +29,20 @@ import CoreData
// MARK: - NSManagedObjectContext
extension NSManagedObjectContext: FetchableSource, QueryableSource {
internal extension NSManagedObjectContext {
// MARK: FetchableSource
// MARK: Internal: Fetch Existing
@nonobjc
public func fetchExisting<T: NSManagedObject>(_ object: T) -> T? {
internal func fetchExisting<T: NSManagedObject>(object: T) -> T? {
if object.objectID.isTemporaryID {
if object.objectID.temporaryID {
do {
try withExtendedLifetime(self) { (context: NSManagedObjectContext) -> Void in
try context.obtainPermanentIDs(for: [object])
try context.obtainPermanentIDsForObjects([object])
}
}
catch {
@@ -54,9 +54,10 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
return nil
}
}
do {
let existingObject = try self.existingObject(with: object.objectID)
let existingObject = try self.existingObjectWithID(object.objectID)
return (existingObject as! T)
}
catch {
@@ -69,154 +70,42 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
}
}
@nonobjc
public func fetchExisting<T: NSManagedObject>(_ objectID: NSManagedObjectID) -> T? {
do {
return (try self.existingObject(with: objectID) as! T)
}
catch _ {
return nil
}
}
// MARK: Internal: Fetch One
@nonobjc
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? {
internal func fetchOne<T: NSManagedObject>(from: From<T>, _ fetchClauses: FetchClause...) -> T? {
return self.fetchOne(from, fetchClauses)
}
@nonobjc
public func fetchOne<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
internal 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.dynamicCast())
return self.fetchOne(fetchRequest)
}
@nonobjc
public func fetchAll<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
internal func fetchOne<T: NSManagedObject>(fetchRequest: NSFetchRequest) -> T? {
return self.fetchAll(from, fetchClauses)
}
@nonobjc
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
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchAll(fetchRequest.dynamicCast())
}
@nonobjc
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
return self.fetchCount(from, fetchClauses)
}
@nonobjc
public func fetchCount<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchCount(fetchRequest.dynamicCast())
}
@nonobjc
public func fetchObjectID<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
return self.fetchObjectID(from, fetchClauses)
}
@nonobjc
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
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchObjectID(fetchRequest.dynamicCast())
}
@nonobjc
public func fetchObjectIDs<T: NSManagedObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
return self.fetchObjectIDs(from, fetchClauses)
}
@nonobjc
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
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchObjectIDs(fetchRequest.dynamicCast())
}
@nonobjc
internal func fetchObjectIDs(_ fetchRequest: NSFetchRequest<NSManagedObjectID>) -> [NSManagedObjectID]? {
var fetchResults: [NSManagedObjectID]?
var fetchError: Error?
self.performAndWait {
var fetchResults: [T]?
var fetchError: ErrorType?
self.performBlockAndWait {
do {
fetchResults = try self.fetch(fetchRequest)
fetchResults = try self.executeFetchRequest(fetchRequest) as? [T]
}
catch {
@@ -231,20 +120,291 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
)
return nil
}
return fetchResults?.first
}
// MARK: Internal: Fetch All
@nonobjc
internal 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]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchRequest.fetchLimit = 0
fetchRequest.resultType = .ManagedObjectResultType
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchAll(fetchRequest)
}
@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: QueryableSource
// MARK: Internal: Count
@nonobjc
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
internal 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? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchCount(fetchRequest)
}
@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? {
return self.fetchObjectID(from, fetchClauses)
}
@nonobjc
internal 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
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchObjectID(fetchRequest)
}
@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]? {
return self.fetchObjectIDs(from, fetchClauses)
}
@nonobjc
internal 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
fetchClauses.forEach { $0.applyToFetchRequest(fetchRequest) }
guard storeFound else {
return nil
}
return self.fetchObjectIDs(fetchRequest)
}
@nonobjc
internal func fetchObjectIDs(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
}
// MARK: Internal: Delete All
@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? {
return self.queryValue(from, selectClause, queryClauses)
}
@nonobjc
public func queryValue<T: NSManagedObject, U: SelectValueResultType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
internal 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)
@@ -263,13 +423,82 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
}
@nonobjc
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
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]]? {
return self.queryAttributes(from, selectClause, queryClauses)
}
@nonobjc
public func queryAttributes<T: NSManagedObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
internal func queryAttributes<T: NSManagedObject>(from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? {
let fetchRequest = CoreStoreFetchRequest()
let storeFound = from.applyToFetchRequest(fetchRequest, context: self)
@@ -286,210 +515,16 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
return self.queryAttributes(fetchRequest)
}
// MARK: FetchableSource, QueryableSource
@nonobjc
public func internalContext() -> NSManagedObjectContext {
internal func queryAttributes(fetchRequest: NSFetchRequest) -> [[NSString: AnyObject]]? {
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 {
var fetchResults: [AnyObject]?
var fetchError: ErrorType?
self.performBlockAndWait {
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
}
@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)
fetchResults = try self.executeFetchRequest(fetchRequest)
}
catch {
@@ -507,67 +542,4 @@ 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.parent {
if let parentContext = self.parentContext {
return parentContext.parentStack
}
@@ -47,7 +47,7 @@ internal extension NSManagedObjectContext {
}
set {
guard self.parent == nil else {
guard self.parentContext == 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,20 +72,18 @@ internal extension NSManagedObjectContext {
#if os(iOS) || os(OSX)
context.observerForDidImportUbiquitousContentChangesNotification = NotificationObserver(
notificationName: NSNotification.Name.NSPersistentStoreDidImportUbiquitousContentChanges,
notificationName: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
object: coordinator,
closure: { [weak context] (note) -> Void in
context?.perform { () -> Void in
context?.performBlock { () -> Void in
if let updatedObjectIDs = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObjectID>) {
let updatedObjectIDs = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObjectID>) ?? []
for objectID in updatedObjectIDs {
for objectID in updatedObjectIDs {
context?.object(with: objectID).willAccessValue(forKey: nil)
}
context?.objectWithID(objectID).willAccessValueForKey(nil)
}
context?.mergeChanges(fromContextDidSave: note)
context?.mergeChangesFromContextDidSaveNotification(note)
}
}
)
@@ -96,15 +94,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.parent = rootContext
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.parentContext = rootContext
context.mergePolicy = NSRollbackMergePolicy
context.undoManager = nil
context.setupForCoreStoreWithContextName("com.corestore.maincontext")
context.observerForDidSaveNotification = NotificationObserver(
notificationName: NSNotification.Name.NSManagedObjectContextDidSave,
notificationName: NSManagedObjectContextDidSaveNotification,
object: rootContext,
closure: { [weak context] (note) -> Void in
@@ -115,22 +113,21 @@ internal extension NSManagedObjectContext {
}
let mergeChanges = { () -> Void in
if let updatedObjects = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>) {
let updatedObjects = (note.userInfo?[NSUpdatedObjectsKey] as? Set<NSManagedObject>) ?? []
for object in updatedObjects {
for object in updatedObjects {
context.object(with: object.objectID).willAccessValue(forKey: nil)
}
context.objectWithID(object.objectID).willAccessValueForKey(nil)
}
context.mergeChanges(fromContextDidSave: note)
context.mergeChangesFromContextDidSaveNotification(note)
}
if rootContext.isSavingSynchronously == true {
context.performAndWait(mergeChanges)
context.performBlockAndWait(mergeChanges)
}
else {
context.perform(mergeChanges)
context.performBlock(mergeChanges)
}
}
)

View File

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

View File

@@ -34,37 +34,32 @@ internal extension NSManagedObjectModel {
// MARK: Internal
@nonobjc
internal static func fromBundle(_ bundle: Bundle, modelName: String, modelVersionHints: Set<String> = []) -> NSManagedObjectModel {
internal static func fromBundle(bundle: NSBundle, modelName: String, modelVersionHints: Set<String> = []) -> NSManagedObjectModel {
guard let modelFilePath = bundle.path(forResource: modelName, ofType: "momd") else {
guard let modelFilePath = bundle.pathForResource(modelName, ofType: "momd") else {
// For users migrating from very old Xcode versions: Old xcdatamodel files are not contained inside xcdatamodeld (with a "d"), and will thus fail this check. If that was the case, create a new xcdatamodeld file and copy all contents into the new model.
let foundModels = bundle
.paths(forResourcesOfType: "momd", inDirectory: nil)
.map({ ($0 as NSString).lastPathComponent })
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle \"\(bundle.bundleIdentifier ?? "<nil>")\". Other model files in bundle: \(foundModels.coreStoreDumpString)")
CoreStore.abort("Could not find \"\(modelName).momd\" from the bundle. \(bundle)")
}
let modelFileURL = URL(fileURLWithPath: modelFilePath)
let versionInfoPlistURL = modelFileURL.appendingPathComponent("VersionInfo.plist", isDirectory: false)
let modelFileURL = NSURL(fileURLWithPath: modelFilePath)
let versionInfoPlistURL = modelFileURL.URLByAppendingPathComponent("VersionInfo.plist", isDirectory: false)
guard let versionInfo = NSDictionary(contentsOf: versionInfoPlistURL),
guard let versionInfo = NSDictionary(contentsOfURL: versionInfoPlistURL),
let versionHashes = versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject] else {
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel.self)) metadata from path \"\(versionInfoPlistURL)\".")
CoreStore.abort("Could not load \(cs_typeName(NSManagedObjectModel)) metadata from path \"\(versionInfoPlistURL)\".")
}
let modelVersions = Set(versionHashes.keys)
let currentModelVersion: String
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String,
modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
if let plistModelVersion = versionInfo["NSManagedObjectModel_CurrentVersionName"] as? String where modelVersionHints.isEmpty || modelVersionHints.contains(plistModelVersion) {
currentModelVersion = plistModelVersion
}
else if let resolvedVersion = modelVersions.intersection(modelVersionHints).first {
else if let resolvedVersion = modelVersions.intersect(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
@@ -74,7 +69,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)\"."
)
}
@@ -85,10 +80,10 @@ internal extension NSManagedObjectModel {
CoreStore.abort("No model files were found in URL \"\(modelFileURL)\".")
}
var modelVersionFileURL: URL?
var modelVersionFileURL: NSURL?
for modelVersion in modelVersions {
let fileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
let fileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)
if modelVersion == currentModelVersion {
@@ -97,13 +92,13 @@ internal extension NSManagedObjectModel {
}
precondition(
NSManagedObjectModel(contentsOf: fileURL) != nil,
NSManagedObjectModel(contentsOfURL: fileURL) != nil,
"Could not find the \"\(modelVersion).mom\" version file for the model at URL \"\(modelFileURL)\"."
)
}
if let modelVersionFileURL = modelVersionFileURL,
let rootModel = NSManagedObjectModel(contentsOf: modelVersionFileURL) {
let rootModel = NSManagedObjectModel(contentsOfURL: modelVersionFileURL) {
rootModel.modelVersionFileURL = modelVersionFileURL
rootModel.modelVersions = modelVersions
@@ -111,7 +106,7 @@ internal extension NSManagedObjectModel {
return rootModel
}
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel.self)) from the model at URL \"\(modelFileURL)\".")
CoreStore.abort("Could not create an \(cs_typeName(NSManagedObjectModel)) from the model at URL \"\(modelFileURL)\".")
}
@nonobjc
@@ -123,7 +118,7 @@ internal extension NSManagedObjectModel {
&PropertyKeys.currentModelVersion,
inObject: self
)
return value as String?
return value as? String
}
set {
@@ -157,7 +152,7 @@ internal extension NSManagedObjectModel {
}
@nonobjc
internal func entityNameForClass(_ entityClass: AnyClass) -> String {
internal func entityNameForClass(entityClass: AnyClass) -> String {
return self.entityNameMapping[NSStringFromClass(entityClass)]!
}
@@ -188,14 +183,14 @@ internal extension NSManagedObjectModel {
}
guard let modelFileURL = self.modelFileURL,
let modelVersions = self.modelVersions,
modelVersions.contains(modelVersion) else {
let modelVersions = self.modelVersions
where modelVersions.contains(modelVersion) else {
return nil
}
let versionModelFileURL = modelFileURL.appendingPathComponent("\(modelVersion).mom", isDirectory: false)
guard let model = NSManagedObjectModel(contentsOf: versionModelFileURL) else {
let versionModelFileURL = modelFileURL.URLByAppendingPathComponent("\(modelVersion).mom", isDirectory: false)
guard let model = NSManagedObjectModel(contentsOfURL: versionModelFileURL) else {
return nil
}
@@ -207,15 +202,15 @@ internal extension NSManagedObjectModel {
}
@nonobjc
internal subscript(metadata: [String: Any]) -> NSManagedObjectModel? {
internal subscript(metadata: [String: AnyObject]) -> NSManagedObjectModel? {
guard let modelHashes = metadata[NSStoreModelVersionHashesKey] as? [String : Data] else {
guard let modelHashes = metadata[NSStoreModelVersionHashesKey] as? [String : NSData] else {
return nil
}
for modelVersion in self.modelVersions ?? [] {
if let versionModel = self[modelVersion], modelHashes == versionModel.entityVersionHashesByName {
if let versionModel = self[modelVersion] where modelHashes == versionModel.entityVersionHashesByName {
return versionModel
}
@@ -227,16 +222,16 @@ internal extension NSManagedObjectModel {
// MARK: Private
@nonobjc
private var modelFileURL: URL? {
private var modelFileURL: NSURL? {
get {
return self.modelVersionFileURL?.deletingLastPathComponent()
return self.modelVersionFileURL?.URLByDeletingLastPathComponent
}
}
@nonobjc
private var modelVersionFileURL: URL? {
private var modelVersionFileURL: NSURL? {
get {
@@ -244,12 +239,12 @@ internal extension NSManagedObjectModel {
&PropertyKeys.modelVersionFileURL,
inObject: self
)
return value as URL?
return value
}
set {
cs_setAssociatedCopiedObject(
newValue as NSURL?,
newValue,
forKey: &PropertyKeys.modelVersionFileURL,
inObject: self
)
@@ -275,7 +270,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
fileprivate class StorageObject: NSObject {
private class StorageObject: NSObject {
// MARK: Private
@nonobjc
fileprivate let storageInterface: StorageInterface?
private let storageInterface: StorageInterface?
@nonobjc
fileprivate init(_ storage: StorageInterface?) {
private init(_ storage: StorageInterface?) {
self.storageInterface = storage
}

View File

@@ -26,53 +26,134 @@
import Foundation
import CoreData
#if USE_FRAMEWORKS
import GCDKit
#endif
// MARK: - NSPersistentStoreCoordinator
internal extension NSPersistentStoreCoordinator {
@nonobjc
internal func performAsynchronously(_ closure: @escaping () -> Void) {
internal func performAsynchronously(closure: () -> Void) {
self.perform(closure)
#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
}
@nonobjc
internal func performSynchronously<T>(_ closure: @escaping () -> T) -> T {
internal func performSynchronously<T>(closure: () -> T) -> T {
var result: T?
self.performAndWait {
#if USE_FRAMEWORKS
result = closure()
}
self.performBlockAndWait {
result = closure()
}
#else
if #available(iOS 8.0, *) {
self.performBlockAndWait {
result = closure()
}
}
else {
self.lock()
cs_autoreleasepool {
result = closure()
}
self.unlock()
}
#endif
return result!
}
@nonobjc
internal func performSynchronously<T>(_ closure: @escaping () throws -> T) throws -> T {
internal func performSynchronously<T>(closure: () throws -> T) throws -> T {
var closureError: Error?
var closureError: ErrorType?
var result: T?
self.performAndWait {
#if USE_FRAMEWORKS
do {
self.performBlockAndWait {
result = try closure()
do {
result = try closure()
}
catch {
closureError = error
}
}
catch {
#else
if #available(iOS 8.0, *) {
closureError = error
self.performBlockAndWait {
do {
result = try closure()
}
catch {
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: URL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore {
internal func addPersistentStoreSynchronously(storeType: String, configuration: String?, URL storeURL: NSURL?, options: [NSObject : AnyObject]?) throws -> NSPersistentStore {
var store: NSPersistentStore?
var storeError: NSError?
@@ -80,10 +161,10 @@ internal extension NSPersistentStoreCoordinator {
do {
store = try self.addPersistentStore(
ofType: storeType,
configurationName: configuration,
at: storeURL,
store = try self.addPersistentStoreWithType(
storeType,
configuration: configuration,
URL: storeURL,
options: options
)
}
@@ -92,10 +173,12 @@ 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: Notification.Name, object: Any?, queue: OperationQueue? = nil, closure: @escaping (_ note: Notification) -> Void) {
init(notificationName: String, object: AnyObject?, queue: NSOperationQueue? = nil, closure: (note: NSNotification) -> Void) {
self.observer = NotificationCenter.default.addObserver(
forName: notificationName,
self.observer = NSNotificationCenter.defaultCenter().addObserverForName(
notificationName,
object: object,
queue: queue,
using: closure
usingBlock: closure
)
}
deinit {
NotificationCenter.default.removeObserver(self.observer)
NSNotificationCenter.defaultCenter().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 as Any)
("result", self.result)
)
}
}
@@ -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.append(flags.joined(separator: ",\n"))
string.appendContentsOf(flags.joinWithSeparator(",\n"))
string.indent(1)
string.append("\n]")
string.appendContentsOf("\n]")
return string
}
}
@@ -117,30 +117,30 @@ extension CoreStoreError: CustomDebugStringConvertible, CoreStoreDebugStringConv
let firstLine: String
var info: DumpInfo = [
("errorDomain", type(of: self).errorDomain),
("errorCode", self.errorCode),
("_domain", self._domain),
("_code", self._code),
]
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 as Any),
("storeOptions", self.storeOptions as Any),
("configuration", self.configuration),
("storeOptions", self.storeOptions),
("cacheFileURL", self.cacheFileURL),
("cloudStorageOptions", self.cloudStorageOptions)
)
@@ -283,8 +283,8 @@ extension InMemoryStore: CustomDebugStringConvertible, CoreStoreDebugStringConve
return createFormattedString(
"(", ")",
("configuration", self.configuration as Any),
("storeOptions", self.storeOptions as Any)
("configuration", self.configuration),
("storeOptions", self.storeOptions)
)
}
}
@@ -309,7 +309,7 @@ extension Into: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("entityClass", self.entityClass),
("configuration", self.configuration as Any),
("configuration", self.configuration),
("inferStoreIfPossible", self.inferStoreIfPossible)
)
}
@@ -334,8 +334,8 @@ extension LegacySQLiteStore: CustomDebugStringConvertible, CoreStoreDebugStringC
return createFormattedString(
"(", ")",
("configuration", self.configuration as Any),
("storeOptions", self.storeOptions as Any),
("configuration", self.configuration),
("storeOptions", self.storeOptions),
("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 as Any)
("indexTitle", self.sectionInfo.indexTitle)
)
}
}
@@ -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.append(flags.joined(separator: ",\n"))
string.appendContentsOf(flags.joinWithSeparator(",\n"))
string.indent(1)
string.append("\n]")
string.appendContentsOf("\n]")
return string
}
}
@@ -465,7 +465,7 @@ extension MigrationChain: CustomDebugStringConvertible, CoreStoreDebugStringConv
steps.append(nextVersion)
version = nextVersion
}
paths.append(steps.joined(separator: ""))
paths.append(steps.joinWithSeparator(""))
}
switch paths.count {
@@ -479,10 +479,10 @@ extension MigrationChain: CustomDebugStringConvertible, CoreStoreDebugStringConv
var string = "["
paths.forEach {
string.append("\n\($0);")
string.appendContentsOf("\n\($0);")
}
string.indent(1)
string.append("\n]")
string.appendContentsOf("\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 as Any)
("object", self.object)
)
}
}
@@ -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 as Any),
("storeOptions", self.storeOptions as Any),
("configuration", self.configuration),
("storeOptions", self.storeOptions),
("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 as Any)
("result", self.result)
)
}
}
@@ -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: type(of: any)))) "
string.append(formattedValue(any))
var string = "(\(String(reflecting: any.dynamicType))) "
string.appendContentsOf(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, _ in
string.appendDumpInfo(key, value)
}
string.indent(1)
string.append("\n\(lastLine)")
string.appendContentsOf("\n\(lastLine)")
return string
}
fileprivate extension String {
private extension String {
fileprivate static func indention(_ level: Int = 1) -> String {
private static func indention(level: Int = 1) -> String {
return String(repeating: " ", count: level * 4)
return String(count: level * 4, repeatedValue: Character(" "))
}
fileprivate func trimSwiftModuleName() -> String {
private func trimSwiftModuleName() -> String {
if self.hasPrefix("Swift.") {
return self.substring(from: "Swift.".endIndex)
return self.substringFromIndex("Swift.".endIndex)
}
return self
}
fileprivate mutating func indent(_ level: Int) {
private mutating func indent(level: Int) {
self = self.replacingOccurrences(of: "\n", with: "\n\(String.indention(level))")
self = self.stringByReplacingOccurrencesOfString("\n", withString: "\n\(String.indention(level))")
}
fileprivate mutating func appendDumpInfo(_ key: String, _ value: Any) {
private mutating func appendDumpInfo(key: String, _ value: Any) {
self.append("\n.\(key) = \(formattedValue(value));")
self.appendContentsOf("\n.\(key) = \(formattedValue(value));")
}
}
@@ -979,17 +979,17 @@ extension Array: CoreStoreDebugStringConvertible {
var string = "\(self.count) item(s) ["
if self.isEmpty {
string.append("]")
string.appendContentsOf("]")
return string
}
else {
for (index, item) in self.enumerated() {
for (index, item) in self.enumerate() {
string.append("\n\(index) = \(formattedValue(item));")
string.appendContentsOf("\n\(index) = \(formattedValue(item));")
}
string.indent(1)
string.append("\n]")
string.appendContentsOf("\n]")
return string
}
}
@@ -1002,17 +1002,17 @@ extension Dictionary: CoreStoreDebugStringConvertible {
var string = "\(self.count) key-value(s) ["
if self.isEmpty {
string.append("]")
string.appendContentsOf("]")
return string
}
else {
for (key, value) in self {
string.append("\n\(formattedValue(key)) = \(formattedValue(value));")
string.appendContentsOf("\n\(formattedValue(key)) = \(formattedValue(value));")
}
string.indent(1)
string.append("\n]")
string.appendContentsOf("\n]")
return string
}
}
@@ -1025,21 +1025,21 @@ extension NSAttributeDescription: CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("attributeType", self.attributeType),
("attributeValueClassName", self.attributeValueClassName as Any),
("defaultValue", self.defaultValue as Any),
("valueTransformerName", self.valueTransformerName as Any),
("attributeValueClassName", self.attributeValueClassName),
("defaultValue", self.defaultValue),
("valueTransformerName", self.valueTransformerName),
("allowsExternalBinaryDataStorage", self.allowsExternalBinaryDataStorage),
("entity.name", self.entity.name as Any),
("entity.name", self.entity.name),
("name", self.name),
("isOptional", self.isOptional),
("isTransient", self.isTransient),
("userInfo", self.userInfo as Any),
("isIndexed", self.isIndexed),
("optional", self.optional),
("transient", self.transient),
("userInfo", self.userInfo),
("indexed", self.indexed),
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier as Any),
("isIndexedBySpotlight", self.isIndexedBySpotlight),
("isStoredInExternalRecord", self.isStoredInExternalRecord),
("renamingIdentifier", self.renamingIdentifier as Any)
("versionHashModifier", self.versionHashModifier),
("indexedBySpotlight", self.indexedBySpotlight),
("storedInExternalRecord", self.storedInExternalRecord),
("renamingIdentifier", self.renamingIdentifier)
)
}
}
@@ -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 Bundle: CoreStoreDebugStringConvertible {
extension NSBundle: CoreStoreDebugStringConvertible {
public var coreStoreDumpString: String {
return "\(self.bundleIdentifier.flatMap({ "\"\($0)\"" }) ?? "<unknown bundle identifier>") (\(self.bundleURL.lastPathComponent))"
return "\(self.bundleIdentifier.flatMap({ "\"\($0)\"" }) ?? "<unknown bundle identifier>") (\(self.bundleURL.lastPathComponent ?? "<unknown bundle URL>"))"
}
}
@@ -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 as Any),
("isAbstract", self.isAbstract),
("superentity?.name", self.superentity?.name as Any),
("name", self.name),
("abstract", self.abstract),
("superentity?.name", self.superentity?.name),
("subentities", self.subentities.map({ $0.name })),
("properties", self.properties),
("userInfo", self.userInfo as Any),
("userInfo", self.userInfo),
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier as Any),
("renamingIdentifier", self.renamingIdentifier as Any),
("versionHashModifier", self.versionHashModifier),
("renamingIdentifier", self.renamingIdentifier),
("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 as Any),
("isTemporaryID", self.isTemporaryID as Any),
("persistentStore?.url", self.persistentStore?.url as Any)
"\(self.URIRepresentation().coreStoreDumpString) (", ")",
("entity.name", self.entity.name),
("temporaryID", self.temporaryID),
("persistentStore?.URL", self.persistentStore?.URL)
)
}
}
@@ -1177,24 +1177,24 @@ extension NSRelationshipDescription: CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("destinationEntity?.name", self.destinationEntity?.name as Any),
("inverseRelationship?.name", self.inverseRelationship?.name as Any),
("destinationEntity?.name", self.destinationEntity?.name),
("inverseRelationship?.name", self.inverseRelationship?.name),
("minCount", self.minCount),
("maxCount", self.maxCount),
("deleteRule", self.deleteRule),
("isToMany", self.isToMany),
("isOrdered", self.isOrdered),
("entity.name", self.entity.name as Any),
("toMany", self.toMany),
("ordered", self.ordered),
("entity.name", self.entity.name),
("name", self.name),
("isOptional", self.isOptional),
("isTransient", self.isTransient),
("userInfo", self.userInfo as Any),
("isIndexed", self.isIndexed),
("optional", self.optional),
("transient", self.transient),
("userInfo", self.userInfo),
("indexed", self.indexed),
("versionHash", self.versionHash),
("versionHashModifier", self.versionHashModifier as Any),
("isIndexedBySpotlight", self.isIndexedBySpotlight),
("isStoredInExternalRecord", self.isStoredInExternalRecord),
("renamingIdentifier", self.renamingIdentifier as Any)
("versionHashModifier", self.versionHashModifier),
("indexedBySpotlight", self.indexedBySpotlight),
("storedInExternalRecord", self.storedInExternalRecord),
("renamingIdentifier", self.renamingIdentifier)
)
}
}
@@ -1205,14 +1205,14 @@ extension NSSortDescriptor: CoreStoreDebugStringConvertible {
return createFormattedString(
"(", ")",
("key", self.key as Any),
("key", self.key),
("ascending", self.ascending),
("selector", self.selector as Any)
("selector", self.selector)
)
}
}
extension URL: CoreStoreDebugStringConvertible {
extension NSURL: CoreStoreDebugStringConvertible {
public var coreStoreDumpString: String {
@@ -1236,7 +1236,7 @@ extension Selector: CoreStoreDebugStringConvertible {
public var coreStoreDumpString: String {
return "\"\(self)\""
return self == nil ? "nil" : "\"\(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( _ condition: @autoclosure () -> Bool, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
internal static func assert(@autoclosure condition: () -> Bool, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.assert(
condition,
@@ -71,7 +71,8 @@ public extension CoreStore {
)
}
internal static func abort(_ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) -> Never {
@noreturn
internal static func abort(message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
self.logger.abort(
message,

View File

@@ -33,25 +33,20 @@ 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(...)`, `assert(...)`, and `abort(...)` 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(...)`, `handleError(...)`, and `assert(...)` are not tied to a specific queue/thread, so it is the implementer's job to handle thread-safety.
*/
public protocol CoreStoreLogger {
/**
When `true`, all `NSManagedObject` attribute and relationship access will raise an assertion when executed on the wrong transaction/datastack queue. Defaults to `false` if not implemented.
*/
var enableObjectConcurrencyDebugging: Bool { get set }
/**
Handles log messages sent by the `CoreStore` framework.
@@ -61,7 +56,7 @@ public protocol CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles errors sent by the `CoreStore` framework.
@@ -72,7 +67,7 @@ public protocol CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
/**
Handles assertions made throughout the `CoreStore` framework.
@@ -83,29 +78,41 @@ public protocol CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString)
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> 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 `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.
- 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.
- 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)
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)
}
extension CoreStoreLogger {
public var enableObjectConcurrencyDebugging: Bool {
get { return false }
set {}
/**
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,14 +30,13 @@ 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 {
/**
When `true`, all `NSManagedObject` attribute and relationship access will raise an assertion when executed on the wrong transaction/datastack queue. Defaults to `false`.
*/
public var enableObjectConcurrencyDebugging: Bool = false
/**
Creates a `DefaultLogger`.
*/
@@ -52,30 +51,30 @@ public final class DefaultLogger: CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func log(level 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)] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
Swift.print("\(icon) [CoreStore: \(levelString)] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
#endif
}
@@ -88,10 +87,10 @@ public final class DefaultLogger: CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
Swift.print("⚠️ [CoreStore: Error] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n \(error)\n")
Swift.print("⚠️ [CoreStore: Error] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n \(error)\n")
#endif
}
@@ -104,30 +103,30 @@ public final class DefaultLogger: CoreStoreLogger {
- parameter lineNumber: the source line number
- parameter functionName: the source function name
*/
public func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
public func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
#if DEBUG
if condition() {
return
}
Swift.print("❗ [CoreStore: Assertion Failure] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message())\n")
Swift.print("❗ [CoreStore: Assertion Failure] \((fileName.stringValue 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: 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.
- 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.
- 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] \((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
Swift.print("❗ [CoreStore: Fatal Error] \((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ \(message)\n")
Swift.fatalError(file: fileName, line: UInt(lineNumber))
}
}

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