mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-12 20:30:30 +01:00
Compare commits
275 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1740d168c8 | ||
|
|
d42b397090 | ||
|
|
058cc1915b | ||
|
|
02d5bf85ae | ||
|
|
ed3d21db77 | ||
|
|
67bb9340c7 | ||
|
|
5d49bd79f2 | ||
|
|
9f397b4337 | ||
|
|
7508d150d6 | ||
|
|
239db8168d | ||
|
|
30ab4386bf | ||
|
|
08053ccb15 | ||
|
|
367cfea8a7 | ||
|
|
5d3b7e3dab | ||
|
|
fe7e6e7b84 | ||
|
|
b2dba0d6fd | ||
|
|
6f290213fa | ||
|
|
0ab52d2f43 | ||
|
|
bf8a1062e0 | ||
|
|
0e254867b6 | ||
|
|
0376ac6908 | ||
|
|
b3421888a6 | ||
|
|
7b3f4ae0a4 | ||
|
|
b4e12cc922 | ||
|
|
6c282b18af | ||
|
|
ebbde8b7b6 | ||
|
|
a1407e4121 | ||
|
|
99b871b97a | ||
|
|
1cd3c4fcf4 | ||
|
|
e09ac9ee00 | ||
|
|
4b0d134acb | ||
|
|
eeec3979ee | ||
|
|
5b365c642d | ||
|
|
635201868a | ||
|
|
db4426e6b9 | ||
|
|
41902fee2e | ||
|
|
9239370793 | ||
|
|
a4d2f326a5 | ||
|
|
9f54ec26e2 | ||
|
|
9425cb56d7 | ||
|
|
1de56d2776 | ||
|
|
b3261ea930 | ||
|
|
88dd7aef72 | ||
|
|
2863605d84 | ||
|
|
94d9116299 | ||
|
|
57ddbbd515 | ||
|
|
78954b9d78 | ||
|
|
4eb06c9858 | ||
|
|
0d634c1dcc | ||
|
|
84f3740ea1 | ||
|
|
6dc48b6af7 | ||
|
|
09ce2816bf | ||
|
|
62e962eebe | ||
|
|
682472c1bd | ||
|
|
46ab70b839 | ||
|
|
ac8304f977 | ||
|
|
5777831565 | ||
|
|
42d1f41939 | ||
|
|
8c30ec3a3d | ||
|
|
237a1b648e | ||
|
|
614f1572c2 | ||
|
|
a48f16aa8c | ||
|
|
cdbadae002 | ||
|
|
4a28a39df6 | ||
|
|
5febf2542d | ||
|
|
c21ab11a41 | ||
|
|
10cd18dbf0 | ||
|
|
8409a13289 | ||
|
|
a9a73fa5c4 | ||
|
|
82cae2e11e | ||
|
|
42caee2418 | ||
|
|
1dea1d0d06 | ||
|
|
d344b9d878 | ||
|
|
95c1ce52cc | ||
|
|
cc346816d6 | ||
|
|
f14b561c33 | ||
|
|
6f655951aa | ||
|
|
ff8fbae568 | ||
|
|
4d4b02d076 | ||
|
|
06c0981ded | ||
|
|
20d581d536 | ||
|
|
45e110755d | ||
|
|
ab40532801 | ||
|
|
40f458a09c | ||
|
|
1ad233ca9d | ||
|
|
3a8e394272 | ||
|
|
1f54daa528 | ||
|
|
f25879b6fe | ||
|
|
8fa3109e91 | ||
|
|
808e8ff97a | ||
|
|
30685d4355 | ||
|
|
7152962026 | ||
|
|
91735e38d1 | ||
|
|
333a50ad9e | ||
|
|
b7a602fc67 | ||
|
|
2ff7ecef96 | ||
|
|
e3f9139304 | ||
|
|
4aa461872f | ||
|
|
3d43314076 | ||
|
|
7b1075b759 | ||
|
|
0c29e07ddb | ||
|
|
ce91cf22f9 | ||
|
|
2dd033c002 | ||
|
|
c7fcba112e | ||
|
|
c8b1c4358f | ||
|
|
5431e2e974 | ||
|
|
83e6082c56 | ||
|
|
c7bdbbde57 | ||
|
|
abf15c8aa8 | ||
|
|
d9db7e4a82 | ||
|
|
65dbc22ddd | ||
|
|
51961dd737 | ||
|
|
18a7055cdf | ||
|
|
4b9fddad6a | ||
|
|
fbe7bd7bf8 | ||
|
|
15edabdbb5 | ||
|
|
f447bcfb95 | ||
|
|
15e5e4fdf6 | ||
|
|
583c6b7249 | ||
|
|
18b933957e | ||
|
|
2c7039232e | ||
|
|
d3b3b5ff4a | ||
|
|
d90e8d1303 | ||
|
|
b55dd13dff | ||
|
|
66dd5b6f27 | ||
|
|
49c4b770eb | ||
|
|
662aaa1e75 | ||
|
|
dd4e47d7f9 | ||
|
|
9ea5073bc8 | ||
|
|
e314db8f56 | ||
|
|
48d936d068 | ||
|
|
b2ff8a15ef | ||
|
|
8a4d1cd7c6 | ||
|
|
8ce26c213d | ||
|
|
f3816b9abf | ||
|
|
21961780d4 | ||
|
|
305e2b61a0 | ||
|
|
0430f66240 | ||
|
|
65772edd00 | ||
|
|
02d7870d75 | ||
|
|
aca1709e13 | ||
|
|
b6ee0b014f | ||
|
|
e37186da73 | ||
|
|
588fa35c84 | ||
|
|
f6614cda66 | ||
|
|
639574d8c2 | ||
|
|
094703155c | ||
|
|
6dd254e713 | ||
|
|
204025721c | ||
|
|
27ffc1d225 | ||
|
|
ba6f0c39d5 | ||
|
|
ab2eac8f6c | ||
|
|
f460a0b30f | ||
|
|
50bc3ace06 | ||
|
|
d2ddf2002f | ||
|
|
b4117eeb02 | ||
|
|
106275b2dd | ||
|
|
08d9298be0 | ||
|
|
ff0c4d94fc | ||
|
|
50e50c0613 | ||
|
|
5c8a0e425b | ||
|
|
03b71caf7e | ||
|
|
7ff29d6086 | ||
|
|
8d86425875 | ||
|
|
97242d9726 | ||
|
|
780ff4e60b | ||
|
|
11743dfb5f | ||
|
|
9eaf85388c | ||
|
|
06635c9d2f | ||
|
|
1d2eef7894 | ||
|
|
85ed815ec2 | ||
|
|
096e5493a6 | ||
|
|
0aa8c03424 | ||
|
|
4ead3c34dd | ||
|
|
645034dde5 | ||
|
|
85706a3c57 | ||
|
|
c5ae4606b9 | ||
|
|
fa682215c5 | ||
|
|
e814733ae9 | ||
|
|
e2236698fa | ||
|
|
be5da632b3 | ||
|
|
dc73cd6dd9 | ||
|
|
7beb3bec75 | ||
|
|
53100b202d | ||
|
|
cc84b1f8bd | ||
|
|
474f52ed2b | ||
|
|
16225fc4c6 | ||
|
|
03bb7619da | ||
|
|
1bfb7451c3 | ||
|
|
3e082d5ed4 | ||
|
|
e45d67252c | ||
|
|
3d427c29c4 | ||
|
|
1068517b94 | ||
|
|
0d23ce1598 | ||
|
|
fd1ce20863 | ||
|
|
2c5fa63f40 | ||
|
|
78e43a37a5 | ||
|
|
fde85a9743 | ||
|
|
dbbc0adae5 | ||
|
|
2a62770552 | ||
|
|
f436b26e8e | ||
|
|
c566226747 | ||
|
|
cd405e038e | ||
|
|
92a37053b0 | ||
|
|
0b57cff27d | ||
|
|
3ebc44b546 | ||
|
|
68f1027ba7 | ||
|
|
005729be85 | ||
|
|
8bac4aa901 | ||
|
|
da170c7e51 | ||
|
|
211e69023e | ||
|
|
2912dcf010 | ||
|
|
3e00a3da06 | ||
|
|
a33e248828 | ||
|
|
75e14fbbed | ||
|
|
9922deac4d | ||
|
|
86be046c9f | ||
|
|
0f10bc3349 | ||
|
|
9685f0aef2 | ||
|
|
1e51000155 | ||
|
|
3bd459bb1a | ||
|
|
c89bc3c227 | ||
|
|
0f405a50aa | ||
|
|
f5e1643ef7 | ||
|
|
f62137fb58 | ||
|
|
37fbedd799 | ||
|
|
28b43f33fa | ||
|
|
81a72f29ea | ||
|
|
f7aaf4fb2a | ||
|
|
a52acf2ebd | ||
|
|
74c64619c3 | ||
|
|
4a5bc6450b | ||
|
|
fe69e7c6c4 | ||
|
|
ccf7c62aad | ||
|
|
f36cb8af63 | ||
|
|
10ccadd96c | ||
|
|
5c0e78bd53 | ||
|
|
8a09688117 | ||
|
|
a366bcf1a3 | ||
|
|
fcd4be9011 | ||
|
|
535eb76adc | ||
|
|
c6e68ac24f | ||
|
|
aff966aac9 | ||
|
|
32743b3aee | ||
|
|
a20ad87583 | ||
|
|
a11915db12 | ||
|
|
961f39a806 | ||
|
|
3096cb784c | ||
|
|
809aa4ff96 | ||
|
|
8d926d25ec | ||
|
|
790454f514 | ||
|
|
9a38707c58 | ||
|
|
fb7e2f7f7f | ||
|
|
f72efc80b2 | ||
|
|
fcda5399da | ||
|
|
fd3a9b00ec | ||
|
|
f56c37f9ee | ||
|
|
5f5000218a | ||
|
|
e8eb309d82 | ||
|
|
d0c3203e63 | ||
|
|
f5b3901caa | ||
|
|
1a99fea820 | ||
|
|
195b60615b | ||
|
|
2c394965b8 | ||
|
|
746d697691 | ||
|
|
eced8f2e93 | ||
|
|
3b735d07ec | ||
|
|
5eb5476e3a | ||
|
|
6a42a0054e | ||
|
|
23e12c4539 | ||
|
|
ca9798be14 | ||
|
|
6e01a58c85 | ||
|
|
f618617053 | ||
|
|
49b8b9c372 | ||
|
|
7f9a915d71 |
2
.cocoapods.yml
Normal file
2
.cocoapods.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
try:
|
||||
project: 'CoreStore.xcworkspace'
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,3 +7,5 @@ CoreStore.xcworkspace/xcuserdata
|
||||
.DS_Store
|
||||
DerivedData
|
||||
*.orig
|
||||
build
|
||||
Playground_macOS.playground/playground.xcworkspace/xcuserdata
|
||||
|
||||
15
.jazzy.yaml
Normal file
15
.jazzy.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
author: John Estropia
|
||||
author_url: https://github.com/JohnEstropia
|
||||
github_url: https://github.com/JohnEstropia/CoreStore
|
||||
module: CoreStore
|
||||
readme: README.md
|
||||
include: Sources/*
|
||||
output: docs
|
||||
theme: fullwidth
|
||||
clean: true
|
||||
skip_undocumented: true
|
||||
xcodebuild_arguments:
|
||||
- -sdk
|
||||
- iphonesimulator
|
||||
- -scheme
|
||||
- CoreStore iOS
|
||||
@@ -1 +0,0 @@
|
||||
3.1
|
||||
40
.travis.yml
40
.travis.yml
@@ -1,5 +1,5 @@
|
||||
language: objective-c
|
||||
osx_image: xcode8.3
|
||||
osx_image: xcode10.2
|
||||
sudo: false
|
||||
git:
|
||||
submodules: false
|
||||
@@ -10,26 +10,22 @@ env:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
- LANG=en_US.UTF-8
|
||||
matrix:
|
||||
- DESTINATION="OS=10.3,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.3,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.3,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.3 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.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.2 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.2 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.14 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=12.0,name=iPhone XS" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=11.0.1,name=iPhone 8" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.3.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=4.0,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=3.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator5.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=12.0,name=Apple TV 4K" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=11.0,name=Apple TV 4K (at 1080p)" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator12.0 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.23.0/Carthage.pkg"
|
||||
- sudo installer -pkg "Carthage.pkg" -target /
|
||||
- rm "Carthage.pkg"
|
||||
before_script:
|
||||
- carthage update --use-submodules
|
||||
- gem install cocoapods --no-rdoc --no-ri --no-document
|
||||
- gem install xcpretty --no-rdoc --no-ri --no-document
|
||||
- npm install ios-sim -g
|
||||
- ios-sim start --devicetypeid "com.apple.CoreSimulator.SimDeviceType.iPhone-8, 11.0"
|
||||
script:
|
||||
- set -o pipefail
|
||||
- xcodebuild -version
|
||||
@@ -38,8 +34,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.3" -destination "OS=10.3,name=iPhone 7" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
|
||||
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator10.3" -destination "OS=10.3,name=iPhone 7" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
|
||||
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c;
|
||||
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStoreDemo" -sdk "iphonesimulator12.0" -destination "OS=11.0.1,name=iPhone 8" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty -c;
|
||||
- if [ $POD_LINT == "YES" ]; then
|
||||
pod lib lint --quick;
|
||||
fi
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "CoreStore"
|
||||
s.version = "4.0.5"
|
||||
s.version = "6.3.2"
|
||||
s.swift_version = "5.0"
|
||||
s.license = "MIT"
|
||||
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
|
||||
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
||||
s.documentation_url = "https://JohnEstropia.github.io/CoreStore"
|
||||
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
|
||||
s.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" }
|
||||
s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s }
|
||||
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.osx.deployment_target = "10.10"
|
||||
s.watchos.deployment_target = "2.0"
|
||||
s.tvos.deployment_target = "9.0"
|
||||
s.ios.deployment_target = "10.0"
|
||||
s.osx.deployment_target = "10.12"
|
||||
s.watchos.deployment_target = "3.0"
|
||||
s.tvos.deployment_target = "10.0"
|
||||
|
||||
s.source_files = "Sources", "Sources/**/*.{swift,h,m}"
|
||||
s.public_header_files = "Sources/**/*.h"
|
||||
|
||||
BIN
CoreStore.sketch
BIN
CoreStore.sketch
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -89,6 +89,12 @@
|
||||
ReferencedContainer = "container:CoreStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-com.apple.CoreData.SQLDebug 2"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
@@ -265,18 +265,18 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = "John Rommel Estropia";
|
||||
TargetAttributes = {
|
||||
B54AAD481AF4D26E00848AE0 = {
|
||||
CreatedOnToolsVersion = 6.3;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 0900;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = B54AAD441AF4D26E00848AE0 /* Build configuration list for PBXProject "CoreStoreDemo" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
@@ -371,14 +371,22 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -402,11 +410,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -418,14 +428,22 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -442,9 +460,11 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
@@ -454,11 +474,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -467,12 +486,11 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
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;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/02.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -18,9 +18,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
|
||||
application.statusBarStyle = .lightContent
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10112" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
@@ -12,10 +14,10 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2018 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="440" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="q8C-V6-gXH">
|
||||
@@ -24,11 +26,11 @@
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CoreStore" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="273" width="440" height="57.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
|
||||
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12113" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Ni8-QF-XHB">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Ni8-QF-XHB">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12078"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
@@ -78,14 +75,14 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8b8-lM-Krq">
|
||||
<rect key="frame" x="15" y="13" width="28.5" height="19"/>
|
||||
<rect key="frame" x="16" y="13" width="28.5" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hR1-Zb-BOk">
|
||||
<rect key="frame" x="308" y="13" width="52" height="19"/>
|
||||
<rect key="frame" x="307" y="13" width="52" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="16"/>
|
||||
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -136,7 +133,7 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OQf-Bd-Zze">
|
||||
<rect key="frame" x="295" y="8" width="72" height="27.5"/>
|
||||
<rect key="frame" x="288" y="11" width="72" height="22"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<inset key="contentEdgeInsets" minX="7" minY="0.0" maxX="7" maxY="0.0"/>
|
||||
<state key="normal" title="mutate!"/>
|
||||
@@ -145,7 +142,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VZk-6K-4ut">
|
||||
<rect key="frame" x="15" y="8" width="270" height="27.5"/>
|
||||
<rect key="frame" x="22" y="11" width="256" height="22"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="17"/>
|
||||
<color key="textColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -275,18 +272,18 @@
|
||||
<rect key="frame" x="0.0" y="35" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AXm-KE-45G" id="9te-Wx-hkf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Accounts" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Q3n-Df-v1t">
|
||||
<rect key="frame" x="15" y="6" width="82" height="24"/>
|
||||
<rect key="frame" x="16" y="6" width="82" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Setting up multiple persistent store configurations" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Hbn-cf-Y7m">
|
||||
<rect key="frame" x="15" y="30" width="263.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="30" width="263.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -302,18 +299,18 @@
|
||||
<rect key="frame" x="0.0" y="85" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fsb-zw-8Ii" id="Upm-AO-Fw3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Colors" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="vpt-cT-gMo">
|
||||
<rect key="frame" x="15" y="6" width="56" height="24"/>
|
||||
<rect key="frame" x="16" y="6" width="56" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Observing list changes and single object changes" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ou9-TZ-8bf">
|
||||
<rect key="frame" x="15" y="30" width="260.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="30" width="260.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -329,18 +326,18 @@
|
||||
<rect key="frame" x="0.0" y="135" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ekW-PJ-mbo" id="CYq-mg-PVS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Placemarks" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UbU-Kd-yrY">
|
||||
<rect key="frame" x="15" y="6" width="100.5" height="24"/>
|
||||
<rect key="frame" x="16" y="6" width="100.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Making changes with transactions" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="uP1-Jc-o9v">
|
||||
<rect key="frame" x="15" y="30" width="179" height="13.5"/>
|
||||
<rect key="frame" x="16" y="30" width="179" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -356,18 +353,18 @@
|
||||
<rect key="frame" x="0.0" y="185" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ph1-8z-C1m" id="nNz-rd-ksg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Time Zones" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C8Y-0y-lEG">
|
||||
<rect key="frame" x="15" y="6" width="101.5" height="24"/>
|
||||
<rect key="frame" x="16" y="6" width="101.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Fetching objects and raw values" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jZw-qE-0ws">
|
||||
<rect key="frame" x="15" y="30" width="168.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="30" width="168.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -383,18 +380,18 @@
|
||||
<rect key="frame" x="0.0" y="235" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wyK-rk-3tI" id="fLd-KK-QcW">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ZfY-Aq-Ykq">
|
||||
<rect key="frame" x="15" y="6" width="61" height="24"/>
|
||||
<rect key="frame" x="16" y="6" width="61" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Implementing a custom logger" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QzD-9b-k1j">
|
||||
<rect key="frame" x="15" y="30" width="159" height="13.5"/>
|
||||
<rect key="frame" x="16" y="30" width="159" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -410,18 +407,18 @@
|
||||
<rect key="frame" x="0.0" y="285" width="375" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xTM-Cf-0if" id="DfO-BW-krd">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="49.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="49.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Evolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hSG-mG-YBw">
|
||||
<rect key="frame" x="15" y="6" width="78.5" height="24"/>
|
||||
<rect key="frame" x="16" y="6" width="78.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Migrating and de-migrating stores" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="X9P-TQ-LYh">
|
||||
<rect key="frame" x="15" y="30" width="179.5" height="13.5"/>
|
||||
<rect key="frame" x="16" y="30" width="179.5" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -459,8 +456,8 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" verticalCompressionResistancePriority="250" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd">
|
||||
<rect key="frame" x="20" y="69.5" width="552" height="36.5"/>
|
||||
<view contentMode="scaleToFill" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd">
|
||||
<rect key="frame" x="16" y="69.5" width="343" height="70"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="TIX-qi-B34"/>
|
||||
@@ -511,8 +508,8 @@
|
||||
<action selector="brightnessSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="F09-EP-2iD"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p4O-tf-dgt">
|
||||
<rect key="frame" x="20" y="49" width="552" height="20.5"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p4O-tf-dgt">
|
||||
<rect key="frame" x="16" y="49" width="343" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -623,7 +620,7 @@
|
||||
<tabBarItem key="tabBarItem" title="Demo" image="second" id="3iQ-I2-4LW"/>
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="00L-5k-Eno">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" red="0.90744441747665405" green="0.9265514612197876" blue="0.93116652965545654" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -653,18 +650,18 @@
|
||||
<rect key="frame" x="0.0" y="22" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="G3X-70-BCD" id="aT8-nz-i5l">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uQX-PI-UWF">
|
||||
<rect key="frame" x="8" y="8" width="27" height="27"/>
|
||||
<rect key="frame" x="16" y="11" width="22" height="22"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="uQX-PI-UWF" secondAttribute="height" multiplier="1:1" id="9qA-iN-Neb"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HJC-5w-lIN">
|
||||
<rect key="frame" x="45" y="8" width="34.5" height="27"/>
|
||||
<rect key="frame" x="48" y="11" width="34.5" height="22"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -713,18 +710,18 @@
|
||||
<rect key="frame" x="0.0" y="22" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="zSO-3e-OVq" id="cHA-by-n4b">
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5uq-Yi-XwH">
|
||||
<rect key="frame" x="8" y="8" width="27" height="27"/>
|
||||
<rect key="frame" x="16" y="11" width="22" height="22"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="5uq-Yi-XwH" secondAttribute="height" multiplier="1:1" id="oOe-HC-VyN"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zyu-PC-WmO">
|
||||
<rect key="frame" x="45" y="8" width="34.5" height="27"/>
|
||||
<rect key="frame" x="48" y="11" width="34.5" height="22"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -767,7 +764,7 @@
|
||||
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="6XA-6M-yvZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -794,11 +791,11 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="RZg-hi-T8O"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="k4s-iL-Krh">
|
||||
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="536"/>
|
||||
<mapView verifyAmbiguity="ignoreSizes" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="jPl-fH-NlD" id="Sjn-YC-haS"/>
|
||||
</connections>
|
||||
@@ -806,7 +803,7 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="RZg-hi-T8O" firstAttribute="top" secondItem="V2U-0R-Ts0" secondAttribute="bottom" id="GcS-Jz-Wcm"/>
|
||||
<constraint firstItem="RZg-hi-T8O" firstAttribute="top" secondItem="V2U-0R-Ts0" secondAttribute="bottom" id="N9r-9J-68d"/>
|
||||
<constraint firstItem="V2U-0R-Ts0" firstAttribute="top" secondItem="k4s-iL-Krh" secondAttribute="top" id="S5Z-Da-V6J"/>
|
||||
<constraint firstAttribute="trailing" secondItem="V2U-0R-Ts0" secondAttribute="trailing" id="YPc-RK-5ib"/>
|
||||
<constraint firstItem="V2U-0R-Ts0" firstAttribute="leading" secondItem="k4s-iL-Krh" secondAttribute="leading" id="hk5-Rz-FyU"/>
|
||||
@@ -820,7 +817,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="YnG-TD-zxQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3694" y="2020"/>
|
||||
<point key="canvasLocation" x="3693.5" y="2019.5"/>
|
||||
</scene>
|
||||
<!--Logger-->
|
||||
<scene sceneID="n7W-0g-bbY">
|
||||
@@ -888,7 +885,7 @@
|
||||
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wJo-mp-1pS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -927,7 +924,7 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="YVj-dA-fyV">
|
||||
<rect key="frame" x="20" y="26" width="560" height="29"/>
|
||||
<rect key="frame" x="20" y="26" width="335" height="29"/>
|
||||
<segments>
|
||||
<segment title="Fetch"/>
|
||||
<segment title="Query"/>
|
||||
@@ -1008,14 +1005,14 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RgX-yK-1L2">
|
||||
<rect key="frame" x="15" y="11" width="48.5" height="24"/>
|
||||
<rect key="frame" x="16" y="11" width="48.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QZ4-A2-x4h">
|
||||
<rect key="frame" x="15" y="35" width="31" height="13.5"/>
|
||||
<rect key="frame" x="16" y="35" width="31" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -1054,14 +1051,14 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Syt-QJ-KXg">
|
||||
<rect key="frame" x="15" y="11" width="48.5" height="24"/>
|
||||
<rect key="frame" x="16" y="11" width="48.5" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="yHS-dP-IKS">
|
||||
<rect key="frame" x="15" y="35" width="31" height="13.5"/>
|
||||
<rect key="frame" x="16" y="35" width="31" height="13.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/12.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -25,7 +25,7 @@ private struct Static {
|
||||
_ = try? dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
transaction.deleteAll(From<TimeZone>())
|
||||
try transaction.deleteAll(From<TimeZone>())
|
||||
|
||||
for name in NSTimeZone.knownTimeZoneNames {
|
||||
|
||||
@@ -164,67 +164,80 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
title: "All Time Zones",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>(),
|
||||
OrderBy(.ascending(#keyPath(TimeZone.name)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>()
|
||||
.orderBy(.ascending(\.name))
|
||||
)
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Time Zones in Asia",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>(),
|
||||
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Asia"),
|
||||
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>()
|
||||
.where(
|
||||
format: "%K BEGINSWITH[c] %@",
|
||||
#keyPath(TimeZone.name),
|
||||
"Asia"
|
||||
)
|
||||
.orderBy(.ascending(\.secondsFromGMT))
|
||||
)
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Time Zones in America and Europe",
|
||||
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)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>()
|
||||
.where(
|
||||
format: "%K BEGINSWITH[c] %@ OR %K BEGINSWITH[c] %@",
|
||||
#keyPath(TimeZone.name),
|
||||
"America",
|
||||
#keyPath(TimeZone.name),
|
||||
"Europe"
|
||||
)
|
||||
.orderBy(.ascending(\.secondsFromGMT))
|
||||
)
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "All Time Zones Except America",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>(),
|
||||
!Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America"),
|
||||
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>()
|
||||
.where(
|
||||
format: "%K BEGINSWITH[c] %@",
|
||||
#keyPath(TimeZone.name),
|
||||
"America"
|
||||
)
|
||||
.orderBy(.ascending(\.secondsFromGMT))
|
||||
)
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Time Zones with Summer Time",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>(),
|
||||
Where("hasDaylightSavingTime", isEqualTo: true),
|
||||
OrderBy(.ascending(#keyPath(TimeZone.name)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.fetchAll(
|
||||
From<TimeZone>()
|
||||
.where(\.hasDaylightSavingTime == true)
|
||||
.orderBy(.ascending(\.name))
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
|
||||
private let queryingItems = [
|
||||
private let queryingItems: [(title: String, query: () -> Any)] = [
|
||||
(
|
||||
title: "Number of Time Zones",
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryValue(
|
||||
From<TimeZone>(),
|
||||
Select<NSNumber>(.count(#keyPath(TimeZone.name)))
|
||||
return try! Static.timeZonesStack.queryValue(
|
||||
From<TimeZone>()
|
||||
.select(NSNumber.self, .count(\.name))
|
||||
)!
|
||||
}
|
||||
),
|
||||
@@ -232,10 +245,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
title: "Abbreviation For Tokyo's Time Zone",
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryValue(
|
||||
From<TimeZone>(),
|
||||
Select<String>(#keyPath(TimeZone.abbreviation)),
|
||||
Where("%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
|
||||
return try! Static.timeZonesStack.queryValue(
|
||||
From<TimeZone>()
|
||||
.select(String.self, .attribute(\.abbreviation))
|
||||
.where(format: "%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
|
||||
)!
|
||||
}
|
||||
),
|
||||
@@ -243,38 +256,53 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
title: "All Abbreviations",
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From<TimeZone>(),
|
||||
Select<NSDictionary>(#keyPath(TimeZone.name), #keyPath(TimeZone.abbreviation)),
|
||||
OrderBy(.ascending(#keyPath(TimeZone.name)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.queryAttributes(
|
||||
From<TimeZone>()
|
||||
.select(
|
||||
NSDictionary.self,
|
||||
.attribute(\.name),
|
||||
.attribute(\.abbreviation)
|
||||
)
|
||||
.orderBy(.ascending(\.name))
|
||||
)
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Number of Countries per Time Zone",
|
||||
query: { () -> Any 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)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.queryAttributes(
|
||||
From<TimeZone>()
|
||||
.select(
|
||||
NSDictionary.self,
|
||||
.count(\.abbreviation),
|
||||
.attribute(\.abbreviation)
|
||||
)
|
||||
.groupBy(\.abbreviation)
|
||||
.orderBy(
|
||||
.ascending(\.secondsFromGMT),
|
||||
.ascending(\.name)
|
||||
)
|
||||
)
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Number of Countries with Summer Time",
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From<TimeZone>(),
|
||||
Select<NSDictionary>(
|
||||
.count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"),
|
||||
#keyPath(TimeZone.hasDaylightSavingTime)
|
||||
),
|
||||
GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)),
|
||||
OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime)))
|
||||
)!
|
||||
return try! Static.timeZonesStack.queryAttributes(
|
||||
From<TimeZone>()
|
||||
.select(
|
||||
NSDictionary.self,
|
||||
.count(\.hasDaylightSavingTime, as: "numberOfCountries"),
|
||||
.attribute(\.hasDaylightSavingTime)
|
||||
)
|
||||
.groupBy(\.hasDaylightSavingTime)
|
||||
.orderBy(
|
||||
.descending(\.hasDaylightSavingTime),
|
||||
.ascending(\.name)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/17.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -30,7 +30,7 @@ class FetchingResultsViewController: UITableViewController {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.tableView.estimatedRowHeight = 60
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension
|
||||
self.tableView.rowHeight = UITableView.automaticDimension
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/17.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -49,7 +49,7 @@ class QueryingResultsViewController: UITableViewController {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.tableView.estimatedRowHeight = 60
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension
|
||||
self.tableView.rowHeight = UITableView.automaticDimension
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/15.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
@@ -32,6 +42,36 @@
|
||||
"filename" : "Icon-60@3x-1.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
@@ -44,6 +84,22 @@
|
||||
"filename" : "Icon-76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Mask + Oval 1 + Oval 1 + Oval 1.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "car",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "car",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.0.3</string>
|
||||
<string>6.3.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/02.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -28,13 +28,13 @@ struct ColorsDemo {
|
||||
}
|
||||
}
|
||||
|
||||
func whereClause() -> Where {
|
||||
func whereClause() -> Where<Palette> {
|
||||
|
||||
switch self {
|
||||
|
||||
case .all: return Where(true)
|
||||
case .light: return Palette.where({ $0.brightness >= 0.9 })
|
||||
case .dark: return Palette.where({ $0.brightness <= 0.4 })
|
||||
case .all: return .init()
|
||||
case .light: return (\Palette.brightness >= 0.9)
|
||||
case .dark: return (\Palette.brightness <= 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ struct ColorsDemo {
|
||||
|
||||
self.palettes.refetch(
|
||||
self.filter.whereClause(),
|
||||
Palette.orderBy(ascending: { $0.hue })
|
||||
OrderBy<Palette>(.ascending(\.hue))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -74,9 +74,9 @@ struct ColorsDemo {
|
||||
)
|
||||
)
|
||||
return ColorsDemo.stack.monitorSectionedList(
|
||||
From<Palette>(),
|
||||
SectionBy(Palette.keyPath({ $0.colorName })),
|
||||
Palette.orderBy(ascending: { $0.hue })
|
||||
From<Palette>()
|
||||
.sectionBy(\.colorName)
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
}()
|
||||
}
|
||||
@@ -122,6 +122,11 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
target: self,
|
||||
action: #selector(self.addBarButtonItemTouched(_:))
|
||||
),
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .refresh,
|
||||
target: self,
|
||||
action: #selector(self.shuffleBarButtonItemTouched(_:))
|
||||
),
|
||||
filterBarButton
|
||||
]
|
||||
self.filterBarButton = filterBarButton
|
||||
@@ -155,7 +160,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return ColorsDemo.palettes.numberOfObjectsInSection(section)
|
||||
return ColorsDemo.palettes.numberOfObjects(in: section)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
@@ -182,7 +187,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
|
||||
switch editingStyle {
|
||||
|
||||
@@ -203,7 +208,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return ColorsDemo.palettes.sectionInfoAtIndex(section).name
|
||||
return ColorsDemo.palettes.sectionInfo(at: section).name
|
||||
}
|
||||
|
||||
|
||||
@@ -255,9 +260,8 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
|
||||
|
||||
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
|
||||
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
|
||||
|
||||
self.tableView.moveRow(at: fromIndexPath, to: toIndexPath)
|
||||
}
|
||||
|
||||
|
||||
@@ -268,7 +272,6 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
}
|
||||
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
@@ -284,7 +287,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
transaction.deleteAll(From<Palette>())
|
||||
try transaction.deleteAll(From<Palette>())
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
@@ -306,9 +309,29 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction private dynamic func shuffleBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
self.setTable(enabled: false)
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
for palette in try transaction.fetchAll(From<Palette>()) {
|
||||
|
||||
palette.hue .= Palette.randomHue()
|
||||
palette.colorName .= nil
|
||||
}
|
||||
},
|
||||
completion: { _ in
|
||||
|
||||
self.setTable(enabled: true)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private func setTable(enabled: Bool) {
|
||||
|
||||
|
||||
tableView.isUserInteractionEnabled = enabled
|
||||
UIView.animate(
|
||||
withDuration: 0.2,
|
||||
delay: 0,
|
||||
@@ -318,7 +341,6 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
if let tableView = self.tableView {
|
||||
|
||||
tableView.alpha = enabled ? 1.0 : 0.5
|
||||
tableView.isUserInteractionEnabled = enabled
|
||||
}
|
||||
},
|
||||
completion: nil
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/06.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -50,7 +50,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
|
||||
if let palette = ColorsDemo.stack.fetchOne(From<Palette>(), Palette.orderBy(ascending: { $0.hue })) {
|
||||
if let palette = try! ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue))) {
|
||||
|
||||
self.monitor = ColorsDemo.stack.monitorObject(palette)
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
}
|
||||
)
|
||||
|
||||
let palette = ColorsDemo.stack.fetchOne(From<Palette>(), Palette.orderBy(ascending: { $0.hue }))!
|
||||
let palette = try! ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue)))!
|
||||
self.monitor = ColorsDemo.stack.monitorObject(palette)
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ 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<KeyPathString>) {
|
||||
|
||||
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
|
||||
}
|
||||
@@ -184,15 +184,15 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
self.hsbLabel?.text = palette.colorText
|
||||
|
||||
if changedKeys == nil || changedKeys?.contains(Palette.keyPath{ $0.hue }) == true {
|
||||
if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.hue)) == true {
|
||||
|
||||
self.hueSlider?.value = Float(palette.hue.value)
|
||||
}
|
||||
if changedKeys == nil || changedKeys?.contains(Palette.keyPath{ $0.saturation }) == true {
|
||||
if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.saturation)) == true {
|
||||
|
||||
self.saturationSlider?.value = palette.saturation.value
|
||||
}
|
||||
if changedKeys == nil || changedKeys?.contains(Palette.keyPath{ $0.brightness }) == true {
|
||||
if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.brightness)) == true {
|
||||
|
||||
self.brightnessSlider?.value = palette.brightness.value
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/05.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@@ -16,25 +16,30 @@ import CoreStore
|
||||
|
||||
final class Palette: CoreStoreObject {
|
||||
|
||||
let hue = Value.Required<Int>("hue")
|
||||
let saturation = Value.Required<Float>("saturation")
|
||||
let brightness = Value.Required<Float>("brightness")
|
||||
let hue = Value.Required<Int>("hue", initial: 0)
|
||||
let saturation = Value.Required<Float>("saturation", initial: 0)
|
||||
let brightness = Value.Required<Float>("brightness", initial: 0)
|
||||
|
||||
let colorName = Value.Optional<String>(
|
||||
"colorName",
|
||||
isTransient: true,
|
||||
customGetter: Palette.getCachedColorName
|
||||
customGetter: Palette.getColorName
|
||||
)
|
||||
|
||||
static func randomHue() -> Int {
|
||||
|
||||
return Int(arc4random_uniform(360))
|
||||
}
|
||||
|
||||
private static func getCachedColorName(_ instance: Palette, _ getValue: () -> String?) -> String? {
|
||||
private static func getColorName(_ partialObject: PartialObject<Palette>) -> String? {
|
||||
|
||||
if let colorName = getValue() {
|
||||
if let colorName = partialObject.primitiveValue(for: { $0.colorName }) {
|
||||
|
||||
return colorName
|
||||
}
|
||||
|
||||
let colorName: String
|
||||
switch instance.hue.value % 360 {
|
||||
switch partialObject.value(for: { $0.hue }) % 360 {
|
||||
|
||||
case 0 ..< 20: colorName = "Lower Reds"
|
||||
case 20 ..< 57: colorName = "Oranges and Browns"
|
||||
@@ -47,7 +52,7 @@ final class Palette: CoreStoreObject {
|
||||
default: colorName = "Upper Reds"
|
||||
}
|
||||
|
||||
instance.colorName.primitiveValue = colorName
|
||||
partialObject.setPrimitiveValue(colorName, for: { $0.colorName })
|
||||
return colorName
|
||||
}
|
||||
}
|
||||
@@ -71,7 +76,7 @@ extension Palette {
|
||||
|
||||
func setInitialValues(in transaction: BaseDataTransaction) {
|
||||
|
||||
self.hue .= Int(arc4random_uniform(360))
|
||||
self.hue .= Palette.randomHue()
|
||||
self.saturation .= Float(1.0)
|
||||
self.brightness .= Float(arc4random_uniform(70) + 30) / 100.0
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/05.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/05.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -16,11 +16,6 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
deinit {
|
||||
|
||||
CoreStore.logger = DefaultLogger()
|
||||
}
|
||||
|
||||
let dataStack = DataStack()
|
||||
|
||||
// MARK: UIViewController
|
||||
@@ -30,13 +25,14 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
super.viewDidLoad()
|
||||
|
||||
try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite"))
|
||||
CoreStore.logger = self
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
|
||||
CoreStore.logger = self
|
||||
|
||||
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.",
|
||||
@@ -46,6 +42,13 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
CoreStore.logger = DefaultLogger()
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreLogger
|
||||
|
||||
@@ -99,8 +102,8 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
case 0?:
|
||||
let request = NSFetchRequest<NSFetchRequestResult>()
|
||||
Where(true).applyToFetchRequest(request)
|
||||
Where(false).applyToFetchRequest(request)
|
||||
Where<NSManagedObject>(true).applyToFetchRequest(request)
|
||||
Where<NSManagedObject>(false).applyToFetchRequest(request)
|
||||
|
||||
case 1?:
|
||||
_ = try? dataStack.addStorageAndWait(
|
||||
@@ -113,7 +116,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
case 2?:
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
|
||||
_ = self.dataStack.fetchOne(From<Place>())
|
||||
_ = try! self.dataStack.fetchOne(From<Place>())
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/21.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -79,7 +79,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
func listMonitorDidChange(_ monitor: ListMonitor<NSManagedObject>) {
|
||||
|
||||
if self.lastSelectedIndexPath == nil,
|
||||
let numberOfObjectsInSection = self.listMonitor?.numberOfObjectsInSection(0),
|
||||
let numberOfObjectsInSection = self.listMonitor?.numberOfObjects(in: 0),
|
||||
numberOfObjectsInSection > 0 {
|
||||
|
||||
self.tableView?.reloadData()
|
||||
@@ -100,7 +100,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
|
||||
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
|
||||
return self.listMonitor?.numberOfObjects(in: 0) ?? 0
|
||||
}
|
||||
|
||||
@objc dynamic func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
@@ -109,7 +109,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
|
||||
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
|
||||
cell.dnaLabel?.text = "DNA: \(dna)"
|
||||
cell.mutateButtonHandler = { [weak self] _ -> Void in
|
||||
cell.mutateButtonHandler = { [weak self] () -> Void in
|
||||
|
||||
guard let `self` = self,
|
||||
let dataStack = self.dataStack,
|
||||
@@ -286,9 +286,9 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
|
||||
self.set(dataStack: dataStack, model: model, scrollToSelection: true)
|
||||
|
||||
let count = dataStack.queryValue(
|
||||
From(model.entityType),
|
||||
Select<Int>(.count(#keyPath(OrganismV1.dna))))!
|
||||
let count = try! dataStack.queryValue(
|
||||
From<NSManagedObject>(model.entityType)
|
||||
.select(Int.self, .count(#keyPath(OrganismV1.dna))))!
|
||||
if count > 0 {
|
||||
|
||||
self.setEnabled(true)
|
||||
@@ -360,21 +360,25 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
if let dataStack = dataStack, let model = model {
|
||||
|
||||
self.segmentedControl?.selectedSegmentIndex = self.models
|
||||
.index(
|
||||
where: { (_, _, schemaHistory) -> Bool in
|
||||
.firstIndex(
|
||||
where: { (arg) -> Bool in
|
||||
|
||||
schemaHistory.currentModelVersion == model.schemaHistory.currentModelVersion
|
||||
let (_, _, schemaHistory) = arg
|
||||
return schemaHistory.currentModelVersion == model.schemaHistory.currentModelVersion
|
||||
}
|
||||
)!
|
||||
|
||||
self._dataStack = dataStack
|
||||
let listMonitor = dataStack.monitorList(From(model.entityType), OrderBy(.descending("dna")))
|
||||
let listMonitor = dataStack.monitorList(
|
||||
From(model.entityType),
|
||||
OrderBy<NSManagedObject>(.descending(#keyPath(OrganismV1.dna)))
|
||||
)
|
||||
listMonitor.addObserver(self)
|
||||
self._listMonitor = listMonitor
|
||||
|
||||
if self.lastSelectedIndexPath == nil {
|
||||
|
||||
if listMonitor.numberOfObjectsInSection(0) > 0 {
|
||||
if listMonitor.numberOfObjects(in: 0) > 0 {
|
||||
|
||||
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: true)
|
||||
}
|
||||
@@ -382,7 +386,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
|
||||
}
|
||||
else {
|
||||
|
||||
self.segmentedControl?.selectedSegmentIndex = UISegmentedControlNoSegment
|
||||
self.segmentedControl?.selectedSegmentIndex = UISegmentedControl.noSegment
|
||||
self._listMonitor = nil
|
||||
self._dataStack = nil
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/27.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol OrganismProtocol: class {
|
||||
protocol OrganismProtocol: AnyObject {
|
||||
|
||||
var dna: Int64 { get set }
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/07/12.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/21.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/21.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/27.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/27.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/06.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/06.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
@@ -36,7 +36,7 @@ private struct Static {
|
||||
_ = try? dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
transaction.deleteAll(From<UserAccount>())
|
||||
try transaction.deleteAll(From<UserAccount>())
|
||||
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Facebook"
|
||||
@@ -74,7 +74,7 @@ private struct Static {
|
||||
_ = try? dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
transaction.deleteAll(From<UserAccount>())
|
||||
try transaction.deleteAll(From<UserAccount>())
|
||||
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Twitter"
|
||||
@@ -99,8 +99,8 @@ private struct Static {
|
||||
class StackSetupDemoViewController: UITableViewController {
|
||||
|
||||
let accounts = [
|
||||
Static.facebookStack.fetchAll(From(UserAccount.self)) ?? [],
|
||||
Static.twitterStack.fetchAll(From(UserAccount.self)) ?? []
|
||||
try! Static.facebookStack.fetchAll(From<UserAccount>()),
|
||||
try! Static.twitterStack.fetchAll(From<UserAccount>())
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright © 2015 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Contacts
|
||||
import CoreLocation
|
||||
import MapKit
|
||||
import AddressBookUI
|
||||
@@ -25,7 +26,7 @@ private struct Static {
|
||||
)
|
||||
)
|
||||
|
||||
var place = CoreStore.fetchOne(From<Place>())
|
||||
var place = try! CoreStore.fetchOne(From<Place>())
|
||||
if place == nil {
|
||||
|
||||
_ = try? CoreStore.perform(
|
||||
@@ -35,7 +36,7 @@ private struct Static {
|
||||
place.setInitialValues()
|
||||
}
|
||||
)
|
||||
place = CoreStore.fetchOne(From<Place>())
|
||||
place = try! CoreStore.fetchOne(From<Place>())
|
||||
}
|
||||
|
||||
return CoreStore.monitorObject(place!)
|
||||
@@ -131,7 +132,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
// none
|
||||
}
|
||||
|
||||
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPathString>) {
|
||||
|
||||
if let mapView = self.mapView {
|
||||
|
||||
@@ -203,11 +204,23 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
CLLocation(latitude: place.latitude, longitude: place.longitude),
|
||||
completionHandler: { [weak self] (placemarks, error) -> Void in
|
||||
|
||||
if let placemark = placemarks?.first, let addressDictionary = placemark.addressDictionary {
|
||||
if let placemark = placemarks?.first, let dictionary = placemark.addressDictionary {
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
place?.title = placemark.name
|
||||
place?.subtitle = ABCreateStringWithAddressDictionary(addressDictionary, true)
|
||||
place?.subtitle = CNPostalAddressFormatter.string(
|
||||
from: autoreleasepool {
|
||||
|
||||
let address = CNMutablePostalAddress()
|
||||
(dictionary["Street"] as? String).flatMap({ address.street = $0 })
|
||||
(dictionary["State"] as? String).flatMap({ address.state = $0 })
|
||||
(dictionary["City"] as? String).flatMap({ address.city = $0 })
|
||||
(dictionary["Country"] as? String).flatMap({ address.country = $0 })
|
||||
(dictionary["ZIP"] as? String).flatMap({ address.postalCode = $0 })
|
||||
return address
|
||||
},
|
||||
style: .mailingAddress
|
||||
)
|
||||
transaction.commit { (_) -> Void in }
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// BaseTestCase.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -36,8 +36,7 @@ class BaseTestCase: XCTestCase {
|
||||
// MARK: Internal
|
||||
|
||||
@nonobjc
|
||||
@discardableResult
|
||||
func prepareStack<T>(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T {
|
||||
func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) throws -> Void) {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
@@ -57,16 +56,16 @@ class BaseTestCase: XCTestCase {
|
||||
)
|
||||
)
|
||||
}
|
||||
try closure(stack)
|
||||
}
|
||||
catch let error as NSError {
|
||||
|
||||
XCTFail(error.coreStoreDumpString)
|
||||
}
|
||||
return closure(stack)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () -> T) -> T {
|
||||
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
|
||||
|
||||
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
|
||||
defer {
|
||||
@@ -74,7 +73,7 @@ class BaseTestCase: XCTestCase {
|
||||
self.checkExpectationsImmediately()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
}
|
||||
return closure()
|
||||
return try closure()
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
@@ -82,6 +81,33 @@ class BaseTestCase: XCTestCase {
|
||||
|
||||
CoreStore.logger = TestLogger(expectations)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func expectError<T>(code: CoreStoreErrorCode, closure: () throws -> T) {
|
||||
|
||||
CoreStore.logger = TestLogger(self.prepareLoggerExpectations([.logError]))
|
||||
defer {
|
||||
|
||||
self.checkExpectationsImmediately()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
}
|
||||
do {
|
||||
|
||||
_ = try closure()
|
||||
}
|
||||
catch let error as CoreStoreError {
|
||||
|
||||
if error.errorCode == code.rawValue {
|
||||
|
||||
return
|
||||
}
|
||||
XCTFail("Expected error code \(code) different from actual error: \((error as NSError).coreStoreDumpString)")
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail("Error not wrapped as \(cs_typeName(CoreStoreError.self)): \((error as NSError).coreStoreDumpString)")
|
||||
}
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
|
||||
|
||||
@@ -2,8 +2,25 @@
|
||||
// BaseTestDataTestCase.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Created by John Rommel Estropia on 2016/06/11.
|
||||
// Copyright © 2016 John Rommel Estropia. All rights reserved.
|
||||
// Copyright © 2018 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// BridgingTests.h
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// BridgingTests.m
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -193,7 +193,17 @@
|
||||
XCTAssertEqualObjects([[sqliteStorage class] storeType], [CSSQLiteStore storeType]);
|
||||
XCTAssertEqualObjects([[sqliteStorage class] storeType], NSSQLiteStoreType);
|
||||
XCTAssertNil(sqliteStorage.configuration);
|
||||
XCTAssertEqualObjects(sqliteStorage.storeOptions, @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" } });
|
||||
NSDictionary *storeOptions;
|
||||
if (@available(iOS 11.0, macOS 10.13, tvOS 11.0, *)) {
|
||||
|
||||
storeOptions = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" },
|
||||
NSBinaryStoreInsecureDecodingCompatibilityOption: @YES };
|
||||
}
|
||||
else {
|
||||
|
||||
storeOptions = @{ NSSQLitePragmasOption: @{ @"journal_mode": @"WAL" }};
|
||||
}
|
||||
XCTAssertEqualObjects(sqliteStorage.storeOptions, storeOptions);
|
||||
XCTAssertNil(sqliteError);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ConvenienceTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -29,7 +29,7 @@ import CoreStore
|
||||
|
||||
// MARK: - ConvenienceTests
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@available(macOS 10.12, *)
|
||||
class ConvenienceTests: BaseTestCase {
|
||||
|
||||
@objc
|
||||
@@ -40,8 +40,8 @@ class ConvenienceTests: BaseTestCase {
|
||||
let controller = stack.createFetchedResultsController(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testString)),
|
||||
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testString))),
|
||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
|
||||
Tweak { $0.fetchLimit = 10 }
|
||||
)
|
||||
XCTAssertEqual(controller.managedObjectContext, stack.mainContext)
|
||||
@@ -49,11 +49,11 @@ class ConvenienceTests: BaseTestCase {
|
||||
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.sortDescriptors!,
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
||||
)
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.predicate,
|
||||
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
||||
)
|
||||
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
|
||||
}
|
||||
@@ -69,8 +69,8 @@ class ConvenienceTests: BaseTestCase {
|
||||
let controller = transaction.createFetchedResultsController(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testString)),
|
||||
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testString))),
|
||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
|
||||
Tweak { $0.fetchLimit = 10 }
|
||||
)
|
||||
XCTAssertEqual(controller.managedObjectContext, transaction.context)
|
||||
@@ -78,11 +78,11 @@ class ConvenienceTests: BaseTestCase {
|
||||
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.sortDescriptors!,
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
||||
)
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.predicate,
|
||||
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
||||
)
|
||||
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// DynamicModelTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2017 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -28,16 +28,17 @@ import XCTest
|
||||
@testable
|
||||
import CoreStore
|
||||
|
||||
#if os(OSX)
|
||||
#if os(macOS)
|
||||
typealias Color = NSColor
|
||||
|
||||
#else
|
||||
|
||||
typealias Color = UIColor
|
||||
|
||||
#endif
|
||||
|
||||
class Animal: CoreStoreObject {
|
||||
|
||||
let species = Value.Required<String>("species", default: "Swift")
|
||||
let species = Value.Required<String>("species", initial: "Swift")
|
||||
let master = Relationship.ToOne<Person>("master")
|
||||
let color = Transformable.Optional<Color>("color")
|
||||
}
|
||||
@@ -45,53 +46,69 @@ class Animal: CoreStoreObject {
|
||||
class Dog: Animal {
|
||||
|
||||
let nickname = Value.Optional<String>("nickname")
|
||||
let age = Value.Required<Int>("age", default: 1)
|
||||
let age = Value.Required<Int>("age", initial: 1)
|
||||
let friends = Relationship.ToManyOrdered<Dog>("friends")
|
||||
let friendedBy = Relationship.ToManyUnordered<Dog>("friendedBy", inverse: { $0.friends })
|
||||
}
|
||||
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
let title = Value.Required<String>(
|
||||
"title",
|
||||
default: "Mr.",
|
||||
customSetter: { (`self`, setValue, originalNewValue) in
|
||||
|
||||
setValue(originalNewValue)
|
||||
self.displayName .= nil
|
||||
}
|
||||
initial: "Mr.",
|
||||
customSetter: Person.setTitle
|
||||
)
|
||||
|
||||
let name = Value.Required<String>(
|
||||
"name",
|
||||
customSetter: { (`self`, setValue, originalNewValue) in
|
||||
|
||||
setValue(originalNewValue)
|
||||
self.displayName .= nil
|
||||
}
|
||||
initial: "",
|
||||
customSetter: Person.setName
|
||||
)
|
||||
|
||||
let displayName = Value.Optional<String>(
|
||||
"displayName",
|
||||
isTransient: true,
|
||||
customGetter: Person.cachedDisplayName(_:_:),
|
||||
customGetter: Person.getDisplayName(_:),
|
||||
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
|
||||
)
|
||||
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
|
||||
|
||||
let spouse = Relationship.ToOne<Person>("spouse")
|
||||
|
||||
static func cachedDisplayName(_ instance: Person, _ getValue: () -> String?) -> String? {
|
||||
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
|
||||
|
||||
private let _spouse = Relationship.ToOne<Person>("_spouseInverse", inverse: { $0.spouse })
|
||||
|
||||
|
||||
private static func setTitle(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
||||
|
||||
if let cached = getValue() {
|
||||
partialObject.setPrimitiveValue(newValue, for: { $0.title })
|
||||
partialObject.setPrimitiveValue(nil, for: { $0.displayName })
|
||||
}
|
||||
|
||||
private static func setName(_ partialObject: PartialObject<Person>, _ newValue: String) {
|
||||
|
||||
partialObject.setPrimitiveValue(newValue, for: { $0.name })
|
||||
partialObject.setPrimitiveValue(nil, for: { $0.displayName })
|
||||
}
|
||||
|
||||
static func getDisplayName(_ partialObject: PartialObject<Person>) -> String? {
|
||||
|
||||
if let displayName = partialObject.primitiveValue(for: { $0.displayName }) {
|
||||
|
||||
return cached
|
||||
return displayName
|
||||
}
|
||||
let primitiveValue = "\(instance.title.value) \(instance.name.value)"
|
||||
instance.displayName .= primitiveValue
|
||||
return primitiveValue
|
||||
let title = partialObject.value(for: { $0.title })
|
||||
let name = partialObject.value(for: { $0.name })
|
||||
let displayName = "\(title) \(name)"
|
||||
partialObject.setPrimitiveValue(displayName, for: { $0.displayName })
|
||||
return displayName
|
||||
}
|
||||
|
||||
static func keyPathsAffectingDisplayName() -> Set<String> {
|
||||
|
||||
return [
|
||||
self.keyPath({ $0.title }),
|
||||
self.keyPath({ $0.name })
|
||||
String(keyPath: \Person.title),
|
||||
String(keyPath: \Person.name)
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -101,7 +118,8 @@ class Person: CoreStoreObject {
|
||||
|
||||
class DynamicModelTests: BaseTestDataTestCase {
|
||||
|
||||
func testDynamicModels_CanBeDeclaredCorrectly() {
|
||||
@objc
|
||||
dynamic func test_ThatDynamicModels_CanBeDeclaredCorrectly() {
|
||||
|
||||
let dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
@@ -114,23 +132,26 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
versionLock: [
|
||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
||||
"Person": [0x66d8bbfd8b21561f, 0xcecec69ecae3570f, 0xc4b73d71256214ef, 0x89b99bfe3e013e8b]
|
||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
||||
]
|
||||
)
|
||||
)
|
||||
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
|
||||
|
||||
let k1 = Animal.keyPath({ $0.species })
|
||||
let k1 = String(keyPath: \Animal.species)
|
||||
XCTAssertEqual(k1, "species")
|
||||
|
||||
let k2 = Dog.keyPath({ $0.species })
|
||||
|
||||
let k2 = String(keyPath: \Dog.species)
|
||||
XCTAssertEqual(k2, "species")
|
||||
|
||||
let k3 = Dog.keyPath({ $0.nickname })
|
||||
let k3 = String(keyPath: \Dog.nickname)
|
||||
XCTAssertEqual(k3, "nickname")
|
||||
|
||||
let updateDone = self.expectation(description: "update-done")
|
||||
let fetchDone = self.expectation(description: "fetch-done")
|
||||
let willSetPriorObserverDone = self.expectation(description: "willSet-observe-prior-done")
|
||||
let willSetNotPriorObserverDone = self.expectation(description: "willSet-observe-notPrior-done")
|
||||
let didSetObserverDone = self.expectation(description: "didSet-observe-done")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
@@ -148,9 +169,42 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(dog.species.value, "Swift")
|
||||
XCTAssertEqual(dog.nickname.value, nil)
|
||||
XCTAssertEqual(dog.age.value, 1)
|
||||
|
||||
let didSetObserver = dog.species.observe(options: [.new, .old]) { (object, change) in
|
||||
|
||||
XCTAssertEqual(object, dog)
|
||||
XCTAssertEqual(change.kind, .setting)
|
||||
XCTAssertEqual(change.newValue, "Dog")
|
||||
XCTAssertEqual(change.oldValue, "Swift")
|
||||
XCTAssertFalse(change.isPrior)
|
||||
XCTAssertEqual(object.species.value, "Dog")
|
||||
didSetObserverDone.fulfill()
|
||||
}
|
||||
let willSetObserver = dog.species.observe(options: [.new, .old, .prior]) { (object, change) in
|
||||
|
||||
XCTAssertEqual(object, dog)
|
||||
XCTAssertEqual(change.kind, .setting)
|
||||
XCTAssertEqual(change.oldValue, "Swift")
|
||||
|
||||
if change.isPrior {
|
||||
|
||||
XCTAssertNil(change.newValue)
|
||||
XCTAssertEqual(object.species.value, "Swift")
|
||||
willSetPriorObserverDone.fulfill()
|
||||
}
|
||||
else {
|
||||
|
||||
XCTAssertEqual(change.newValue, "Dog")
|
||||
XCTAssertEqual(object.species.value, "Dog")
|
||||
willSetNotPriorObserverDone.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
dog.species .= "Dog"
|
||||
XCTAssertEqual(dog.species.value, "Dog")
|
||||
|
||||
didSetObserver.invalidate()
|
||||
willSetObserver.invalidate()
|
||||
|
||||
dog.nickname .= "Spot"
|
||||
XCTAssertEqual(dog.nickname.value, "Spot")
|
||||
@@ -159,7 +213,7 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
XCTAssertTrue(person.pets.value.isEmpty)
|
||||
|
||||
XCTAssertEqual(
|
||||
object_getClass(person.rawObject!).keyPathsForValuesAffectingValue(forKey: "displayName"),
|
||||
cs_dynamicType(of: person.rawObject!).keyPathsForValuesAffectingValue(forKey: "displayName"),
|
||||
["title", "name"]
|
||||
)
|
||||
|
||||
@@ -185,7 +239,7 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(dog.master.value, person)
|
||||
XCTAssertEqual(dog.master.value?.pets.value.first, dog)
|
||||
},
|
||||
success: {
|
||||
success: { _ in
|
||||
|
||||
updateDone.fulfill()
|
||||
},
|
||||
@@ -197,29 +251,62 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let p1 = Animal.where({ $0.species == "Sparrow" })
|
||||
let p1 = Where<Animal>({ $0.species == "Sparrow" })
|
||||
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
|
||||
|
||||
let bird = transaction.fetchOne(From<Animal>(), p1)
|
||||
let bird = try transaction.fetchOne(From<Animal>(), p1)
|
||||
XCTAssertNotNil(bird)
|
||||
XCTAssertEqual(bird!.species.value, "Sparrow")
|
||||
|
||||
let p2 = Dog.where({ $0.nickname == "Spot" })
|
||||
let p2 = Where<Dog>({ $0.nickname == "Spot" })
|
||||
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
|
||||
|
||||
let dog = transaction.fetchOne(From<Dog>(), p2)
|
||||
let dog = try transaction.fetchOne(From<Dog>().where(\.nickname == "Spot"))
|
||||
XCTAssertNotNil(dog)
|
||||
XCTAssertEqual(dog!.nickname.value, "Spot")
|
||||
XCTAssertEqual(dog!.species.value, "Dog")
|
||||
|
||||
let person = transaction.fetchOne(From<Person>())
|
||||
let person = try transaction.fetchOne(From<Person>())
|
||||
XCTAssertNotNil(person)
|
||||
XCTAssertEqual(person!.pets.value.first, dog)
|
||||
|
||||
let p3 = Dog.where({ $0.age == 10 })
|
||||
let p3 = Where<Dog>({ $0.age == 10 })
|
||||
XCTAssertEqual(p3.predicate, NSPredicate(format: "%K == %d", "age", 10))
|
||||
|
||||
let totalAge = try transaction.queryValue(From<Dog>().select(Int.self, .sum(\Dog.age)))
|
||||
XCTAssertEqual(totalAge, 1)
|
||||
|
||||
_ = try transaction.fetchAll(
|
||||
From<Dog>()
|
||||
.where(\Animal.species == "Dog" && \Dog.age == 10)
|
||||
)
|
||||
_ = try transaction.fetchAll(
|
||||
From<Dog>()
|
||||
.where(\Dog.age == 10 && \Animal.species == "Dog")
|
||||
.orderBy(.ascending({ $0.species }))
|
||||
)
|
||||
_ = try transaction.fetchAll(
|
||||
From<Dog>(),
|
||||
Where<Dog>({ $0.age > 10 && $0.age <= 15 })
|
||||
)
|
||||
_ = try transaction.fetchAll(
|
||||
From<Dog>(),
|
||||
Where<Dog>({ $0.species == "Dog" && $0.age == 10 })
|
||||
)
|
||||
_ = try transaction.fetchAll(
|
||||
From<Dog>(),
|
||||
Where<Dog>({ $0.age == 10 && $0.species == "Dog" })
|
||||
)
|
||||
_ = try transaction.fetchAll(
|
||||
From<Dog>(),
|
||||
Where<Dog>({ $0.age > 10 && $0.age <= 15 })
|
||||
)
|
||||
_ = try transaction.fetchAll(
|
||||
From<Dog>(),
|
||||
(\Dog.age > 10 && \Dog.age <= 15)
|
||||
)
|
||||
},
|
||||
success: {
|
||||
success: { _ in
|
||||
|
||||
fetchDone.fulfill()
|
||||
},
|
||||
@@ -232,6 +319,13 @@ class DynamicModelTests: BaseTestDataTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
|
||||
|
||||
XCTAssertEqual(String(keyPath: \Animal.species), "species")
|
||||
XCTAssertEqual(String(keyPath: \Dog.species), "species")
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func prepareStack(_ dataStack: DataStack, configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) -> Void) {
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ErrorTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
// FromTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -74,33 +74,31 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.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 = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
}
|
||||
@@ -115,102 +113,98 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
}
|
||||
@@ -225,99 +219,96 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.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 = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
}
|
||||
@@ -332,96 +323,94 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config2"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = self.expectLogger([.logWarning]) {
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
self.expectError(code: .persistentStoreNotFound) {
|
||||
|
||||
from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
try from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
}
|
||||
XCTAssertFalse(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertTrue(storesFound)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
XCTAssertNotNil(storesFound)
|
||||
XCTAssertNotNil(request.entity)
|
||||
XCTAssertNotNil(request.safeAffectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config2"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// GroupByTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -38,14 +38,14 @@ final class GroupByTests: BaseTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let groupBy = GroupBy()
|
||||
let groupBy = GroupBy<NSManagedObject>()
|
||||
XCTAssertEqual(groupBy, GroupBy([] as [String]))
|
||||
XCTAssertNotEqual(groupBy, GroupBy("key"))
|
||||
XCTAssertTrue(groupBy.keyPaths.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let groupBy = GroupBy("key1")
|
||||
let groupBy = GroupBy<NSManagedObject>("key1")
|
||||
XCTAssertEqual(groupBy, GroupBy("key1"))
|
||||
XCTAssertEqual(groupBy, GroupBy(["key1"]))
|
||||
XCTAssertNotEqual(groupBy, GroupBy("key2"))
|
||||
@@ -53,7 +53,7 @@ final class GroupByTests: BaseTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let groupBy = GroupBy("key1", "key2")
|
||||
let groupBy = GroupBy<NSManagedObject>("key1", "key2")
|
||||
XCTAssertEqual(groupBy, GroupBy("key1", "key2"))
|
||||
XCTAssertEqual(groupBy, GroupBy(["key1", "key2"]))
|
||||
XCTAssertNotEqual(groupBy, GroupBy("key2", "key1"))
|
||||
@@ -66,10 +66,10 @@ final class GroupByTests: BaseTestCase {
|
||||
|
||||
self.prepareStack { (dataStack) in
|
||||
|
||||
let groupBy = GroupBy(#keyPath(TestEntity1.testString))
|
||||
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
|
||||
|
||||
let request = CoreStoreFetchRequest()
|
||||
_ = From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
try From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
|
||||
groupBy.applyToFetchRequest(request)
|
||||
|
||||
XCTAssertNotNil(request.propertiesToGroupBy)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ImportTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -36,33 +36,33 @@ class ImportTests: BaseTestDataTestCase {
|
||||
@objc
|
||||
dynamic func test_ThatAttributeProtocols_BehaveCorrectly() {
|
||||
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSNumber(value: true))?.boolValue, true)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSNumber(value: Int16.max))?.int16Value, Int16.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSNumber(value: Int32.max))?.int32Value, Int32.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSNumber(value: Int64.max))?.int64Value, Int64.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSNumber(value: MAXFLOAT))?.floatValue, MAXFLOAT)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSNumber(value: Double(MAXFLOAT)))?.doubleValue, Double(MAXFLOAT))
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSNumber(value: true))?.boolValue, true)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSNumber(value: Int16.max))?.int16Value, Int16.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSNumber(value: Int32.max))?.int32Value, Int32.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSNumber(value: Int64.max))?.int64Value, Int64.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSNumber(value: MAXFLOAT))?.floatValue, MAXFLOAT)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSNumber(value: Double(MAXFLOAT)))?.doubleValue, Double(MAXFLOAT))
|
||||
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromImportableNativeType(NSDecimalNumber(string: "1"))?.boolValue, true)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromImportableNativeType(NSDecimalNumber(string: Int16.max.description))?.int16Value, Int16.max)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromImportableNativeType(NSDecimalNumber(string: Int32.max.description))?.int32Value, Int32.max)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromImportableNativeType(NSDecimalNumber(string: Int64.max.description))?.int64Value, Int64.max)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromImportableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.doubleValue, NSDecimalNumber(string: MAXFLOAT.description).doubleValue)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromImportableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.floatValue, NSDecimalNumber(string: MAXFLOAT.description).floatValue)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: "1"))?.boolValue, true)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: Int16.max.description))?.int16Value, Int16.max)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: Int32.max.description))?.int32Value, Int32.max)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: Int64.max.description))?.int64Value, Int64.max)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.doubleValue, NSDecimalNumber(string: MAXFLOAT.description).doubleValue)
|
||||
XCTAssertEqual(NSDecimalNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.floatValue, NSDecimalNumber(string: MAXFLOAT.description).floatValue)
|
||||
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSDecimalNumber(string: "1"))?.boolValue, true)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSDecimalNumber(string: Int16.max.description))?.int16Value, Int16.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSDecimalNumber(string: Int32.max.description))?.int32Value, Int32.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSDecimalNumber(string: Int64.max.description))?.int64Value, Int64.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.doubleValue, NSDecimalNumber(string: MAXFLOAT.description).doubleValue)
|
||||
XCTAssertEqual(NSNumber.cs_fromImportableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.floatValue, NSDecimalNumber(string: MAXFLOAT.description).floatValue)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: "1"))?.boolValue, true)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: Int16.max.description))?.int16Value, Int16.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: Int32.max.description))?.int32Value, Int32.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: Int64.max.description))?.int64Value, Int64.max)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.doubleValue, NSDecimalNumber(string: MAXFLOAT.description).doubleValue)
|
||||
XCTAssertEqual(NSNumber.cs_fromQueryableNativeType(NSDecimalNumber(string: MAXFLOAT.description))?.floatValue, NSDecimalNumber(string: MAXFLOAT.description).floatValue)
|
||||
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromImportableNativeType(NSNumber(value: true)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromImportableNativeType(NSNumber(value: Int16.max)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromImportableNativeType(NSNumber(value: Int32.max)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromImportableNativeType(NSNumber(value: Int64.max)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromImportableNativeType(NSNumber(value: MAXFLOAT)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromImportableNativeType(NSNumber(value: Double(MAXFLOAT))))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromQueryableNativeType(NSNumber(value: true)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromQueryableNativeType(NSNumber(value: Int16.max)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromQueryableNativeType(NSNumber(value: Int32.max)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromQueryableNativeType(NSNumber(value: Int64.max)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromQueryableNativeType(NSNumber(value: MAXFLOAT)))
|
||||
XCTAssertNil(NSDecimalNumber.cs_fromQueryableNativeType(NSNumber(value: Double(MAXFLOAT))))
|
||||
|
||||
XCTAssertEqual(true.cs_toQueryableNativeType(), NSNumber(value: true))
|
||||
XCTAssertEqual(Int16.max.cs_toQueryableNativeType(), NSNumber(value: Int16.max))
|
||||
@@ -95,7 +95,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
]
|
||||
)
|
||||
XCTAssertNil(object)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 0)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -103,7 +103,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,9 @@ class ImportTests: BaseTestDataTestCase {
|
||||
catch _ as TestInsertError {
|
||||
|
||||
errorExpectation.fulfill()
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>())
|
||||
let object = try transaction.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertNil(object?.testEntityID)
|
||||
XCTAssertNil(object?.testBoolean)
|
||||
@@ -182,7 +182,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
]
|
||||
)
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertNil(object?.testEntityID)
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
|
||||
@@ -202,7 +202,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
#keyPath(TestEntity1.testDate): self.dateFormatter.date(from: "2000-01-02T00:00:00Z")!
|
||||
]
|
||||
)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertNil(object?.testEntityID)
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 2))
|
||||
@@ -254,7 +254,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
sourceArray: sourceArray
|
||||
)
|
||||
XCTAssertEqual(objects.count, 1)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = objects[0]
|
||||
let dictionary = sourceArray[1]
|
||||
@@ -316,9 +316,9 @@ class ImportTests: BaseTestDataTestCase {
|
||||
catch _ as TestInsertError {
|
||||
|
||||
errorExpectation.fulfill()
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>())
|
||||
let object = try transaction.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertNil(object?.testEntityID)
|
||||
XCTAssertNil(object?.testBoolean)
|
||||
@@ -372,7 +372,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
sourceArray: sourceArray
|
||||
)
|
||||
XCTAssertEqual(objects.count, sourceArray.count)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 2)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 2)
|
||||
|
||||
for i in 0 ..< sourceArray.count {
|
||||
|
||||
@@ -424,7 +424,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
]
|
||||
)
|
||||
XCTAssertNil(object)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
}
|
||||
do {
|
||||
|
||||
@@ -442,20 +442,19 @@ class ImportTests: BaseTestDataTestCase {
|
||||
]
|
||||
)
|
||||
XCTAssertNil(object)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
|
||||
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertNotNil(existingObjects)
|
||||
XCTAssertEqual(existingObjects?.count, 1)
|
||||
let existingObjects = try transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertEqual(existingObjects.count, 1)
|
||||
|
||||
let existingObject = existingObjects?[0]
|
||||
XCTAssertEqual(existingObject?.testEntityID, NSNumber(value: 105))
|
||||
XCTAssertEqual(existingObject?.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(existingObject?.testNumber, NSNumber(value: 5))
|
||||
XCTAssertEqual(existingObject?.testDecimal, NSDecimalNumber(string: "5"))
|
||||
XCTAssertEqual(existingObject?.testString, "nil:TestEntity1:5")
|
||||
XCTAssertEqual(existingObject?.testData, ("nil:TestEntity1:5" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(existingObject?.testDate, self.dateFormatter.date(from: "2000-01-05T00:00:00Z")!)
|
||||
let existingObject = existingObjects[0]
|
||||
XCTAssertEqual(existingObject.testEntityID, NSNumber(value: 105))
|
||||
XCTAssertEqual(existingObject.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(existingObject.testNumber, NSNumber(value: 5))
|
||||
XCTAssertEqual(existingObject.testDecimal, NSDecimalNumber(string: "5"))
|
||||
XCTAssertEqual(existingObject.testString, "nil:TestEntity1:5")
|
||||
XCTAssertEqual(existingObject.testData, ("nil:TestEntity1:5" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(existingObject.testDate, self.dateFormatter.date(from: "2000-01-05T00:00:00Z")!)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -504,7 +503,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
)
|
||||
|
||||
XCTAssertEqual(objects.count, 1)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
|
||||
let object = objects[0]
|
||||
let dictionary = sourceArray[1]
|
||||
@@ -565,7 +564,9 @@ class ImportTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(objects.count, 2)
|
||||
|
||||
zip(objects, sourceArray)
|
||||
.forEach { object, dictionary in
|
||||
.forEach {
|
||||
|
||||
let (object, dictionary) = $0
|
||||
XCTAssertEqual(object.testEntityID, dictionary[(#keyPath(TestEntity1.testEntityID))] as? NSNumber)
|
||||
XCTAssertEqual(object.testBoolean, dictionary[(#keyPath(TestEntity1.testBoolean))] as? NSNumber)
|
||||
XCTAssertEqual(object.testNumber, dictionary[(#keyPath(TestEntity1.testNumber))] as? NSNumber)
|
||||
@@ -616,9 +617,9 @@ class ImportTests: BaseTestDataTestCase {
|
||||
catch _ as TestInsertError {
|
||||
|
||||
errorExpectation.fulfill()
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
|
||||
let object = try transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 106))
|
||||
XCTAssertNil(object?.testBoolean)
|
||||
@@ -655,21 +656,19 @@ class ImportTests: BaseTestDataTestCase {
|
||||
catch _ as TestUpdateError {
|
||||
|
||||
errorExpectation.fulfill()
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
|
||||
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertNotNil(existingObjects)
|
||||
XCTAssertEqual(existingObjects?.count, 1)
|
||||
let existingObjects = try transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertEqual(existingObjects.count, 1)
|
||||
|
||||
let existingObject = existingObjects?[0]
|
||||
XCTAssertNotNil(existingObject)
|
||||
XCTAssertEqual(existingObject?.testEntityID, NSNumber(value: 105))
|
||||
XCTAssertEqual(existingObject?.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(existingObject?.testNumber, NSNumber(value: 5))
|
||||
XCTAssertEqual(existingObject?.testDecimal, NSDecimalNumber(string: "5"))
|
||||
XCTAssertEqual(existingObject?.testString, "nil:TestEntity1:5")
|
||||
XCTAssertEqual(existingObject?.testData, ("nil:TestEntity1:5" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(existingObject?.testDate, self.dateFormatter.date(from: "2000-01-05T00:00:00Z")!)
|
||||
let existingObject = existingObjects[0]
|
||||
XCTAssertEqual(existingObject.testEntityID, NSNumber(value: 105))
|
||||
XCTAssertEqual(existingObject.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(existingObject.testNumber, NSNumber(value: 5))
|
||||
XCTAssertEqual(existingObject.testDecimal, NSDecimalNumber(string: "5"))
|
||||
XCTAssertEqual(existingObject.testString, "nil:TestEntity1:5")
|
||||
XCTAssertEqual(existingObject.testData, ("nil:TestEntity1:5" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(existingObject.testDate, self.dateFormatter.date(from: "2000-01-05T00:00:00Z")!)
|
||||
}
|
||||
self.checkExpectationsImmediately()
|
||||
}
|
||||
@@ -708,7 +707,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
]
|
||||
)
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 106))
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
@@ -733,7 +732,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
]
|
||||
)
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 106))
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
|
||||
@@ -743,11 +742,10 @@ class ImportTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:7" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-07T00:00:00Z")!)
|
||||
|
||||
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
|
||||
XCTAssertNotNil(existingObjects)
|
||||
XCTAssertEqual(existingObjects?.count, 1)
|
||||
let existingObjects = try transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
|
||||
XCTAssertEqual(existingObjects.count, 1)
|
||||
|
||||
let existingObject = existingObjects?[0]
|
||||
let existingObject = existingObjects[0]
|
||||
XCTAssertEqual(existingObject, object)
|
||||
}
|
||||
}
|
||||
@@ -797,7 +795,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
sourceArray: sourceArray
|
||||
)
|
||||
XCTAssertEqual(objects.count, 1)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
|
||||
let object = objects[0]
|
||||
let dictionary = sourceArray[1]
|
||||
@@ -862,10 +860,10 @@ class ImportTests: BaseTestDataTestCase {
|
||||
catch _ as TestIDError {
|
||||
|
||||
errorExpectation.fulfill()
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
|
||||
XCTAssertNil(transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106)))
|
||||
XCTAssertNil(transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 107)))
|
||||
XCTAssertNil(try transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106)))
|
||||
XCTAssertNil(try transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 107)))
|
||||
}
|
||||
transaction.unsafeContext().reset()
|
||||
self.checkExpectationsImmediately()
|
||||
@@ -908,7 +906,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
|
||||
errorExpectation.fulfill()
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
|
||||
let object = try transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 106))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 106))
|
||||
XCTAssertNil(object?.testBoolean)
|
||||
@@ -949,9 +947,9 @@ class ImportTests: BaseTestDataTestCase {
|
||||
catch _ as TestUpdateError {
|
||||
|
||||
errorExpectation.fulfill()
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 5)
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
let object = try transaction.fetchOne(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 105))
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
@@ -961,11 +959,10 @@ class ImportTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:5" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-05T00:00:00Z")!)
|
||||
|
||||
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertNotNil(existingObjects)
|
||||
XCTAssertEqual(existingObjects?.count, 1)
|
||||
let existingObjects = try transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertEqual(existingObjects.count, 1)
|
||||
|
||||
let existingObject = existingObjects?[0]
|
||||
let existingObject = existingObjects[0]
|
||||
XCTAssertEqual(existingObject, object)
|
||||
}
|
||||
transaction.context.reset()
|
||||
@@ -1016,7 +1013,7 @@ class ImportTests: BaseTestDataTestCase {
|
||||
sourceArray: sourceArray
|
||||
)
|
||||
XCTAssertEqual(objects.count, sourceArray.count)
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 6)
|
||||
for i in 0 ..< sourceArray.count {
|
||||
|
||||
let object = objects[i]
|
||||
@@ -1030,11 +1027,10 @@ class ImportTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(object.testData, dictionary[(#keyPath(TestEntity1.testData))] as? Data)
|
||||
XCTAssertEqual(object.testDate, dictionary[(#keyPath(TestEntity1.testDate))] as? Date)
|
||||
}
|
||||
let existingObjects = transaction.fetchAll(From<TestEntity1>(), Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertNotNil(existingObjects)
|
||||
XCTAssertEqual(existingObjects?.count, 1)
|
||||
let existingObjects = try transaction.fetchAll(From<TestEntity1>(), Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 105))
|
||||
XCTAssertEqual(existingObjects.count, 1)
|
||||
|
||||
let existingObject = existingObjects?[0]
|
||||
let existingObject = existingObjects[0]
|
||||
XCTAssertEqual(existingObject, objects[0])
|
||||
}
|
||||
)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>6.2.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// IntoTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ListObserverTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -31,7 +31,7 @@ import CoreStore
|
||||
|
||||
// MARK: - ListObserverTests
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@available(macOS 10.12, *)
|
||||
class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
@objc
|
||||
@@ -43,7 +43,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
@@ -54,7 +54,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
var events = 0
|
||||
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorWillChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -68,7 +68,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
}
|
||||
)
|
||||
let didInsertSectionExpectation = self.expectation(
|
||||
forNotification: "listMonitor:didInsertSection:toSectionIndex:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -76,7 +76,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
XCTAssertEqual(
|
||||
((note.userInfo as NSDictionary?) ?? [:]),
|
||||
[
|
||||
"sectionInfo": monitor.sectionInfoAtIndex(0),
|
||||
"sectionInfo": monitor.sectionInfo(at: 0),
|
||||
"sectionIndex": 0
|
||||
] as NSDictionary
|
||||
)
|
||||
@@ -88,7 +88,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
}
|
||||
)
|
||||
let didInsertObjectExpectation = self.expectation(
|
||||
forNotification: "listMonitor:didInsertObject:toIndexPath:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -120,7 +120,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorDidChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -171,21 +171,21 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
XCTAssertTrue(monitor.hasSections())
|
||||
XCTAssertEqual(monitor.numberOfSections(), 2)
|
||||
XCTAssertTrue(monitor.hasObjects())
|
||||
XCTAssertTrue(monitor.hasObjectsInSection(0))
|
||||
XCTAssertEqual(monitor.numberOfObjectsInSection(0), 2)
|
||||
XCTAssertEqual(monitor.numberOfObjectsInSection(1), 3)
|
||||
XCTAssertTrue(monitor.hasObjects(in: 0))
|
||||
XCTAssertEqual(monitor.numberOfObjects(in: 0), 2)
|
||||
XCTAssertEqual(monitor.numberOfObjects(in: 1), 3)
|
||||
|
||||
var events = 0
|
||||
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorWillChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -198,62 +198,60 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
for _ in 1 ... 2 {
|
||||
|
||||
let didUpdateObjectExpectation = self.expectation(
|
||||
forNotification: "listMonitor:didUpdateObject:atIndexPath:",
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
let didUpdateObjectExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssert(events == 1 || events == 2)
|
||||
|
||||
let userInfo = note.userInfo
|
||||
XCTAssertNotNil(userInfo)
|
||||
XCTAssertEqual(
|
||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
["indexPath", "object"]
|
||||
)
|
||||
|
||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
let object = userInfo?["object"] as? TestEntity1
|
||||
|
||||
switch object?.testEntityID {
|
||||
|
||||
XCTAssert(events == 1 || events == 2)
|
||||
case NSNumber(value: 101)?:
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
|
||||
let userInfo = note.userInfo
|
||||
XCTAssertNotNil(userInfo)
|
||||
XCTAssertEqual(
|
||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
["indexPath", "object"]
|
||||
)
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
|
||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
|
||||
|
||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
let object = userInfo?["object"] as? TestEntity1
|
||||
case NSNumber(value: 102)?:
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
|
||||
switch object?.testEntityID {
|
||||
|
||||
case NSNumber(value: 101)?:
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
|
||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
|
||||
|
||||
case NSNumber(value: 102)?:
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
|
||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
}
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
}
|
||||
return events == 1 || events == 2
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
|
||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
}
|
||||
)
|
||||
}
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
}
|
||||
return events == 1 || events == 2
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorDidChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -270,9 +268,9 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
if let object = transaction.fetchOne(
|
||||
if let object = try transaction.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
||||
|
||||
object.testNumber = NSNumber(value: 11)
|
||||
object.testDecimal = NSDecimalNumber(string: "11")
|
||||
@@ -284,9 +282,9 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
if let object = transaction.fetchOne(
|
||||
if let object = try transaction.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
|
||||
object.testNumber = NSNumber(value: 22)
|
||||
object.testDecimal = NSDecimalNumber(string: "22")
|
||||
@@ -325,14 +323,14 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
var events = 0
|
||||
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorWillChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -346,7 +344,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
}
|
||||
)
|
||||
let didMoveObjectExpectation = self.expectation(
|
||||
forNotification: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -379,7 +377,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorDidChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -396,9 +394,9 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
if let object = transaction.fetchOne(
|
||||
if let object = try transaction.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
|
||||
object.testBoolean = NSNumber(value: true)
|
||||
}
|
||||
@@ -433,14 +431,14 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
var events = 0
|
||||
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorWillChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -453,40 +451,37 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
for _ in 1 ... 2 {
|
||||
|
||||
let didUpdateObjectExpectation = self.expectation(
|
||||
forNotification: "listMonitor:didDeleteObject:fromIndexPath:",
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
let didUpdateObjectExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssert(events == 1 || events == 2)
|
||||
|
||||
let userInfo = note.userInfo
|
||||
XCTAssertNotNil(userInfo)
|
||||
XCTAssertEqual(
|
||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
["indexPath", "object"]
|
||||
)
|
||||
|
||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
|
||||
XCTAssertEqual(indexPath?.section, 0)
|
||||
XCTAssert(indexPath?.index(atPosition: 1) == 0 || indexPath?.index(atPosition: 1) == 1)
|
||||
|
||||
let object = userInfo?["object"] as? TestEntity1
|
||||
XCTAssertEqual(object?.isDeleted, true)
|
||||
|
||||
defer {
|
||||
|
||||
XCTAssert(events == 1 || events == 2)
|
||||
|
||||
let userInfo = note.userInfo
|
||||
XCTAssertNotNil(userInfo)
|
||||
XCTAssertEqual(
|
||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
["indexPath", "object"]
|
||||
)
|
||||
|
||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
|
||||
XCTAssertEqual(indexPath?.section, 0)
|
||||
XCTAssert(indexPath?.index(atPosition: 1) == 0 || indexPath?.index(atPosition: 1) == 1)
|
||||
|
||||
let object = userInfo?["object"] as? TestEntity1
|
||||
XCTAssertEqual(object?.isDeleted, true)
|
||||
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
}
|
||||
return events == 1 || events == 2
|
||||
events += 1
|
||||
}
|
||||
)
|
||||
}
|
||||
return events == 1 || events == 2
|
||||
}
|
||||
)
|
||||
let didDeleteSectionExpectation = self.expectation(
|
||||
forNotification: "listMonitor:didDeleteSection:fromSectionIndex:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -514,7 +509,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorDidChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -531,10 +526,11 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
transaction.deleteAll(
|
||||
let count = try transaction.deleteAll(
|
||||
From<TestEntity1>(),
|
||||
Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
||||
)
|
||||
XCTAssertEqual(count, 2)
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
@@ -555,7 +551,7 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
// MARK: TestListObserver
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@available(macOS 10.12, *)
|
||||
class TestListObserver: ListSectionObserver {
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// MigrationChainTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11759" systemVersion="16C67" minimumToolsVersion="Xcode 4.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14460.32" systemVersion="17G2307" minimumToolsVersion="Xcode 4.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
|
||||
<entity name="TestEntity1AAA" representedClassName="CoreStoreTests.TestEntity1" syncable="YES">
|
||||
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
|
||||
@@ -9,6 +9,8 @@
|
||||
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<relationship name="testToManyUnordered" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToOne" inverseEntity="TestEntity1AAA" syncable="YES"/>
|
||||
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToManyUnordered" inverseEntity="TestEntity1AAA" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="TestEntity2" representedClassName="CoreStoreTests.TestEntity2" syncable="YES">
|
||||
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
@@ -19,6 +21,8 @@
|
||||
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<relationship name="testToManyOrdered" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TestEntity2" inverseName="testToOne" inverseEntity="TestEntity2" syncable="YES"/>
|
||||
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity2" inverseName="testToManyOrdered" inverseEntity="TestEntity2" syncable="YES"/>
|
||||
</entity>
|
||||
<configuration name="Config1">
|
||||
<memberEntity name="TestEntity1AAA"/>
|
||||
@@ -27,7 +31,7 @@
|
||||
<memberEntity name="TestEntity2"/>
|
||||
</configuration>
|
||||
<elements>
|
||||
<element name="TestEntity1AAA" positionX="-63" positionY="-18" width="128" height="165"/>
|
||||
<element name="TestEntity2" positionX="-63" positionY="9" width="128" height="165"/>
|
||||
<element name="TestEntity1AAA" positionX="-63" positionY="-18" width="128" height="195"/>
|
||||
<element name="TestEntity2" positionX="-63" positionY="9" width="128" height="195"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -2,7 +2,7 @@
|
||||
// ObjectObserverTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -31,7 +31,7 @@ import CoreStore
|
||||
|
||||
// MARK: - ObjectObserverTests
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@available(macOS 10.12, *)
|
||||
class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
@objc
|
||||
@@ -41,9 +41,9 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
self.prepareTestDataForStack(stack)
|
||||
|
||||
guard let object = stack.fetchOne(
|
||||
guard let object = try stack.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -58,7 +58,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
var events = 0
|
||||
|
||||
let willUpdateExpectation = self.expectation(
|
||||
forNotification: "objectMonitor:willUpdateObject:",
|
||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -75,7 +75,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
}
|
||||
)
|
||||
let didUpdateExpectation = self.expectation(
|
||||
forNotification: "objectMonitor:didUpdateObject:changedPersistentKeys:",
|
||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -138,9 +138,9 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
self.prepareTestDataForStack(stack)
|
||||
|
||||
guard let object = stack.fetchOne(
|
||||
guard let object = try stack.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -155,7 +155,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
var events = 0
|
||||
|
||||
let didDeleteExpectation = self.expectation(
|
||||
forNotification: "objectMonitor:didDeleteObject:",
|
||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -203,7 +203,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
// MARK: TestObjectObserver
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@available(macOS 10.12, *)
|
||||
class TestObjectObserver: ObjectObserver {
|
||||
|
||||
typealias ObjectEntityType = TestEntity1
|
||||
@@ -219,7 +219,7 @@ class TestObjectObserver: ObjectObserver {
|
||||
)
|
||||
}
|
||||
|
||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<String>) {
|
||||
|
||||
NotificationCenter.default.post(
|
||||
name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// OrderByTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -38,21 +38,21 @@ final class OrderByTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let orderBy = OrderBy()
|
||||
XCTAssertEqual(orderBy, OrderBy([NSSortDescriptor]()))
|
||||
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key", ascending: false)))
|
||||
let orderBy = OrderBy<NSManagedObject>()
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([NSSortDescriptor]()))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key", ascending: false)))
|
||||
XCTAssertTrue(orderBy.sortDescriptors.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
|
||||
let orderBy = OrderBy(sortDescriptor)
|
||||
let orderBy = OrderBy<NSManagedObject>(sortDescriptor)
|
||||
XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
|
||||
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, OrderBy<NSManagedObject>(.ascending("key1")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key1", ascending: false)))
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
|
||||
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
|
||||
}
|
||||
do {
|
||||
@@ -61,76 +61,76 @@ final class OrderByTests: XCTestCase {
|
||||
NSSortDescriptor(key: "key1", ascending: true),
|
||||
NSSortDescriptor(key: "key2", ascending: false)
|
||||
]
|
||||
let orderBy = OrderBy(sortDescriptors)
|
||||
XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
|
||||
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
|
||||
let orderBy = OrderBy<NSManagedObject>(sortDescriptors)
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
||||
XCTAssertNotEqual(
|
||||
orderBy,
|
||||
OrderBy(
|
||||
OrderBy<NSManagedObject>(
|
||||
[
|
||||
NSSortDescriptor(key: "key1", ascending: false),
|
||||
NSSortDescriptor(key: "key2", ascending: false)
|
||||
]
|
||||
)
|
||||
)
|
||||
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
|
||||
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
|
||||
}
|
||||
do {
|
||||
|
||||
let orderBy = OrderBy(.ascending("key1"))
|
||||
let orderBy = OrderBy<NSManagedObject>(.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([sortDescriptor]))
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptor))
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
|
||||
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
|
||||
}
|
||||
do {
|
||||
|
||||
let orderBy = OrderBy(.ascending("key1"), .descending("key2"))
|
||||
let orderBy = OrderBy<NSManagedObject>(.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<NSManagedObject>(sortDescriptors))
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
||||
XCTAssertNotEqual(
|
||||
orderBy,
|
||||
OrderBy(
|
||||
OrderBy<NSManagedObject>(
|
||||
[
|
||||
NSSortDescriptor(key: "key1", ascending: false),
|
||||
NSSortDescriptor(key: "key2", ascending: false)
|
||||
]
|
||||
)
|
||||
)
|
||||
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
|
||||
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
|
||||
}
|
||||
do {
|
||||
|
||||
let sortKeys: [SortKey] = [.ascending("key1"), .descending("key2")]
|
||||
let orderBy = OrderBy(sortKeys)
|
||||
let sortKeys: [OrderBy<NSManagedObject>.SortKey] = [.ascending("key1"), .descending("key2")]
|
||||
let orderBy = OrderBy<NSManagedObject>(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<NSManagedObject>(sortDescriptors))
|
||||
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
||||
XCTAssertNotEqual(
|
||||
orderBy,
|
||||
OrderBy(
|
||||
OrderBy<NSManagedObject>(
|
||||
[
|
||||
NSSortDescriptor(key: "key1", ascending: false),
|
||||
NSSortDescriptor(key: "key2", ascending: false)
|
||||
]
|
||||
)
|
||||
)
|
||||
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
|
||||
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.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<NSManagedObject>(.ascending("key1"))
|
||||
let orderBy2 = OrderBy<NSManagedObject>(.descending("key2"))
|
||||
let orderBy3 = OrderBy<NSManagedObject>(.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<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
|
||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.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<NSManagedObject>(.ascending("key1"), .descending("key2")))
|
||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.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<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
|
||||
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")) + OrderBy<NSManagedObject>(.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<NSManagedObject>(.ascending("key"))
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
orderBy.applyToFetchRequest(request)
|
||||
XCTAssertNotNil(request.sortDescriptors)
|
||||
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
// SectionByTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -31,7 +31,7 @@ import CoreStore
|
||||
|
||||
//MARK: - SectionByTests
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@available(macOS 10.12, *)
|
||||
final class SectionByTests: XCTestCase {
|
||||
|
||||
@objc
|
||||
@@ -39,13 +39,13 @@ final class SectionByTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let sectionBy = SectionBy("key")
|
||||
let sectionBy = SectionBy<NSManagedObject>("key")
|
||||
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
|
||||
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key")
|
||||
}
|
||||
do {
|
||||
|
||||
let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } }
|
||||
let sectionBy = SectionBy<NSManagedObject>("key") { $0.flatMap { "\($0):suffix" } }
|
||||
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
|
||||
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
|
||||
XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SelectTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -38,7 +38,7 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term: SelectTerm = "attribute"
|
||||
let term: SelectTerm<NSManagedObject> = "attribute"
|
||||
XCTAssertEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
@@ -58,7 +58,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.attribute("attribute")
|
||||
let term = SelectTerm<NSManagedObject>.attribute("attribute")
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
@@ -82,7 +82,7 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.average("attribute")
|
||||
let term = SelectTerm<NSManagedObject>.average("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
|
||||
@@ -106,7 +106,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.average("attribute", as: "alias")
|
||||
let term = SelectTerm<NSManagedObject>.average("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
|
||||
@@ -135,7 +135,7 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.count("attribute")
|
||||
let term = SelectTerm<NSManagedObject>.count("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
|
||||
@@ -159,7 +159,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.count("attribute", as: "alias")
|
||||
let term = SelectTerm<NSManagedObject>.count("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
|
||||
@@ -188,7 +188,7 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.maximum("attribute")
|
||||
let term = SelectTerm<NSManagedObject>.maximum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
|
||||
@@ -212,7 +212,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.maximum("attribute", as: "alias")
|
||||
let term = SelectTerm<NSManagedObject>.maximum("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
|
||||
@@ -241,7 +241,7 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.minimum("attribute")
|
||||
let term = SelectTerm<NSManagedObject>.minimum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
|
||||
@@ -265,7 +265,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.minimum("attribute", as: "alias")
|
||||
let term = SelectTerm<NSManagedObject>.minimum("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
|
||||
@@ -294,7 +294,7 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.sum("attribute")
|
||||
let term = SelectTerm<NSManagedObject>.sum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
|
||||
@@ -318,7 +318,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.sum("attribute", as: "alias")
|
||||
let term = SelectTerm<NSManagedObject>.sum("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
|
||||
@@ -347,7 +347,7 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.objectID()
|
||||
let term = SelectTerm<NSManagedObject>.objectID()
|
||||
XCTAssertEqual(term, SelectTerm.objectID())
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
@@ -368,7 +368,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.objectID(as: "alias")
|
||||
let term = SelectTerm<NSManagedObject>.objectID(as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
@@ -393,12 +393,12 @@ 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<NSManagedObject>.attribute("attribute1")
|
||||
let term2 = SelectTerm<NSManagedObject>.attribute("attribute2")
|
||||
let term3 = SelectTerm<NSManagedObject>.attribute("attribute3")
|
||||
do {
|
||||
|
||||
let select = Select<Int>(term1, term2, term3)
|
||||
let select = Select<NSManagedObject, Int>(term1, term2, term3)
|
||||
XCTAssertEqual(select.selectTerms, [term1, term2, term3])
|
||||
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
|
||||
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
|
||||
@@ -408,7 +408,7 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let select = Select<Int>([term1, term2, term3])
|
||||
let select = Select<NSManagedObject, Int>([term1, term2, term3])
|
||||
XCTAssertEqual(select.selectTerms, [term1, term2, term3])
|
||||
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
|
||||
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SetupTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -330,7 +330,14 @@ class SetupTests: BaseTestDataTestCase {
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
try! stack.addStorageAndWait(sqliteStore)
|
||||
try! stack.addStorageAndWait(
|
||||
SQLiteStore.legacy(
|
||||
fileName: sqliteStore.fileURL.lastPathComponent,
|
||||
configuration: sqliteStore.configuration,
|
||||
migrationMappingProviders: sqliteStore.migrationMappingProviders,
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
self.prepareTestDataForStack(stack)
|
||||
}
|
||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// StorageInterfaceTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -83,7 +83,21 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
let store = SQLiteStore()
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertNil(store.configuration)
|
||||
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
||||
)
|
||||
}
|
||||
else {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL)
|
||||
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
|
||||
@@ -93,8 +107,8 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
@objc
|
||||
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
|
||||
|
||||
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
|
||||
.appendingPathComponent(NSUUID().uuidString, isDirectory: false)!
|
||||
let fileURL = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent(UUID().uuidString, isDirectory: false)
|
||||
.appendingPathExtension("db")
|
||||
let mappingProvider = XcodeSchemaMappingProvider(
|
||||
from: "V1", to: "V2",
|
||||
@@ -109,7 +123,21 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
)
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
||||
)
|
||||
}
|
||||
else {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(store.fileURL, fileURL)
|
||||
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
|
||||
@@ -132,7 +160,21 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
)
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
||||
)
|
||||
}
|
||||
else {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.defaultRootDirectory)
|
||||
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
|
||||
@@ -167,7 +209,21 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
let store = SQLiteStore.legacy()
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertNil(store.configuration)
|
||||
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
||||
)
|
||||
}
|
||||
else {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(store.fileURL, SQLiteStore.legacyDefaultFileURL)
|
||||
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
|
||||
@@ -190,7 +246,21 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
)
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
|
||||
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
|
||||
)
|
||||
}
|
||||
else {
|
||||
|
||||
XCTAssertEqual(
|
||||
store.storeOptions as NSDictionary?,
|
||||
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
|
||||
)
|
||||
}
|
||||
|
||||
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.legacyDefaultRootDirectory)
|
||||
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// TestEntity1.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2014 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -36,4 +36,6 @@ class TestEntity1: NSManagedObject {
|
||||
@NSManaged var testDecimal: NSDecimalNumber?
|
||||
@NSManaged var testData: Data?
|
||||
@NSManaged var testNil: String?
|
||||
@NSManaged var testToOne: TestEntity1?
|
||||
@NSManaged var testToManyUnordered: NSSet?
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// TestEntity1.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2014 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -36,4 +36,6 @@ class TestEntity2: NSManagedObject {
|
||||
@NSManaged var testDecimal: NSDecimalNumber?
|
||||
@NSManaged var testData: Data?
|
||||
@NSManaged var testNil: String?
|
||||
@NSManaged var testToOne: TestEntity2?
|
||||
@NSManaged var testToManyOrdered: NSOrderedSet?
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// TransactionTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -69,9 +69,9 @@ final class TransactionTests: BaseTestCase {
|
||||
self.checkExpectationsImmediately()
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.fetchSource()?.unsafeContext(), stack.mainContext)
|
||||
XCTAssertEqual(object?.querySource()?.unsafeContext(), stack.mainContext)
|
||||
@@ -84,14 +84,14 @@ final class TransactionTests: BaseTestCase {
|
||||
do {
|
||||
|
||||
let updateExpectation = self.expectation(description: "update")
|
||||
let hasChanges: Bool = try! stack.perform(
|
||||
let hasChanges: Bool = try stack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
defer {
|
||||
|
||||
updateExpectation.fulfill()
|
||||
}
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
// TODO: convert fetch methods to throwing methods
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
@@ -107,9 +107,9 @@ final class TransactionTests: BaseTestCase {
|
||||
self.checkExpectationsImmediately()
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
@@ -128,7 +128,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
deleteExpectation.fulfill()
|
||||
}
|
||||
let object = transaction.fetchOne(From<TestEntity1>())
|
||||
let object = try transaction.fetchOne(From<TestEntity1>())
|
||||
transaction.delete(object)
|
||||
return transaction.hasChanges
|
||||
}
|
||||
@@ -141,9 +141,9 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
self.checkExpectationsImmediately()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNil(object)
|
||||
}
|
||||
}
|
||||
@@ -184,10 +184,10 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
self.checkExpectationsImmediately()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
let object = try stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
@@ -206,7 +206,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
updateExpectation.fulfill()
|
||||
}
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>("Config1")) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>("Config1")) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
@@ -226,10 +226,10 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
self.checkExpectationsImmediately()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
let object = try stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
@@ -248,7 +248,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
deleteExpectation.fulfill()
|
||||
}
|
||||
let object = transaction.fetchOne(From<TestEntity1>("Config1"))
|
||||
let object = try transaction.fetchOne(From<TestEntity1>("Config1"))
|
||||
transaction.delete(object)
|
||||
|
||||
return transaction.hasChanges
|
||||
@@ -262,8 +262,8 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
self.checkExpectationsImmediately()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 0)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,17 +294,17 @@ final class TransactionTests: BaseTestCase {
|
||||
)
|
||||
self.checkExpectationsImmediately()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNil(object)
|
||||
}
|
||||
let testDate = Date()
|
||||
do {
|
||||
|
||||
let createExpectation = self.expectation(description: "create")
|
||||
let dataPrepared: Void? = try? stack.perform(
|
||||
synchronous: { (transaction) in
|
||||
try stack.perform(
|
||||
synchronous: { (transaction) -> Void in
|
||||
|
||||
let object = transaction.create(Into<TestEntity1>())
|
||||
object.testEntityID = NSNumber(value: 1)
|
||||
@@ -313,10 +313,7 @@ final class TransactionTests: BaseTestCase {
|
||||
object.testDate = testDate
|
||||
}
|
||||
)
|
||||
if dataPrepared != nil {
|
||||
|
||||
createExpectation.fulfill()
|
||||
}
|
||||
createExpectation.fulfill()
|
||||
self.checkExpectationsImmediately()
|
||||
}
|
||||
do {
|
||||
@@ -329,7 +326,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
updateDiscardExpectation.fulfill()
|
||||
}
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
@@ -343,9 +340,9 @@ final class TransactionTests: BaseTestCase {
|
||||
)
|
||||
self.checkExpectationsImmediately()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
@@ -362,7 +359,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
deleteDiscardExpectation.fulfill()
|
||||
}
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
@@ -374,9 +371,9 @@ final class TransactionTests: BaseTestCase {
|
||||
)
|
||||
self.checkExpectationsImmediately()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
@@ -387,7 +384,7 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
@available(macOS 10.12, *)
|
||||
@objc
|
||||
dynamic func test_ThatSynchronousTransactions_CanCommitWithoutWaitingForMerges() {
|
||||
|
||||
@@ -396,7 +393,7 @@ final class TransactionTests: BaseTestCase {
|
||||
let observer = TestListObserver()
|
||||
let monitor = stack.monitorList(
|
||||
From<TestEntity1>(),
|
||||
OrderBy(.ascending("testEntityID"))
|
||||
OrderBy<TestEntity1>(.ascending("testEntityID"))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
@@ -404,7 +401,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
var events = 0
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorWillChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -418,7 +415,7 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
)
|
||||
let didInsertObjectExpectation = self.expectation(
|
||||
forNotification: "listMonitor:didInsertObject:toIndexPath:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -448,7 +445,7 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: "listMonitorDidChange:",
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -520,19 +517,26 @@ final class TransactionTests: BaseTestCase {
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.fetchSource()?.unsafeContext(), stack.mainContext)
|
||||
XCTAssertEqual(object?.querySource()?.unsafeContext(), stack.mainContext)
|
||||
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
XCTAssertEqual(object?.testNumber, 100)
|
||||
XCTAssertEqual(object?.testDate, testDate)
|
||||
createExpectation.fulfill()
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.fetchSource()?.unsafeContext(), stack.mainContext)
|
||||
XCTAssertEqual(object?.querySource()?.unsafeContext(), stack.mainContext)
|
||||
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
XCTAssertEqual(object?.testNumber, 100)
|
||||
XCTAssertEqual(object?.testDate, testDate)
|
||||
createExpectation.fulfill()
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
@@ -546,7 +550,7 @@ final class TransactionTests: BaseTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
@@ -560,16 +564,23 @@ final class TransactionTests: BaseTestCase {
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
XCTAssertEqual(object?.testNumber, 200)
|
||||
XCTAssertEqual(object?.testDate, Date.distantFuture)
|
||||
updateExpectation.fulfill()
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
XCTAssertEqual(object?.testNumber, 200)
|
||||
XCTAssertEqual(object?.testDate, Date.distantFuture)
|
||||
updateExpectation.fulfill()
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
@@ -583,7 +594,7 @@ final class TransactionTests: BaseTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>())
|
||||
let object = try transaction.fetchOne(From<TestEntity1>())
|
||||
transaction.delete(object)
|
||||
|
||||
return transaction.hasChanges
|
||||
@@ -591,12 +602,19 @@ final class TransactionTests: BaseTestCase {
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNil(object)
|
||||
deleteExpectation.fulfill()
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 0)
|
||||
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNil(object)
|
||||
deleteExpectation.fulfill()
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
@@ -631,17 +649,24 @@ final class TransactionTests: BaseTestCase {
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
XCTAssertEqual(object?.testNumber, 100)
|
||||
XCTAssertEqual(object?.testDate, testDate)
|
||||
createExpectation.fulfill()
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = try stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
XCTAssertEqual(object?.testNumber, 100)
|
||||
XCTAssertEqual(object?.testDate, testDate)
|
||||
createExpectation.fulfill()
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
@@ -655,7 +680,7 @@ final class TransactionTests: BaseTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>("Config1")) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>("Config1")) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
@@ -669,17 +694,24 @@ final class TransactionTests: BaseTestCase {
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
XCTAssertEqual(object?.testNumber, 200)
|
||||
XCTAssertEqual(object?.testDate, Date.distantFuture)
|
||||
updateExpectation.fulfill()
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = try stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
XCTAssertEqual(object?.testNumber, 200)
|
||||
XCTAssertEqual(object?.testDate, Date.distantFuture)
|
||||
updateExpectation.fulfill()
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
@@ -693,7 +725,7 @@ final class TransactionTests: BaseTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>("Config1"))
|
||||
let object = try transaction.fetchOne(From<TestEntity1>("Config1"))
|
||||
transaction.delete(object)
|
||||
|
||||
return transaction.hasChanges
|
||||
@@ -701,11 +733,21 @@ final class TransactionTests: BaseTestCase {
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 0)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
deleteExpectation.fulfill()
|
||||
|
||||
do {
|
||||
|
||||
let configCount = try stack.fetchCount(From<TestEntity1>("Config1"))
|
||||
XCTAssertEqual(configCount, 0)
|
||||
|
||||
let defaultCount = try stack.fetchCount(From<TestEntity1>(nil))
|
||||
XCTAssertEqual(defaultCount, 0)
|
||||
|
||||
deleteExpectation.fulfill()
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
@@ -737,7 +779,7 @@ final class TransactionTests: BaseTestCase {
|
||||
createDiscardExpectation.fulfill()
|
||||
try transaction.cancel()
|
||||
},
|
||||
success: {
|
||||
success: { _ in
|
||||
|
||||
XCTFail()
|
||||
},
|
||||
@@ -754,8 +796,8 @@ final class TransactionTests: BaseTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(transaction.fetchOne(From<TestEntity1>()))
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(try transaction.fetchOne(From<TestEntity1>()))
|
||||
|
||||
let object = transaction.create(Into<TestEntity1>())
|
||||
object.testEntityID = NSNumber(value: 1)
|
||||
@@ -782,7 +824,7 @@ final class TransactionTests: BaseTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -795,7 +837,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
try transaction.cancel()
|
||||
},
|
||||
success: {
|
||||
success: { _ in
|
||||
|
||||
XCTFail()
|
||||
},
|
||||
@@ -811,9 +853,9 @@ final class TransactionTests: BaseTestCase {
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
@@ -828,22 +870,29 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
try transaction.cancel()
|
||||
},
|
||||
success: {
|
||||
success: { _ in
|
||||
|
||||
XCTFail()
|
||||
},
|
||||
failure: { (error) in
|
||||
|
||||
XCTAssertEqual(error, CoreStoreError.userCancelled)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
XCTAssertEqual(object?.testNumber, 100)
|
||||
XCTAssertEqual(object?.testDate, testDate)
|
||||
deleteDiscardExpectation.fulfill()
|
||||
do {
|
||||
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
XCTAssertEqual(object?.testNumber, 100)
|
||||
XCTAssertEqual(object?.testDate, testDate)
|
||||
deleteDiscardExpectation.fulfill()
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -878,9 +927,9 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTAssertTrue(transaction.hasChanges)
|
||||
try transaction.commitAndWait()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.fetchSource()?.unsafeContext(), stack.mainContext)
|
||||
XCTAssertEqual(object?.querySource()?.unsafeContext(), stack.mainContext)
|
||||
@@ -897,7 +946,7 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -911,9 +960,9 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTAssertTrue(transaction.hasChanges)
|
||||
try transaction.commitAndWait()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>())
|
||||
let object = try stack.fetchOne(From<TestEntity1>())
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
@@ -927,7 +976,7 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>())
|
||||
let object = try transaction.fetchOne(From<TestEntity1>())
|
||||
transaction.delete(object)
|
||||
|
||||
do {
|
||||
@@ -935,8 +984,8 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTAssertTrue(transaction.hasChanges)
|
||||
try transaction.commitAndWait()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(stack.fetchOne(From<TestEntity1>()))
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(try stack.fetchOne(From<TestEntity1>()))
|
||||
}
|
||||
catch {
|
||||
|
||||
@@ -967,10 +1016,10 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTAssertTrue(transaction.hasChanges)
|
||||
try transaction.commitAndWait()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
let object = try stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1")
|
||||
@@ -984,7 +1033,7 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>("Config1")) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>("Config1")) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -998,10 +1047,10 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTAssertTrue(transaction.hasChanges)
|
||||
try transaction.commitAndWait()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 1)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
|
||||
let object = stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
let object = try stack.fetchOne(From<TestEntity1>("Config1"))
|
||||
XCTAssertNotNil(object)
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testString, "string1_edit")
|
||||
@@ -1015,7 +1064,7 @@ final class TransactionTests: BaseTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let object = transaction.fetchOne(From<TestEntity1>("Config1"))
|
||||
let object = try transaction.fetchOne(From<TestEntity1>("Config1"))
|
||||
transaction.delete(object)
|
||||
|
||||
do {
|
||||
@@ -1023,8 +1072,8 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTAssertTrue(transaction.hasChanges)
|
||||
try transaction.commitAndWait()
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>("Config1")), 0)
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>("Config1")), 0)
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>(nil)), 0)
|
||||
}
|
||||
catch {
|
||||
|
||||
@@ -1050,11 +1099,11 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
transaction.rollback()
|
||||
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(transaction.fetchOne(From<TestEntity1>()))
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(try transaction.fetchOne(From<TestEntity1>()))
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(stack.fetchOne(From<TestEntity1>()))
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 0)
|
||||
XCTAssertNil(try stack.fetchOne(From<TestEntity1>()))
|
||||
}
|
||||
|
||||
let testDate = Date()
|
||||
@@ -1079,7 +1128,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
do {
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -1090,8 +1139,8 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
transaction.rollback()
|
||||
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = transaction.fetchOne(From<TestEntity1>()) {
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = try transaction.fetchOne(From<TestEntity1>()) {
|
||||
|
||||
XCTAssertEqual(object.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object.testString, "string1")
|
||||
@@ -1103,8 +1152,8 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTFail()
|
||||
}
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = stack.fetchOne(From<TestEntity1>()) {
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = try stack.fetchOne(From<TestEntity1>()) {
|
||||
|
||||
XCTAssertEqual(object.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object.testString, "string1")
|
||||
@@ -1119,7 +1168,7 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
do {
|
||||
|
||||
guard let object = transaction.fetchOne(From<TestEntity1>()) else {
|
||||
guard let object = try transaction.fetchOne(From<TestEntity1>()) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -1128,8 +1177,8 @@ final class TransactionTests: BaseTestCase {
|
||||
|
||||
transaction.rollback()
|
||||
|
||||
XCTAssertEqual(transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = transaction.fetchOne(From<TestEntity1>()) {
|
||||
XCTAssertEqual(try transaction.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = try transaction.fetchOne(From<TestEntity1>()) {
|
||||
|
||||
XCTAssertEqual(object.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object.testString, "string1")
|
||||
@@ -1141,8 +1190,8 @@ final class TransactionTests: BaseTestCase {
|
||||
XCTFail()
|
||||
}
|
||||
|
||||
XCTAssertEqual(stack.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = stack.fetchOne(From<TestEntity1>()) {
|
||||
XCTAssertEqual(try stack.fetchCount(From<TestEntity1>()), 1)
|
||||
if let object = try stack.fetchOne(From<TestEntity1>()) {
|
||||
|
||||
XCTAssertEqual(object.testEntityID, NSNumber(value: 1))
|
||||
XCTAssertEqual(object.testString, "string1")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// TweakTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -43,7 +43,7 @@ final class TweakTests: XCTestCase {
|
||||
$0.fetchLimit = 200
|
||||
$0.predicate = predicate
|
||||
}
|
||||
let request = CoreStoreFetchRequest()
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
tweak.applyToFetchRequest(request)
|
||||
XCTAssertEqual(request.fetchOffset, 100)
|
||||
XCTAssertEqual(request.fetchLimit, 200)
|
||||
|
||||
55
CoreStoreTests/VersionLockTests.swift
Normal file
55
CoreStoreTests/VersionLockTests.swift
Normal file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// VersionLockTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 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 XCTest
|
||||
|
||||
@testable
|
||||
import CoreStore
|
||||
|
||||
|
||||
//MARK: - VersionLockTests
|
||||
|
||||
final class VersionLockTests: XCTestCase {
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatVersionLocksProduceCorrectHashes() {
|
||||
|
||||
let versionLock: VersionLock = [
|
||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
||||
]
|
||||
XCTAssertEqual(
|
||||
versionLock.description,
|
||||
"""
|
||||
[
|
||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
||||
]
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// WhereTests.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -31,12 +31,12 @@ import CoreStore
|
||||
|
||||
// MARK: - XCTAssertAllEqual
|
||||
|
||||
private func XCTAssertAllEqual(_ whereClauses: Where...) {
|
||||
private func XCTAssertAllEqual<D>(_ whereClauses: Where<D>...) {
|
||||
|
||||
XCTAssertAllEqual(whereClauses)
|
||||
}
|
||||
|
||||
private func XCTAssertAllEqual(_ whereClauses: [Where]) {
|
||||
private func XCTAssertAllEqual<D>(_ whereClauses: [Where<D>]) {
|
||||
|
||||
for i in whereClauses.indices {
|
||||
|
||||
@@ -52,56 +52,331 @@ private func XCTAssertAllEqual(_ whereClauses: [Where]) {
|
||||
|
||||
final class WhereTests: XCTestCase {
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
|
||||
|
||||
XCTAssertEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
|
||||
XCTAssertEqual(String(keyPath: \Animal.color), "color")
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatExpressions_HaveCorrectKeyPaths() {
|
||||
|
||||
do {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
#keyPath(TestEntity1.testToOne.testEntityID),
|
||||
(\TestEntity1.testToOne ~ \.testEntityID).description,
|
||||
String(keyPath: \TestEntity1.testToOne ~ \.testEntityID)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
#keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered).description,
|
||||
String(keyPath: \TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).description,
|
||||
String(keyPath: \TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered)
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"master.pets",
|
||||
(\Animal.master ~ \.pets).description,
|
||||
String(keyPath: \Animal.master ~ \.pets)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).description,
|
||||
String(keyPath: \Animal.master ~ \.pets ~ \.species)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"master.pets.master",
|
||||
(\Animal.master ~ \.pets ~ \.master).description,
|
||||
String(keyPath: \Animal.master ~ \.pets ~ \.master)
|
||||
)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
#keyPath(TestEntity1.testToOne.testToManyUnordered) + ".@count",
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).count().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).count())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered) + ".@count",
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count())
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"master.pets.@count",
|
||||
(\Animal.master ~ \.pets).count().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).count())
|
||||
)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"ANY " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).any().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).any())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ANY " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any())
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"ANY master.pets",
|
||||
(\Animal.master ~ \.pets).any().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).any())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ANY master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).any().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).any())
|
||||
)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"ALL " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).all().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).all())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALL " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all())
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"ALL master.pets",
|
||||
(\Animal.master ~ \.pets).all().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).all())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALL master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).all().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).all())
|
||||
)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"NONE " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
|
||||
(\TestEntity1.testToOne ~ \.testToManyUnordered).none().description,
|
||||
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).none())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"NONE " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
|
||||
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none().description,
|
||||
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none())
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
XCTAssertEqual(
|
||||
"NONE master.pets",
|
||||
(\Animal.master ~ \.pets).none().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets).none())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"NONE master.pets.species",
|
||||
(\Animal.master ~ \.pets ~ \.species).none().description,
|
||||
String(keyPath: (\Animal.master ~ \.pets ~ \.species).none())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatWhereClauses_CanBeCreatedFromExpressionsCorrectly() {
|
||||
|
||||
do {
|
||||
|
||||
let dummy = "dummy"
|
||||
do {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testString) == dummy
|
||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.name) == dummy
|
||||
let predicate = NSPredicate(format: "master.name == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
let dummy = "dummy"
|
||||
do {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToOne ~ \.testString) == dummy
|
||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToOne.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.spouse ~ \.name) == dummy
|
||||
let predicate = NSPredicate(format: "master.spouse.name == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
let count = 3
|
||||
do {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered).count() == count
|
||||
let predicate = NSPredicate(format: "\(#keyPath(TestEntity1.testToOne.testToManyUnordered)).@count == %d", count)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets).count() == count
|
||||
let predicate = NSPredicate(format: "master.pets.@count == %d", count)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
let dummy = "dummy"
|
||||
do {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).any() == dummy
|
||||
let predicate = NSPredicate(format: "ANY \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).any() == dummy
|
||||
let predicate = NSPredicate(format: "ANY master.pets.species == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
let dummy = "dummy"
|
||||
do {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).all() == dummy
|
||||
let predicate = NSPredicate(format: "ALL \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).all() == dummy
|
||||
let predicate = NSPredicate(format: "ALL master.pets.species == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
let dummy = "dummy"
|
||||
do {
|
||||
|
||||
let whereClause: Where<TestEntity1> = (\.testToOne ~ \.testToManyUnordered ~ \TestEntity1.testString).none() == dummy
|
||||
let predicate = NSPredicate(format: "NONE \(#keyPath(TestEntity1.testToOne.testToManyUnordered)).\(#keyPath(TestEntity1.testString)) == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<TestEntity1>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause: Where<Animal> = (\.master ~ \.pets ~ \.species).none() == dummy
|
||||
let predicate = NSPredicate(format: "NONE master.pets.species == %@", dummy)
|
||||
XCTAssertEqual(whereClause, Where<Animal>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatWhereClauses_ConfigureCorrectly() {
|
||||
|
||||
do {
|
||||
|
||||
let whereClause = Where()
|
||||
XCTAssertEqual(whereClause, Where(true))
|
||||
XCTAssertNotEqual(whereClause, Where(false))
|
||||
let whereClause = Where<NSManagedObject>()
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(true))
|
||||
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
|
||||
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where(true)
|
||||
XCTAssertEqual(whereClause, Where())
|
||||
XCTAssertNotEqual(whereClause, Where(false))
|
||||
let whereClause = Where<NSManagedObject>(true)
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>())
|
||||
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
|
||||
XCTAssertEqual(whereClause.predicate, NSPredicate(value: true))
|
||||
}
|
||||
do {
|
||||
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
let whereClause = Where(predicate)
|
||||
XCTAssertEqual(whereClause, Where(predicate))
|
||||
let whereClause = Where<NSManagedObject>(predicate)
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where("%K == %@", "key", "value")
|
||||
let whereClause = Where<NSManagedObject>("%K == %@", "key", "value")
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
XCTAssertEqual(whereClause, Where(predicate))
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where("%K == %@", argumentArray: ["key", "value"])
|
||||
let whereClause = Where<NSManagedObject>("%K == %@", argumentArray: ["key", "value"])
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
XCTAssertEqual(whereClause, Where(predicate))
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where("key", isEqualTo: "value")
|
||||
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
|
||||
let predicate = NSPredicate(format: "%K == %@", "key", "value")
|
||||
XCTAssertEqual(whereClause, Where(predicate))
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let whereClause = Where("key", isMemberOf: ["value1", "value2", "value3"])
|
||||
let whereClause = Where<NSManagedObject>("key", isMemberOf: ["value1", "value2", "value3"])
|
||||
let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"])
|
||||
XCTAssertEqual(whereClause, Where(predicate))
|
||||
XCTAssertEqual(whereClause, Where<NSManagedObject>(predicate))
|
||||
XCTAssertEqual(whereClause.predicate, predicate)
|
||||
}
|
||||
}
|
||||
@@ -113,112 +388,112 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let value: Int = 100
|
||||
XCTAssertAllEqual(
|
||||
Where("%K == %d", "key", value),
|
||||
Where("%K == %d", "key", value as AnyObject),
|
||||
Where("%K == %d", "key", NSNumber(value: value)),
|
||||
Where("%K == %@", "key", value),
|
||||
Where("%K == %@", "key", value as AnyObject),
|
||||
Where("%K == %@", "key", NSNumber(value: value)),
|
||||
Where("key", isEqualTo: value),
|
||||
Where("key", isEqualTo: NSNumber(value: value))
|
||||
Where<NSManagedObject>("%K == %d", "key", value),
|
||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
|
||||
Where<NSManagedObject>("%K == %@", "key", value),
|
||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
|
||||
Where<NSManagedObject>("key", isEqualTo: value),
|
||||
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let value = NSNumber(value: 100)
|
||||
XCTAssertAllEqual(
|
||||
Where("%K == %d", "key", value),
|
||||
Where("%K == %d", "key", value as AnyObject),
|
||||
Where("%K == %d", "key", value.intValue),
|
||||
Where("%K == %@", "key", value),
|
||||
Where("%K == %@", "key", value as AnyObject),
|
||||
Where("%K == %@", "key", value.intValue),
|
||||
Where("key", isEqualTo: value),
|
||||
Where("key", isEqualTo: value.intValue)
|
||||
Where<NSManagedObject>("%K == %d", "key", value),
|
||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %d", "key", value.intValue),
|
||||
Where<NSManagedObject>("%K == %@", "key", value),
|
||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %@", "key", value.intValue),
|
||||
Where<NSManagedObject>("key", isEqualTo: value),
|
||||
Where<NSManagedObject>("key", isEqualTo: value.intValue)
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let value: Int64 = Int64.max
|
||||
XCTAssertAllEqual(
|
||||
Where("%K == %d", "key", value),
|
||||
Where("%K == %d", "key", value as AnyObject),
|
||||
Where("%K == %d", "key", NSNumber(value: value)),
|
||||
Where("%K == %@", "key", value),
|
||||
Where("%K == %@", "key", value as AnyObject),
|
||||
Where("%K == %@", "key", NSNumber(value: value)),
|
||||
Where("key", isEqualTo: value),
|
||||
Where("key", isEqualTo: NSNumber(value: value))
|
||||
Where<NSManagedObject>("%K == %d", "key", value),
|
||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
|
||||
Where<NSManagedObject>("%K == %@", "key", value),
|
||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
|
||||
Where<NSManagedObject>("key", isEqualTo: value),
|
||||
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let value = NSNumber(value: Int64.max)
|
||||
XCTAssertAllEqual(
|
||||
Where("%K == %d", "key", value),
|
||||
Where("%K == %d", "key", value as AnyObject),
|
||||
Where("%K == %d", "key", value.int64Value),
|
||||
Where("%K == %@", "key", value),
|
||||
Where("%K == %@", "key", value as AnyObject),
|
||||
Where("%K == %@", "key", value.int64Value),
|
||||
Where("key", isEqualTo: value),
|
||||
Where("key", isEqualTo: value.int64Value)
|
||||
Where<NSManagedObject>("%K == %d", "key", value),
|
||||
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %d", "key", value.int64Value),
|
||||
Where<NSManagedObject>("%K == %@", "key", value),
|
||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %@", "key", value.int64Value),
|
||||
Where<NSManagedObject>("key", isEqualTo: value),
|
||||
Where<NSManagedObject>("key", isEqualTo: value.int64Value)
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let value: String = "value"
|
||||
XCTAssertAllEqual(
|
||||
Where("%K == %s", "key", value),
|
||||
Where("%K == %s", "key", value as AnyObject),
|
||||
Where("%K == %s", "key", NSString(string: value)),
|
||||
Where("%K == %@", "key", value),
|
||||
Where("%K == %@", "key", value as AnyObject),
|
||||
Where("%K == %@", "key", NSString(string: value)),
|
||||
Where("key", isEqualTo: value),
|
||||
Where("key", isEqualTo: value as NSString),
|
||||
Where("key", isEqualTo: NSString(string: value))
|
||||
Where<NSManagedObject>("%K == %s", "key", value),
|
||||
Where<NSManagedObject>("%K == %s", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %s", "key", NSString(string: value)),
|
||||
Where<NSManagedObject>("%K == %@", "key", value),
|
||||
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K == %@", "key", NSString(string: value)),
|
||||
Where<NSManagedObject>("key", isEqualTo: value),
|
||||
Where<NSManagedObject>("key", isEqualTo: value as NSString),
|
||||
Where<NSManagedObject>("key", isEqualTo: NSString(string: value))
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let value = NSString(string: "value")
|
||||
XCTAssertAllEqual(
|
||||
Where("%K == %s", "key", value),
|
||||
Where("%K == %s", "key", value as String),
|
||||
Where("%K == %s", "key", value as String as AnyObject),
|
||||
Where("%K == %@", "key", value),
|
||||
Where("%K == %@", "key", value as String),
|
||||
Where("%K == %@", "key", value as String as AnyObject),
|
||||
Where("key", isEqualTo: value),
|
||||
Where("key", isEqualTo: value as String),
|
||||
Where("key", isEqualTo: value as String as NSString)
|
||||
Where<NSManagedObject>("%K == %s", "key", value),
|
||||
Where<NSManagedObject>("%K == %s", "key", value as String),
|
||||
Where<NSManagedObject>("%K == %s", "key", value as String as AnyObject),
|
||||
Where<NSManagedObject>("%K == %@", "key", value),
|
||||
Where<NSManagedObject>("%K == %@", "key", value as String),
|
||||
Where<NSManagedObject>("%K == %@", "key", value as String as AnyObject),
|
||||
Where<NSManagedObject>("key", isEqualTo: value),
|
||||
Where<NSManagedObject>("key", isEqualTo: value as String),
|
||||
Where<NSManagedObject>("key", isEqualTo: value as String as NSString)
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let value: [Int] = [100, 200]
|
||||
XCTAssertAllEqual(
|
||||
Where("%K IN %@", "key", value),
|
||||
Where("%K IN %@", "key", value as AnyObject),
|
||||
Where("%K IN %@", "key", value as [AnyObject]),
|
||||
Where("%K IN %@", "key", value as NSArray),
|
||||
Where("%K IN %@", "key", NSArray(array: value)),
|
||||
Where("%K IN %@", "key", value as AnyObject as! NSArray),
|
||||
Where("key", isMemberOf: value)
|
||||
Where<NSManagedObject>("%K IN %@", "key", value),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
|
||||
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
|
||||
Where<NSManagedObject>("key", isMemberOf: value)
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let value: [Int64] = [Int64.min, 100, Int64.max]
|
||||
XCTAssertAllEqual(
|
||||
Where("%K IN %@", "key", value),
|
||||
Where("%K IN %@", "key", value as AnyObject),
|
||||
Where("%K IN %@", "key", value as [AnyObject]),
|
||||
Where("%K IN %@", "key", value as NSArray),
|
||||
Where("%K IN %@", "key", NSArray(array: value)),
|
||||
Where("%K IN %@", "key", value as AnyObject as! NSArray),
|
||||
Where("key", isMemberOf: value)
|
||||
Where<NSManagedObject>("%K IN %@", "key", value),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
|
||||
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
|
||||
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
|
||||
Where<NSManagedObject>("key", isMemberOf: value)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -226,9 +501,9 @@ final class WhereTests: XCTestCase {
|
||||
@objc
|
||||
dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() {
|
||||
|
||||
let whereClause1 = Where("key1", isEqualTo: "value1")
|
||||
let whereClause2 = Where("key2", isEqualTo: "value2")
|
||||
let whereClause3 = Where("key3", isEqualTo: "value3")
|
||||
let whereClause1 = Where<NSManagedObject>("key1", isEqualTo: "value1")
|
||||
let whereClause2 = Where<NSManagedObject>("key2", isEqualTo: "value2")
|
||||
let whereClause3 = Where<NSManagedObject>("key3", isEqualTo: "value3")
|
||||
|
||||
do {
|
||||
|
||||
@@ -256,6 +531,21 @@ final class WhereTests: XCTestCase {
|
||||
XCTAssertEqual(andWhere.predicate, andPredicate)
|
||||
XCTAssertEqual(andWhere, whereClause1 && whereClause2 && whereClause3)
|
||||
}
|
||||
do {
|
||||
|
||||
let andWhere = whereClause1 && whereClause2 && whereClause3
|
||||
let noneWhere: Where<NSManagedObject>? = nil
|
||||
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
|
||||
|
||||
|
||||
let finalNoneWhere = andWhere &&? noneWhere
|
||||
let finalSomeWhere = andWhere &&? someWhere
|
||||
let unwrappedFinalSomeWhere = andWhere && someWhere!
|
||||
|
||||
|
||||
XCTAssertEqual(andWhere.predicate, finalNoneWhere.predicate)
|
||||
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
||||
}
|
||||
do {
|
||||
|
||||
let orWhere = whereClause1 || whereClause2 || whereClause3
|
||||
@@ -272,13 +562,28 @@ final class WhereTests: XCTestCase {
|
||||
XCTAssertEqual(orWhere.predicate, orPredicate)
|
||||
XCTAssertEqual(orWhere, whereClause1 || whereClause2 || whereClause3)
|
||||
}
|
||||
do {
|
||||
|
||||
let orWhere = whereClause1 || whereClause2 || whereClause3
|
||||
let noneWhere: Where<NSManagedObject>? = nil
|
||||
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
|
||||
|
||||
|
||||
let finalNoneWhere = orWhere &&? noneWhere
|
||||
let finalSomeWhere = orWhere &&? someWhere
|
||||
let unwrappedFinalSomeWhere = orWhere && someWhere!
|
||||
|
||||
XCTAssertEqual(orWhere.predicate, finalNoneWhere.predicate)
|
||||
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
|
||||
|
||||
let whereClause = Where("key", isEqualTo: "value")
|
||||
let request = CoreStoreFetchRequest()
|
||||
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
|
||||
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
|
||||
whereClause.applyToFetchRequest(request)
|
||||
XCTAssertNotNil(request.predicate)
|
||||
XCTAssertEqual(request.predicate, whereClause.predicate)
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2014 John Rommel Estropia
|
||||
Copyright © 2018 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
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// swift-tools-version:4.2
|
||||
//
|
||||
// Package.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -25,21 +26,18 @@
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let targets: [Target]
|
||||
#if os(iOS)
|
||||
targets = [Target(name: "CoreStore iOS")]
|
||||
#elseif os(OSX)
|
||||
targets = [Target(name: "CoreStore OSX")]
|
||||
#elseif os(watchOS)
|
||||
targets = [Target(name: "CoreStore watchOS")]
|
||||
#elseif os(tvOS)
|
||||
targets = [Target(name: "CoreStore tvOS")]
|
||||
#else
|
||||
targets = []
|
||||
#endif
|
||||
|
||||
let package = Package(
|
||||
name: "CoreStore",
|
||||
targets: targets,
|
||||
exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"]
|
||||
products: [
|
||||
.library(name: "CoreStore", type: .static, targets: ["CoreStore"])
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(
|
||||
name: "CoreStore",
|
||||
dependencies: [],
|
||||
path: "Sources",
|
||||
exclude: ["CoreStoreBridge.h", "CoreStoreBridge.m"]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
79
Playground_iOS.playground/Contents.swift
Normal file
79
Playground_iOS.playground/Contents.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
import UIKit
|
||||
import CoreStore
|
||||
import PlaygroundSupport
|
||||
|
||||
PlaygroundPage.current.needsIndefiniteExecution = true
|
||||
|
||||
/// Model Declaration =====
|
||||
class Animal: CoreStoreObject {
|
||||
let species = Value.Required<String>("species", initial: "Swift")
|
||||
let master = Relationship.ToOne<Person>("master")
|
||||
let color = Transformable.Optional<UIColor>("color", initial: .orange)
|
||||
}
|
||||
|
||||
class Person: CoreStoreObject {
|
||||
let name = Value.Optional<String>("name")
|
||||
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
|
||||
}
|
||||
/// =======================
|
||||
|
||||
/// Stack setup ===========
|
||||
let dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "V1",
|
||||
entities: [
|
||||
Entity<Animal>("Animal"),
|
||||
Entity<Person>("Person")
|
||||
]
|
||||
)
|
||||
)
|
||||
dataStack.addStorage(
|
||||
SQLiteStore(fileName: "data.sqlite"),
|
||||
completion: { result in
|
||||
|
||||
switch result {
|
||||
|
||||
case .failure(let error):
|
||||
print(error)
|
||||
|
||||
case .success:
|
||||
/// Transactions ==========
|
||||
dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
let animal = transaction.create(Into<Animal>())
|
||||
animal.species .= "Sparrow"
|
||||
animal.color .= .yellow
|
||||
|
||||
let person = transaction.create(Into<Person>())
|
||||
person.name .= "John"
|
||||
person.pets.value.insert(animal)
|
||||
},
|
||||
completion: { result in
|
||||
|
||||
switch result {
|
||||
|
||||
case .failure(let error):
|
||||
print(error)
|
||||
|
||||
case .success:
|
||||
/// Accessing Objects =====
|
||||
let bird = try! dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
|
||||
print(bird.species.value)
|
||||
print(bird.color.value as Any)
|
||||
print(bird)
|
||||
|
||||
let owner = bird.master.value!
|
||||
print(owner.name.value as Any)
|
||||
print(owner.pets.count)
|
||||
print(owner)
|
||||
/// =======================
|
||||
}
|
||||
}
|
||||
)
|
||||
/// =======================
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
4
Playground_iOS.playground/contents.xcplayground
Normal file
4
Playground_iOS.playground/contents.xcplayground
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='ios' executeOnSourceChanges='false'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
4
Playground_iOS.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
4
Playground_iOS.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
</Workspace>
|
||||
77
Playground_macOS.playground/Contents.swift
Normal file
77
Playground_macOS.playground/Contents.swift
Normal file
@@ -0,0 +1,77 @@
|
||||
import AppKit
|
||||
import CoreStore
|
||||
import PlaygroundSupport
|
||||
|
||||
PlaygroundPage.current.needsIndefiniteExecution = true
|
||||
|
||||
/// Model Declaration =====
|
||||
class Animal: CoreStoreObject {
|
||||
let species = Value.Required<String>("species", initial: "Swift")
|
||||
let master = Relationship.ToOne<Person>("master")
|
||||
let color = Transformable.Optional<NSColor>("color", initial: .orange)
|
||||
}
|
||||
|
||||
class Person: CoreStoreObject {
|
||||
let name = Value.Optional<String>("name")
|
||||
let pets = Relationship.ToManyUnordered<Animal>("pets", inverse: { $0.master })
|
||||
}
|
||||
/// =======================
|
||||
|
||||
/// Stack setup ===========
|
||||
let dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "V1",
|
||||
entities: [
|
||||
Entity<Animal>("Animal"),
|
||||
Entity<Person>("Person")
|
||||
]
|
||||
)
|
||||
)
|
||||
dataStack.addStorage(
|
||||
SQLiteStore(fileName: "data.sqlite"),
|
||||
completion: { result in
|
||||
|
||||
switch result {
|
||||
|
||||
case .failure(let error):
|
||||
print(error)
|
||||
|
||||
case .success:
|
||||
/// Transactions ==========
|
||||
dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
let animal = transaction.create(Into<Animal>())
|
||||
animal.species .= "Sparrow"
|
||||
animal.color .= .yellow
|
||||
|
||||
let person = transaction.create(Into<Person>())
|
||||
person.name .= "John"
|
||||
person.pets.value.insert(animal)
|
||||
},
|
||||
completion: { result in
|
||||
|
||||
switch result {
|
||||
|
||||
case .failure(let error):
|
||||
print(error)
|
||||
|
||||
case .success:
|
||||
/// Accessing Objects =====
|
||||
let bird = try! dataStack.fetchOne(From<Animal>().where(\.species == "Sparrow"))!
|
||||
print(bird.species.value)
|
||||
print(bird.color.value as Any)
|
||||
print(bird)
|
||||
|
||||
let owner = bird.master.value!
|
||||
print(owner.name.value as Any)
|
||||
print(owner.pets.count)
|
||||
print(owner)
|
||||
/// =======================
|
||||
}
|
||||
}
|
||||
)
|
||||
/// =======================
|
||||
}
|
||||
}
|
||||
)
|
||||
4
Playground_macOS.playground/contents.xcplayground
Normal file
4
Playground_macOS.playground/contents.xcplayground
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
7
Playground_macOS.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
Playground_macOS.playground/playground.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
452
README.md
452
README.md
@@ -6,48 +6,48 @@ Unleashing the real power of Core Data with the elegance and safety of Swift
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://travis-ci.org/JohnEstropia/CoreStore"><img alt="Build Status" src="https://img.shields.io/travis/JohnEstropia/CoreStore/master.svg?style=flat" /></a>
|
||||
<a href="https://github.com/JohnEstropia/CoreStore/commits"><img alt="Last Commit" src="https://img.shields.io/github/last-commit/johnestropia/corestore.svg?style=flat" /></a>
|
||||
<a href="http://cocoadocs.org/docsets/CoreStore"><img alt="Platform" src="https://img.shields.io/cocoapods/p/CoreStore.svg?style=flat" /></a>
|
||||
<a href="https://raw.githubusercontent.com/JohnEstropia/CoreStore/master/LICENSE"><img alt="License" src="https://img.shields.io/cocoapods/l/CoreStore.svg?style=flat" /></a>
|
||||
<br /><br />Dependency managers<br />
|
||||
<a href="https://cocoapods.org/pods/CoreStore"><img alt="Cocoapods compatible" src="https://img.shields.io/cocoapods/v/CoreStore.svg?style=flat&label=Cocoapods" /></a>
|
||||
<a href="https://github.com/Carthage/Carthage"><img alt="Carthage compatible" src="https://img.shields.io/badge/Carthage-compatible-16a085.svg?style=flat" /></a>
|
||||
<a href="https://swiftpkgs.ng.bluemix.net/package/JohnEstropia/CoreStore"><img alt="Swift Package Manager compatible" src="https://img.shields.io/badge/Swift_Package_Manager-compatible-orange.svg?style=flat" /></a>
|
||||
<a href="https://swift.org/source-compatibility/#current-list-of-projects"><img alt="Swift Package Manager compatible" src="https://img.shields.io/badge/Swift_Package_Manager-compatible-orange.svg?style=flat" /></a>
|
||||
<br /><br />Contact<br />
|
||||
<a href="http://swift-corestore-slack.herokuapp.com/"><img alt="Join us on Slack!" src="http://swift-corestore-slack.herokuapp.com/badge.svg" /></a>
|
||||
<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 3.1:** iOS 8+ / macOS 10.10+ / watchOS 2.0+ / tvOS 9.0+
|
||||
* Beta support: [Swift 3.2](https://github.com/JohnEstropia/CoreStore/tree/prototype/Swift_3_2), [Swift 4.0](https://github.com/JohnEstropia/CoreStore/tree/prototype/Swift_4_0)
|
||||
* **Swift 5.0:** iOS 10+ / macOS 10.12+ / watchOS 3.0+ / tvOS 10.0+
|
||||
* Previously supported Swift versions: [Swift 3.2](https://github.com/JohnEstropia/CoreStore/tree/4.2.3), [Swift 4.2](https://github.com/JohnEstropia/CoreStore/tree/6.2.1)
|
||||
|
||||
Upgrading from CoreStore 3.x to 4.x? Check out the [new features](#features) and make sure to read the [Migration guide](#upgrading-from-3xx-to-4xx).
|
||||
Upgrading from CoreStore 5.x (min iOS 9) to 6.x (min iOS 10)? Check out the [new features](#features) and make sure to read the [Change logs](https://github.com/JohnEstropia/CoreStore/releases).
|
||||
|
||||
CoreStore is now part of the [Swift Source Compatibility projects](https://swift.org/source-compatibility/#current-list-of-projects).
|
||||
|
||||
|
||||
## Why use CoreStore?
|
||||
CoreStore is the answer to the [challenges](http://inessential.com/2010/02/26/on_switching_away_from_core_data) [of](http://bsktapp.com/blog/why-is-realm-great-and-why-are-we-not-using-it/) [using](https://www.quora.com/Why-would-you-use-Realm-over-Core-Data) [Core](http://sebastiandobrincu.com/blog/5-reasons-why-you-should-choose-realm-over-coredata) [Data](https://medium.com/the-way-north/ditching-core-data-865c1bb5564c#.a5h8ou6ri).
|
||||
|
||||
CoreStore was (and is) heavily shaped by real-world needs of developing data-dependent apps. It enforces safe and convenient Core Data usage while letting you take advantage of the industry's encouraged best practices.
|
||||
|
||||
### Features
|
||||
|
||||
- **Tight design around Swift’s code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features.
|
||||
- **Safer concurrency architecture.** CoreStore makes it hard to fall into common concurrency mistakes. The main `NSManagedObjectContext` is strictly read-only, while all updates are done through serial *transactions*. *(See [Saving and processing transactions](#saving-and-processing-transactions))*
|
||||
- **Clean fetching and querying API.** Fetching objects is easy, but querying for raw aggregates (`min`, `max`, etc.) and raw property values is now just as convenient. *(See [Fetching and querying](#fetching-and-querying))*
|
||||
- **Type-safe, easy to configure observers.** You don't have to deal with the burden of setting up `NSFetchedResultsController`s and KVO. As an added bonus, `ListMonitor`s and `ObjectMonitor`s can have multiple observers. This means you can have multiple view controllers efficiently share a single resource! *(See [Observing changes and notifications](#observing-changes-and-notifications))*
|
||||
- **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))*
|
||||
- ⭐️ **New in 4.0: Say goodbye to *.xcdatamodeld* files!** The new `CoreStoreObject` is *the* replacement to `NSManagedObject`. `CoreStoreObject` subclasses can declare type-safe properties all in Swift code, no need to maintain separate resource files for the models. As bonus, these special properties support custom types, and can be used to create type-safe keypaths and queries. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects))*
|
||||
- **Progressive migrations.** No need to think how to migrate from all previous model versions to your latest model. Just tell the `DataStack` the sequence of version strings (`MigrationChain`s) and CoreStore will automatically use progressive migrations when needed. *(See [Migrations](#migrations))*
|
||||
- ⭐️ **New in 4.0: Easier custom migrations.** Say goodbye to *.xcmappingmodel* files; CoreStore can now infer entity mappings when possible, while still allowing an easy way to write custom mappings. *(See [Migrations](#migrations))*
|
||||
- **Plug-in your own logging framework.** Although a default logger is built-in, all logging, asserting, and error reporting can be funneled to `CoreStoreLogger` protocol implementations. *(See [Logging and error reporting](#logging-and-error-reporting))*
|
||||
- **Heavy support for multiple persistent stores per data stack.** CoreStore lets you manage separate stores in a single `DataStack`, just the way *.xcdatamodeld* configurations are designed to. CoreStore will also manage one stack by default, but you can create and manage as many as you need. *(See [Setting up](#setting-up))*
|
||||
- **Free to name entities and their class names independently.** CoreStore gets around a restriction with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you can assign different names for the entities and their class names.
|
||||
- **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.
|
||||
- **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))*
|
||||
- **More extensive Unit Tests.** Extending CoreStore is safe without having to worry about breaking old behavior.
|
||||
- **💎Tight design around Swift’s code elegance and type safety.** CoreStore fully utilizes Swift's community-driven language features.
|
||||
- **🚦Safer concurrency architecture.** CoreStore makes it hard to fall into common concurrency mistakes. The main `NSManagedObjectContext` is strictly read-only, while all updates are done through serial *transactions*. *(See [Saving and processing transactions](#saving-and-processing-transactions))*
|
||||
- **🔍Clean fetching and querying API.** Fetching objects is easy, but querying for raw aggregates (`min`, `max`, etc.) and raw property values is now just as convenient. *(See [Fetching and querying](#fetching-and-querying))*
|
||||
- **🔭Type-safe, easy to configure observers.** You don't have to deal with the burden of setting up `NSFetchedResultsController`s and KVO. As an added bonus, `ListMonitor`s and `ObjectMonitor`s can have multiple observers. This means you can have multiple view controllers efficiently share a single resource! *(See [Observing changes and notifications](#observing-changes-and-notifications))*
|
||||
- **📥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))*
|
||||
- **🗑Say goodbye to *.xcdatamodeld* files!** The new `CoreStoreObject` is *the* replacement to `NSManagedObject`. `CoreStoreObject` subclasses can declare type-safe properties all in Swift code, no need to maintain separate resource files for the models. As bonus, these special properties support custom types, and can be used to create type-safe keypaths and queries. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects))*
|
||||
- **🔗Progressive migrations.** No need to think how to migrate from all previous model versions to your latest model. Just tell the `DataStack` the sequence of version strings (`MigrationChain`s) and CoreStore will automatically use progressive migrations when needed. *(See [Migrations](#migrations))*
|
||||
- **Easier custom migrations.** Say goodbye to *.xcmappingmodel* files; CoreStore can now infer entity mappings when possible, while still allowing an easy way to write custom mappings. *(See [Migrations](#migrations))*
|
||||
- **📝Plug-in your own logging framework.** Although a default logger is built-in, all logging, asserting, and error reporting can be funneled to `CoreStoreLogger` protocol implementations. *(See [Logging and error reporting](#logging-and-error-reporting))*
|
||||
- **⛓Heavy support for multiple persistent stores per data stack.** CoreStore lets you manage separate stores in a single `DataStack`, just the way *.xcdatamodeld* configurations are designed to. CoreStore will also manage one stack by default, but you can create and manage as many as you need. *(See [Setting up](#setting-up))*
|
||||
- **🎯Free to name entities and their class names independently.** CoreStore gets around a restriction with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you can assign different names for the entities and their class names.
|
||||
- **📙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.
|
||||
- **ℹ️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))*
|
||||
- **🛡More extensive Unit Tests.** Extending CoreStore is safe without having to worry about breaking old behavior.
|
||||
|
||||
*Have ideas that may benefit other Core Data users? [Feature Request](https://github.com/JohnEstropia/CoreStore/issues)s are welcome!*
|
||||
|
||||
@@ -59,13 +59,12 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
|
||||
- [Setting up](#setting-up)
|
||||
- [In-memory store](#in-memory-store)
|
||||
- [Local store](#local-store)
|
||||
- [iCloud store](#icloud-store)
|
||||
- [Migrations](#migrations)
|
||||
- [Declaring model versions](#declaring-model-versions)
|
||||
- [Starting migrations](#starting-migrations)
|
||||
- [Progressive migrations](#progressive-migrations)
|
||||
- [Forecasting migrations](#forecasting-migrations)
|
||||
- [Custom migratoins](#custom-migrations)
|
||||
- [Custom migrations](#custom-migrations)
|
||||
- [Saving and processing transactions](#saving-and-processing-transactions)
|
||||
- [Transaction types](#transaction-types)
|
||||
- [Asynchronous transactions](#asynchronous-transactions)
|
||||
@@ -86,7 +85,8 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
|
||||
- [`Select<T>` clause](#selectt-clause)
|
||||
- [`GroupBy` clause](#groupby-clause)
|
||||
- [Logging and error reporting](#logging-and-error-reporting)
|
||||
- [Observing changes and notifications](#observing-changes-and-notifications) (unavailable on macOS)
|
||||
- [Observing changes and notifications](#observing-changes-and-notifications)
|
||||
- [Observe a single property](#observe-a-single-property)
|
||||
- [Observe a single object](#observe-a-single-object)
|
||||
- [Observe a list of objects](#observe-a-list-of-objects)
|
||||
- [Objective-C support](#objective-c-support)
|
||||
@@ -95,8 +95,6 @@ CoreStore was (and is) heavily shaped by real-world needs of developing data-dep
|
||||
- [Roadmap](#roadmap)
|
||||
- [Installation](#installation)
|
||||
- [Changesets](#changesets)
|
||||
- [Upgrading from 3.x.x to 4.x.x](#upgrading-from-3xx-to-4xx)
|
||||
- [Other Releases](#other-releases)
|
||||
- [Contact](#contact)
|
||||
- [Who uses CoreStore?](#who-uses-corestore)
|
||||
- [License](#license)
|
||||
@@ -142,26 +140,24 @@ CoreStore.perform(
|
||||
|
||||
Fetching objects (simple):
|
||||
```swift
|
||||
let people = CoreStore.fetchAll(From<MyPersonEntity>())
|
||||
let people = try CoreStore.fetchAll(From<MyPersonEntity>())
|
||||
```
|
||||
|
||||
Fetching objects (complex):
|
||||
```swift
|
||||
let people = CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where("age > 30"),
|
||||
OrderBy(.ascending("name"), .descending("age")),
|
||||
Tweak { (fetchRequest) -> Void in
|
||||
fetchRequest.includesPendingChanges = false
|
||||
}
|
||||
let people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30),
|
||||
.orderBy(.ascending(\.name), .descending(.\age)),
|
||||
.tweak({ $0.includesPendingChanges = false })
|
||||
)
|
||||
```
|
||||
|
||||
Querying values:
|
||||
```swift
|
||||
let maxAge = CoreStore.queryValue(
|
||||
From<MyPersonEntity>(),
|
||||
Select<Int>(.maximum("age"))
|
||||
let maxAge = try CoreStore.queryValue(
|
||||
From<MyPersonEntity>()
|
||||
.select(Int.self, .maximum(\.age))
|
||||
)
|
||||
```
|
||||
|
||||
@@ -220,9 +216,9 @@ let migrationProgress = dataStack.addStorage(
|
||||
completion: { (result) -> Void in
|
||||
switch result {
|
||||
case .success(let storage):
|
||||
print("Successfully added sqlite store: \(storage)"
|
||||
print("Successfully added sqlite store: \(storage)")
|
||||
case .failure(let error):
|
||||
print("Failed adding sqlite store with error: \(error)"
|
||||
print("Failed adding sqlite store with error: \(error)")
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -230,8 +226,8 @@ let migrationProgress = dataStack.addStorage(
|
||||
CoreStore.defaultStack = dataStack // pass the dataStack to CoreStore for easier access later on
|
||||
```
|
||||
|
||||
(If you have never heard of "Configurations", you'll find them in your *.xcdatamodeld* file)
|
||||
<img src="https://cloud.githubusercontent.com/assets/3029684/8333192/e52cfaac-1acc-11e5-9902-08724f9f1324.png" alt="xcode configurations screenshot" height=212 />
|
||||
> 💡If you have never heard of "Configurations", you'll find them in your *.xcdatamodeld* file
|
||||
> <img src="https://cloud.githubusercontent.com/assets/3029684/8333192/e52cfaac-1acc-11e5-9902-08724f9f1324.png" alt="xcode configurations screenshot" height=212 />
|
||||
|
||||
In our sample code above, note that you don't need to do the `CoreStore.defaultStack = dataStack` line. You can just as well hold a reference to the `DataStack` like below and call all its instance methods directly:
|
||||
```swift
|
||||
@@ -264,12 +260,14 @@ class MyViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
func methodToBeCalledLaterOn() {
|
||||
let objects = CoreStore.fetchAll(From(MyEntity))
|
||||
let objects = CoreStore.fetchAll(From<MyEntity>())
|
||||
print(objects)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 💡By default, CoreStore will initialize `NSManagedObject`s from *.xcdatamodeld* files, but you can create models completely from source code using `CoreStoreObject`s and `CoreStoreSchema`. To use this feature, refer to [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects).
|
||||
|
||||
Notice that in our previous examples, `addStorageAndWait(_:)` and `addStorage(_:completion:)` both accept either `InMemoryStore`, `SQLiteStore`, or `ICloudStore`. These implement the `StorageInterface` protocol.
|
||||
|
||||
### In-memory store
|
||||
@@ -314,66 +312,6 @@ public protocol LocalStorage: StorageInterface {
|
||||
```
|
||||
If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`.
|
||||
|
||||
### iCloud Store
|
||||
> **Important:** The iCloud Store is currently in beta. Please use with caution. If you have any concerns please do send me a message on [Twitter](https://twitter.com/JohnEstropia) or on the [CoreStore Slack Team](http://swift-corestore-slack.herokuapp.com/)
|
||||
|
||||
As a counterpart to `LocalStorage`, the `CloudStorage` protocol abstracts stores managed in the cloud. CoreStore currently provides the concrete class `ICloudStore`. Unlike `InMemoryStore` and `SQLiteStore` though, the `ICloudStore`'s initializer may return `nil` if the iCloud container could not be located or if iCloud is not available on the device:
|
||||
```swift
|
||||
guard let storage = ICloudStore(
|
||||
ubiquitousContentName: "MyAppCloudData", // the name of the store in iCloud
|
||||
ubiquitousContentTransactionLogsSubdirectory: "logs/config1", // optional. Subdirectory path for the transaction logs
|
||||
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
|
||||
) else {
|
||||
// The iCloud container could not be located or if iCloud is not available on the device.
|
||||
// Handle appropriately
|
||||
return
|
||||
}
|
||||
CoreStore.addStorage(,
|
||||
storage,
|
||||
completion: { result in
|
||||
switch result {
|
||||
case .success(let storage): // ...
|
||||
case .failure(let error): // ...
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
If your app is using iCloud stores, you may want to be notified of particular iCloud events. The `ICloudStoreObserver` functions are all optional, so you may implement only the ones your app is interested in:
|
||||
```swift
|
||||
public protocol ICloudStoreObserver: class {
|
||||
func iCloudStoreWillFinishUbiquitousStoreInitialImport(storage storage: ICloudStore, dataStack: DataStack)
|
||||
func iCloudStoreDidFinishUbiquitousStoreInitialImport(storage storage: ICloudStore, dataStack: DataStack)
|
||||
func iCloudStoreWillAddAccount(storage storage: ICloudStore, dataStack: DataStack)
|
||||
func iCloudStoreDidAddAccount(storage storage: ICloudStore, dataStack: DataStack)
|
||||
func iCloudStoreWillRemoveAccount(storage storage: ICloudStore, dataStack: DataStack)
|
||||
func iCloudStoreDidRemoveAccount(storage storage: ICloudStore, dataStack: DataStack)
|
||||
func iCloudStoreWillRemoveContent(storage storage: ICloudStore, dataStack: DataStack)
|
||||
func iCloudStoreDidRemoveContent(storage storage: ICloudStore, dataStack: DataStack)
|
||||
}
|
||||
```
|
||||
To register your `ICloudStoreObserver`, call `addObserver(_:)` on the `ICloudStore` instance:
|
||||
|
||||
```swift
|
||||
guard let storage = ICloudStore(/* ... */) else {
|
||||
return
|
||||
}
|
||||
storage.addObserver(self) // assuming self implements ICloudStoreObserver
|
||||
CoreStore.addStorage(,
|
||||
storage,
|
||||
completion: { result in
|
||||
switch result {
|
||||
case .success(let storage): // ... You may also call storage.addObserver(_:) here
|
||||
case .failure(let error): // ...
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
The `ICloudStore` only keeps weak references of the registered observers. You may call `removeObserver(_:)` for precise deregistration, but `ICloudStore` automatically removes deallocated observers.
|
||||
|
||||
|
||||
## Migrations
|
||||
|
||||
@@ -554,14 +492,14 @@ This closure is executed on the main thread so UIKit and AppKit calls can be don
|
||||
|
||||
|
||||
### Progressive migrations
|
||||
By default, CoreStore uses Core Data's default automatic migration mechanism. In other words, CoreStore will try to migrate the existing persistent store to the *.xcdatamodeld* file's current model version. If no mapping model is found from the store's version to the data model's version, CoreStore gives up and reports an error.
|
||||
By default, CoreStore uses Core Data's default automatic migration mechanism. In other words, CoreStore will try to migrate the existing persistent store until it matches the `SchemaHistory`'s `currentModelVersion`. If no mapping model path is found from the store's version to the data model's version, CoreStore gives up and reports an error.
|
||||
|
||||
The `DataStack` lets you specify hints on how to break a migration into several sub-migrations using a `MigrationChain`. This is typically passed to the `DataStack` initializer and will be applied to all stores added to the `DataStack` with `addSQLiteStore(...)` and its variants:
|
||||
```swift
|
||||
let dataStack = DataStack(migrationChain:
|
||||
["MyAppModel", "MyAppModelV2", "MyAppModelV3", "MyAppModelV4"])
|
||||
```
|
||||
The most common usage is to pass in the *.xcdatamodeld* version names in increasing order as above.
|
||||
The most common usage is to pass in the model version (*.xcdatamodeld* version names for `NSManagedObject`s, or the `modelName` for `CoreStoreSchema`s) in increasing order as above.
|
||||
|
||||
For more complex, non-linear migration paths, you can also pass in a version tree that maps the key-values to the source-destination versions:
|
||||
```swift
|
||||
@@ -586,7 +524,7 @@ The `MigrationChain` is validated when passed to the `DataStack` and unless it i
|
||||
- a version appears twice as a key in a dictionary literal
|
||||
- a loop is found in any of the paths
|
||||
|
||||
One important thing to remember is that **if a `MigrationChain` is specified, the *.xcdatamodeld*'s "Current Version" will be bypassed** and the `MigrationChain`'s leafmost version will be the `DataStack`'s base model version.
|
||||
> ⚠️**Important: If a `MigrationChain` is specified, the *.xcdatamodeld*'s "Current Version" will be bypassed** and the `MigrationChain`'s leafmost version will be the `DataStack`'s base model version.
|
||||
|
||||
|
||||
### Forecasting migrations
|
||||
@@ -721,7 +659,7 @@ dataStack.perform(
|
||||
}
|
||||
)
|
||||
```
|
||||
Never use `try?` or `try!` on a `transaction.cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to save as normal. Using `try!` will crash the app as `transaction.cancel()` will *always* throw an error.
|
||||
> ⚠️**Important:** Never use `try?` or `try!` on a `transaction.cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to save as normal. Using `try!` will crash the app as `transaction.cancel()` will *always* throw an error.
|
||||
|
||||
The examples above use `perform(asynchronous:...)`, but there are actually 3 types of transactions at your disposal: *asynchronous*, *synchronous*, and *unsafe*.
|
||||
|
||||
@@ -758,6 +696,9 @@ CoreStore.perform(
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
> ⚠️Be careful when returning `NSManagedObject`s or `CoreStoreObject`s from the transaction closure. Those instances are for the transaction's use only. See [Passing objects safely](#passing-objects-safely).
|
||||
|
||||
Transactions created from `perform(asynchronous:...)` are instances of `AsynchronousDataTransaction`.
|
||||
|
||||
#### Synchronous transactions
|
||||
@@ -774,6 +715,21 @@ let hasChanges = CoreStore.perform(
|
||||
|
||||
Since `perform(synchronous:...)` technically blocks two queues (the caller's queue and the transaction's background queue), it is considered less safe as it's more prone to deadlock. Take special care that the closure does not block on any other external queues.
|
||||
|
||||
By default, `perform(synchronous:...)` will wait for observers such as `ListMonitor`s to be notified before the method returns. This may cause deadlocks, especially if you are calling this from the main thread. To reduce this risk, you may try to set the `waitForAllObservers:` parameter to `false`. Doing so tells the `SynchronousDataTransaction` to block only until it completes saving. It will not wait for other context's to receive those changes. This reduces deadlock risk but may have surprising side-effects:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
synchronous: { (transaction) in
|
||||
let person = transaction.create(Into<Person>())
|
||||
person.name = "John"
|
||||
},
|
||||
waitForAllObservers: false
|
||||
)
|
||||
let newPerson = CoreStore.fetchOne(From<Person>.where(\.name == "John"))
|
||||
// newPerson may be nil!
|
||||
// The DataStack may have not yet received the update notification.
|
||||
```
|
||||
Due to this complicated nature of synchronous transactions, if your app has very heavy transaction throughput it is highly recommended to use [asynchronous transactions](#asynchronous-transactions) instead.
|
||||
|
||||
#### Unsafe transactions
|
||||
are special in that they do not enclose updates within a closure:
|
||||
```swift
|
||||
@@ -806,17 +762,17 @@ 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
|
||||
- If the entity belongs to only one persistent store, a new object is inserted into that store and returned from `create(...)`
|
||||
- If the entity does not belong to any store, an assert will be triggered. **This is a programmer error and should never occur in production code.**
|
||||
- If the entity belongs to multiple stores, an assert will be triggered. **This is also a programmer error and should never occur in production code.** Normally, with Core Data you can insert an object in this state but saving the `NSManagedObjectContext` will always fail. CoreStore checks this for you at creation time when it makes sense (not during save).
|
||||
- If the entity does not belong to any store, an assertion failure will be raised. **This is a programmer error and should never occur in production code.**
|
||||
- If the entity belongs to multiple stores, an assertion failure will be raised. **This is also a programmer error and should never occur in production code.** Normally, with Core Data you can insert an object in this state but saving the `NSManagedObjectContext` will always fail. CoreStore checks this for you at creation time when it makes sense (not during save).
|
||||
|
||||
If the entity exists in multiple configurations, you need to provide the configuration name for the destination persistent store:
|
||||
|
||||
let person = transaction.create(Into<MyPersonEntity>("Config1"))
|
||||
|
||||
```swift
|
||||
let person = transaction.create(Into<MyPersonEntity>("Config1"))
|
||||
```
|
||||
or if the persistent store is the auto-generated "Default" configuration, specify `nil`:
|
||||
|
||||
let person = transaction.create(Into<MyPersonEntity>(nil))
|
||||
|
||||
```swift
|
||||
let person = transaction.create(Into<MyPersonEntity>(nil))
|
||||
```
|
||||
Note that if you do explicitly specify the configuration name, CoreStore will only try to insert the created object to that particular store and will fail if that store is not found; it will not fall back to any other configuration that the entity belongs to.
|
||||
|
||||
### Updating objects
|
||||
@@ -836,9 +792,9 @@ To update an existing object, fetch the object's instance from the transaction:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let person = transaction.fetchOne(
|
||||
From<MyPersonEntity>(),
|
||||
Where("name", isEqualTo: "Jane Smith")
|
||||
let person = try transaction.fetchOne(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.name == "Jane Smith")
|
||||
)
|
||||
person.age = person.age + 1
|
||||
},
|
||||
@@ -898,8 +854,8 @@ let jane: MyPersonEntity = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
transaction.delete(john, jane)
|
||||
// transaction.delete([john, jane]) is also allowed
|
||||
try transaction.delete(john, jane)
|
||||
// try transaction.delete([john, jane]) is also allowed
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
@@ -908,9 +864,9 @@ If you do not have references yet to the objects to be deleted, transactions hav
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
transaction.deleteAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where("age > 30")
|
||||
try transaction.deleteAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30)
|
||||
)
|
||||
},
|
||||
completion: { _ in }
|
||||
@@ -956,9 +912,9 @@ var peopleIDs: [NSManagedObjectID] = // ...
|
||||
|
||||
CoreStore.perform(
|
||||
asynchronous: { (transaction) -> Void in
|
||||
let jane = transaction.fetchOne(
|
||||
From<MyPersonEntity>(),
|
||||
Where("name", isEqualTo: "Jane Smith")
|
||||
let jane = try transaction.fetchOne(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.name == "Jane Smith")
|
||||
)
|
||||
jane.friends = NSSet(array: transaction.fetchExisting(peopleIDs)!)
|
||||
// ...
|
||||
@@ -1003,12 +959,12 @@ typealias ImportSource = [String: Any]
|
||||
```swift
|
||||
typealias ImportSource = NSData
|
||||
```
|
||||
You can even use external types from popular 3rd-party JSON libraries ([SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)'s `JSON` type is a personal favorite), or just simple tuples or primitives.
|
||||
You can even use external types from popular 3rd-party JSON libraries, or just simple tuples or primitives.
|
||||
|
||||
#### `ImportableObject`
|
||||
`ImportableObject` is a very simple protocol:
|
||||
```swift
|
||||
public protocol ImportableObject: class {
|
||||
public protocol ImportableObject: AnyObject {
|
||||
typealias ImportSource
|
||||
static func shouldInsert(from source: ImportSource, in transaction: BaseDataTransaction) -> Bool
|
||||
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
|
||||
@@ -1169,17 +1125,17 @@ 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 = try CoreStore.fetchAll(From<MyPersonEntity>())
|
||||
```
|
||||
`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
|
||||
let people = CoreStore.fetchAll(From<MyPersonEntity>("Config1")) // ignore objects in persistent stores other than the "Config1" configuration
|
||||
let people = try CoreStore.fetchAll(From<MyPersonEntity>("Config1")) // ignore objects in persistent stores other than the "Config1" configuration
|
||||
```
|
||||
or if the persistent store is the auto-generated "Default" configuration, specify `nil`:
|
||||
```swift
|
||||
let person = CoreStore.fetchAll(From<MyPersonEntity>(nil))
|
||||
let person = try CoreStore.fetchAll(From<MyPersonEntity>(nil))
|
||||
```
|
||||
Now we know how to use a `From` clause, let's move on to fetching and querying.
|
||||
|
||||
@@ -1199,13 +1155,13 @@ 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(
|
||||
var people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where("%K > %d", "age", 30) // string format initializer
|
||||
Where<MyPersonEntity>("%K > %d", "age", 30) // string format initializer
|
||||
)
|
||||
people = CoreStore.fetchAll(
|
||||
people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where(true) // boolean initializer
|
||||
Where<MyPersonEntity>(true) // boolean initializer
|
||||
)
|
||||
```
|
||||
If you do have an existing `NSPredicate` instance already, you can pass that to `Where` as well:
|
||||
@@ -1213,14 +1169,21 @@ If you do have an existing `NSPredicate` instance already, you can pass that to
|
||||
let predicate = NSPredicate(...)
|
||||
var people = CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where(predicate) // predicate initializer
|
||||
Where<MyPersonEntity>(predicate) // predicate initializer
|
||||
)
|
||||
```
|
||||
⭐️Starting CoreStore 5.0, `Where` clauses became more type-safe and are now generic types. To avoid verbose repetition of the generic object type, fetch methods now support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `Where` clause expression:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30) // Type-safe!
|
||||
)
|
||||
```
|
||||
`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>(),
|
||||
Where("age > %d", 30) && Where("gender == %@", "M")
|
||||
var people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30 && \.gender == "M")
|
||||
)
|
||||
```
|
||||
If you do not provide a `Where` clause, all objects that belong to the specified `From` will be returned.
|
||||
@@ -1229,20 +1192,27 @@ 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(
|
||||
var mostValuablePeople = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
OrderBy(.descending("rating"), .ascending("surname"))
|
||||
OrderBy<MyPersonEntity>(.descending("rating"), .ascending("surname"))
|
||||
)
|
||||
```
|
||||
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.ascending` or `.descending`.
|
||||
⭐️As with `Where` clauses, CoreStore 5.0 turned `OrderBy` clauses into generic types. To avoid verbose repetition of the generic object type, fetch methods now support **Fetch Chain builders**. We can also use Swift's Smart KeyPaths as the `OrderBy` clause expression:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.orderBy(.descending(\.rating), .ascending(\.surname)) // Type-safe!
|
||||
)
|
||||
```
|
||||
|
||||
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<MyPersonEntity>(.descending(\.rating))
|
||||
if sortFromYoungest {
|
||||
orderBy += OrderBy(.ascending("age"))
|
||||
orderBy += OrderBy(.ascending(\.age))
|
||||
}
|
||||
var mostValuablePeople = CoreStore.fetchAll(
|
||||
var mostValuablePeople = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
orderBy
|
||||
)
|
||||
@@ -1252,10 +1222,10 @@ 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(
|
||||
var people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
Where("age > %d", 30),
|
||||
OrderBy(.ascending("surname")),
|
||||
Where<MyPersonEntity>("age > %d", 30),
|
||||
OrderBy<MyPersonEntity>(.ascending("surname")),
|
||||
Tweak { (fetchRequest) -> Void in
|
||||
fetchRequest.includesPendingChanges = false
|
||||
fetchRequest.returnsObjectsAsFaults = false
|
||||
@@ -1263,6 +1233,19 @@ var people = CoreStore.fetchAll(
|
||||
}
|
||||
)
|
||||
```
|
||||
`Tweak` also supports **Fetch Chain builders**:
|
||||
```swift
|
||||
var people = try CoreStore.fetchAll(
|
||||
From<MyPersonEntity>(),
|
||||
.where(\.age > 30)
|
||||
.orderBy(.ascending(\.surname))
|
||||
.tweak {
|
||||
$0.includesPendingChanges = false
|
||||
$0.returnsObjectsAsFaults = false
|
||||
$0.includesSubentities = false
|
||||
}
|
||||
)
|
||||
```
|
||||
The clauses are evaluated the order they appear in the fetch/query, so you typically need to set `Tweak` as the last clause.
|
||||
`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.
|
||||
|
||||
@@ -1283,7 +1266,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(
|
||||
let johnsAge = try CoreStore.queryValue(
|
||||
From<MyPersonEntity>(),
|
||||
Select<Int>("age"),
|
||||
Where("name == %@", "John Smith")
|
||||
@@ -1293,11 +1276,19 @@ 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(
|
||||
let allAges = try CoreStore.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("age")
|
||||
)
|
||||
```
|
||||
⭐️Starting CoreStore 5.0, query methods now support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
|
||||
```swift
|
||||
let johnsAge = try CoreStore.queryValue(
|
||||
From<MyPersonEntity>()
|
||||
.select(\.age) // binds the result to Int
|
||||
.where(\.name == "John Smith")
|
||||
)
|
||||
```
|
||||
|
||||
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(...)`
|
||||
@@ -1307,7 +1298,7 @@ If you only need a value for a particular attribute, you can just specify the ke
|
||||
- `.sum(...)`
|
||||
|
||||
```swift
|
||||
let oldestAge = CoreStore.queryValue(
|
||||
let oldestAge = try CoreStore.queryValue(
|
||||
From<MyPersonEntity>(),
|
||||
Select<Int>(.maximum("age"))
|
||||
)
|
||||
@@ -1315,7 +1306,7 @@ let oldestAge = CoreStore.queryValue(
|
||||
|
||||
For `queryAttributes(...)` which returns an array of dictionaries, you can specify multiple attributes/aggregates to `Select`:
|
||||
```swift
|
||||
let personJSON = CoreStore.queryAttributes(
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("name", "age")
|
||||
)
|
||||
@@ -1335,7 +1326,7 @@ let personJSON = CoreStore.queryAttributes(
|
||||
```
|
||||
You can also include an aggregate as well:
|
||||
```swift
|
||||
let personJSON = CoreStore.queryAttributes(
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("name", .count("friends"))
|
||||
)
|
||||
@@ -1355,7 +1346,7 @@ 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(
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("name", .count("friends", as: "friendsCount"))
|
||||
)
|
||||
@@ -1378,12 +1369,20 @@ 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(
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
From<MyPersonEntity>(),
|
||||
Select("age", .count("age", as: "count")),
|
||||
GroupBy("age")
|
||||
)
|
||||
```
|
||||
⭐️Starting CoreStore 5.0, `GroupBy` clauses are now also generic types and now support **Query Chain builders**. We can also use Swift's Smart KeyPaths to use in the expressions:
|
||||
```swift
|
||||
let personJSON = try CoreStore.queryAttributes(
|
||||
From<MyPersonEntity>()
|
||||
.select(.attribute(\.age), .count(\.age, as: "count"))
|
||||
.groupBy(\.age)
|
||||
)
|
||||
```
|
||||
this returns dictionaries that shows the count for each `"age"`:
|
||||
```swift
|
||||
[
|
||||
@@ -1432,22 +1431,43 @@ A couple of examples, `ListMonitor`:
|
||||
|
||||
These are all implemented with `CustomDebugStringConvertible.debugDescription`, so they work with lldb's `po` command as well.
|
||||
|
||||
## Observing changes and notifications (unavailable on macOS)
|
||||
## Observing changes and notifications
|
||||
|
||||
CoreStore provides type-safe wrappers for observing managed objects:
|
||||
|
||||
- `ObjectMonitor`: use to monitor changes to a single `NSManagedObject` or `CoreStoreObject` instance (instead of Key-Value Observing)
|
||||
- `ListMonitor`: use to monitor changes to a list of `NSManagedObject` or `CoreStoreObject` instances (instead of `NSFetchedResultsController`)
|
||||
|
||||
### Observe a single property
|
||||
To get notifications for single property changes in an object, there are two methods depending on the object's base class.
|
||||
|
||||
- For `NSManagedObject` subclasses: Use the standard KVO method:
|
||||
```swift
|
||||
let observer = person.observe(\.age, options: [.new]) { (person, change)
|
||||
print("Happy \(change.newValue)th birthday!")
|
||||
}
|
||||
```
|
||||
|
||||
- For `CoreStoreObject` subclasses: Call the `observe(...)` method directly on the property. You'll notice that the API itself is a bit similar to the KVO method:
|
||||
```swift
|
||||
let observer = person.age.observe(options: [.new]) { (person, change)
|
||||
print("Happy \(change.newValue)th birthday!")
|
||||
}
|
||||
```
|
||||
|
||||
For both methods, you will need to keep a reference to the returned `observer` for the duration of the observation.
|
||||
|
||||
|
||||
### Observe a single object
|
||||
|
||||
To observe an object, implement the `ObjectObserver` protocol and specify the `EntityType`:
|
||||
To observe an object itself as a whole, implement the `ObjectObserver` protocol and specify the `EntityType`:
|
||||
```swift
|
||||
class MyViewController: UIViewController, ObjectObserver {
|
||||
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, willUpdateObject object: MyPersonEntity) {
|
||||
// ...
|
||||
}
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, didUpdateObject object: MyPersonEntity, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(monitor: ObjectMonitor<MyPersonEntity>, didUpdateObject object: MyPersonEntity, changedPersistentKeys: Set<KeyPathString>) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -1507,12 +1527,10 @@ 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>(),
|
||||
Where("age > 30"),
|
||||
OrderBy(.ascending("name")),
|
||||
Tweak { (fetchRequest) -> Void in
|
||||
fetchRequest.fetchBatchSize = 20
|
||||
}
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 30)
|
||||
.orderBy(.ascending(\.name))
|
||||
.tweak { $0.fetchBatchSize = 20 }
|
||||
)
|
||||
self.monitor.addObserver(self)
|
||||
```
|
||||
@@ -1528,13 +1546,11 @@ 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>(),
|
||||
SectionBy("age"),
|
||||
Where("gender", isEqualTo: "M"),
|
||||
OrderBy(.ascending("age"), .ascending("name")),
|
||||
Tweak { (fetchRequest) -> Void in
|
||||
fetchRequest.fetchBatchSize = 20
|
||||
}
|
||||
From<MyPersonEntity>()
|
||||
.sectionBy(\.age)
|
||||
.where(\.gender == "M")
|
||||
.orderBy(.ascending(\.age), .ascending(\.name))
|
||||
.tweak { $0.fetchBatchSize = 20 }
|
||||
)
|
||||
```
|
||||
A list controller created this way will group the objects by the attribute key indicated by the `SectionBy` clause. One more thing to remember is that the `OrderBy` clause should sort the list in such a way that the `SectionBy` attribute would be sorted together (a requirement shared by `NSFetchedResultsController`.)
|
||||
@@ -1542,11 +1558,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>(),
|
||||
SectionBy("age") { (sectionName) -> String? in
|
||||
"\(sectionName) years old"
|
||||
},
|
||||
OrderBy(.ascending("age"), .ascending("name"))
|
||||
From<MyPersonEntity>()
|
||||
.sectionBy(\.age) { (sectionName) -> String? in
|
||||
"\(sectionName) years old"
|
||||
}
|
||||
.orderBy(.ascending(\.age), .ascending(\.name))
|
||||
)
|
||||
```
|
||||
This is useful when implementing a `UITableViewDelegate`'s section header:
|
||||
@@ -1566,9 +1582,9 @@ let person2 = self.monitor[1, 2]
|
||||
```
|
||||
|
||||
## Objective-C support
|
||||
CoreStore 2.0 was a big move to address the large number of apps starting to convert from Objective-C to Swift. The basic problem is this: The cost of converting all code base to Swift is very big, so most apps are forced to do undergo a *transitional* ObjC-Swift hybrid phase. This used to mean that these apps could not use the Swifty-est libraries out there yet, or that they may have to write their own bridging methods just to make new code usable in their old Objective-C code.
|
||||
> ⚠️Objective-C support is planned to be deprecated in a future CoreStore version.
|
||||
|
||||
With 2.0, all CoreStore types are still written in pure Swift, but they now have Objective-C "bridging classes" that are visible to Objective-C code. To show a couple of usage examples:
|
||||
All CoreStore types are still written in pure Swift, but most core types have Objective-C "bridging classes" that are visible to Objective-C code. To show a couple of usage examples:
|
||||
|
||||
<table>
|
||||
<tr><th>Swift</th><th>Objective-C</th></tr>
|
||||
@@ -1598,14 +1614,13 @@ CoreStore.perform(
|
||||
<td><pre lang=objc>
|
||||
[CSCoreStore beginAsynchronous:^(CSAsynchronousDataTransaction *transaction) {
|
||||
// ...
|
||||
[transaction commitWithCompletion:^(CSSaveResult *result) {
|
||||
if (result.isSuccess) {
|
||||
NSLog(@"Done");
|
||||
}
|
||||
else if (result.isFailure) {
|
||||
NSLog(@"error: %@", result.error);
|
||||
}
|
||||
}];
|
||||
[transaction
|
||||
commitWithSuccess:^{
|
||||
NSLog(@"Done");
|
||||
}
|
||||
failure: ^(CSError *error) {
|
||||
NSLog(@"error: %@", result.error);
|
||||
}];
|
||||
}];
|
||||
</pre></td>
|
||||
</tr>
|
||||
@@ -1616,7 +1631,7 @@ All of these `CS`-prefixed bridging classes have very similar usage to the exist
|
||||
For example, you may have a new, modern Swift class that holds a `ListMonitor`:
|
||||
```swift
|
||||
class MyViewController: UIViewController {
|
||||
let monitor = CoreStore.monitorList(From(MyEntity), ...)
|
||||
let monitor = CoreStore.monitorList(From<MyEntity>(), ...)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -1630,7 +1645,7 @@ Now let's say you have a legacy Objective-C class that previously uses `NSFetche
|
||||
When you need to instantiate this class from Swift, you just call `bridgeToObjectiveC`:
|
||||
```swift
|
||||
class MyViewController: UIViewController {
|
||||
let monitor = CoreStore.monitorList(From(MyEntity), ...)
|
||||
let monitor = CoreStore.monitorList(From<MyEntity>(), ...)
|
||||
func showOldController() {
|
||||
let controller = MYOldViewController(monitor: self.monitor.bridgeToObjectiveC)
|
||||
self.presentViewController(controller, animated: true, completion: nil)
|
||||
@@ -1675,7 +1690,7 @@ To use these syntax sugars, include *CoreStoreBridge.h* in your Objective-C sour
|
||||
Starting CoreStore 4.0, we can now create persisted objects without depending on *.xcdatamodeld* Core Data files. The new `CoreStoreObject` subclass replaces `NSManagedObject`, and specially-typed properties declared on these classes will be synthesized as Core Data attributes.
|
||||
```swift
|
||||
class Animal: CoreStoreObject {
|
||||
let species = Value.Required<String>("species")
|
||||
let species = Value.Required<String>("species", initial: "")
|
||||
}
|
||||
|
||||
class Dog: Animal {
|
||||
@@ -1684,22 +1699,22 @@ class Dog: Animal {
|
||||
}
|
||||
|
||||
class Person: CoreStoreObject {
|
||||
let name = Value.Required<String>("name")
|
||||
let name = Value.Required<String>("name", initial: "")
|
||||
let pets = Relationship.ToManyUnordered<Dog>("pets", inverse: { $0.master })
|
||||
}
|
||||
```
|
||||
The property names to be saved to Core Data is specified as the `keyPath` argument. This lets us refactor our Swift code without affecting the underlying database. For example:
|
||||
```swift
|
||||
class Person: CoreStoreObject {
|
||||
private let _name = Value.Required<String>("name")
|
||||
// ...
|
||||
private let _name = Value.Required<String>("name", initial: "")
|
||||
// note property name is independent of the storage key name
|
||||
}
|
||||
```
|
||||
Here we added an underscore to the property name and made it `private`, but the underlying key-path `"name"` was unchanged so our model will not trigger a data migration.
|
||||
|
||||
> **Important:** As a rule, CoreStore can only process *stored properties*. Computed, `static`, `weak`, or `lazy` properties will not be added to the store. It is also strictly advised use `let` instead of `var` to declare these properties, as any changes to the schema after declaration is not allowed.
|
||||
> ⚠️**Important:** As a rule, CoreStore can only process *stored properties*. Computed, `static`, `weak`, or `lazy` properties will be ignored and will not be added to the store. It is also strictly advised use `let` instead of `var` to declare these properties, as any changes to the property value will break the schema.
|
||||
|
||||
Also note how `Relationship`s are linked statically with the `inverse:` argument. All relationships are required to have an "inverse" relationship. Unfortunately, due to Swift compiler limitation we can only declare the `inverse:` on one end of the relationship-pair.
|
||||
Also note how `Relationship`s are linked statically with the `inverse:` argument. **All relationships are required to have an "inverse" relationship**. Unfortunately, due to Swift compiler limitation we can only declare the `inverse:` on one end of the relationship-pair.
|
||||
|
||||
To tell the `DataStack` about these types, add all `CoreStoreObject`s' entities to a `CoreStoreSchema`:
|
||||
```swift
|
||||
@@ -1722,7 +1737,7 @@ These special properties' values can be accessed or mutated using `.value`:
|
||||
```swift
|
||||
CoreStore.perform(
|
||||
asynchronous: { (transaction) in
|
||||
let dog: Dog = CoreStore.fetchOne(From<Dog>())!
|
||||
let dog: Dog = transaction.fetchOne(From<Dog>())!
|
||||
// ...
|
||||
let nickname = dog.nickname.value // String?
|
||||
let species = dog.species.value // String
|
||||
@@ -1740,10 +1755,10 @@ let keyPath: String = Dog.keyPath { $0.nickname }
|
||||
```
|
||||
as well as `Where` and `OrderBy` clauses
|
||||
```swift
|
||||
let puppies = CoreStore.fetchAll(
|
||||
From<Dog>(),
|
||||
Dog.where { $0.age < 1 },
|
||||
Dog.ascending { $0.age }
|
||||
let puppies = try CoreStore.fetchAll(
|
||||
From<Dog>()
|
||||
.where(\.age < 1)
|
||||
.orderBy(.ascending(\.age))
|
||||
)
|
||||
```
|
||||
|
||||
@@ -1753,7 +1768,7 @@ All CoreStore APIs that are usable with `NSManagedObject`s are also available fo
|
||||
|
||||
While it is convenient to be able to declare entities only in code, it is worrying that we might accidentally change the `CoreStoreObject`'s properties and break our users' model version history. For this, the `CoreStoreSchema` allows us to "lock" our properties to a particular configuration. Any changes to that `VersionLock` will raise an assertion failure during the `CoreStoreSchema` initialization, so you can then look for the commit which changed the `VersionLock` hash.
|
||||
|
||||
To use `VersionLock`s, create the `CoreStoreSchema`, run the app, and look for this particular log message that is automatically printed to the console:
|
||||
To use `VersionLock`s, create the `CoreStoreSchema`, run the app, and look for a similar log message that is automatically printed to the console:
|
||||
|
||||
<img width="700" alt="VersionLock" src="https://cloud.githubusercontent.com/assets/3029684/26525632/757f1bd0-4398-11e7-9795-4132a2df0538.png" />
|
||||
|
||||
@@ -1785,8 +1800,9 @@ Once the version lock is set, any changes in the properties or to the model will
|
||||
|
||||
# Installation
|
||||
- Requires:
|
||||
- iOS 8 SDK and above
|
||||
- Swift 3.1 (Xcode 8.3.2+)
|
||||
- iOS 10 SDK and above
|
||||
- Swift 5.0 (Xcode 10+)
|
||||
- For previous Swift versions: [Swift 3.2](https://github.com/JohnEstropia/CoreStore/tree/4.2.3), [Swift 4.2](https://github.com/JohnEstropia/CoreStore/tree/6.2.1)
|
||||
- Dependencies:
|
||||
- *None*
|
||||
- Other notes:
|
||||
@@ -1795,7 +1811,7 @@ Once the version lock is set, any changes in the properties or to the model will
|
||||
### Install with CocoaPods
|
||||
In your `Podfile`, add
|
||||
```
|
||||
pod 'CoreStore', '~> 4.0'
|
||||
pod 'CoreStore', '~> 6.3'
|
||||
```
|
||||
and run
|
||||
```
|
||||
@@ -1806,7 +1822,7 @@ This installs CoreStore as a framework. Declare `import CoreStore` in your swift
|
||||
### Install with Carthage
|
||||
In your `Cartfile`, add
|
||||
```
|
||||
github "JohnEstropia/CoreStore" >= 4.0.0
|
||||
github "JohnEstropia/CoreStore" >= 6.3.0
|
||||
```
|
||||
and run
|
||||
```
|
||||
@@ -1814,48 +1830,32 @@ carthage update
|
||||
```
|
||||
This installs CoreStore as a framework. Declare `import CoreStore` in your swift file to use the library.
|
||||
|
||||
#### Install with Swift Package Manager:
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/JohnEstropia/CoreStore.git", from: "6.3.0"))
|
||||
]
|
||||
```
|
||||
Declare `import CoreStore` in your swift file to use the library.
|
||||
|
||||
### Install as Git Submodule
|
||||
```
|
||||
git submodule add https://github.com/JohnEstropia/CoreStore.git <destination directory>
|
||||
```
|
||||
Drag and drop **CoreStore.xcodeproj** to your project.
|
||||
|
||||
#### To install as a framework:
|
||||
Drag and drop **CoreStore.xcodeproj** to your project.
|
||||
|
||||
#### To include directly in your app module:
|
||||
Add all *.swift* files to your project.
|
||||
|
||||
|
||||
### Objective-C support
|
||||
|
||||
To use the Objective-C syntax sugars, import *CoreStoreBridge.h* in your *.m* source files.
|
||||
|
||||
# Changesets
|
||||
### Upgrading from 3.x.x to 4.x.x
|
||||
**Obsoleted**
|
||||
- `LegacySQLiteStore` is now finally obsoleted in favor of `SQLiteStore`. For sqlite files that were created previously with `LegacySQLiteStore`, make sure to use the `SQLiteStore.legacy(...)` factory method to create an `SQLiteStore` that can load the file from the legacy file path.
|
||||
- `SQLiteStore.init(...)`'s `mappingModelBundles` argument is now obsolete. The new initializer accepts a `migrationMappingProviders` optional argument where explicit mapping sources are declared. For reference on how to do this, read on [Custom migrations](#custom-migrations).
|
||||
|
||||
**Deprecated**
|
||||
- `DataStack.beginAsynchronous(...)`, `DataStack.beginSynchronous(...)`, `AsynchronousDataTransaction.commit(...)`, and `SynchronousDataTransaction.commit(...)` are now deprecated in favor of `DataStack.perform(asynchronous:...)` and `DataStack.perform(synchronous:...)` family of methods. These new `perform(...)` methods are auto-commit, meaning the transaction automatically calls `commit()` internally after the transction closure completes. To roll-back and cancel a transaction, call `try transaction.cancel()`. Read [Saving and processing transactions](#saving-and-processing-transactions) for more details.
|
||||
|
||||
**Other Changes**
|
||||
- `ListMonitor.refetch(...)` now works by recreating its internal `NSFetchedResultsController`. Previously `refetch(...)` would only apply new `FetchClause`s on top of previous fetches. Now all `FetchClauses` are required to be passed to `refetch(...)` each time it is called.
|
||||
- New important concepts on "Dynamic Models", "Schema", and "Schema Histories".
|
||||
- **Dynamic Models** (`DynamicObject` protocol): These are Core Data object types that any `NSManagedObject` or `CoreStoreObject`s conform to. *(See [Type-safe `CoreStoreObject`s](#type-safe-corestoreobjects))*
|
||||
- **Version Schema** (`DynamicSchema` protocol): These types contain info for a single model version, as well as entities that belong to it. Currently supports `XcodeDataModelSchema` (*.xcdatamodeld* file), `CoreStoreSchema`, or `UnsafeDataModelSchema`. *(See [Migrations](#migrations))*
|
||||
- **Schema History** (`SchemaHistory` class): This is now the preferred way to express all models to the `DataStack`. This class contains info to all the `DynamicSchema` across multiple model versions. *(See [Migrations](#migrations))*
|
||||
|
||||
### Other Releases
|
||||
|
||||
For the full Changelog, refer to the [Releases](https://github.com/JohnEstropia/CoreStore/releases) page.
|
||||
|
||||
|
||||
# Contact
|
||||
Questions? Suggestions?
|
||||
|
||||
Reach me on Twitter [@JohnEstropia](https://twitter.com/JohnEstropia)
|
||||
You can reach me on Twitter [@JohnEstropia](https://twitter.com/JohnEstropia)
|
||||
|
||||
or join our Slack team at [swift-corestore.slack.com](http://swift-corestore-slack.herokuapp.com/)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// AsynchronousDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2015 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -50,45 +50,11 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
// MARK: - Result
|
||||
|
||||
/**
|
||||
The `Result` contains the success or failure information for a completed transaction
|
||||
The `Result` contains the success or failure information for a completed transaction.
|
||||
`Result<T>.success` indicates that the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated `userInfo` is the value returned from the transaction closure.
|
||||
`Result<T>.failure` indicates that the transaction either failed or was cancelled. The associated object for this value is a `CoreStoreError` enum value.
|
||||
*/
|
||||
public enum Result<T> {
|
||||
|
||||
/**
|
||||
`Result<T>.success` indicates that the transaction succeeded, either because the save succeeded or because there were no changes to save. The associated `userInfo` is the value returned from the transaction closure.
|
||||
*/
|
||||
case success(userInfo: T)
|
||||
|
||||
/**
|
||||
`Result<T>.failure` indicates that the transaction either failed or was cancelled. The associated object for this value is a `CoreStoreError` enum value.
|
||||
*/
|
||||
case failure(error: CoreStoreError)
|
||||
|
||||
/**
|
||||
Returns `true` if the result indicates `.success`, `false` if the result is `.failure`.
|
||||
*/
|
||||
public var boolValue: Bool {
|
||||
|
||||
switch self {
|
||||
|
||||
case .success: return true
|
||||
case .failure: return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(userInfo: T) {
|
||||
|
||||
self = .success(userInfo: userInfo)
|
||||
}
|
||||
|
||||
internal init(error: CoreStoreError) {
|
||||
|
||||
self = .failure(error: error)
|
||||
}
|
||||
}
|
||||
public typealias Result<UserInfoType> = Swift.Result<UserInfoType, CoreStoreError>
|
||||
|
||||
// MARK: -
|
||||
|
||||
@@ -100,7 +66,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
|
||||
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
|
||||
*/
|
||||
public override func create<T: DynamicObject>(_ into: Into<T>) -> T {
|
||||
public override func create<D>(_ into: Into<D>) -> D {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
@@ -116,7 +82,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public override func edit<T: DynamicObject>(_ object: T?) -> T? {
|
||||
public override func edit<D: DynamicObject>(_ object: D?) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
@@ -133,7 +99,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
- parameter objectID: the `NSManagedObjectID` for the object to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public override func edit<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
|
||||
public override func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
@@ -148,7 +114,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
*/
|
||||
public override func delete<T: DynamicObject>(_ object: T?) {
|
||||
public override func delete<D: DynamicObject>(_ object: D?) {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
@@ -165,14 +131,14 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
- parameter object2: another `DynamicObject` to be deleted
|
||||
- parameter objects: other `DynamicObject`s to be deleted
|
||||
*/
|
||||
public override func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) {
|
||||
public override func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to delete an entities from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
super.delete(([object1, object2] + objects).flatMap { $0 })
|
||||
super.delete(([object1, object2] + objects).compactMap { $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,72 +169,13 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
self.isCommitted = true
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
|
||||
self.context.saveAsynchronouslyWithCompletion { (hasChanges, error) -> Void in
|
||||
|
||||
completion(result.0, result.1)
|
||||
self.result = result
|
||||
completion(hasChanges, error)
|
||||
self.result = (hasChanges, error)
|
||||
group.leave()
|
||||
}
|
||||
group.wait()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated, message: "Use the new auto-commiting methods `DataStack.perform(asynchronous:completion:)` or `DataStack.perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
|
||||
public func commit(_ completion: @escaping (_ result: SaveResult) -> Void = { _ in }) {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to commit a \(cs_typeName(self)) more than once."
|
||||
)
|
||||
self.autoCommit { (result) in
|
||||
|
||||
switch result {
|
||||
|
||||
case (let hasChanges, nil): completion(SaveResult(hasChanges: hasChanges))
|
||||
case (_, let error?): completion(SaveResult(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ")
|
||||
@discardableResult
|
||||
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
"Attempted to begin a child transaction from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to begin a child transaction from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
let childTransaction = SynchronousDataTransaction(
|
||||
mainContext: self.context,
|
||||
queue: self.childTransactionQueue
|
||||
)
|
||||
childTransaction.transactionQueue.cs_sync {
|
||||
|
||||
closure(childTransaction)
|
||||
|
||||
if !childTransaction.isCommitted && childTransaction.hasChanges {
|
||||
|
||||
CoreStore.log(
|
||||
.warning,
|
||||
message: "The closure for the \(cs_typeName(childTransaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||
)
|
||||
}
|
||||
}
|
||||
switch childTransaction.result {
|
||||
|
||||
case nil: return nil
|
||||
case (let hasChanges, nil)?: return SaveResult(hasChanges: hasChanges)
|
||||
case (_, let error?)?: return SaveResult(error)
|
||||
}
|
||||
self.context.reset()
|
||||
}
|
||||
}
|
||||
|
||||
47
Sources/AttributeProtocol.swift
Normal file
47
Sources/AttributeProtocol.swift
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// AttributeProtocol.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2018 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: - AttributeProtocol
|
||||
|
||||
internal protocol AttributeProtocol: AnyObject {
|
||||
|
||||
static var attributeType: NSAttributeType { get }
|
||||
|
||||
var keyPath: KeyPathString { get }
|
||||
var isOptional: Bool { get }
|
||||
var isTransient: Bool { get }
|
||||
var allowsExternalBinaryDataStorage: Bool { get }
|
||||
var versionHashModifier: () -> String? { get }
|
||||
var renamingIdentifier: () -> String? { get }
|
||||
var defaultValue: () -> Any? { get }
|
||||
var affectedByKeyPaths: () -> Set<String> { get }
|
||||
var rawObject: CoreStoreManagedObject? { get set }
|
||||
var getter: CoreStoreManagedObject.CustomGetter? { get }
|
||||
var setter: CoreStoreManagedObject.CustomSetter? { get }
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// BaseDataTransaction+Importing.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2015 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -29,7 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - BaseDataTransaction
|
||||
|
||||
public extension BaseDataTransaction {
|
||||
extension BaseDataTransaction {
|
||||
|
||||
/**
|
||||
Creates an `ImportableObject` by importing from the specified import source.
|
||||
@@ -39,9 +39,9 @@ public extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
- returns: the created `ImportableObject` instance, or `nil` if the import was ignored
|
||||
*/
|
||||
public func importObject<T: DynamicObject & ImportableObject>(
|
||||
_ into: Into<T>,
|
||||
source: T.ImportSource) throws -> T? {
|
||||
public func importObject<D: ImportableObject>(
|
||||
_ into: Into<D>,
|
||||
source: D.ImportSource) throws -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -69,9 +69,9 @@ public extension BaseDataTransaction {
|
||||
- parameter source: the object to import values from
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
*/
|
||||
public func importObject<T: DynamicObject & ImportableObject>(
|
||||
_ object: T,
|
||||
source: T.ImportSource) throws {
|
||||
public func importObject<D: ImportableObject>(
|
||||
_ object: D,
|
||||
source: D.ImportSource) throws {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -80,7 +80,7 @@ public extension BaseDataTransaction {
|
||||
|
||||
try autoreleasepool {
|
||||
|
||||
let entityType = type(of: object)
|
||||
let entityType = cs_dynamicType(of: object)
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
|
||||
return
|
||||
@@ -97,9 +97,9 @@ public extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
- returns: the array of created `ImportableObject` instances
|
||||
*/
|
||||
public func importObjects<T: DynamicObject & ImportableObject, S: Sequence>(
|
||||
_ into: Into<T>,
|
||||
sourceArray: S) throws -> [T] where S.Iterator.Element == T.ImportSource {
|
||||
public func importObjects<D: ImportableObject, S: Sequence>(
|
||||
_ into: Into<D>,
|
||||
sourceArray: S) throws -> [D] where S.Iterator.Element == D.ImportSource {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -108,7 +108,7 @@ public extension BaseDataTransaction {
|
||||
|
||||
return try autoreleasepool {
|
||||
|
||||
return try sourceArray.flatMap { (source) -> T? in
|
||||
return try sourceArray.compactMap { (source) -> D? in
|
||||
|
||||
let entityType = into.entityClass
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
@@ -133,9 +133,9 @@ public extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
|
||||
- returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored
|
||||
*/
|
||||
public func importUniqueObject<T: DynamicObject & ImportableUniqueObject>(
|
||||
_ into: Into<T>,
|
||||
source: T.ImportSource) throws -> T? {
|
||||
public func importUniqueObject<D: ImportableUniqueObject>(
|
||||
_ into: Into<D>,
|
||||
source: D.ImportSource) throws -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -151,7 +151,7 @@ public extension BaseDataTransaction {
|
||||
return nil
|
||||
}
|
||||
|
||||
if let object = self.fetchOne(From(entityType), Where(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
|
||||
if let object = try self.fetchOne(From(entityType), Where<D>(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
|
||||
|
||||
guard entityType.shouldUpdate(from: source, in: self) else {
|
||||
|
||||
@@ -185,10 +185,10 @@ public extension BaseDataTransaction {
|
||||
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
|
||||
- returns: the array of created/updated `ImportableUniqueObject` instances
|
||||
*/
|
||||
public func importUniqueObjects<T: DynamicObject & ImportableUniqueObject, S: Sequence>(
|
||||
_ into: Into<T>,
|
||||
public func importUniqueObjects<D: ImportableUniqueObject, S: Sequence>(
|
||||
_ into: Into<D>,
|
||||
sourceArray: S,
|
||||
preProcess: @escaping (_ mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] where S.Iterator.Element == T.ImportSource {
|
||||
preProcess: @escaping (_ mapping: [D.UniqueIDType: D.ImportSource]) throws -> [D.UniqueIDType: D.ImportSource] = { $0 }) throws -> [D] where S.Iterator.Element == D.ImportSource {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -198,10 +198,10 @@ public extension BaseDataTransaction {
|
||||
return try autoreleasepool {
|
||||
|
||||
let entityType = into.entityClass
|
||||
var importSourceByID = Dictionary<T.UniqueIDType, T.ImportSource>()
|
||||
var importSourceByID = Dictionary<D.UniqueIDType, D.ImportSource>()
|
||||
let sortedIDs = try autoreleasepool {
|
||||
|
||||
return try sourceArray.flatMap { (source) -> T.UniqueIDType? in
|
||||
return try sourceArray.compactMap { (source) -> D.UniqueIDType? in
|
||||
|
||||
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
|
||||
|
||||
@@ -214,12 +214,13 @@ public extension BaseDataTransaction {
|
||||
|
||||
importSourceByID = try autoreleasepool { try preProcess(importSourceByID) }
|
||||
|
||||
var existingObjectsByID = Dictionary<T.UniqueIDType, T>()
|
||||
self.fetchAll(From(entityType), Where(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))?
|
||||
var existingObjectsByID = Dictionary<D.UniqueIDType, D>()
|
||||
try self
|
||||
.fetchAll(From(entityType), Where<D>(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))
|
||||
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
|
||||
|
||||
var processedObjectIDs = Set<T.UniqueIDType>()
|
||||
var result = [T]()
|
||||
var processedObjectIDs = Set<D.UniqueIDType>()
|
||||
var result = [D]()
|
||||
|
||||
for objectID in sortedIDs where !processedObjectIDs.contains(objectID) {
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// BaseDataTransaction+Querying.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2015 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -39,14 +39,13 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the number of `DynamicObject`s deleted
|
||||
*/
|
||||
@discardableResult
|
||||
public func deleteAll<T: DynamicObject>(_ from: From<T>, _ deleteClauses: DeleteClause...) -> Int? {
|
||||
public func deleteAll<D>(_ from: From<D>, _ deleteClauses: DeleteClause...) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
|
||||
return self.context.deleteAll(from, deleteClauses)
|
||||
return try self.context.deleteAll(from, deleteClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,14 +56,32 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- returns: the number of `DynamicObject`s deleted
|
||||
*/
|
||||
@discardableResult
|
||||
public func deleteAll<T: DynamicObject>(_ from: From<T>, _ deleteClauses: [DeleteClause]) -> Int? {
|
||||
public func deleteAll<D>(_ from: From<D>, _ deleteClauses: [DeleteClause]) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.deleteAll(from, deleteClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes all `DynamicObject`s that satisfy the specified conditions.
|
||||
```
|
||||
transaction.deleteAll(From<Person>().where(\.age > 50))
|
||||
```
|
||||
- parameter clauseChain: a `FetchChainableBuilderType` clause chain created from a `From` clause
|
||||
- returns: the number of `DynamicObject`s deleted
|
||||
*/
|
||||
@discardableResult
|
||||
public func deleteAll<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
|
||||
return self.context.deleteAll(from, deleteClauses)
|
||||
return try self.context.deleteAll(clauseChain.from, clauseChain.fetchClauses)
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +93,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter object: a reference to the object created/fetched outside the transaction
|
||||
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
|
||||
*/
|
||||
public func fetchExisting<T: DynamicObject>(_ object: T) -> T? {
|
||||
public func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
|
||||
|
||||
return self.context.fetchExisting(object)
|
||||
}
|
||||
@@ -87,7 +104,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter objectID: the `NSManagedObjectID` for the object
|
||||
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
|
||||
*/
|
||||
public func fetchExisting<T: DynamicObject>(_ objectID: NSManagedObjectID) -> T? {
|
||||
public func fetchExisting<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
|
||||
|
||||
return self.context.fetchExisting(objectID)
|
||||
}
|
||||
@@ -98,7 +115,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter objects: an array of `DynamicObject`s created/fetched outside the transaction
|
||||
- returns: the `DynamicObject` array for objects that exists in the transaction
|
||||
*/
|
||||
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objects: S) -> [T] where S.Iterator.Element == T {
|
||||
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
|
||||
|
||||
return self.context.fetchExisting(objects)
|
||||
}
|
||||
@@ -109,7 +126,7 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- parameter objectIDs: the `NSManagedObjectID` array for the objects
|
||||
- returns: the `DynamicObject` array for objects that exists in the transaction
|
||||
*/
|
||||
public func fetchExisting<T: DynamicObject, S: Sequence>(_ objectIDs: S) -> [T] where S.Iterator.Element == NSManagedObjectID {
|
||||
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
|
||||
|
||||
return self.context.fetchExisting(objectIDs)
|
||||
}
|
||||
@@ -119,15 +136,16 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject` instance that satisfies the specified `FetchClause`s
|
||||
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> T? {
|
||||
public func fetchOne<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchOne(from, fetchClauses)
|
||||
return try self.context.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,15 +153,38 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject` instance that satisfies the specified `FetchClause`s
|
||||
- returns: the first `DynamicObject` instance that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchOne<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> T? {
|
||||
public func fetchOne<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchOne(from, fetchClauses)
|
||||
return try self.context.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let youngestTeen = transaction.fetchOne(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
)
|
||||
```
|
||||
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
|
||||
- returns: the first `DynamicObject` instance that satisfies the specified `FetchChainableBuilderType`, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchOne<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> B.ObjectType? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchOne(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,15 +192,16 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject` instances that satisfy the specified `FetchClause`s
|
||||
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [T]? {
|
||||
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [D] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchAll(from, fetchClauses)
|
||||
return try self.context.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,15 +209,38 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject` instances that satisfy the specified `FetchClause`s
|
||||
- returns: all `DynamicObject` instances that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchAll<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [T]? {
|
||||
public func fetchAll<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [D] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchAll(from, fetchClauses)
|
||||
return try self.context.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let people = transaction.fetchAll(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
)
|
||||
```
|
||||
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
|
||||
- returns: all `DynamicObject` instances that satisfy the specified `FetchChainableBuilderType`, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchAll<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [B.ObjectType] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchAll(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,15 +248,16 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> Int? {
|
||||
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchCount(from, fetchClauses)
|
||||
return try self.context.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,15 +265,38 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- returns: the number of `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchCount<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> Int? {
|
||||
public func fetchCount<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchCount(from, fetchClauses)
|
||||
return try self.context.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let numberOfAdults = transaction.fetchCount(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
)
|
||||
```
|
||||
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
|
||||
- returns: the number of `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchCount<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> Int {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchCount(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,15 +304,16 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject` that satisfies the specified `FetchClause`s
|
||||
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> NSManagedObjectID? {
|
||||
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchObjectID(from, fetchClauses)
|
||||
return try self.context.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,15 +321,38 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject` that satisfies the specified `FetchClause`s
|
||||
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectID<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> NSManagedObjectID? {
|
||||
public func fetchObjectID<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchObjectID(from, fetchClauses)
|
||||
return try self.context.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let youngestTeenID = transaction.fetchObjectID(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
)
|
||||
```
|
||||
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
|
||||
- returns: the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchChainableBuilderType`, or `nil` if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectID<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> NSManagedObjectID? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectID(clauseChain)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,15 +360,16 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: FetchClause...) -> [NSManagedObjectID]? {
|
||||
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: FetchClause...) throws -> [NSManagedObjectID] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchObjectIDs(from, fetchClauses)
|
||||
return try self.context.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,15 +377,38 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
- 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 `DynamicObject`s that satisfy the specified `FetchClause`s
|
||||
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectIDs<T: DynamicObject>(_ from: From<T>, _ fetchClauses: [FetchClause]) -> [NSManagedObjectID]? {
|
||||
public func fetchObjectIDs<D>(_ from: From<D>, _ fetchClauses: [FetchClause]) throws -> [NSManagedObjectID] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.fetchObjectIDs(from, fetchClauses)
|
||||
return try self.context.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType` built from a chain of clauses.
|
||||
```
|
||||
let idsOfAdults = transaction.fetchObjectIDs(
|
||||
From<MyPersonEntity>()
|
||||
.where(\.age > 18)
|
||||
.orderBy(.ascending(\.age))
|
||||
)
|
||||
```
|
||||
- parameter clauseChain: a `FetchChainableBuilderType` built from a chain of clauses
|
||||
- returns: the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchChainableBuilderType`, or an empty array if no match was found
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func fetchObjectIDs<B: FetchChainableBuilderType>(_ clauseChain: B) throws -> [NSManagedObjectID] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.fetchObjectIDs(clauseChain)
|
||||
}
|
||||
|
||||
|
||||
@@ -285,15 +422,16 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- 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.
|
||||
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryValue<T: DynamicObject, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: QueryClause...) -> U? {
|
||||
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: QueryClause...) throws -> U? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.queryValue(from, selectClause, queryClauses)
|
||||
return try self.context.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,15 +442,40 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- 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.
|
||||
- returns: the result of the the query, or `nil` if no match was found. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryValue<T: DynamicObject, U: QueryableAttributeType>(_ from: From<T>, _ selectClause: Select<U>, _ queryClauses: [QueryClause]) -> U? {
|
||||
public func queryValue<D, U: QueryableAttributeType>(_ from: From<D>, _ selectClause: Select<D, U>, _ queryClauses: [QueryClause]) throws -> U? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.queryValue(from, selectClause, queryClauses)
|
||||
return try self.context.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a property value or aggregate as specified by the `QueryChainableBuilderType` built from a chain of 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.
|
||||
```
|
||||
let averageAdultAge = transaction.queryValue(
|
||||
From<MyPersonEntity>()
|
||||
.select(Int.self, .average(\.age))
|
||||
.where(\.age > 18)
|
||||
)
|
||||
```
|
||||
- parameter clauseChain: a `QueryChainableBuilderType` indicating the property/aggregate to fetch and the series of queries for the request.
|
||||
- returns: the result of the the query as specified by the `QueryChainableBuilderType`, or `nil` if no match was found.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryValue<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> B.ResultType? where B.ResultType: QueryableAttributeType {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryValue(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,14 +487,15 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- 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.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryAttributes<T: DynamicObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: QueryClause...) -> [[String: Any]]? {
|
||||
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: QueryClause...) throws -> [[String: Any]] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
return try self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,14 +507,48 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
- 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.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryAttributes<T: DynamicObject>(_ from: From<T>, _ selectClause: Select<NSDictionary>, _ queryClauses: [QueryClause]) -> [[String: Any]]? {
|
||||
public func queryAttributes<D>(_ from: From<D>, _ selectClause: Select<D, NSDictionary>, _ queryClauses: [QueryClause]) throws -> [[String: Any]] {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
return try self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a dictionary of attribute values or as specified by the `QueryChainableBuilderType` built from a chain of 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.
|
||||
```
|
||||
let results = dataStack.queryAttributes(
|
||||
From<MyPersonEntity>()
|
||||
.select(
|
||||
NSDictionary.self,
|
||||
.attribute(\.age, as: "age"),
|
||||
.count(\.age, as: "numberOfPeople")
|
||||
)
|
||||
.groupBy(\.age)
|
||||
)
|
||||
for dictionary in results! {
|
||||
let age = dictionary["age"] as! Int
|
||||
let count = dictionary["numberOfPeople"] as! Int
|
||||
print("There are \(count) people who are \(age) years old."
|
||||
}
|
||||
```
|
||||
- parameter clauseChain: a `QueryChainableBuilderType` indicating the properties to fetch and the series of queries for the request.
|
||||
- returns: the result of the the query as specified by the `QueryChainableBuilderType`
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
public func queryAttributes<B: QueryChainableBuilderType>(_ clauseChain: B) throws -> [[String: Any]] where B.ResultType == NSDictionary {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return try self.context.queryAttributes(clauseChain.from, clauseChain.select, clauseChain.queryClauses)
|
||||
}
|
||||
|
||||
|
||||
@@ -363,13 +561,4 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
return self.context
|
||||
}
|
||||
|
||||
|
||||
// MARK: Obsoleted
|
||||
|
||||
@available(*, obsoleted: 3.1, renamed: "unsafeContext()")
|
||||
public func internalContext() -> NSManagedObjectContext {
|
||||
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// BaseDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2014 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -50,7 +50,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter into: the `Into` clause indicating the destination `NSManagedObject` or `CoreStoreObject` entity type and the destination configuration
|
||||
- returns: a new `NSManagedObject` or `CoreStoreObject` instance of the specified entity type.
|
||||
*/
|
||||
public func create<T: DynamicObject>(_ into: Into<T>) -> T {
|
||||
public func create<D>(_ into: Into<D>) -> D {
|
||||
|
||||
let entityClass = into.entityClass
|
||||
CoreStore.assert(
|
||||
@@ -116,12 +116,12 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of a specified `NSManagedObject`.
|
||||
Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
|
||||
|
||||
- parameter object: the `NSManagedObject` type to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject`.
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` type to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public func edit<T: DynamicObject>(_ object: T?) -> T? {
|
||||
public func edit<D: DynamicObject>(_ object: D?) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -139,9 +139,9 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
|
||||
- parameter into: an `Into` clause specifying the entity type
|
||||
- parameter objectID: the `NSManagedObjectID` for the object to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject`.
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public func edit<T: DynamicObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
|
||||
public func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -156,11 +156,11 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes a specified `NSManagedObject`.
|
||||
Deletes a specified `NSManagedObject` or `CoreStoreObject`.
|
||||
|
||||
- parameter object: the `NSManagedObject` to be deleted
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
*/
|
||||
public func delete<T: DynamicObject>(_ object: T?) {
|
||||
public func delete<D: DynamicObject>(_ object: D?) {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -173,21 +173,21 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`s.
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
|
||||
|
||||
- parameter object1: the `NSManagedObject` to be deleted
|
||||
- parameter object2: another `NSManagedObject` to be deleted
|
||||
- parameter objects: other `NSManagedObject`s to be deleted
|
||||
- parameter object1: the `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
- parameter object2: another `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
- parameter objects: other `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
*/
|
||||
public func delete<T: DynamicObject>(_ object1: T?, _ object2: T?, _ objects: T?...) {
|
||||
public func delete<D: DynamicObject>(_ object1: D?, _ object2: D?, _ objects: D?...) {
|
||||
|
||||
self.delete(([object1, object2] + objects).flatMap { $0 })
|
||||
self.delete(([object1, object2] + objects).compactMap { $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `NSManagedObject`s.
|
||||
Deletes the specified `NSManagedObject`s or `CoreStoreObject`s.
|
||||
|
||||
- parameter objects: the `NSManagedObject`s to be deleted
|
||||
- parameter objects: the `NSManagedObject`s or `CoreStoreObject`s to be deleted
|
||||
*/
|
||||
public func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
|
||||
|
||||
@@ -213,6 +213,25 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
|
||||
|
||||
// MARK: Inspecting Pending Objects
|
||||
|
||||
/**
|
||||
Returns `true` if the object has any property values changed. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `DynamicObject` instance
|
||||
- returns: `true` if the object has any property values changed.
|
||||
*/
|
||||
public func objectHasPersistentChangedValues<D: DynamicObject>(_ entity: D) -> Bool {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return entity.cs_toRaw().hasPersistentChangedValues
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `DynamicObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
|
||||
@@ -220,17 +239,17 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were inserted to the transaction.
|
||||
*/
|
||||
public func insertedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
|
||||
public func insertedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return Set(self.context.insertedObjects.flatMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,7 +260,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
public func insertedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
@@ -257,17 +276,17 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction.
|
||||
*/
|
||||
public func insertedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
|
||||
public func insertedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return Set(self.context.insertedObjects.flatMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,17 +295,17 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were updated in the transaction.
|
||||
*/
|
||||
public func updatedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
|
||||
public func updatedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return Set(self.context.updatedObjects.flatMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,7 +316,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
public func updatedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
@@ -313,17 +332,17 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction.
|
||||
*/
|
||||
public func updatedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
|
||||
public func updatedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access updated object IDs from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return Set(self.context.updatedObjects.flatMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,17 +351,17 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
public func deletedObjects<T: DynamicObject>(_ entity: T.Type) -> Set<T> {
|
||||
public func deletedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return Set(self.context.deletedObjects.flatMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,7 +373,7 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
public func deletedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
@@ -370,17 +389,17 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
public func deletedObjectIDs<T: DynamicObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
|
||||
public func deletedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access deleted object IDs from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return Set(self.context.deletedObjects.flatMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
|
||||
|
||||
@@ -438,48 +457,8 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
return self.bypassesQueueing || self.transactionQueue.cs_isCurrentExecutionContext()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated, message: "Use insertedObjects(_:) and pass the specific entity type")
|
||||
public func insertedObjects() -> Set<NSManagedObject> {
|
||||
deinit {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return self.context.insertedObjects
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use updatedObjects(_:) and pass the specific entity type")
|
||||
public func updatedObjects() -> Set<NSManagedObject> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return self.context.updatedObjects
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use deletedObjects(_:) and pass the specific entity type")
|
||||
public func deletedObjects() -> Set<NSManagedObject> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
return self.context.deletedObjects
|
||||
self.context.reset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSAsynchronousDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -54,12 +54,15 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction, CoreSto
|
||||
!self.bridgeToSwift.isCommitted,
|
||||
"Attempted to commit a \(cs_typeName(self)) more than once."
|
||||
)
|
||||
self.bridgeToSwift.autoCommit { (result) in
|
||||
self.bridgeToSwift.autoCommit { (_, error) in
|
||||
|
||||
switch result {
|
||||
if let error = error {
|
||||
|
||||
case (_, nil): success?()
|
||||
case (_, let error?): failure?(error.bridgeToObjectiveC)
|
||||
failure?(error.bridgeToObjectiveC)
|
||||
}
|
||||
else {
|
||||
|
||||
success?()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,41 +156,6 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction, CoreSto
|
||||
|
||||
super.init(swiftValue)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated, message: "Use the new -[CSAsynchronousDataTransaction commitWithSuccess:failure:] method.")
|
||||
@objc
|
||||
public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) {
|
||||
|
||||
CoreStore.assert(
|
||||
self.bridgeToSwift.transactionQueue.cs_isCurrentExecutionContext(),
|
||||
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.bridgeToSwift.isCommitted,
|
||||
"Attempted to commit a \(cs_typeName(self)) more than once."
|
||||
)
|
||||
self.bridgeToSwift.commit { (result) in
|
||||
|
||||
completion?(result.bridgeToObjectiveC)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ")
|
||||
@objc
|
||||
@discardableResult
|
||||
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
|
||||
|
||||
return bridge {
|
||||
|
||||
self.bridgeToSwift.beginSynchronous { (transaction) in
|
||||
|
||||
closure(transaction.bridgeToObjectiveC)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSBaseDataTransaction+Querying.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -29,7 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSBaseDataTransaction
|
||||
|
||||
public extension CSBaseDataTransaction {
|
||||
extension CSBaseDataTransaction {
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
|
||||
@@ -93,7 +93,8 @@ public extension CSBaseDataTransaction {
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.swiftTransaction.context.fetchOne(from, fetchClauses)
|
||||
return (try? self.swiftTransaction.context.fetchOne(from, fetchClauses))?
|
||||
.flatMap({ $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +111,8 @@ public extension CSBaseDataTransaction {
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.swiftTransaction.context.fetchAll(from, fetchClauses)
|
||||
return (try? self.swiftTransaction.context.fetchAll(from, fetchClauses))
|
||||
.flatMap({ $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,9 +129,8 @@ public extension CSBaseDataTransaction {
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.swiftTransaction.context
|
||||
.fetchCount(from, fetchClauses)
|
||||
.flatMap { NSNumber(value: $0) }
|
||||
return (try? self.swiftTransaction.context.fetchCount(from, fetchClauses))
|
||||
.flatMap({ NSNumber(value: $0) })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +147,8 @@ public extension CSBaseDataTransaction {
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.swiftTransaction.context.fetchObjectID(from, fetchClauses)
|
||||
return (try? self.swiftTransaction.context.fetchObjectID(from, fetchClauses))
|
||||
.flatMap({ $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,7 +168,8 @@ public extension CSBaseDataTransaction {
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.swiftTransaction.context.queryValue(from, selectClause, queryClauses)
|
||||
return (try? self.swiftTransaction.context.queryValue(from, selectClause, queryClauses))
|
||||
.flatMap({ $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,6 +189,7 @@ public extension CSBaseDataTransaction {
|
||||
self.swiftTransaction.isRunningInAllowedQueue(),
|
||||
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
return self.swiftTransaction.context.queryAttributes(from, selectClause, queryClauses)
|
||||
return (try? self.swiftTransaction.context.queryAttributes(from, selectClause, queryClauses))
|
||||
.flatMap({ $0 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSBaseDataTransaction.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -251,28 +251,4 @@ public class CSBaseDataTransaction: NSObject {
|
||||
self.swiftTransaction = swiftValue
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated, message: "Use -[insertedObjectsOfType:] and pass the specific entity class")
|
||||
@objc
|
||||
public func insertedObjects() -> Set<NSManagedObject> {
|
||||
|
||||
return self.swiftTransaction.insertedObjects()
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use -[updatedObjectsOfType:] and pass the specific entity class")
|
||||
@objc
|
||||
public func updatedObjects() -> Set<NSManagedObject> {
|
||||
|
||||
return self.swiftTransaction.updatedObjects()
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use -[deletedObjectsOfType:] and pass the specific entity class")
|
||||
@objc
|
||||
public func deletedObjects() -> Set<NSManagedObject> {
|
||||
|
||||
return self.swiftTransaction.deletedObjects()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSClauseTypes.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSCoreStore+Migrating.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -29,7 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
public extension CSCoreStore {
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
Asynchronously adds a `CSInMemoryStore` to the `defaultStack`. Migrations are also initiated by default.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSCoreStore+Observing.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2015 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -29,8 +29,8 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
public extension CSCoreStore {
|
||||
@available(macOS 10.12, *)
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, creates an `CSObjectMonitor` for the specified `NSManagedObject`. Multiple `CSObjectObserver`s may then register themselves to be notified when changes are made to the `NSManagedObject`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSCoreStore+Querying.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -29,7 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
public extension CSCoreStore {
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
Using the `defaultStack`, fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// CSCoreStore+Setup.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
// Copyright © 2018 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
|
||||
@@ -29,7 +29,7 @@ import CoreData
|
||||
|
||||
// MARK: - CSCoreStore
|
||||
|
||||
public extension CSCoreStore {
|
||||
extension CSCoreStore {
|
||||
|
||||
/**
|
||||
Returns the `defaultStack`'s model version. The version string is the same as the name of the version-specific .xcdatamodeld file.
|
||||
@@ -125,21 +125,4 @@ public extension CSCoreStore {
|
||||
|
||||
return self.defaultStack.addSQLiteStorageAndWait(storage, error: error)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Deprecated
|
||||
|
||||
@available(*, deprecated, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
|
||||
@objc
|
||||
public static var entityClassesByName: [EntityName: NSManagedObject.Type] {
|
||||
|
||||
return CoreStore.entityTypesByName
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use the new +entityTypesByNameForType: method passing `[NSManagedObject class]` as argument.")
|
||||
@objc
|
||||
public static func entityClassWithName(_ name: EntityName) -> NSManagedObject.Type? {
|
||||
|
||||
return CoreStore.entityTypesByName[name]
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user