Compare commits

...

394 Commits
3.0.3 ... 6.3.2

Author SHA1 Message Date
John Estropia
1740d168c8 Merge branch 'develop' 2019-08-27 14:38:16 +09:00
John Estropia
d42b397090 version bump 2019-08-27 14:38:05 +09:00
John Estropia
058cc1915b fix optimization issues in release build 2019-08-27 14:21:33 +09:00
John Estropia
02d5bf85ae fix ListMonitor demo for iOS 13 2019-08-20 12:42:34 +09:00
John Estropia
ed3d21db77 WIP: reorganization of keypath utilities (in prep for @propertyWrappers) 2019-07-09 14:50:23 +09:00
John Estropia
67bb9340c7 provide way to check if an object has updated properties 2019-07-05 19:07:25 +09:00
John Estropia
5d49bd79f2 Merge pull request #326 from cool8jay/patch-1
Update README code style.
2019-06-29 13:19:14 +09:00
John Estropia
9f397b4337 Prevent crashing when DataStack is deallocated ahead of ListMonitor and child objects 2019-06-10 18:34:15 +09:00
cool8jay
7508d150d6 Update code style.
Update code style.
2019-06-05 08:43:06 +08:00
John Estropia
239db8168d remove artifacts from Carthage 2019-05-19 01:51:46 +09:00
John Estropia
30ab4386bf Merge branch 'develop' 2019-04-27 17:51:12 +09:00
John Estropia
08053ccb15 change protocol inheritance from class to AnyObject (as per recent Swift recommendation) 2019-04-27 17:50:55 +09:00
John Estropia
367cfea8a7 Merge branch 'develop' 2019-04-05 08:36:30 +09:00
John Estropia
5d3b7e3dab version bump 2019-04-05 08:36:09 +09:00
John Estropia
fe7e6e7b84 Fix wrong VersionLock printing on Swift 5 (fixes #311) 2019-04-05 08:29:14 +09:00
John Estropia
b2dba0d6fd update pod version and jazzy docs 2019-03-31 00:29:43 +09:00
John Estropia
6f290213fa update README 2019-03-31 00:05:13 +09:00
John Estropia
0ab52d2f43 converted *Result types to new Swift.Result 2019-03-30 23:58:26 +09:00
John Estropia
bf8a1062e0 deleted obsoleted and deprecated API 2019-03-30 23:56:39 +09:00
John Estropia
0e254867b6 update project for Swift 5 / Xcode 10.2 2019-03-30 23:36:56 +09:00
John Estropia
0376ac6908 bump 2019-02-28 18:57:28 +09:00
John Estropia
b3421888a6 version bump 2019-02-28 18:55:32 +09:00
John Estropia
7b3f4ae0a4 fix compile error 2019-02-28 17:58:17 +09:00
John Estropia
b4e12cc922 restore NSPersistentStore.affectedStores ARC bug workaround 2019-02-28 17:57:34 +09:00
John Estropia
6c282b18af version bump 2019-02-28 13:14:27 +09:00
John Estropia
ebbde8b7b6 minor fix in demo app 2019-02-28 13:13:01 +09:00
John Estropia
a1407e4121 Revert workaround for iOS 10 NSFetchedResultsController (#100) 2019-02-28 13:07:47 +09:00
John Estropia
99b871b97a add missing documentations for Where.Expression, updated playgrounds 2019-02-20 18:47:29 +09:00
John Estropia
1cd3c4fcf4 fix compile error 2019-02-12 18:18:44 +09:00
John Estropia
e09ac9ee00 add macOS playground 2019-02-12 18:05:06 +09:00
John Estropia
4b0d134acb remove swift 5 annotation 2019-02-12 18:03:59 +09:00
John Estropia
eeec3979ee SwiftPM support 2019-02-12 15:48:50 +09:00
John Estropia
5b365c642d add tests for expressio evaluations 2019-02-08 18:42:19 +09:00
John Estropia
635201868a add comparison operators for Where.Expression 2019-02-08 17:16:56 +09:00
John Estropia
db4426e6b9 Swift 5 support. WIP: Support type-safe predicate expressions 2019-02-01 18:32:22 +09:00
John Estropia
41902fee2e fix compiler errors 2019-01-31 16:50:43 +09:00
John Estropia
9239370793 Added reference comment explaining crashes on A12 devices #291 2019-01-29 14:15:01 +09:00
John Estropia
a4d2f326a5 Improve perfomance by bypassing bridging (similar to https://github.com/JohnEstropia/CoreStore/pull/288) 2019-01-28 20:12:18 +09:00
John Estropia
9f54ec26e2 add Where initializer that can accept another Where clause 2019-01-28 20:10:15 +09:00
John Estropia
9425cb56d7 update documentation for -[CSListMonitor refetch:] to reflect actual behavior 2019-01-28 19:04:46 +09:00
John Estropia
1de56d2776 add missing From.orderBy(_:) overloads 2019-01-25 17:30:11 +09:00
John Estropia
b3261ea930 Update README.md 2019-01-24 16:12:12 +09:00
John Estropia
88dd7aef72 updated README 2019-01-24 15:32:54 +09:00
John Estropia
2863605d84 silence deprecation internal warnings 2019-01-23 12:25:52 +09:00
John Estropia
94d9116299 pod bump 2019-01-23 10:56:10 +09:00
John Estropia
57ddbbd515 make some test cases validate specific error codes from thrown errors 2019-01-23 10:55:58 +09:00
John Estropia
78954b9d78 version bump 2019-01-22 16:41:58 +09:00
John Estropia
4eb06c9858 Merge branch 'throwables' into develop 2019-01-22 16:38:57 +09:00
John Estropia
0d634c1dcc add missing MARKs 2019-01-22 16:38:17 +09:00
John Estropia
84f3740ea1 fix unit test warnings 2019-01-18 17:30:54 +09:00
John Estropia
6dc48b6af7 Add docs for new throwing methods 2019-01-17 18:43:10 +09:00
John Estropia
09ce2816bf Merge branch 'develop' into throwables 2019-01-16 17:03:49 +09:00
John Estropia
62e962eebe Merge pull request #301 from ianbytchek/develop
Resolve source entity and managed object attributes by name
2019-01-16 17:01:48 +09:00
John Estropia
682472c1bd fetches, queries, and deletes are now throwable methods 2019-01-15 20:40:15 +09:00
Ian Bytchek
46ab70b839 Update TravisCI base image to Xcode 10
Replace deprecated build matrix configurations with newer alternatives.
2019-01-13 06:24:04 +00:00
Ian Bytchek
ac8304f977 Resolve source entity and managed object attributes by name
Addresses #300 – see it for details. Also improves the use of whitespace consistency across the `CustomSchemaMappingProvider.swift` and uses method names for `cs_resolve…` over `cs_resolved…` for better alignment with [Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines).
2019-01-13 05:41:34 +00:00
John Estropia
5777831565 WIP: make fetching methods throwable 2019-01-11 19:52:12 +09:00
John Estropia
42d1f41939 Provide more context when failing to search for mapping models #299 2019-01-11 19:48:35 +09:00
John Estropia
8c30ec3a3d minor fixes on Playgrounds and Demo app 2019-01-09 11:59:06 +09:00
John Estropia
237a1b648e Assert on reserved property names 2019-01-09 11:58:37 +09:00
John Estropia
614f1572c2 print PartialObjects 2018-12-26 22:35:28 +08:00
John Estropia
a48f16aa8c add Jazzy docs 2018-12-19 16:27:05 +09:00
John Estropia
cdbadae002 added comments to playground 2018-12-18 18:44:47 +09:00
John Estropia
4a28a39df6 removed long-standing workaround for NSFetchedResultsController bugs since they seem to be fixed 2018-12-18 18:43:36 +09:00
John Estropia
5febf2542d added playgrounds just to show off 2018-12-14 19:28:55 +09:00
John Estropia
c21ab11a41 format header comment 2018-12-14 18:21:41 +09:00
John Estropia
10cd18dbf0 prototype for CoreStoreObject property observers (a.k.a. KVO) 2018-12-14 18:20:42 +09:00
John Estropia
8409a13289 Merge pull request #288 from ruslanskorb/list-monitor-number-of-objects-performance
[ListMonitor] Fix performance of `numberOfObjects()`.
2018-12-06 18:53:06 +09:00
Ruslan Skorb
a9a73fa5c4 [ListMonitor] [numberOfObjects()] Return count of fetchedObjects.
Casting `fetchedObjects` to `NSArray?` has better performance.
https://github.com/JohnEstropia/CoreStore/pull/288
2018-12-06 10:56:30 +02:00
John Estropia
82cae2e11e Merge pull request #292 from eliseo-juan/patch-1
Fix documentation
2018-12-06 10:54:50 +09:00
John Estropia
42caee2418 Merge pull request #287 from ruslanskorb/list-monitor-subscript-performance
[ListMonitor] Fix performance of `subscript(safeSectionIndex:safeItemIndex:)`.
2018-12-06 10:54:12 +09:00
Eliseo Juan Quintanilla
1dea1d0d06 Fix documentation
Changed attribtue to attribute
2018-12-05 10:09:05 +01:00
John Estropia
d344b9d878 minimum deployment version bumped to iOS 10, macOS 10.12, tvOS 10, watchOS 3. Deprecated iCloud Storage 2018-12-05 17:31:16 +09:00
John Estropia
95c1ce52cc Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2018-12-05 16:17:03 +09:00
John Estropia
cc346816d6 Added new error for cases when addStorageAndWait() is used with .allowSynchronousLightweightMigration but migrations are only allowed asynchronously (related to #277) 2018-12-05 16:15:20 +09:00
John Estropia
f14b561c33 Merge pull request #275 from DmitrijMaz/fix_queueing
Fix queue validation for UnsafeDataTransaction
2018-12-05 11:02:47 +09:00
Ruslan Skorb
6f655951aa [ListMonitor] [numberOfObjects()] Calculate the number of objects in all sections by summing the number of objects stored in NSFetchedResultsSectionInfo.
There is a performance problem in Swift when calling `count` method on an array with a large number of fetched objects. It requires casting the array between Objective-C and Swift, that is pretty slow.
2018-11-24 16:24:14 +02:00
Ruslan Skorb
ff8fbae568 [ListMonitor] [subscript(safeSectionIndex:safeItemIndex:)] Use subscript(indexPath:) after the validation of sectionIndex and itemIndex to get an object.
There is a performance problem in Swift when getting an object from the Objective-C array with a large number of objects using subscript. It requires casting the array between Objective-C and Swift, that is pretty slow.
2018-11-24 16:23:36 +02:00
Dmitry Mazurenko
4d4b02d076 Fix queue validation for UnsafeDataTransaction 2018-10-10 16:48:04 +03:00
John Estropia
06c0981ded debug string for CoreStoreObject 2018-09-24 00:49:53 +09:00
John Estropia
20d581d536 version bump 2018-09-19 18:48:45 +09:00
John Estropia
45e110755d deleted unnecessary Equatable and Hashable custom implementations 2018-09-19 11:06:19 +09:00
John Estropia
ab40532801 fix issue with early-deallocated CoreStoreObjects 2018-09-18 23:50:14 +09:00
John Estropia
40f458a09c Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2018-09-15 12:56:21 +09:00
John Estropia
1ad233ca9d Swift 4.2 support 2018-09-15 12:56:08 +09:00
John Estropia
3a8e394272 Merge pull request #269 from congbach/develop
Fixed bug where ListObjectObserver didUpdateObject was not called on …
2018-09-10 19:30:06 +09:00
Ken Bach
1f54daa528 Fixed bug where ListObjectObserver.didUpdateObject was not called on watchos. 2018-08-21 22:47:54 +01:00
John Estropia
f25879b6fe fix compile error on tvOS and watchOS 2018-08-09 21:04:09 +09:00
John Estropia
8fa3109e91 version bump 2018-08-09 20:45:46 +09:00
John Estropia
808e8ff97a stabilize NSProgress when lightweight migration falls back to InferredMappingModel 2018-08-09 18:18:21 +09:00
John Estropia
30685d4355 Use InferredMappingModel in case lightweight migration fails for some reason 2018-08-09 02:09:54 +09:00
John Estropia
7152962026 revert 2018-08-09 01:39:16 +09:00
John Estropia
91735e38d1 Fix issue where CoreStoreObjects nested in a type is mismatching classnames before migration 2018-08-08 23:52:47 +09:00
John Estropia
333a50ad9e Merge pull request #256 from vGubriienko/demo-fix
Fixed issue with brightness observing in the Demo
2018-08-03 17:44:40 +09:00
John Rommel Estropia
b7a602fc67 iOS 11 Core Data changes 2018-07-29 23:33:51 +09:00
Viktor Gubriienko
2ff7ecef96 Fixed issue with brightness observing in the Demo 2018-06-12 17:53:00 +03:00
John Rommel Estropia
e3f9139304 version bump 2018-06-10 11:52:47 +09:00
John Rommel Estropia
4aa461872f specify swift version in podspec 2018-06-10 11:47:03 +09:00
John Rommel Estropia
3d43314076 update readme 2018-04-14 09:05:13 +09:00
John Rommel Estropia
7b1075b759 support compound indexes and unique constraints on CoreStore properties 2018-03-17 23:56:42 +09:00
John Rommel Estropia
0c29e07ddb support allowsExternalBinaryDataStorage option on Transformable CoreStoreObject properties 2018-03-17 23:56:01 +09:00
John Rommel Estropia
ce91cf22f9 Swift 4.1 support 2018-03-17 23:53:24 +09:00
John Rommel Estropia
2dd033c002 Merge branch 'develop' into prototype/Swift_4_1 2018-03-10 21:09:29 +09:00
John Rommel Estropia
c7fcba112e Fix bug where ListMonitor sectionIndexTitles are not updated on refetch (fixes #218) 2018-03-10 21:09:18 +09:00
John Rommel Estropia
c8b1c4358f Fix bug where ListMonitor sectionIndexTitles are not updated on refetch (fixes #218) 2018-03-10 21:08:40 +09:00
John Rommel Estropia
5431e2e974 Swift 4.1 support 2018-03-10 21:07:53 +09:00
John Rommel Estropia
83e6082c56 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2018-01-07 23:25:11 +09:00
John Rommel Estropia
c7bdbbde57 convert value to native type before formatting predicates 2018-01-07 21:06:35 +09:00
John Estropia
abf15c8aa8 Merge pull request #232 from kf99916/external-storage-migration
External storage migration
2018-01-06 17:48:38 +09:00
Zheng-Xiang Ke
d9db7e4a82 Typo 2018-01-06 15:00:53 +08:00
John Estropia
65dbc22ddd Merge pull request #231 from doodzik/patch-1
Fix syntax error in readme
2018-01-06 15:11:48 +09:00
Zheng-Xiang Ke
51961dd737 Migrate external storage 2018-01-06 10:22:44 +08:00
Frederik Dudzik
18a7055cdf Fix syntax error 2018-01-05 21:16:04 +01:00
John Rommel Estropia
4b9fddad6a Merge branch 'develop' 2017-12-29 01:09:07 +09:00
John Rommel Estropia
fbe7bd7bf8 update podfile 2017-12-29 00:53:48 +09:00
John Rommel Estropia
15edabdbb5 changed keyPath string utility to use String initializer 2017-12-29 00:05:11 +09:00
John Rommel Estropia
f447bcfb95 Merge branch 'develop' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/DataStack+Migration.swift
#	Sources/Info.plist
2017-11-19 15:35:29 +09:00
John Rommel Estropia
15e5e4fdf6 delete shm file after converting to DELETE journal mode 2017-11-19 15:34:09 +09:00
John Rommel Estropia
583c6b7249 minor code cleanup 2017-11-19 13:49:21 +09:00
John Rommel Estropia
18b933957e version bump 2017-11-16 02:28:18 +09:00
John Rommel Estropia
2c7039232e merge sqlite journal files before migration 2017-11-16 02:27:06 +09:00
John Rommel Estropia
d3b3b5ff4a added fake progress for lightweight migrations 2017-11-16 02:26:56 +09:00
John Rommel Estropia
d90e8d1303 force true lightweight migration 2017-11-16 02:26:44 +09:00
John Rommel Estropia
b55dd13dff merge sqlite journal files before migration 2017-11-15 23:50:10 +09:00
John Rommel Estropia
66dd5b6f27 added fake progress for lightweight migrations 2017-11-13 02:44:26 +09:00
John Estropia
49c4b770eb WIP: Readme 2017-11-10 19:19:48 +09:00
John Rommel Estropia
662aaa1e75 force true lightweight migration 2017-11-10 02:48:37 +09:00
John Rommel Estropia
dd4e47d7f9 revert null overloads, remove optional objectIDs as condition 2017-11-09 23:26:53 +09:00
John Estropia
9ea5073bc8 Merge branch 'master' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-11-09 19:52:29 +09:00
John Estropia
e314db8f56 version bump 2017-11-09 19:45:21 +09:00
John Estropia
48d936d068 Fix regression for ARC bugfix (fixes #221) 2017-11-09 19:44:27 +09:00
John Estropia
b2ff8a15ef add query overloads to == so comparison with nil don't confuse the compiler 2017-11-09 19:27:56 +09:00
John Estropia
8a4d1cd7c6 fix demo app warnings 2017-11-09 19:27:05 +09:00
John Rommel Estropia
8ce26c213d more source docs, deprecated some Where clause utilities 2017-11-04 10:37:54 +09:00
John Estropia
f3816b9abf update for Xcode 9.1 2017-11-01 19:49:42 +09:00
John Estropia
21961780d4 force dynamic typing on DynamicObject.Type to mitigate optimization issues 2017-11-01 19:38:38 +09:00
John Rommel Estropia
305e2b61a0 fix compile errors for Xcode 9.1 beta 2017-11-01 19:37:53 +09:00
John Estropia
0430f66240 force dynamic typing on DynamicObject.Type to mitigate optimization issues 2017-11-01 11:33:41 +09:00
John Estropia
65772edd00 Merge pull request #208 from volodg/prototype/Swift_4_0
(Xcode 9.1) fix compile error:
2017-10-29 18:55:13 +09:00
John Rommel Estropia
02d7870d75 fix compile errors for Xcode 9.1 beta 2017-10-29 15:20:58 +09:00
John Rommel Estropia
aca1709e13 WIP: documentation 2017-10-29 15:06:57 +09:00
John Rommel Estropia
b6ee0b014f WIP: documentations 2017-10-24 00:31:27 +09:00
John Estropia
e37186da73 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-10-17 13:42:04 +09:00
John Estropia
588fa35c84 version bump 2017-10-17 13:39:57 +09:00
John Estropia
f6614cda66 Merge branch 'develop' 2017-10-17 13:39:20 +09:00
John Estropia
639574d8c2 remove inline casts because optimized builds seem to trip on them 2017-10-17 13:38:25 +09:00
John Rommel Estropia
094703155c Merge branch 'master' into prototype/Swift_4_0
# Conflicts:
#	.swift-version
2017-10-13 08:14:20 +09:00
John Rommel Estropia
6dd254e713 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-10-13 08:10:56 +09:00
John Rommel Estropia
204025721c version bump 2017-10-13 08:10:26 +09:00
John Rommel Estropia
27ffc1d225 Merge branch 'develop'
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2017-10-13 08:01:30 +09:00
John Rommel Estropia
ba6f0c39d5 swift version 3.2 2017-10-13 08:00:39 +09:00
John Rommel Estropia
ab2eac8f6c Swift 3.2 README update 2017-10-13 07:58:37 +09:00
John Rommel Estropia
f460a0b30f CI: test demo app 2017-10-12 01:10:08 +09:00
John Rommel Estropia
50bc3ace06 travis 2017-10-12 00:02:39 +09:00
John Rommel Estropia
d2ddf2002f version update 2017-10-11 22:40:27 +09:00
John Rommel Estropia
b4117eeb02 updated documentation (fixes #198) 2017-10-11 07:50:24 +09:00
Vladimir
106275b2dd fix compile error:
inheritance from 'AnyObject'
2017-10-07 12:21:27 +08:00
John Rommel Estropia
08d9298be0 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	Sources/OrderBy.swift
2017-10-07 01:13:30 +09:00
John Rommel Estropia
ff0c4d94fc Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-10-07 01:10:28 +09:00
John Rommel Estropia
50e50c0613 Merge branch 'develop' into prototype/Swift_3_2 2017-10-07 01:07:09 +09:00
John Rommel Estropia
5c8a0e425b version bump 2017-10-07 00:59:37 +09:00
John Rommel Estropia
03b71caf7e Merge branch 'develop' 2017-10-07 00:58:04 +09:00
John Rommel Estropia
7ff29d6086 version bump 2017-10-07 00:57:41 +09:00
John Rommel Estropia
8d86425875 always create subclass type from cs_rawObject 2017-10-07 00:56:19 +09:00
John Estropia
97242d9726 added type-erasers for CoreStoreObject property containers 2017-10-02 12:00:45 +09:00
John Estropia
780ff4e60b fix compile errors 2017-10-02 11:10:28 +09:00
John Estropia
11743dfb5f oops 2017-10-02 11:08:44 +09:00
John Estropia
9eaf85388c relax generic type requirements for some Where utilities 2017-10-02 10:33:59 +09:00
John Rommel Estropia
06635c9d2f orderby utilities 2017-10-02 08:04:28 +09:00
John Rommel Estropia
1d2eef7894 revert 2017-10-01 01:01:10 +09:00
John Rommel Estropia
85ed815ec2 WIP: more chain clause builder utilities 2017-10-01 00:45:21 +09:00
John Estropia
096e5493a6 WIP: protocol cleanup 2017-09-29 20:33:10 +09:00
John Estropia
0aa8c03424 Merge pull request #205 from jannon/case-insensitive-orderby
add case-insensitive sortkeys
2017-09-29 19:38:36 +09:00
John Estropia
4ead3c34dd delete errant operator 2017-09-26 11:59:28 +09:00
John Rommel Estropia
645034dde5 keyPath utilities for SectionBy clauses 2017-09-24 10:38:17 +09:00
John Rommel Estropia
85706a3c57 version bump 2017-09-22 23:43:19 +09:00
John Rommel Estropia
c5ae4606b9 move cocoapods.yml 2017-09-22 23:41:07 +09:00
John Rommel Estropia
fa682215c5 version bump 2017-09-22 23:26:15 +09:00
John Rommel Estropia
e814733ae9 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	Sources/DynamicObject.swift
2017-09-22 23:20:16 +09:00
John Rommel Estropia
e2236698fa Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-09-22 23:18:38 +09:00
John Rommel Estropia
be5da632b3 fix segmentation fault 2017-09-22 23:18:25 +09:00
John Estropia
dc73cd6dd9 added a yml file for pod try (#200) 2017-09-22 15:48:02 +09:00
John Rommel Estropia
7beb3bec75 rename methods 2017-09-22 08:02:13 +09:00
Jannon Frank
53100b202d add case-insensitive sortkeys 2017-09-21 11:38:29 -07:00
John Rommel Estropia
cc84b1f8bd minor 2017-09-22 01:00:03 +09:00
John Rommel Estropia
474f52ed2b alow nil comparison for relationship keypaths 2017-09-22 00:30:02 +09:00
John Rommel Estropia
16225fc4c6 allow optionals in relationship keyPaths 2017-09-22 00:20:55 +09:00
John Rommel Estropia
03bb7619da added queryBuilder utilities for clause sequences 2017-09-22 00:08:01 +09:00
John Rommel Estropia
1bfb7451c3 keyPath utilities for Select queries 2017-09-21 07:56:02 +09:00
John Rommel Estropia
3e082d5ed4 queryBuilders for list monitors 2017-09-20 00:45:38 +09:00
John Rommel Estropia
e45d67252c CoreStore querying utilities 2017-09-20 00:24:03 +09:00
John Rommel Estropia
3d427c29c4 added required settings 2017-09-20 00:09:57 +09:00
John Rommel Estropia
1068517b94 Merge branch 'prototype/queryBuilders' of github.com:JohnEstropia/CoreStore into prototype/queryBuilders 2017-09-20 00:02:36 +09:00
John Estropia
0d23ce1598 fix Demo app compiler errors 2017-09-19 16:22:59 +09:00
John Estropia
fd1ce20863 set swift version 2017-09-19 16:04:26 +09:00
John Estropia
2c5fa63f40 revert 2017-09-19 15:55:51 +09:00
John Estropia
78e43a37a5 fix OSX compiler errors 2017-09-19 15:54:15 +09:00
John Rommel Estropia
fde85a9743 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-09-17 01:15:55 +09:00
John Rommel Estropia
dbbc0adae5 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-09-17 01:10:11 +09:00
John Rommel Estropia
2a62770552 Merge branch 'develop' into prototype/Swift_3_2 2017-09-10 12:31:30 +09:00
John Rommel Estropia
f436b26e8e allow compound keypaths in Select terms 2017-09-08 01:28:24 +09:00
John Rommel Estropia
c566226747 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-08-31 23:50:12 +09:00
John Rommel Estropia
cd405e038e updated demo app 2017-08-31 23:00:17 +09:00
John Estropia
92a37053b0 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-08-31 18:33:28 +09:00
John Estropia
0b57cff27d Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	Sources/DynamicSchema+Convenience.swift
2017-08-31 18:33:12 +09:00
John Estropia
3ebc44b546 optimize redundant casting in printCoreStoreSchema() 2017-08-31 18:28:23 +09:00
John Estropia
68f1027ba7 fix code misuse in readme 2017-08-31 17:55:10 +09:00
John Rommel Estropia
005729be85 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-08-26 14:29:16 +09:00
John Estropia
8bac4aa901 Fixed Xcode 9 beta 6 errors 2017-08-24 10:11:12 +09:00
John Estropia
da170c7e51 Fixed Xcode 9 beta 6 errors 2017-08-23 18:40:06 +09:00
John Estropia
211e69023e version bump 2017-08-23 12:59:36 +09:00
John Rommel Estropia
2912dcf010 iOS 11 fixed the NSFetchRequest.affectedStores bug 2017-08-23 12:55:02 +09:00
John Rommel Estropia
3e00a3da06 fix demo app errors 2017-08-17 09:24:33 +09:00
John Rommel Estropia
a33e248828 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	Sources/NSManagedObjectContext+Querying.swift
2017-08-16 21:09:09 +09:00
John Rommel Estropia
75e14fbbed Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0
# Conflicts:
#	Sources/NSManagedObjectContext+Querying.swift
2017-08-16 21:08:33 +09:00
John Rommel Estropia
9922deac4d Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	Sources/AttributeProtocol.swift
#	Sources/DynamicSchema+Convenience.swift
#	Sources/ImportableAttributeType.swift
#	Sources/Relationship.swift
#	Sources/RelationshipProtocol.swift
#	Sources/Transformable.swift
#	Sources/Value.swift
2017-08-16 21:07:34 +09:00
John Rommel Estropia
86be046c9f updated podspec 2017-08-16 20:43:10 +09:00
John Rommel Estropia
0f10bc3349 version bump 2017-08-16 20:26:22 +09:00
John Rommel Estropia
9685f0aef2 #191 2017-08-16 20:21:26 +09:00
John Estropia
1e51000155 Merge pull request #191 from sidmani/prototype/Swift_4_0
Corrected type-checking in fetchExisting to preserve input type
2017-08-16 20:20:23 +09:00
John Rommel Estropia
3bd459bb1a updated docs 2017-08-16 20:09:09 +09:00
Sid Mani
c89bc3c227 Corrected type-checking in fetchExisting to preserve input type 2017-08-16 00:36:06 -07:00
John Rommel Estropia
0f405a50aa WIP: KeyPath utilities for all clauses 2017-08-10 00:42:29 +09:00
John Estropia
f5e1643ef7 minor cleanup 2017-08-10 00:10:15 +09:00
John Rommel Estropia
f62137fb58 rename file 2017-08-10 00:10:08 +09:00
John Rommel Estropia
37fbedd799 WIP: keypath utilities for all raw clauses 2017-08-09 08:11:41 +09:00
John Rommel Estropia
28b43f33fa Value.Required now requires an "initial:" parameter. For previous CoreStoreObject users, use the appropriate empty value for your existing properties (0 for numeric types, false for Bool, "" for String) 2017-08-08 18:36:25 +09:00
John Rommel Estropia
81a72f29ea Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders 2017-08-08 08:02:17 +09:00
John Rommel Estropia
f7aaf4fb2a Fix compile errors for Xcode 9 beta 5 2017-08-08 08:02:05 +09:00
John Rommel Estropia
a52acf2ebd Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-08-08 07:56:32 +09:00
John Rommel Estropia
74c64619c3 Fix compile error for Xcode 9 beta 5 2017-08-08 07:56:21 +09:00
John Rommel Estropia
4a5bc6450b complete query utilities 2017-08-08 07:36:52 +09:00
John Rommel Estropia
fe69e7c6c4 Merge branch 'prototype/Swift_4_0' into prototype/queryBuilders
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
#	Sources/Relationship.swift
#	Sources/Value.swift
2017-08-05 23:02:00 +09:00
John Rommel Estropia
ccf7c62aad Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-08-05 08:25:49 +09:00
John Rommel Estropia
f36cb8af63 iOS 11 fixed the NSFetchRequest.affectedStores bug 2017-08-05 08:25:28 +09:00
John Rommel Estropia
10ccadd96c update demo app 2017-08-05 08:25:03 +09:00
John Rommel Estropia
5c0e78bd53 Deleted EmptyableAttributeType and require "initial" parameter for Value.Required 2017-08-05 00:03:17 +09:00
John Rommel Estropia
8a09688117 Merge branch 'develop' into prototype/Swift_3_2 2017-07-15 21:30:05 +09:00
John Estropia
a366bcf1a3 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2017-07-11 15:47:20 +09:00
John Rommel Estropia
fcd4be9011 WIP: chained queries for section monitors 2017-07-10 08:23:59 +09:00
John Rommel Estropia
535eb76adc WIP: query chains! 2017-07-09 10:44:53 +09:00
John Rommel Estropia
c6e68ac24f reset transactions' context on deinit to break reference cycles in unsafed many-to-many relationships 2017-07-05 23:32:45 +09:00
John Rommel Estropia
aff966aac9 WIP: Query builders 2017-07-05 08:45:10 +09:00
John Rommel Estropia
32743b3aee Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-07-04 23:16:49 +09:00
John Rommel Estropia
a20ad87583 Merge branch 'develop' into prototype/Swift_3_2 2017-07-04 23:14:06 +09:00
John Estropia
a11915db12 minor cleanup 2017-07-04 12:21:46 +09:00
John Rommel Estropia
961f39a806 add internal utilities to force checkpoint operations on SQLite 2017-07-01 17:05:10 +09:00
John Rommel Estropia
3096cb784c add internal utilities to force checkpoint operations on SQLite 2017-07-01 16:45:11 +09:00
John Rommel Estropia
809aa4ff96 allow querying file size on SQLiteStore 2017-07-01 11:50:23 +09:00
John Estropia
8d926d25ec Merge pull request #177 from blender/feature/optional-where-chaining
Add optional && and || operators to Where clause
2017-06-28 13:32:16 +09:00
Tommaso Piazza
790454f514 Add optional && and || operators to Where clause 2017-06-27 13:58:16 +02:00
John Rommel Estropia
9a38707c58 Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-26 00:36:07 +09:00
John Rommel Estropia
fb7e2f7f7f Merge branch 'develop' into prototype/Swift_3_2 2017-06-26 00:34:32 +09:00
John Rommel Estropia
f72efc80b2 added utilities for combining Where arrays and OrderBy arrays 2017-06-24 17:42:56 +09:00
John Estropia
fcda5399da Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-23 17:58:49 +09:00
John Estropia
fd3a9b00ec fix FRC breaking again for iOS 8 2017-06-23 17:58:34 +09:00
John Estropia
f56c37f9ee Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-23 12:43:20 +09:00
John Estropia
5f5000218a Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/Palette.swift
#	Sources/Value.swift
2017-06-23 12:43:03 +09:00
John Estropia
e8eb309d82 Added source docs on usage of custom getters and setters for CoreStoreObject properties (Value.Required, etc) 2017-06-20 20:32:27 +09:00
John Rommel Estropia
d0c3203e63 force reset contexts after autocommit 2017-06-17 21:50:21 +09:00
John Rommel Estropia
f5b3901caa fix tests and demo app 2017-06-17 02:13:54 +09:00
John Rommel Estropia
1a99fea820 complete PartialObject utilities 2017-06-17 01:55:36 +09:00
John Rommel Estropia
195b60615b added missing utilities 2017-06-16 01:42:09 +09:00
John Rommel Estropia
2c394965b8 remove direct access to CoreStoreObject.primitiveValues and replace PartialObject<O> 2017-06-16 01:02:23 +09:00
John Rommel Estropia
746d697691 WIP: new PartialObject to act as faster KVC wrappers when implementing custom getters and setters for CoreStoreObject 2017-06-15 08:27:08 +09:00
John Estropia
5689158b43 version bump 2017-06-14 21:50:58 +09:00
John Estropia
6fcdf3d011 fix logger demo 2017-06-14 17:43:34 +09:00
John Estropia
e26573c18e converted the Demo app's observer demo to use CoreStoreObject instead of NSManagedObject 2017-06-14 17:39:57 +09:00
John Estropia
801cf8d9f0 Fixed ListMonitor bug for CoreStoreObjects where ListObservers don't get update notifications 2017-06-14 17:37:46 +09:00
John Rommel Estropia
eced8f2e93 fixed compile error on release mode 2017-06-12 22:39:06 +09:00
John Rommel Estropia
3b735d07ec fix merge compile errors 2017-06-11 09:33:25 +09:00
John Rommel Estropia
5eb5476e3a Merge branch 'prototype/Swift_3_2' into prototype/Swift_4_0 2017-06-11 09:17:03 +09:00
John Rommel Estropia
6a42a0054e Merge branch 'develop' into prototype/Swift_3_2
# Conflicts:
#	Sources/CoreStoreManagedObject.swift
#	Sources/CoreStoreSchema.swift
#	Sources/NSEntityDescription+DynamicModel.swift
#	Sources/Value.swift
2017-06-11 09:16:34 +09:00
John Rommel Estropia
8c437e19b8 version bump 2017-06-10 23:19:02 +09:00
John Rommel Estropia
9cd3b6c879 code cleanup 2017-06-10 22:13:32 +09:00
John Rommel Estropia
fe135acbec Improve CoreStoreObjects KVO behavior 2017-06-10 21:02:36 +09:00
John Estropia
997c5bdcfa uniquify subclass names across model versions 2017-06-09 12:47:22 +09:00
John Estropia
23e12c4539 add constraints to Value.Optional and Value.Required native types 2017-06-09 11:30:09 +09:00
John Estropia
ca9798be14 add constraints to Value.Optional and Value.Required native types 2017-06-09 11:29:51 +09:00
John Estropia
6e01a58c85 Swift 4 support 2017-06-09 11:25:28 +09:00
John Estropia
f618617053 work around issue that crashes the Swift 3.2 compiler (fixes #171) 2017-06-08 20:18:50 +09:00
John Rommel Estropia
49b8b9c372 Merge branch 'master' into prototype/Swift_3_2 2017-06-08 08:10:59 +09:00
John Rommel Estropia
129f975d96 version bump 2017-06-08 01:17:39 +09:00
John Rommel Estropia
a2e463e58c Merge branch 'prototype/customMigrationTest' of github.com:JohnEstropia/CoreStore into prototype/customMigrationTest 2017-06-08 01:07:00 +09:00
John Rommel Estropia
5fd50f0e15 fix migration for CoreStoreObject relationships 2017-06-08 01:06:51 +09:00
John Estropia
7f9a915d71 WIP: Swift 3.2 2017-06-07 20:07:43 +09:00
John Estropia
0a81736b7a Merge branch 'develop' into prototype/customMigrationTest 2017-06-07 12:31:42 +09:00
John Estropia
f9b6dd0c6a fix bug when using ObjectMonitor with CoreStoreObjects 2017-06-06 17:40:29 +09:00
John Rommel Estropia
0354401b56 WIP: bugfix for CustomSchemaMappingProvider relationship migration bug 2017-06-06 08:39:59 +09:00
John Rommel Estropia
0304067beb fix ToManyOrdered and ToManyUnordered enumeration crash 2017-06-06 00:49:16 +09:00
John Rommel Estropia
ddd83da434 add Where comparison operators for optional values 2017-06-05 23:09:19 +09:00
John Estropia
fc7df671de Fixes https://bugs.swift.org/browse/SR-4981 2017-06-05 12:45:35 +09:00
John Rommel Estropia
5fde9030c7 use stronger namespace for CoreStoreObject's internal managed object type 2017-06-05 08:03:37 +09:00
John Rommel Estropia
d7b07b3f00 Added alternative way to set keyPathsForValuesAffectingValue(forKey:) for CoreStoreObjects 2017-06-05 01:30:26 +09:00
John Rommel Estropia
ddd1ffb29f added ~= operation to create Where clauses for value arrays 2017-06-03 08:51:52 +09:00
John Rommel Estropia
98094000bb Merge branch 'master' into develop 2017-06-02 23:10:31 +09:00
John Estropia
d5026ef996 Merge branch 'temp/develop' into develop 2017-06-02 19:35:01 +09:00
John Estropia
2cd913b9dd added more utilities for CoreStoreObject meta 2017-06-02 19:34:54 +09:00
John Estropia
ad9520abbc Update README.md 2017-06-02 13:24:15 +09:00
John Estropia
c0fc57d10c Update README.md 2017-06-02 11:34:04 +09:00
John Estropia
0cf4d303e4 Added README sample on how to version CoreStoreObjects 2017-06-02 11:32:48 +09:00
John Rommel Estropia
6de397958a fix demo app warnings 2017-06-02 02:06:47 +09:00
John Rommel Estropia
55292a84dc made mapping modell providers public 2017-06-02 02:03:41 +09:00
John Estropia
981b560d53 test travis ci 2017-05-30 11:14:57 +09:00
John Estropia
c4c4dd55cd test travis build 2017-05-30 11:06:30 +09:00
John Rommel Estropia
1ddbe20c86 Updated README, fixed demo app, and bumped to 4.0.1 2017-05-28 11:37:40 +09:00
John Rommel Estropia
da9e8c1550 disallow "empty" default values on some ImportableAttributeTypes 2017-05-28 10:50:25 +09:00
John Estropia
ef0937fec4 make unit tests happy 2017-05-24 12:15:55 +09:00
John Estropia
35885b40de README done! Welcome to CoreStore 4.0! 2017-05-24 12:05:34 +09:00
John Rommel Estropia
d669569196 WIP: readme 2017-05-24 00:37:32 +09:00
John Rommel Estropia
ae919ff3c8 WIP: readme 2017-05-24 00:35:25 +09:00
John Rommel Estropia
1a7a4690d1 WIP: readme 2017-05-24 00:33:43 +09:00
John Rommel Estropia
b9b96d1a35 WIP: Updating README and other docs. Some minor fixes 2017-05-22 01:27:38 +09:00
John Rommel Estropia
da3a9590ac accept optionals in setValue 2017-05-21 09:38:56 +09:00
John Rommel Estropia
6b3d75bea1 fix fixits 2017-05-21 09:29:34 +09:00
John Rommel Estropia
d44721fef0 fix xcode hints 2017-05-21 09:11:34 +09:00
John Rommel Estropia
3f268e8376 added NSManagedObject.setValue(_:forKvcKey:willSetValue:didSetValue:) 2017-05-21 09:06:29 +09:00
John Rommel Estropia
303fea4ebe fix warnings 2017-05-21 08:51:38 +09:00
John Estropia
77173cdad0 minor fix 2017-05-18 21:10:43 +09:00
John Estropia
1e24a7d739 ListObserver's listMonitorDidChange(_:) and listMonitorDidRefetch(_:) handlers are now required. 2017-05-18 12:59:58 +09:00
John Estropia
a3b33bedb8 added more migration error types 2017-05-18 12:59:02 +09:00
John Estropia
eaf7544c50 fix error when CoreStoreObject types have deep namespaces 2017-05-17 15:55:33 +09:00
John Estropia
67863120e0 WIP: readme 2017-05-15 11:03:21 +09:00
John Estropia
1b0e305d9a beta bump 2017-05-15 10:23:55 +09:00
John Rommel Estropia
91fda01071 WIP: readme 2017-05-15 08:51:31 +09:00
John Estropia
feb0e30735 tag as beta 2017-05-12 14:46:28 +09:00
John Rommel Estropia
9c25336ff6 WIP: documentation 2017-05-12 01:42:19 +09:00
John Estropia
66bef87422 WIP: documentation 2017-05-11 20:55:31 +09:00
John Rommel Estropia
dd2949ee18 WIP: documentation 2017-05-11 00:03:13 +09:00
John Estropia
e0abb9b0af Merge branch 'develop' into corestore4_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/CoreStoreImportableAttributeType.swift
#	Sources/CoreStoreQueryableAttributeType.swift
#	Sources/Info.plist
#	Sources/NSManagedObjectModel+Setup.swift
2017-05-10 19:11:01 +09:00
John Estropia
42c28b064a remove unneeded swift flags 2017-05-10 12:47:40 +09:00
John Estropia
0b097b8c85 version bump 2017-05-10 12:43:18 +09:00
John Estropia
fce5d2f301 Flatten file directories (fixes #159) 2017-05-10 12:42:20 +09:00
John Rommel Estropia
8ff163af30 WIP: documentation 2017-05-10 02:00:47 +09:00
John Estropia
19abedfa9f WIP: documentation 2017-05-09 21:16:03 +09:00
John Estropia
48828fdca3 Custom migrations! 2017-05-09 17:58:41 +09:00
John Rommel Estropia
9d65a27557 WIP: custom migration 2017-05-09 03:10:35 +09:00
John Rommel Estropia
6d04806608 WIP 2017-04-26 08:31:37 +09:00
John Rommel Estropia
54129f7362 Merge branch 'corestore4_develop' of github.com:JohnEstropia/CoreStore into corestore4_develop 2017-04-25 22:08:58 +09:00
John Estropia
54c81d23f5 WIP: dynamic migrations 2017-04-25 18:08:43 +09:00
John Estropia
53ab140341 Improve refetch method (may fix #118) 2017-04-24 11:57:47 +09:00
John Estropia
9dc4331b26 oops 2017-04-21 21:21:47 +09:00
John Estropia
e6aa72fb5f support transformable values 2017-04-21 19:35:29 +09:00
John Estropia
274a54451a fix compiler errors 2017-04-21 15:07:26 +09:00
John Estropia
fe70b7a27d added tool to convert existing NSManagedObjectModels to the new CoreStoreSchema 2017-04-21 14:54:57 +09:00
John Estropia
02a660e4a6 WIP: Migrations 2017-04-20 20:26:11 +09:00
John Estropia
a543a4c94a Added a "userInfo" property to relevant types to allow external code to store custom data 2017-04-20 16:40:27 +09:00
John Estropia
fd14a18248 Unify generics usage in ListMonitor and ObjectMonitor 2017-04-20 10:42:47 +09:00
John Estropia
b0e2655bdf added a typealias for the object type contained in ListMonitor and ObjectMonitor 2017-04-19 17:04:34 +09:00
John Estropia
b6bc7c2edf allow edit() calls to any DynamicObject 2017-04-18 18:14:16 +09:00
John Estropia
1938f0d9de no need to be optional 2017-04-18 12:09:37 +09:00
John Estropia
94e6db669f added a way to lazily-initialize user info data 2017-04-18 12:02:39 +09:00
John Estropia
b1972b82f1 added way to store userInfo in DataStack and in transactions 2017-04-18 11:29:16 +09:00
John Rommel Estropia
5ffaca1375 WIP: docs 2017-04-18 08:02:07 +09:00
John Estropia
a73306fecb check correct queue for managed object value access 2017-04-12 19:22:18 +09:00
John Estropia
9f3db61ff7 WIP: allow migrations for CoreStoreObjects 2017-04-11 19:13:35 +09:00
John Estropia
e5ef4992d3 WIP: migrations for CoreStoreObjects 2017-04-07 21:57:45 +09:00
John Estropia
c0ae129b22 NSManagedObject features are now fully supported for CoreStoreObject types. MacOSX 10.12 onwards now support ListMonitors and ObjectMonitors 2017-04-07 20:14:13 +09:00
John Estropia
4aa1a63f9a updated unit tests with easier to understand examples 2017-04-06 20:45:54 +09:00
John Estropia
4fc10afe1e relationships done! 2017-04-06 20:28:17 +09:00
John Estropia
8b77e4e5a0 WIP: prototype for ManagedObjectProtocol 2017-04-05 21:56:19 +09:00
John Estropia
258c237100 It works! (WIP!) 2017-04-04 20:25:40 +09:00
John Estropia
6948db516d WIP: typesafe queries 2017-04-03 22:02:24 +09:00
John Estropia
b5d80fd272 WIP: Dynamic models (Goodbye xcdatamodel files!) 2017-04-03 21:41:25 +09:00
John Rommel Estropia
cdcd7d0416 removed deprecated functions in unit tests and demo app 2017-04-01 23:08:36 +09:00
John Rommel Estropia
a5162239d5 kick-off deprecations with 4.0 version bump 2017-04-01 21:23:50 +09:00
John Rommel Estropia
1ad6ac5769 accept NSManagedObject as Where predicate argument 2017-04-01 17:15:24 +09:00
John Rommel Estropia
ecb3d0cfa0 revert prototyped stack setup 2017-04-01 01:31:40 +09:00
John Estropia
81355fd9c5 update travis file for Xcode 8.3 2017-03-31 19:56:19 +09:00
John Estropia
97d7a276fe new auto-commit transaction methods 2017-03-31 19:44:18 +09:00
John Estropia
d72d1afe8b Merge branch 'develop' into corestore4_develop
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
2017-03-28 11:38:02 +09:00
John Estropia
716e069984 version bump 2017-03-28 11:25:24 +09:00
John Estropia
881ee4af0a remove warnings when calling unsafeBitCast() 2017-03-28 10:54:08 +09:00
John Estropia
acc0ce1c32 Merge pull request #157 from ruslanskorb/fetched-objects-dynamicCast
Use `dynamicCast()` to cast `fetchedObjects` to `[T]?` without checking the type.
2017-03-28 10:10:23 +09:00
John Estropia
b97f6d6a0a Merge branch 'prototype/mainContextToPSC' into corestore4_develop 2017-03-27 14:08:07 +09:00
John Rommel Estropia
818abfc1a1 WIP 2017-03-27 01:48:51 +09:00
Ruslan Skorb
f055c54a66 [ListMonitor] Use dynamicCast() to cast fetchedObjects to [T]? without checking the type.
Type checking takes a time. So there is a performance problem when casting a large number of fetched objects to an array of a certain type using the operator `as?`.
2017-03-24 21:30:46 +02:00
John Estropia
cb6d5b015b WIP: prototyping new transaction structure 2017-03-24 21:15:51 +09:00
John Rommel Estropia
494965de23 changed protocol naming 2017-03-10 08:30:12 +09:00
John Estropia
fe25a9aa36 remove warnings when calling unsafeBitCast() 2017-03-09 18:59:37 +09:00
John Estropia
f21e4e12e0 Merge branch 'develop' into corestore4_develop 2017-03-09 18:08:35 +09:00
John Estropia
92890d1e1d Merge pull request #154 from ruslanskorb/remove-duplicate-code
[FetchedResultsControllerDelegate] Remove duplicate code.
2017-03-07 12:58:18 +09:00
Ruslan Skorb
0c483e0e19 [FetchedResultsControllerDelegate] Remove duplicate code. 2017-03-05 12:20:12 +02:00
John Rommel Estropia
6055685c00 WIP: compilable again now 2017-03-02 22:26:45 +09:00
John Rommel Estropia
ee71442b08 Merge branch 'develop' into corestore4_develop 2017-03-02 21:07:30 +09:00
John Estropia
341ec5e771 reverted unsafeDowncast usage to unsafeBitCast (It worked differently) 2017-03-01 19:56:13 +09:00
John Estropia
8569c3c524 WIP: rehaul of type-safe fetching and querying 2017-03-01 19:34:07 +09:00
John Estropia
3224fcf71d move type safety goodness 2017-02-21 19:17:06 +09:00
John Rommel Estropia
9ff1c9d545 declare operators as static functions 2017-02-19 20:05:23 +09:00
John Rommel Estropia
c40d17a6ad Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2017-02-19 09:56:40 +09:00
John Estropia
9d5e04854a extra extra type safety for attributes (fetching and importing) 2017-02-17 14:13:16 +09:00
John Estropia
d2fd03c1f0 Where clauses are now more strict with the argument types 2017-02-17 10:47:38 +09:00
John Rommel Estropia
7baaee493d unit test for scalar IDs for ImportableUniqueObject 2017-02-13 22:17:03 +09:00
John Estropia
7ee027f44d Test mainContext fetching directly from PSC. Needs benchmarking esp. with merging 2017-02-09 10:49:50 +09:00
638 changed files with 495908 additions and 14823 deletions

2
.cocoapods.yml Normal file
View File

@@ -0,0 +1,2 @@
try:
project: 'CoreStore.xcworkspace'

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ CoreStore.xcworkspace/xcuserdata
.DS_Store
DerivedData
*.orig
build
Playground_macOS.playground/playground.xcworkspace/xcuserdata

15
.jazzy.yaml Normal file
View 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

View File

@@ -1 +0,0 @@
3.0.1

View File

@@ -1,5 +1,5 @@
language: objective-c
osx_image: xcode8.2
osx_image: xcode10.2
sudo: false
git:
submodules: false
@@ -10,25 +10,22 @@ env:
- LC_CTYPE=en_US.UTF-8
- LANG=en_US.UTF-8
matrix:
- DESTINATION="OS=10.1,name=iPhone 7" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.0,name=iPhone 6 Plus" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.4,name=iPhone 6" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 5" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=8.3,name=iPhone 4S" SCHEME="CoreStore iOS" SDK=iphonesimulator10.2 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="arch=x86_64" SCHEME="CoreStore OSX" SDK=macosx10.12 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=3.1,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.1 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="CoreStore watchOS" SDK=watchsimulator3.1 RUN_TESTS="NO" POD_LINT="NO"
- DESTINATION="OS=10.1,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.1 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="CoreStore tvOS" SDK=appletvsimulator10.1 RUN_TESTS="YES" POD_LINT="NO"
- DESTINATION="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.18/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
@@ -37,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.2" -destination "OS=10.1,name=iPhone 7" -configuration Debug ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "CoreStore iOS" -sdk "iphonesimulator10.2" -destination "OS=10.1,name=iPhone 7" -configuration Release ONLY_ACTIVE_ARCH=NO clean test | xcpretty -c;
- xcodebuild -workspace "CoreStore.xcworkspace" -scheme "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

View File

View File

View File

@@ -1,22 +1,22 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "3.0.3"
s.version = "6.3.2"
s.swift_version = "5.0"
s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore"
s.documentation_url = "https://JohnEstropia.github.io/CoreStore"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.author = { "John Rommel Estropia" => "rommel.estropia@gmail.com" }
s.source = { :git => "https://github.com/JohnEstropia/CoreStore.git", :tag => s.version.to_s }
s.ios.deployment_target = "8.0"
s.osx.deployment_target = "10.10"
s.watchos.deployment_target = "2.0"
s.tvos.deployment_target = "9.0"
s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.12"
s.watchos.deployment_target = "3.0"
s.tvos.deployment_target = "10.0"
s.source_files = "Sources", "Sources/**/*.{swift,h,m}"
s.public_header_files = "Sources/**/*.h"
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.pod_target_xcconfig = { 'OTHER_SWIFT_FLAGS[config=Debug]' => '-D DEBUG' }
end

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -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>

View File

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

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -63,6 +63,11 @@
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
</TestAction>
<LaunchAction
@@ -84,6 +89,12 @@
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
<CommandLineArgument
argument = "-com.apple.CoreData.SQLDebug 2"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>

View File

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

View File

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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 */; };
@@ -266,18 +265,18 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "John Rommel Estropia";
TargetAttributes = {
B54AAD481AF4D26E00848AE0 = {
CreatedOnToolsVersion = 6.3;
LastSwiftMigration = 0800;
LastSwiftMigration = 0900;
};
};
};
buildConfigurationList = B54AAD441AF4D26E00848AE0 /* Build configuration list for PBXProject "CoreStoreDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
@@ -331,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 */,
@@ -373,14 +371,22 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -404,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;
};
@@ -420,14 +428,22 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -444,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;
@@ -456,11 +474,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
};
name = Debug;
};
@@ -469,12 +486,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = CoreStoreDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.corestore.demo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
};
name = Release;
};

View File

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

View File

@@ -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: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
application.statusBarStyle = .lightContent
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
return true
}

View File

@@ -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"/>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
@@ -22,26 +22,24 @@ private struct Static {
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.isDaylightSavingTime
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
}()
}
@@ -166,67 +164,80 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
title: "All Time Zones",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
return try! Static.timeZonesStack.fetchAll(
From<TimeZone>()
.orderBy(.ascending(\.name))
)
}
),
(
title: "Time Zones in Asia",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Asia"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
return try! Static.timeZonesStack.fetchAll(
From<TimeZone>()
.where(
format: "%K BEGINSWITH[c] %@",
#keyPath(TimeZone.name),
"Asia"
)
.orderBy(.ascending(\.secondsFromGMT))
)
}
),
(
title: "Time Zones in America and Europe",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America")
|| Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "Europe"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
return try! Static.timeZonesStack.fetchAll(
From<TimeZone>()
.where(
format: "%K BEGINSWITH[c] %@ OR %K BEGINSWITH[c] %@",
#keyPath(TimeZone.name),
"America",
#keyPath(TimeZone.name),
"Europe"
)
.orderBy(.ascending(\.secondsFromGMT))
)
}
),
(
title: "All Time Zones Except America",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
!Where("%K BEGINSWITH[c] %@", #keyPath(TimeZone.name), "America"),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)))
)!
return try! Static.timeZonesStack.fetchAll(
From<TimeZone>()
.where(
format: "%K BEGINSWITH[c] %@",
#keyPath(TimeZone.name),
"America"
)
.orderBy(.ascending(\.secondsFromGMT))
)
}
),
(
title: "Time Zones with Summer Time",
fetch: { () -> [TimeZone] in
return Static.timeZonesStack.fetchAll(
From<TimeZone>(),
Where("hasDaylightSavingTime", isEqualTo: true),
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
return try! Static.timeZonesStack.fetchAll(
From<TimeZone>()
.where(\.hasDaylightSavingTime == true)
.orderBy(.ascending(\.name))
)
}
)
]
private let queryingItems = [
private let queryingItems: [(title: String, query: () -> Any)] = [
(
title: "Number of Time Zones",
query: { () -> Any in
return Static.timeZonesStack.queryValue(
From<TimeZone>(),
Select<NSNumber>(.count(#keyPath(TimeZone.name)))
return try! Static.timeZonesStack.queryValue(
From<TimeZone>()
.select(NSNumber.self, .count(\.name))
)!
}
),
@@ -234,10 +245,10 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
title: "Abbreviation For Tokyo's Time Zone",
query: { () -> Any in
return Static.timeZonesStack.queryValue(
From<TimeZone>(),
Select<String>(#keyPath(TimeZone.abbreviation)),
Where("%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
return try! Static.timeZonesStack.queryValue(
From<TimeZone>()
.select(String.self, .attribute(\.abbreviation))
.where(format: "%K ENDSWITH[c] %@", #keyPath(TimeZone.name), "Tokyo")
)!
}
),
@@ -245,38 +256,53 @@ class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSo
title: "All Abbreviations",
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From<TimeZone>(),
Select<NSDictionary>(#keyPath(TimeZone.name), #keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.name)))
)!
return try! Static.timeZonesStack.queryAttributes(
From<TimeZone>()
.select(
NSDictionary.self,
.attribute(\.name),
.attribute(\.abbreviation)
)
.orderBy(.ascending(\.name))
)
}
),
(
title: "Number of Countries per Time Zone",
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From<TimeZone>(),
Select<NSDictionary>(.count(#keyPath(TimeZone.abbreviation)), #keyPath(TimeZone.abbreviation)),
GroupBy(#keyPath(TimeZone.abbreviation)),
OrderBy(.ascending(#keyPath(TimeZone.secondsFromGMT)), .ascending(#keyPath(TimeZone.name)))
)!
return try! Static.timeZonesStack.queryAttributes(
From<TimeZone>()
.select(
NSDictionary.self,
.count(\.abbreviation),
.attribute(\.abbreviation)
)
.groupBy(\.abbreviation)
.orderBy(
.ascending(\.secondsFromGMT),
.ascending(\.name)
)
)
}
),
(
title: "Number of Countries with Summer Time",
query: { () -> Any in
return Static.timeZonesStack.queryAttributes(
From<TimeZone>(),
Select<NSDictionary>(
.count(#keyPath(TimeZone.hasDaylightSavingTime), as: "numberOfCountries"),
#keyPath(TimeZone.hasDaylightSavingTime)
),
GroupBy(#keyPath(TimeZone.hasDaylightSavingTime)),
OrderBy(.descending(#keyPath(TimeZone.hasDaylightSavingTime)))
)!
return try! Static.timeZonesStack.queryAttributes(
From<TimeZone>()
.select(
NSDictionary.self,
.count(\.hasDaylightSavingTime, as: "numberOfCountries"),
.attribute(\.hasDaylightSavingTime)
)
.groupBy(\.hasDaylightSavingTime)
.orderBy(
.descending(\.hasDaylightSavingTime),
.ascending(\.name)
)
)
}
)
]

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/17.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2018 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -30,7 +30,7 @@ class FetchingResultsViewController: UITableViewController {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 60
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.rowHeight = UITableView.automaticDimension
}

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/17.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2018 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -49,7 +49,7 @@ class QueryingResultsViewController: UITableViewController {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 60
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.rowHeight = UITableView.automaticDimension
}

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -3,14 +3,14 @@
// 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 {
@@ -28,13 +28,13 @@ private struct Static {
}
}
func whereClause() -> Where {
func whereClause() -> Where<Palette> {
switch self {
case .all: return Where(true)
case .light: return Where("%K >= %@", #keyPath(Palette.brightness), 0.9)
case .dark: return Where("%K <= %@", #keyPath(Palette.brightness), 0.4)
case .all: return .init()
case .light: return (\Palette.brightness >= 0.9)
case .dark: return (\Palette.brightness <= 0.4)
}
}
}
@@ -43,24 +43,40 @@ private struct Static {
didSet {
self.palettes.refetch(self.filter.whereClause())
self.palettes.refetch(
self.filter.whereClause(),
OrderBy<Palette>(.ascending(\.hue))
)
}
}
static let stack: DataStack = {
return DataStack(
CoreStoreSchema(
modelVersion: "ColorsDemo",
entities: [
Entity<Palette>("Palette"),
],
versionLock: [
"Palette": [0x8c25aa53c7c90a28, 0xa243a34d25f1a3a7, 0x56565b6935b6055a, 0x4f988bb257bf274f]
]
)
)
}()
static let palettes: ListMonitor<Palette> = {
try! CoreStore.addStorageAndWait(
try! ColorsDemo.stack.addStorageAndWait(
SQLiteStore(
fileName: "ColorsDemo.sqlite",
configuration: "ObservingDemo",
localStorageOptions: .recreateStoreOnModelMismatch
)
)
return CoreStore.monitorSectionedList(
From<Palette>(),
SectionBy(#keyPath(Palette.colorName)),
OrderBy(.ascending(#keyPath(Palette.hue)))
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)
}
@@ -95,7 +111,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
]
let filterBarButton = UIBarButtonItem(
title: Static.filter.rawValue,
title: ColorsDemo.filter.rawValue,
style: .plain,
target: self,
action: #selector(self.filterBarButtonItemTouched(_:))
@@ -106,13 +122,18 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
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.setTable(enabled: !Static.palettes.isPendingRefetch)
self.setTable(enabled: !ColorsDemo.palettes.isPendingRefetch)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
@@ -134,19 +155,19 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
override func numberOfSections(in tableView: UITableView) -> Int {
return Static.palettes.numberOfSections()
return ColorsDemo.palettes.numberOfSections()
}
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, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
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
@@ -162,21 +183,23 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
self.performSegue(
withIdentifier: "ObjectObserverDemoViewController",
sender: Static.palettes[indexPath]
sender: ColorsDemo.palettes[indexPath]
)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
switch editingStyle {
case .delete:
let palette = Static.palettes[indexPath]
CoreStore.beginAsynchronous{ (transaction) -> Void in
transaction.delete(palette)
transaction.commit { (result) -> Void in }
}
let palette = ColorsDemo.palettes[indexPath]
ColorsDemo.stack.perform(
asynchronous: { (transaction) in
transaction.delete(palette)
},
completion: { _ in }
)
default:
break
@@ -185,7 +208,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Static.palettes.sectionInfoAtIndex(section).name
return ColorsDemo.palettes.sectionInfo(at: section).name
}
@@ -208,7 +231,7 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
func listMonitorDidRefetch(_ monitor: ListMonitor<Palette>) {
self.filterBarButton?.title = Static.filter.rawValue
self.filterBarButton?.title = ColorsDemo.filter.rawValue
self.tableView.reloadData()
self.setTable(enabled: true)
}
@@ -230,16 +253,15 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
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: IndexPath, toIndexPath: IndexPath) {
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
self.tableView.moveRow(at: fromIndexPath, to: toIndexPath)
}
@@ -250,7 +272,6 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
}
func listMonitor(_ monitor: ListMonitor<Palette>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
@@ -263,31 +284,54 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
@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?) {
Static.filter = Static.filter.next()
ColorsDemo.filter = ColorsDemo.filter.next()
}
@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 setTable(enabled: Bool) {
tableView.isUserInteractionEnabled = enabled
UIView.animate(
withDuration: 0.2,
delay: 0,
@@ -297,7 +341,6 @@ class ListObserverDemoViewController: UITableViewController, ListSectionObserver
if let tableView = self.tableView {
tableView.alpha = enabled ? 1.0 : 0.5
tableView.isUserInteractionEnabled = enabled
}
},
completion: nil

View File

@@ -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(#keyPath(Palette.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.self))
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(#keyPath(Palette.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,7 +85,7 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
// MARK: ObjectObserver
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<Palette>, didUpdateObject object: Palette, changedPersistentKeys: Set<KeyPathString>) {
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
}
@@ -121,54 +121,62 @@ class ObjectObserverDemoViewController: UIViewController, ObjectObserver {
@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?) {
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?) {
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?) {
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>?) {
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(#keyPath(Palette.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(#keyPath(Palette.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(#keyPath(Palette.brightness)) == true {
if changedKeys == nil || changedKeys?.contains(String(keyPath: \Palette.brightness)) == true {
self.brightnessSlider?.value = palette.brightness
self.brightnessSlider?.value = palette.brightness.value
}
}
}

View File

@@ -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

View File

@@ -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 = #keyPath(Palette.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: #keyPath(Palette.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
}
}

View File

@@ -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

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/05.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2018 John Rommel Estropia. All rights reserved.
//
import UIKit
@@ -16,11 +16,6 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
// MARK: NSObject
deinit {
CoreStore.logger = DefaultLogger()
}
let dataStack = DataStack()
// MARK: UIViewController
@@ -30,13 +25,14 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
super.viewDidLoad()
try! self.dataStack.addStorageAndWait(SQLiteStore(fileName: "emptyStore.sqlite"))
CoreStore.logger = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
CoreStore.logger = self
let alert = UIAlertController(
title: "Logger Demo",
message: "This demo shows how to plug-in any logging framework to CoreStore.\n\nThe view controller implements CoreStoreLogger and appends all logs to the text view.",
@@ -46,6 +42,13 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
self.present(alert, animated: true, completion: nil)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
CoreStore.logger = DefaultLogger()
}
// MARK: CoreStoreLogger
@@ -98,10 +101,9 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
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(
@@ -112,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:

View File

@@ -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
@@ -46,7 +46,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
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, ListObserver, UITableViewD
}
for model in models {
if model.version == storeVersion {
if model.schemaHistory.currentModelVersion == storeVersion {
return model
}
@@ -79,7 +79,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
func listMonitorDidChange(_ monitor: ListMonitor<NSManagedObject>) {
if self.lastSelectedIndexPath == nil,
let numberOfObjectsInSection = self.listMonitor?.numberOfObjectsInSection(0),
let numberOfObjectsInSection = self.listMonitor?.numberOfObjects(in: 0),
numberOfObjectsInSection > 0 {
self.tableView?.reloadData()
@@ -91,11 +91,16 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
}
}
func listMonitorDidRefetch(_ monitor: ListMonitor<NSManagedObject>) {
self.listMonitorDidChange(monitor)
}
// MARK: UITableViewDataSource
@objc dynamic func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.listMonitor?.numberOfObjectsInSection(0) ?? 0
return self.listMonitor?.numberOfObjects(in: 0) ?? 0
}
@objc dynamic func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@@ -104,7 +109,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
let dna = (self.listMonitor?[indexPath] as? OrganismProtocol)?.dna.description ?? ""
cell.dnaLabel?.text = "DNA: \(dna)"
cell.mutateButtonHandler = { [weak self] _ -> Void in
cell.mutateButtonHandler = { [weak self] () -> Void in
guard let `self` = self,
let dataStack = self.dataStack,
@@ -115,16 +120,17 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
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
dataStack.perform(
asynchronous: { (transaction) in
let organism = transaction.edit(organism) as! OrganismProtocol
organism.mutate()
},
completion: { [weak self] _ in
self?.setEnabled(true)
}
}
)
}
return cell
}
@@ -140,29 +146,47 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
// 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"]
)
)
]
@@ -209,21 +233,44 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
private func selectModelVersion(_ model: ModelMetadata) {
if self.dataStack?.modelVersion == model.version {
if self.dataStack?.modelVersion == model.schemaHistory.currentModelVersion {
return
}
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 {
@@ -239,9 +286,9 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
self.set(dataStack: dataStack, model: model, scrollToSelection: true)
let count = dataStack.queryValue(
From(model.entityType),
Select<Int>(.count(#keyPath(OrganismV1.dna))))!
let count = try! dataStack.queryValue(
From<NSManagedObject>(model.entityType)
.select(Int.self, .count(#keyPath(OrganismV1.dna))))!
if count > 0 {
self.setEnabled(true)
@@ -250,25 +297,26 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
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)
}
}
)
}
}
)
@@ -311,16 +359,26 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
if let dataStack = dataStack, let model = model {
self.segmentedControl?.selectedSegmentIndex = self.models.map { $0.version }.index(of: 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(IndexPath(row: 0, section: 0), scrollToSelection: true)
}
@@ -328,7 +386,7 @@ class MigrationsDemoViewController: UIViewController, ListObserver, UITableViewD
}
else {
self.segmentedControl?.selectedSegmentIndex = UISegmentedControlNoSegment
self.segmentedControl?.selectedSegmentIndex = UISegmentedControl.noSegment
self._listMonitor = nil
self._dataStack = nil
}

View File

@@ -3,12 +3,12 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2018 John Rommel Estropia. All rights reserved.
//
import Foundation
protocol OrganismProtocol: class {
protocol OrganismProtocol: AnyObject {
var dna: Int64 { get set }

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -3,7 +3,7 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/06/27.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2018 John Rommel Estropia. All rights reserved.
//
import CoreData

View File

@@ -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

View File

@@ -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>

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="11198.3" systemVersion="15F34" minimumToolsVersion="Xcode 4.3" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model 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" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasHead" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasTail" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="hasVertebrae" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="numberOfLimbs" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="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"/>

View File

@@ -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

View File

@@ -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

View File

@@ -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,7 +17,7 @@ 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",
@@ -33,29 +33,29 @@ private struct Static {
)
)
_ = 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",
@@ -71,23 +71,22 @@ private struct Static {
)
)
_ = 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,8 +99,8 @@ private struct Static {
class StackSetupDemoViewController: UITableViewController {
let accounts = [
Static.facebookStack.fetchAll(From(UserAccount.self)) ?? [],
Static.twitterStack.fetchAll(From(UserAccount.self)) ?? []
try! Static.facebookStack.fetchAll(From<UserAccount>()),
try! Static.twitterStack.fetchAll(From<UserAccount>())
]

View File

@@ -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

View File

@@ -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

View File

@@ -3,10 +3,11 @@
// CoreStoreDemo
//
// Created by John Rommel Estropia on 2015/05/24.
// Copyright © 2015 John Rommel Estropia. All rights reserved.
// Copyright © 2018 John Rommel Estropia. All rights reserved.
//
import UIKit
import Contacts
import CoreLocation
import MapKit
import AddressBookUI
@@ -25,17 +26,17 @@ private struct Static {
)
)
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!)
@@ -131,7 +132,7 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
// none
}
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<Place>, didUpdateObject object: Place, changedPersistentKeys: Set<KeyPathString>) {
if let mapView = self.mapView {
@@ -169,23 +170,26 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Objec
gesture.location(in: mapView),
toCoordinateFrom: mapView
)
CoreStore.beginAsynchronous { (transaction) -> Void in
let place = transaction.edit(Static.placeController.object)
place?.coordinate = coordinate
transaction.commit { (_) -> 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?) {
_ = CoreStore.beginSynchronous { (transaction) -> Void in
let place = transaction.edit(Static.placeController.object)
place?.setInitialValues()
_ = transaction.commitAndWait()
}
_ = try? CoreStore.perform(
synchronous: { (transaction) in
let place = transaction.edit(Static.placeController.object)
place?.setInitialValues()
}
)
}
func geocode(place: Place) {
@@ -200,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 }
}

View File

@@ -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,10 @@ class BaseTestCase: XCTestCase {
// MARK: Internal
@nonobjc
@discardableResult
func prepareStack<T>(configurations: [String?] = [nil], _ closure: (_ dataStack: DataStack) -> T) -> T {
func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) throws -> Void) {
let stack = DataStack(
modelName: "Model",
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
do {
@@ -57,16 +56,16 @@ class BaseTestCase: XCTestCase {
)
)
}
try closure(stack)
}
catch let error as NSError {
XCTFail(error.coreStoreDumpString)
}
return closure(stack)
}
@nonobjc
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () -> T) -> T {
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
CoreStore.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer {
@@ -74,7 +73,7 @@ class BaseTestCase: XCTestCase {
self.checkExpectationsImmediately()
CoreStore.logger = TestLogger([:])
}
return closure()
return try closure()
}
@nonobjc
@@ -82,6 +81,33 @@ class BaseTestCase: XCTestCase {
CoreStore.logger = TestLogger(expectations)
}
@nonobjc
func expectError<T>(code: CoreStoreErrorCode, closure: () throws -> T) {
CoreStore.logger = TestLogger(self.prepareLoggerExpectations([.logError]))
defer {
self.checkExpectationsImmediately()
CoreStore.logger = TestLogger([:])
}
do {
_ = try closure()
}
catch let error as CoreStoreError {
if error.errorCode == code.rawValue {
return
}
XCTFail("Expected error code \(code) different from actual error: \((error as NSError).coreStoreDumpString)")
}
catch {
XCTFail("Error not wrapped as \(cs_typeName(CoreStoreError.self)): \((error as NSError).coreStoreDumpString)")
}
}
@nonobjc
func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {

View File

@@ -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,7 +34,7 @@ import CoreStore
class BaseTestDataTestCase: BaseTestCase {
@nonobjc
let dateFormatter: DateFormatter = {
let dateFormatter: DateFormatter = cs_lazy {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
@@ -25,52 +42,53 @@ class BaseTestDataTestCase: BaseTestCase {
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.enumerated() {
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(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)
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(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)
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()
}
)
}
}

View File

@@ -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

View File

@@ -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,42 +250,18 @@
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
[expectation fulfill];
[transaction
commitWithSuccess:^{
[expectation fulfill];
}
failure:^(CSError *error){
XCTFail();
}];
}];
}
[self waitForExpectationsWithTimeout:10 handler:nil];
}
#if TARGET_OS_IOS || TARGET_OS_WATCHOS || TARGET_OS_TV
- (void)test_ThatDataStacks_CanCreateCustomFetchedResultsControllers {
[CSCoreStore
setDefaultStack:[[CSDataStack alloc]
initWithModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]];
[CSCoreStore
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:nil];
NSFetchedResultsController *controller =
[[CSCoreStore defaultStack]
createFetchedResultsControllerFrom:CSFromClass([TestEntity1 class])
sectionBy:[CSSectionBy keyPath:CSKeyPath(TestEntity1, testString)]
fetchClauses:@[CSWhereFormat(@"%K > %d", CSKeyPath(TestEntity1, testEntityID), 100),
CSOrderByKeys(CSSortAscending(CSKeyPath(TestEntity1, testString)), nil),
CSTweakRequest(^(NSFetchRequest *fetchRequest) { fetchRequest.fetchLimit = 10; })]];
XCTAssertNotNil(controller);
XCTAssertEqualObjects(controller.fetchRequest.entity.managedObjectClassName, [[TestEntity1 class] description]);
XCTAssertEqualObjects(controller.sectionNameKeyPath, CSKeyPath(TestEntity1, testString));
XCTAssertEqualObjects(controller.fetchRequest.predicate,
CSWhereFormat(@"%K > %d", CSKeyPath(TestEntity1, testEntityID), 100).predicate);
XCTAssertEqualObjects(controller.fetchRequest.sortDescriptors,
CSOrderByKeys(CSSortAscending(CSKeyPath(TestEntity1, testString)), nil).sortDescriptors);
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10);
}
#endif
@end

View File

@@ -2,7 +2,7 @@
// ConvenienceTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -27,10 +27,9 @@
import CoreStore
#if os(iOS) || os(watchOS) || os(tvOS)
// MARK: - ConvenienceTests
@available(macOS 10.12, *)
class ConvenienceTests: BaseTestCase {
@objc
@@ -41,8 +40,8 @@ class ConvenienceTests: BaseTestCase {
let controller = stack.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.ascending(#keyPath(TestEntity1.testString))),
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, stack.mainContext)
@@ -50,11 +49,11 @@ class ConvenienceTests: BaseTestCase {
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
@@ -70,8 +69,8 @@ class ConvenienceTests: BaseTestCase {
let controller = transaction.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy(.ascending(#keyPath(TestEntity1.testString))),
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, transaction.context)
@@ -79,16 +78,14 @@ class ConvenienceTests: BaseTestCase {
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
}
}
#endif

View 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)
}
}

View File

@@ -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
@@ -85,16 +85,21 @@ final class ErrorTests: XCTestCase {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let model = NSManagedObjectModel.fromBundle(Bundle(for: type(of: self)), 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)
let userInfo: NSDictionary = [
"localStoreURL": dummyURL,
"targetModel": model,
"targetModel": schemaHistory.rawModel,
"targetModelVersion": version
]
let objcError = error.bridgeToObjectiveC

File diff suppressed because it is too large Load Diff

View File

@@ -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 = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
try from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -115,102 +113,98 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -225,99 +219,96 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(Set(affectedConfigurations), ["PF_DEFAULT_CONFIGURATION_NAME", "Config1"] as Set)
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity2>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
@@ -332,96 +323,94 @@ final class FromTests: BaseTestCase {
let from = From<TestEntity1>()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
do {
let from = From<TestEntity2>("Config1")
let request = CoreStoreFetchRequest()
let storesFound = self.expectLogger([.logWarning]) {
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
from.applyToFetchRequest(request, context: dataStack.mainContext)
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertFalse(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = CoreStoreFetchRequest()
let storesFound = from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertTrue(storesFound)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores!.map { $0.configurationName }
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
}

View File

@@ -2,7 +2,7 @@
// GroupByTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -38,14 +38,14 @@ final class GroupByTests: BaseTestCase {
do {
let groupBy = GroupBy()
let groupBy = GroupBy<NSManagedObject>()
XCTAssertEqual(groupBy, GroupBy([] as [String]))
XCTAssertNotEqual(groupBy, GroupBy("key"))
XCTAssertTrue(groupBy.keyPaths.isEmpty)
}
do {
let groupBy = GroupBy("key1")
let groupBy = GroupBy<NSManagedObject>("key1")
XCTAssertEqual(groupBy, GroupBy("key1"))
XCTAssertEqual(groupBy, GroupBy(["key1"]))
XCTAssertNotEqual(groupBy, GroupBy("key2"))
@@ -53,7 +53,7 @@ final class GroupByTests: BaseTestCase {
}
do {
let groupBy = GroupBy("key1", "key2")
let groupBy = GroupBy<NSManagedObject>("key1", "key2")
XCTAssertEqual(groupBy, GroupBy("key1", "key2"))
XCTAssertEqual(groupBy, GroupBy(["key1", "key2"]))
XCTAssertNotEqual(groupBy, GroupBy("key2", "key1"))
@@ -66,10 +66,10 @@ final class GroupByTests: BaseTestCase {
self.prepareStack { (dataStack) in
let groupBy = GroupBy(#keyPath(TestEntity1.testString))
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
let request = CoreStoreFetchRequest()
_ = From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
try From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
groupBy.applyToFetchRequest(request)
XCTAssertNotNil(request.propertiesToGroupBy)

File diff suppressed because it is too large Load Diff

View File

@@ -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>

View File

@@ -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>())
XCTAssertEqual(into, Into(TestEntity1.self))
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>())
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.self))
XCTAssertFalse(into == Into<TestEntity2>())
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)
}
}
}

View File

@@ -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
@@ -44,7 +43,7 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
@@ -55,7 +54,7 @@ class ListObserverTests: BaseTestDataTestCase {
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -69,7 +68,7 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let didInsertSectionExpectation = self.expectation(
forNotification: "listMonitor:didInsertSection:toSectionIndex:",
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
object: observer,
handler: { (note) -> Bool in
@@ -77,7 +76,7 @@ class ListObserverTests: BaseTestDataTestCase {
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
[
"sectionInfo": monitor.sectionInfoAtIndex(0),
"sectionInfo": monitor.sectionInfo(at: 0),
"sectionIndex": 0
] as NSDictionary
)
@@ -89,7 +88,7 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let didInsertObjectExpectation = self.expectation(
forNotification: "listMonitor:didInsertObject:toIndexPath:",
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: observer,
handler: { (note) -> Bool in
@@ -103,8 +102,8 @@ class ListObserverTests: BaseTestDataTestCase {
)
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(value: true))
@@ -121,7 +120,7 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -134,29 +133,29 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
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")!
transaction.commit { (result) in
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()
}
}
@@ -172,21 +171,21 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
XCTAssertTrue(monitor.hasSections())
XCTAssertEqual(monitor.numberOfSections(), 2)
XCTAssertTrue(monitor.hasObjects())
XCTAssertTrue(monitor.hasObjectsInSection(0))
XCTAssertEqual(monitor.numberOfObjectsInSection(0), 2)
XCTAssertEqual(monitor.numberOfObjectsInSection(1), 3)
XCTAssertTrue(monitor.hasObjects(in: 0))
XCTAssertEqual(monitor.numberOfObjects(in: 0), 2)
XCTAssertEqual(monitor.numberOfObjects(in: 1), 3)
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -199,62 +198,60 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didUpdateObject:atIndexPath:",
object: observer,
handler: { (note) -> Bool in
let didUpdateObjectExpectation = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
object: observer,
handler: { (note) -> Bool in
XCTAssert(events == 1 || events == 2)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
let object = userInfo?["object"] as? TestEntity1
switch object?.testEntityID {
XCTAssert(events == 1 || events == 2)
case NSNumber(value: 101)?:
XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
let object = userInfo?["object"] as? TestEntity1
case NSNumber(value: 102)?:
XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
switch object?.testEntityID {
case NSNumber(value: 101)?:
XCTAssertEqual(indexPath?.section, 1)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
case NSNumber(value: 102)?:
XCTAssertEqual(indexPath?.section, 0)
XCTAssertEqual(indexPath?.row, 0)
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
default:
XCTFail()
}
defer {
events += 1
}
return events == 1 || events == 2
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
default:
XCTFail()
}
)
}
defer {
events += 1
}
return events == 1 || events == 2
}
)
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -268,49 +265,49 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
stack.perform(
asynchronous: { (transaction) -> Bool in
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 {
XCTFail()
}
if let object = transaction.fetchOne(
From<TestEntity1>(),
Where(#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()
}
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()
}
}
@@ -326,14 +323,14 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -347,7 +344,7 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let didMoveObjectExpectation = self.expectation(
forNotification: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:",
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
object: observer,
handler: { (note) -> Bool in
@@ -361,12 +358,12 @@ class ListObserverTests: BaseTestDataTestCase {
)
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(value: 102))
@@ -380,7 +377,7 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -394,31 +391,31 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
if let object = transaction.fetchOne(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
stack.perform(
asynchronous: { (transaction) -> Bool in
object.testBoolean = NSNumber(value: 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()
}
}
@@ -434,14 +431,14 @@ class ListObserverTests: BaseTestDataTestCase {
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
var events = 0
let willChangeExpectation = self.expectation(
forNotification: "listMonitorWillChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -454,40 +451,37 @@ class ListObserverTests: BaseTestDataTestCase {
return events == 0
}
)
for _ in 1 ... 2 {
let didUpdateObjectExpectation = self.expectation(
forNotification: "listMonitor:didDeleteObject:fromIndexPath:",
object: observer,
handler: { (note) -> Bool in
let didUpdateObjectExpectation = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
object: observer,
handler: { (note) -> Bool in
XCTAssert(events == 1 || events == 2)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
XCTAssertEqual(indexPath?.section, 0)
XCTAssert(indexPath?.index(atPosition: 1) == 0 || indexPath?.index(atPosition: 1) == 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.isDeleted, true)
defer {
XCTAssert(events == 1 || events == 2)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["indexPath", "object"]
)
let indexPath = userInfo?["indexPath"] as? NSIndexPath
XCTAssertEqual(indexPath?.section, 0)
XCTAssert(indexPath?.row == 0 || indexPath?.row == 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.isDeleted, true)
defer {
events += 1
}
return events == 1 || events == 2
events += 1
}
)
}
return events == 1 || events == 2
}
)
let didDeleteSectionExpectation = self.expectation(
forNotification: "listMonitor:didDeleteSection:fromSectionIndex:",
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
object: observer,
handler: { (note) -> Bool in
@@ -515,7 +509,7 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let didChangeExpectation = self.expectation(
forNotification: "listMonitorDidChange:",
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
@@ -529,25 +523,26 @@ class ListObserverTests: BaseTestDataTestCase {
}
)
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
transaction.deleteAll(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
)
transaction.commit { (result) in
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,6 +551,7 @@ class ListObserverTests: BaseTestDataTestCase {
// MARK: TestListObserver
@available(macOS 10.12, *)
class TestListObserver: ListSectionObserver {
// MARK: ListObserver
@@ -678,5 +674,3 @@ class TestListObserver: ListSectionObserver {
)
}
}
#endif

View File

@@ -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"))

View File

@@ -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>

View File

@@ -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(
guard let object = try stack.fetchOne(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
@@ -59,7 +58,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0
let willUpdateExpectation = self.expectation(
forNotification: "objectMonitor:willUpdateObject:",
forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
object: observer,
handler: { (note) -> Bool in
@@ -76,7 +75,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
}
)
let didUpdateExpectation = self.expectation(
forNotification: "objectMonitor:didUpdateObject:changedPersistentKeys:",
forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
object: observer,
handler: { (note) -> Bool in
@@ -105,29 +104,29 @@ class ObjectObserverTests: BaseTestDataTestCase {
}
)
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
guard let object = transaction.edit(object) else {
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(value: 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(
guard let object = try stack.fetchOne(
From<TestEntity1>(),
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
@@ -156,7 +155,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
var events = 0
let didDeleteExpectation = self.expectation(
forNotification: "objectMonitor:didDeleteObject:",
forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
object: observer,
handler: { (note) -> Bool in
@@ -173,29 +172,29 @@ class ObjectObserverTests: BaseTestDataTestCase {
}
)
let saveExpectation = self.expectation(description: "save")
stack.beginAsynchronous { (transaction) in
guard let object = transaction.edit(object) else {
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,6 +203,7 @@ class ObjectObserverTests: BaseTestDataTestCase {
// MARK: TestObjectObserver
@available(macOS 10.12, *)
class TestObjectObserver: ObjectObserver {
typealias ObjectEntityType = TestEntity1
@@ -219,7 +219,7 @@ class TestObjectObserver: ObjectObserver {
)
}
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<KeyPath>) {
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<String>) {
NotificationCenter.default.post(
name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
@@ -242,5 +242,3 @@ class TestObjectObserver: ObjectObserver {
)
}
}
#endif

View File

@@ -2,7 +2,7 @@
// OrderByTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -38,21 +38,21 @@ final class OrderByTests: XCTestCase {
do {
let orderBy = OrderBy()
XCTAssertEqual(orderBy, OrderBy([NSSortDescriptor]()))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key", ascending: false)))
let orderBy = OrderBy<NSManagedObject>()
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([NSSortDescriptor]()))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key", ascending: false)))
XCTAssertTrue(orderBy.sortDescriptors.isEmpty)
}
do {
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
let orderBy = OrderBy(sortDescriptor)
let orderBy = OrderBy<NSManagedObject>(sortDescriptor)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(NSSortDescriptor(key: "key1", ascending: false)))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor]))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(NSSortDescriptor(key: "key1", ascending: false)))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
}
do {
@@ -61,76 +61,76 @@ final class OrderByTests: XCTestCase {
NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false)
]
let orderBy = OrderBy(sortDescriptors)
XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
let orderBy = OrderBy<NSManagedObject>(sortDescriptors)
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy(
OrderBy<NSManagedObject>(
[
NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false)
]
)
)
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
do {
let orderBy = OrderBy(.ascending("key1"))
let orderBy = OrderBy<NSManagedObject>(.ascending("key1"))
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
XCTAssertEqual(orderBy, OrderBy(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key2")))
XCTAssertEqual(orderBy, OrderBy([sortDescriptor]))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptor))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.descending("key1")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key2")))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>([sortDescriptor]))
XCTAssertEqual(orderBy.sortDescriptors, [sortDescriptor])
}
do {
let orderBy = OrderBy(.ascending("key1"), .descending("key2"))
let orderBy = OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"))
let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false)
]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy(
OrderBy<NSManagedObject>(
[
NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false)
]
)
)
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
do {
let sortKeys: [SortKey] = [.ascending("key1"), .descending("key2")]
let orderBy = OrderBy(sortKeys)
let sortKeys: [OrderBy<NSManagedObject>.SortKey] = [.ascending("key1"), .descending("key2")]
let orderBy = OrderBy<NSManagedObject>(sortKeys)
let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false)
]
XCTAssertEqual(orderBy, OrderBy(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy(
OrderBy<NSManagedObject>(
[
NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false)
]
)
)
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy(.ascending("key1"), .descending("key3")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
}
@@ -138,15 +138,15 @@ final class OrderByTests: XCTestCase {
@objc
dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() {
let orderBy1 = OrderBy(.ascending("key1"))
let orderBy2 = OrderBy(.descending("key2"))
let orderBy3 = OrderBy(.ascending("key3"))
let orderBy1 = OrderBy<NSManagedObject>(.ascending("key1"))
let orderBy2 = OrderBy<NSManagedObject>(.descending("key2"))
let orderBy3 = OrderBy<NSManagedObject>(.ascending("key3"))
do {
let plusOrderBy = orderBy1 + orderBy2 + orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2"), .ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -158,14 +158,14 @@ final class OrderByTests: XCTestCase {
var plusOrderBy = orderBy1
plusOrderBy += orderBy2
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1")) + OrderBy(.descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1")) + OrderBy<NSManagedObject>(.descending("key2")))
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1)
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors)
plusOrderBy += orderBy3
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy(.ascending("key1"), .descending("key2")) + OrderBy(.ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2"), .ascending("key3")))
XCTAssertEqual(plusOrderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")) + OrderBy<NSManagedObject>(.ascending("key3")))
XCTAssertNotEqual(plusOrderBy, orderBy1 + orderBy3 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy1 + orderBy3)
XCTAssertNotEqual(plusOrderBy, orderBy2 + orderBy3 + orderBy1)
@@ -178,8 +178,8 @@ final class OrderByTests: XCTestCase {
@objc
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
let orderBy = OrderBy(.ascending("key"))
let request = CoreStoreFetchRequest()
let orderBy = OrderBy<NSManagedObject>(.ascending("key"))
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
orderBy.applyToFetchRequest(request)
XCTAssertNotNil(request.sortDescriptors)
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)

File diff suppressed because it is too large Load Diff

View File

@@ -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("key"), "key")
}
do {
let sectionBy = SectionBy("key") { $0.flatMap { "\($0):suffix" } }
let sectionBy = SectionBy<NSManagedObject>("key") { $0.flatMap { "\($0):suffix" } }
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
}
}
}
#endif

View File

@@ -2,7 +2,7 @@
// SelectTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +38,7 @@ final class SelectTests: XCTestCase {
do {
let term: SelectTerm = "attribute"
let term: SelectTerm<NSManagedObject> = "attribute"
XCTAssertEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
@@ -58,7 +58,7 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.attribute("attribute")
let term = SelectTerm<NSManagedObject>.attribute("attribute")
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
@@ -82,7 +82,7 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.average("attribute")
let term = SelectTerm<NSManagedObject>.average("attribute")
XCTAssertEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
@@ -106,7 +106,7 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.average("attribute", as: "alias")
let term = SelectTerm<NSManagedObject>.average("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
@@ -135,7 +135,7 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.count("attribute")
let term = SelectTerm<NSManagedObject>.count("attribute")
XCTAssertEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
@@ -159,7 +159,7 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.count("attribute", as: "alias")
let term = SelectTerm<NSManagedObject>.count("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
@@ -188,7 +188,7 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.maximum("attribute")
let term = SelectTerm<NSManagedObject>.maximum("attribute")
XCTAssertEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
@@ -212,7 +212,7 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.maximum("attribute", as: "alias")
let term = SelectTerm<NSManagedObject>.maximum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
@@ -241,7 +241,7 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.minimum("attribute")
let term = SelectTerm<NSManagedObject>.minimum("attribute")
XCTAssertEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
@@ -265,7 +265,7 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.minimum("attribute", as: "alias")
let term = SelectTerm<NSManagedObject>.minimum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
@@ -294,7 +294,7 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.sum("attribute")
let term = SelectTerm<NSManagedObject>.sum("attribute")
XCTAssertEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
@@ -318,7 +318,7 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.sum("attribute", as: "alias")
let term = SelectTerm<NSManagedObject>.sum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
@@ -347,7 +347,7 @@ final class SelectTests: XCTestCase {
do {
let term = SelectTerm.objectID()
let term = SelectTerm<NSManagedObject>.objectID()
XCTAssertEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
@@ -368,7 +368,7 @@ final class SelectTests: XCTestCase {
}
do {
let term = SelectTerm.objectID(as: "alias")
let term = SelectTerm<NSManagedObject>.objectID(as: "alias")
XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.objectID())
@@ -393,12 +393,12 @@ final class SelectTests: XCTestCase {
@objc
dynamic func test_ThatSelectClauses_ConfigureCorrectly() {
let term1 = SelectTerm.attribute("attribute1")
let term2 = SelectTerm.attribute("attribute2")
let term3 = SelectTerm.attribute("attribute3")
let term1 = SelectTerm<NSManagedObject>.attribute("attribute1")
let term2 = SelectTerm<NSManagedObject>.attribute("attribute2")
let term3 = SelectTerm<NSManagedObject>.attribute("attribute3")
do {
let select = Select<Int>(term1, term2, term3)
let select = Select<NSManagedObject, Int>(term1, term2, term3)
XCTAssertEqual(select.selectTerms, [term1, term2, term3])
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])
@@ -408,7 +408,7 @@ final class SelectTests: XCTestCase {
}
do {
let select = Select<Int>([term1, term2, term3])
let select = Select<NSManagedObject, Int>([term1, term2, term3])
XCTAssertEqual(select.selectTerms, [term1, term2, term3])
XCTAssertNotEqual(select.selectTerms, [term1, term3, term2])
XCTAssertNotEqual(select.selectTerms, [term2, term1, term3])

View File

@@ -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
@@ -36,10 +36,14 @@ class SetupTests: BaseTestDataTestCase {
do {
let model = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!
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.parent)
XCTAssertFalse(stack.rootSavingContext.isDataStackContext)
@@ -47,29 +51,29 @@ class SetupTests: BaseTestDataTestCase {
XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
XCTAssertTrue(stack.mainContext.isDataStackContext)
XCTAssertFalse(stack.mainContext.isTransactionContext)
XCTAssertEqual(stack.model, model)
XCTAssertTrue(stack.migrationChain.valid)
XCTAssertTrue(stack.migrationChain.empty)
XCTAssertTrue(stack.migrationChain.rootVersions.isEmpty)
XCTAssertTrue(stack.migrationChain.leafVersions.isEmpty)
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]) {
DataStack(
modelName: "Model",
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)
@@ -80,7 +84,7 @@ class SetupTests: BaseTestDataTestCase {
dynamic func test_ThatInMemoryStores_SetupCorrectly() {
let stack = DataStack(
modelName: "Model",
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
do {
@@ -135,7 +139,7 @@ class SetupTests: BaseTestDataTestCase {
dynamic func test_ThatSQLiteStores_SetupCorrectly() {
let stack = DataStack(
modelName: "Model",
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
do {
@@ -203,14 +207,13 @@ class SetupTests: BaseTestDataTestCase {
do {
let stack = DataStack(
modelName: "Model",
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("-wal")))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
@@ -223,10 +226,13 @@ class SetupTests: BaseTestDataTestCase {
let metadata = try createStore()
let stack = DataStack(
modelName: "Model",
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: stack.model[metadata])
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")))
@@ -238,7 +244,7 @@ class SetupTests: BaseTestDataTestCase {
do {
let metadata = try createStore()
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
@@ -253,12 +259,12 @@ class SetupTests: BaseTestDataTestCase {
dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() {
let stack = DataStack(
modelName: "Model",
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
do {
let sqliteStore = LegacySQLiteStore()
let sqliteStore = SQLiteStore.legacy()
do {
try stack.addStorageAndWait(sqliteStore)
@@ -273,7 +279,7 @@ class SetupTests: BaseTestDataTestCase {
}
do {
let sqliteStore = LegacySQLiteStore(
let sqliteStore = SQLiteStore.legacy(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .recreateStoreOnModelMismatch
@@ -292,7 +298,7 @@ class SetupTests: BaseTestDataTestCase {
}
do {
let sqliteStore = LegacySQLiteStore(
let sqliteStore = SQLiteStore.legacy(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .recreateStoreOnModelMismatch
@@ -315,20 +321,26 @@ class SetupTests: BaseTestDataTestCase {
dynamic func test_ThatLegacySQLiteStores_DeleteFilesCorrectly() {
let fileManager = FileManager.default
let sqliteStore = LegacySQLiteStore()
let sqliteStore = SQLiteStore.legacy()
func createStore() throws -> [String: Any] {
do {
let stack = DataStack(
modelName: "Model",
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try! stack.addStorageAndWait(sqliteStore)
try! stack.addStorageAndWait(
SQLiteStore.legacy(
fileName: sqliteStore.fileURL.lastPathComponent,
configuration: sqliteStore.configuration,
migrationMappingProviders: sqliteStore.migrationMappingProviders,
localStorageOptions: .recreateStoreOnModelMismatch
)
)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
@@ -341,10 +353,13 @@ class SetupTests: BaseTestDataTestCase {
let metadata = try createStore()
let stack = DataStack(
modelName: "Model",
xcodeModelName: "Model",
bundle: Bundle(for: type(of: self))
)
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: stack.model[metadata])
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")))
@@ -356,7 +371,7 @@ class SetupTests: BaseTestDataTestCase {
do {
let metadata = try createStore()
try sqliteStore.eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))

View File

@@ -2,7 +2,7 @@
// StorageInterfaceTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -83,33 +83,64 @@ final class StorageInterfaceTests: XCTestCase {
let store = SQLiteStore()
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL)
XCTAssertEqual(store.mappingModelBundles, Bundle.allBundles)
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
XCTAssertEqual(store.localStorageOptions, .none)
}
@objc
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(NSUUID().uuidString, isDirectory: false)!
let fileURL = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString, isDirectory: false)
.appendingPathExtension("db")
let bundles = [Bundle(for: type(of: self))]
let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: type(of: self))
)
let store = SQLiteStore(
fileURL: fileURL,
configuration: "config1",
mappingModelBundles: bundles,
migrationMappingProviders: [mappingProvider],
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, fileURL)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@@ -117,21 +148,37 @@ final class StorageInterfaceTests: XCTestCase {
dynamic func test_ThatFileNameSQLiteStores_ConfigureCorrectly() {
let fileName = UUID().uuidString + ".db"
let bundles = [Bundle(for: type(of: self))]
let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: type(of: self))
)
let store = SQLiteStore(
fileName: fileName,
configuration: "config1",
mappingModelBundles: bundles,
migrationMappingProviders: [mappingProvider],
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@@ -152,65 +199,72 @@ final class StorageInterfaceTests: XCTestCase {
.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()
let store = SQLiteStore.legacy()
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, LegacySQLiteStore.defaultFileURL)
XCTAssertEqual(store.mappingModelBundles, Bundle.allBundles)
XCTAssertEqual(store.fileURL, SQLiteStore.legacyDefaultFileURL)
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
XCTAssertEqual(store.localStorageOptions, .none)
}
@objc
dynamic func test_ThatFileURLLegacySQLiteStores_ConfigureCorrectly() {
let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(NSUUID().uuidString, isDirectory: false)!
.appendingPathExtension("db")
let bundles = [Bundle(for: type(of: self))]
let store = LegacySQLiteStore(
fileURL: fileURL,
configuration: "config1",
mappingModelBundles: bundles,
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
XCTAssertEqual(store.fileURL, fileURL)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@objc
dynamic func test_ThatFileNameLegacySQLiteStores_ConfigureCorrectly() {
let fileName = UUID().uuidString + ".db"
let bundles = [Bundle(for: type(of: self))]
let store = LegacySQLiteStore(
let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: type(of: self))
)
let store = SQLiteStore.legacy(
fileName: fileName,
configuration: "config1",
mappingModelBundles: bundles,
migrationMappingProviders: [mappingProvider],
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertEqual(store.storeOptions as NSDictionary?, [NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary)
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), LegacySQLiteStore.defaultRootDirectory)
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.legacyDefaultRootDirectory)
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
XCTAssertEqual(store.mappingModelBundles, bundles)
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
}

View File

@@ -2,7 +2,7 @@
// TestEntity1.swift
// CoreStore
//
// Copyright © 2014 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -36,4 +36,6 @@ class TestEntity1: NSManagedObject {
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: Data?
@NSManaged var testNil: String?
@NSManaged var testToOne: TestEntity1?
@NSManaged var testToManyUnordered: NSSet?
}

View File

@@ -2,7 +2,7 @@
// TestEntity1.swift
// CoreStore
//
// Copyright © 2014 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -36,4 +36,6 @@ class TestEntity2: NSManagedObject {
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: Data?
@NSManaged var testNil: String?
@NSManaged var testToOne: TestEntity2?
@NSManaged var testToManyOrdered: NSOrderedSet?
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// TweakTests.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -43,7 +43,7 @@ final class TweakTests: XCTestCase {
$0.fetchLimit = 200
$0.predicate = predicate
}
let request = CoreStoreFetchRequest()
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
tweak.applyToFetchRequest(request)
XCTAssertEqual(request.fetchOffset, 100)
XCTAssertEqual(request.fetchLimit, 200)

View 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]
]
"""
)
}
}

View File

@@ -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,60 +29,354 @@ 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)
}
}
@@ -93,211 +387,123 @@ final class WhereTests: XCTestCase {
do {
let value: Int = 100
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", NSNumber(value: value))
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", NSNumber(value: value))
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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)
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", value.intValue)
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", value.intValue)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", NSNumber(value: value))
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", NSNumber(value: value))
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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)
let whereClause1 = Where("%K == %d", "key", value)
let whereClause2 = Where("%K == %d", "key", value as AnyObject)
let whereClause3 = Where("%K == %d", "key", value.int64Value)
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", value.int64Value)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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"
let whereClause1 = Where("%K == %s", "key", value)
let whereClause2 = Where("%K == %s", "key", value as AnyObject)
let whereClause3 = Where("%K == %s", "key", NSString(string: value))
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as AnyObject)
let whereClause6 = Where("%K == %@", "key", NSString(string: value))
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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")
let whereClause1 = Where("%K == %s", "key", value)
let whereClause2 = Where("%K == %s", "key", value as String)
let whereClause3 = Where("%K == %s", "key", value as String as AnyObject)
let whereClause4 = Where("%K == %@", "key", value)
let whereClause5 = Where("%K == %@", "key", value as String)
let whereClause6 = Where("%K == %@", "key", value as String as AnyObject)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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]
let whereClause1 = Where("%K == %@", "key", value)
let whereClause2 = Where("%K == %@", "key", value as AnyObject)
let whereClause3 = Where("%K == %@", "key", value as [AnyObject])
let whereClause4 = Where("%K == %@", "key", value as NSArray)
let whereClause5 = Where("%K == %@", "key", NSArray(array: value))
let whereClause6 = Where("%K == %@", "key", value as AnyObject as! NSArray)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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]
let whereClause1 = Where("%K == %@", "key", value)
let whereClause2 = Where("%K == %@", "key", value as AnyObject)
let whereClause3 = Where("%K == %@", "key", value as [AnyObject])
let whereClause4 = Where("%K == %@", "key", value as NSArray)
let whereClause5 = Where("%K == %@", "key", NSArray(array: value))
let whereClause6 = Where("%K == %@", "key", value as AnyObject as! NSArray)
XCTAssertEqual(whereClause1, whereClause2)
XCTAssertEqual(whereClause1, whereClause3)
XCTAssertEqual(whereClause1, whereClause4)
XCTAssertEqual(whereClause1, whereClause5)
XCTAssertEqual(whereClause1, whereClause6)
XCTAssertEqual(whereClause2, whereClause3)
XCTAssertEqual(whereClause2, whereClause4)
XCTAssertEqual(whereClause2, whereClause5)
XCTAssertEqual(whereClause2, whereClause6)
XCTAssertEqual(whereClause3, whereClause4)
XCTAssertEqual(whereClause3, whereClause5)
XCTAssertEqual(whereClause3, whereClause6)
XCTAssertEqual(whereClause4, whereClause5)
XCTAssertEqual(whereClause4, whereClause6)
XCTAssertEqual(whereClause5, whereClause6)
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 {
@@ -325,6 +531,21 @@ final class WhereTests: XCTestCase {
XCTAssertEqual(andWhere.predicate, andPredicate)
XCTAssertEqual(andWhere, whereClause1 && whereClause2 && whereClause3)
}
do {
let andWhere = whereClause1 && whereClause2 && whereClause3
let noneWhere: Where<NSManagedObject>? = nil
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
let finalNoneWhere = andWhere &&? noneWhere
let finalSomeWhere = andWhere &&? someWhere
let unwrappedFinalSomeWhere = andWhere && someWhere!
XCTAssertEqual(andWhere.predicate, finalNoneWhere.predicate)
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
}
do {
let orWhere = whereClause1 || whereClause2 || whereClause3
@@ -341,13 +562,28 @@ final class WhereTests: XCTestCase {
XCTAssertEqual(orWhere.predicate, orPredicate)
XCTAssertEqual(orWhere, whereClause1 || whereClause2 || whereClause3)
}
do {
let orWhere = whereClause1 || whereClause2 || whereClause3
let noneWhere: Where<NSManagedObject>? = nil
let someWhere: Where<NSManagedObject>? = Where<NSManagedObject>("key4", isEqualTo: "value4")
let finalNoneWhere = orWhere &&? noneWhere
let finalSomeWhere = orWhere &&? someWhere
let unwrappedFinalSomeWhere = orWhere && someWhere!
XCTAssertEqual(orWhere.predicate, finalNoneWhere.predicate)
XCTAssertEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
}
}
@objc
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where("key", isEqualTo: "value")
let request = CoreStoreFetchRequest()
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let request = CoreStoreFetchRequest<NSFetchRequestResult>()
whereClause.applyToFetchRequest(request)
XCTAssertNotNil(request.predicate)
XCTAssertEqual(request.predicate, whereClause.predicate)

View File

@@ -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

View File

@@ -1,8 +1,9 @@
// swift-tools-version:4.2
//
// Package.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -25,21 +26,18 @@
import PackageDescription
let targets: [Target]
#if os(iOS)
targets = [Target(name: "CoreStore iOS")]
#elseif os(OSX)
targets = [Target(name: "CoreStore OSX")]
#elseif os(watchOS)
targets = [Target(name: "CoreStore watchOS")]
#elseif os(tvOS)
targets = [Target(name: "CoreStore tvOS")]
#else
targets = []
#endif
let package = Package(
name: "CoreStore",
targets: targets,
exclude: ["Carthage", "CoreStoreDemo", "Sources/libA/images"]
products: [
.library(name: "CoreStore", type: .static, targets: ["CoreStore"])
],
dependencies: [],
targets: [
.target(
name: "CoreStore",
dependencies: [],
path: "Sources",
exclude: ["CoreStoreBridge.h", "CoreStoreBridge.m"]
)
]
)

View 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)
/// =======================
}
}
)
/// =======================
}
}
)

View 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>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
</Workspace>

View 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)
/// =======================
}
}
)
/// =======================
}
}
)

View 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>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -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>

1288
README.md

File diff suppressed because it is too large Load Diff

View 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()
}
}

View File

@@ -0,0 +1,47 @@
//
// AttributeProtocol.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
import CoreData
// MARK: - AttributeProtocol
internal protocol AttributeProtocol: AnyObject {
static var attributeType: NSAttributeType { get }
var keyPath: KeyPathString { get }
var isOptional: Bool { get }
var isTransient: Bool { get }
var allowsExternalBinaryDataStorage: Bool { get }
var versionHashModifier: () -> String? { get }
var renamingIdentifier: () -> String? { get }
var defaultValue: () -> Any? { get }
var affectedByKeyPaths: () -> Set<String> { get }
var rawObject: CoreStoreManagedObject? { get set }
var getter: CoreStoreManagedObject.CustomGetter? { get }
var setter: CoreStoreManagedObject.CustomSetter? { get }
}

View File

@@ -2,7 +2,7 @@
// BaseDataTransaction+Importing.swift
// CoreStore
//
// Copyright © 2015 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@ import CoreData
// MARK: - BaseDataTransaction
public extension BaseDataTransaction {
extension BaseDataTransaction {
/**
Creates an `ImportableObject` by importing from the specified import source.
@@ -39,9 +39,9 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the created `ImportableObject` instance, or `nil` if the import was ignored
*/
public func importObject<T>(
_ into: Into<T>,
source: T.ImportSource) throws -> T? where T: NSManagedObject, T: ImportableObject {
public func importObject<D: ImportableObject>(
_ into: Into<D>,
source: D.ImportSource) throws -> D? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -50,8 +50,7 @@ public extension BaseDataTransaction {
return try autoreleasepool {
let entityType = into.entityClass as! T.Type
let entityType = into.entityClass
guard entityType.shouldInsert(from: source, in: self) else {
return nil
@@ -70,9 +69,9 @@ public extension BaseDataTransaction {
- parameter source: the object to import values from
- throws: an `Error` thrown from any of the `ImportableObject` methods
*/
public func importObject<T>(
_ object: T,
source: T.ImportSource) throws where T: NSManagedObject, T: ImportableObject {
public func importObject<D: ImportableObject>(
_ object: D,
source: D.ImportSource) throws {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -81,7 +80,7 @@ public extension BaseDataTransaction {
try autoreleasepool {
let entityType = type(of: object)
let entityType = cs_dynamicType(of: object)
guard entityType.shouldInsert(from: source, in: self) else {
return
@@ -98,9 +97,9 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableObject` methods
- returns: the array of created `ImportableObject` instances
*/
public func importObjects<T, S: Sequence>(
_ into: Into<T>,
sourceArray: S) throws -> [T] where T: NSManagedObject, T: ImportableObject, S.Iterator.Element == T.ImportSource {
public func importObjects<D: ImportableObject, S: Sequence>(
_ into: Into<D>,
sourceArray: S) throws -> [D] where S.Iterator.Element == D.ImportSource {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -109,9 +108,9 @@ public extension BaseDataTransaction {
return try autoreleasepool {
return try sourceArray.flatMap { (source) -> T? in
return try sourceArray.compactMap { (source) -> D? in
let entityType = into.entityClass as! T.Type
let entityType = into.entityClass
guard entityType.shouldInsert(from: source, in: self) else {
return nil
@@ -134,9 +133,9 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the created/updated `ImportableUniqueObject` instance, or `nil` if the import was ignored
*/
public func importUniqueObject<T>(
_ into: Into<T>,
source: T.ImportSource) throws -> T? where T: NSManagedObject, T: ImportableUniqueObject {
public func importUniqueObject<D: ImportableUniqueObject>(
_ into: Into<D>,
source: D.ImportSource) throws -> D? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -145,14 +144,14 @@ public extension BaseDataTransaction {
return try autoreleasepool {
let entityType = into.entityClass as! T.Type
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(entityType), Where(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
if let object = try self.fetchOne(From(entityType), Where<D>(uniqueIDKeyPath, isEqualTo: uniqueIDValue)) {
guard entityType.shouldUpdate(from: source, in: self) else {
@@ -178,7 +177,7 @@ public extension BaseDataTransaction {
/**
Updates existing `ImportableUniqueObject`s or creates them by importing from the specified array of import sources.
`ImportableUniqueObject` methods are called on the objects in the same order as they are in the `sourceArray`, and are returned in an array with that same order.
- Warning: If `sourceArray` contains multiple import sources with same ID, no merging will occur and ONLY THE LAST duplicate will be imported.
- Warning: 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
@@ -186,10 +185,10 @@ public extension BaseDataTransaction {
- throws: an `Error` thrown from any of the `ImportableUniqueObject` methods
- returns: the array of created/updated `ImportableUniqueObject` instances
*/
public func importUniqueObjects<T, S: Sequence>(
_ into: Into<T>,
public func importUniqueObjects<D: ImportableUniqueObject, S: Sequence>(
_ into: Into<D>,
sourceArray: S,
preProcess: @escaping (_ mapping: [T.UniqueIDType: T.ImportSource]) throws -> [T.UniqueIDType: T.ImportSource] = { $0 }) throws -> [T] where T: NSManagedObject, T: ImportableUniqueObject, S.Iterator.Element == T.ImportSource {
preProcess: @escaping (_ mapping: [D.UniqueIDType: D.ImportSource]) throws -> [D.UniqueIDType: D.ImportSource] = { $0 }) throws -> [D] where S.Iterator.Element == D.ImportSource {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -198,11 +197,11 @@ public extension BaseDataTransaction {
return try autoreleasepool {
let entityType = into.entityClass as! T.Type
var importSourceByID = Dictionary<T.UniqueIDType, T.ImportSource>()
let entityType = into.entityClass
var importSourceByID = Dictionary<D.UniqueIDType, D.ImportSource>()
let sortedIDs = try autoreleasepool {
return try sourceArray.flatMap { (source) -> T.UniqueIDType? in
return try sourceArray.compactMap { (source) -> D.UniqueIDType? in
guard let uniqueIDValue = try entityType.uniqueID(from: source, in: self) else {
@@ -215,12 +214,13 @@ public extension BaseDataTransaction {
importSourceByID = try autoreleasepool { try preProcess(importSourceByID) }
var existingObjectsByID = Dictionary<T.UniqueIDType, T>()
self.fetchAll(From(entityType), Where(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))?
var existingObjectsByID = Dictionary<D.UniqueIDType, D>()
try self
.fetchAll(From(entityType), Where<D>(entityType.uniqueIDKeyPath, isMemberOf: sortedIDs))
.forEach { existingObjectsByID[$0.uniqueIDValue] = $0 }
var processedObjectIDs = Set<T.UniqueIDType>()
var result = [T]()
var processedObjectIDs = Set<D.UniqueIDType>()
var result = [D]()
for objectID in sortedIDs where !processedObjectIDs.contains(objectID) {

View 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
}
}

View File

@@ -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
@@ -45,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 as! T.Type)
let entityClass = into.entityClass
CoreStore.assert(
self.isRunningInAllowedQueue(),
"Attempted to create an entity of type \(cs_typeName(entityClass)) outside its designated queue."
)
let context = self.context
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)
context.assign(object, to: 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.")
@@ -81,17 +85,19 @@ public /*abstract*/ class BaseDataTransaction {
}
else {
switch context.parentStack!.persistentStoreForEntityClass(
entityClass,
switch dataStack.persistentStore(
for: entityIdentifier,
configuration: into.configuration
?? type(of: into).defaultConfigurationName,
?? DataStack.defaultConfigurationName,
inferStoreIfPossible: false
) {
case (let persistentStore?, _):
let object = entityClass.createInContext(context)
context.assign(object, to: 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.")
@@ -110,12 +116,12 @@ public /*abstract*/ class BaseDataTransaction {
}
/**
Returns an editable proxy of a specified `NSManagedObject`.
Returns an editable proxy of a specified `NSManagedObject` or `CoreStoreObject`.
- parameter object: the `NSManagedObject` type to be edited
- returns: an editable proxy for the specified `NSManagedObject`.
- parameter object: the `NSManagedObject` or `CoreStoreObject` type to be edited
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/
public func edit<T: NSManagedObject>(_ object: T?) -> T? {
public func edit<D: DynamicObject>(_ object: D?) -> D? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -133,9 +139,9 @@ public /*abstract*/ class BaseDataTransaction {
- parameter into: an `Into` clause specifying the entity type
- parameter objectID: the `NSManagedObjectID` for the object to be edited
- returns: an editable proxy for the specified `NSManagedObject`.
- returns: an editable proxy for the specified `NSManagedObject` or `CoreStoreObject`.
*/
public func edit<T: NSManagedObject>(_ into: Into<T>, _ objectID: NSManagedObjectID) -> T? {
public func edit<D>(_ into: Into<D>, _ objectID: NSManagedObjectID) -> D? {
CoreStore.assert(
self.isRunningInAllowedQueue(),
@@ -143,56 +149,54 @@ public /*abstract*/ class BaseDataTransaction {
)
CoreStore.assert(
into.inferStoreIfPossible
|| (into.configuration ?? Into.defaultConfigurationName) == objectID.persistentStore?.configurationName,
|| (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: Sequence>(_ objects: S) where S.Iterator.Element: NSManagedObject {
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()) }) }
}
/**
@@ -204,50 +208,48 @@ public /*abstract*/ class BaseDataTransaction {
self.isRunningInAllowedQueue(),
"Attempted to refresh entities outside their designated queue."
)
self.context.refreshAndMergeAllObjects()
}
// 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.
Returns `true` if the object has any property values changed. This method should not be called after the `commit()` method was called.
- parameter entity: the `DynamicObject` instance
- returns: `true` if the object has any property values changed.
*/
public func insertedObjects() -> Set<NSManagedObject> {
public func objectHasPersistentChangedValues<D: DynamicObject>(_ entity: D) -> Bool {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
)
return self.context.insertedObjects
return entity.cs_toRaw().hasPersistentChangedValues
}
/**
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.
*/
public func insertedObjects<T: NSManagedObject>(_ entity: T.Type) -> Set<T> {
public func insertedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access inserted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access inserted objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.insertedObjects.flatMap { $0 as? T })
return Set(self.context.insertedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
}
/**
@@ -258,74 +260,52 @@ public /*abstract*/ class BaseDataTransaction {
public func insertedObjectIDs() -> Set<NSManagedObjectID> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!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.
*/
public func insertedObjectIDs<T: NSManagedObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
public func insertedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access inserted object IDs from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access inserted objects IDs from an already committed \(cs_typeName(self))."
)
return Set(self.context.insertedObjects.filter { $0.isKind(of: 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.
*/
public func updatedObjects() -> Set<NSManagedObject> {
public func updatedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
)
return 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.
*/
public func updatedObjects<T: NSManagedObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access updated objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access updated objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.updatedObjects.filter { $0.isKind(of: entity) }.map { $0 as! T })
return Set(self.context.updatedObjects.compactMap({ entity.cs_matches(object: $0) ? entity.cs_fromRaw(object: $0) : nil }))
}
/**
@@ -336,126 +316,117 @@ public /*abstract*/ class BaseDataTransaction {
public func updatedObjectIDs() -> Set<NSManagedObjectID> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!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.
*/
public func updatedObjectIDs<T: NSManagedObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
public func updatedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access updated object IDs from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access updated object IDs from an already committed \(cs_typeName(self))."
)
return Set(self.context.updatedObjects.filter { $0.isKind(of: 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.
*/
public func deletedObjects() -> Set<NSManagedObject> {
public func deletedObjects<D: DynamicObject>(_ entity: D.Type) -> Set<D> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
)
return 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.
*/
public func deletedObjects<T: NSManagedObject>(_ entity: T.Type) -> Set<T> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to access deleted objects from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access deleted objects from an already committed \(cs_typeName(self))."
)
return Set(self.context.deletedObjects.filter { $0.isKind(of: entity) }.map { $0 as! T })
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.
*/
public func deletedObjectIDs() -> Set<NSManagedObjectID> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!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.
*/
public func deletedObjectIDs<T: NSManagedObject>(_ entity: T.Type) -> Set<NSManagedObjectID> {
public func deletedObjectIDs<D: DynamicObject>(_ entity: D.Type) -> Set<NSManagedObjectID> {
CoreStore.assert(
self.transactionQueue.cs_isCurrentExecutionContext(),
self.isRunningInAllowedQueue(),
"Attempted to access deleted object IDs from a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to access deleted object IDs from an already committed \(cs_typeName(self))."
)
return Set(self.context.deletedObjects.filter { $0.isKind(of: 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: DispatchQueue
internal let childTransactionQueue = DispatchQueue.serial("com.corestore.datastack.childtransactionqueue")
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: DispatchQueue, supportsUndo: Bool, bypassesQueueing: Bool) {
@@ -485,4 +456,9 @@ public /*abstract*/ class BaseDataTransaction {
return self.bypassesQueueing || self.transactionQueue.cs_isCurrentExecutionContext()
}
deinit {
self.context.reset()
}
}

View File

@@ -2,7 +2,7 @@
// CSAsynchronousDataTransaction.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -35,37 +35,34 @@ import CoreData
- SeeAlso: `AsynchronousDataTransaction`
*/
@objc
public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
public final class CSAsynchronousDataTransaction: CSBaseDataTransaction, CoreStoreObjectiveCType {
/**
Saves the transaction changes. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
- parameter success: the block executed if the save succeeds.
- parameter failure: the block executed if the save fails. A `CSError` is reported as the argument of the block.
*/
@objc
public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) {
public func commitWithSuccess(_ success: (() -> Void)?, failure: ((CSError) -> Void)?) {
self.bridgeToSwift.commit { (result) in
CoreStore.assert(
self.bridgeToSwift.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.bridgeToSwift.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once."
)
self.bridgeToSwift.autoCommit { (_, error) in
completion?(result.bridgeToObjectiveC)
}
}
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
if let error = error {
closure(transaction.bridgeToObjectiveC)
failure?(error.bridgeToObjectiveC)
}
else {
success?()
}
}
}
@@ -145,9 +142,9 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
public typealias SwiftType = AsynchronousDataTransaction
public override var bridgeToSwift: AsynchronousDataTransaction {
public var bridgeToSwift: AsynchronousDataTransaction {
return super.bridgeToSwift as! AsynchronousDataTransaction
return super.swiftTransaction as! AsynchronousDataTransaction
}
public required init(_ swiftValue: AsynchronousDataTransaction) {
@@ -155,9 +152,9 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
super.init(swiftValue as BaseDataTransaction)
}
public required init(_ swiftValue: BaseDataTransaction) {
public required override init(_ swiftValue: BaseDataTransaction) {
super.init(swiftValue as! AsynchronousDataTransaction)
super.init(swiftValue)
}
}

View File

@@ -2,7 +2,7 @@
// CSBaseDataTransaction+Querying.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@ import CoreData
// MARK: - CSBaseDataTransaction
public extension CSBaseDataTransaction {
extension CSBaseDataTransaction {
/**
Fetches the `NSManagedObject` instance in the transaction's context from a reference created from a transaction or from a different managed object context.
@@ -40,7 +40,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObject(_ object: NSManagedObject) -> Any? {
return self.bridgeToSwift.context.fetchExisting(object)
return self.swiftTransaction.context.fetchExisting(object) as NSManagedObject?
}
/**
@@ -52,7 +52,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObjectWithID(_ objectID: NSManagedObjectID) -> Any? {
return self.bridgeToSwift.context.fetchExisting(objectID)
return self.swiftTransaction.context.fetchExisting(objectID) as NSManagedObject?
}
/**
@@ -64,7 +64,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObjects(_ objects: [NSManagedObject]) -> [Any] {
return self.bridgeToSwift.context.fetchExisting(objects)
return self.swiftTransaction.context.fetchExisting(objects) as [NSManagedObject]
}
/**
@@ -76,7 +76,7 @@ public extension CSBaseDataTransaction {
@objc
public func fetchExistingObjectsWithIDs(_ objectIDs: [NSManagedObjectID]) -> [Any] {
return self.bridgeToSwift.context.fetchExisting(objectIDs)
return self.swiftTransaction.context.fetchExisting(objectIDs) as [NSManagedObject]
}
/**
@@ -90,10 +90,11 @@ public extension CSBaseDataTransaction {
public func fetchOneFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> Any? {
CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(),
self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.bridgeToSwift.context.fetchOne(from, fetchClauses)
return (try? self.swiftTransaction.context.fetchOne(from, fetchClauses))?
.flatMap({ $0 })
}
/**
@@ -107,10 +108,11 @@ public extension CSBaseDataTransaction {
public func fetchAllFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> [Any]? {
CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(),
self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.bridgeToSwift.context.fetchAll(from, fetchClauses)
return (try? self.swiftTransaction.context.fetchAll(from, fetchClauses))
.flatMap({ $0 })
}
/**
@@ -124,12 +126,11 @@ public extension CSBaseDataTransaction {
public func fetchCountFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSNumber? {
CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(),
self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.bridgeToSwift.context
.fetchCount(from, fetchClauses)
.flatMap { NSNumber(value: $0) }
return (try? self.swiftTransaction.context.fetchCount(from, fetchClauses))
.flatMap({ NSNumber(value: $0) })
}
/**
@@ -143,10 +144,11 @@ public extension CSBaseDataTransaction {
public func fetchObjectIDFrom(_ from: CSFrom, fetchClauses: [CSFetchClause]) -> NSManagedObjectID? {
CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(),
self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to fetch from a \(cs_typeName(self)) outside its designated queue."
)
return self.bridgeToSwift.context.fetchObjectID(from, fetchClauses)
return (try? self.swiftTransaction.context.fetchObjectID(from, fetchClauses))
.flatMap({ $0 })
}
/**
@@ -163,10 +165,11 @@ public extension CSBaseDataTransaction {
public func queryValueFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> Any? {
CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(),
self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.bridgeToSwift.context.queryValue(from, selectClause, queryClauses)
return (try? self.swiftTransaction.context.queryValue(from, selectClause, queryClauses))
.flatMap({ $0 })
}
/**
@@ -183,9 +186,10 @@ public extension CSBaseDataTransaction {
public func queryAttributesFrom(_ from: CSFrom, selectClause: CSSelect, queryClauses: [CSQueryClause]) -> [[String: Any]]? {
CoreStore.assert(
self.bridgeToSwift.isRunningInAllowedQueue(),
self.swiftTransaction.isRunningInAllowedQueue(),
"Attempted to query from a \(cs_typeName(self)) outside its designated queue."
)
return self.bridgeToSwift.context.queryAttributes(from, selectClause, queryClauses)
return (try? self.swiftTransaction.context.queryAttributes(from, selectClause, queryClauses))
.flatMap({ $0 })
}
}

View File

@@ -2,7 +2,7 @@
// CSBaseDataTransaction.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -35,7 +35,7 @@ import CoreData
- SeeAlso: `BaseDataTransaction`
*/
@objc
public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
public class CSBaseDataTransaction: NSObject {
// MARK: Object management
@@ -45,7 +45,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public var hasChanges: Bool {
return self.bridgeToSwift.hasChanges
return self.swiftTransaction.hasChanges
}
/**
@@ -57,7 +57,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func createInto(_ into: CSInto) -> Any {
return self.bridgeToSwift.create(into.bridgeToSwift)
return self.swiftTransaction.create(into.bridgeToSwift)
}
/**
@@ -69,7 +69,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func editObject(_ object: NSManagedObject?) -> Any? {
return self.bridgeToSwift.edit(object)
return self.swiftTransaction.edit(object)
}
/**
@@ -82,7 +82,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func editInto(_ into: CSInto, objectID: NSManagedObjectID) -> Any? {
return self.bridgeToSwift.edit(into.bridgeToSwift, objectID)
return self.swiftTransaction.edit(into.bridgeToSwift, objectID)
}
/**
@@ -93,7 +93,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func deleteObject(_ object: NSManagedObject?) {
self.bridgeToSwift.delete(object)
self.swiftTransaction.delete(object)
}
/**
@@ -104,7 +104,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func deleteObjects(_ objects: [NSManagedObject]) {
self.bridgeToSwift.delete(objects)
self.swiftTransaction.delete(objects)
}
/**
@@ -113,23 +113,12 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func refreshAndMergeAllObjects() {
self.bridgeToSwift.refreshAndMergeAllObjects()
self.swiftTransaction.refreshAndMergeAllObjects()
}
// MARK: Inspecting Pending Objects
/**
Returns all pending `NSManagedObject`s that were inserted to the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were inserted to the transaction.
*/
@objc
public func insertedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.insertedObjects()
}
/**
Returns all pending `NSManagedObject`s of the specified type that were inserted to the transaction. This method should not be called after the `-commit*:` method was called.
@@ -139,7 +128,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func insertedObjectsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObject> {
return self.bridgeToSwift.insertedObjects(entity)
return self.swiftTransaction.insertedObjects(entity)
}
/**
@@ -150,7 +139,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func insertedObjectIDs() -> Set<NSManagedObjectID> {
return self.bridgeToSwift.insertedObjectIDs()
return self.swiftTransaction.insertedObjectIDs()
}
/**
@@ -162,18 +151,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func insertedObjectIDsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
return self.bridgeToSwift.insertedObjectIDs(entity)
}
/**
Returns all pending `NSManagedObject`s that were updated in the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were updated to the transaction.
*/
@objc
public func updatedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.updatedObjects()
return self.swiftTransaction.insertedObjectIDs(entity)
}
/**
@@ -185,7 +163,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func updatedObjectsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObject> {
return self.bridgeToSwift.updatedObjects(entity)
return self.swiftTransaction.updatedObjects(entity)
}
/**
@@ -196,7 +174,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func updatedObjectIDs() -> Set<NSManagedObjectID> {
return self.bridgeToSwift.updatedObjectIDs()
return self.swiftTransaction.updatedObjectIDs()
}
/**
@@ -208,18 +186,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func updatedObjectIDsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
return self.bridgeToSwift.updatedObjectIDs(entity)
}
/**
Returns all pending `NSManagedObject`s that were deleted from the transaction. This method should not be called after the `-commit*:` method was called.
- returns: an `NSSet` of pending `NSManagedObject`s that were deleted from the transaction.
*/
@objc
public func deletedObjects() -> Set<NSManagedObject> {
return self.bridgeToSwift.deletedObjects()
return self.swiftTransaction.updatedObjectIDs(entity)
}
/**
@@ -231,19 +198,18 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func deletedObjectsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObject> {
return self.bridgeToSwift.deletedObjects(entity)
return self.swiftTransaction.deletedObjects(entity)
}
/**
Returns all pending `NSManagedObjectID`s of the specified type that were deleted from the transaction. This method should not be called after the `-commit*:` method was called.
- parameter entity: the `NSManagedObject` subclass to filter
- returns: an `NSSet` of pending `NSManagedObjectID`s of the specified type that were deleted from the transaction.
*/
@objc
public func deletedObjectIDs() -> Set<NSManagedObjectID> {
return self.bridgeToSwift.deletedObjectIDs()
return self.swiftTransaction.deletedObjectIDs()
}
/**
@@ -255,7 +221,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
@objc
public func deletedObjectIDsOfType(_ entity: NSManagedObject.Type) -> Set<NSManagedObjectID> {
return self.bridgeToSwift.deletedObjectIDs(entity)
return self.swiftTransaction.deletedObjectIDs(entity)
}
@@ -263,7 +229,7 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
public override var hash: Int {
return ObjectIdentifier(self.bridgeToSwift).hashValue
return ObjectIdentifier(self.swiftTransaction).hashValue
}
public override func isEqual(_ object: Any?) -> Bool {
@@ -272,25 +238,17 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
return false
}
return self.bridgeToSwift === object.bridgeToSwift
return self.swiftTransaction === object.swiftTransaction
}
// MARK: CoreStoreObjectiveCType
// MARK: Internal
public required init(_ swiftValue: BaseDataTransaction) {
internal let swiftTransaction: BaseDataTransaction
internal init(_ swiftValue: BaseDataTransaction) {
self.swiftTransaction = swiftValue
super.init()
}
public var bridgeToSwift: BaseDataTransaction {
return self.swiftTransaction
}
// MARK: Private
private let swiftTransaction: BaseDataTransaction
}

View File

@@ -2,7 +2,7 @@
// CSClauseTypes.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

View File

@@ -2,7 +2,7 @@
// CSCoreStore+Migrating.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@ import CoreData
// MARK: - CSCoreStore
public extension CSCoreStore {
extension CSCoreStore {
/**
Asynchronously adds a `CSInMemoryStore` to the `defaultStack`. Migrations are also initiated by default.

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