mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-12 04:10:36 +01:00
Compare commits
462 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
5689158b43 | ||
|
|
6fcdf3d011 | ||
|
|
e26573c18e | ||
|
|
801cf8d9f0 | ||
|
|
eced8f2e93 | ||
|
|
3b735d07ec | ||
|
|
5eb5476e3a | ||
|
|
6a42a0054e | ||
|
|
8c437e19b8 | ||
|
|
9cd3b6c879 | ||
|
|
fe135acbec | ||
|
|
997c5bdcfa | ||
|
|
23e12c4539 | ||
|
|
ca9798be14 | ||
|
|
6e01a58c85 | ||
|
|
f618617053 | ||
|
|
49b8b9c372 | ||
|
|
129f975d96 | ||
|
|
a2e463e58c | ||
|
|
5fd50f0e15 | ||
|
|
7f9a915d71 | ||
|
|
0a81736b7a | ||
|
|
f9b6dd0c6a | ||
|
|
0354401b56 | ||
|
|
0304067beb | ||
|
|
ddd83da434 | ||
|
|
fc7df671de | ||
|
|
5fde9030c7 | ||
|
|
d7b07b3f00 | ||
|
|
ddd1ffb29f | ||
|
|
98094000bb | ||
|
|
d5026ef996 | ||
|
|
2cd913b9dd | ||
|
|
ad9520abbc | ||
|
|
c0fc57d10c | ||
|
|
0cf4d303e4 | ||
|
|
6de397958a | ||
|
|
55292a84dc | ||
|
|
981b560d53 | ||
|
|
c4c4dd55cd | ||
|
|
1ddbe20c86 | ||
|
|
da9e8c1550 | ||
|
|
ef0937fec4 | ||
|
|
35885b40de | ||
|
|
d669569196 | ||
|
|
ae919ff3c8 | ||
|
|
1a7a4690d1 | ||
|
|
b9b96d1a35 | ||
|
|
da3a9590ac | ||
|
|
6b3d75bea1 | ||
|
|
d44721fef0 | ||
|
|
3f268e8376 | ||
|
|
303fea4ebe | ||
|
|
77173cdad0 | ||
|
|
1e24a7d739 | ||
|
|
a3b33bedb8 | ||
|
|
eaf7544c50 | ||
|
|
67863120e0 | ||
|
|
1b0e305d9a | ||
|
|
91fda01071 | ||
|
|
feb0e30735 | ||
|
|
9c25336ff6 | ||
|
|
66bef87422 | ||
|
|
dd2949ee18 | ||
|
|
e0abb9b0af | ||
|
|
42c28b064a | ||
|
|
0b097b8c85 | ||
|
|
fce5d2f301 | ||
|
|
8ff163af30 | ||
|
|
19abedfa9f | ||
|
|
48828fdca3 | ||
|
|
9d65a27557 | ||
|
|
6d04806608 | ||
|
|
54129f7362 | ||
|
|
54c81d23f5 | ||
|
|
53ab140341 | ||
|
|
9dc4331b26 | ||
|
|
e6aa72fb5f | ||
|
|
274a54451a | ||
|
|
fe70b7a27d | ||
|
|
02a660e4a6 | ||
|
|
a543a4c94a | ||
|
|
fd14a18248 | ||
|
|
b0e2655bdf | ||
|
|
b6bc7c2edf | ||
|
|
1938f0d9de | ||
|
|
94e6db669f | ||
|
|
b1972b82f1 | ||
|
|
5ffaca1375 | ||
|
|
a73306fecb | ||
|
|
9f3db61ff7 | ||
|
|
e5ef4992d3 | ||
|
|
c0ae129b22 | ||
|
|
4aa1a63f9a | ||
|
|
4fc10afe1e | ||
|
|
8b77e4e5a0 | ||
|
|
258c237100 | ||
|
|
6948db516d | ||
|
|
b5d80fd272 | ||
|
|
cdcd7d0416 | ||
|
|
a5162239d5 | ||
|
|
1ad6ac5769 | ||
|
|
ecb3d0cfa0 | ||
|
|
81355fd9c5 | ||
|
|
97d7a276fe | ||
|
|
d72d1afe8b | ||
|
|
716e069984 | ||
|
|
881ee4af0a | ||
|
|
acc0ce1c32 | ||
|
|
b97f6d6a0a | ||
|
|
818abfc1a1 | ||
|
|
f055c54a66 | ||
|
|
cb6d5b015b | ||
|
|
494965de23 | ||
|
|
fe25a9aa36 | ||
|
|
f21e4e12e0 | ||
|
|
92890d1e1d | ||
|
|
0c483e0e19 | ||
|
|
6055685c00 | ||
|
|
ee71442b08 | ||
|
|
341ec5e771 | ||
|
|
8569c3c524 | ||
|
|
3224fcf71d | ||
|
|
9ff1c9d545 | ||
|
|
c40d17a6ad | ||
|
|
9d5e04854a | ||
|
|
d2fd03c1f0 | ||
|
|
7baaee493d | ||
|
|
03973790a8 | ||
|
|
7ee027f44d | ||
|
|
19fea6953a | ||
|
|
9f11b1005d | ||
|
|
698326f89a | ||
|
|
bdf6308d8f | ||
|
|
69d96c53d6 | ||
|
|
7b961fa249 | ||
|
|
73450d0b29 | ||
|
|
6d83564a1a | ||
|
|
c0d72799b4 | ||
|
|
06a1919e91 | ||
|
|
16def2d84b | ||
|
|
e9a2c58f32 | ||
|
|
1a3e0dd4c6 | ||
|
|
518bb134f9 | ||
|
|
4d7feca848 | ||
|
|
64a80bf401 | ||
|
|
4d63fc744a | ||
|
|
9480e372f1 | ||
|
|
23df460c35 | ||
|
|
1c233b7302 | ||
|
|
f42288802c | ||
|
|
a27556f294 | ||
|
|
e330291e1b | ||
|
|
4a282150f0 | ||
|
|
5d2956d674 | ||
|
|
92756fec42 | ||
|
|
2b37daefe0 | ||
|
|
5724d4599e | ||
|
|
4a882e6108 | ||
|
|
b230ed6400 | ||
|
|
33a5c123aa | ||
|
|
73637321ce | ||
|
|
088f1717f9 | ||
|
|
cff2bb1740 | ||
|
|
d902d62172 | ||
|
|
b955495012 | ||
|
|
d2e78a70e1 | ||
|
|
970957cbc2 | ||
|
|
2f9e5db89f | ||
|
|
1789eb7daf | ||
|
|
3999654ee7 | ||
|
|
4c3bec287c | ||
|
|
2a2d9b3483 | ||
|
|
32a388e0ca | ||
|
|
1a6fbad3d4 | ||
|
|
ac55f20f5f | ||
|
|
910b5039fd | ||
|
|
ffea06ee7e | ||
|
|
a92d6cac02 | ||
|
|
de5d660257 | ||
|
|
55b2e6eecd | ||
|
|
b64c776335 | ||
|
|
432af667e8 | ||
|
|
cf60a4bc2e | ||
|
|
c620859899 | ||
|
|
65ac069a0b | ||
|
|
862ef27374 | ||
|
|
243b6a76d5 | ||
|
|
8be20370d5 | ||
|
|
a9c0feae46 | ||
|
|
2e44f86eb6 | ||
|
|
ed8c7b35e8 | ||
|
|
4d2ebe4ea8 | ||
|
|
54be9d471c | ||
|
|
a51ed1a007 | ||
|
|
e5245a0e5b | ||
|
|
0fa2a23461 | ||
|
|
3f28198552 | ||
|
|
82de482191 | ||
|
|
b502895d63 | ||
|
|
0ba63c6e72 | ||
|
|
e9be711d4c | ||
|
|
db5b8ca702 | ||
|
|
2f39f9188b | ||
|
|
872e69ddc6 | ||
|
|
f9e33101a0 | ||
|
|
0621c54868 | ||
|
|
a638620858 | ||
|
|
267c21063a |
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
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "Carthage/Checkouts/GCDKit"]
|
||||
path = Carthage/Checkouts/GCDKit
|
||||
url = https://github.com/JohnEstropia/GCDKit.git
|
||||
|
||||
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
|
||||
38
.travis.yml
38
.travis.yml
@@ -1,5 +1,5 @@
|
||||
language: objective-c
|
||||
osx_image: xcode8
|
||||
osx_image: xcode10.2
|
||||
sudo: false
|
||||
git:
|
||||
submodules: false
|
||||
@@ -10,24 +10,22 @@ env:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
- LANG=en_US.UTF-8
|
||||
matrix:
|
||||
- DESTINATION="OS=10.0,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator10.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator10.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.2,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator10.0 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.0 RUN_TESTS="YES" POD_LINT="YES"
|
||||
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.12 RUN_TESTS="YES" POD_LINT="NO"
|
||||
- DESTINATION="OS=3.0,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.0 RUN_TESTS="NO" POD_LINT="NO"
|
||||
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.0 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.11/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
|
||||
@@ -36,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.0" -destination "OS=10.0,name=iPhone 7" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
|
||||
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator10.0" -destination "OS=10.0,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 +0,0 @@
|
||||
github "JohnEstropia/GCDKit" "1.3.0"
|
||||
|
||||
1
Carthage/Checkouts/GCDKit
vendored
1
Carthage/Checkouts/GCDKit
vendored
Submodule Carthage/Checkouts/GCDKit deleted from a7f2b8ac84
@@ -1,24 +1,22 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "CoreStore"
|
||||
s.version = "2.1.0"
|
||||
s.version = "6.3.1"
|
||||
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"
|
||||
s.frameworks = "Foundation", "CoreData"
|
||||
s.requires_arc = true
|
||||
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D USE_FRAMEWORKS -D DEBUG',
|
||||
'OTHER_SWIFT_FLAGS[config=Release]' => '-D USE_FRAMEWORKS',
|
||||
'GCC_PREPROCESSOR_DEFINITIONS' => 'USE_FRAMEWORKS=1' }
|
||||
|
||||
s.dependency "GCDKit", "1.3.0"
|
||||
s.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D DEBUG' }
|
||||
end
|
||||
|
||||
BIN
CoreStore.sketch
BIN
CoreStore.sketch
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -10,10 +10,10 @@
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F347F55F-7F5C-4476-9148-6E902F06E4AD",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore"
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
|
||||
"DVTSourceControlWorkspaceBlueprintVersion" : 203,
|
||||
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
|
||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
||||
{
|
||||
|
||||
@@ -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 = "0710"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -11,8 +11,7 @@
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES"
|
||||
hideIssues = "NO">
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
|
||||
@@ -26,8 +25,7 @@
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO"
|
||||
hideIssues = "NO">
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
|
||||
@@ -65,6 +63,11 @@
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "NSZombieEnabled"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
@@ -86,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 = "0720"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
3
CoreStore.xcworkspace/contents.xcworkspacedata
generated
3
CoreStore.xcworkspace/contents.xcworkspacedata
generated
@@ -7,7 +7,4 @@
|
||||
<FileRef
|
||||
location = "group:CoreStoreDemo/CoreStoreDemo.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Carthage/Checkouts/GCDKit/GCDKit.xcodeproj">
|
||||
</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>
|
||||
@@ -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>
|
||||
@@ -12,7 +12,6 @@
|
||||
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADD1AFDC71700F90881 /* Palette.swift */; };
|
||||
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B503FADE1AFDC71700F90881 /* PaletteTableViewCell.swift */; };
|
||||
B5125C121B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C111B521B78003A42C7 /* OrganismV2ToV3.xcmappingmodel */; };
|
||||
B5125C141B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B5125C131B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel */; };
|
||||
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977D81B120B80003D50A5 /* ObserversViewController.swift */; };
|
||||
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52977DC1B120F3B003D50A5 /* TransactionsDemoViewController.swift */; };
|
||||
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52977DE1B120F83003D50A5 /* MapKit.framework */; };
|
||||
@@ -36,8 +35,6 @@
|
||||
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
|
||||
B56965291B3582D30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56965271B3582D30075EE4A /* MigrationDemo.xcdatamodeld */; };
|
||||
B5E599321B5240F50084BD5F /* OrganismTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */; };
|
||||
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; };
|
||||
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9241C202429008147CD /* GCDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; };
|
||||
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5BDC9211C202429008147CD /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B5EE25851B36E23C0000406B /* OrganismV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EE25841B36E23C0000406B /* OrganismV1.swift */; };
|
||||
@@ -54,7 +51,6 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
B5E89ACE1C52929C003B04A9 /* GCDKit.framework in Embed Frameworks */,
|
||||
B5E89AD11C5292A2003B04A9 /* CoreStore.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
@@ -94,7 +90,6 @@
|
||||
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryingResultsViewController.swift; sourceTree = "<group>"; };
|
||||
B56965281B3582D30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5BDC9211C202429008147CD /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B5BDC9241C202429008147CD /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GCDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B5E599311B5240F50084BD5F /* OrganismTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OrganismTableViewCell.swift; path = "CoreStoreDemo/MIgrations Demo/OrganismTableViewCell.swift"; sourceTree = SOURCE_ROOT; };
|
||||
B5EE25801B36E1B00000406B /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5EE25841B36E23C0000406B /* OrganismV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrganismV1.swift; sourceTree = "<group>"; };
|
||||
@@ -110,7 +105,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B5E89ACD1C52929C003B04A9 /* GCDKit.framework in Frameworks */,
|
||||
B5E89AD01C5292A2003B04A9 /* CoreStore.framework in Frameworks */,
|
||||
B52977E11B120F8A003D50A5 /* CoreLocation.framework in Frameworks */,
|
||||
B52977DF1B120F83003D50A5 /* MapKit.framework in Frameworks */,
|
||||
@@ -146,7 +140,6 @@
|
||||
children = (
|
||||
B52977E01B120F8A003D50A5 /* CoreLocation.framework */,
|
||||
B5BDC9211C202429008147CD /* CoreStore.framework */,
|
||||
B5BDC9241C202429008147CD /* GCDKit.framework */,
|
||||
B52977DE1B120F83003D50A5 /* MapKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
@@ -272,18 +265,18 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0700;
|
||||
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,
|
||||
@@ -337,7 +330,6 @@
|
||||
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */,
|
||||
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */,
|
||||
B560070F1B3EC90F00A9A8F9 /* OrganismV2ToV3MigrationPolicy.swift in Sources */,
|
||||
B5125C141B521BA7003A42C7 /* OrganismV3ToV2.xcmappingmodel in Sources */,
|
||||
B503FADF1AFDC71700F90881 /* ListObserverDemoViewController.swift in Sources */,
|
||||
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */,
|
||||
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */,
|
||||
@@ -379,13 +371,23 @@
|
||||
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;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -408,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;
|
||||
};
|
||||
@@ -424,13 +428,23 @@
|
||||
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;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -446,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;
|
||||
@@ -458,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 = 2.3;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -471,11 +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_VERSION = 2.3;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B54AAD481AF4D26E00848AE0"
|
||||
BuildableName = "CoreStoreDemo.app"
|
||||
BlueprintName = "CoreStoreDemo"
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -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,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
|
||||
|
||||
application.statusBarStyle = .LightContent
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
|
||||
|
||||
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,39 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10112" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Ni8-QF-XHB">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="10083"/>
|
||||
<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">
|
||||
<mutableArray key="AppleSDGothicNeo.ttc">
|
||||
<array key="AppleSDGothicNeo.ttc">
|
||||
<string>AppleSDGothicNeo-Regular</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="HelveticaNeue.ttc">
|
||||
<string>HelveticaNeue-Bold</string>
|
||||
<string>HelveticaNeue-Bold</string>
|
||||
</array>
|
||||
<array key="HelveticaNeue.ttc">
|
||||
<string>HelveticaNeue</string>
|
||||
<string>HelveticaNeue</string>
|
||||
</mutableArray>
|
||||
<mutableArray key="HelveticaNeueLights.ttc">
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Bold</string>
|
||||
</array>
|
||||
<array key="HelveticaNeueLights.ttc">
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Thin</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
<string>HelveticaNeue-Light</string>
|
||||
</mutableArray>
|
||||
</array>
|
||||
</customFonts>
|
||||
<scenes>
|
||||
<!--SNS Accounts-->
|
||||
@@ -41,34 +27,34 @@
|
||||
<objects>
|
||||
<tableViewController id="AW4-lY-JNk" customClass="StackSetupDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="S3A-lm-AuA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="yud-WH-MPa">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="150"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="sns" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="czc-nd-es9">
|
||||
<rect key="frame" x="20" y="20" width="560" height="26.5"/>
|
||||
<rect key="frame" x="20" y="20" width="335" height="26.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/>
|
||||
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" 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>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="name" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1eh-91-O2N">
|
||||
<rect key="frame" x="20" y="70" width="41" height="20.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
|
||||
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" 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>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="friends" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p2y-0T-hQs">
|
||||
<rect key="frame" x="539.5" y="72" width="40.5" height="17"/>
|
||||
<rect key="frame" x="314.5" y="72" width="40.5" height="17"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/>
|
||||
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" 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 firstItem="1eh-91-O2N" firstAttribute="top" secondItem="czc-nd-es9" secondAttribute="bottom" constant="23.5" id="F6q-Jt-glI"/>
|
||||
<constraint firstItem="p2y-0T-hQs" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="1eh-91-O2N" secondAttribute="trailing" constant="20" id="GVS-6o-rmj"/>
|
||||
@@ -82,24 +68,24 @@
|
||||
</view>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="8b8-lM-Krq" detailTextLabel="hR1-Zb-BOk" style="IBUITableViewCellStyleValue1" id="dMt-nx-EO5">
|
||||
<rect key="frame" x="0.0" y="236" width="600" height="44"/>
|
||||
<rect key="frame" x="0.0" y="172" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dMt-nx-EO5" id="gdK-VV-zNb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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="533" 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="calibratedRGB"/>
|
||||
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -131,23 +117,23 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="t9A-zf-Iew"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="75P-2m-6cr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WUc-3Y-Quw">
|
||||
<rect key="frame" x="0.0" y="324" width="600" height="276"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<rect key="frame" x="0.0" y="324" width="375" height="343"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="OrganismTableViewCell" id="WVb-th-o8c" customClass="OrganismTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="22" width="600" height="44"/>
|
||||
<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="WVb-th-o8c" id="JBq-Ml-a9p">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<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="520" 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!"/>
|
||||
@@ -156,9 +142,9 @@
|
||||
</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="495" 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.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -184,42 +170,42 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XKA-Ub-c2X">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="260"/>
|
||||
<rect key="frame" x="0.0" y="64" width="375" height="260"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="i7U-bW-juB" customClass="UIButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="260"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Organism" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zxy-nY-P44">
|
||||
<rect key="frame" x="20" y="90.5" width="560" height="26.5"/>
|
||||
<rect key="frame" x="20" y="90.5" width="335" height="26.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="22"/>
|
||||
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" 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>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="attributes" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Ac-xl-ldZ">
|
||||
<rect key="frame" x="20" y="131.5" width="560" height="20.5"/>
|
||||
<rect key="frame" x="20" y="131.5" width="335" height="20.5"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="17"/>
|
||||
<color key="textColor" red="0.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" 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>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="rAZ-eJ-sxy">
|
||||
<rect key="frame" x="20" y="20" width="560" height="29"/>
|
||||
<rect key="frame" x="20" y="20" width="335" height="29"/>
|
||||
<segments>
|
||||
<segment title="First"/>
|
||||
<segment title="Second"/>
|
||||
<segment title=""/>
|
||||
</segments>
|
||||
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<action selector="segmentedControlValueChanged:" destination="iVv-Vc-nCL" eventType="valueChanged" id="RwG-kW-RPg"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
<progressView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="869-wx-Odb">
|
||||
<rect key="frame" x="20" y="68" width="560" height="2"/>
|
||||
<color key="progressTintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="trackTintColor" white="1" alpha="0.20000000000000001" colorSpace="calibratedWhite"/>
|
||||
<rect key="frame" x="20" y="68" width="335" height="2"/>
|
||||
<color key="progressTintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="trackTintColor" red="1" green="1" blue="1" alpha="0.20000000000000001" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</progressView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" 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 firstItem="zxy-nY-P44" firstAttribute="leading" secondItem="i7U-bW-juB" secondAttribute="leading" constant="20" id="1u1-Tq-hRn"/>
|
||||
<constraint firstItem="6Ac-xl-ldZ" firstAttribute="top" secondItem="zxy-nY-P44" secondAttribute="bottom" constant="14.5" id="39B-9l-O3g"/>
|
||||
@@ -237,7 +223,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="260" id="90R-Mf-iAB"/>
|
||||
<constraint firstItem="i7U-bW-juB" firstAttribute="leading" secondItem="XKA-Ub-c2X" secondAttribute="leading" id="e9h-f4-c37"/>
|
||||
@@ -246,7 +232,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="XKA-Ub-c2X" secondAttribute="trailing" id="U0P-51-KT9"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WUc-3Y-Quw" secondAttribute="trailing" id="i7I-7B-97K"/>
|
||||
@@ -276,31 +262,31 @@
|
||||
<objects>
|
||||
<tableViewController id="t0d-B0-B7U" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="50" sectionHeaderHeight="10" sectionFooterHeight="10" id="uHB-Yr-ujV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<sections>
|
||||
<tableViewSection id="wIP-Hn-YfF">
|
||||
<cells>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="Q3n-Df-v1t" detailTextLabel="Hbn-cf-Y7m" style="IBUITableViewCellStyleSubtitle" id="AXm-KE-45G">
|
||||
<rect key="frame" x="0.0" y="99" width="600" height="50"/>
|
||||
<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="567" 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.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -310,24 +296,24 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="vpt-cT-gMo" detailTextLabel="ou9-TZ-8bf" style="IBUITableViewCellStyleSubtitle" id="fsb-zw-8Ii">
|
||||
<rect key="frame" x="0.0" y="149" width="600" height="50"/>
|
||||
<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="567" 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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -337,24 +323,24 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="UbU-Kd-yrY" detailTextLabel="uP1-Jc-o9v" style="IBUITableViewCellStyleSubtitle" id="ekW-PJ-mbo">
|
||||
<rect key="frame" x="0.0" y="199" width="600" height="50"/>
|
||||
<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="567" 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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -364,24 +350,24 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="C8Y-0y-lEG" detailTextLabel="jZw-qE-0ws" style="IBUITableViewCellStyleSubtitle" id="ph1-8z-C1m">
|
||||
<rect key="frame" x="0.0" y="249" width="600" height="50"/>
|
||||
<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="567" 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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -391,24 +377,24 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="ZfY-Aq-Ykq" detailTextLabel="QzD-9b-k1j" style="IBUITableViewCellStyleSubtitle" id="wyK-rk-3tI">
|
||||
<rect key="frame" x="0.0" y="299" width="600" height="50"/>
|
||||
<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="567" 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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -418,24 +404,24 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="hSG-mG-YBw" detailTextLabel="X9P-TQ-LYh" style="IBUITableViewCellStyleSubtitle" id="xTM-Cf-0if">
|
||||
<rect key="frame" x="0.0" y="349" width="600" height="50"/>
|
||||
<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="567" 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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -467,69 +453,69 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="aI4-O3-OCi"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="w8K-eN-RvU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/>
|
||||
<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" translatesAutoresizingMaskIntoConstraints="NO" id="NhC-oM-bkd">
|
||||
<rect key="frame" x="20" y="69.5" width="552" height="36.5"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<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"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="250" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vfe-Yq-3Xa">
|
||||
<rect key="frame" x="20" y="116" width="552" height="18"/>
|
||||
<rect key="frame" x="16" y="149.5" width="343" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="4h9-ha-EzR"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hue" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sgg-Md-Nf3">
|
||||
<rect key="frame" x="20" y="154" width="74" height="18"/>
|
||||
<rect key="frame" x="16" y="187.5" width="74" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Saturation" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rry-vh-bRK">
|
||||
<rect key="frame" x="20" y="192" width="74" height="18"/>
|
||||
<rect key="frame" x="16" y="225.5" width="74" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Brightness" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vTa-ly-eyO">
|
||||
<rect key="frame" x="20" y="230" width="74" height="18"/>
|
||||
<rect key="frame" x="16" y="263.5" width="74" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="359" translatesAutoresizingMaskIntoConstraints="NO" id="YQ6-fq-3Wb">
|
||||
<rect key="frame" x="102" y="148" width="472" height="31"/>
|
||||
<rect key="frame" x="98" y="181.5" width="263" height="31"/>
|
||||
<connections>
|
||||
<action selector="hueSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="9Hy-3h-llE"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="xXz-78-tAd">
|
||||
<rect key="frame" x="102" y="186" width="472" height="31"/>
|
||||
<rect key="frame" x="98" y="219.5" width="263" height="31"/>
|
||||
<connections>
|
||||
<action selector="saturationSliderValueDidChange:" destination="dX3-kR-CYC" eventType="valueChanged" id="qtU-ua-ZTc"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="hpy-2d-eOP">
|
||||
<rect key="frame" x="102" y="224" width="472" height="31"/>
|
||||
<rect key="frame" x="98" y="257.5" width="263" height="31"/>
|
||||
<connections>
|
||||
<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" 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"/>
|
||||
<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="calibratedRGB"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="p4O-tf-dgt" firstAttribute="trailing" secondItem="w8K-eN-RvU" secondAttribute="trailingMargin" id="022-ll-1s1"/>
|
||||
<constraint firstItem="vTa-ly-eyO" firstAttribute="top" secondItem="rry-vh-bRK" secondAttribute="bottom" constant="20" id="1hd-Ti-CnT"/>
|
||||
@@ -591,23 +577,23 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="LNL-mj-D7l"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="6x3-vn-Egt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L5f-tW-lXf">
|
||||
<rect key="frame" x="4" y="64" width="592" height="268"/>
|
||||
<rect key="frame" x="0.0" y="64" width="375" height="301.5"/>
|
||||
<connections>
|
||||
<segue destination="5Fw-je-9gI" kind="embed" id="YcI-2Z-ijV"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6So-f3-4Gp">
|
||||
<rect key="frame" x="4" y="332" width="592" height="268"/>
|
||||
<rect key="frame" x="0.0" y="365.5" width="375" height="301.5"/>
|
||||
<connections>
|
||||
<segue destination="sll-yo-mBc" kind="embed" id="AAl-HS-dq2"/>
|
||||
</connections>
|
||||
</containerView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="6So-f3-4Gp" firstAttribute="top" secondItem="L5f-tW-lXf" secondAttribute="bottom" id="3m8-tj-Nd4"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="6So-f3-4Gp" secondAttribute="trailing" constant="-16" id="4L8-wZ-F59"/>
|
||||
@@ -634,13 +620,13 @@
|
||||
<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.92549019610000005" green="0.94117647059999998" blue="0.94509803920000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="24"/>
|
||||
<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"/>
|
||||
</textAttributes>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
@@ -657,27 +643,27 @@
|
||||
<objects>
|
||||
<tableViewController id="3AE-ED-0oj" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="DAz-BE-6Ca">
|
||||
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="G3X-70-BCD" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="66" width="592" height="44"/>
|
||||
<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="559" 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"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -716,28 +702,28 @@
|
||||
<objects>
|
||||
<tableViewController id="lCE-i6-UCT" customClass="ListObserverDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Zba-8M-Zd7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="592" height="268"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="301.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="PaletteTableViewCell" id="zSO-3e-OVq" customClass="PaletteTableViewCell" customModule="CoreStoreDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="66" width="592" height="44"/>
|
||||
<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="559" 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"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -778,13 +764,13 @@
|
||||
<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.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</textAttributes>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
@@ -805,19 +791,19 @@
|
||||
<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="600" height="536"/>
|
||||
<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" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="V2U-0R-Ts0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" 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>
|
||||
</mapView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<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"/>
|
||||
@@ -831,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">
|
||||
@@ -842,30 +828,30 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="Cwn-Jd-4Lr"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="n9M-Je-Dj0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" alwaysBounceVertical="YES" indicatorStyle="white" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TpK-gX-CTN">
|
||||
<rect key="frame" x="0.0" y="142" width="600" height="458"/>
|
||||
<color key="backgroundColor" red="0.20392156862745098" green="0.28627450980392155" blue="0.36862745098039218" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.94509803921568625" green="0.7686274509803922" blue="0.058823529411764705" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<rect key="frame" x="0.0" y="142" width="375" height="525"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.92706394195556641" green="0.72759377956390381" blue="0.064024783670902252" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="15"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" momentary="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4iq-B4-k0p">
|
||||
<rect key="frame" x="20" y="94" width="560" height="29"/>
|
||||
<rect key="frame" x="20" y="94" width="335" height="29"/>
|
||||
<segments>
|
||||
<segment title="Log"/>
|
||||
<segment title="Error"/>
|
||||
<segment title="Assert"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<action selector="segmentedControlValueChanged:" destination="5yy-0N-QDU" eventType="valueChanged" id="2pp-Vt-2Os"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="4iq-B4-k0p" firstAttribute="leading" secondItem="n9M-Je-Dj0" secondAttribute="leading" constant="20" id="6SM-eN-NxP"/>
|
||||
<constraint firstItem="TpK-gX-CTN" firstAttribute="leading" secondItem="n9M-Je-Dj0" secondAttribute="leading" id="AAw-IG-taz"/>
|
||||
@@ -899,13 +885,13 @@
|
||||
<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.74117647058823533" green="0.76470588235294112" blue="0.7803921568627451" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" red="0.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Thin" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.68773996829986572" green="0.71417498588562012" blue="0.73246318101882935" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</textAttributes>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
@@ -926,30 +912,30 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="DlN-cN-JXd"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="eC3-ql-d2o">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WGY-kX-mAx">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="536"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="iaH-1W-Sbo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="80"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="80"/>
|
||||
<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"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<action selector="segmentedControlValueChanged:" destination="qbj-MK-nIY" eventType="valueChanged" id="Wok-dl-uq7"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="0.80000000000000004" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.80000000000000004" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YVj-dA-fyV" firstAttribute="leading" secondItem="iaH-1W-Sbo" secondAttribute="leading" constant="20" id="1dX-t7-dyR"/>
|
||||
<constraint firstAttribute="centerY" secondItem="YVj-dA-fyV" secondAttribute="centerY" id="HXU-Z7-jfu"/>
|
||||
@@ -958,17 +944,17 @@
|
||||
</view>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="6db-P0-6Ms" style="IBUITableViewCellStyleDefault" id="vUr-WV-qur">
|
||||
<rect key="frame" x="0.0" y="102" width="600" height="44"/>
|
||||
<rect key="frame" x="0.0" y="102" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vUr-WV-qur" id="Vr0-hE-cn9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="567" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="342" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6db-P0-6Ms">
|
||||
<rect key="frame" x="15" y="0.0" width="550" height="43.5"/>
|
||||
<rect key="frame" x="15" y="0.0" width="325" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="18"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -981,7 +967,7 @@
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="WGY-kX-mAx" firstAttribute="top" secondItem="dgu-PC-LiB" secondAttribute="bottom" id="0pS-cU-ibk"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WGY-kX-mAx" secondAttribute="trailing" id="NeY-g5-CaB"/>
|
||||
@@ -1006,30 +992,30 @@
|
||||
<objects>
|
||||
<tableViewController id="tIs-pN-OgO" customClass="FetchingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="tVl-tT-UDk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="RgX-yK-1L2" detailTextLabel="QZ4-A2-x4h" style="IBUITableViewCellStyleSubtitle" id="uBt-Iy-nWP">
|
||||
<rect key="frame" x="0.0" y="100" width="600" height="60"/>
|
||||
<rect key="frame" x="0.0" y="36" width="375" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uBt-Iy-nWP" id="6SD-ur-9zp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="59.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
@@ -1052,30 +1038,30 @@
|
||||
<objects>
|
||||
<tableViewController id="o9D-Xm-13g" customClass="QueryingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="bMh-zR-xwu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="backgroundColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.15542715787887573" green="0.2203737199306488" blue="0.2959403395652771" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="Syt-QJ-KXg" detailTextLabel="yHS-dP-IKS" style="IBUITableViewCellStyleSubtitle" id="q7Q-aF-Ftl">
|
||||
<rect key="frame" x="0.0" y="100" width="600" height="60"/>
|
||||
<rect key="frame" x="0.0" y="36" width="375" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="q7Q-aF-Ftl" id="fc3-eg-yes">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="59.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="59.5"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<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.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="textColor" red="0.13079629838466644" green="0.184075728058815" blue="0.24594299495220184" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
|
||||
@@ -1,36 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10169.1" systemVersion="15D21" minimumToolsVersion="Automatic">
|
||||
<entity name="Palette" representedClassName="CoreStoreDemo.Palette">
|
||||
<attribute name="brightness" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="colorName" optional="YES" transient="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="hue" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="saturation" optional="YES" attributeType="Float" defaultValueString="0.0" syncable="YES"/>
|
||||
<userInfo/>
|
||||
</entity>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16F73" minimumToolsVersion="Xcode 7.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Place" representedClassName="CoreStoreDemo.Place" syncable="YES">
|
||||
<attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="longitude" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="longitude" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="TimeZone" representedClassName="CoreStoreDemo.TimeZone" syncable="YES">
|
||||
<attribute name="abbreviation" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="daylightSavingTimeOffset" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="daylightSavingTimeOffset" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" usesScalarValueType="NO" syncable="YES"/>
|
||||
</entity>
|
||||
<configuration name="FetchingAndQueryingDemo">
|
||||
<memberEntity name="TimeZone"/>
|
||||
</configuration>
|
||||
<configuration name="ObservingDemo">
|
||||
<memberEntity name="Palette"/>
|
||||
</configuration>
|
||||
<configuration name="TransactionsDemo">
|
||||
<memberEntity name="Place"/>
|
||||
</configuration>
|
||||
<elements>
|
||||
<element name="Palette" positionX="261" positionY="189" width="128" height="105"/>
|
||||
<element name="Place" positionX="261" positionY="225" width="128" height="105"/>
|
||||
<element name="TimeZone" positionX="297" positionY="270" width="128" height="120"/>
|
||||
</elements>
|
||||
|
||||
@@ -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
|
||||
@@ -19,29 +19,27 @@ private struct Static {
|
||||
SQLiteStore(
|
||||
fileName: "TimeZoneDemo.sqlite",
|
||||
configuration: "FetchingAndQueryingDemo",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From(TimeZone))
|
||||
|
||||
for name in NSTimeZone.knownTimeZoneNames() {
|
||||
_ = try? dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
let rawTimeZone = NSTimeZone(name: name)!
|
||||
let cachedTimeZone = transaction.create(Into(TimeZone))
|
||||
try transaction.deleteAll(From<TimeZone>())
|
||||
|
||||
cachedTimeZone.name = rawTimeZone.name
|
||||
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
|
||||
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT)
|
||||
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.daylightSavingTime
|
||||
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
|
||||
for name in NSTimeZone.knownTimeZoneNames {
|
||||
|
||||
let rawTimeZone = NSTimeZone(name: name)!
|
||||
let cachedTimeZone = transaction.create(Into<TimeZone>())
|
||||
|
||||
cachedTimeZone.name = rawTimeZone.name
|
||||
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
|
||||
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT)
|
||||
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.isDaylightSavingTime
|
||||
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
|
||||
}
|
||||
}
|
||||
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
|
||||
)
|
||||
return dataStack
|
||||
}()
|
||||
}
|
||||
@@ -53,7 +51,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
@@ -67,27 +65,27 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
let alert = UIAlertController(
|
||||
title: "Fetch and Query Demo",
|
||||
message: "This demo shows how to execute fetches and queries.\n\nEach menu item executes and displays a preconfigured fetch/query.",
|
||||
preferredStyle: .Alert
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
|
||||
super.prepareForSegue(segue, sender: sender)
|
||||
super.prepare(for: segue, sender: sender)
|
||||
|
||||
if let indexPath = sender as? NSIndexPath {
|
||||
if let indexPath = sender as? IndexPath {
|
||||
|
||||
switch segue.destinationViewController {
|
||||
switch segue.destination {
|
||||
|
||||
case let controller as FetchingResultsViewController:
|
||||
let item = self.fetchingItems[indexPath.row]
|
||||
controller.setTimeZones(item.fetch(), title: item.title)
|
||||
controller.set(timeZones: item.fetch(), title: item.title)
|
||||
|
||||
case let controller as QueryingResultsViewController:
|
||||
let item = self.queryingItems[indexPath.row]
|
||||
controller.setValue(item.query(), title: item.title)
|
||||
controller.set(value: item.query(), title: item.title)
|
||||
|
||||
default:
|
||||
break
|
||||
@@ -98,14 +96,14 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case Section.Fetching.rawValue?:
|
||||
case Section.fetching.rawValue?:
|
||||
return self.fetchingItems.count
|
||||
|
||||
case Section.Querying.rawValue?:
|
||||
case Section.querying.rawValue?:
|
||||
return self.queryingItems.count
|
||||
|
||||
default:
|
||||
@@ -113,16 +111,16 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case Section.Fetching.rawValue?:
|
||||
case Section.fetching.rawValue?:
|
||||
cell.textLabel?.text = self.fetchingItems[indexPath.row].title
|
||||
|
||||
case Section.Querying.rawValue?:
|
||||
case Section.querying.rawValue?:
|
||||
cell.textLabel?.text = self.queryingItems[indexPath.row].title
|
||||
|
||||
default:
|
||||
@@ -135,17 +133,17 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
||||
tableView.deselectRowAtIndexPath(indexPath, animated: true)
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case Section.Fetching.rawValue?:
|
||||
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath)
|
||||
case Section.fetching.rawValue?:
|
||||
self.performSegue(withIdentifier: "FetchingResultsViewController", sender: indexPath)
|
||||
|
||||
case Section.Querying.rawValue?:
|
||||
self.performSegueWithIdentifier("QueryingResultsViewController", sender: indexPath)
|
||||
case Section.querying.rawValue?:
|
||||
self.performSegue(withIdentifier: "QueryingResultsViewController", sender: indexPath)
|
||||
|
||||
default:
|
||||
break
|
||||
@@ -157,8 +155,8 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
|
||||
private enum Section: Int {
|
||||
|
||||
case Fetching
|
||||
case Querying
|
||||
case fetching
|
||||
case querying
|
||||
}
|
||||
|
||||
private let fetchingItems = [
|
||||
@@ -166,117 +164,145 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
title: "All Time Zones",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From(TimeZone),
|
||||
OrderBy(.Ascending("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] %@", "name", "Asia"),
|
||||
OrderBy(.Ascending("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] %@", "name", "America")
|
||||
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"),
|
||||
OrderBy(.Ascending("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] %@", "name", "America"),
|
||||
OrderBy(.Ascending("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("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: { () -> AnyObject in
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryValue(
|
||||
From(TimeZone),
|
||||
Select<NSNumber>(.Count("name"))
|
||||
return try! Static.timeZonesStack.queryValue(
|
||||
From<TimeZone>()
|
||||
.select(NSNumber.self, .count(\.name))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Abbreviation For Tokyo's Time Zone",
|
||||
query: { () -> AnyObject in
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryValue(
|
||||
From(TimeZone),
|
||||
Select<String>("abbreviation"),
|
||||
Where("%K ENDSWITH[c] %@", "name", "Tokyo")
|
||||
return try! Static.timeZonesStack.queryValue(
|
||||
From<TimeZone>()
|
||||
.select(String.self, .attribute(\.abbreviation))
|
||||
.where(format: "%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "All Abbreviations",
|
||||
query: { () -> AnyObject in
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From(TimeZone),
|
||||
Select<NSDictionary>("name", "abbreviation"),
|
||||
OrderBy(.Ascending("name"))
|
||||
)!
|
||||
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: { () -> AnyObject in
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From(TimeZone),
|
||||
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"),
|
||||
GroupBy("abbreviation"),
|
||||
OrderBy(.Ascending("secondsFromGMT"), .Ascending("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: { () -> AnyObject in
|
||||
query: { () -> Any in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From(TimeZone),
|
||||
Select<NSDictionary>(
|
||||
.Count("hasDaylightSavingTime", As: "numberOfCountries"),
|
||||
"hasDaylightSavingTime"
|
||||
),
|
||||
GroupBy("hasDaylightSavingTime"),
|
||||
OrderBy(.Descending("hasDaylightSavingTime"))
|
||||
)!
|
||||
return try! Static.timeZonesStack.queryAttributes(
|
||||
From<TimeZone>()
|
||||
.select(
|
||||
NSDictionary.self,
|
||||
.count(\.hasDaylightSavingTime, as: "numberOfCountries"),
|
||||
.attribute(\.hasDaylightSavingTime)
|
||||
)
|
||||
.groupBy(\.hasDaylightSavingTime)
|
||||
.orderBy(
|
||||
.descending(\.hasDaylightSavingTime),
|
||||
.ascending(\.name)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
@@ -286,7 +312,7 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
|
||||
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
|
||||
@IBOutlet dynamic weak var tableView: UITableView?
|
||||
|
||||
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
|
||||
@IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
|
||||
|
||||
self.tableView?.reloadData()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -14,7 +14,7 @@ class FetchingResultsViewController: UITableViewController {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
func setTimeZones(timeZones: [TimeZone]?, title: String) {
|
||||
func set(timeZones: [TimeZone]?, title: String) {
|
||||
|
||||
self.timeZones += timeZones ?? []
|
||||
self.sectionTitle = title
|
||||
@@ -30,20 +30,20 @@ class FetchingResultsViewController: UITableViewController {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.tableView.estimatedRowHeight = 60
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension
|
||||
self.tableView.rowHeight = UITableView.automaticDimension
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.timeZones.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
|
||||
|
||||
let timeZone = self.timeZones[indexPath.row]
|
||||
cell.textLabel?.text = timeZone.name
|
||||
@@ -55,7 +55,7 @@ class FetchingResultsViewController: UITableViewController {
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return self.sectionTitle
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -12,23 +12,23 @@ class QueryingResultsViewController: UITableViewController {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
func setValue(value: AnyObject?, title: String) {
|
||||
func set(value: Any?, title: String) {
|
||||
|
||||
switch value {
|
||||
|
||||
case (let array as [AnyObject])?:
|
||||
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
|
||||
case (let array as [Any])?:
|
||||
self.values = array.map { (item: Any) -> (title: String, detail: String) in
|
||||
(
|
||||
title: item.description,
|
||||
detail: String(reflecting: item.dynamicType)
|
||||
title: String(describing: item),
|
||||
detail: String(reflecting: type(of: item))
|
||||
)
|
||||
}
|
||||
|
||||
case let item?:
|
||||
self.values = [
|
||||
(
|
||||
title: item.description,
|
||||
detail: String(reflecting: item.dynamicType)
|
||||
title: String(describing: item),
|
||||
detail: String(reflecting: type(of: item))
|
||||
)
|
||||
]
|
||||
|
||||
@@ -49,20 +49,20 @@ class QueryingResultsViewController: UITableViewController {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.tableView.estimatedRowHeight = 60
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension
|
||||
self.tableView.rowHeight = UITableView.automaticDimension
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.values.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath)
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
|
||||
|
||||
let value = self.values[indexPath.row]
|
||||
|
||||
@@ -75,7 +75,7 @@ class QueryingResultsViewController: UITableViewController {
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return self.sectionTitle
|
||||
}
|
||||
|
||||
@@ -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,11 +17,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.1</string>
|
||||
<string>6.3.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>4</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
|
||||
@@ -3,64 +3,80 @@
|
||||
// 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
|
||||
import CoreStore
|
||||
|
||||
|
||||
private struct Static {
|
||||
struct ColorsDemo {
|
||||
|
||||
enum Filter: String {
|
||||
|
||||
case All = "All Colors"
|
||||
case Light = "Light Colors"
|
||||
case Dark = "Dark Colors"
|
||||
case all = "All Colors"
|
||||
case light = "Light Colors"
|
||||
case dark = "Dark Colors"
|
||||
|
||||
func next() -> Filter {
|
||||
|
||||
switch self {
|
||||
|
||||
case All: return .Light
|
||||
case Light: return .Dark
|
||||
case Dark: return .All
|
||||
case .all: return .light
|
||||
case .light: return .dark
|
||||
case .dark: return .all
|
||||
}
|
||||
}
|
||||
|
||||
func whereClause() -> Where {
|
||||
func whereClause() -> Where<Palette> {
|
||||
|
||||
switch self {
|
||||
|
||||
case .All: return Where(true)
|
||||
case .Light: return Where("brightness >= 0.9")
|
||||
case .Dark: return Where("brightness <= 0.4")
|
||||
case .all: return .init()
|
||||
case .light: return (\Palette.brightness >= 0.9)
|
||||
case .dark: return (\Palette.brightness <= 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static var filter = Filter.All {
|
||||
static var filter = Filter.all {
|
||||
|
||||
didSet {
|
||||
|
||||
self.palettes.refetch(self.filter.whereClause())
|
||||
self.palettes.refetch(
|
||||
self.filter.whereClause(),
|
||||
OrderBy<Palette>(.ascending(\.hue))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static let palettes: ListMonitor<Palette> = {
|
||||
|
||||
try! CoreStore.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "ColorsDemo.sqlite",
|
||||
configuration: "ObservingDemo",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
static let stack: DataStack = {
|
||||
|
||||
return DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "ColorsDemo",
|
||||
entities: [
|
||||
Entity<Palette>("Palette"),
|
||||
],
|
||||
versionLock: [
|
||||
"Palette": [0x8c25aa53c7c90a28, 0xa243a34d25f1a3a7, 0x56565b6935b6055a, 0x4f988bb257bf274f]
|
||||
]
|
||||
)
|
||||
)
|
||||
}()
|
||||
|
||||
static let palettes: ListMonitor<Palette> = {
|
||||
|
||||
return CoreStore.monitorSectionedList(
|
||||
From(Palette),
|
||||
SectionBy("colorName"),
|
||||
OrderBy(.Ascending("hue"))
|
||||
try! ColorsDemo.stack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "ColorsDemo.sqlite",
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
return ColorsDemo.stack.monitorSectionedList(
|
||||
From<Palette>()
|
||||
.sectionBy(\.colorName)
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
}()
|
||||
}
|
||||
@@ -74,7 +90,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
deinit {
|
||||
|
||||
Static.palettes.removeObserver(self)
|
||||
ColorsDemo.palettes.removeObserver(self)
|
||||
}
|
||||
|
||||
|
||||
@@ -86,40 +102,45 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
let navigationItem = self.navigationItem
|
||||
navigationItem.leftBarButtonItems = [
|
||||
self.editButtonItem(),
|
||||
self.editButtonItem,
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .Trash,
|
||||
barButtonSystemItem: .trash,
|
||||
target: self,
|
||||
action: #selector(self.resetBarButtonItemTouched(_:))
|
||||
)
|
||||
]
|
||||
|
||||
let filterBarButton = UIBarButtonItem(
|
||||
title: Static.filter.rawValue,
|
||||
style: .Plain,
|
||||
title: ColorsDemo.filter.rawValue,
|
||||
style: .plain,
|
||||
target: self,
|
||||
action: #selector(self.filterBarButtonItemTouched(_:))
|
||||
)
|
||||
navigationItem.rightBarButtonItems = [
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .Add,
|
||||
barButtonSystemItem: .add,
|
||||
target: self,
|
||||
action: #selector(self.addBarButtonItemTouched(_:))
|
||||
),
|
||||
UIBarButtonItem(
|
||||
barButtonSystemItem: .refresh,
|
||||
target: self,
|
||||
action: #selector(self.shuffleBarButtonItemTouched(_:))
|
||||
),
|
||||
filterBarButton
|
||||
]
|
||||
self.filterBarButton = filterBarButton
|
||||
|
||||
Static.palettes.addObserver(self)
|
||||
ColorsDemo.palettes.addObserver(self)
|
||||
|
||||
self.setTableEnabled(!Static.palettes.isPendingRefetch)
|
||||
self.setTable(enabled: !ColorsDemo.palettes.isPendingRefetch)
|
||||
}
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
|
||||
super.prepareForSegue(segue, sender: sender)
|
||||
super.prepare(for: segue, sender: sender)
|
||||
|
||||
switch (segue.identifier, segue.destinationViewController, sender) {
|
||||
switch (segue.identifier, segue.destination, sender) {
|
||||
|
||||
case ("ObjectObserverDemoViewController"?, let destinationViewController as ObjectObserverDemoViewController, let palette as Palette):
|
||||
destinationViewController.palette = palette
|
||||
@@ -132,21 +153,21 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
|
||||
return Static.palettes.numberOfSections()
|
||||
return ColorsDemo.palettes.numberOfSections()
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return Static.palettes.numberOfObjectsInSection(section)
|
||||
return ColorsDemo.palettes.numberOfObjects(in: section)
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("PaletteTableViewCell") as! PaletteTableViewCell
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "PaletteTableViewCell") as! PaletteTableViewCell
|
||||
|
||||
let palette = Static.palettes[indexPath]
|
||||
let palette = ColorsDemo.palettes[indexPath]
|
||||
cell.colorView?.backgroundColor = palette.color
|
||||
cell.label?.text = palette.colorText
|
||||
|
||||
@@ -156,103 +177,105 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
||||
tableView.deselectRowAtIndexPath(indexPath, animated: true)
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
self.performSegueWithIdentifier(
|
||||
"ObjectObserverDemoViewController",
|
||||
sender: Static.palettes[indexPath]
|
||||
self.performSegue(
|
||||
withIdentifier: "ObjectObserverDemoViewController",
|
||||
sender: ColorsDemo.palettes[indexPath]
|
||||
)
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
|
||||
switch editingStyle {
|
||||
|
||||
case .Delete:
|
||||
let palette = Static.palettes[indexPath]
|
||||
CoreStore.beginAsynchronous{ (transaction) -> Void in
|
||||
|
||||
transaction.delete(palette)
|
||||
transaction.commit { (result) -> Void in }
|
||||
}
|
||||
case .delete:
|
||||
let palette = ColorsDemo.palettes[indexPath]
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
transaction.delete(palette)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return Static.palettes.sectionInfoAtIndex(section).name
|
||||
return ColorsDemo.palettes.sectionInfo(at: section).name
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
func listMonitorWillChange(monitor: ListMonitor<Palette>) {
|
||||
func listMonitorWillChange(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.tableView.beginUpdates()
|
||||
}
|
||||
|
||||
func listMonitorDidChange(monitor: ListMonitor<Palette>) {
|
||||
func listMonitorDidChange(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.tableView.endUpdates()
|
||||
}
|
||||
|
||||
func listMonitorWillRefetch(monitor: ListMonitor<Palette>) {
|
||||
func listMonitorWillRefetch(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.setTableEnabled(false)
|
||||
self.setTable(enabled: false)
|
||||
}
|
||||
|
||||
func listMonitorDidRefetch(monitor: ListMonitor<Palette>) {
|
||||
func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
|
||||
|
||||
self.filterBarButton?.title = Static.filter.rawValue
|
||||
self.filterBarButton?.title = ColorsDemo.filter.rawValue
|
||||
self.tableView.reloadData()
|
||||
self.setTableEnabled(true)
|
||||
self.setTable(enabled: true)
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListObjectObserver
|
||||
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertObject object: Palette, toIndexPath indexPath: IndexPath) {
|
||||
|
||||
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
|
||||
self.tableView.insertRows(at: [indexPath], with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteObject object: Palette, fromIndexPath indexPath: IndexPath) {
|
||||
|
||||
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
|
||||
self.tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didUpdateObject object: Palette, atIndexPath indexPath: IndexPath) {
|
||||
|
||||
if let cell = self.tableView.cellForRowAtIndexPath(indexPath) as? PaletteTableViewCell {
|
||||
if let cell = self.tableView.cellForRow(at: indexPath) as? PaletteTableViewCell {
|
||||
|
||||
let palette = Static.palettes[indexPath]
|
||||
let palette = ColorsDemo.palettes[indexPath]
|
||||
cell.colorView?.backgroundColor = palette.color
|
||||
cell.label?.text = palette.colorText
|
||||
}
|
||||
}
|
||||
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didMoveObject object: Palette, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
|
||||
|
||||
self.tableView.deleteRowsAtIndexPaths([fromIndexPath], withRowAnimation: .Automatic)
|
||||
self.tableView.insertRowsAtIndexPaths([toIndexPath], withRowAnimation: .Automatic)
|
||||
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
|
||||
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListSectionObserver
|
||||
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
|
||||
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic)
|
||||
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
}
|
||||
|
||||
|
||||
@@ -260,43 +283,65 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
|
||||
|
||||
private var filterBarButton: UIBarButtonItem?
|
||||
|
||||
@IBAction private dynamic func resetBarButtonItemTouched(sender: AnyObject?) {
|
||||
@IBAction private dynamic func resetBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From(Palette))
|
||||
transaction.commit()
|
||||
}
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
try transaction.deleteAll(From<Palette>())
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction private dynamic func filterBarButtonItemTouched(sender: AnyObject?) {
|
||||
@IBAction private dynamic func filterBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
Static.filter = Static.filter.next()
|
||||
ColorsDemo.filter = ColorsDemo.filter.next()
|
||||
}
|
||||
|
||||
@IBAction private dynamic func addBarButtonItemTouched(sender: AnyObject?) {
|
||||
@IBAction private dynamic func addBarButtonItemTouched(_ sender: AnyObject?) {
|
||||
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
let palette = transaction.create(Into(Palette))
|
||||
palette.setInitialValues()
|
||||
|
||||
transaction.commit()
|
||||
}
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let palette = transaction.create(Into<Palette>())
|
||||
palette.setInitialValues(in: transaction)
|
||||
},
|
||||
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 setTableEnabled(enabled: Bool) {
|
||||
|
||||
UIView.animateWithDuration(
|
||||
0.2,
|
||||
private func setTable(enabled: Bool) {
|
||||
|
||||
tableView.isUserInteractionEnabled = enabled
|
||||
UIView.animate(
|
||||
withDuration: 0.2,
|
||||
delay: 0,
|
||||
options: .BeginFromCurrentState,
|
||||
options: .beginFromCurrentState,
|
||||
animations: { () -> Void in
|
||||
|
||||
if let tableView = self.tableView {
|
||||
|
||||
tableView.alpha = enabled ? 1.0 : 0.5
|
||||
tableView.userInteractionEnabled = enabled
|
||||
}
|
||||
},
|
||||
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
|
||||
@@ -29,7 +29,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
if let palette = newValue {
|
||||
|
||||
self.monitor = CoreStore.monitorObject(palette)
|
||||
self.monitor = ColorsDemo.stack.monitorObject(palette)
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -50,22 +50,22 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
|
||||
if let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue"))) {
|
||||
if let palette = try! ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue))) {
|
||||
|
||||
self.monitor = CoreStore.monitorObject(palette)
|
||||
self.monitor = ColorsDemo.stack.monitorObject(palette)
|
||||
}
|
||||
else {
|
||||
|
||||
CoreStore.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
let palette = transaction.create(Into(Palette))
|
||||
palette.setInitialValues()
|
||||
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
_ = try? ColorsDemo.stack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
let palette = transaction.create(Into<Palette>())
|
||||
palette.setInitialValues(in: transaction)
|
||||
}
|
||||
)
|
||||
|
||||
let palette = CoreStore.fetchOne(From(Palette), OrderBy(.Ascending("hue")))!
|
||||
self.monitor = CoreStore.monitorObject(palette)
|
||||
let palette = try! ColorsDemo.stack.fetchOne(From<Palette>().orderBy(.ascending(\.hue)))!
|
||||
self.monitor = ColorsDemo.stack.monitorObject(palette)
|
||||
}
|
||||
|
||||
super.init(coder: aDecoder)
|
||||
@@ -85,24 +85,24 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
// MARK: ObjectObserver
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPathString>) {
|
||||
|
||||
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
|
||||
}
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didDeleteObject object: Palette) {
|
||||
|
||||
self.navigationItem.rightBarButtonItem?.enabled = false
|
||||
self.navigationItem.rightBarButtonItem?.isEnabled = false
|
||||
|
||||
self.colorNameLabel?.alpha = 0.3
|
||||
self.colorView?.alpha = 0.3
|
||||
|
||||
self.hsbLabel?.text = "Deleted"
|
||||
self.hsbLabel?.textColor = UIColor.redColor()
|
||||
self.hsbLabel?.textColor = UIColor.red
|
||||
|
||||
self.hueSlider?.enabled = false
|
||||
self.saturationSlider?.enabled = false
|
||||
self.brightnessSlider?.enabled = false
|
||||
self.hueSlider?.isEnabled = false
|
||||
self.saturationSlider?.isEnabled = false
|
||||
self.brightnessSlider?.isEnabled = false
|
||||
}
|
||||
|
||||
|
||||
@@ -118,57 +118,65 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
@IBOutlet weak var saturationSlider: UISlider?
|
||||
@IBOutlet weak var brightnessSlider: UISlider?
|
||||
|
||||
@IBAction dynamic func hueSliderValueDidChange(sender: AnyObject?) {
|
||||
@IBAction dynamic func hueSliderValueDidChange(_ sender: AnyObject?) {
|
||||
|
||||
let hue = self.hueSlider?.value ?? 0
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { [weak self] (transaction) in
|
||||
|
||||
palette.hue = Int32(hue)
|
||||
transaction.commit()
|
||||
}
|
||||
}
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
|
||||
palette.hue .= Int(hue)
|
||||
}
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction dynamic func saturationSliderValueDidChange(sender: AnyObject?) {
|
||||
@IBAction dynamic func saturationSliderValueDidChange(_ sender: AnyObject?) {
|
||||
|
||||
let saturation = self.saturationSlider?.value ?? 0
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { [weak self] (transaction) in
|
||||
|
||||
palette.saturation = saturation
|
||||
transaction.commit()
|
||||
}
|
||||
}
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
|
||||
palette.saturation .= saturation
|
||||
}
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction dynamic func brightnessSliderValueDidChange(sender: AnyObject?) {
|
||||
@IBAction dynamic func brightnessSliderValueDidChange(_ sender: AnyObject?) {
|
||||
|
||||
let brightness = self.brightnessSlider?.value ?? 0
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { [weak self] (transaction) in
|
||||
|
||||
palette.brightness = brightness
|
||||
transaction.commit()
|
||||
}
|
||||
}
|
||||
if let palette = transaction.edit(self?.monitor?.object) {
|
||||
|
||||
palette.brightness .= brightness
|
||||
}
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction dynamic func deleteBarButtonTapped(sender: AnyObject?) {
|
||||
@IBAction dynamic func deleteBarButtonTapped(_ sender: AnyObject?) {
|
||||
|
||||
CoreStore.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
transaction.delete(self?.monitor?.object)
|
||||
transaction.commit()
|
||||
}
|
||||
ColorsDemo.stack.perform(
|
||||
asynchronous: { [weak self] (transaction) in
|
||||
|
||||
transaction.delete(self?.monitor?.object)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
func reloadPaletteInfo(palette: Palette, changedKeys: Set<String>?) {
|
||||
func reloadPaletteInfo(_ palette: Palette, changedKeys: Set<String>?) {
|
||||
|
||||
self.colorNameLabel?.text = palette.colorName
|
||||
self.colorNameLabel?.text = palette.colorName.value
|
||||
|
||||
let color = palette.color
|
||||
self.colorNameLabel?.textColor = color
|
||||
@@ -176,17 +184,17 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
|
||||
|
||||
self.hsbLabel?.text = palette.colorText
|
||||
|
||||
if changedKeys == nil || changedKeys?.contains("hue") == true {
|
||||
if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.hue)) == true {
|
||||
|
||||
self.hueSlider?.value = Float(palette.hue)
|
||||
self.hueSlider?.value = Float(palette.hue.value)
|
||||
}
|
||||
if changedKeys == nil || changedKeys?.contains("saturation") == true {
|
||||
if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.saturation)) == true {
|
||||
|
||||
self.saturationSlider?.value = palette.saturation
|
||||
self.saturationSlider?.value = palette.saturation.value
|
||||
}
|
||||
if changedKeys == nil || changedKeys?.contains("brightness") == true {
|
||||
if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.brightness)) == true {
|
||||
|
||||
self.brightnessSlider?.value = palette.brightness
|
||||
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
|
||||
@@ -15,16 +15,16 @@ class ObserversViewController: UIViewController {
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Observers Demo",
|
||||
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ListMonitor\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ObjectMonitor\".",
|
||||
preferredStyle: .Alert
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -14,64 +14,70 @@ import CoreStore
|
||||
|
||||
// MARK: - Palette
|
||||
|
||||
class Palette: NSManagedObject {
|
||||
|
||||
@NSManaged var hue: Int32
|
||||
@NSManaged var saturation: Float
|
||||
@NSManaged var brightness: Float
|
||||
final class Palette: CoreStoreObject {
|
||||
|
||||
@objc dynamic var colorName: String {
|
||||
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.getColorName
|
||||
)
|
||||
|
||||
static func randomHue() -> Int {
|
||||
|
||||
return Int(arc4random_uniform(360))
|
||||
}
|
||||
|
||||
private static func getColorName(_ partialObject: PartialObject<Palette>) -> String? {
|
||||
|
||||
get {
|
||||
if let colorName = partialObject.primitiveValue(for: { $0.colorName }) {
|
||||
|
||||
let KVCKey = "colorName"
|
||||
if let colorName = self.accessValueForKVCKey(KVCKey) as? String {
|
||||
|
||||
return colorName
|
||||
}
|
||||
|
||||
let colorName: String
|
||||
switch self.hue % 360 {
|
||||
|
||||
case 0 ..< 20: colorName = "Lower Reds"
|
||||
case 20 ..< 57: colorName = "Oranges and Browns"
|
||||
case 57 ..< 90: colorName = "Yellow-Greens"
|
||||
case 90 ..< 159: colorName = "Greens"
|
||||
case 159 ..< 197: colorName = "Blue-Greens"
|
||||
case 197 ..< 241: colorName = "Blues"
|
||||
case 241 ..< 297: colorName = "Violets"
|
||||
case 297 ..< 331: colorName = "Magentas"
|
||||
default: colorName = "Upper Reds"
|
||||
}
|
||||
|
||||
self.setPrimitiveValue(colorName, forKey: KVCKey)
|
||||
return colorName
|
||||
}
|
||||
set {
|
||||
|
||||
let colorName: String
|
||||
switch partialObject.value(for: { $0.hue }) % 360 {
|
||||
|
||||
self.setValue(newValue, forKVCKey: "colorName")
|
||||
case 0 ..< 20: colorName = "Lower Reds"
|
||||
case 20 ..< 57: colorName = "Oranges and Browns"
|
||||
case 57 ..< 90: colorName = "Yellow-Greens"
|
||||
case 90 ..< 159: colorName = "Greens"
|
||||
case 159 ..< 197: colorName = "Blue-Greens"
|
||||
case 197 ..< 241: colorName = "Blues"
|
||||
case 241 ..< 297: colorName = "Violets"
|
||||
case 297 ..< 331: colorName = "Magentas"
|
||||
default: colorName = "Upper Reds"
|
||||
}
|
||||
|
||||
partialObject.setPrimitiveValue(colorName, for: { $0.colorName })
|
||||
return colorName
|
||||
}
|
||||
}
|
||||
|
||||
extension Palette {
|
||||
|
||||
var color: UIColor {
|
||||
|
||||
return UIColor(
|
||||
hue: CGFloat(self.hue) / 360.0,
|
||||
saturation: CGFloat(self.saturation),
|
||||
brightness: CGFloat(self.brightness),
|
||||
hue: CGFloat(self.hue.value) / 360.0,
|
||||
saturation: CGFloat(self.saturation.value),
|
||||
brightness: CGFloat(self.brightness.value),
|
||||
alpha: 1.0
|
||||
)
|
||||
}
|
||||
|
||||
var colorText: String {
|
||||
|
||||
return "H: \(self.hue)˚, S: \(round(self.saturation * 100.0))%, B: \(round(self.brightness * 100.0))%"
|
||||
return "H: \(self.hue.value)˚, S: \(round(self.saturation.value * 100.0))%, B: \(round(self.brightness.value * 100.0))%"
|
||||
}
|
||||
|
||||
func setInitialValues() {
|
||||
func setInitialValues(in transaction: BaseDataTransaction) {
|
||||
|
||||
self.hue = Int32(arc4random_uniform(360))
|
||||
self.saturation = 1.0
|
||||
self.brightness = Float(arc4random_uniform(70) + 30) / 100.0
|
||||
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,12 +3,11 @@
|
||||
// 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
|
||||
import CoreStore
|
||||
import GCDKit
|
||||
|
||||
|
||||
// MARK: - CustomLoggerViewController
|
||||
@@ -17,11 +16,6 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
deinit {
|
||||
|
||||
CoreStore.logger = DefaultLogger()
|
||||
}
|
||||
|
||||
let dataStack = DataStack()
|
||||
|
||||
// MARK: UIViewController
|
||||
@@ -31,50 +25,58 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
super.viewDidLoad()
|
||||
|
||||
try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite"))
|
||||
CoreStore.logger = self
|
||||
}
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
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.",
|
||||
preferredStyle: .Alert
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
CoreStore.logger = DefaultLogger()
|
||||
}
|
||||
|
||||
|
||||
// MARK: CoreStoreLogger
|
||||
|
||||
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
GCDQueue.Main.async { [weak self] in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
let levelString: String
|
||||
switch level {
|
||||
|
||||
case .Trace: levelString = "Trace"
|
||||
case .Notice: levelString = "Notice"
|
||||
case .Warning: levelString = "Warning"
|
||||
case .Fatal: levelString = "Fatal"
|
||||
case .trace: levelString = "Trace"
|
||||
case .notice: levelString = "Notice"
|
||||
case .warning: levelString = "Warning"
|
||||
case .fatal: levelString = "Fatal"
|
||||
}
|
||||
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
|
||||
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
GCDQueue.Main.async { [weak self] in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
|
||||
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Error] \(message): \(error)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
if condition() {
|
||||
|
||||
@@ -82,9 +84,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
}
|
||||
|
||||
let messageString = message()
|
||||
GCDQueue.Main.async { [weak self] in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
||||
self?.textView?.insertText("\((fileName.stringValue as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
|
||||
self?.textView?.insertText("\((String(describing: fileName) as NSString).lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Assert] \(messageString)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,15 +96,14 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
@IBOutlet dynamic weak var textView: UITextView?
|
||||
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
|
||||
|
||||
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
|
||||
@IBAction dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case 0?:
|
||||
self.dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.create(Into(Palette))
|
||||
}
|
||||
let request = NSFetchRequest<NSFetchRequestResult>()
|
||||
Where<NSManagedObject>(true).applyToFetchRequest(request)
|
||||
Where<NSManagedObject>(false).applyToFetchRequest(request)
|
||||
|
||||
case 1?:
|
||||
_ = try? dataStack.addStorageAndWait(
|
||||
@@ -113,10 +114,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
)
|
||||
|
||||
case 2?:
|
||||
self.dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
|
||||
transaction.commit()
|
||||
transaction.commit()
|
||||
_ = 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
|
||||
@@ -12,7 +12,7 @@ import CoreStore
|
||||
|
||||
// MARK: - MigrationsDemoViewController
|
||||
|
||||
class MigrationsDemoViewController: UIViewController {
|
||||
class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
@@ -22,31 +22,31 @@ class MigrationsDemoViewController: UIViewController {
|
||||
|
||||
if let segmentedControl = self.segmentedControl {
|
||||
|
||||
for (index, model) in self.models.enumerate() {
|
||||
for (index, model) in self.models.enumerated() {
|
||||
|
||||
segmentedControl.setTitle(
|
||||
model.label,
|
||||
forSegmentAtIndex: index
|
||||
forSegmentAt: index
|
||||
)
|
||||
}
|
||||
}
|
||||
self.setDataStack(nil, model: nil, scrollToSelection: false)
|
||||
self.set(dataStack: nil, model: nil, scrollToSelection: false)
|
||||
}
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Migrations Demo",
|
||||
message: "This demo shows how to run progressive migrations and how to support multiple model versions in a single project.\n\nThe persistent store contains 10000 organisms, which gain/lose properties when the migration evolves/devolves them.\n\nYou can use the \"mutate\" button to change an organism's properties then migrate to a different model to see how its value gets affected.",
|
||||
preferredStyle: .Alert
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
|
||||
|
||||
let modelMetadata = withExtendedLifetime(DataStack(modelName: "MigrationDemo")) {
|
||||
let modelMetadata = withExtendedLifetime(DataStack(xcodeModelName: "MigrationDemo")) {
|
||||
(dataStack: DataStack) -> ModelMetadata in
|
||||
|
||||
let models = self.models
|
||||
@@ -60,7 +60,7 @@ class MigrationsDemoViewController: UIViewController {
|
||||
}
|
||||
for model in models {
|
||||
|
||||
if model.version == storeVersion {
|
||||
if model.schemaHistory.currentModelVersion == storeVersion {
|
||||
|
||||
return model
|
||||
}
|
||||
@@ -72,32 +72,121 @@ class MigrationsDemoViewController: UIViewController {
|
||||
self.selectModelVersion(modelMetadata)
|
||||
}
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
func listMonitorWillChange(_ monitor: ListMonitor<NSManagedObject>) { }
|
||||
|
||||
func listMonitorDidChange(_ monitor: ListMonitor<NSManagedObject>) {
|
||||
|
||||
if self.lastSelectedIndexPath == nil,
|
||||
let numberOfObjectsInSection = self.listMonitor?.numberOfObjects(in: 0),
|
||||
numberOfObjectsInSection > 0 {
|
||||
|
||||
self.tableView?.reloadData()
|
||||
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: false)
|
||||
}
|
||||
else {
|
||||
|
||||
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
func listMonitorDidRefetch(_ monitor: ListMonitor<NSManagedObject>) {
|
||||
|
||||
self.listMonitorDidChange(monitor)
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.listMonitor?.numberOfObjects(in: 0) ?? 0
|
||||
}
|
||||
|
||||
@objc dynamic func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "OrganismTableViewCell", for: indexPath) as! OrganismTableViewCell
|
||||
|
||||
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
|
||||
cell.dnaLabel?.text = "DNA: \(dna)"
|
||||
cell.mutateButtonHandler = { [weak self] () -> Void in
|
||||
|
||||
guard let `self` = self,
|
||||
let dataStack = self.dataStack,
|
||||
let organism = self.listMonitor?[indexPath] else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||
self.setEnabled(false)
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let organism = transaction.edit(organism) as! OrganismProtocol
|
||||
organism.mutate()
|
||||
},
|
||||
completion: { [weak self] _ in
|
||||
|
||||
self?.setEnabled(true)
|
||||
}
|
||||
)
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
@objc dynamic func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private typealias ModelMetadata = (label: String, version: String, entityType: AnyClass, migrationChain: MigrationChain)
|
||||
private typealias ModelMetadata = (label: String, entityType: NSManagedObject.Type, schemaHistory: SchemaHistory)
|
||||
|
||||
private let models: [ModelMetadata] = [
|
||||
(
|
||||
label: "Model V1",
|
||||
version: "MigrationDemo",
|
||||
entityType: OrganismV1.self,
|
||||
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
|
||||
schemaHistory: SchemaHistory(
|
||||
XcodeDataModelSchema.from(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
|
||||
),
|
||||
migrationChain: ["MigrationDemoV3", "MigrationDemoV2", "MigrationDemo"]
|
||||
)
|
||||
),
|
||||
(
|
||||
label: "Model V2",
|
||||
version: "MigrationDemoV2",
|
||||
entityType: OrganismV2.self,
|
||||
migrationChain: [
|
||||
"MigrationDemo": "MigrationDemoV2",
|
||||
"MigrationDemoV3": "MigrationDemoV2"
|
||||
]
|
||||
schemaHistory: SchemaHistory(
|
||||
XcodeDataModelSchema.from(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: [
|
||||
"MigrationDemo": "MigrationDemoV2",
|
||||
"MigrationDemoV3": "MigrationDemoV2"
|
||||
]
|
||||
),
|
||||
migrationChain: [
|
||||
"MigrationDemo": "MigrationDemoV2",
|
||||
"MigrationDemoV3": "MigrationDemoV2"
|
||||
]
|
||||
)
|
||||
),
|
||||
(
|
||||
label: "Model V3",
|
||||
version: "MigrationDemoV3",
|
||||
entityType: OrganismV3.self,
|
||||
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
|
||||
schemaHistory: SchemaHistory(
|
||||
XcodeDataModelSchema.from(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
|
||||
),
|
||||
migrationChain: ["MigrationDemo", "MigrationDemoV2", "MigrationDemoV3"]
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
@@ -113,13 +202,13 @@ class MigrationsDemoViewController: UIViewController {
|
||||
return self._dataStack
|
||||
}
|
||||
|
||||
private var _lastSelectedIndexPath: NSIndexPath?
|
||||
private var lastSelectedIndexPath: NSIndexPath? {
|
||||
private var _lastSelectedIndexPath: IndexPath?
|
||||
private var lastSelectedIndexPath: IndexPath? {
|
||||
|
||||
return self._lastSelectedIndexPath
|
||||
}
|
||||
|
||||
private func setSelectedIndexPath(indexPath: NSIndexPath, scrollToSelection: Bool) {
|
||||
private func setSelectedIndexPath(_ indexPath: IndexPath, scrollToSelection: Bool) {
|
||||
|
||||
self._lastSelectedIndexPath = indexPath
|
||||
self.updateDisplay(reloadData: false, scrollToSelection: scrollToSelection, animated: true)
|
||||
@@ -132,7 +221,7 @@ class MigrationsDemoViewController: UIViewController {
|
||||
@IBOutlet private dynamic weak var progressView: UIProgressView?
|
||||
@IBOutlet private dynamic weak var tableView: UITableView?
|
||||
|
||||
@IBAction private dynamic func segmentedControlValueChanged(sender: AnyObject?) {
|
||||
@IBAction private dynamic func segmentedControlValueChanged(_ sender: AnyObject?) {
|
||||
|
||||
guard let index = self.segmentedControl?.selectedSegmentIndex else {
|
||||
|
||||
@@ -142,23 +231,46 @@ class MigrationsDemoViewController: UIViewController {
|
||||
self.selectModelVersion(self.models[index])
|
||||
}
|
||||
|
||||
private func selectModelVersion(model: ModelMetadata) {
|
||||
private func selectModelVersion(_ model: ModelMetadata) {
|
||||
|
||||
if self.dataStack?.modelVersion == model.version {
|
||||
if self.dataStack?.modelVersion == model.schemaHistory.currentModelVersion {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.setDataStack(nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
|
||||
self.set(dataStack: nil, model: nil, scrollToSelection: false) // explicitly trigger NSPersistentStore cleanup by deallocating the stack
|
||||
|
||||
let dataStack = DataStack(
|
||||
modelName: "MigrationDemo",
|
||||
migrationChain: model.migrationChain
|
||||
)
|
||||
let dataStack = DataStack(schemaHistory: model.schemaHistory)
|
||||
|
||||
self.setEnabled(false)
|
||||
let progress = dataStack.addStorage(
|
||||
SQLiteStore(fileName: "MigrationDemo.sqlite"),
|
||||
SQLiteStore(
|
||||
fileName: "MigrationDemo.sqlite",
|
||||
migrationMappingProviders: [
|
||||
CustomSchemaMappingProvider(
|
||||
from: "MigrationDemoV3",
|
||||
to: "MigrationDemoV2",
|
||||
entityMappings: [
|
||||
.transformEntity(
|
||||
sourceEntity: "Organism",
|
||||
destinationEntity: "Organism",
|
||||
transformer: { (source, createDestination) in
|
||||
|
||||
let destination = createDestination()
|
||||
destination.enumerateAttributes { (attribute, sourceAttribute) in
|
||||
|
||||
if let sourceAttribute = sourceAttribute {
|
||||
|
||||
destination[attribute] = source[sourceAttribute]
|
||||
}
|
||||
}
|
||||
destination["numberOfFlippers"] = source["numberOfLimbs"]
|
||||
}
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
),
|
||||
completion: { [weak self] (result) -> Void in
|
||||
|
||||
guard let `self` = self else {
|
||||
@@ -166,18 +278,17 @@ class MigrationsDemoViewController: UIViewController {
|
||||
return
|
||||
}
|
||||
|
||||
guard case .Success = result else {
|
||||
guard case .success = result else {
|
||||
|
||||
self.setEnabled(true)
|
||||
return
|
||||
}
|
||||
|
||||
self.setDataStack(dataStack, model: model, scrollToSelection: true)
|
||||
self.set(dataStack: dataStack, model: model, scrollToSelection: true)
|
||||
|
||||
let count = dataStack.queryValue(
|
||||
From(model.entityType),
|
||||
Select<Int>(.Count("dna"))
|
||||
)
|
||||
let count = try! dataStack.queryValue(
|
||||
From<NSManagedObject>(model.entityType)
|
||||
.select(Int.self, .count(#keyPath(OrganismV1.dna))))!
|
||||
if count > 0 {
|
||||
|
||||
self.setEnabled(true)
|
||||
@@ -186,25 +297,26 @@ class MigrationsDemoViewController: UIViewController {
|
||||
|
||||
for i: Int64 in 0 ..< 20 {
|
||||
|
||||
dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
for j: Int64 in 0 ..< 500 {
|
||||
dataStack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let organism = transaction.create(Into(model.entityType)) as! OrganismProtocol
|
||||
organism.dna = (i * 500) + j + 1
|
||||
organism.mutate()
|
||||
}
|
||||
|
||||
transaction.commit()
|
||||
}
|
||||
for j: Int64 in 0 ..< 500 {
|
||||
|
||||
let organism = transaction.create(Into(model.entityType)) as! OrganismProtocol
|
||||
organism.dna = (i * 500) + j + 1
|
||||
organism.mutate()
|
||||
}
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
transaction.commit { _ in
|
||||
|
||||
dataStack.perform(
|
||||
asynchronous: { _ in },
|
||||
completion: { [weak self] _ in
|
||||
|
||||
self?.setEnabled(true)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -218,53 +330,63 @@ class MigrationsDemoViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func setEnabled(enabled: Bool) {
|
||||
private func setEnabled(_ enabled: Bool) {
|
||||
|
||||
UIView.animateWithDuration(
|
||||
0.2,
|
||||
UIView.animate(
|
||||
withDuration: 0.2,
|
||||
delay: 0,
|
||||
options: .BeginFromCurrentState,
|
||||
options: .beginFromCurrentState,
|
||||
animations: { () -> Void in
|
||||
|
||||
let navigationItem = self.navigationItem
|
||||
navigationItem.leftBarButtonItem?.enabled = enabled
|
||||
navigationItem.rightBarButtonItem?.enabled = enabled
|
||||
navigationItem.leftBarButtonItem?.isEnabled = enabled
|
||||
navigationItem.rightBarButtonItem?.isEnabled = enabled
|
||||
navigationItem.hidesBackButton = !enabled
|
||||
|
||||
self.segmentedControl?.enabled = enabled
|
||||
self.segmentedControl?.isEnabled = enabled
|
||||
|
||||
if let tableView = self.tableView {
|
||||
|
||||
tableView.alpha = enabled ? 1.0 : 0.5
|
||||
tableView.userInteractionEnabled = enabled
|
||||
tableView.isUserInteractionEnabled = enabled
|
||||
}
|
||||
},
|
||||
completion: nil
|
||||
)
|
||||
}
|
||||
|
||||
private func setDataStack(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
|
||||
private func set(dataStack: DataStack?, model: ModelMetadata?, scrollToSelection: Bool) {
|
||||
|
||||
if let dataStack = dataStack, let model = model {
|
||||
|
||||
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.indexOf(model.version)!
|
||||
self.segmentedControl?.selectedSegmentIndex = self.models
|
||||
.firstIndex(
|
||||
where: { (arg) -> Bool in
|
||||
|
||||
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(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: true)
|
||||
self.setSelectedIndexPath(IndexPath(row: 0, section: 0), scrollToSelection: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
self.segmentedControl?.selectedSegmentIndex = UISegmentedControlNoSegment
|
||||
self.segmentedControl?.selectedSegmentIndex = UISegmentedControl.noSegment
|
||||
self._listMonitor = nil
|
||||
self._dataStack = nil
|
||||
}
|
||||
@@ -272,14 +394,14 @@ class MigrationsDemoViewController: UIViewController {
|
||||
self.updateDisplay(reloadData: true, scrollToSelection: scrollToSelection, animated: false)
|
||||
}
|
||||
|
||||
private func reloadTableHeaderWithProgress(progress: NSProgress) {
|
||||
private func reloadTableHeaderWithProgress(_ progress: Progress) {
|
||||
|
||||
self.progressView?.setProgress(Float(progress.fractionCompleted), animated: true)
|
||||
self.titleLabel?.text = "Migrating: \(progress.localizedDescription)"
|
||||
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription)"
|
||||
self.titleLabel?.text = "Migrating: \(progress.localizedDescription ?? "")"
|
||||
self.organismLabel?.text = "Progressive step \(progress.localizedAdditionalDescription ?? "")"
|
||||
}
|
||||
|
||||
private func updateDisplay(reloadData reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
|
||||
private func updateDisplay(reloadData: Bool, scrollToSelection: Bool, animated: Bool) {
|
||||
|
||||
var lines = [String]()
|
||||
var organismType = ""
|
||||
@@ -287,14 +409,14 @@ class MigrationsDemoViewController: UIViewController {
|
||||
|
||||
for property in organism.entity.properties {
|
||||
|
||||
let value: AnyObject = organism.valueForKey(property.name) ?? NSNull()
|
||||
let value = organism.value(forKey: property.name) ?? NSNull()
|
||||
lines.append("\(property.name): \(value)")
|
||||
}
|
||||
organismType = organism.entity.managedObjectClassName
|
||||
}
|
||||
|
||||
self.titleLabel?.text = organismType
|
||||
self.organismLabel?.text = lines.joinWithSeparator("\n")
|
||||
self.organismLabel?.text = lines.joined(separator: "\n")
|
||||
self.progressView?.progress = 0
|
||||
|
||||
self.headerContainer?.setNeedsLayout()
|
||||
@@ -311,87 +433,13 @@ class MigrationsDemoViewController: UIViewController {
|
||||
|
||||
tableView.layoutIfNeeded()
|
||||
|
||||
if let indexPath = self.lastSelectedIndexPath where indexPath.row < tableView.numberOfRowsInSection(0) {
|
||||
if let indexPath = self.lastSelectedIndexPath,
|
||||
indexPath.row < tableView.numberOfRows(inSection: 0) {
|
||||
|
||||
tableView.selectRowAtIndexPath(indexPath,
|
||||
tableView.selectRow(at: indexPath,
|
||||
animated: scrollToSelection && animated,
|
||||
scrollPosition: scrollToSelection ? .Middle : .None
|
||||
scrollPosition: scrollToSelection ? .middle : .none
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - MigrationsDemoViewController: ListObserver
|
||||
|
||||
extension MigrationsDemoViewController: ListObserver {
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
func listMonitorWillChange(monitor: ListMonitor<NSManagedObject>) { }
|
||||
|
||||
func listMonitorDidChange(monitor: ListMonitor<NSManagedObject>) {
|
||||
|
||||
if self.lastSelectedIndexPath == nil && self.listMonitor?.numberOfObjectsInSection(0) > 0 {
|
||||
|
||||
self.tableView?.reloadData()
|
||||
self.setSelectedIndexPath(NSIndexPath(forRow: 0, inSection: 0), scrollToSelection: false)
|
||||
}
|
||||
else {
|
||||
|
||||
self.updateDisplay(reloadData: true, scrollToSelection: true, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate
|
||||
|
||||
extension MigrationsDemoViewController: UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
@objc dynamic func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
|
||||
}
|
||||
|
||||
@objc dynamic func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("OrganismTableViewCell", forIndexPath: indexPath) as! OrganismTableViewCell
|
||||
|
||||
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
|
||||
cell.dnaLabel?.text = "DNA: \(dna)"
|
||||
cell.mutateButtonHandler = { [weak self] _ -> Void in
|
||||
|
||||
guard let `self` = self,
|
||||
let dataStack = self.dataStack,
|
||||
let organism = self.listMonitor?[indexPath] else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||
self.setEnabled(false)
|
||||
dataStack.beginAsynchronous { [weak self] (transaction) -> Void in
|
||||
|
||||
let organism = transaction.edit(organism) as! OrganismProtocol
|
||||
organism.mutate()
|
||||
|
||||
transaction.commit { _ -> Void in
|
||||
|
||||
self?.setEnabled(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
@objc dynamic func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
self.setSelectedIndexPath(indexPath, scrollToSelection: false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -13,4 +13,4 @@ protocol OrganismProtocol: class {
|
||||
var dna: Int64 { get set }
|
||||
|
||||
func mutate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -15,7 +15,7 @@ class OrganismTableViewCell: UITableViewCell {
|
||||
|
||||
var mutateButtonHandler: (() -> Void)?
|
||||
|
||||
@IBAction dynamic func mutateButtonTouchUpInside(sender: UIButton?) {
|
||||
@IBAction dynamic func mutateButtonTouchUpInside(_ sender: UIButton?) {
|
||||
|
||||
self.mutateButtonHandler?()
|
||||
}
|
||||
|
||||
@@ -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,21 +3,27 @@
|
||||
// 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
|
||||
|
||||
class OrganismV2ToV3MigrationPolicy: NSEntityMigrationPolicy {
|
||||
|
||||
override func createDestinationInstancesForSourceInstance(sInstance: NSManagedObject, entityMapping mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
|
||||
try super.createDestinationInstancesForSourceInstance(sInstance, entityMapping: mapping, manager: manager)
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
|
||||
for dInstance in manager.destinationInstancesForEntityMappingNamed(mapping.name, sourceInstances: [sInstance]) {
|
||||
for dInstance in manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]) {
|
||||
|
||||
dInstance.setValue(false, forKey: "hasVertebrae")
|
||||
dInstance.setValue(sInstance.valueForKey("numberOfFlippers"), forKey: "numberOfLimbs")
|
||||
dInstance.setValue(
|
||||
false,
|
||||
forKey: #keyPath(OrganismV3.hasVertebrae)
|
||||
)
|
||||
dInstance.setValue(
|
||||
sInstance.value(forKey: #keyPath(OrganismV2.numberOfFlippers)),
|
||||
forKey: #keyPath(OrganismV3.numberOfLimbs)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE database SYSTEM "file:///System/Library/DTDs/CoreData.dtd">
|
||||
|
||||
<database>
|
||||
@@ -10,7 +10,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPersistenceFrameworkVersion</key>
|
||||
<integer>526</integer>
|
||||
<integer>754</integer>
|
||||
<key>NSStoreModelVersionHashes</key>
|
||||
<dict>
|
||||
<key>XDDevAttributeMapping</key>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV1" syncable="YES">
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="hasHead" optional="YES" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasTail" optional="YES" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasHead" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasTail" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="90"/>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV2" syncable="YES">
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="105"/>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14E46" minimumToolsVersion="Xcode 4.3">
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16E195" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Organism" representedClassName="CoreStoreDemo.OrganismV3" syncable="YES">
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="hasHead" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasTail" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="hasVertebrae" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
<attribute name="dna" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="hasVertebrae" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" elementID="numberOfFlippers" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="120"/>
|
||||
|
||||
@@ -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
|
||||
@@ -17,77 +17,76 @@ private struct Static {
|
||||
|
||||
static let facebookStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(modelName: "StackSetupDemo")
|
||||
let dataStack = DataStack(xcodeModelName: "StackSetupDemo")
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_FB_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_FB_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From(UserAccount))
|
||||
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Facebook"
|
||||
account1.name = "John Smith HCD"
|
||||
account1.friends = 42
|
||||
|
||||
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
|
||||
account2.accountType = "Facebook"
|
||||
account2.name = "Jane Doe HCD"
|
||||
account2.friends = 314
|
||||
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
_ = try? dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
try transaction.deleteAll(From<UserAccount>())
|
||||
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Facebook"
|
||||
account1.name = "John Smith HCD"
|
||||
account1.friends = 42
|
||||
|
||||
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
|
||||
account2.accountType = "Facebook"
|
||||
account2.name = "Jane Doe HCD"
|
||||
account2.friends = 314
|
||||
}
|
||||
)
|
||||
|
||||
return dataStack
|
||||
}()
|
||||
|
||||
static let twitterStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(modelName: "StackSetupDemo")
|
||||
let dataStack = DataStack(xcodeModelName: "StackSetupDemo")
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_TW_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "AccountsDemo_TW_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From(UserAccount))
|
||||
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Twitter"
|
||||
account1.name = "#johnsmith_hcd"
|
||||
account1.friends = 7
|
||||
|
||||
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
|
||||
account2.accountType = "Twitter"
|
||||
account2.name = "#janedoe_hcd"
|
||||
account2.friends = 100
|
||||
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
|
||||
_ = try? dataStack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
try transaction.deleteAll(From<UserAccount>())
|
||||
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Twitter"
|
||||
account1.name = "#johnsmith_hcd"
|
||||
account1.friends = 7
|
||||
|
||||
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
|
||||
account2.accountType = "Twitter"
|
||||
account2.name = "#janedoe_hcd"
|
||||
account2.friends = 100
|
||||
}
|
||||
)
|
||||
return dataStack
|
||||
}()
|
||||
}
|
||||
@@ -100,53 +99,53 @@ private struct Static {
|
||||
class StackSetupDemoViewController: UITableViewController {
|
||||
|
||||
let accounts = [
|
||||
Static.facebookStack.fetchAll(From(UserAccount)) ?? [],
|
||||
Static.twitterStack.fetchAll(From(UserAccount)) ?? []
|
||||
try! Static.facebookStack.fetchAll(From<UserAccount>()),
|
||||
try! Static.twitterStack.fetchAll(From<UserAccount>())
|
||||
]
|
||||
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewWillAppear(animated: Bool) {
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
self.tableView.reloadData()
|
||||
|
||||
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
|
||||
self.tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
|
||||
self.updateDetailsWithAccount(self.accounts[indexPath.section][indexPath.row])
|
||||
let indexPath = IndexPath(row: 0, section: 0)
|
||||
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
|
||||
self.updateDetails(account: self.accounts[indexPath.section][indexPath.row])
|
||||
}
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Setup Demo",
|
||||
message: "This demo shows how to initialize 2 DataStacks with 2 configurations each, for a total of 4 SQLite files, each with 1 instance of a \"UserAccount\" entity.",
|
||||
preferredStyle: .Alert
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
|
||||
return self.accounts.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.accounts[section].count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")!
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!
|
||||
|
||||
let account = self.accounts[indexPath.section][indexPath.row]
|
||||
cell.textLabel?.text = account.name
|
||||
@@ -158,13 +157,13 @@ class StackSetupDemoViewController: UITableViewController {
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
||||
let account = self.accounts[indexPath.section][indexPath.row]
|
||||
self.updateDetailsWithAccount(account)
|
||||
self.updateDetails(account: account)
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
switch section {
|
||||
|
||||
@@ -188,7 +187,7 @@ class StackSetupDemoViewController: UITableViewController {
|
||||
@IBOutlet private dynamic weak var nameLabel: UILabel?
|
||||
@IBOutlet private dynamic weak var friendsLabel: UILabel?
|
||||
|
||||
private func updateDetailsWithAccount(account: UserAccount) {
|
||||
private func updateDetails(account: UserAccount) {
|
||||
|
||||
self.accountTypeLabel?.text = account.accountType
|
||||
self.nameLabel?.text = account.name
|
||||
|
||||
@@ -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,15 +3,15 @@
|
||||
// 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
|
||||
import CoreStore
|
||||
import GCDKit
|
||||
|
||||
|
||||
private struct Static {
|
||||
@@ -22,21 +22,21 @@ private struct Static {
|
||||
SQLiteStore(
|
||||
fileName: "PlaceDemo.sqlite",
|
||||
configuration: "TransactionsDemo",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
|
||||
var place = CoreStore.fetchOne(From(Place))
|
||||
var place = try! CoreStore.fetchOne(From<Place>())
|
||||
if place == nil {
|
||||
|
||||
CoreStore.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
let place = transaction.create(Into(Place))
|
||||
place.setInitialValues()
|
||||
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
place = CoreStore.fetchOne(From(Place))
|
||||
_ = try? CoreStore.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
let place = transaction.create(Into<Place>())
|
||||
place.setInitialValues()
|
||||
}
|
||||
)
|
||||
place = try! CoreStore.fetchOne(From<Place>())
|
||||
}
|
||||
|
||||
return CoreStore.monitorObject(place!)
|
||||
@@ -71,33 +71,33 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
Static.placeController.addObserver(self)
|
||||
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(
|
||||
barButtonSystemItem: .Refresh,
|
||||
barButtonSystemItem: .refresh,
|
||||
target: self,
|
||||
action: #selector(self.refreshButtonTapped(_:))
|
||||
)
|
||||
}
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Transactions Demo",
|
||||
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and unsafe.\n\nTap and hold on the map to change the pin location.",
|
||||
preferredStyle: .Alert
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(animated: Bool) {
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
if let mapView = self.mapView, let place = Static.placeController.object {
|
||||
|
||||
mapView.addAnnotation(place)
|
||||
mapView.setCenterCoordinate(place.coordinate, animated: false)
|
||||
mapView.setCenter(place.coordinate, animated: false)
|
||||
mapView.selectAnnotation(place, animated: false)
|
||||
}
|
||||
}
|
||||
@@ -105,14 +105,14 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
|
||||
// MARK: MKMapViewDelegate
|
||||
|
||||
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
|
||||
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
|
||||
|
||||
let identifier = "MKAnnotationView"
|
||||
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
|
||||
var annotationView: MKPinAnnotationView! = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
|
||||
if annotationView == nil {
|
||||
|
||||
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
|
||||
annotationView.enabled = true
|
||||
annotationView.isEnabled = true
|
||||
annotationView.canShowCallout = true
|
||||
annotationView.animatesDrop = true
|
||||
}
|
||||
@@ -127,28 +127,28 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
|
||||
// MARK: ObjectObserver
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<Place>, willUpdateObject object: Place) {
|
||||
|
||||
// none
|
||||
}
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPathString>) {
|
||||
|
||||
if let mapView = self.mapView {
|
||||
|
||||
mapView.removeAnnotations(mapView.annotations ?? [])
|
||||
mapView.removeAnnotations(mapView.annotations)
|
||||
mapView.addAnnotation(object)
|
||||
mapView.setCenterCoordinate(object.coordinate, animated: true)
|
||||
mapView.setCenter(object.coordinate, animated: true)
|
||||
mapView.selectAnnotation(object, animated: true)
|
||||
|
||||
if changedPersistentKeys.contains("latitude") || changedPersistentKeys.contains("longitude") {
|
||||
if changedPersistentKeys.contains(#keyPath(Place.latitude)) || changedPersistentKeys.contains(#keyPath(Place.longitude)) {
|
||||
|
||||
self.geocodePlace(object)
|
||||
self.geocode(place: object)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<Place>, didDeleteObject object: Place) {
|
||||
|
||||
// none
|
||||
}
|
||||
@@ -160,34 +160,39 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
|
||||
|
||||
@IBOutlet weak var mapView: MKMapView?
|
||||
|
||||
@IBAction dynamic func longPressGestureRecognized(sender: AnyObject?) {
|
||||
@IBAction dynamic func longPressGestureRecognized(_ sender: AnyObject?) {
|
||||
|
||||
if let mapView = self.mapView, let gesture = sender as? UILongPressGestureRecognizer where gesture.state == .Began {
|
||||
if let mapView = self.mapView,
|
||||
let gesture = sender as? UILongPressGestureRecognizer,
|
||||
gesture.state == .began {
|
||||
|
||||
let coordinate = mapView.convertPoint(
|
||||
gesture.locationInView(mapView),
|
||||
toCoordinateFromView: mapView
|
||||
let coordinate = mapView.convert(
|
||||
gesture.location(in: mapView),
|
||||
toCoordinateFrom: mapView
|
||||
)
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
CoreStore.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
place?.coordinate = coordinate
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction dynamic func refreshButtonTapped(_ sender: AnyObject?) {
|
||||
|
||||
_ = try? CoreStore.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
place?.coordinate = coordinate
|
||||
transaction.commit { (_) -> Void in }
|
||||
place?.setInitialValues()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction dynamic func refreshButtonTapped(sender: AnyObject?) {
|
||||
|
||||
CoreStore.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
let place = transaction.edit(Static.placeController.object)
|
||||
place?.setInitialValues()
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
}
|
||||
|
||||
func geocodePlace(place: Place) {
|
||||
func geocode(place: Place) {
|
||||
|
||||
let transaction = CoreStore.beginUnsafe()
|
||||
|
||||
@@ -199,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,11 +36,11 @@ class BaseTestCase: XCTestCase {
|
||||
// MARK: Internal
|
||||
|
||||
@nonobjc
|
||||
func prepareStack<T>(configurations configurations: [String?] = [nil], @noescape _ closure: (dataStack: DataStack) -> T) -> T {
|
||||
func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) throws -> Void) {
|
||||
|
||||
let stack = DataStack(
|
||||
modelName: "Model",
|
||||
bundle: NSBundle(forClass: self.dynamicType)
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -49,23 +49,23 @@ class BaseTestCase: XCTestCase {
|
||||
try stack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileURL: SQLiteStore.defaultRootDirectory
|
||||
.URLByAppendingPathComponent(NSUUID().UUIDString)!
|
||||
.URLByAppendingPathComponent("\(self.dynamicType)_\(($0 ?? "-null-")).sqlite")!,
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathComponent("\(type(of: self))_\(($0 ?? "-null-")).sqlite"),
|
||||
configuration: $0,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
}
|
||||
try closure(stack)
|
||||
}
|
||||
catch let error as NSError {
|
||||
|
||||
XCTFail(error.coreStoreDumpString)
|
||||
}
|
||||
return closure(dataStack: stack)
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func expectLogger<T>(expectations: [TestLogger.Expectation], @noescape closure: () -> T) -> T {
|
||||
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
|
||||
|
||||
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
|
||||
defer {
|
||||
@@ -73,22 +73,49 @@ class BaseTestCase: XCTestCase {
|
||||
self.checkExpectationsImmediately()
|
||||
CoreStore.logger = TestLogger([:])
|
||||
}
|
||||
return closure()
|
||||
return try closure()
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func expectLogger(expectations: [TestLogger.Expectation: XCTestExpectation]) {
|
||||
func expectLogger(_ expectations: [TestLogger.Expectation: XCTestExpectation]) {
|
||||
|
||||
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] {
|
||||
func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
|
||||
|
||||
var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:]
|
||||
for expectation in expectations {
|
||||
|
||||
testExpectations[expectation] = self.expectationWithDescription("Logger Expectation: \(expectation)")
|
||||
testExpectations[expectation] = self.expectation(description: "Logger Expectation: \(expectation)")
|
||||
}
|
||||
return testExpectations
|
||||
}
|
||||
@@ -96,13 +123,13 @@ class BaseTestCase: XCTestCase {
|
||||
@nonobjc
|
||||
func checkExpectationsImmediately() {
|
||||
|
||||
self.waitForExpectationsWithTimeout(0, handler: nil)
|
||||
self.waitForExpectations(timeout: 0, handler: { _ in })
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func waitAndCheckExpectations() {
|
||||
|
||||
self.waitForExpectationsWithTimeout(10, handler: nil)
|
||||
self.waitForExpectations(timeout: 10, handler: {_ in })
|
||||
}
|
||||
|
||||
// MARK: XCTestCase
|
||||
@@ -126,7 +153,7 @@ class BaseTestCase: XCTestCase {
|
||||
|
||||
private func deleteStores() {
|
||||
|
||||
_ = try? NSFileManager.defaultManager().removeItemAtURL(SQLiteStore.defaultRootDirectory)
|
||||
_ = try? FileManager.default.removeItem(at: SQLiteStore.defaultRootDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,11 +164,11 @@ class TestLogger: CoreStoreLogger {
|
||||
|
||||
enum Expectation {
|
||||
|
||||
case LogWarning
|
||||
case LogFatal
|
||||
case LogError
|
||||
case AssertionFailure
|
||||
case FatalError
|
||||
case logWarning
|
||||
case logFatal
|
||||
case logError
|
||||
case assertionFailure
|
||||
case fatalError
|
||||
}
|
||||
|
||||
init(_ expectations: [Expectation: XCTestExpectation]) {
|
||||
@@ -152,33 +179,35 @@ class TestLogger: CoreStoreLogger {
|
||||
|
||||
// MARK: CoreStoreLogger
|
||||
|
||||
func log(level level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
var enableObjectConcurrencyDebugging: Bool = true
|
||||
|
||||
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
switch level {
|
||||
|
||||
case .Warning: self.fulfill(.LogWarning)
|
||||
case .Fatal: self.fulfill(.LogFatal)
|
||||
case .warning: self.fulfill(.logWarning)
|
||||
case .fatal: self.fulfill(.logFatal)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
func log(error error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
self.fulfill(.LogError)
|
||||
self.fulfill(.logError)
|
||||
}
|
||||
|
||||
func assert(@autoclosure condition: () -> Bool, @autoclosure message: () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
if condition() {
|
||||
|
||||
return
|
||||
}
|
||||
self.fulfill(.AssertionFailure)
|
||||
self.fulfill(.assertionFailure)
|
||||
}
|
||||
|
||||
func abort(message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
|
||||
|
||||
self.fulfill(.FatalError)
|
||||
self.fulfill(.fatalError)
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +215,7 @@ class TestLogger: CoreStoreLogger {
|
||||
|
||||
private var expectations: [Expectation: XCTestExpectation]
|
||||
|
||||
private func fulfill(expectation: Expectation) {
|
||||
private func fulfill(_ expectation: Expectation) {
|
||||
|
||||
if let instance = self.expectations[expectation] {
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -17,60 +34,61 @@ import CoreStore
|
||||
class BaseTestDataTestCase: BaseTestCase {
|
||||
|
||||
@nonobjc
|
||||
let dateFormatter: NSDateFormatter = {
|
||||
let dateFormatter: DateFormatter = cs_lazy {
|
||||
|
||||
let formatter = NSDateFormatter()
|
||||
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
|
||||
formatter.timeZone = NSTimeZone(name: "UTC")
|
||||
formatter.calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
|
||||
let formatter = DateFormatter()
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
formatter.timeZone = TimeZone(identifier: "UTC")
|
||||
formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
|
||||
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
|
||||
return formatter
|
||||
}()
|
||||
}
|
||||
|
||||
@nonobjc
|
||||
func prepareTestDataForStack(stack: DataStack, configurations: [String?] = [nil]) {
|
||||
func prepareTestDataForStack(_ stack: DataStack, configurations: [ModelConfiguration] = [nil]) {
|
||||
|
||||
stack.beginSynchronous { (transaction) in
|
||||
|
||||
for (configurationIndex, configuration) in configurations.enumerate() {
|
||||
try! stack.perform(
|
||||
synchronous: { (transaction) in
|
||||
|
||||
let configurationOrdinal = configurationIndex + 1
|
||||
if configuration == nil || configuration == "Config1" {
|
||||
for (configurationIndex, configuration) in configurations.enumerated() {
|
||||
|
||||
for idIndex in 1 ... 5 {
|
||||
let configurationOrdinal = configurationIndex + 1
|
||||
if configuration == nil || configuration == "Config1" {
|
||||
|
||||
let object = transaction.create(Into<TestEntity1>(configuration))
|
||||
object.testEntityID = NSNumber(integer: (configurationOrdinal * 100) + idIndex)
|
||||
|
||||
object.testNumber = idIndex
|
||||
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||
object.testBoolean = (idIndex % 2) == 1
|
||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||
|
||||
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
|
||||
object.testString = string
|
||||
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
|
||||
for idIndex in 1 ... 5 {
|
||||
|
||||
let object = transaction.create(Into<TestEntity1>(configuration))
|
||||
object.testEntityID = NSNumber(value: (configurationOrdinal * 100) + idIndex)
|
||||
|
||||
object.testNumber = NSNumber(value: idIndex)
|
||||
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||
|
||||
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
|
||||
object.testString = string
|
||||
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
if configuration == nil || configuration == "Config2" {
|
||||
|
||||
for idIndex in 1 ... 5 {
|
||||
if configuration == nil || configuration == "Config2" {
|
||||
|
||||
let object = transaction.create(Into<TestEntity2>(configuration))
|
||||
object.testEntityID = NSNumber(integer: (configurationOrdinal * 200) + idIndex)
|
||||
|
||||
object.testNumber = idIndex
|
||||
object.testDate = self.dateFormatter.dateFromString("2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||
object.testBoolean = (idIndex % 2) == 1
|
||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||
|
||||
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
|
||||
object.testString = string
|
||||
object.testData = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
|
||||
for idIndex in 1 ... 5 {
|
||||
|
||||
let object = transaction.create(Into<TestEntity2>(configuration))
|
||||
object.testEntityID = NSNumber(value: (configurationOrdinal * 200) + idIndex)
|
||||
|
||||
object.testNumber = NSNumber(value: idIndex)
|
||||
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||
|
||||
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
|
||||
object.testString = string
|
||||
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
transaction.commitAndWait()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -163,7 +163,7 @@
|
||||
- (void)test_ThatDataStacks_BridgeCorrectly {
|
||||
|
||||
CSDataStack *dataStack = [[CSDataStack alloc]
|
||||
initWithModelName:@"Model"
|
||||
initWithXcodeModelName:@"Model"
|
||||
bundle:[NSBundle bundleForClass:[self class]]
|
||||
versionChain:nil];
|
||||
XCTAssertNotNil(dataStack);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -201,7 +211,7 @@
|
||||
|
||||
[CSCoreStore
|
||||
setDefaultStack:[[CSDataStack alloc]
|
||||
initWithModelName:@"Model"
|
||||
initWithXcodeModelName:@"Model"
|
||||
bundle:[NSBundle bundleForClass:[self class]]
|
||||
versionChain:nil]];
|
||||
[CSCoreStore
|
||||
@@ -212,15 +222,27 @@
|
||||
CSUnsafeDataTransaction *transaction = [CSCoreStore beginUnsafe];
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
|
||||
NSError *error;
|
||||
BOOL result = [transaction commitAndWaitWithError:&error];
|
||||
XCTAssertTrue(result);
|
||||
XCTAssertNil(error);
|
||||
}
|
||||
{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
|
||||
[CSCoreStore beginSynchronous:^(CSSynchronousDataTransaction * _Nonnull transaction) {
|
||||
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
NSError *error;
|
||||
BOOL result = [CSCoreStore
|
||||
beginSynchronous:^(CSSynchronousDataTransaction * _Nonnull transaction) {
|
||||
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
|
||||
NSError *error;
|
||||
XCTAssertTrue([transaction commitAndWaitWithError:&error]);
|
||||
XCTAssertNil(error);
|
||||
[expectation fulfill];
|
||||
}
|
||||
error:&error];
|
||||
XCTAssertTrue(result);
|
||||
XCTAssertNil(error);
|
||||
}
|
||||
{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"async"];
|
||||
@@ -228,7 +250,15 @@
|
||||
|
||||
XCTAssertNotNil(transaction);
|
||||
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
|
||||
[expectation fulfill];
|
||||
[transaction
|
||||
commitWithSuccess:^{
|
||||
|
||||
[expectation fulfill];
|
||||
}
|
||||
failure:^(CSError *error){
|
||||
|
||||
XCTFail();
|
||||
}];
|
||||
}];
|
||||
}
|
||||
[self waitForExpectationsWithTimeout:10 handler:nil];
|
||||
|
||||
91
CoreStoreTests/ConvenienceTests.swift
Normal file
91
CoreStoreTests/ConvenienceTests.swift
Normal file
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// ConvenienceTests.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.
|
||||
//
|
||||
|
||||
@testable
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - ConvenienceTests
|
||||
|
||||
@available(macOS 10.12, *)
|
||||
class ConvenienceTests: BaseTestCase {
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatDataStacks_CanCreateFetchedResultsControllers() {
|
||||
|
||||
self.prepareStack { (stack) in
|
||||
|
||||
let controller = stack.createFetchedResultsController(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#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)
|
||||
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
|
||||
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.sortDescriptors!,
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
||||
)
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.predicate,
|
||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
||||
)
|
||||
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatUnsafeDataTransactions_CanCreateFetchedResultsControllers() {
|
||||
|
||||
self.prepareStack { (stack) in
|
||||
|
||||
_ = withExtendedLifetime(stack.beginUnsafe()) { (transaction: UnsafeDataTransaction) in
|
||||
|
||||
let controller = transaction.createFetchedResultsController(
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testString)),
|
||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
|
||||
Tweak { $0.fetchLimit = 10 }
|
||||
)
|
||||
XCTAssertEqual(controller.managedObjectContext, transaction.context)
|
||||
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
|
||||
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.sortDescriptors!,
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
|
||||
)
|
||||
XCTAssertEqual(
|
||||
controller.fetchRequest.predicate,
|
||||
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
|
||||
)
|
||||
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
353
CoreStoreTests/DynamicModelTests.swift
Normal file
353
CoreStoreTests/DynamicModelTests.swift
Normal file
@@ -0,0 +1,353 @@
|
||||
//
|
||||
// DynamicModelTests.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
|
||||
|
||||
#if os(macOS)
|
||||
typealias Color = NSColor
|
||||
|
||||
#else
|
||||
typealias Color = UIColor
|
||||
|
||||
#endif
|
||||
|
||||
class Animal: CoreStoreObject {
|
||||
|
||||
let species = Value.Required<String>("species", initial: "Swift")
|
||||
let master = Relationship.ToOne<Person>("master")
|
||||
let color = Transformable.Optional<Color>("color")
|
||||
}
|
||||
|
||||
class Dog: Animal {
|
||||
|
||||
let nickname = Value.Optional<String>("nickname")
|
||||
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",
|
||||
initial: "Mr.",
|
||||
customSetter: Person.setTitle
|
||||
)
|
||||
|
||||
let name = Value.Required<String>(
|
||||
"name",
|
||||
initial: "",
|
||||
customSetter: Person.setName
|
||||
)
|
||||
|
||||
let displayName = Value.Optional<String>(
|
||||
"displayName",
|
||||
isTransient: true,
|
||||
customGetter: Person.getDisplayName(_:),
|
||||
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
|
||||
)
|
||||
|
||||
let spouse = Relationship.ToOne<Person>("spouse")
|
||||
|
||||
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) {
|
||||
|
||||
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 displayName
|
||||
}
|
||||
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 [
|
||||
String(keyPath: \Person.title),
|
||||
String(keyPath: \Person.name)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - DynamicModelTests
|
||||
|
||||
class DynamicModelTests: BaseTestDataTestCase {
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatDynamicModels_CanBeDeclaredCorrectly() {
|
||||
|
||||
let dataStack = DataStack(
|
||||
CoreStoreSchema(
|
||||
modelVersion: "V1",
|
||||
entities: [
|
||||
Entity<Animal>("Animal"),
|
||||
Entity<Dog>("Dog"),
|
||||
Entity<Person>("Person")
|
||||
],
|
||||
versionLock: [
|
||||
"Animal": [0x1b59d511019695cf, 0xdeb97e86c5eff179, 0x1cfd80745646cb3, 0x4ff99416175b5b9a],
|
||||
"Dog": [0xe3f0afeb109b283a, 0x29998d292938eb61, 0x6aab788333cfc2a3, 0x492ff1d295910ea7],
|
||||
"Person": [0x2831cf046084d96d, 0xbe19b13ace54641, 0x635a082728b0f6f0, 0x3d4ef2dd4b74a87c]
|
||||
]
|
||||
)
|
||||
)
|
||||
self.prepareStack(dataStack, configurations: [nil]) { (stack) in
|
||||
|
||||
let k1 = String(keyPath: \Animal.species)
|
||||
XCTAssertEqual(k1, "species")
|
||||
|
||||
let k2 = String(keyPath: \Dog.species)
|
||||
XCTAssertEqual(k2, "species")
|
||||
|
||||
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
|
||||
|
||||
let animal = transaction.create(Into<Animal>())
|
||||
XCTAssertEqual(animal.species.value, "Swift")
|
||||
XCTAssertTrue(type(of: animal.species.value) == String.self)
|
||||
|
||||
animal.species .= "Sparrow"
|
||||
XCTAssertEqual(animal.species.value, "Sparrow")
|
||||
|
||||
animal.color .= .yellow
|
||||
XCTAssertEqual(animal.color.value, Color.yellow)
|
||||
|
||||
let dog = transaction.create(Into<Dog>())
|
||||
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")
|
||||
|
||||
let person = transaction.create(Into<Person>())
|
||||
XCTAssertTrue(person.pets.value.isEmpty)
|
||||
|
||||
XCTAssertEqual(
|
||||
cs_dynamicType(of: person.rawObject!).keyPathsForValuesAffectingValue(forKey: "displayName"),
|
||||
["title", "name"]
|
||||
)
|
||||
|
||||
person.name .= "Joe"
|
||||
|
||||
XCTAssertEqual(person.rawObject!.value(forKey: "name") as! String?, "Joe")
|
||||
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "Mr. Joe")
|
||||
|
||||
person.rawObject!.setValue("AAAA", forKey: "displayName")
|
||||
XCTAssertEqual(person.rawObject!.value(forKey: "displayName") as! String?, "AAAA")
|
||||
|
||||
person.name .= "John"
|
||||
XCTAssertEqual(person.name.value, "John")
|
||||
XCTAssertEqual(person.displayName.value, "Mr. John") // Custom getter
|
||||
|
||||
person.title .= "Sir"
|
||||
XCTAssertEqual(person.displayName.value, "Sir John")
|
||||
|
||||
person.pets.value.insert(dog)
|
||||
XCTAssertEqual(person.pets.count, 1)
|
||||
XCTAssertEqual(person.pets.value.first, dog)
|
||||
XCTAssertEqual(person.pets.value.first?.master.value, person)
|
||||
XCTAssertEqual(dog.master.value, person)
|
||||
XCTAssertEqual(dog.master.value?.pets.value.first, dog)
|
||||
},
|
||||
success: { _ in
|
||||
|
||||
updateDone.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
)
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
let p1 = Where<Animal>({ $0.species == "Sparrow" })
|
||||
XCTAssertEqual(p1.predicate, NSPredicate(format: "%K == %@", "species", "Sparrow"))
|
||||
|
||||
let bird = try transaction.fetchOne(From<Animal>(), p1)
|
||||
XCTAssertNotNil(bird)
|
||||
XCTAssertEqual(bird!.species.value, "Sparrow")
|
||||
|
||||
let p2 = Where<Dog>({ $0.nickname == "Spot" })
|
||||
XCTAssertEqual(p2.predicate, NSPredicate(format: "%K == %@", "nickname", "Spot"))
|
||||
|
||||
let dog = try transaction.fetchOne(From<Dog>().where(\.nickname == "Spot"))
|
||||
XCTAssertNotNil(dog)
|
||||
XCTAssertEqual(dog!.nickname.value, "Spot")
|
||||
XCTAssertEqual(dog!.species.value, "Dog")
|
||||
|
||||
let person = try transaction.fetchOne(From<Person>())
|
||||
XCTAssertNotNil(person)
|
||||
XCTAssertEqual(person!.pets.value.first, dog)
|
||||
|
||||
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: { _ in
|
||||
|
||||
fetchDone.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
||||
do {
|
||||
|
||||
try configurations.forEach { (configuration) in
|
||||
|
||||
try dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileURL: SQLiteStore.defaultRootDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathComponent("\(type(of: self))_\((configuration ?? "-null-")).sqlite"),
|
||||
configuration: configuration,
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
catch let error as NSError {
|
||||
|
||||
XCTFail(error.coreStoreDumpString)
|
||||
}
|
||||
closure(dataStack)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -36,33 +36,33 @@ final class ErrorTests: XCTestCase {
|
||||
@objc
|
||||
dynamic func test_ThatUnknownErrors_BridgeCorrectly() {
|
||||
|
||||
let error = CoreStoreError.Unknown
|
||||
let error = CoreStoreError.unknown
|
||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.UnknownError.rawValue)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.unknownError.rawValue)
|
||||
|
||||
let userInfo: NSDictionary = [:]
|
||||
|
||||
let objcError = error.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.UnknownError.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.unknownError.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
||||
|
||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.UnknownError.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.unknownError.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() {
|
||||
|
||||
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
|
||||
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
|
||||
|
||||
let error = CoreStoreError.DifferentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
|
||||
let error = CoreStoreError.differentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
|
||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
|
||||
|
||||
let userInfo: NSDictionary = [
|
||||
"existingPersistentStoreURL": dummyURL
|
||||
@@ -70,54 +70,59 @@ final class ErrorTests: XCTestCase {
|
||||
let objcError = error.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
||||
|
||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.DifferentPersistentStoreExistsAtURL.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() {
|
||||
|
||||
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
|
||||
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
|
||||
|
||||
let model = NSManagedObjectModel.fromBundle(NSBundle(forClass: self.dynamicType), modelName: "Model")
|
||||
let schemaHistory = SchemaHistory(
|
||||
XcodeDataModelSchema.from(
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
)
|
||||
let version = "1.0.0"
|
||||
|
||||
let error = CoreStoreError.MappingModelNotFound(localStoreURL: dummyURL, targetModel: model, targetModelVersion: version)
|
||||
let error = CoreStoreError.mappingModelNotFound(localStoreURL: dummyURL, targetModel: schemaHistory.rawModel, targetModelVersion: version)
|
||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
|
||||
|
||||
let userInfo: NSDictionary = [
|
||||
"localStoreURL": dummyURL,
|
||||
"targetModel": model,
|
||||
"targetModel": schemaHistory.rawModel,
|
||||
"targetModelVersion": version
|
||||
]
|
||||
let objcError = error.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
||||
|
||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.MappingModelNotFound.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() {
|
||||
|
||||
let dummyURL = NSURL(string: "file:///test1/test2.sqlite")!
|
||||
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
|
||||
|
||||
let error = CoreStoreError.ProgressiveMigrationRequired(localStoreURL: dummyURL)
|
||||
let error = CoreStoreError.progressiveMigrationRequired(localStoreURL: dummyURL)
|
||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
|
||||
|
||||
let userInfo: NSDictionary = [
|
||||
"localStoreURL": dummyURL
|
||||
@@ -125,14 +130,14 @@ final class ErrorTests: XCTestCase {
|
||||
let objcError = error.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
||||
|
||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.ProgressiveMigrationRequired.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
||||
}
|
||||
|
||||
@objc
|
||||
@@ -144,12 +149,12 @@ final class ErrorTests: XCTestCase {
|
||||
userInfo: [
|
||||
"key1": "value1",
|
||||
"key2": 2,
|
||||
"key3": NSDate()
|
||||
"key3": Date()
|
||||
]
|
||||
)
|
||||
let error = CoreStoreError(internalError)
|
||||
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.InternalError.rawValue)
|
||||
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.internalError.rawValue)
|
||||
|
||||
let userInfo: NSDictionary = [
|
||||
"NSError": internalError
|
||||
@@ -157,13 +162,13 @@ final class ErrorTests: XCTestCase {
|
||||
let objcError = error.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError.bridgeToSwift)
|
||||
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.InternalError.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError.code, CoreStoreErrorCode.internalError.rawValue)
|
||||
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
|
||||
|
||||
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
|
||||
XCTAssertEqual(error, objcError2.bridgeToSwift)
|
||||
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.InternalError.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo, userInfo)
|
||||
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.internalError.rawValue)
|
||||
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -38,7 +38,7 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let from = From()
|
||||
let from = From<NSManagedObject>()
|
||||
XCTAssert(from.entityClass === NSManagedObject.self)
|
||||
XCTAssertNil(from.configurations)
|
||||
}
|
||||
@@ -74,33 +74,31 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = NSFetchRequest()
|
||||
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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
}
|
||||
@@ -115,102 +113,98 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = NSFetchRequest()
|
||||
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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let 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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
}
|
||||
@@ -225,99 +219,96 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = NSFetchRequest()
|
||||
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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let 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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = 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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
}
|
||||
@@ -332,96 +323,94 @@ final class FromTests: BaseTestCase {
|
||||
|
||||
let from = From<TestEntity1>()
|
||||
|
||||
let request = NSFetchRequest()
|
||||
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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config1")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let 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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config1"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity1>("Config2")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>()
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = 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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config2"])
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config1")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = self.expectLogger([.LogWarning]) {
|
||||
let request = CoreStoreFetchRequest<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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertTrue(affectedConfigurations.isEmpty)
|
||||
}
|
||||
do {
|
||||
|
||||
let from = From<TestEntity2>("Config2")
|
||||
|
||||
let request = NSFetchRequest()
|
||||
let storesFound = 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.affectedStores)
|
||||
XCTAssertNotNil(request.safeAffectedStores())
|
||||
|
||||
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
|
||||
|
||||
let affectedConfigurations = request.affectedStores!.map { $0.configurationName }
|
||||
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
|
||||
XCTAssertEqual(affectedConfigurations, ["Config2"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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("testString")
|
||||
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
|
||||
|
||||
let request = NSFetchRequest()
|
||||
_ = 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)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -36,7 +36,7 @@ final class IntoTests: XCTestCase {
|
||||
@objc
|
||||
dynamic func test_ThatIntoClauseConstants_AreCorrect() {
|
||||
|
||||
XCTAssertEqual(Into<NSManagedObject>.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME")
|
||||
XCTAssertEqual(DataStack.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME")
|
||||
}
|
||||
|
||||
@objc
|
||||
@@ -44,7 +44,7 @@ final class IntoTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let into = Into()
|
||||
let into = Into<NSManagedObject>()
|
||||
XCTAssert(into.entityClass === NSManagedObject.self)
|
||||
XCTAssertNil(into.configuration)
|
||||
XCTAssertTrue(into.inferStoreIfPossible)
|
||||
@@ -58,14 +58,7 @@ final class IntoTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1)
|
||||
XCTAssert(into.entityClass === TestEntity1.self)
|
||||
XCTAssertNil(into.configuration)
|
||||
XCTAssertTrue(into.inferStoreIfPossible)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self as AnyClass)
|
||||
let into = Into(TestEntity1.self)
|
||||
XCTAssert(into.entityClass === TestEntity1.self)
|
||||
XCTAssertNil(into.configuration)
|
||||
XCTAssertTrue(into.inferStoreIfPossible)
|
||||
@@ -84,13 +77,6 @@ final class IntoTests: XCTestCase {
|
||||
XCTAssertEqual(into.configuration, "Config1")
|
||||
XCTAssertFalse(into.inferStoreIfPossible)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self as AnyClass, "Config1")
|
||||
XCTAssert(into.entityClass === TestEntity1.self)
|
||||
XCTAssertEqual(into.configuration, "Config1")
|
||||
XCTAssertFalse(into.inferStoreIfPossible)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
@@ -98,43 +84,30 @@ final class IntoTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let into = Into()
|
||||
XCTAssertEqual(into, Into())
|
||||
let into = Into<NSManagedObject>()
|
||||
XCTAssertEqual(into, Into<NSManagedObject>())
|
||||
XCTAssertEqual(into, Into(NSManagedObject.self as AnyClass))
|
||||
XCTAssertFalse(into == Into<TestEntity1>())
|
||||
XCTAssertEqual(into, Into(NSManagedObject.self))
|
||||
XCTAssertNotEqual(into, Into<NSManagedObject>(TestEntity1.self))
|
||||
XCTAssertNotEqual(into, Into<NSManagedObject>("Config1"))
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into<TestEntity1>()
|
||||
XCTAssertEqual(into, Into(TestEntity1))
|
||||
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass))
|
||||
XCTAssertFalse(into == Into<TestEntity2>())
|
||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1)
|
||||
XCTAssertEqual(into, Into<TestEntity1>())
|
||||
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass))
|
||||
XCTAssertFalse(into == Into<TestEntity2>())
|
||||
XCTAssertEqual(into, Into(TestEntity1.self))
|
||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self as AnyClass)
|
||||
let into = Into(TestEntity1.self)
|
||||
XCTAssert(into == Into<TestEntity1>())
|
||||
XCTAssertEqual(into, Into(TestEntity1))
|
||||
XCTAssertFalse(into == Into<TestEntity2>())
|
||||
XCTAssertEqual(into, Into(TestEntity1.self))
|
||||
XCTAssertFalse(into == Into<TestEntity1>("Config1"))
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into<TestEntity1>("Config1")
|
||||
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
|
||||
XCTAssertEqual(into, Into(TestEntity1.self as AnyClass, "Config1"))
|
||||
XCTAssertFalse(into == Into<TestEntity2>("Config1"))
|
||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
|
||||
}
|
||||
do {
|
||||
@@ -142,16 +115,14 @@ final class IntoTests: XCTestCase {
|
||||
let into = Into(TestEntity1.self, "Config1")
|
||||
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
|
||||
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
|
||||
XCTAssertFalse(into == Into<TestEntity2>("Config1"))
|
||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self as AnyClass, "Config1")
|
||||
XCTAssert(into == Into<TestEntity1>("Config1"))
|
||||
let into = Into(TestEntity1.self, "Config1")
|
||||
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
|
||||
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
|
||||
XCTAssertFalse(into == Into<TestEntity2>("Config1"))
|
||||
XCTAssertFalse(into == Into<TestEntity1>("Config2"))
|
||||
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,45 +131,9 @@ final class IntoTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let into = Into()
|
||||
let into = Into<NSManagedObject>()
|
||||
let objcInto = into.bridgeToObjectiveC
|
||||
XCTAssertEqual(into, objcInto.bridgeToSwift)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into<TestEntity1>()
|
||||
let objcInto = into.bridgeToObjectiveC
|
||||
XCTAssertTrue(into == objcInto.bridgeToSwift)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self as AnyClass)
|
||||
let objcInto = into.bridgeToObjectiveC
|
||||
XCTAssertEqual(into, objcInto.bridgeToSwift)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self as AnyClass)
|
||||
let objcInto = into.bridgeToObjectiveC
|
||||
XCTAssertEqual(into, objcInto.bridgeToSwift)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into<TestEntity1>("Config1")
|
||||
let objcInto = into.bridgeToObjectiveC
|
||||
XCTAssertTrue(into == objcInto.bridgeToSwift)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self, "Config1")
|
||||
let objcInto = into.bridgeToObjectiveC
|
||||
XCTAssertTrue(into == objcInto.bridgeToSwift)
|
||||
}
|
||||
do {
|
||||
|
||||
let into = Into(TestEntity1.self as AnyClass, "Config1")
|
||||
let objcInto = into.bridgeToObjectiveC
|
||||
XCTAssertTrue(into == objcInto.bridgeToSwift)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -29,10 +29,9 @@ import XCTest
|
||||
import CoreStore
|
||||
|
||||
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
|
||||
// MARK: - ListObserverTests
|
||||
|
||||
@available(macOS 10.12, *)
|
||||
class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
@objc
|
||||
@@ -42,9 +41,9 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
let observer = TestListObserver()
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From(TestEntity1),
|
||||
SectionBy("testBoolean"),
|
||||
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
@@ -54,13 +53,13 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
var events = 0
|
||||
|
||||
let willChangeExpectation = self.expectationForNotification(
|
||||
"listMonitorWillChange:",
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 0)
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -68,16 +67,16 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
let didInsertSectionExpectation = self.expectationForNotification(
|
||||
"listMonitor:didInsertSection:toSectionIndex:",
|
||||
let didInsertSectionExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 1)
|
||||
XCTAssertEqual(
|
||||
(note.userInfo ?? [:]),
|
||||
((note.userInfo as NSDictionary?) ?? [:]),
|
||||
[
|
||||
"sectionInfo": monitor.sectionInfoAtIndex(0),
|
||||
"sectionInfo": monitor.sectionInfo(at: 0),
|
||||
"sectionIndex": 0
|
||||
] as NSDictionary
|
||||
)
|
||||
@@ -88,8 +87,8 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 1
|
||||
}
|
||||
)
|
||||
let didInsertObjectExpectation = self.expectationForNotification(
|
||||
"listMonitor:didInsertObject:toIndexPath:",
|
||||
let didInsertObjectExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -98,21 +97,21 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
let userInfo = note.userInfo
|
||||
XCTAssertNotNil(userInfo)
|
||||
XCTAssertEqual(
|
||||
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
|
||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
["indexPath", "object"]
|
||||
)
|
||||
|
||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
XCTAssertEqual(indexPath?.section, 0)
|
||||
XCTAssertEqual(indexPath?.row, 0)
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
|
||||
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
|
||||
|
||||
let object = userInfo?["object"] as? TestEntity1
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(integer: 1))
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
|
||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!)
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!)
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -120,12 +119,12 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 2
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectationForNotification(
|
||||
"listMonitorDidChange:",
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -133,30 +132,30 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 3
|
||||
}
|
||||
)
|
||||
let saveExpectation = self.expectationWithDescription("save")
|
||||
stack.beginAsynchronous { (transaction) in
|
||||
|
||||
let object = transaction.create(Into(TestEntity1))
|
||||
object.testBoolean = NSNumber(bool: true)
|
||||
object.testNumber = NSNumber(integer: 1)
|
||||
object.testDecimal = NSDecimalNumber(string: "1")
|
||||
object.testString = "nil:TestEntity1:1"
|
||||
object.testData = ("nil:TestEntity1:1" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
object.testDate = self.dateFormatter.dateFromString("2000-01-01T00:00:00Z")!
|
||||
|
||||
transaction.commit { (result) in
|
||||
let saveExpectation = self.expectation(description: "save")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
switch result {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
|
||||
case .Failure:
|
||||
XCTFail()
|
||||
}
|
||||
let object = transaction.create(Into<TestEntity1>())
|
||||
object.testBoolean = NSNumber(value: true)
|
||||
object.testNumber = NSNumber(value: 1)
|
||||
object.testDecimal = NSDecimalNumber(string: "1")
|
||||
object.testString = "nil:TestEntity1:1"
|
||||
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
|
||||
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
}
|
||||
}
|
||||
@@ -170,28 +169,28 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
let observer = TestListObserver()
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From(TestEntity1),
|
||||
SectionBy("testBoolean"),
|
||||
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy<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.expectationForNotification(
|
||||
"listMonitorWillChange:",
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 0)
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -199,67 +198,65 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
for _ in 1 ... 2 {
|
||||
|
||||
let didUpdateObjectExpectation = self.expectationForNotification(
|
||||
"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 as? [String: AnyObject]) ?? [:]).keys),
|
||||
["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(integer: 101)?:
|
||||
XCTAssertEqual(indexPath?.section, 1)
|
||||
XCTAssertEqual(indexPath?.row, 0)
|
||||
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(integer: 11))
|
||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!)
|
||||
|
||||
case NSNumber(integer: 102)?:
|
||||
XCTAssertEqual(indexPath?.section, 0)
|
||||
XCTAssertEqual(indexPath?.row, 0)
|
||||
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(bool: false))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(integer: 22))
|
||||
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
|
||||
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
|
||||
XCTAssertEqual(object?.testDate, self.dateFormatter.dateFromString("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()
|
||||
}
|
||||
)
|
||||
}
|
||||
let didChangeExpectation = self.expectationForNotification(
|
||||
"listMonitorDidChange:",
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
}
|
||||
return events == 1 || events == 2
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 3)
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -267,50 +264,50 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 3
|
||||
}
|
||||
)
|
||||
let saveExpectation = self.expectationWithDescription("save")
|
||||
stack.beginAsynchronous { (transaction) in
|
||||
|
||||
if let object = transaction.fetchOne(
|
||||
From(TestEntity1),
|
||||
Where("testEntityID", isEqualTo: 101)) {
|
||||
let saveExpectation = self.expectation(description: "save")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
object.testNumber = NSNumber(integer: 11)
|
||||
object.testDecimal = NSDecimalNumber(string: "11")
|
||||
object.testString = "nil:TestEntity1:11"
|
||||
object.testData = ("nil:TestEntity1:11" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
object.testDate = self.dateFormatter.dateFromString("2000-01-11T00:00:00Z")!
|
||||
}
|
||||
else {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
if let object = transaction.fetchOne(
|
||||
From(TestEntity1),
|
||||
Where("testEntityID", isEqualTo: 102)) {
|
||||
|
||||
object.testNumber = NSNumber(integer: 22)
|
||||
object.testDecimal = NSDecimalNumber(string: "22")
|
||||
object.testString = "nil:TestEntity1:22"
|
||||
object.testData = ("nil:TestEntity1:22" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
object.testDate = self.dateFormatter.dateFromString("2000-01-22T00:00:00Z")!
|
||||
}
|
||||
else {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
transaction.commit { (result) in
|
||||
|
||||
switch result {
|
||||
if let object = try transaction.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
object.testNumber = NSNumber(value: 11)
|
||||
object.testDecimal = NSDecimalNumber(string: "11")
|
||||
object.testString = "nil:TestEntity1:11"
|
||||
object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||
object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
|
||||
}
|
||||
else {
|
||||
|
||||
case .Failure:
|
||||
XCTFail()
|
||||
}
|
||||
if let object = try transaction.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
|
||||
object.testNumber = NSNumber(value: 22)
|
||||
object.testDecimal = NSDecimalNumber(string: "22")
|
||||
object.testString = "nil:TestEntity1:22"
|
||||
object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||
object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
|
||||
}
|
||||
else {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
}
|
||||
}
|
||||
@@ -324,21 +321,21 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
let observer = TestListObserver()
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From(TestEntity1),
|
||||
SectionBy("testBoolean"),
|
||||
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
var events = 0
|
||||
|
||||
let willChangeExpectation = self.expectationForNotification(
|
||||
"listMonitorWillChange:",
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 0)
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -346,8 +343,8 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
let didMoveObjectExpectation = self.expectationForNotification(
|
||||
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
|
||||
let didMoveObjectExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -356,21 +353,21 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
let userInfo = note.userInfo
|
||||
XCTAssertNotNil(userInfo)
|
||||
XCTAssertEqual(
|
||||
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
|
||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
["fromIndexPath", "toIndexPath", "object"]
|
||||
)
|
||||
|
||||
let fromIndexPath = userInfo?["fromIndexPath"] as? NSIndexPath
|
||||
XCTAssertEqual(fromIndexPath?.section, 0)
|
||||
XCTAssertEqual(fromIndexPath?.row, 0)
|
||||
XCTAssertEqual(fromIndexPath?.index(atPosition: 0), 0)
|
||||
XCTAssertEqual(fromIndexPath?.index(atPosition: 1), 0)
|
||||
|
||||
let toIndexPath = userInfo?["toIndexPath"] as? NSIndexPath
|
||||
XCTAssertEqual(toIndexPath?.section, 1)
|
||||
XCTAssertEqual(toIndexPath?.row, 1)
|
||||
XCTAssertEqual(toIndexPath?.index(atPosition: 0), 1)
|
||||
XCTAssertEqual(toIndexPath?.index(atPosition: 1), 1)
|
||||
|
||||
let object = userInfo?["object"] as? TestEntity1
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(integer: 102))
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(bool: true))
|
||||
XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
|
||||
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
|
||||
|
||||
defer {
|
||||
|
||||
@@ -379,13 +376,13 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 1
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectationForNotification(
|
||||
"listMonitorDidChange:",
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 2)
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -393,32 +390,32 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 2
|
||||
}
|
||||
)
|
||||
let saveExpectation = self.expectationWithDescription("save")
|
||||
stack.beginAsynchronous { (transaction) in
|
||||
|
||||
if let object = transaction.fetchOne(
|
||||
From(TestEntity1),
|
||||
Where("testEntityID", isEqualTo: 102)) {
|
||||
let saveExpectation = self.expectation(description: "save")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
object.testBoolean = NSNumber(bool: true)
|
||||
}
|
||||
else {
|
||||
if let object = try transaction.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||
|
||||
object.testBoolean = NSNumber(value: true)
|
||||
}
|
||||
else {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
transaction.commit { (result) in
|
||||
|
||||
switch result {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
|
||||
case .Failure:
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
}
|
||||
}
|
||||
@@ -432,21 +429,21 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
let observer = TestListObserver()
|
||||
let monitor = stack.monitorSectionedList(
|
||||
From(TestEntity1),
|
||||
SectionBy("testBoolean"),
|
||||
OrderBy(.Ascending("testBoolean"), .Ascending("testEntityID"))
|
||||
From<TestEntity1>(),
|
||||
SectionBy(#keyPath(TestEntity1.testBoolean)),
|
||||
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
|
||||
)
|
||||
monitor.addObserver(observer)
|
||||
|
||||
var events = 0
|
||||
|
||||
let willChangeExpectation = self.expectationForNotification(
|
||||
"listMonitorWillChange:",
|
||||
let willChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 0)
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -454,40 +451,37 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
for _ in 1 ... 2 {
|
||||
|
||||
let didUpdateObjectExpectation = self.expectationForNotification(
|
||||
"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 as? [String: AnyObject]) ?? [:]).keys),
|
||||
["indexPath", "object"]
|
||||
)
|
||||
|
||||
let indexPath = userInfo?["indexPath"] as? NSIndexPath
|
||||
|
||||
XCTAssertEqual(indexPath?.section, 0)
|
||||
XCTAssert(indexPath?.row == 0 || indexPath?.row == 1)
|
||||
|
||||
let object = userInfo?["object"] as? TestEntity1
|
||||
XCTAssertEqual(object?.deleted, true)
|
||||
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
}
|
||||
return events == 1 || events == 2
|
||||
events += 1
|
||||
}
|
||||
)
|
||||
}
|
||||
let didDeleteSectionExpectation = self.expectationForNotification(
|
||||
"listMonitor:didDeleteSection:fromSectionIndex:",
|
||||
return events == 1 || events == 2
|
||||
}
|
||||
)
|
||||
let didDeleteSectionExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
@@ -496,16 +490,16 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
let userInfo = note.userInfo
|
||||
XCTAssertNotNil(userInfo)
|
||||
XCTAssertEqual(
|
||||
Set(((userInfo as? [String: AnyObject]) ?? [:]).keys),
|
||||
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
|
||||
["sectionInfo", "sectionIndex"]
|
||||
)
|
||||
|
||||
let sectionInfo = userInfo?["sectionInfo"]
|
||||
let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
|
||||
XCTAssertNotNil(sectionInfo)
|
||||
XCTAssertEqual(sectionInfo?.name, "0")
|
||||
|
||||
let sectionIndex = userInfo?["sectionIndex"]
|
||||
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(integer: 0))
|
||||
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
|
||||
|
||||
defer {
|
||||
|
||||
@@ -514,13 +508,13 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 3
|
||||
}
|
||||
)
|
||||
let didChangeExpectation = self.expectationForNotification(
|
||||
"listMonitorDidChange:",
|
||||
let didChangeExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 4)
|
||||
XCTAssertEqual((note.userInfo ?? [:]), NSDictionary())
|
||||
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
|
||||
defer {
|
||||
|
||||
events += 1
|
||||
@@ -528,26 +522,27 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
return events == 4
|
||||
}
|
||||
)
|
||||
let saveExpectation = self.expectationWithDescription("save")
|
||||
stack.beginAsynchronous { (transaction) in
|
||||
|
||||
transaction.deleteAll(
|
||||
From(TestEntity1),
|
||||
Where("testBoolean", isEqualTo: false)
|
||||
)
|
||||
transaction.commit { (result) in
|
||||
let saveExpectation = self.expectation(description: "save")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
switch result {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
|
||||
case .Failure:
|
||||
XCTFail()
|
||||
}
|
||||
let count = try transaction.deleteAll(
|
||||
From<TestEntity1>(),
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
||||
)
|
||||
XCTAssertEqual(count, 2)
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
}
|
||||
}
|
||||
@@ -556,43 +551,44 @@ class ListObserverTests: BaseTestDataTestCase {
|
||||
|
||||
// MARK: TestListObserver
|
||||
|
||||
@available(macOS 10.12, *)
|
||||
class TestListObserver: ListSectionObserver {
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
typealias ListEntityType = TestEntity1
|
||||
|
||||
func listMonitorWillChange(monitor: ListMonitor<TestEntity1>) {
|
||||
func listMonitorWillChange(_ monitor: ListMonitor<TestEntity1>) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitorWillChange:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitorWillChange:"),
|
||||
object: self,
|
||||
userInfo: [:]
|
||||
)
|
||||
}
|
||||
|
||||
func listMonitorDidChange(monitor: ListMonitor<TestEntity1>) {
|
||||
func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitorDidChange:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitorDidChange:"),
|
||||
object: self,
|
||||
userInfo: [:]
|
||||
)
|
||||
}
|
||||
|
||||
func listMonitorWillRefetch(monitor: ListMonitor<TestEntity1>) {
|
||||
func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitorWillRefetch:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
|
||||
object: self,
|
||||
userInfo: [:]
|
||||
)
|
||||
}
|
||||
|
||||
func listMonitorDidRefetch(monitor: ListMonitor<TestEntity1>) {
|
||||
func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitorDidRefetch:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
|
||||
object: self,
|
||||
userInfo: [:]
|
||||
)
|
||||
@@ -601,10 +597,10 @@ class TestListObserver: ListSectionObserver {
|
||||
|
||||
// MARK: ListObjectObserver
|
||||
|
||||
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitor:didInsertObject:toIndexPath:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"object": object,
|
||||
@@ -613,10 +609,10 @@ class TestListObserver: ListSectionObserver {
|
||||
)
|
||||
}
|
||||
|
||||
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: IndexPath) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitor:didDeleteObject:fromIndexPath:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"object": object,
|
||||
@@ -625,10 +621,10 @@ class TestListObserver: ListSectionObserver {
|
||||
)
|
||||
}
|
||||
|
||||
func listMonitor(monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: IndexPath) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitor:didUpdateObject:atIndexPath:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"object": object,
|
||||
@@ -638,10 +634,10 @@ class TestListObserver: ListSectionObserver {
|
||||
}
|
||||
|
||||
|
||||
func listMonitor(monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
|
||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"object": object,
|
||||
@@ -654,10 +650,10 @@ class TestListObserver: ListSectionObserver {
|
||||
|
||||
// MARK: ListSectionObserver
|
||||
|
||||
func listMonitor(monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitor:didInsertSection:toSectionIndex:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"sectionInfo": sectionInfo,
|
||||
@@ -666,10 +662,10 @@ class TestListObserver: ListSectionObserver {
|
||||
)
|
||||
}
|
||||
|
||||
func listMonitor(monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"listMonitor:didDeleteSection:fromSectionIndex:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"sectionInfo": sectionInfo,
|
||||
@@ -678,5 +674,3 @@ class TestListObserver: ListSectionObserver {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
@@ -37,8 +37,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
dynamic func test_ThatNilMigrationChains_HaveNoVersions() {
|
||||
|
||||
let chain: MigrationChain = nil
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertTrue(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertTrue(chain.isEmpty)
|
||||
|
||||
XCTAssertFalse(chain.contains("version1"))
|
||||
XCTAssertNil(chain.nextVersionFrom("version1"))
|
||||
@@ -48,8 +48,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
dynamic func test_ThatStringMigrationChains_HaveOneVersion() {
|
||||
|
||||
let chain: MigrationChain = "version1"
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertTrue(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertTrue(chain.isEmpty)
|
||||
|
||||
XCTAssertTrue(chain.contains("version1"))
|
||||
XCTAssertFalse(chain.contains("version2"))
|
||||
@@ -62,8 +62,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
dynamic func test_ThatArrayMigrationChains_HaveLinearVersions() {
|
||||
|
||||
let chain: MigrationChain = ["version1", "version2", "version3", "version4"]
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertFalse(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertFalse(chain.isEmpty)
|
||||
|
||||
XCTAssertTrue(chain.contains("version1"))
|
||||
XCTAssertTrue(chain.contains("version2"))
|
||||
@@ -86,8 +86,8 @@ final class MigrationChainTests: XCTestCase {
|
||||
"version2": "version3",
|
||||
"version3": "version4"
|
||||
]
|
||||
XCTAssertTrue(chain.valid)
|
||||
XCTAssertFalse(chain.empty)
|
||||
XCTAssertTrue(chain.isValid)
|
||||
XCTAssertFalse(chain.isEmpty)
|
||||
|
||||
XCTAssertTrue(chain.contains("version1"))
|
||||
XCTAssertTrue(chain.contains("version2"))
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10174" systemVersion="15F34" minimumToolsVersion="Xcode 4.3">
|
||||
<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" syncable="YES"/>
|
||||
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
|
||||
<attribute name="testDate" optional="YES" attributeType="Date" syncable="YES"/>
|
||||
<attribute name="testDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
|
||||
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="testNumber" optional="YES" attributeType="Integer 32" 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" syncable="YES"/>
|
||||
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
|
||||
<attribute name="testDate" optional="YES" attributeType="Date" syncable="YES"/>
|
||||
<attribute name="testDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testDecimal" optional="YES" attributeType="Decimal" syncable="YES"/>
|
||||
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" syncable="YES"/>
|
||||
<attribute name="testEntityID" optional="YES" attributeType="Integer 64" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="testNumber" optional="YES" attributeType="Integer 32" 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
|
||||
@@ -29,10 +29,9 @@ import XCTest
|
||||
import CoreStore
|
||||
|
||||
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
|
||||
// MARK: - ObjectObserverTests
|
||||
|
||||
@available(macOS 10.12, *)
|
||||
class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
@objc
|
||||
@@ -42,9 +41,9 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
self.prepareTestDataForStack(stack)
|
||||
|
||||
guard let object = stack.fetchOne(
|
||||
From(TestEntity1),
|
||||
Where("testEntityID", isEqualTo: 101)) else {
|
||||
guard let object = try stack.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -58,14 +57,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
var events = 0
|
||||
|
||||
let willUpdateExpectation = self.expectationForNotification(
|
||||
"objectMonitor:willUpdateObject:",
|
||||
let willUpdateExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 0)
|
||||
XCTAssertEqual(
|
||||
(note.userInfo ?? [:]),
|
||||
((note.userInfo as NSDictionary?) ?? [:]),
|
||||
["object": object] as NSDictionary
|
||||
)
|
||||
defer {
|
||||
@@ -75,26 +74,26 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
let didUpdateExpectation = self.expectationForNotification(
|
||||
"objectMonitor:didUpdateObject:changedPersistentKeys:",
|
||||
let didUpdateExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 1)
|
||||
XCTAssertEqual(
|
||||
(note.userInfo ?? [:]),
|
||||
((note.userInfo as NSDictionary?) ?? [:]),
|
||||
[
|
||||
"object": object,
|
||||
"changedPersistentKeys": Set(
|
||||
[
|
||||
"testNumber",
|
||||
"testString"
|
||||
#keyPath(TestEntity1.testNumber),
|
||||
#keyPath(TestEntity1.testString)
|
||||
]
|
||||
)
|
||||
] as NSDictionary
|
||||
)
|
||||
let object = note.userInfo?["object"] as? TestEntity1
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(integer: 10))
|
||||
XCTAssertEqual(object?.testNumber, NSNumber(value: 10))
|
||||
XCTAssertEqual(object?.testString, "nil:TestEntity1:10")
|
||||
|
||||
defer {
|
||||
@@ -104,30 +103,30 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
return events == 1
|
||||
}
|
||||
)
|
||||
let saveExpectation = self.expectationWithDescription("save")
|
||||
stack.beginAsynchronous { (transaction) in
|
||||
|
||||
guard let object = transaction.edit(object) else {
|
||||
let saveExpectation = self.expectation(description: "save")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
guard let object = transaction.edit(object) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
}
|
||||
object.testNumber = NSNumber(value: 10)
|
||||
object.testString = "nil:TestEntity1:10"
|
||||
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
object.testNumber = NSNumber(integer: 10)
|
||||
object.testString = "nil:TestEntity1:10"
|
||||
|
||||
transaction.commit { (result) in
|
||||
|
||||
switch result {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges)
|
||||
saveExpectation.fulfill()
|
||||
|
||||
case .Failure:
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
}
|
||||
}
|
||||
@@ -139,9 +138,9 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
self.prepareTestDataForStack(stack)
|
||||
|
||||
guard let object = stack.fetchOne(
|
||||
From(TestEntity1),
|
||||
Where("testEntityID", isEqualTo: 101)) else {
|
||||
guard let object = try stack.fetchOne(
|
||||
From<TestEntity1>(),
|
||||
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
@@ -155,14 +154,14 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
var events = 0
|
||||
|
||||
let didDeleteExpectation = self.expectationForNotification(
|
||||
"objectMonitor:didDeleteObject:",
|
||||
let didDeleteExpectation = self.expectation(
|
||||
forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
|
||||
object: observer,
|
||||
handler: { (note) -> Bool in
|
||||
|
||||
XCTAssertEqual(events, 0)
|
||||
XCTAssertEqual(
|
||||
(note.userInfo ?? [:]),
|
||||
((note.userInfo as NSDictionary?) ?? [:]),
|
||||
["object": object] as NSDictionary
|
||||
)
|
||||
defer {
|
||||
@@ -172,30 +171,30 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
return events == 0
|
||||
}
|
||||
)
|
||||
let saveExpectation = self.expectationWithDescription("save")
|
||||
stack.beginAsynchronous { (transaction) in
|
||||
|
||||
guard let object = transaction.edit(object) else {
|
||||
let saveExpectation = self.expectation(description: "save")
|
||||
stack.perform(
|
||||
asynchronous: { (transaction) -> Bool in
|
||||
|
||||
guard let object = transaction.edit(object) else {
|
||||
|
||||
XCTFail()
|
||||
try transaction.cancel()
|
||||
}
|
||||
transaction.delete(object)
|
||||
|
||||
return transaction.hasChanges
|
||||
},
|
||||
success: { (hasChanges) in
|
||||
|
||||
XCTAssertTrue(hasChanges)
|
||||
XCTAssertTrue(monitor.isObjectDeleted)
|
||||
saveExpectation.fulfill()
|
||||
},
|
||||
failure: { _ in
|
||||
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
transaction.delete(object)
|
||||
|
||||
transaction.commit { (result) in
|
||||
|
||||
switch result {
|
||||
|
||||
case .Success(let hasChanges):
|
||||
XCTAssertTrue(hasChanges)
|
||||
XCTAssertTrue(monitor.isObjectDeleted)
|
||||
saveExpectation.fulfill()
|
||||
|
||||
case .Failure:
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.waitAndCheckExpectations()
|
||||
}
|
||||
}
|
||||
@@ -204,14 +203,15 @@ class ObjectObserverTests: BaseTestDataTestCase {
|
||||
|
||||
// MARK: TestObjectObserver
|
||||
|
||||
@available(macOS 10.12, *)
|
||||
class TestObjectObserver: ObjectObserver {
|
||||
|
||||
typealias ObjectEntityType = TestEntity1
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"objectMonitor:willUpdateObject:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "objectMonitor:willUpdateObject:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"object": object
|
||||
@@ -219,10 +219,10 @@ class TestObjectObserver: ObjectObserver {
|
||||
)
|
||||
}
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<KeyPath>) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<String>) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"objectMonitor:didUpdateObject:changedPersistentKeys:",
|
||||
NotificationCenter.default.post(
|
||||
name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"object": object,
|
||||
@@ -231,10 +231,10 @@ class TestObjectObserver: ObjectObserver {
|
||||
)
|
||||
}
|
||||
|
||||
func objectMonitor(monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) {
|
||||
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) {
|
||||
|
||||
NSNotificationCenter.defaultCenter().postNotificationName(
|
||||
"objectMonitor:didDeleteObject:",
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name(rawValue: "objectMonitor:didDeleteObject:"),
|
||||
object: self,
|
||||
userInfo: [
|
||||
"object": object
|
||||
@@ -242,5 +242,3 @@ class TestObjectObserver: ObjectObserver {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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([] as [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 = NSFetchRequest()
|
||||
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
|
||||
@@ -29,10 +29,9 @@ import XCTest
|
||||
import CoreStore
|
||||
|
||||
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
|
||||
//MARK: - SectionByTests
|
||||
|
||||
@available(macOS 10.12, *)
|
||||
final class SectionByTests: XCTestCase {
|
||||
|
||||
@objc
|
||||
@@ -40,18 +39,16 @@ final class SectionByTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let sectionBy = SectionBy("key")
|
||||
let sectionBy = SectionBy<NSManagedObject>("key")
|
||||
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
|
||||
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key")
|
||||
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key")
|
||||
}
|
||||
do {
|
||||
|
||||
let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } }
|
||||
let sectionBy = SectionBy<NSManagedObject>("key") { $0.flatMap { "\($0):suffix" } }
|
||||
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
|
||||
XCTAssertEqual(sectionBy.sectionIndexTransformer(sectionName: "key"), "key:suffix")
|
||||
XCTAssertNil(sectionBy.sectionIndexTransformer(sectionName: nil))
|
||||
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
|
||||
XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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,18 +38,18 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term: SelectTerm = "attribute"
|
||||
XCTAssertEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term: SelectTerm<NSManagedObject> = "attribute"
|
||||
XCTAssertEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Attribute(let key):
|
||||
case ._attribute(let key):
|
||||
XCTAssertEqual(key, "attribute")
|
||||
|
||||
default:
|
||||
@@ -58,17 +58,17 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Attribute("attribute")
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.attribute("attribute")
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Attribute(let key):
|
||||
case ._attribute(let key):
|
||||
XCTAssertEqual(key, "attribute")
|
||||
|
||||
default:
|
||||
@@ -82,23 +82,23 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Average("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.average("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "average:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "average(attribute)")
|
||||
XCTAssertTrue(nativeType == .DecimalAttributeType)
|
||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -106,23 +106,23 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Average("attribute", As: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.Average("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute", As: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.average("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "average:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "alias")
|
||||
XCTAssertTrue(nativeType == .DecimalAttributeType)
|
||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -135,23 +135,23 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Count("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.count("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "count:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "count(attribute)")
|
||||
XCTAssertTrue(nativeType == .Integer64AttributeType)
|
||||
XCTAssertTrue(nativeType == .integer64AttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -159,23 +159,23 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Count("attribute", As: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.Count("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute", As: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.count("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "count:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "alias")
|
||||
XCTAssertTrue(nativeType == .Integer64AttributeType)
|
||||
XCTAssertTrue(nativeType == .integer64AttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -188,23 +188,23 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Maximum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.maximum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "max:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "max(attribute)")
|
||||
XCTAssertTrue(nativeType == .UndefinedAttributeType)
|
||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -212,23 +212,23 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Maximum("attribute", As: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.Maximum("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute", As: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.maximum("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "max:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "alias")
|
||||
XCTAssertTrue(nativeType == .UndefinedAttributeType)
|
||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -241,23 +241,23 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Minimum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.minimum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "min:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "min(attribute)")
|
||||
XCTAssertTrue(nativeType == .UndefinedAttributeType)
|
||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -265,23 +265,23 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Minimum("attribute", As: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.Minimum("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute", As: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.minimum("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "min:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "alias")
|
||||
XCTAssertTrue(nativeType == .UndefinedAttributeType)
|
||||
XCTAssertTrue(nativeType == .undefinedAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -294,23 +294,23 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Sum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.Sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.sum("attribute")
|
||||
XCTAssertEqual(term, SelectTerm.sum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "sum:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "sum(attribute)")
|
||||
XCTAssertTrue(nativeType == .DecimalAttributeType)
|
||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -318,23 +318,23 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.Sum("attribute", As: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.Sum("attribute", As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute", As: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
let term = SelectTerm<NSManagedObject>.sum("attribute", as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
switch term {
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
case ._aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
XCTAssertEqual(function, "sum:")
|
||||
XCTAssertEqual(keyPath, "attribute")
|
||||
XCTAssertEqual(alias, "alias")
|
||||
XCTAssertTrue(nativeType == .DecimalAttributeType)
|
||||
XCTAssertTrue(nativeType == .decimalAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -347,20 +347,20 @@ final class SelectTests: XCTestCase {
|
||||
|
||||
do {
|
||||
|
||||
let term = SelectTerm.ObjectID()
|
||||
XCTAssertEqual(term, SelectTerm.ObjectID())
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID(As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
let term = SelectTerm<NSManagedObject>.objectID()
|
||||
XCTAssertEqual(term, SelectTerm.objectID())
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
switch term {
|
||||
|
||||
case ._Identity(let alias, let nativeType):
|
||||
case ._identity(let alias, let nativeType):
|
||||
XCTAssertEqual(alias, "objectID")
|
||||
XCTAssertTrue(nativeType == .ObjectIDAttributeType)
|
||||
XCTAssertTrue(nativeType == .objectIDAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -368,21 +368,21 @@ final class SelectTests: XCTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let term = SelectTerm.ObjectID(As: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.ObjectID(As: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID(As: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.ObjectID())
|
||||
XCTAssertNotEqual(term, SelectTerm.Attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.Sum("attribute"))
|
||||
let term = SelectTerm<NSManagedObject>.objectID(as: "alias")
|
||||
XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
|
||||
XCTAssertNotEqual(term, SelectTerm.objectID())
|
||||
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
|
||||
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
|
||||
switch term {
|
||||
|
||||
case ._Identity(let alias, let nativeType):
|
||||
case ._identity(let alias, let nativeType):
|
||||
XCTAssertEqual(alias, "alias")
|
||||
XCTAssertTrue(nativeType == .ObjectIDAttributeType)
|
||||
XCTAssertTrue(nativeType == .objectIDAttributeType)
|
||||
|
||||
default:
|
||||
XCTFail()
|
||||
@@ -393,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
|
||||
@@ -29,43 +29,51 @@ import CoreStore
|
||||
|
||||
// MARK: - SetupTests
|
||||
|
||||
class SetupTests: BaseTestCase {
|
||||
class SetupTests: BaseTestDataTestCase {
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatDataStacks_ConfigureCorrectly() {
|
||||
|
||||
do {
|
||||
|
||||
let model = NSManagedObjectModel.mergedModelFromBundles([NSBundle(forClass: self.dynamicType)])!
|
||||
|
||||
let stack = DataStack(model: model, migrationChain: nil)
|
||||
XCTAssertEqual(stack.coordinator.managedObjectModel, model)
|
||||
let schemaHistory = SchemaHistory(
|
||||
XcodeDataModelSchema.from(
|
||||
modelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
)
|
||||
let stack = DataStack(schemaHistory: schemaHistory)
|
||||
XCTAssertEqual(stack.coordinator.managedObjectModel, schemaHistory.rawModel)
|
||||
XCTAssertEqual(stack.rootSavingContext.persistentStoreCoordinator, stack.coordinator)
|
||||
XCTAssertNil(stack.rootSavingContext.parentContext)
|
||||
XCTAssertEqual(stack.mainContext.parentContext, stack.rootSavingContext)
|
||||
XCTAssertEqual(stack.model, model)
|
||||
XCTAssertTrue(stack.migrationChain.valid)
|
||||
XCTAssertTrue(stack.migrationChain.empty)
|
||||
XCTAssertTrue(stack.migrationChain.rootVersions.isEmpty)
|
||||
XCTAssertTrue(stack.migrationChain.leafVersions.isEmpty)
|
||||
XCTAssertNil(stack.rootSavingContext.parent)
|
||||
XCTAssertFalse(stack.rootSavingContext.isDataStackContext)
|
||||
XCTAssertFalse(stack.rootSavingContext.isTransactionContext)
|
||||
XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
|
||||
XCTAssertTrue(stack.mainContext.isDataStackContext)
|
||||
XCTAssertFalse(stack.mainContext.isTransactionContext)
|
||||
XCTAssertEqual(stack.schemaHistory.rawModel, schemaHistory.rawModel)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.isValid)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.isEmpty)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.rootVersions.isEmpty)
|
||||
XCTAssertTrue(stack.schemaHistory.migrationChain.leafVersions.isEmpty)
|
||||
|
||||
CoreStore.defaultStack = stack
|
||||
XCTAssertEqual(CoreStore.defaultStack, stack)
|
||||
}
|
||||
do {
|
||||
|
||||
let migrationChain: MigrationChain = ["version1", "version2", "version3"]
|
||||
let migrationChain: MigrationChain = ["version1", "version2", "version3", "Model"]
|
||||
|
||||
let stack = self.expectLogger([.LogWarning]) {
|
||||
let stack = self.expectLogger([.logWarning]) {
|
||||
|
||||
DataStack(
|
||||
modelName: "Model",
|
||||
bundle: NSBundle(forClass: self.dynamicType),
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self)),
|
||||
migrationChain: migrationChain
|
||||
)
|
||||
}
|
||||
XCTAssertEqual(stack.modelVersion, "Model")
|
||||
XCTAssertEqual(stack.migrationChain, migrationChain)
|
||||
XCTAssertEqual(stack.schemaHistory.migrationChain, migrationChain)
|
||||
|
||||
CoreStore.defaultStack = stack
|
||||
XCTAssertEqual(CoreStore.defaultStack, stack)
|
||||
@@ -76,8 +84,8 @@ class SetupTests: BaseTestCase {
|
||||
dynamic func test_ThatInMemoryStores_SetupCorrectly() {
|
||||
|
||||
let stack = DataStack(
|
||||
modelName: "Model",
|
||||
bundle: NSBundle(forClass: self.dynamicType)
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -131,8 +139,8 @@ class SetupTests: BaseTestCase {
|
||||
dynamic func test_ThatSQLiteStores_SetupCorrectly() {
|
||||
|
||||
let stack = DataStack(
|
||||
modelName: "Model",
|
||||
bundle: NSBundle(forClass: self.dynamicType)
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -154,7 +162,7 @@ class SetupTests: BaseTestCase {
|
||||
let sqliteStore = SQLiteStore(
|
||||
fileName: "ConfigStore1.sqlite",
|
||||
configuration: "Config1",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -173,7 +181,7 @@ class SetupTests: BaseTestCase {
|
||||
let sqliteStore = SQLiteStore(
|
||||
fileName: "ConfigStore2.sqlite",
|
||||
configuration: "Config2",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -189,16 +197,74 @@ class SetupTests: BaseTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatSQLiteStores_DeleteFilesCorrectly() {
|
||||
|
||||
let fileManager = FileManager.default
|
||||
let sqliteStore = SQLiteStore()
|
||||
func createStore() throws -> [String: Any] {
|
||||
|
||||
do {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
try! stack.addStorageAndWait(sqliteStore)
|
||||
self.prepareTestDataForStack(stack)
|
||||
}
|
||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
|
||||
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
|
||||
ofType: type(of: sqliteStore).storeType,
|
||||
at: sqliteStore.fileURL,
|
||||
options: sqliteStore.storeOptions
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let metadata = try createStore()
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
try sqliteStore.cs_eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
|
||||
)
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
do {
|
||||
|
||||
let metadata = try createStore()
|
||||
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() {
|
||||
|
||||
let stack = DataStack(
|
||||
modelName: "Model",
|
||||
bundle: NSBundle(forClass: self.dynamicType)
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
do {
|
||||
|
||||
let sqliteStore = SQLiteStore()
|
||||
let sqliteStore = SQLiteStore.legacy()
|
||||
do {
|
||||
|
||||
try stack.addStorageAndWait(sqliteStore)
|
||||
@@ -213,10 +279,10 @@ class SetupTests: BaseTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let sqliteStore = SQLiteStore(
|
||||
let sqliteStore = SQLiteStore.legacy(
|
||||
fileName: "ConfigStore1.sqlite",
|
||||
configuration: "Config1",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -232,10 +298,10 @@ class SetupTests: BaseTestCase {
|
||||
}
|
||||
do {
|
||||
|
||||
let sqliteStore = SQLiteStore(
|
||||
let sqliteStore = SQLiteStore.legacy(
|
||||
fileName: "ConfigStore2.sqlite",
|
||||
configuration: "Config2",
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
do {
|
||||
|
||||
@@ -250,4 +316,69 @@ class SetupTests: BaseTestCase {
|
||||
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatLegacySQLiteStores_DeleteFilesCorrectly() {
|
||||
|
||||
let fileManager = FileManager.default
|
||||
let sqliteStore = SQLiteStore.legacy()
|
||||
func createStore() throws -> [String: Any] {
|
||||
|
||||
do {
|
||||
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
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))
|
||||
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
|
||||
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
|
||||
ofType: type(of: sqliteStore).storeType,
|
||||
at: sqliteStore.fileURL,
|
||||
options: sqliteStore.storeOptions
|
||||
)
|
||||
}
|
||||
do {
|
||||
|
||||
let metadata = try createStore()
|
||||
let stack = DataStack(
|
||||
xcodeModelName: "Model",
|
||||
bundle: Bundle(for: type(of: self))
|
||||
)
|
||||
try sqliteStore.cs_eraseStorageAndWait(
|
||||
metadata: metadata,
|
||||
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
|
||||
)
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
do {
|
||||
|
||||
let metadata = try createStore()
|
||||
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
|
||||
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
|
||||
}
|
||||
catch {
|
||||
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -37,7 +37,7 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
dynamic func test_ThatDefaultInMemoryStores_ConfigureCorrectly() {
|
||||
|
||||
let store = InMemoryStore()
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSInMemoryStoreType)
|
||||
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
|
||||
XCTAssertNil(store.configuration)
|
||||
XCTAssertNil(store.storeOptions)
|
||||
}
|
||||
@@ -46,7 +46,7 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
dynamic func test_ThatCustomInMemoryStores_ConfigureCorrectly() {
|
||||
|
||||
let store = InMemoryStore(configuration: "config1")
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSInMemoryStoreType)
|
||||
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertNil(store.storeOptions)
|
||||
}
|
||||
@@ -55,23 +55,23 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
dynamic func test_ThatSQLiteStoreDefaultDirectories_AreCorrect() {
|
||||
|
||||
#if os(tvOS)
|
||||
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
|
||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
|
||||
#else
|
||||
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
|
||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
|
||||
#endif
|
||||
|
||||
let defaultSystemDirectory = NSFileManager
|
||||
.defaultManager()
|
||||
.URLsForDirectory(systemDirectorySearchPath, inDomains: .UserDomainMask).first!
|
||||
let defaultSystemDirectory = FileManager.default
|
||||
.urls(for: systemDirectorySearchPath, in: .userDomainMask).first!
|
||||
|
||||
let defaultRootDirectory = defaultSystemDirectory.URLByAppendingPathComponent(
|
||||
NSBundle.mainBundle().bundleIdentifier ?? "com.CoreStore.DataStack",
|
||||
isDirectory: true)!
|
||||
let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData"
|
||||
let defaultRootDirectory = defaultSystemDirectory.appendingPathComponent(
|
||||
Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
|
||||
isDirectory: true
|
||||
)
|
||||
let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
|
||||
|
||||
let defaultFileURL = defaultRootDirectory
|
||||
.URLByAppendingPathComponent(applicationName, isDirectory: false)!
|
||||
.URLByAppendingPathExtension("sqlite")!
|
||||
.appendingPathComponent(applicationName, isDirectory: false)
|
||||
.appendingPathExtension("sqlite")
|
||||
|
||||
XCTAssertEqual(SQLiteStore.defaultRootDirectory, defaultRootDirectory)
|
||||
XCTAssertEqual(SQLiteStore.defaultFileURL, defaultFileURL)
|
||||
@@ -81,137 +81,190 @@ final class StorageInterfaceTests: XCTestCase {
|
||||
dynamic func test_ThatDefaultSQLiteStores_ConfigureCorrectly() {
|
||||
|
||||
let store = SQLiteStore()
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertNil(store.configuration)
|
||||
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
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)
|
||||
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles())
|
||||
XCTAssertEqual(store.localStorageOptions, [.None])
|
||||
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
|
||||
XCTAssertEqual(store.localStorageOptions, .none)
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
|
||||
|
||||
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
|
||||
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false)!
|
||||
.URLByAppendingPathExtension("db")!
|
||||
let bundles = [NSBundle(forClass: self.dynamicType)]
|
||||
let fileURL = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent(UUID().uuidString, isDirectory: false)
|
||||
.appendingPathExtension("db")
|
||||
let mappingProvider = XcodeSchemaMappingProvider(
|
||||
from: "V1", to: "V2",
|
||||
mappingModelBundle: Bundle(for: type(of: self))
|
||||
)
|
||||
|
||||
let store = SQLiteStore(
|
||||
fileURL: fileURL,
|
||||
configuration: "config1",
|
||||
mappingModelBundles: bundles,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
migrationMappingProviders: [mappingProvider],
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
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.mappingModelBundles, bundles)
|
||||
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
|
||||
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
|
||||
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatFileNameSQLiteStores_ConfigureCorrectly() {
|
||||
|
||||
let fileName = NSUUID().UUIDString + ".db"
|
||||
let bundles = [NSBundle(forClass: self.dynamicType)]
|
||||
|
||||
let fileName = UUID().uuidString + ".db"
|
||||
let mappingProvider = XcodeSchemaMappingProvider(
|
||||
from: "V1", to: "V2",
|
||||
mappingModelBundle: Bundle(for: type(of: self))
|
||||
)
|
||||
let store = SQLiteStore(
|
||||
fileName: fileName,
|
||||
configuration: "config1",
|
||||
mappingModelBundles: bundles,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
migrationMappingProviders: [mappingProvider],
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
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.URLByDeletingLastPathComponent, SQLiteStore.defaultRootDirectory)
|
||||
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.defaultRootDirectory)
|
||||
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
|
||||
XCTAssertEqual(store.mappingModelBundles, bundles)
|
||||
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
|
||||
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
|
||||
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatLegacySQLiteStoreDefaultDirectories_AreCorrect() {
|
||||
|
||||
#if os(tvOS)
|
||||
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
|
||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
|
||||
#else
|
||||
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
|
||||
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
|
||||
#endif
|
||||
|
||||
let legacyDefaultRootDirectory = NSFileManager.defaultManager().URLsForDirectory(
|
||||
systemDirectorySearchPath,
|
||||
inDomains: .UserDomainMask
|
||||
).first!
|
||||
let legacyDefaultRootDirectory = FileManager.default.urls(
|
||||
for: systemDirectorySearchPath,
|
||||
in: .userDomainMask).first!
|
||||
|
||||
let legacyDefaultFileURL = legacyDefaultRootDirectory
|
||||
.URLByAppendingPathComponent(DataStack.applicationName, isDirectory: false)!
|
||||
.URLByAppendingPathExtension("sqlite")!
|
||||
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
|
||||
.appendingPathExtension("sqlite")
|
||||
|
||||
XCTAssertEqual(LegacySQLiteStore.defaultRootDirectory, legacyDefaultRootDirectory)
|
||||
XCTAssertEqual(LegacySQLiteStore.defaultFileURL, legacyDefaultFileURL)
|
||||
XCTAssertEqual(SQLiteStore.legacyDefaultRootDirectory, legacyDefaultRootDirectory)
|
||||
XCTAssertEqual(SQLiteStore.legacyDefaultFileURL, legacyDefaultFileURL)
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatDefaultLegacySQLiteStores_ConfigureCorrectly() {
|
||||
|
||||
let store = LegacySQLiteStore()
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
|
||||
let store = SQLiteStore.legacy()
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertNil(store.configuration)
|
||||
XCTAssertEqual(store.storeOptions, [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, LegacySQLiteStore.defaultFileURL)
|
||||
XCTAssertEqual(store.mappingModelBundles, NSBundle.allBundles())
|
||||
XCTAssertEqual(store.localStorageOptions, [.None])
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatFileURLLegacySQLiteStores_ConfigureCorrectly() {
|
||||
|
||||
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
|
||||
.URLByAppendingPathComponent(NSUUID().UUIDString, isDirectory: false)!
|
||||
.URLByAppendingPathExtension("db")!
|
||||
let bundles = [NSBundle(forClass: self.dynamicType)]
|
||||
|
||||
let store = LegacySQLiteStore(
|
||||
fileURL: fileURL,
|
||||
configuration: "config1",
|
||||
mappingModelBundles: bundles,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
)
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
|
||||
XCTAssertEqual(store.fileURL, fileURL)
|
||||
XCTAssertEqual(store.mappingModelBundles, bundles)
|
||||
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
|
||||
XCTAssertEqual(store.fileURL, SQLiteStore.legacyDefaultFileURL)
|
||||
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
|
||||
XCTAssertEqual(store.localStorageOptions, .none)
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatFileNameLegacySQLiteStores_ConfigureCorrectly() {
|
||||
|
||||
let fileName = NSUUID().UUIDString + ".db"
|
||||
let bundles = [NSBundle(forClass: self.dynamicType)]
|
||||
|
||||
let store = LegacySQLiteStore(
|
||||
let fileName = UUID().uuidString + ".db"
|
||||
let mappingProvider = XcodeSchemaMappingProvider(
|
||||
from: "V1", to: "V2",
|
||||
mappingModelBundle: Bundle(for: type(of: self))
|
||||
)
|
||||
let store = SQLiteStore.legacy(
|
||||
fileName: fileName,
|
||||
configuration: "config1",
|
||||
mappingModelBundles: bundles,
|
||||
localStorageOptions: .RecreateStoreOnModelMismatch
|
||||
migrationMappingProviders: [mappingProvider],
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
XCTAssertEqual(store.dynamicType.storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
|
||||
XCTAssertEqual(store.configuration, "config1")
|
||||
XCTAssertEqual(store.storeOptions, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
|
||||
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.URLByDeletingLastPathComponent, LegacySQLiteStore.defaultRootDirectory)
|
||||
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.legacyDefaultRootDirectory)
|
||||
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
|
||||
XCTAssertEqual(store.mappingModelBundles, bundles)
|
||||
XCTAssertEqual(store.localStorageOptions, [.RecreateStoreOnModelMismatch])
|
||||
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
|
||||
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -31,9 +31,11 @@ class TestEntity1: NSManagedObject {
|
||||
@NSManaged var testEntityID: NSNumber?
|
||||
@NSManaged var testString: String?
|
||||
@NSManaged var testNumber: NSNumber?
|
||||
@NSManaged var testDate: NSDate?
|
||||
@NSManaged var testDate: Date?
|
||||
@NSManaged var testBoolean: NSNumber?
|
||||
@NSManaged var testDecimal: NSDecimalNumber?
|
||||
@NSManaged var testData: NSData?
|
||||
@NSManaged var testData: Data?
|
||||
@NSManaged var testNil: String?
|
||||
@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
|
||||
@@ -31,9 +31,11 @@ class TestEntity2: NSManagedObject {
|
||||
@NSManaged var testEntityID: NSNumber?
|
||||
@NSManaged var testString: String?
|
||||
@NSManaged var testNumber: NSNumber?
|
||||
@NSManaged var testDate: NSDate?
|
||||
@NSManaged var testDate: Date?
|
||||
@NSManaged var testBoolean: NSNumber?
|
||||
@NSManaged var testDecimal: NSDecimalNumber?
|
||||
@NSManaged var testData: NSData?
|
||||
@NSManaged var testData: Data?
|
||||
@NSManaged var testNil: String?
|
||||
@NSManaged var testToOne: TestEntity2?
|
||||
@NSManaged var testToManyOrdered: NSOrderedSet?
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 = NSFetchRequest()
|
||||
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
|
||||
@@ -29,76 +29,487 @@ import XCTest
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - XCTAssertAllEqual
|
||||
|
||||
private func XCTAssertAllEqual<D>(_ whereClauses: Where<D>...) {
|
||||
|
||||
XCTAssertAllEqual(whereClauses)
|
||||
}
|
||||
|
||||
private func XCTAssertAllEqual<D>(_ whereClauses: [Where<D>]) {
|
||||
|
||||
for i in whereClauses.indices {
|
||||
|
||||
for j in whereClauses.indices where j != i {
|
||||
|
||||
XCTAssertEqual(whereClauses[i], whereClauses[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: - WhereTests
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
dynamic func test_ThatWhereClauses_BridgeArgumentsCorrectly() {
|
||||
|
||||
do {
|
||||
|
||||
let value: Int = 100
|
||||
XCTAssertAllEqual(
|
||||
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<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<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<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<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<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<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<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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
let notWhere = !whereClause1
|
||||
let notPredicate = NSCompoundPredicate(
|
||||
type: .NotPredicateType,
|
||||
type: .not,
|
||||
subpredicates: [whereClause1.predicate]
|
||||
)
|
||||
XCTAssertEqual(notWhere.predicate, notPredicate)
|
||||
@@ -108,10 +519,10 @@ final class WhereTests: XCTestCase {
|
||||
|
||||
let andWhere = whereClause1 && whereClause2 && whereClause3
|
||||
let andPredicate = NSCompoundPredicate(
|
||||
type: .AndPredicateType,
|
||||
type: .and,
|
||||
subpredicates: [
|
||||
NSCompoundPredicate(
|
||||
type: .AndPredicateType,
|
||||
type: .and,
|
||||
subpredicates: [whereClause1.predicate, whereClause2.predicate]
|
||||
),
|
||||
whereClause3.predicate
|
||||
@@ -120,14 +531,29 @@ 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
|
||||
let orPredicate = NSCompoundPredicate(
|
||||
type: .OrPredicateType,
|
||||
type: .or,
|
||||
subpredicates: [
|
||||
NSCompoundPredicate(
|
||||
type: .OrPredicateType,
|
||||
type: .or,
|
||||
subpredicates: [whereClause1.predicate, whereClause2.predicate]
|
||||
),
|
||||
whereClause3.predicate
|
||||
@@ -136,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 = NSFetchRequest()
|
||||
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,27 +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,
|
||||
dependencies: [
|
||||
.Package(
|
||||
url: "https://github.com/JohnEstropia/GCDKit.git",
|
||||
"1.2.6"
|
||||
)
|
||||
products: [
|
||||
.library(name: "CoreStore", type: .static, targets: ["CoreStore"])
|
||||
],
|
||||
exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"]
|
||||
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>
|
||||
181
Sources/AsynchronousDataTransaction.swift
Normal file
181
Sources/AsynchronousDataTransaction.swift
Normal file
@@ -0,0 +1,181 @@
|
||||
//
|
||||
// AsynchronousDataTransaction.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: - AsynchronousDataTransaction
|
||||
|
||||
/**
|
||||
The `AsynchronousDataTransaction` provides an interface for `DynamicObject` creates, updates, and deletes. A transaction object should typically be only used from within a transaction block initiated from `DataStack.perform(asynchronous:...)`, or from `CoreStore.perform(synchronous:...)`.
|
||||
*/
|
||||
public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||
|
||||
/**
|
||||
Cancels a transaction by throwing `CoreStoreError.userCancelled`.
|
||||
```
|
||||
try transaction.cancel()
|
||||
```
|
||||
- Important: Never use `try?` or `try!` on a `cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error.
|
||||
*/
|
||||
public func cancel() throws -> Never {
|
||||
|
||||
throw CoreStoreError.userCancelled
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Result
|
||||
|
||||
/**
|
||||
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 typealias Result<UserInfoType> = Swift.Result<UserInfoType, CoreStoreError>
|
||||
|
||||
// MARK: -
|
||||
|
||||
// MARK: BaseDataTransaction
|
||||
|
||||
/**
|
||||
Creates a new `NSManagedObject` or `CoreStoreObject` with the specified entity type.
|
||||
|
||||
- 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<D>(_ into: Into<D>) -> D {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to create an entity of type \(cs_typeName(into.entityClass)) from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
return super.create(into)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
|
||||
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be edited
|
||||
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
|
||||
*/
|
||||
public override func edit<D: DynamicObject>(_ object: D?) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to update an entity of type \(cs_typeName(object)) from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
return super.edit(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an editable proxy of the object with the specified `NSManagedObjectID`.
|
||||
|
||||
- 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` or `CoreStoreObject`.
|
||||
*/
|
||||
public override func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to update an entity of type \(cs_typeName(into.entityClass)) from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
return super.edit(into, objectID)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes a specified `NSManagedObject` or `CoreStoreObject`.
|
||||
|
||||
- parameter object: the `NSManagedObject` or `CoreStoreObject` to be deleted
|
||||
*/
|
||||
public override func delete<D: DynamicObject>(_ object: D?) {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to delete an entity of type \(cs_typeName(object)) from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
super.delete(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `DynamicObject`s.
|
||||
|
||||
- parameter object1: the `DynamicObject` to be deleted
|
||||
- parameter object2: another `DynamicObject` to be deleted
|
||||
- parameter objects: other `DynamicObject`s to be deleted
|
||||
*/
|
||||
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).compactMap { $0 })
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the specified `DynamicObject`s.
|
||||
|
||||
- parameter objects: the `DynamicObject`s to be deleted
|
||||
*/
|
||||
public override func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
|
||||
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to delete an entities from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
super.delete(objects)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue) {
|
||||
|
||||
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
|
||||
}
|
||||
|
||||
internal func autoCommit(_ completion: @escaping (_ hasChanges: Bool, _ error: CoreStoreError?) -> Void) {
|
||||
|
||||
self.isCommitted = true
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
self.context.saveAsynchronouslyWithCompletion { (hasChanges, error) -> Void in
|
||||
|
||||
completion(hasChanges, error)
|
||||
self.result = (hasChanges, error)
|
||||
group.leave()
|
||||
}
|
||||
group.wait()
|
||||
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: class {
|
||||
|
||||
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,34 +29,35 @@ import CoreData
|
||||
|
||||
// MARK: - BaseDataTransaction
|
||||
|
||||
public extension BaseDataTransaction {
|
||||
extension BaseDataTransaction {
|
||||
|
||||
/**
|
||||
Creates an `ImportableObject` by importing from the specified import source.
|
||||
|
||||
- parameter into: an `Into` clause specifying the entity type
|
||||
- parameter source: the object to import values from
|
||||
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
- returns: the created `ImportableObject` instance, or `nil` if the import was ignored
|
||||
*/
|
||||
public func importObject<T where T: NSManagedObject, T: ImportableObject>(
|
||||
into: Into<T>,
|
||||
source: T.ImportSource) throws -> T? {
|
||||
public func importObject<D: ImportableObject>(
|
||||
_ into: Into<D>,
|
||||
source: D.ImportSource) throws -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try cs_autoreleasepool {
|
||||
|
||||
return try autoreleasepool {
|
||||
|
||||
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
|
||||
let entityType = into.entityClass
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
let object = self.create(into)
|
||||
try object.didInsertFromImportSource(source, inTransaction: self)
|
||||
try object.didInsert(from: source, in: self)
|
||||
return object
|
||||
}
|
||||
}
|
||||
@@ -66,25 +67,25 @@ public extension BaseDataTransaction {
|
||||
|
||||
- parameter object: the `NSManagedObject` to update
|
||||
- parameter source: the object to import values from
|
||||
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
*/
|
||||
public func importObject<T where T: NSManagedObject, T: ImportableObject>(
|
||||
object: T,
|
||||
source: T.ImportSource) throws {
|
||||
public func importObject<D: ImportableObject>(
|
||||
_ object: D,
|
||||
source: D.ImportSource) throws {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(object)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
try cs_autoreleasepool {
|
||||
|
||||
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
|
||||
try autoreleasepool {
|
||||
|
||||
let entityType = cs_dynamicType(of: object)
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
try object.didInsertFromImportSource(source, inTransaction: self)
|
||||
try object.didInsert(from: source, in: self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,31 +94,31 @@ public extension BaseDataTransaction {
|
||||
|
||||
- parameter into: an `Into` clause specifying the entity type
|
||||
- parameter sourceArray: the array of objects to import values from
|
||||
- throws: an `ErrorType` thrown from any of the `ImportableObject` methods
|
||||
- throws: an `Error` thrown from any of the `ImportableObject` methods
|
||||
- returns: the array of created `ImportableObject` instances
|
||||
*/
|
||||
public func importObjects<T, S: SequenceType where T: NSManagedObject, T: ImportableObject, S.Generator.Element == T.ImportSource>(
|
||||
into: Into<T>,
|
||||
sourceArray: S) throws -> [T] {
|
||||
public func importObjects<D: ImportableObject, S: Sequence>(
|
||||
_ into: Into<D>,
|
||||
sourceArray: S) throws -> [D] where S.Iterator.Element == D.ImportSource {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try cs_autoreleasepool {
|
||||
return try autoreleasepool {
|
||||
|
||||
return try sourceArray.flatMap { (source) -> T? in
|
||||
|
||||
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
|
||||
return try sourceArray.compactMap { (source) -> D? in
|
||||
|
||||
let entityType = into.entityClass
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return try cs_autoreleasepool {
|
||||
return try autoreleasepool {
|
||||
|
||||
let object = self.create(into)
|
||||
try object.didInsertFromImportSource(source, inTransaction: self)
|
||||
try object.didInsert(from: source, in: self)
|
||||
return object
|
||||
}
|
||||
}
|
||||
@@ -129,46 +130,45 @@ public extension BaseDataTransaction {
|
||||
|
||||
- parameter into: an `Into` clause specifying the entity type
|
||||
- parameter source: the object to import values from
|
||||
- throws: an `ErrorType` thrown from any of the `ImportableUniqueObject` methods
|
||||
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
|
||||
- returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored
|
||||
*/
|
||||
public func importUniqueObject<T where T: NSManagedObject, T: ImportableUniqueObject>(
|
||||
into: Into<T>,
|
||||
source: T.ImportSource) throws -> T? {
|
||||
public func importUniqueObject<D: ImportableUniqueObject>(
|
||||
_ into: Into<D>,
|
||||
source: D.ImportSource) throws -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try cs_autoreleasepool {
|
||||
|
||||
let uniqueIDKeyPath = T.uniqueIDKeyPath
|
||||
guard let uniqueIDValue = try T.uniqueIDFromImportSource(source, inTransaction: self) else {
|
||||
return try autoreleasepool {
|
||||
|
||||
let entityType = into.entityClass
|
||||
let uniqueIDKeyPath = entityType.uniqueIDKeyPath
|
||||
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if let object = self.fetchOne(From(T), Where(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
|
||||
if let object = try self.fetchOne(From(entityType), Where<D>(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
|
||||
|
||||
guard T.shouldUpdateFromImportSource(source, inTransaction: self) else {
|
||||
guard entityType.shouldUpdate(from: source, in: self) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
try object.updateFromImportSource(source, inTransaction: self)
|
||||
try object.update(from: source, in: self)
|
||||
return object
|
||||
}
|
||||
else {
|
||||
|
||||
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
|
||||
guard entityType.shouldInsert(from: source, in: self) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
let object = self.create(into)
|
||||
object.uniqueIDValue = uniqueIDValue
|
||||
try object.didInsertFromImportSource(source, inTransaction: self)
|
||||
try object.didInsert(from: source, in: self)
|
||||
return object
|
||||
}
|
||||
}
|
||||
@@ -176,79 +176,80 @@ public extension BaseDataTransaction {
|
||||
|
||||
/**
|
||||
Updates existing `ImportableUniqueObject`s or creates them by importing from the specified array of import sources.
|
||||
- Warning: While the array returned from `importUniqueObjects(...)` correctly maps to the order of `sourceArray`, the order of objects called with `ImportableUniqueObject` methods is arbitrary. Do not make assumptions that any particular object will be imported ahead or after another object.
|
||||
`ImportableUniqueObject` methods are called on the objects in the same order as they are in the `sourceArray`, and are returned in an array with that same order.
|
||||
- Warning: If `sourceArray` contains multiple import sources with same ID, only the last `ImportSource` of the duplicates will be imported.
|
||||
|
||||
- parameter into: an `Into` clause specifying the entity type
|
||||
- parameter sourceArray: the array of objects to import values from
|
||||
- parameter preProcess: a closure that lets the caller tweak the internal `UniqueIDType`-to-`ImportSource` mapping to be used for importing. Callers can remove from/add to/update `mapping` and return the updated array from the closure.
|
||||
- throws: an `ErrorType` thrown from any of the `ImportableUniqueObject` methods
|
||||
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
|
||||
- returns: the array of created/updated `ImportableUniqueObject` instances
|
||||
*/
|
||||
public func importUniqueObjects<T, S: SequenceType where T: NSManagedObject, T: ImportableUniqueObject, S.Generator.Element == T.ImportSource>(
|
||||
into: Into<T>,
|
||||
public func importUniqueObjects<D: ImportableUniqueObject, S: Sequence>(
|
||||
_ into: Into<D>,
|
||||
sourceArray: S,
|
||||
@noescape preProcess: (mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] {
|
||||
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(),
|
||||
"Attempted to import an object of type \(cs_typeName(into.entityClass)) outside the transaction's designated queue."
|
||||
)
|
||||
|
||||
return try cs_autoreleasepool {
|
||||
|
||||
var mapping = Dictionary<T.UniqueIDType, T.ImportSource>()
|
||||
let sortedIDs = try cs_autoreleasepool {
|
||||
|
||||
return try sourceArray.flatMap { (source) -> T.UniqueIDType? in
|
||||
return try autoreleasepool {
|
||||
|
||||
let entityType = into.entityClass
|
||||
var importSourceByID = Dictionary<D.UniqueIDType, D.ImportSource>()
|
||||
let sortedIDs = try autoreleasepool {
|
||||
|
||||
return try sourceArray.compactMap { (source) -> D.UniqueIDType? in
|
||||
|
||||
guard let uniqueIDValue = try T.uniqueIDFromImportSource(source, inTransaction: self) else {
|
||||
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
mapping[uniqueIDValue] = source
|
||||
importSourceByID[uniqueIDValue] = source // effectively replaces duplicate with the latest
|
||||
return uniqueIDValue
|
||||
}
|
||||
}
|
||||
|
||||
mapping = try cs_autoreleasepool { try preProcess(mapping: mapping) }
|
||||
|
||||
var objects = Dictionary<T.UniqueIDType, T>()
|
||||
for object in self.fetchAll(From(T), Where(T.uniqueIDKeyPath, isMemberOf: sortedIDs)) ?? [] {
|
||||
importSourceByID = try autoreleasepool { try preProcess(importSourceByID) }
|
||||
|
||||
var existingObjectsByID = Dictionary<D.UniqueIDType, D>()
|
||||
try self
|
||||
.fetchAll(From(entityType), Where<D>(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))
|
||||
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
|
||||
|
||||
var processedObjectIDs = Set<D.UniqueIDType>()
|
||||
var result = [D]()
|
||||
|
||||
for objectID in sortedIDs where !processedObjectIDs.contains(objectID) {
|
||||
|
||||
try cs_autoreleasepool {
|
||||
guard let source = importSourceByID[objectID] else {
|
||||
|
||||
let uniqueIDValue = object.uniqueIDValue
|
||||
|
||||
guard let source = mapping.removeValueForKey(uniqueIDValue)
|
||||
where T.shouldUpdateFromImportSource(source, inTransaction: self) else {
|
||||
continue
|
||||
}
|
||||
try autoreleasepool {
|
||||
|
||||
if let object = existingObjectsByID[objectID] {
|
||||
|
||||
guard entityType.shouldUpdate(from: source, in: self) else {
|
||||
|
||||
return
|
||||
}
|
||||
try object.update(from: source, in: self)
|
||||
result.append(object)
|
||||
}
|
||||
|
||||
try object.updateFromImportSource(source, inTransaction: self)
|
||||
objects[uniqueIDValue] = object
|
||||
}
|
||||
}
|
||||
|
||||
for (uniqueIDValue, source) in mapping {
|
||||
|
||||
try cs_autoreleasepool {
|
||||
|
||||
guard T.shouldInsertFromImportSource(source, inTransaction: self) else {
|
||||
else if entityType.shouldInsert(from: source, in: self) {
|
||||
|
||||
return
|
||||
let object = self.create(into)
|
||||
object.uniqueIDValue = objectID
|
||||
try object.didInsert(from: source, in: self)
|
||||
result.append(object)
|
||||
}
|
||||
|
||||
let object = self.create(into)
|
||||
object.uniqueIDValue = uniqueIDValue
|
||||
try object.didInsertFromImportSource(source, inTransaction: self)
|
||||
|
||||
objects[uniqueIDValue] = object
|
||||
processedObjectIDs.insert(objectID)
|
||||
}
|
||||
}
|
||||
|
||||
return sortedIDs.flatMap { objects[$0] }
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
564
Sources/BaseDataTransaction+Querying.swift
Normal file
564
Sources/BaseDataTransaction+Querying.swift
Normal file
@@ -0,0 +1,564 @@
|
||||
//
|
||||
// BaseDataTransaction+Querying.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: - DataTransaction
|
||||
|
||||
extension BaseDataTransaction: FetchableSource, QueryableSource {
|
||||
|
||||
/**
|
||||
Deletes all `DynamicObject`s that satisfy the specified `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the number of `DynamicObject`s deleted
|
||||
*/
|
||||
@discardableResult
|
||||
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 `DeleteClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter deleteClauses: a series of `DeleteClause` instances for the delete request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- returns: the number of `DynamicObject`s deleted
|
||||
*/
|
||||
@discardableResult
|
||||
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 try self.context.deleteAll(clauseChain.from, clauseChain.fetchClauses)
|
||||
}
|
||||
|
||||
|
||||
// MARK: FetchableSource
|
||||
|
||||
/**
|
||||
Fetches the `DynamicObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
|
||||
|
||||
- parameter object: a reference to the object created/fetched outside the transaction
|
||||
- returns: the `DynamicObject` instance if the object exists in the transaction, or `nil` if not found.
|
||||
*/
|
||||
public func fetchExisting<D: DynamicObject>(_ object: D) -> D? {
|
||||
|
||||
return self.context.fetchExisting(object)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `DynamicObject` instance in the transaction's context from an `NSManagedObjectID`.
|
||||
|
||||
- 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<D: DynamicObject>(_ objectID: NSManagedObjectID) -> D? {
|
||||
|
||||
return self.context.fetchExisting(objectID)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `DynamicObject` instances in the transaction's context from references created from a transaction or from a different managed object context.
|
||||
|
||||
- parameter objects: an array of `DynamicObject`s created/fetched outside the transaction
|
||||
- returns: the `DynamicObject` array for objects that exists in the transaction
|
||||
*/
|
||||
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objects: S) -> [D] where S.Iterator.Element == D {
|
||||
|
||||
return self.context.fetchExisting(objects)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `DynamicObject` instances in the transaction's context from a list of `NSManagedObjectID`.
|
||||
|
||||
- parameter objectIDs: the `NSManagedObjectID` array for the objects
|
||||
- returns: the `DynamicObject` array for objects that exists in the transaction
|
||||
*/
|
||||
public func fetchExisting<D: DynamicObject, S: Sequence>(_ objectIDs: S) -> [D] where S.Iterator.Element == NSManagedObjectID {
|
||||
|
||||
return self.context.fetchExisting(objectIDs)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 try self.context.fetchOne(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the first `DynamicObject` instance that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 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)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 try self.context.fetchAll(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches all `DynamicObject` instances that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 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)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- 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<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 try self.context.fetchCount(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the number of `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter fetchClauses: a series of `FetchClause` instances for the fetch request. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
- 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<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 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)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 try self.context.fetchObjectID(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for the first `DynamicObject` that satisfies the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 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)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 try self.context.fetchObjectIDs(from, fetchClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Fetches the `NSManagedObjectID` for all `DynamicObject`s that satisfy the specified `FetchClause`s. Accepts `Where`, `OrderBy`, and `Tweak` clauses.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter 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, 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<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 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)
|
||||
}
|
||||
|
||||
|
||||
// MARK: QueryableSource
|
||||
|
||||
/**
|
||||
Queries aggregate values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
- returns: the result of the the query, 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<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 try self.context.queryValue(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries aggregate values or aggregates as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
- returns: the result of the the query, 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<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 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)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
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 try self.context.queryAttributes(from, selectClause, queryClauses)
|
||||
}
|
||||
|
||||
/**
|
||||
Queries a dictionary of attribute values as specified by the `QueryClause`s. Requires at least a `Select` clause, and optional `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
|
||||
A "query" differs from a "fetch" in that it only retrieves values already stored in the persistent store. As such, values from unsaved transactions or contexts will not be incorporated in the query result.
|
||||
|
||||
- parameter from: a `From` clause indicating the entity type
|
||||
- parameter selectClause: a `Select<U>` clause indicating the properties to fetch, and with the generic type indicating the return type.
|
||||
- parameter queryClauses: a series of `QueryClause` instances for the query request. Accepts `Where`, `OrderBy`, `GroupBy`, and `Tweak` clauses.
|
||||
- returns: the result of the the query. The type of the return value is specified by the generic type of the `Select<U>` parameter.
|
||||
- throws: `CoreStoreError.persistentStoreNotFound` if the specified entity could not be found in any store's schema.
|
||||
*/
|
||||
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 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)
|
||||
}
|
||||
|
||||
|
||||
// MARK: FetchableSource, QueryableSource
|
||||
|
||||
/**
|
||||
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
||||
*/
|
||||
public func unsafeContext() -> NSManagedObjectContext {
|
||||
|
||||
return self.context
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
#if USE_FRAMEWORKS
|
||||
import GCDKit
|
||||
#endif
|
||||
|
||||
|
||||
// MARK: - BaseDataTransaction
|
||||
@@ -48,32 +45,36 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new `NSManagedObject` with the specified entity type.
|
||||
Creates a new `NSManagedObject` or `CoreStoreObject` with the specified entity type.
|
||||
|
||||
- parameter into: the `Into` clause indicating the destination `NSManagedObject` entity type and the destination configuration
|
||||
- returns: a new `NSManagedObject` instance of the specified entity type.
|
||||
- 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: NSManagedObject>(into: Into<T>) -> T {
|
||||
public func create<D>(_ into: Into<D>) -> D {
|
||||
|
||||
let entityClass = into.entityClass
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to create an entity of type \(cs_typeName(T)) outside its designated queue."
|
||||
"Attempted to create an entity of type \(cs_typeName(entityClass)) outside its designated queue."
|
||||
)
|
||||
|
||||
let context = self.context
|
||||
let entityClass = (into.entityClass as! NSManagedObject.Type)
|
||||
let dataStack = context.parentStack!
|
||||
let entityIdentifier = EntityIdentifier(entityClass)
|
||||
if into.inferStoreIfPossible {
|
||||
|
||||
switch context.parentStack!.persistentStoreForEntityClass(
|
||||
entityClass,
|
||||
switch dataStack.persistentStore(
|
||||
for: entityIdentifier,
|
||||
configuration: nil,
|
||||
inferStoreIfPossible: true
|
||||
) {
|
||||
|
||||
case (let persistentStore?, _):
|
||||
let object = entityClass.createInContext(context) as! T
|
||||
context.assignObject(object, toPersistentStore: persistentStore)
|
||||
return object
|
||||
return entityClass.cs_forceCreate(
|
||||
entityDescription: dataStack.entityDescription(for: entityIdentifier)!,
|
||||
into: context,
|
||||
assignTo: persistentStore
|
||||
)
|
||||
|
||||
case (nil, true):
|
||||
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
|
||||
@@ -84,17 +85,19 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
}
|
||||
else {
|
||||
|
||||
switch context.parentStack!.persistentStoreForEntityClass(
|
||||
entityClass,
|
||||
switch dataStack.persistentStore(
|
||||
for: entityIdentifier,
|
||||
configuration: into.configuration
|
||||
?? into.dynamicType.defaultConfigurationName,
|
||||
?? DataStack.defaultConfigurationName,
|
||||
inferStoreIfPossible: false
|
||||
) {
|
||||
|
||||
case (let persistentStore?, _):
|
||||
let object = entityClass.createInContext(context) as! T
|
||||
context.assignObject(object, toPersistentStore: persistentStore)
|
||||
return object
|
||||
return entityClass.cs_forceCreate(
|
||||
entityDescription: dataStack.entityDescription(for: entityIdentifier)!,
|
||||
into: context,
|
||||
assignTo: persistentStore
|
||||
)
|
||||
|
||||
case (nil, true):
|
||||
CoreStore.abort("Attempted to create an entity of type \(cs_typeName(entityClass)) with ambiguous destination persistent store, but the configuration name was not specified.")
|
||||
@@ -113,13 +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`.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func edit<T: NSManagedObject>(object: T?) -> T? {
|
||||
public func edit<D: DynamicObject>(_ object: D?) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
@@ -137,67 +139,64 @@ 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`.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func edit<T: NSManagedObject>(into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
|
||||
public func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to update an entity of type \(cs_typeName(T)) outside its designated queue."
|
||||
"Attempted to update an entity of type \(cs_typeName(into.entityClass)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
into.inferStoreIfPossible
|
||||
|| (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName,
|
||||
"Attempted to update an entity of type \(cs_typeName(T)) but the specified persistent store do not match the `NSManagedObjectID`."
|
||||
|| (into.configuration ?? DataStack.defaultConfigurationName) == objectID.persistentStore?.configurationName,
|
||||
"Attempted to update an entity of type \(cs_typeName(into.entityClass)) but the specified persistent store do not match the `NSManagedObjectID`."
|
||||
)
|
||||
return self.fetchExisting(objectID) as? T
|
||||
return self.fetchExisting(objectID)
|
||||
}
|
||||
|
||||
/**
|
||||
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(object: NSManagedObject?) {
|
||||
public func delete<D: DynamicObject>(_ object: D?) {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete an entity outside its designated queue."
|
||||
)
|
||||
guard let object = object else {
|
||||
|
||||
return
|
||||
}
|
||||
self.context.fetchExisting(object)?.deleteFromContext()
|
||||
let context = self.context
|
||||
object
|
||||
.flatMap(context.fetchExisting)
|
||||
.flatMap({ context.delete($0.cs_toRaw()) })
|
||||
}
|
||||
|
||||
/**
|
||||
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(object1: NSManagedObject?, _ object2: NSManagedObject?, _ objects: NSManagedObject?...) {
|
||||
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: SequenceType where S.Generator.Element: NSManagedObject>(objects: S) {
|
||||
public func delete<S: Sequence>(_ objects: S) where S.Iterator.Element: DynamicObject {
|
||||
|
||||
CoreStore.assert(
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to delete entities outside their designated queue."
|
||||
)
|
||||
|
||||
let context = self.context
|
||||
objects.forEach { context.fetchExisting($0)?.deleteFromContext() }
|
||||
objects.forEach { context.fetchExisting($0).flatMap({ context.delete($0.cs_toRaw()) }) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +208,6 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
self.isRunningInAllowedQueue(),
|
||||
"Attempted to refresh entities outside their designated queue."
|
||||
)
|
||||
|
||||
self.context.refreshAndMergeAllObjects()
|
||||
}
|
||||
|
||||
@@ -217,44 +215,22 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
// MARK: Inspecting Pending Objects
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObject`s that were inserted to the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- returns: a `Set` of pending `NSManagedObject`s that were inserted to the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func insertedObjects() -> Set<NSManagedObject> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
|
||||
Returns all pending `DynamicObject`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `NSManagedObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were inserted to the transaction.
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were inserted to the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func insertedObjects<T: NSManagedObject>(entity: T.Type) -> Set<T> {
|
||||
public func insertedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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 { $0 as? T })
|
||||
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,81 +238,55 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s that were inserted to the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func insertedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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.map { $0.objectID })
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObjectID`s of the specified type that were inserted to the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `NSManagedObject` subclass to filter
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were inserted to the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func insertedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
|
||||
public func insertedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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.filter { $0.isKindOfClass(entity) }.map { $0.objectID })
|
||||
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObject`s that were updated in the transaction. This method should not be called after the `commit()` method was called.
|
||||
Returns all pending `DynamicObject`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- returns: a `Set` of pending `NSManagedObject`s that were updated to the transaction.
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were updated in the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func updatedObjects() -> Set<NSManagedObject> {
|
||||
public func updatedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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 self.context.updatedObjects
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObject`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `NSManagedObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were updated in the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func updatedObjects<T: NSManagedObject>(entity: T.Type) -> Set<T> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.isCurrentExecutionContext(),
|
||||
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
return Set(self.context.updatedObjects.filter { $0.isKindOfClass(entity) }.map { $0 as! T })
|
||||
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,144 +294,127 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s that were updated in the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func updatedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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.map { $0.objectID })
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObjectID`s of the specified type that were updated in the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `NSManagedObject` subclass to filter
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were updated in the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func updatedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
|
||||
public func updatedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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.filter { $0.isKindOfClass(entity) }.map { $0.objectID })
|
||||
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObject`s that were deleted from the transaction. This method should not be called after the `commit()` method was called.
|
||||
Returns all pending `DynamicObject`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- returns: a `Set` of pending `NSManagedObject`s that were deleted from the transaction.
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `DynamicObject`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func deletedObjects() -> Set<NSManagedObject> {
|
||||
public func deletedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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 self.context.deletedObjects
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObject`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `NSManagedObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObject`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func deletedObjects<T: NSManagedObject>(entity: T.Type) -> Set<T> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.isCurrentExecutionContext(),
|
||||
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!self.isCommitted,
|
||||
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
|
||||
)
|
||||
|
||||
return Set(self.context.deletedObjects.filter { $0.isKindOfClass(entity) }.map { $0 as! T })
|
||||
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `NSManagedObject` subclass to filter
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func deletedObjectIDs() -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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.map { $0.objectID })
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `commit()` method was called.
|
||||
|
||||
- parameter entity: the `NSManagedObject` subclass to filter
|
||||
- parameter entity: the `DynamicObject` subclass to filter
|
||||
- returns: a `Set` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
|
||||
*/
|
||||
@warn_unused_result
|
||||
public func deletedObjectIDs<T: NSManagedObject>(entity: T.Type) -> Set<NSManagedObjectID> {
|
||||
public func deletedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
|
||||
|
||||
CoreStore.assert(
|
||||
self.transactionQueue.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.filter { $0.isKindOfClass(entity) }.map { $0.objectID })
|
||||
return Set(self.context.deletedObjects.compactMap({ entity.cs_matches(object: $0) ? $0.objectID : nil }))
|
||||
}
|
||||
|
||||
|
||||
// MARK: 3rd Party Utilities
|
||||
|
||||
/**
|
||||
Allow external libraries to store custom data in the transaction. App code should rarely have a need for this.
|
||||
```
|
||||
enum Static {
|
||||
static var myDataKey: Void?
|
||||
}
|
||||
transaction.userInfo[&Static.myDataKey] = myObject
|
||||
```
|
||||
- Important: Do not use this method to store thread-sensitive data.
|
||||
*/
|
||||
public let userInfo = UserInfo()
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let context: NSManagedObjectContext
|
||||
internal let transactionQueue: GCDQueue
|
||||
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue")
|
||||
internal let transactionQueue: DispatchQueue
|
||||
internal let childTransactionQueue = DispatchQueue.serial("com.corestore.datastack.childTransactionQueue")
|
||||
internal let supportsUndo: Bool
|
||||
internal let bypassesQueueing: Bool
|
||||
|
||||
|
||||
internal var isCommitted = false
|
||||
internal var result: SaveResult?
|
||||
internal var result: (hasChanges: Bool, error: CoreStoreError?)?
|
||||
|
||||
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, supportsUndo: Bool, bypassesQueueing: Bool) {
|
||||
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue, supportsUndo: Bool, bypassesQueueing: Bool) {
|
||||
|
||||
let context = mainContext.temporaryContextInTransactionWithConcurrencyType(
|
||||
queue == .Main
|
||||
? .MainQueueConcurrencyType
|
||||
: .PrivateQueueConcurrencyType
|
||||
queue == .main
|
||||
? .mainQueueConcurrencyType
|
||||
: .privateQueueConcurrencyType
|
||||
)
|
||||
self.transactionQueue = queue
|
||||
self.context = context
|
||||
@@ -489,18 +422,24 @@ public /*abstract*/ class BaseDataTransaction {
|
||||
self.bypassesQueueing = bypassesQueueing
|
||||
|
||||
context.parentTransaction = self
|
||||
context.isTransactionContext = true
|
||||
if !supportsUndo {
|
||||
|
||||
context.undoManager = nil
|
||||
}
|
||||
else if context.undoManager == nil {
|
||||
|
||||
context.undoManager = NSUndoManager()
|
||||
context.undoManager = UndoManager()
|
||||
}
|
||||
}
|
||||
|
||||
internal func isRunningInAllowedQueue() -> Bool {
|
||||
|
||||
return self.bypassesQueueing || self.transactionQueue.isCurrentExecutionContext()
|
||||
return self.bypassesQueueing || self.transactionQueue.cs_isCurrentExecutionContext()
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
self.context.reset()
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user