Compare commits

..

1118 Commits

Author SHA1 Message Date
John Estropia edd8ba55d8 fix rare duplication of uniqueID values during import when an import candidate is added by a previous insertion block 2021-01-23 16:51:45 +09:00
John Estropia 18aac84335 fix compiler error 2021-01-02 10:36:33 +09:00
John Estropia c6be892cb0 added .where(combinedByAnd:) and .where(combinedByOr:) to help compiler with long && and || chains 2021-01-02 10:00:23 +09:00
John Estropia 2cd8101987 Implement ObjectRepresentation on ObjectMonitor, ObjectPublisher, and ObjectSnapshot for future APIs 2021-01-02 09:59:15 +09:00
John Estropia e1aed37da0 avoid using default queue qos 2020-12-26 23:45:11 +09:00
John Estropia 5de5ecee06 give opportunity for faster equating of ObjectSnapshot 2020-12-26 23:44:35 +09:00
John Estropia 9406901b28 WIP: SwiftUI utils 2020-12-26 19:21:46 +09:00
John Estropia 477f478d85 Add missing Where operators (fixes #410) 2020-12-26 14:02:20 +09:00
John Estropia 668b5ad606 Update playground samples to use Field properties instead of old syntax 2020-12-07 14:08:05 +09:00
John Estropia f985828f3b cleanup 2020-11-17 18:14:23 +09:00
John Estropia bb3bc940c2 Remove the dataStack SwiftUI environment key since it's prone to initialization issues 2020-11-11 16:56:20 +09:00
John Estropia 2d5bc77219 Merge branch 'master' into minIOS11
# Conflicts:
#	Sources/ListSnapshot.swift
2020-11-11 13:44:58 +09:00
John Estropia a40df37192 version bump 2020-11-11 13:29:02 +09:00
John Estropia 63b3d25d78 clear warnings 2020-11-11 13:18:11 +09:00
John Estropia 74721b5c12 allow ObjectSnapshot and ObjectPublisher as parameter to Where clauses 2020-10-10 16:55:35 +09:00
John Estropia f136549b46 prevent creation of ObjectSnapshot if object is already deleted 2020-10-09 20:14:04 +09:00
John Estropia 4ec2b2e311 Optimize ListSnapshot collection implementation 2020-10-05 23:12:17 +09:00
John Estropia 3d82ee18c7 reinclude LegacyDemo in workspace 2020-10-03 14:36:57 +09:00
John Estropia d6eae8c091 fix podspec 2020-09-19 15:07:27 +09:00
John Estropia 6f8d86cd8f remove xcuserdata 2020-09-19 14:59:14 +09:00
John Estropia 3b6f226389 version bump 2020-09-19 14:44:55 +09:00
John Estropia 228e4e8e1a rename CoreStoreDemo to LegacyDemo 2020-09-19 14:32:43 +09:00
John Estropia 98a42feb95 demo cleanup 2020-09-19 12:38:09 +09:00
John Estropia 2f93ee7591 Migrations demo done 2020-09-17 23:21:41 +09:00
John Estropia 11f5cb9a05 WIP: demo 2020-09-14 09:46:47 +09:00
John Estropia 2c00fc31bc WIP: migrations demo 2020-09-13 14:17:06 +09:00
John Estropia 2bbf6b34ea WIP: migrations demo 2020-09-08 09:09:36 +09:00
John Estropia 8d7f282743 added demo for classic ListMonitor 2020-08-30 20:16:01 +09:00
John Estropia 007da014f8 cleanup 2020-08-30 10:24:10 +09:00
John Estropia b26e50f777 add version lock to demo 2020-08-29 23:06:12 +09:00
John Estropia 611bc53c9a cleanup 2020-08-29 23:05:07 +09:00
John Estropia 9d36582c10 minor fix 2020-08-29 20:06:00 +09:00
John Estropia 1c735a9228 improve Pokedex demo 2020-08-29 20:02:05 +09:00
John Estropia 1db91fcec3 make demo compilable on Xcode 11 2020-08-27 09:50:12 +09:00
John Estropia 8b3b947406 pokedex demo 2020-08-20 00:39:03 +09:00
John Estropia 2c0cadf2fa WIP 2020-08-19 18:49:08 +09:00
John Estropia 5e536556da fix for SR-13069 2020-08-19 11:01:12 +09:00
John Estropia d75029f54b WIP 2020-08-19 08:32:18 +09:00
John Estropia 204c4de1f6 use randomElement in unit test 2020-08-18 17:50:00 +09:00
John Estropia 0f3455a4a4 WIP 2020-08-18 12:05:20 +09:00
John Estropia 72f36e7237 WIP 2020-08-17 17:09:41 +09:00
John Estropia d988daa025 WIP: new demo app 2020-08-17 09:06:25 +09:00
John Estropia e720504855 Update README.md 2020-06-20 17:37:12 +09:00
John Estropia ee51c5ad9c fix readme indentations 2020-06-20 16:47:52 +09:00
John Estropia 4ac7df7364 version bump 2020-06-20 13:16:14 +09:00
John Estropia 56f873ccb3 fix readme table of contents 2020-06-20 13:12:11 +09:00
John Estropia 1f90f846f3 readme update 2020-06-20 13:07:10 +09:00
John Estropia 4a97d5a8dc remove persistentstores during DataStack deinitialization to prevent warnings in Unit tests during teardown 2020-05-26 09:43:39 +09:00
John Estropia 0eb9b6393d add unit testst for Field dynamic initializers 2020-05-24 10:54:16 +09:00
John Estropia 56d0ea46ea Implement dynamic initializers for Field properties (fixes #382) 2020-05-23 12:07:16 +09:00
John Estropia a7568eebdb fix comments 2020-04-15 16:49:45 +09:00
John Estropia 4049e1944a trigger lazy initialization of ObjectPublisher observation after addObserver() (fixes #383) 2020-04-15 16:48:42 +09:00
John Estropia 73b7fcd907 Merge branch 'prototype/propertyWrapperFields' into develop 2020-03-26 02:04:33 +09:00
John Estropia 74c1a97af4 Version bump 2020-03-26 02:04:10 +09:00
John Estropia 97f2a53124 AppleDocs for Field source files 2020-03-26 01:57:32 +09:00
John Estropia b6db872be0 Merge branch 'prototype/propertyWrapperFields' of github.com:JohnEstropia/CoreStore into prototype/propertyWrapperFields 2020-03-25 19:00:56 +09:00
John Estropia 0d9299f900 WIP: docs 2020-03-25 14:21:49 +09:00
John Estropia 7f928dc684 docs 2020-03-19 14:12:09 +09:00
John Estropia 231e138ab0 performant access of relationship objectIDs for snapshots 2020-02-21 13:51:17 +09:00
John Estropia 361dba58c6 bypass thread checks depending on location of Field call 2020-02-21 11:52:11 +09:00
John Estropia e1b03b4a89 fix wrong optional configuration in Field.Virtual 2020-02-21 11:20:32 +09:00
John Estropia 0df6c737c1 fix wrong optional configuration in Field.Virtual 2020-02-21 11:17:39 +09:00
John Estropia 12c5aeaaa4 safer casting 2020-02-21 10:36:28 +09:00
John Estropia dd3fb17dd0 fix runtime issue with Fields on objects with base classes 2020-02-21 10:19:42 +09:00
John Estropia 627a5d4355 add OrderBy utilities for Field.Stored 2020-02-19 22:01:46 +09:00
John Estropia 58629bc1df add missing predicate operator overloads 2020-02-19 13:58:14 +09:00
John Estropia f925803b93 Create FUNDING.yml 2020-02-19 13:32:57 +09:00
John Estropia 843adf21f7 improved API for custom getters and setters in Field properties 2020-02-18 18:17:52 +09:00
John Estropia 2d1b1e0592 add Field.Coded dynamic lookups for ObjectPublisher and ObjectSnapshot 2020-02-17 18:30:18 +09:00
John Estropia 38e9878c04 Merge branch 'master' into prototype/propertyWrapperFields 2020-02-08 09:47:35 +09:00
John Estropia 8cb8b95c2e fix build for watchOS 2020-02-08 08:49:11 +09:00
John Estropia 8e4e308ccc Merge branch 'prototype/propertyWrapperFields' of github.com:JohnEstropia/CoreStore into prototype/propertyWrapperFields 2020-02-06 09:33:15 +09:00
John Estropia f0f4049798 renamed Field.Computed to Field.Virtual to distinguish from Field.Derived 2020-02-06 09:33:08 +09:00
John Estropia c20fe4ac17 add Field.Relationship dynamicMemberLookups 2020-02-05 11:03:57 +09:00
John Estropia e9c3312612 Fix default encoders for top-level values 2020-01-21 17:03:12 +09:00
John Estropia 92ad895044 Field.Relationship propertyWrapper 2020-01-20 17:13:01 +09:00
John Estropia bcc2d9def3 Field.Coded implementations for transformable attributes 2020-01-18 16:22:06 +09:00
John Estropia 43f61359da prototype new Fields as propertyWrappers (Swift 5.2 above only) 2020-01-15 18:29:58 +09:00
John Estropia 5e37ee4566 Reorganize properties source files 2020-01-10 17:04:51 +09:00
John Estropia c544e0cce8 lazily evaluate NSEntityDescription-required fields from CoreStoreObject attributes 2020-01-09 17:00:43 +09:00
John Estropia f119a3adec add SPM installation instructions to README 2020-01-08 11:21:41 +09:00
John Estropia c951cb87a3 version bump 2020-01-08 11:03:43 +09:00
John Estropia 08147806a0 explicit exclusion of objc files in package.swift 2020-01-08 11:01:22 +09:00
John Estropia 4beb11519e Deprecation of ObjectiveC shivs 2020-01-08 10:26:27 +09:00
John Estropia b7ebda4487 Use generic collection types in ListSnapshot mutators 2020-01-05 02:37:42 +09:00
John Estropia b4489301ac fix SPM spec 2019-12-23 11:53:46 +09:00
John Estropia c025e5acc6 version bump 2019-12-23 10:11:26 +09:00
John Estropia 57745f36a8 Allow purging of datasource 2019-12-17 21:10:01 +09:00
John Estropia eef1c99f11 Allow custom views to consume ListSnapshot diffable data 2019-12-17 19:45:53 +09:00
John Estropia 9a19919392 add utility to create ObjectPublisher directly from a DynamicObject using its own context 2019-12-02 12:21:06 +09:00
John Estropia 3e2d62fe67 missed public modifier 2019-12-02 11:53:23 +09:00
John Estropia 6f275eb63a add "updatedItemIdentifiers" utility to ListSnapshot 2019-12-02 10:52:36 +09:00
John Estropia b12dba4d15 optimizations 2019-11-29 20:09:43 +09:00
John Estropia 4ee1b04523 Support for fetchOffset in ListPublisher, optimize slicing logic 2019-11-18 19:52:57 +09:00
John Estropia b1decc9853 Force fetchLimit for ListPublisher and ListSnapshot 2019-11-14 20:34:48 +09:00
John Estropia c2e4c033ef Merge pull request #348 from ntnmrndn/fixWarning
Fix warning
2019-11-05 19:11:51 +09:00
John Estropia e12223df85 fix casting error 2019-10-29 20:37:08 +09:00
John Estropia 468922d5ed fix casting issues 2019-10-29 20:30:03 +09:00
John Estropia 6b9a4b480b minor 2019-10-29 20:18:14 +09:00
Antoine Marandon 81b482e28b Fix warning 2019-10-29 17:27:25 +09:00
John Estropia c112a84c0a Add debugDescription implementation for new Publisher and Snapshot types 2019-10-28 19:31:02 +09:00
John Estropia 88ab0b5e15 provide direct conversion from DynamicObject to ObjectSnapshot 2019-10-28 12:03:17 +09:00
John Estropia 717cb75720 Add utility to fetch ObjectPublishers by ObjectID 2019-10-28 11:23:12 +09:00
John Estropia 998938490c Make ObjectPublishers even lighter by lazy-loading observers 2019-10-25 19:16:38 +09:00
John Estropia f3beca8769 fix compiler error in testcases 2019-10-25 16:17:25 +09:00
John Estropia 4baeb6d922 Fix weak linking of SwiftUI in podspec 2019-10-25 14:35:04 +09:00
John Estropia 98d860aff6 Add unit tests for List and Object Publishers 2019-10-25 14:34:22 +09:00
John Estropia 11a9e3991c changed ListPublisher and ObjectPublisher factory method naming to match ListMonitor and ObjectMonitor naming 2019-10-25 12:43:39 +09:00
John Estropia f380d9dc25 ObjectSnapshot: allow dynamicMember keyPaths from superclasses 2019-10-25 12:36:13 +09:00
John Estropia d546ff154f Merge pull request #344 from timfraedrich/patch-1
small correction to documentation
2019-10-23 19:27:33 +09:00
John Estropia f21597d332 Merge pull request #341 from dmatushkin/develop
Fix for build on iOS with Swift Package Manager
2019-10-23 19:27:01 +09:00
John Estropia d971c3a2ac README bug 2019-10-22 17:24:54 +09:00
John Estropia 80166a42bb Unify generic labeling 2019-10-22 16:16:47 +09:00
John Estropia 3d8bdf1cf3 Remove references to OSAtomic to silence deprecation warnings 2019-10-22 11:48:09 +09:00
John Estropia 1ddce5aa8d Package.swift update 2019-10-21 22:39:54 +09:00
John Estropia 7a1600fac4 README ok for now 2019-10-21 21:34:45 +09:00
John Estropia e4e664d8ce README update 2019-10-21 21:24:34 +09:00
John Estropia 145edd5a7d README update 2019-10-21 21:15:46 +09:00
John Estropia f5fed063ee Docs update 2019-10-20 18:17:31 +09:00
John Estropia a267395618 WIP: README 2019-10-19 22:17:25 +09:00
John Estropia 326b897b06 WIP: docs 2019-10-19 09:34:31 +09:00
John Estropia 0b18366ab1 Renamed LiveList to ListPublisher and LiveObject to ObjectPublisher. WIP: docs 2019-10-18 19:36:27 +09:00
John Estropia ddf599ba85 WIP: documentation 2019-10-18 08:19:55 +09:00
John Estropia 6e3e540d0a Improve handling in LiveObject and ObjectSnapshot when objects are deleted 2019-10-17 19:27:03 +09:00
John Estropia bd066f0cef delete unused files 2019-10-17 16:59:00 +09:00
John Estropia 9764f33086 update demo app 2019-10-17 12:32:47 +09:00
John Estropia 0c19c878c5 LiveList refetch 2019-10-17 11:39:29 +09:00
John Estropia 1b8e517b5a WIP: update demo app 2019-10-17 07:40:15 +09:00
John Estropia 2818a778a4 Revert ObjectMonitor to previous implementation 2019-10-16 19:20:11 +09:00
John Estropia 64a0264354 DiffableDataSource.CollectionView implementation 2019-10-16 14:01:25 +09:00
John Estropia 7932625644 Merge branch 'develop' into datasources 2019-10-16 10:16:13 +09:00
John Estropia 4619fbbec3 WIP: ObjectRepresentable 2019-10-16 08:22:03 +09:00
John Estropia 6b64eb7650 WIP: ObjectRepresentable utilities 2019-10-14 21:36:03 +09:00
John Estropia f5a165d47d back-portable TableView DiffableDataSource 2019-10-13 11:45:30 +09:00
John Estropia 12c58e3955 improved caching in utility methods 2019-10-12 10:02:00 +09:00
John Estropia 5af0d17de4 remov stateIDs 2019-10-12 07:20:09 +09:00
John Estropia 81dfb8e3e5 WIP: editable datasources 2019-10-11 07:47:49 +09:00
John Estropia d5114fc4bc WIP 2019-10-08 21:09:34 +09:00
John Estropia 693fc7fbbb Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2019-10-07 10:16:11 +09:00
John Estropia b073b7e795 swiftUI support done for now 2019-10-06 23:37:04 +09:00
Tim Fraedrich 56d9719984 small correction to documentation
While using some code from the documentation that led to issues I noticed that some parts of it are not accurate anymore, so I corrected a few small things that came to my attention. Maybe it is worth having an even closer look though.
2019-10-04 14:19:14 +00:00
John Estropia 953c9723a8 (WIP) SwiftUI working demo for LiveList<D> 2019-10-04 19:12:32 +09:00
John Estropia c5a996d5ed WIP: do not use yet 2019-10-04 08:43:04 +09:00
John Estropia 53a83d823e Merge branch 'develop' into datasources 2019-09-22 07:39:18 +09:00
dmatushkin 6d75dcbc32 Fix for build on iOS with Swift Package Manager 2019-09-15 14:57:20 +04:00
John Estropia 0345ee9c94 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2019-09-14 01:40:37 -04:00
John Estropia 4016b5dc83 Merge pull request #331 from jagbryrmiginte/develop
Fixes #328 by specifying platform requirements in Package.swift
2019-09-14 01:34:35 -04:00
John Estropia 64b5e102aa Merge pull request #340 from pushp1989/develop
Added Support for Swift 5
2019-09-14 01:33:51 -04:00
Pushpendra 8e3c44c072 Added Support for Swift 5
Upgraded Xcode build version
Added missing reference of for different targets
2019-09-13 15:27:46 +05:30
John Estropia 12dc32f7e6 Merge branch 'develop' into datasources
# Conflicts:
#	CoreStoreDemo/CoreStoreDemo/List and Object Observers Demo/ListObserverDemoViewController.swift
#	CoreStoreTests/DynamicModelTests.swift
#	Sources/BaseDataTransaction+Importing.swift
#	Sources/CoreStoreObject.swift
#	Sources/CustomSchemaMappingProvider.swift
#	Sources/DynamicObject.swift
#	Sources/Functions.swift
#	Sources/ImportableUniqueObject.swift
#	Sources/NSManagedObjectContext+Querying.swift
2019-08-29 17:15:45 +09:00
John Estropia b4c38caf1e Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2019-08-29 17:03:16 +09:00
John Estropia 266b1a9913 Deprecation of enum CoreStore, reorganize global symbols 2019-08-29 17:03:09 +09:00
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
jagbryrmiginte f0dac2454c Bump SPM package description to 5.0 to resolve compiler error 2019-07-21 12:12:30 +02:00
jagbryrmiginte d4deed0cf7 Specify minimum deployment target for Swift Package Manager, fixes Issue #328 2019-07-21 12:09:53 +02:00
John Estropia 79655ffde5 added ObjectSnapshot as foundation for datasources API 2019-07-10 08:11:42 +09:00
John Estropia cf46b45e8e Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2019-07-09 22:53:33 +09:00
John Estropia ed3d21db77 WIP: reorganization of keypath utilities (in prep for @propertyWrappers) 2019-07-09 14:50:23 +09:00
John Estropia f16e3593c0 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2019-07-06 23:00:20 +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 03973790a8 revert recent swizzling update. sorry about that 2017-02-10 20:33:07 +09:00
John Estropia 7ee027f44d Test mainContext fetching directly from PSC. Needs benchmarking esp. with merging 2017-02-09 10:49:50 +09:00
John Estropia 19fea6953a Merge branch 'master' into develop 2017-02-08 13:13:27 +09:00
John Estropia 9f11b1005d added .swift-version file 2017-02-08 13:08:44 +09:00
John Estropia 698326f89a version bump 2017-02-07 18:21:54 +09:00
John Estropia bdf6308d8f swift 3.1 support 2017-02-07 18:17:40 +09:00
John Estropia 69d96c53d6 WIP: object concurrency debugging utilities 2017-02-02 19:53:47 +09:00
John Estropia 7b961fa249 Display list of model files in bundle when requested modelname is not found 2017-02-01 19:03:59 +09:00
John Estropia 73450d0b29 WIP: minor conveniences to the ImportableUniqueObject protocol 2017-01-20 21:51:00 +09:00
John Estropia 6d83564a1a Swift 3 master candidate 2017-01-06 16:50:38 +09:00
John Estropia c0d72799b4 Merge branch 'swift3_develop' into develop
# Conflicts:
#	.travis.yml
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	Sources/Info.plist
2017-01-06 16:03:28 +09:00
John Estropia 06a1919e91 minor fixes 2017-01-06 15:56:47 +09:00
John Rommel Estropia 16def2d84b disable tests on iOS 8.2 and 8.1 (keeps failing due to xcode bug) 2016-12-31 13:14:50 +08:00
John Rommel Estropia e9a2c58f32 travis bug 2016-12-31 11:26:35 +08:00
John Rommel Estropia 1a3e0dd4c6 CoreStore 3 master candidate 2016-12-31 11:03:03 +08:00
John Rommel Estropia 518bb134f9 merge fix 2016-12-26 14:55:06 +08:00
John Estropia 4d7feca848 Merge pull request #139 from deanWombourne/swift3_develop
Add an override to cs_typeName which deals with String explicitly.
2016-12-26 14:53:51 +08:00
John Rommel Estropia 64a80bf401 Swift 3.0.1 support 2016-12-26 14:51:36 +08:00
John Rommel Estropia 4d63fc744a Add String overload for cs_typeName (fixes #138) 2016-12-26 14:51:23 +08:00
Sam Dean 9480e372f1 Add an override to cs_typeName which deals with String explicitly. 2016-12-23 11:06:09 +00:00
John Rommel Estropia 23df460c35 require transaction logs path from icloud stores 2016-12-10 18:39:53 +09:00
John Rommel Estropia 1c233b7302 don't access iCloud's ubiquitous cache file 2016-12-10 09:43:45 +09:00
John Estropia f42288802c Merge branch 'swift3_develop' of github.com:JohnEstropia/CoreStore into swift3_develop
# Conflicts:
#	Sources/Convenience/NSManagedObject+Convenience.swift
2016-12-08 19:00:38 +09:00
John Estropia a27556f294 minor Swift 3 cleanup 2016-12-08 18:59:41 +09:00
John Rommel Estropia e330291e1b support generics for KVC accessors 2016-12-03 10:13:50 +09:00
John Rommel Estropia 4a282150f0 utilities for safer KVO access in objects 2016-12-03 09:59:17 +09:00
John Rommel Estropia 5d2956d674 Make RecreateStoreOnModelMismatch flag work again (fixes #126) 2016-11-26 16:19:12 +09:00
John Estropia 92756fec42 always dispatch completion right after adding a store to the coordinator (allow stores to fully complete their run loop) 2016-11-17 16:27:28 +09:00
John Estropia 2b37daefe0 minor documentation updates 2016-11-17 14:31:06 +09:00
John Estropia 5724d4599e Merge pull request #122 from ruslanskorb/rename-error-type-to-error
`ErrorType` has been renamed to `Error` in Swift 3.
2016-11-17 13:34:03 +09:00
Ruslan Skorb 4a882e6108 ErrorType has been renamed to Error in Swift 3. 2016-11-15 19:16:18 +02:00
John Estropia b230ed6400 FetchableSource and QueryableSource protocols 2016-11-15 18:00:39 +09:00
John Estropia 33a5c123aa resurrect utilities for creating NSFetchedResultsController (fixes #119) 2016-11-11 17:32:13 +09:00
John Estropia 73637321ce xcode 8.1 (swift 3.0.1) update 2016-11-11 14:03:37 +09:00
John Estropia 088f1717f9 Merge pull request #115 from deville/import-unique-objects-order
Import unique objects in the same order as the array of import sources (with fix for potential duplicates)
2016-11-11 11:46:27 +09:00
John Estropia cff2bb1740 version bump 2016-10-27 19:16:17 +09:00
John Estropia d902d62172 Turn off whole-module-optimization to prevent Swift compiler bugs (#113) 2016-10-27 18:41:27 +09:00
John Estropia b955495012 Turn off whole-module-optimization to prevent Swift compiler bugs (#113) 2016-10-27 18:30:35 +09:00
Andrii Chernenko d2e78a70e1 add test for the order of unique object import 2016-10-23 16:22:26 +02:00
Andrii Chernenko 970957cbc2 Merge branch 'duplicate-import-fix' into import-unique-objects-order 2016-10-23 14:52:34 +02:00
John Rommel Estropia 2f9e5db89f Added comment (fixes #106) 2016-10-16 14:40:25 +09:00
John Estropia 1789eb7daf Merge pull request #112 from JohnEstropia/revert-109-import-unique-objects-order
Revert "Import unique objects in the same order as the array of import sources"
2016-10-14 17:46:27 +09:00
John Estropia 3999654ee7 Revert "Import unique objects in the same order as the array of import sources" 2016-10-14 17:45:31 +09:00
Andrii Chernenko 4c3bec287c fix duplication when using importUniqueObjects with non-unique import sources 2016-10-12 02:01:23 +02:00
John Estropia 2a2d9b3483 Merge pull request #109 from deville/import-unique-objects-order
Import unique objects in the same order as the array of import sources
2016-10-10 20:29:59 +09:00
Andrii Chernenko 32a388e0ca import unique objects in the same order as the array of import sources 2016-10-08 23:14:22 +02:00
John Rommel Estropia 1a6fbad3d4 force dynamic dispatch on generic types 2016-10-09 00:52:18 +09:00
John Estropia ac55f20f5f Merge pull request #108 from deville/type-method-dispatch-fix
Fix type method dispatch when importing objects
2016-10-08 10:43:21 +09:00
Andrii Chernenko 910b5039fd fix type method dispatch when importing objects 2016-10-07 15:26:45 +02:00
John Estropia ffea06ee7e try again 2016-09-30 19:16:14 +09:00
John Estropia a92d6cac02 try again 2016-09-30 19:08:17 +09:00
John Estropia de5d660257 try again 2016-09-30 17:53:15 +09:00
John Estropia 55b2e6eecd try again 2016-09-30 17:36:48 +09:00
John Estropia b64c776335 try again 2016-09-30 17:28:02 +09:00
John Estropia 432af667e8 try again 2016-09-30 17:08:04 +09:00
John Estropia cf60a4bc2e updated travis.yml 2016-09-30 17:00:11 +09:00
John Estropia c620859899 run demo project on CI 2016-09-30 13:58:11 +09:00
John Estropia 65ac069a0b skip observer testing on macOS 2016-09-30 13:32:31 +09:00
John Estropia 862ef27374 version bump, cleanup, unit test 2016-09-30 13:28:19 +09:00
John Estropia 243b6a76d5 Merge pull request #104 from colinmorelli/feature/sync-transaction-async-merge
Fixes #98 (deadlock when merge happens while main queue is querying)
2016-09-30 12:38:28 +09:00
Colin Morelli 8be20370d5 Fixes #98 (deadlock when merge happens while main queue is querying) 2016-09-29 14:47:51 -04:00
John Estropia a9c0feae46 NSFetchRequest.affectedStores bug workaround 2016-09-27 19:02:24 +09:00
John Estropia 2e44f86eb6 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Cartfile
#	Carthage/Checkouts/GCDKit
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	CoreStoreDemo/CoreStoreDemo.xcodeproj/project.pbxproj
#	CoreStoreTests/BaseTests/BaseTestCase.swift
#	CoreStoreTests/FromTests.swift
#	CoreStoreTests/GroupByTests.swift
#	CoreStoreTests/OrderByTests.swift
#	CoreStoreTests/StorageInterfaceTests.swift
#	CoreStoreTests/TweakTests.swift
#	CoreStoreTests/WhereTests.swift
#	README.md
#	Sources/Internal/CoreStoreFetchRequest.swift
#	Sources/Internal/NSManagedObjectContext+Querying.swift
#	Sources/Internal/NSManagedObjectModel+Setup.swift
#	Sources/Migrating/DataStack+Migration.swift
#	Sources/ObjectiveC/CSSQliteStore.swift
#	Sources/ObjectiveC/CSStorageInterface.swift
#	Sources/ObjectiveC/CoreStoreBridge.swift
#	Sources/Observing/ListMonitor.swift
#	Sources/Setup/DataStack.swift
#	Sources/Setup/StorageInterfaces/ICloudStore.swift
#	Sources/Setup/StorageInterfaces/LegacySQLiteStore.swift
#	Sources/Setup/StorageInterfaces/SQLiteStore.swift
#	Sources/Setup/StorageInterfaces/StorageInterface.swift
2016-09-27 18:55:37 +09:00
John Estropia ed8c7b35e8 Reduce leaking (a little) on the workaround for NSFetchRequest.affectedStores ARC bug 2016-09-27 17:31:08 +09:00
John Rommel Estropia 4d2ebe4ea8 workaround #100 (NSFetchRequest.affectedStores ARC bug) 2016-09-27 02:39:28 +09:00
John Estropia 54be9d471c renamed ImportableObject and ImportableUniqueObject protocol methods to Swift 3 naming style 2016-09-21 12:00:48 +09:00
John Rommel Estropia f18d62f643 travis yml update 2016-09-17 14:27:36 +09:00
John Rommel Estropia af141d4a31 travis yml update 2016-09-17 14:26:33 +09:00
John Rommel Estropia 2da659a967 travis yml update 2016-09-17 14:14:29 +09:00
John Rommel Estropia e5f162c5e1 minor readme edits 2016-09-17 13:59:04 +09:00
John Rommel Estropia effa231719 fix travis 2016-09-17 13:37:00 +09:00
John Rommel Estropia 6cef8f4b4f updated travis yml 2016-09-17 13:23:56 +09:00
John Rommel Estropia aa6bceaaf3 working for Swift 2.3! 2016-09-17 12:22:25 +09:00
John Rommel Estropia 0dbd05b172 version bump 2016-09-11 14:30:32 +09:00
John Rommel Estropia 243c4044ab fix bridging producing base abstract class instead of subclass concrete class 2016-09-11 14:30:25 +09:00
John Rommel Estropia df835114cb ignore errors when deleting wal files 2016-09-10 22:57:45 +09:00
John Rommel Estropia f99d3cc21a fix RecreateStoreOnModelMismatch option not working when an existing xcdatamodel gets updated without adding a new version 2016-09-10 22:51:33 +09:00
John Estropia a51ed1a007 WIP: Renaming to meet Swift 3 API guidelines 2016-09-09 18:30:08 +09:00
John Estropia e5245a0e5b user #keyPath() for keys in demo app and in unit tests 2016-09-09 17:05:55 +09:00
John Estropia 0fa2a23461 workaround for iOS 10 regression in "affectedStores" retain bug 2016-09-09 13:09:13 +09:00
John Estropia 3f28198552 Magical NSFetchedResultsController bugfix.... 2016-09-09 12:49:10 +09:00
John Rommel Estropia 4a34012d58 version bump 2016-09-08 00:40:58 +09:00
John Estropia 45690a29c6 Merge pull request #92 from ThibaultVlacich/develop
Add DEBUG flag to the Debug config
2016-09-07 19:01:19 +09:00
Thibault Vlacich 0d4d036a86 Add DEBUG flag to the Debug config 2016-09-07 10:43:43 +02:00
John Estropia 82de482191 WIP: broken generics 2016-09-06 20:16:46 +09:00
John Estropia b502895d63 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Sources/Internal/NotificationObserver.swift
2016-09-06 12:05:40 +09:00
John Estropia ed0fdc76fe update podspec 2016-09-06 11:19:38 +09:00
John Estropia 58f4907575 Prevent retain cycles in NSManagedObjectContext (fixes #87) 2016-09-06 11:13:16 +09:00
John Estropia 0ba63c6e72 WIP: Xcode 8 beta 6 2016-09-06 09:57:28 +09:00
John Rommel Estropia e9be711d4c WIP: demo app 2016-07-25 08:21:22 +09:00
John Rommel Estropia db5b8ca702 Merge branch 'develop' into swift3_develop
# Conflicts:
#	Cartfile.resolved
#	Carthage/Checkouts/GCDKit
#	CoreStoreTests/ErrorTests.swift
#	Sources/Fetching and Querying/Concrete Clauses/Select.swift
#	Sources/ObjectiveC/CSError.swift
2016-07-22 00:47:03 +09:00
John Rommel Estropia 1950224863 version bump 2016-07-22 00:33:15 +09:00
John Rommel Estropia f0cd288657 allow querying on relationship attributes (fixes #83) 2016-07-22 00:29:48 +09:00
John Rommel Estropia 2f39f9188b WIP: the great renaming 2016-07-21 23:12:24 +09:00
John Estropia 3344e42d7c version bump 2016-07-21 11:51:57 +09:00
John Estropia e4b6c06401 fixed internal errors getting thrown as .Unknown instead of .InternalError (fixes #84) 2016-07-21 11:51:49 +09:00
John Rommel Estropia 872e69ddc6 WIP 2016-07-21 08:34:13 +09:00
John Rommel Estropia f9e33101a0 WIP 2016-07-21 08:32:16 +09:00
John Rommel Estropia 0621c54868 WIP 2016-07-21 02:48:23 +09:00
John Rommel Estropia a638620858 WIP 2016-07-21 02:45:42 +09:00
John Rommel Estropia 267c21063a WIP: segfault 2016-07-20 08:12:04 +09:00
John Estropia 7fc3ad2890 Tidy up, version bump 2016-07-14 19:59:15 +09:00
John Estropia 556f6d13b3 Merge pull request #81 from jannon/mark-app-extension-safe
Mark app extension safe
2016-07-14 19:41:55 +09:00
Jannon Frank a088fe3817 mark iOS and tvOS safe for app extensions 2016-07-12 18:39:23 -07:00
Jannon Frank c4391a8d0c Merge remote-tracking branch 'JohnEstropia/master' into upstream 2016-07-12 18:36:53 -07:00
John Rommel Estropia f486ace437 make cocoapods happy 2016-07-12 00:16:02 +09:00
John Estropia edb2aa2463 Update README.md 2016-07-11 13:40:26 +09:00
John Estropia 7b48d825a3 Update README.md 2016-07-11 13:38:21 +09:00
John Rommel Estropia 921b85d91b documentation updates 2016-07-11 02:04:18 +09:00
John Estropia 4f46cbded9 Update README.md 2016-07-11 02:01:24 +09:00
John Estropia a8af91b2f8 Update README.md 2016-07-11 00:55:01 +09:00
John Estropia 8a8b3fa0b1 Update README.md 2016-07-10 23:01:53 +09:00
John Estropia 4196ed8085 Update README.md 2016-07-10 15:49:08 +09:00
John Estropia 0458de5d65 Update README.md 2016-07-10 15:37:52 +09:00
John Estropia 90ae17e904 Update README.md
WIP
2016-07-10 15:31:59 +09:00
John Estropia 3c0d4d648d Update README.md
WIP
2016-07-09 18:44:26 +09:00
John Estropia b60bcf8da6 Update README.md 2016-07-09 17:21:47 +09:00
John Rommel Estropia f9014e65e0 objc keypath utilities 2016-07-01 01:06:16 +09:00
John Rommel Estropia 82887b1dd2 CSInto unit tests 2016-06-25 13:43:43 +09:00
John Estropia 11d428c05c import magic for objective c utils 2016-06-20 20:28:25 +09:00
John Estropia 0b48bb3347 renamed CSFromCreate() to CSFromClass() 2016-06-20 19:36:57 +09:00
John Estropia aa5cd51da6 Merge branch 'develop' into corestore2_develop 2016-06-20 19:18:42 +09:00
John Estropia e50dd9881d allow accessing a ListMonitor as a flat array when using API's without section info 2016-06-20 19:18:31 +09:00
John Rommel Estropia 3ccbce5c29 WIP: utilities for clauses 2016-06-20 08:09:11 +09:00
John Rommel Estropia e5a199489c WIP: objc utilities 2016-06-19 02:40:25 +09:00
John Rommel Estropia 3d5c4f8121 removed unit test check for undefined behavior 2016-06-17 02:44:37 +09:00
John Rommel Estropia 2dc09289bf fixed platform dependencies 2016-06-17 01:24:19 +09:00
John Rommel Estropia 76a2bc1da2 importing unit tests 2016-06-12 20:34:13 +09:00
John Rommel Estropia 8e5c7ec9b2 querying unit tests 2016-06-11 22:57:00 +09:00
John Rommel Estropia 101ab69861 added testing for logger behaviors 2016-06-11 21:13:06 +09:00
John Rommel Estropia ea2a65cf57 Merge branch 'corestore2_develop' of github.com:JohnEstropia/CoreStore into corestore2_develop 2016-06-11 19:10:12 +09:00
John Rommel Estropia f59b1b6320 WIP: query tests 2016-06-11 19:09:56 +09:00
John Estropia 141e977f9c remove sort assertion when using ObjectMonitor 2016-06-09 18:56:32 +09:00
John Estropia 788cce0df6 Merge branch 'corestore2_develop' of https://github.com/JohnEstropia/CoreStore into corestore2_develop
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-06-09 18:23:59 +09:00
John Estropia 4304d8687e Merge branch 'develop' into corestore2_develop 2016-06-09 18:20:58 +09:00
John Estropia d25f751089 oops 2016-06-09 18:20:49 +09:00
John Estropia 6df78a0595 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-06-09 18:12:18 +09:00
John Estropia c0ed2f23ce ignore negative indexes when using ListMonitor's safeIndex APIs 2016-06-09 18:06:08 +09:00
John Estropia dcf562fb26 ignore negative indexes when using ListMonitor's safeIndex API 2016-06-09 17:57:15 +09:00
John Rommel Estropia b9353238e8 transaction fetching unit tests 2016-06-07 00:14:22 +09:00
John Rommel Estropia b98805e489 WIP: Fetching unit tests 2016-06-06 00:12:00 +09:00
John Rommel Estropia 02a89accc8 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
#	Sources/Internal/CoreStoreFetchRequest.swift
2016-06-05 17:20:59 +09:00
John Rommel Estropia 2e4c9a7a25 fix From clauses not setting the NSFetchRequest's affectedStores property properly 2016-06-05 17:19:20 +09:00
John Rommel Estropia fcca6b205e WIP: Unit tests 2016-06-04 14:29:10 +09:00
John Rommel Estropia b199f38b0c Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2016-05-28 22:40:01 +09:00
John Rommel Estropia 0c8731c610 improved flushing behavior 2016-05-28 22:34:14 +09:00
John Rommel Estropia ee4eb178ed Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Convenience/NSFetchedResultsController+Convenience.swift
#	Sources/Info.plist
2016-05-28 11:46:31 +09:00
John Rommel Estropia f617f2cc53 Simpler API for creating CoreStore-managed NSFetchedResultsControllers, useful for external SDK's that require them 2016-05-28 01:47:48 +09:00
John Rommel Estropia f396b01043 fixed Cartfile dependency 2016-05-26 01:28:26 +09:00
John Rommel Estropia 7942cf411e WIP: clauses unit tests 2016-05-26 01:03:01 +09:00
John Rommel Estropia 02be72b0b7 Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
#	Sources/Transactions/UnsafeDataTransaction.swift
2016-05-25 21:41:44 +09:00
John Rommel Estropia e38093342d version bump, updated dependendencies 2016-05-24 00:42:35 +09:00
John Rommel Estropia c15afcb381 Allow flushing UnsafeDataTransactions to notify its ListMonitors and ObjectMonitors without saving changes to the DataStack (fixes #71) 2016-05-24 00:40:13 +09:00
John Rommel Estropia a97001cdbb fixed scheme 2016-05-24 00:32:54 +09:00
John Rommel Estropia 000a357808 WIP: test cases 2016-05-23 23:40:00 +09:00
John Estropia c8ca16a982 Merge pull request #69 from bretsko/master
fixed Readme
2016-05-17 14:05:11 +09:00
Oleksandr Bretsko 9e0493a20d fixed Readme
replaced importObjects with importUniqueObjects
2016-05-17 08:43:40 +04:00
John Estropia 77236d66d5 relax NSManagedObject return types so callers don't need to cast every time 2016-05-11 21:55:51 +09:00
John Estropia 8b95d337a3 relax NSManagedObject return types so callers don't need to cast every time 2016-05-10 21:49:50 +09:00
John Rommel Estropia 57b66cff34 implementations for desctiption and debugDescription complete for all CoreStore types 2016-05-08 20:30:28 +09:00
John Rommel Estropia 9dae291f62 WIP: logging clauses 2016-05-08 00:28:36 +09:00
John Rommel Estropia 0c2a3ac4e9 fix merge 2016-05-07 18:13:44 +08:00
John Rommel Estropia a6291e116c Merge branch 'master' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
#	Sources/Internal/NSManagedObjectContext+Transaction.swift
2016-05-07 17:47:35 +08:00
John Rommel Estropia c990f7764a version bump 2016-05-07 12:19:30 +08:00
John Rommel Estropia 26ae6293ca merge changes to main context synchronously or asynchronously depending on the caller intention (fixes #65) 2016-05-07 12:18:54 +08:00
John Rommel Estropia b9a2f96d6e renamed refreshAllObjectsAsFaults to refreshAndMergeAllObjects, which is more correct 2016-05-07 12:04:59 +08:00
John Rommel Estropia ae5f737baf WIP: logging clauses 2016-05-07 12:01:31 +08:00
John Rommel Estropia 4eecd80710 WIP: pretty logging 2016-05-06 09:19:24 +08:00
John Rommel Estropia 0073d038e0 WIP: logging utilities 2016-05-05 09:44:14 +08:00
John Rommel Estropia 099dcfab68 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2016-05-02 18:22:43 +08:00
John Rommel Estropia 74fe81bfa7 Fix problem when using carthage where the iOS7 framework overwrites the iOS 8 framework 2016-05-02 12:02:31 +08:00
John Rommel Estropia 0bbb4118a1 documentation for iCloud methods 2016-04-30 01:20:35 +09:00
John Rommel Estropia 3fe9e4ee1d WIP: ICloudStore prototype 2016-04-30 00:26:06 +09:00
John Rommel Estropia bd19326447 folder structure 2016-04-03 19:55:10 +09:00
John Rommel Estropia dccc958ef1 comment documentations 2016-04-03 19:47:25 +09:00
John Rommel Estropia ab3095f078 WIP: documentation 2016-04-03 13:37:00 +09:00
John Rommel Estropia 1a86510045 Group Swift files 2016-04-03 12:20:13 +09:00
John Rommel Estropia aa32f5e158 support value querying in Objective C 2016-04-02 21:39:05 +09:00
John Rommel Estropia b95aaf151d Merge branch 'corestore2_develop' into corestore2_develop_objc 2016-04-01 07:47:03 +09:00
John Rommel Estropia 114bc71841 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	Sources/Info.plist
2016-04-01 07:46:42 +09:00
John Rommel Estropia dff552b95f version bump 2016-04-01 07:42:00 +09:00
John Rommel Estropia 88cac73b20 fix assertion error 2016-04-01 07:41:23 +09:00
John Rommel Estropia 83d0412cb9 Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
2016-04-01 07:20:42 +09:00
John Rommel Estropia 26e4118355 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	CoreStore/Setting Up/DataStack.swift
#	Sources/Info.plist
2016-04-01 07:18:53 +09:00
John Rommel Estropia 0c564add46 separate CoreStoreFetchRequest file 2016-04-01 07:04:02 +09:00
John Rommel Estropia 784a315fb9 version bump 2016-04-01 01:32:32 +09:00
John Rommel Estropia 44cfbebedb prevent deadlock on when DataStack gets deallocated 2016-04-01 01:28:39 +09:00
John Rommel Estropia 0b24072259 Workaround CoreData's bug when using NSFetchRequest's affectedStores property 2016-04-01 01:22:16 +09:00
John Rommel Estropia 28b7ba01dc prevent deadlock on when DataStack gets deallocated 2016-03-31 00:04:17 +09:00
John Rommel Estropia b529735269 Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-03-30 21:41:44 +09:00
John Rommel Estropia d23121d8ed Merge branch 'develop' into corestore2_develop
# Conflicts:
#	Sources/Observing/ListMonitor.swift
2016-03-30 21:40:21 +09:00
John Rommel Estropia 633ab0a249 cache fetchClauses in property so closures do not retain them indeterminately 2016-03-30 21:16:10 +09:00
John Rommel Estropia 410feda5cd tidy up 2016-03-30 20:47:13 +09:00
John Rommel Estropia 06e952af8a clear FRC delegate on deinit 2016-03-30 20:28:10 +09:00
John Estropia a4d3d0c0ed fix mistype 2016-03-30 13:05:29 +09:00
John Estropia 8b7af86526 WIP: Objective-C bridge (90% done!) 2016-03-30 11:12:17 +09:00
John Estropia 48a8694720 attempt to fix closure deallocation bug (#58) 2016-03-30 05:22:05 +09:00
John Rommel Estropia 09d844f5df WIP: CSSetupResult 2016-03-30 01:55:06 +09:00
John Estropia e25e198bf8 WIP: Objective-C migrations 2016-03-29 14:46:31 +09:00
John Estropia e99d19d2ac ListMonitor and ObjectMonitor objective C bridge 2016-03-29 14:15:57 +09:00
John Estropia 9d7960e674 typed arrays 2016-03-28 19:41:11 +09:00
John Estropia e9ac8629a1 tidy up 2016-03-28 19:35:09 +09:00
John Estropia b0b0df2861 allow public access to bridgeToObjectiveC and bridgeToSwift properties 2016-03-28 19:07:35 +09:00
John Estropia eda398d758 WIP: CSListMonitor 2016-03-28 17:19:51 +09:00
John Rommel Estropia 40c320e1ca add missing files in scheme 2016-03-28 00:43:14 +09:00
John Rommel Estropia 8508dd4f79 delete iCloud folder 2016-03-27 23:13:01 +09:00
John Rommel Estropia d3e0f576cf tidy up 2016-03-27 23:12:21 +09:00
John Rommel Estropia 1d5cf5a4cc Merge branch 'corestore2_develop' into corestore2_develop_objc 2016-03-27 23:03:37 +09:00
John Rommel Estropia 9fc0390b45 Merge branch 'develop' into corestore2_develop 2016-03-27 23:03:21 +09:00
John Rommel Estropia b8ea7ecf01 WIP: objective-C fetching 2016-03-27 23:02:24 +09:00
John Estropia 11ac362dcc Update README.md 2016-03-27 20:32:14 +09:00
John Estropia 10c20e0d62 Update README.md 2016-03-27 10:28:35 +09:00
John Estropia 789028bc58 WIP: CSImportableUniqueObject 2016-03-25 19:59:31 +09:00
John Estropia a168ca577a Merge branch 'corestore2_develop' into corestore2_develop_objc 2016-03-25 19:28:47 +09:00
John Estropia 781f3988d2 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStoreDemo/CoreStoreDemo/Loggers Demo/CustomLoggerViewController.swift
#	CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift
2016-03-25 19:28:37 +09:00
John Estropia b914a4b5ed updated Readme 2016-03-25 18:20:24 +09:00
John Estropia 7de13131a4 small demo fix 2016-03-25 18:18:17 +09:00
John Estropia 0c1af09a8d Make demo app compile again (sorry) (fixes #57) 2016-03-25 18:08:03 +09:00
John Estropia 1ff635d8b5 WIP: CSImportableObject 2016-03-25 17:57:26 +09:00
John Rommel Estropia 707445a169 WIP: SaveResult bridge 2016-03-25 07:57:09 +09:00
John Estropia 90369cf994 WIP: simpler bridging 2016-03-24 21:22:58 +09:00
John Estropia 09708e587c Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	CoreStore.xcodeproj/project.pbxproj
2016-03-24 15:16:13 +09:00
John Estropia 36e6e4a8b9 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	Cartfile
#	Cartfile.resolved
#	CoreStore.podspec
#	CoreStore.xcodeproj/project.pbxproj
#	CoreStore/Migrating/DataStack+Migration.swift
#	CoreStore/Setting Up/DataStack.swift
#	README.md
#	Sources/Info.plist
2016-03-24 15:09:36 +09:00
John Rommel Estropia 9f1a351311 add missing scheme 2016-03-23 23:20:24 +09:00
John Rommel Estropia 6e202aa7ca set missing build setting 2016-03-23 22:31:16 +09:00
John Rommel Estropia 783b933294 add missing file 2016-03-23 22:26:39 +09:00
John Rommel Estropia ca49ea3a81 iOS 7 full support 2016-03-23 22:21:05 +09:00
John Rommel Estropia ed8891a6d5 Merge branch 'corestore2_develop' into corestore2_develop_objc
# Conflicts:
#	Sources/Migrating/MigrationChain.swift
2016-03-23 21:24:30 +09:00
John Rommel Estropia dd6c6abaf0 Merge branch 'develop' into corestore2_develop
# Conflicts:
#	CoreStore.podspec
#	CoreStore/CartFile
#	README.md
#	Sources/Info.plist
#	Sources/Internal/NSManagedObjectModel+Setup.swift
#	Sources/Logging/CoreStore+Logging.swift
2016-03-23 21:23:08 +09:00
John Estropia 928585029d XCode 7.3 full support 2016-03-23 12:39:11 +09:00
John Estropia dc6d22b6ff updated travis XCode version 2016-03-23 12:14:34 +09:00
John Estropia 5ca0f657cb XCode 7.3 fixes 2016-03-23 12:07:31 +09:00
John Estropia 2c65ac1834 WIP: transactions in ObjC 2016-03-23 11:32:35 +09:00
John Rommel Estropia 24008d62b2 WIP: error handling 2016-03-22 22:51:42 +09:00
John Rommel Estropia e8a9cc9d67 WIP: error handling 2016-03-22 07:23:11 +09:00
John Estropia 1507ac63f9 WIP: objective C storages 2016-03-18 20:32:23 +09:00
John Rommel Estropia f2df8f7171 WIP: objective C interface 2016-03-18 02:39:18 +09:00
John Rommel Estropia 3ddfd3cccc WIP: objc setup 2016-03-17 07:51:22 +09:00
John Estropia 21f57518c8 WIP: Objective-C bridge 2016-03-16 21:23:41 +09:00
John Rommel Estropia d9422f7f2e Changed error-handling method to rely on new enum CoreStoreError instead of NSErrors 2016-03-16 07:56:19 +09:00
John Estropia 245ec25ad8 Update README.md 2016-03-15 16:24:51 +09:00
John Rommel Estropia 0ce89b8460 WIP: documentation 2016-03-15 07:57:02 +09:00
John Rommel Estropia 42a889a28e WIP: documentation 2016-03-14 07:57:49 +09:00
John Rommel Estropia 456977bf12 renamed default directories 2016-03-13 11:21:01 +09:00
John Rommel Estropia ea8412ab93 removed Nimble 2016-03-13 11:10:09 +09:00
John Rommel Estropia 603dffffb0 WIP: documentation and unit tests 2016-03-12 20:13:38 +09:00
John Rommel Estropia 8a1144b1be Merge branch 'develop' into corestore2_develop
# Conflicts:
#	README.md
2016-03-12 10:37:33 +09:00
John Rommel Estropia c323a28c19 fix warnings in demo app 2016-03-12 09:27:59 +09:00
John Rommel Estropia 4ff7b2d6d9 WIP: documentation 2016-03-12 00:16:54 +09:00
John Estropia 64ad7b3bfd Update README.md 2016-03-11 20:59:52 +09:00
John Estropia df441c5d04 Update README.md 2016-03-11 20:58:33 +09:00
John Estropia fa947faa57 make demo app for migrations initialize smoother 2016-03-10 20:28:19 +09:00
John Estropia 6822a4579e WIP: clean up persistent store setup 2016-03-10 20:19:52 +09:00
John Estropia a89dd76906 WIP: tidy up 2016-03-09 19:42:17 +09:00
John Estropia c85ef16ad0 WIP: tidy up 2016-03-09 18:49:00 +09:00
John Estropia 67f1bd9a63 updated travis.yml 2016-03-09 17:51:45 +09:00
John Estropia 39540628df updated travis.yml 2016-03-09 17:48:54 +09:00
John Estropia c86ca06bd4 Swift Package Manager support 2016-03-09 17:47:46 +09:00
John Estropia 40c27b9fcb Merge branch 'master' into corestore2_develop 2016-03-08 15:54:24 +09:00
John Rommel Estropia 2f8c100cb6 WIP: StorageInterface 2016-03-08 07:55:15 +09:00
John Rommel Estropia 34495d7163 WIP: prevent error when adding non-existent file 2016-03-07 07:35:55 +09:00
John Rommel Estropia 75a4ebb49b WIP: StorageInterface methods 2016-03-07 07:23:44 +09:00
John Rommel Estropia 3c514830d9 WIP: SQLiteStore implementation 2016-03-04 07:51:35 +09:00
John Estropia b283fbf5ab WIP: StorageInterface 2016-03-03 20:03:13 +09:00
John Estropia c1e087b8c1 goodbye strongSelf 2016-03-03 12:51:56 +09:00
John Rommel Estropia ad1ebb3501 WIP: StorageInterface protocol 2016-03-03 07:50:43 +09:00
John Rommel Estropia 99189d160f WIP: Storage protocol 2016-03-02 08:02:33 +09:00
John Estropia 3c2fb28644 added Packaged.swift 2016-03-01 19:42:28 +09:00
John Rommel Estropia f71ad4c577 WIP: Storage protocols 2016-03-01 08:01:40 +09:00
John Rommel Estropia d05fcc5103 updated demo app for deprecated methods 2016-02-29 22:26:34 +09:00
John Rommel Estropia e9329fc93c better quality image 2016-02-28 01:21:00 +09:00
John Rommel Estropia 1ea773f0ec added CoreStore logo 2016-02-27 16:01:48 +09:00
John Rommel Estropia c68c2bdc0a Merge branch 'develop' into corestore2_develop
Conflicts:
	CoreStore.podspec
	CoreStore/Info.plist
2016-02-26 01:51:35 +09:00
John Estropia e66a13632a Merge branch 'develop' 2016-02-25 15:52:59 +09:00
John Estropia 4c78a309bc deprecated NSFetchedResultsController initializer in favor of static factory method 2016-02-25 15:52:49 +09:00
John Estropia 9055daa58c Merge branch 'develop' 2016-02-25 15:11:40 +09:00
John Estropia 3905423038 fix compile error 2016-02-25 15:05:27 +09:00
John Estropia 15353268e2 Allow unsafe transactions to save synchronously 2016-02-25 15:04:05 +09:00
John Rommel Estropia 91dd4b6cb3 tidy up 2016-02-25 07:14:15 +09:00
John Rommel Estropia 0800b706d6 revert 2016-02-24 22:04:14 +09:00
John Rommel Estropia 2071ce722e WIP: iCloud support 2016-02-24 22:03:14 +09:00
John Rommel Estropia df866718cf tidy up 2016-02-24 22:02:26 +09:00
John Rommel Estropia f19a0d29eb added obsolete annotations to previously deprecated methods 2016-02-24 21:52:35 +09:00
John Estropia 8f09f90294 Changed default directories to comply with Apple's guidelines (TODO: update README) 2016-02-24 18:57:03 +09:00
John Estropia 7bddcaa4a2 swift 2.2 (Xcode 7.3 beta 4) updates 2016-02-24 16:54:39 +09:00
John Estropia c12331f403 Merge pull request #53 from mpurbo/patch-1
added missing closing bracket on sample code.
2016-02-22 22:26:38 +09:00
Mamad Purbo a55a8d389c added missing closing bracket on sample code. 2016-02-22 11:50:28 +09:00
John Rommel Estropia 6e88b14237 fixed readme build status 2016-02-20 12:30:02 +09:00
John Rommel Estropia 53700a267f version bump 2016-02-20 12:28:39 +09:00
John Rommel Estropia 6c95b010e9 utility to update an existing ImportableObject from its ImportSource (fixes #52) 2016-02-20 12:26:23 +09:00
John Rommel Estropia 1af675e8b7 tidy up 2016-02-20 12:05:01 +09:00
John Rommel Estropia b85f16cf68 Merge branch 'master' into develop 2016-02-20 01:25:40 +09:00
John Estropia 37bf4179c8 renamed "Incremental Migrations" to "Progressive Migrations" to match the common term used by the community 2016-02-17 15:34:33 +09:00
John Estropia 240dda6ad6 Merge pull request #50 from ReadmeCritic/master
Correct the spelling of Xcode in README
2016-02-17 10:03:47 +09:00
ReadmeCritic ffe73d0f66 Correct the spelling of Xcode in README 2016-02-16 11:47:36 -08:00
John Rommel Estropia 43c4998e20 fix podspec 2016-02-17 02:32:39 +09:00
John Rommel Estropia 0c4e55f061 Merge branch 'develop' 2016-02-17 02:06:57 +09:00
John Rommel Estropia 8c8953c507 updated .travis.yml 2016-02-17 01:57:28 +09:00
John Rommel Estropia 66892f22a3 comments cleanup 2016-02-17 01:38:26 +09:00
John Rommel Estropia def105e73a added utility to query transactions about pending inserts, updates, and deletes 2016-02-17 00:00:25 +09:00
John Rommel Estropia 57bf123fb2 assert missing classes in model 2016-02-16 07:52:34 +09:00
John Rommel Estropia 8efd6572f0 Refetch monitors when persistent stores are added/removed. Allow unsafe transactions to create their own monitors 2016-02-15 07:56:17 +09:00
John Estropia 405e861907 Merge pull request #47 from ReadmeCritic/master
Correct the spelling of CocoaPods in README
2016-02-12 10:37:49 +09:00
ReadmeCritic 74c48c7486 Correct the spelling of CocoaPods in README 2016-02-11 09:45:40 -08:00
John Rommel Estropia e58b3b0131 fixed some typos in the README 2016-02-11 09:25:32 +09:00
John Rommel Estropia b8fad66bfa tidy up: copyright symbol 2016-02-01 01:07:07 +09:00
John Rommel Estropia ff1155dac3 fix OSX compiler error 2016-01-31 23:27:29 +09:00
John Rommel Estropia 5137649b78 Fix for Swift 2.2 compatibility 2016-01-31 17:23:34 +09:00
John Rommel Estropia 7a95267a9c updated Readme 2016-01-26 12:34:06 +09:00
John Rommel Estropia c07435e866 Added utility for re-faulting all objects in a transaction/dataStack 2016-01-26 12:22:30 +09:00
John Rommel Estropia f5627f0855 fixed demo app framework settings 2016-01-23 01:52:27 +09:00
John Estropia d3ea655eb9 Merge branch 'master' into develop
Conflicts:
	README.md
2016-01-19 12:26:37 +09:00
John Estropia fc83180af8 updated README 2016-01-19 12:25:58 +09:00
John Estropia 0c6246475a update README 2016-01-19 12:24:14 +09:00
John Estropia 087480a3a8 update cartfile 2016-01-19 12:22:14 +09:00
John Estropia 83a04e669e updated .travis.yml 2016-01-19 11:55:22 +09:00
John Estropia d05522bb20 tidy up, set default directory to Caches folder on tvOS 2016-01-19 11:38:11 +09:00
Cihat Gündüz 9081b36cca Add tvOS target + Configure target + Add shared scheme for tvOS 2016-01-17 13:30:45 +01:00
Cihat Gündüz 9322371224 Use tvOS_support feature branch of GCDKit (Carthage + git submodules) 2016-01-17 13:11:58 +01:00
John Estropia 26ab6aacd7 exposed utility for extracting the parent transaction for objects created from UnsafeDataTransactions 2016-01-14 17:54:58 +09:00
John Estropia 3e601c1328 tidy up (WIP: queue check for NSManagedObjectContext property updates) 2016-01-08 20:44:42 +09:00
John Estropia 762b877879 Merge pull request #35 from JohnEstropia/modify-gitignore
Update .gitignore: Add .DS_Store
2016-01-08 18:41:29 +09:00
Hiroshi Kimura 084bdc431f Update .gitignore: Add .DS_Store 2016-01-08 18:40:16 +09:00
John Estropia c63bc389b2 updated travis.yml 2016-01-06 19:29:58 +09:00
John Estropia 71c3abc4f3 Let ListMonitor expose methods for Section Indexes (fixes #32) 2016-01-06 19:16:46 +09:00
John Estropia 863d4d1d5a Merge branch 'master' into develop
# Conflicts:
#	README.md
2016-01-06 18:45:45 +09:00
John Estropia 06d177e8bd Update README.md 2016-01-04 19:38:42 +09:00
John Estropia c2bbd537cf Update README.md 2016-01-04 19:38:11 +09:00
John Estropia 761d349b97 Rename CartFile to Cartfile. Sorry about that 2016-01-04 12:38:05 +09:00
John Rommel Estropia 6c28594e41 fixed shouldUpdateFromImportSource() not called from importUniqueObject() (fixes #31) 2015-12-29 08:25:06 +08:00
John Estropia c229af19a2 added GCDKit to Carthage installation guide 2015-12-18 19:28:02 +09:00
John Estropia 8b8a7c7b08 fix macOSX development target 2015-12-16 14:01:56 +09:00
John Estropia eb828d8e42 update deployment version 2015-12-15 21:20:56 +09:00
John Estropia 88a24540c6 remove IPHONEOS_DEPLOYMENT_TARGET flag 2015-12-15 20:51:48 +09:00
John Estropia 74ded8fb7d update .travis.yml 2015-12-15 19:58:59 +09:00
John Estropia 969f4cefb4 use workspaces for better carthage support 2015-12-15 19:56:07 +09:00
John Estropia 1d2947ad26 added Carthage dependency 2015-12-08 18:34:10 +09:00
John Estropia 49274c3c94 fix swift project settings 2015-12-08 16:35:50 +09:00
John Rommel Estropia c0fbb2655b version bump 2015-12-06 20:32:06 +09:00
John Rommel Estropia cefd6f6cbc fix watchOS travis configuration 2015-12-05 20:28:24 +09:00
John Rommel Estropia 2653f7b977 fix watchOS travis configuration 2015-12-05 20:13:52 +09:00
John Rommel Estropia c1163283f5 fix watchOS travis configuration 2015-12-05 20:03:21 +09:00
John Rommel Estropia 529347b6a2 fix watchOS travis configuration 2015-12-05 19:48:40 +09:00
John Rommel Estropia eba7e99374 fixed yml 2015-12-05 19:35:23 +09:00
John Rommel Estropia 3c4350bd5d enable testability 2015-12-05 19:30:04 +09:00
John Rommel Estropia 88b13189e5 fix yml 2015-12-05 19:23:12 +09:00
John Rommel Estropia 03da3544f6 change GCDKit submodule path to public url to make sir Travis happy 2015-12-05 19:20:27 +09:00
John Rommel Estropia 648b59e1ee fix yml 2015-12-05 19:14:35 +09:00
John Rommel Estropia ab3c8ca812 tidy up 2015-12-05 19:01:07 +09:00
John Rommel Estropia 900a31c541 added build status to readme 2015-12-05 18:55:20 +09:00
John Rommel Estropia 656a107767 test travis ci 2015-12-05 18:50:54 +09:00
John Rommel Estropia 4ce3d5de3c undo interface 2015-12-05 18:21:21 +09:00
John Rommel Estropia dec9757dc2 Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2015-12-05 18:19:33 +09:00
John Estropia 578e4966fc added a convenience initializer for clients that only support NSFetchedResultsController (i.e. Objective-C) 2015-11-24 19:12:04 +09:00
John Estropia b741626574 updated GCDKit 2015-11-24 17:50:23 +09:00
John Estropia f79a77ab78 remove unneeded imports in demo app 2015-11-24 17:02:23 +09:00
John Estropia 1f2a70fd42 minor fixes 2015-11-24 16:06:48 +09:00
John Estropia 718d2c9b7d Added ability to initialize ListMonitors asynchronously. This is a deadlock-preventive measure for apps that heavily recreates ListMonitors while updates and saves are running in the background (because NSFetchedResultController's performFetch() locks the whole NSManagedObjectContext chain up until the NSPersistentStoreCoordinator) 2015-11-24 14:49:43 +09:00
John Estropia c5ff02335e debug flag 2015-11-24 12:32:10 +09:00
John Estropia 66b57faa44 Merge branch 'master' into develop 2015-11-24 11:34:35 +09:00
John Estropia eef5a3d80b allow CoreStore installation both through frameworks or through direct linking 2015-11-24 11:33:52 +09:00
John Estropia bc0757cf06 README: Added link to poll for new features 2015-11-18 19:46:17 +09:00
John Rommel Estropia 0c0a2a382c Deprecated rollback() on async and sync transactions. Added undo utilities to unsafe transactions. 2015-11-14 20:00:40 +09:00
John Rommel Estropia 05b4a7092a updated podspec for OSX 2015-10-30 01:46:47 +09:00
John Rommel Estropia 6aed070e7c version bump for OSX support 2015-10-30 01:36:15 +09:00
John Estropia fcb1d7cbbc OSX support!!!11 2015-10-29 17:00:10 +09:00
John Estropia d074aad111 Merge branch 'master' into develop 2015-10-26 14:42:31 +09:00
John Estropia b7685dc747 allow Sequences of NSManagedObject subclasses as argument to delete() method 2015-10-26 14:41:58 +09:00
John Rommel Estropia a185bc96c0 updated README 2015-10-24 11:41:13 +09:00
John Rommel Estropia 91aef44803 fix pod dependency 2015-10-23 00:49:34 +09:00
John Rommel Estropia dcfb09eda7 attempt sight improvement for the FRC bug workaround #20 2015-10-23 00:40:38 +09:00
John Estropia 9ca83d9c5d watchOS support (fixes #19) 2015-10-20 21:01:10 +09:00
John Estropia b00eaf2d0b fix warnings on watchOS 2015-10-20 20:54:09 +09:00
John Estropia dc8bdf3bad watch OS support 2015-10-20 20:38:58 +09:00
John Estropia 4792c4462e fix section index titles when refetching a listMonitor 2015-10-15 18:29:08 +09:00
John Estropia 524757a7cf just a safety measure for the rare case that the FRC delegate gets released earlier than the FRC 2015-10-13 10:47:48 +09:00
John Rommel Estropia 0b6298a802 tidy up 2015-10-07 00:57:48 +09:00
John Estropia ae77558ae8 Merge pull request #16 from mac-cain13/patch-1
Fix FRCdelegate issue where invalid type is passed
2015-10-07 00:44:15 +09:00
Mathijs Kadijk d33aa9c5cf Fix FRCdelegate issue where invalid type is passed
See also https://forums.developer.apple.com/thread/12184#31850
2015-10-06 15:30:22 +02:00
John Estropia d89319d324 Workaround for Xcode 7.0.1+iOS 9 FRC bug 2015-09-30 11:41:27 +09:00
John Estropia cf9af6eef5 Merge branch 'develop' 2015-09-28 20:46:14 +09:00
John Estropia b9ec66f425 fix entityNameMapping bug 2015-09-28 20:44:19 +09:00
John Estropia 2a8df0596d Update README.md 2015-09-24 23:47:06 +09:00
John Rommel Estropia 83e6a41d88 Merge branch 'master' into develop 2015-09-22 11:40:28 +09:00
John Rommel Estropia c6fe494fe1 updated podspec dependency 2015-09-21 23:30:41 +09:00
John Rommel Estropia 7771e047e2 updated GCDKit version to remove warnings 2015-09-21 23:23:22 +09:00
John Rommel Estropia 5b0439835b Deprecated DetachedDataTransaction in favor of UnsafeDataTransaction. beginDetached() methods are also deprecated; use beginUnsafe() instead. 2015-09-21 15:08:46 +09:00
John Rommel Estropia 622c5aa652 Tighter generics implementations. You can now pass any SequenceType's for methods that previously only accepts Array's. 2015-09-19 19:45:01 +09:00
John Rommel Estropia 114b7ce605 Tighter generics implementations. You can now pass any SequenceType's for methods that previously only accepts Array's. 2015-09-19 18:20:52 +09:00
John Rommel Estropia 7451fbe026 added README sections about ImportableObject and ImportableUniqueObject, as well as the new fetchExisting() method usage 2015-09-19 16:23:59 +09:00
John Rommel Estropia ee2398fcdf updated readme 2015-09-18 07:14:41 +09:00
John Rommel Estropia 8d26501040 WIP: Readme 2015-09-14 07:44:23 +09:00
John Estropia 0709fe95cf use transaction queue for refetching instead of a global queue 2015-09-11 15:06:36 +09:00
John Estropia 656a99fe12 added thread safety checks to ListMonitor to prevent deadlocks after calling refetch() 2015-09-11 13:59:28 +09:00
John Estropia 726e0eabe9 dispatch_group seems more semantically fitting than semaphore 2015-09-11 13:50:29 +09:00
John Estropia 032764b9b7 tidy up 2015-09-10 16:59:55 +09:00
John Estropia 5461bb0736 workaround an NSFetchedResultsController bug in Xcode 7 targeted on iOS 8 devices where errant index paths cause crashes 2015-09-10 16:57:35 +09:00
John Estropia 4c6bc4f494 completed appledocs for importing methods 2015-09-10 13:28:53 +09:00
John Rommel Estropia 63a43a6487 WIP: documentation 2015-09-10 07:21:53 +09:00
John Estropia 6a006d5d7c added a flag to inspect the current state of a refetch 2015-09-08 18:12:52 +09:00
John Estropia 399517e357 ListMonitor is now refetch-able. Implement the listMonitorWillRefetch and listMonitorDidRefetch methods of ListObserver and call the refetch(...) method of ListMonitor 2015-09-08 17:21:15 +09:00
John Estropia f47adc12b3 fix typealias name clash when observing both ListMonitor and ObjectMonitor 2015-09-02 13:44:37 +09:00
John Estropia 0de1733efe oops 2015-09-01 21:05:59 +09:00
John Estropia e627cf8161 test improvements to ListMonitor 2015-09-01 20:08:45 +09:00
John Rommel Estropia 22943d2c76 added warn_unused_result annotations where they seem reasonable 2015-08-29 22:29:03 +09:00
John Estropia 56ea14d53c fix disconnected observers when an observer registers itself to multiple ListMonitors 2015-08-28 12:09:55 +09:00
John Rommel Estropia 21a524d725 tidy up 2015-08-28 08:09:06 +09:00
John Estropia d5e769be6c turns out inout arguments in closures are malloc nightmares. this finally fixes it 2015-08-27 22:24:40 +09:00
John Estropia ea6b6f2c37 bandaid solution for over-deallocated sequences bug in swift (for now) 2015-08-27 19:06:52 +09:00
John Estropia c3ef8a4172 bug fix for dictionaries getting deallocated earlier 2015-08-27 17:28:40 +09:00
John Rommel Estropia 16aabe1f3b optimize fetching objects with NSManagedObjectIDs 2015-08-26 23:59:18 +09:00
John Estropia 10e0cf8d2c tidy up 2015-08-25 20:33:36 +09:00
John Estropia 3a0f53321a improved behavior for #12 (as of Xcode 7 beta 6) 2015-08-25 14:35:22 +09:00
John Estropia 0da43d5132 Merge branch 'develop' of https://github.com/JohnEstropia/CoreStore into develop 2015-08-25 14:27:32 +09:00
John Estropia 69f902ef20 XCode7 beta 6 updates 2015-08-25 14:24:18 +09:00
John Estropia d04b4ca085 added utility for ListMonitor to return the index/indexPath of a specified object 2015-08-24 20:40:19 +09:00
John Estropia 8ed6a78609 CoreStore adapter method 2015-08-24 17:36:40 +09:00
John Estropia 0c9e6afe0e added utility to inspect NSEntityDescription for a given NSManagedObject type 2015-08-24 17:33:27 +09:00
John Rommel Estropia ff4629908a Merge branch 'develop' of github.com:JohnEstropia/CoreStore into develop 2015-08-23 14:37:34 +09:00
John Rommel Estropia d3ffe7a8fc add default implementation for souldUpdateFromImportSource 2015-08-23 14:37:21 +09:00
John Rommel Estropia 3919ada428 Merge branch 'master' into develop 2015-08-23 14:29:44 +09:00
John Rommel Estropia 682b13a8d3 version bump 2015-08-23 14:25:18 +09:00
John Rommel Estropia 2f935de04a temporarily fix an Xcode 7 bug (still present as of beta 5) (temporarily fixes #12) 2015-08-23 14:21:12 +09:00
John Rommel Estropia 006d5e1402 rewrote ImportableObject protocol methods 2015-08-23 14:15:48 +09:00
John Rommel Estropia 093c1d410f temporarily fix an Xcode 7 bug (still present as of beta 5) (temporarily fixes #12) 2015-08-23 14:02:27 +09:00
John Estropia 7555ff3ad0 allow preprocessing dictionary mapping before importing objects 2015-08-21 19:48:47 +09:00
John Estropia 4c16a961ba added default implementation to didInsertFromImportSource 2015-08-21 18:28:02 +09:00
John Estropia 1121d44d7b pass transaction to ImportableObject methods 2015-08-21 18:19:21 +09:00
John Rommel Estropia ba4fb5e5cb version bump 2015-08-21 08:03:14 +09:00
John Rommel Estropia d860da2507 Merge branch 'develop' 2015-08-21 08:03:01 +09:00
John Estropia 2bcf8008c5 let transaction fetch existing objects from external contexts 2015-08-20 17:20:38 +09:00
John Estropia 71477c0839 allow equality comparison on ListMonitor and ObjectMonitor to help distinguish senders when observing multiple monitors 2015-08-20 14:25:14 +09:00
John Estropia 3348aa0bef added utility to check if objects exist in a ListMonitor 2015-08-20 13:51:14 +09:00
John Estropia 2ed61fdb17 added utilities to ListMonitor to extract all objects in specified sections 2015-08-20 12:15:20 +09:00
John Estropia 9cfad8a17a oops, GroupBy should not be needed for monitorList() 2015-08-19 21:00:27 +09:00
John Estropia 3bf34f33dc added utilities for ListMonitor to optionally extract objects with potentially invalid indexes/indexPaths 2015-08-19 20:56:50 +09:00
John Estropia 90bfaeaae8 removed unused key tuple 2015-08-19 18:30:39 +09:00
John Estropia a29a4b38fe added utilities to get existing NSManagedObject instances using object IDs 2015-08-19 15:53:20 +09:00
John Estropia 5a96ef13f6 added utility to get NSManagedObjectID from an object URI 2015-08-19 15:07:15 +09:00
John Estropia b92ee76907 added utility to refresh an object 2015-08-19 12:19:14 +09:00
John Estropia 67ccae4ef6 added missing parameters 2015-08-19 11:21:39 +09:00
John Estropia 62b11309f3 expose DataStack vars to CoreStore 2015-08-18 21:49:40 +09:00
John Estropia 8c6a7df731 provide a way to enumerate entities managed by the DataStack 2015-08-18 21:40:33 +09:00
John Rommel Estropia b475afe79f updated Readme 2015-08-17 23:51:08 +09:00
John Rommel Estropia a263851266 import array of ImportableObjects 2015-08-17 23:50:03 +09:00
John Estropia cbc3eb8887 woops, develop branch should be Swift 2.0, not 1.2 2015-08-11 15:37:44 +08:00
John Rommel Estropia 2fb3263aa1 refactored autoreleasepool calls 2015-08-09 18:27:21 +09:00
John Rommel Estropia 64aa97264e added utilities for importing data 2015-08-09 05:06:42 +09:00
John Rommel Estropia 8066bf2a5a fixed assertion failures when fetching from detached data transactions 2015-08-09 05:05:26 +09:00
John Rommel Estropia 283104af3f thanks to protocol extensions, you can now omit ListObserver and ObjectObserver methods you don't need to implement 2015-08-09 05:04:47 +09:00
John Rommel Estropia 83c724f584 updated default logger to still run assertions even on optimized (-O) builds 2015-08-08 22:12:08 +09:00
John Rommel Estropia 59ad525786 fixed for Xcode 7 beta 5 2015-08-08 10:24:40 +09:00
John Rommel Estropia b85d7521e1 version bump 2015-07-29 22:24:11 +09:00
John Rommel Estropia 4dbc4558e3 display explanation dialog for migration demo 2015-07-29 22:21:22 +09:00
John Rommel Estropia 2a56c097f2 Merge branch 'master' into develop 2015-07-29 21:32:17 +09:00
John Estropia d4b95aed64 Merge pull request #10 from bddckr/patch-1
Fix building with Carthage
2015-07-28 12:44:43 +09:00
Christopher - Marcel Böddecker 0d2650c54b Fix building with Carthage 2015-07-27 19:26:19 +02:00
John Rommel Estropia 6a3885edda aesthetic 2015-07-26 21:21:19 +09:00
John Rommel Estropia 1c6085ad82 expose DetachedDataTransaction's context and allow creating children detached transactions (https://github.com/JohnEstropia/CoreStore/issues/9) 2015-07-26 21:20:48 +09:00
John Rommel Estropia 2dae2ae39c update GCDKit submodule version 2015-07-26 17:11:53 +09:00
John Rommel Estropia a1e37975cc updated project settings for Xcode 7 beta 4 2015-07-26 17:08:56 +09:00
John Rommel Estropia 0c8a43c3b0 added shorthand vars for inspecting MigrationType values. updated readme 2015-07-26 17:04:19 +09:00
John Rommel Estropia 9676e3aca2 addSQLiteStoreAndWait() does not support auto-migrating stores anymore; use the asynchronous addSQLiteStore(..., completion:) method instead. 2015-07-26 10:07:42 +09:00
John Rommel Estropia a34d2795af remove queue asserts for detached transactions 2015-07-26 09:27:00 +09:00
John Rommel Estropia 106789d592 refactor some internal methods. renamed addInMemoryStore to addInMemoryStoreAndWait to reflect synchronicity. 2015-07-25 23:05:48 +09:00
John Rommel Estropia edc51de030 catch intentional error in logger demo 2015-07-24 08:06:59 +09:00
John Rommel Estropia f85eb2e057 merge changes to the main context asynchronously (fixes https://github.com/JohnEstropia/CoreStore/issues/7) 2015-07-24 08:05:13 +09:00
John Rommel Estropia f0161b50ed submodule update 2015-07-19 00:07:47 +09:00
John Rommel Estropia 6c780c1282 use GCDKit's swift2.0 supported commit 2015-07-19 00:05:58 +09:00
John Rommel Estropia b711ec9644 gcdkit version 2015-07-18 23:57:59 +09:00
John Rommel Estropia a581f91507 Merge branch 'develop'
Conflicts:
	README.md
2015-07-18 23:53:37 +09:00
John Estropia ebd4df5c2f Update README.md 2015-07-14 13:23:41 +09:00
John Estropia 2780fd7682 Update README.md 2015-07-14 13:23:26 +09:00
John Rommel Estropia 982e75a36e updated README 2015-07-14 07:56:50 +09:00
John Rommel Estropia 79d5598abe updated README 2015-07-14 07:54:23 +09:00
John Rommel Estropia b88679c507 updated README 2015-07-14 07:50:12 +09:00
John Rommel Estropia 858dd0962d updated documentation (in progress) 2015-07-14 07:44:45 +09:00
John Estropia e7bcb501fd fixed migrationchain validation 2015-07-13 16:16:19 +09:00
John Rommel Estropia f99349f99d improved migrationchain validation 2015-07-13 07:47:43 +09:00
John Rommel Estropia a64bcc474e updated error handling for DataStack methods, updated migration demo app 2015-07-12 19:20:38 +09:00
John Rommel Estropia 8cfe8e2500 added NSProgress support for migrations 2015-07-12 00:49:53 +09:00
John Rommel Estropia 33268eeea1 fix demo app: label layout problem on iOS 9 2015-07-10 07:17:22 +09:00
John Estropia b2a190ea33 require explicit parameter for fileName when calling addSQLiteStore() and it's variants 2015-07-09 21:28:37 +09:00
John Estropia 35fbaf9513 updated for Xcode 7 beta 3 2015-07-09 21:25:19 +09:00
John Estropia 450afb00fa Merge branch 'master' into develop
Conflicts:
	CoreStore.podspec
	CoreStore/Info.plist
	CoreStore/Saving and Processing/DataStack+Transaction.swift
2015-07-09 19:01:23 +09:00
John Estropia e0048f589c version bump 2015-07-09 18:57:59 +09:00
John Estropia 929fdfd9a9 remove thread asserts when creating new transactions. fixes https://github.com/JohnEstropia/CoreStore/issues/6 2015-07-09 18:55:35 +09:00
John Estropia 7e0d3120e1 fix jump link for readme 2015-07-09 18:34:42 +09:00
John Rommel Estropia acfe5dd7a7 use GCDKit commit with iOS 7 support 2015-07-09 08:10:36 +09:00
John Rommel Estropia 9da323b0b8 assert migration chain when creating a data stack 2015-07-09 08:08:11 +09:00
John Estropia 4f3e679aa1 Merge branch 'master' into develop
Conflicts:
	CoreStoreDemo/CoreStoreDemo.xcodeproj/xcshareddata/xcschemes/CoreStoreDemo.xcscheme
2015-07-08 12:30:41 +09:00
John Estropia c1967ecdd3 fixed schemes for xcode 6.4 2015-07-08 10:41:18 +09:00
John Estropia 1a56dfd708 shared all schemes for Carthage 2015-07-08 10:28:57 +09:00
John Estropia 5f04f4c496 reversible migrations 2015-07-07 19:38:46 +09:00
John Rommel Estropia 5b85b0749e migration utilities (beta), swift 2 conversion 2015-07-07 08:03:46 +09:00
John Rommel Estropia bf0eebe057 migration utilities (beta) 2015-07-07 07:58:16 +09:00
John Rommel Estropia 261c3a6001 minor changes before Swift 2.0 2015-07-03 00:22:21 +09:00
John Rommel Estropia 91444b6dd3 Merge branch 'master' into develop 2015-07-02 22:47:36 +09:00
John Rommel Estropia 3bbae948ca gitignore 2015-07-02 22:47:19 +09:00
John Rommel Estropia e0b5da27f8 Merge branch 'master' into develop
Conflicts:
	CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata/johnestropia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
2015-07-02 00:19:26 +09:00
John Estropia d247198093 delete gitignore for old project name 2015-07-01 18:56:37 +09:00
John Estropia 589e5618ce delete unnecessary files 2015-07-01 18:54:39 +09:00
John Rommel Estropia 8402ebcc0f Carthage supportt 2015-07-01 08:13:19 +09:00
John Rommel Estropia 40f22761bf Big update. Migration tools in progress 2015-07-01 08:03:09 +09:00
John Rommel Estropia caf5c570df Merge branch 'develop'
Conflicts:
	CoreStoreDemo/CoreStoreDemo/Transactions Demo/TransactionsDemoViewController.swift
2015-06-19 04:07:27 +09:00
John Rommel Estropia 71c80c3497 marked experimental methods as private to prevent accidental usage 2015-06-19 04:05:56 +09:00
John Rommel Estropia 832dd8826e Updated Demo app with Fetching and Querying samples 2015-06-19 04:02:53 +09:00
John Rommel Estropia fcda83e6ac incomplete migration prototype methods 2015-06-15 01:31:03 +08:00
John Rommel Estropia 7303e05820 fixed demo explanation alert title 2015-06-12 23:46:09 +08:00
John Rommel Estropia a44400a935 version bump 2015-06-10 10:38:08 +09:00
John Rommel Estropia f18d29d9bc created an asynchronous method for adding sqlite store to handle asynchronous migrations. note that this commit breaks previous usage of DataStack.addSQLiteStore(...), which is now renamed to addSQLiteStoreAndWait(...) 2015-06-10 10:37:16 +09:00
John Rommel Estropia c4171de86e removed Median and StandardDeviation from supported aggregates as core data doesn't seem to support them either 2015-06-06 17:44:04 +09:00
John Rommel Estropia b0a637520e updated demo app 2015-06-05 02:21:34 +09:00
John Rommel Estropia e8f17cb33a updated read 2015-06-04 01:04:52 +09:00
John Rommel Estropia 3c29cdf2d2 updated read 2015-06-04 00:44:28 +09:00
John Rommel Estropia e462ae5a19 fixed demo app 2015-06-04 00:40:19 +09:00
John Estropia 6ed6159eec Update README.md 2015-06-03 01:52:01 +09:00
John Rommel Estropia 7710578bbc updated readme 2015-06-03 01:20:14 +09:00
John Rommel Estropia 6727c39e21 updated readme 2015-06-01 01:43:19 +09:00
John Rommel Estropia 6aa24cef2d minor changes, updated README 2015-05-31 14:42:06 +09:00
John Rommel Estropia a6f3c0bf95 pod bump 2015-05-30 17:26:31 +09:00
John Rommel Estropia 869660d41d updated README, added more utilities for updating and deleting objects from transactions 2015-05-30 17:26:06 +09:00
John Estropia 6b8d5df049 Updated README 2015-05-29 22:20:54 +09:00
John Estropia 1ca3ba5407 Update README.md 2015-05-29 09:47:56 +09:00
John Rommel Estropia 4da81250ec updating readme 2015-05-29 08:09:03 +09:00
John Rommel Estropia 994370b806 fixed segmentation fault when compiling for release builds 2015-05-28 01:36:29 +09:00
John Rommel Estropia 2145622578 set fixed dependency version 2015-05-28 00:12:29 +09:00
John Rommel Estropia b2bbf5e3b3 cocoapods 2015-05-28 00:06:31 +09:00
John Rommel Estropia 8361ba1b53 Renaming project because of cocoapods name clash with HardcoreData :( 2015-05-27 22:51:02 +09:00
John Rommel Estropia 1cc4f21336 Added setup and transactions demo 2015-05-26 01:44:49 +09:00
John Rommel Estropia cb867c07ab produce error when different store configurations with same file paths collide 2015-05-23 19:41:15 +09:00
John Rommel Estropia 8374c552f0 full inline sourcecode documentation 2015-05-22 02:26:28 +09:00
John Rommel Estropia 637829ec32 renamed some parameters 2015-05-11 00:29:59 +09:00
John Estropia f68a314999 Update README.md 2015-05-10 23:40:36 +09:00
John Rommel Estropia d481b93224 restructured files, added way to transform section names in ManagedObjectListControllers 2015-05-10 23:23:56 +09:00
John Rommel Estropia a5be0fbf67 added changed keys to object changes notification 2015-05-09 23:59:30 +09:00
John Rommel Estropia 202ec371f2 renamed commitAndWait() to overload commit() 2015-05-09 19:40:08 +09:00
John Rommel Estropia a1610534cb updated demo 2015-05-09 14:10:55 +09:00
John Rommel Estropia b16c9deeb9 small refactoring 2015-05-07 01:06:17 +09:00
John Rommel Estropia eade08d0cd added demo for observing changes to a single managed object 2015-05-07 00:30:45 +09:00
John Rommel Estropia 8d42a4a885 ManagedObjectListController demo 2015-05-06 01:06:22 +09:00
John Rommel Estropia d043d64cb1 demo app 2015-05-04 12:40:16 +09:00
John Rommel Estropia b56c08abd9 Merge branch 'master' of github.com:JohnEstropia/HardcoreData 2015-04-28 01:26:52 +09:00
John Rommel Estropia e115820635 FROM clause, list controller 2015-04-28 01:26:34 +09:00
John Estropia 7377d5adc4 Update README.md 2015-03-20 00:46:18 +09:00
John Estropia 8c989bfb48 Update README.md 2015-03-20 00:01:17 +09:00
John Estropia 95c87aa689 Create README.md 2015-03-19 23:40:42 +09:00
John Rommel Estropia cc08053259 merge in context's queue 2015-03-19 02:24:28 +09:00
John Rommel Estropia fddd42f52f don't warn about uncommitted changes when there aren't any 2015-03-19 00:21:35 +09:00
John Rommel Estropia bf41605da9 added ability to query aggregates and attributes straight from the persistent store 2015-03-18 01:25:58 +09:00
John Rommel Estropia 13ca911d77 Added ability to use non-contiguous transactions to be done on the main thread. This is useful for temporary changes such as partial input forms. 2015-03-07 22:15:39 +08:00
John Rommel Estropia e64fc3d2d8 changed concurrency architecture. Transactions are now done on a direct child context of the root saving context (instead of a main context child) 2015-03-05 21:31:38 +08:00
John Rommel Estropia 1fae78434f Added aggregate function querying and deletion querying 2015-03-05 14:24:26 +08:00
John Rommel Estropia 55dee6ec2f refactor logging functions 2015-02-28 11:32:41 +09:00
John Rommel Estropia 59cd505dc6 additional safety for transactions by splitting between sync and async subclasses 2015-02-28 10:37:01 +09:00
John Rommel Estropia 2da04d2d94 lazy -> let 2015-02-28 00:55:51 +09:00
John Rommel Estropia a45c94dd52 allow nested transactions 2015-02-28 00:55:22 +09:00
John Rommel Estropia c71198347d cleanup 2015-02-22 23:01:45 +09:00
John Rommel Estropia 8f77818015 smart way to load entityNames from the model file 2015-02-22 22:01:23 +09:00
John Rommel Estropia f6ced13577 allow fetching from HCD 2015-02-21 21:48:08 +09:00
John Rommel Estropia 061a863235 update 2015-02-21 21:14:19 +09:00
John Rommel Estropia 23f09fe5a6 update submodule 2015-02-13 01:49:01 +09:00
John Rommel Estropia f78895b812 querying 2015-02-13 01:37:59 +09:00
John Rommel Estropia 6b8bb3e434 elegant queries 2014-12-14 23:47:18 +09:00
John Rommel Estropia 45a65d9262 testing some ways to make querying as elegant as possible 2014-12-13 10:06:16 +09:00
John Rommel Estropia 8010daa161 custom error handling, logging, and asserting 2014-12-07 23:57:50 +09:00
John Rommel Estropia daa5e64ae0 here we go 2014-12-07 21:38:54 +09:00
John Rommel Estropia 25bc4a189f Initial Commit 2014-09-14 21:51:40 +09:00
828 changed files with 549897 additions and 3221 deletions
-15
View File
@@ -1,15 +0,0 @@
---
layout: page
title: About
permalink: /about/
---
This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](http://jekyllrb.com/)
You can find the source code for the Jekyll new theme at:
{% include icon-github.html username="jglovier" %} /
[jekyll-new](https://github.com/jglovier/jekyll-new)
You can find the source code for Jekyll at
{% include icon-github.html username="jekyll" %} /
[jekyll](https://github.com/jekyll/jekyll)
+2
View File
@@ -0,0 +1,2 @@
try:
project: 'CoreStore.xcworkspace'
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [JohnEstropia]
+16 -3
View File
@@ -1,3 +1,16 @@
_site CoreStoreDemo/CoreStoreDemo.xcodeproj/project.xcworkspace/xcuserdata
.sass-cache CoreStore.xcodeproj/project.xcworkspace/xcuserdata
.jekyll-metadata CoreStore.xcodeproj/xcuserdata
CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata
Carthage/Build
CoreStore.xcworkspace/xcuserdata
.DS_Store
DerivedData
*.orig
build
Playground_macOS.playground/playground.xcworkspace/xcuserdata
.swiftpm/xcode/package.xcworkspace/xcuserdata
.swiftpm/xcode/xcuserdata
Playground_iOS.playground/playground.xcworkspace/xcuserdata
LegacyDemo/LegacyDemo.xcodeproj/xcuserdata
Demo/Demo.xcodeproj/xcuserdata
View File
+15
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
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,14 @@
<?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>SchemeUserState</key>
<dict>
<key>CoreStore.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
</dict>
</plist>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

+22
View File
@@ -0,0 +1,22 @@
Pod::Spec.new do |s|
s.name = "CoreStore"
s.version = "7.3.1"
s.swift_version = "5.3"
s.license = "MIT"
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 = "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 DEBUG', 'OTHER_LDFLAGS' => '-weak_framework Combine -weak_framework SwiftUI' }
end
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:CoreStore.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,53 @@
<?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>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>F347F55F-7F5C-4476-9148-6E902F06E4AD</string>
<key>IDESourceControlProjectName</key>
<string>CoreStore</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>github.com:JohnEstropia/CoreStore.git</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>github.com:JohnEstropia/GCDKit.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>CoreStore.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>../..</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>../..Libraries/GCDKit</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:JohnEstropia/CoreStore.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlWCCName</key>
<string>CoreStore</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>8B2E522D57154DFA93A06982C36315ECBEA4FA97</string>
<key>IDESourceControlWCCName</key>
<string>GCDKit</string>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,30 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F347F55F-7F5C-4476-9148-6E902F06E4AD",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/CoreStore.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/GCDKit.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
}
]
}
@@ -0,0 +1,53 @@
<?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>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>FE56D6CC-DFA6-4581-B49D-F2486374A545</string>
<key>IDESourceControlProjectName</key>
<string>project</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>github.com:JohnEstropia/HardcoreData.git</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>github.com:JohnEstropia/GCDKit.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>HardcoreData.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
<string>../..</string>
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
<string>../..Libraries/GCDKit</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:JohnEstropia/HardcoreData.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>8B2E522D57154DFA93A06982C36315ECBEA4FA97</string>
<key>IDESourceControlWCCName</key>
<string>GCDKit</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>4B60F1BCB491FF717C56441AE7783C74F417BE48</string>
<key>IDESourceControlWCCName</key>
<string>HardcoreData</string>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD17C1BE1F8CC00949AFE"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B52DD1731BE1F8CC00949AFE"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore OSX"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A53A19C5C6DA005002A5"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
<CommandLineArgument
argument = "-com.apple.CoreData.SQLDebug 2"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2F03A52F19C5C6DA005002A5"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore iOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Release">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18911C4BBCBA00A0916E"
BuildableName = "CoreStoreTests.xctest"
BlueprintName = "CoreStoreTests tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "82BA18881C4BBCBA00A0916E"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore tvOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B563216E1BD65082006C9394"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B563216E1BD65082006C9394"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B563216E1BD65082006C9394"
BuildableName = "CoreStore.framework"
BlueprintName = "CoreStore watchOS"
ReferencedContainer = "container:CoreStore.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Demo/Demo.xcodeproj">
</FileRef>
<FileRef
location = "group:CoreStore.xcodeproj">
</FileRef>
<FileRef
location = "group:LegacyDemo/LegacyDemo.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,37 @@
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
"95438028B10BBB846574013D29F154A00556A9D1" : 0,
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "EBFDEFFE-8BA0-441A-862A-1DE28AA5CD21",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStore\/Carthage\/Checkouts\/GCDKit\/",
"95438028B10BBB846574013D29F154A00556A9D1" : "CoreStore\/Carthage\/Checkouts\/Nimble\/",
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStore",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStore.xcworkspace",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/CoreStore",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JohnEstropia\/GCDKit.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Quick\/Nimble.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "95438028B10BBB846574013D29F154A00556A9D1"
}
]
}
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
+233
View File
@@ -0,0 +1,233 @@
//
// BaseTestCase.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: - BaseTestCase
class BaseTestCase: XCTestCase {
// MARK: Internal
@nonobjc
func prepareStack(configurations: [ModelConfiguration] = [nil], _ closure: (_ dataStack: DataStack) throws -> Void) {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
do {
try configurations.forEach {
try stack.addStorageAndWait(
SQLiteStore(
fileURL: SQLiteStore.defaultRootDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathComponent("\(Self.self)_\(($0 ?? "-null-")).sqlite"),
configuration: $0,
localStorageOptions: .recreateStoreOnModelMismatch
)
)
}
try closure(stack)
}
catch let error as NSError {
XCTFail(error.coreStoreDumpString)
}
self.addTeardownBlock {
stack.unsafeRemoveAllPersistentStoresAndWait()
}
}
@nonobjc
func expectLogger<T>(_ expectations: [TestLogger.Expectation], closure: () throws -> T) rethrows -> T {
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations(expectations))
defer {
self.checkExpectationsImmediately()
CoreStoreDefaults.logger = TestLogger([:])
}
return try closure()
}
@nonobjc
func expectLogger(_ expectations: [TestLogger.Expectation: XCTestExpectation]) {
CoreStoreDefaults.logger = TestLogger(expectations)
}
@nonobjc
func expectError<T>(code: CoreStoreErrorCode, closure: () throws -> T) {
CoreStoreDefaults.logger = TestLogger(self.prepareLoggerExpectations([.logError]))
defer {
self.checkExpectationsImmediately()
CoreStoreDefaults.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 \(Internals.typeName(CoreStoreError.self)): \((error as NSError).coreStoreDumpString)")
}
}
@nonobjc
func prepareLoggerExpectations(_ expectations: [TestLogger.Expectation]) -> [TestLogger.Expectation: XCTestExpectation] {
var testExpectations: [TestLogger.Expectation: XCTestExpectation] = [:]
for expectation in expectations {
testExpectations[expectation] = self.expectation(description: "Logger Expectation: \(expectation)")
}
return testExpectations
}
@nonobjc
func checkExpectationsImmediately() {
self.waitForExpectations(timeout: 0, handler: { _ in })
}
@nonobjc
func waitAndCheckExpectations() {
self.waitForExpectations(timeout: 10, handler: {_ in })
}
// MARK: XCTestCase
override func setUp() {
super.setUp()
self.deleteStores()
CoreStoreDefaults.logger = TestLogger([:])
}
override func tearDown() {
CoreStoreDefaults.logger = DefaultLogger()
self.deleteStores()
super.tearDown()
}
// MARK: Private
private func deleteStores() {
_ = try? FileManager.default.removeItem(at: SQLiteStore.defaultRootDirectory)
}
}
// MARK: - TestLogger
class TestLogger: CoreStoreLogger {
enum Expectation {
case logWarning
case logFatal
case logError
case assertionFailure
case fatalError
}
init(_ expectations: [Expectation: XCTestExpectation]) {
self.expectations = expectations
}
// MARK: CoreStoreLogger
var enableObjectConcurrencyDebugging: Bool = true
func log(level: LogLevel, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
switch level {
case .warning: self.fulfill(.logWarning)
case .fatal: self.fulfill(.logFatal)
default: break
}
}
func log(error: CoreStoreError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.logError)
}
func assert(_ condition: @autoclosure () -> Bool, message: @autoclosure () -> String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
if condition() {
return
}
self.fulfill(.assertionFailure)
}
func abort(_ message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) {
self.fulfill(.fatalError)
}
// MARK: Private
private var expectations: [Expectation: XCTestExpectation]
private func fulfill(_ expectation: Expectation) {
if let instance = self.expectations[expectation] {
instance.fulfill()
self.expectations[expectation] = nil
}
else {
XCTFail("Unexpected Logger Action: \(expectation)")
}
}
}
+94
View File
@@ -0,0 +1,94 @@
//
// BaseTestDataTestCase.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
@testable
import CoreStore
// MARK: - BaseTestDataTestCase
class BaseTestDataTestCase: BaseTestCase {
@nonobjc
let dateFormatter: DateFormatter = Internals.with {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.calendar = Calendar(identifier: Calendar.Identifier.gregorian)
formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
return formatter
}
@nonobjc
func prepareTestDataForStack(_ stack: DataStack, configurations: [ModelConfiguration] = [nil]) {
try! stack.perform(
synchronous: { (transaction) in
for (configurationIndex, configuration) in configurations.enumerated() {
let configurationOrdinal = configurationIndex + 1
if configuration == nil || configuration == "Config1" {
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 {
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)
}
}
}
}
)
}
}
+30
View File
@@ -0,0 +1,30 @@
//
// BridgingTests.h
// 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/XCTest.h>
@interface BridgingTests : XCTestCase
@end
+269
View File
@@ -0,0 +1,269 @@
//
// BridgingTests.m
// 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 "BridgingTests.h"
#import <CoreStore/CoreStore.h>
#import <CoreStore/CoreStore-Swift.h>
#import "CoreStoreTests-Swift.h"
@import CoreData;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// MARK: - BridgingTests
@implementation BridgingTests
- (void)test_ThatFlags_HaveCorrectValues {
XCTAssertEqual(CSLocalStorageOptionsNone, 0);
XCTAssertEqual(CSLocalStorageOptionsRecreateStoreOnModelMismatch, 1);
XCTAssertEqual(CSLocalStorageOptionsPreventProgressiveMigration, 2);
XCTAssertEqual(CSLocalStorageOptionsAllowSynchronousLightweightMigration, 4);
}
- (void)test_ThatKeyPaths_AreCorrect {
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testNumber), @"testNumber");
XCTAssertEqualObjects(CSKeyPath(TestEntity1, testString), @"testString");
XCTAssertEqualObjects(CSKeyPathOperator(count, TestEntity1, testString), @"@count.testString");
XCTAssertEqualObjects(CSKeyPathOperator(max, TestEntity1, testNumber), @"@max.testNumber");
}
- (void)test_ThatFromClauses_BridgeCorrectly {
{
CSFrom *from = CSFromClass([TestEntity1 class]);
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
XCTAssertNil(from.configurations);
}
{
CSFrom *from = CSFromClass([TestEntity1 class], [NSNull null]);
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
NSArray *configurations = @[[NSNull null]];
XCTAssertEqualObjects(from.configurations, configurations);
}
{
CSFrom *from = CSFromClass([TestEntity1 class], @"Config1");
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
NSArray *configurations = @[@"Config1"];
XCTAssertEqualObjects(from.configurations, configurations);
}
{
CSFrom *from = CSFromClass([TestEntity1 class], @[[NSNull null], @"Config2"]);
XCTAssertEqualObjects(from.entityClass, [TestEntity1 class]);
NSArray *configurations = @[[NSNull null], @"Config2"];
XCTAssertEqualObjects(from.configurations, configurations);
}
}
- (void)test_ThatWhereClauses_BridgeCorrectly {
{
CSWhere *where = CSWhereFormat(@"%K == %@", @"key", @"value");
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
XCTAssertEqualObjects(where.predicate, predicate);
}
{
CSWhere *where = CSWhereValue(YES);
NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
XCTAssertEqualObjects(where.predicate, predicate);
}
{
CSWhere *where = CSWherePredicate([NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"]);
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"key", @"value"];
XCTAssertEqualObjects(where.predicate, predicate);
}
}
- (void)test_ThatOrderByClauses_BridgeCorrectly {
{
CSOrderBy *orderBy = CSOrderByKey(CSSortAscending(@"key"));
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:YES]]);
}
{
CSOrderBy *orderBy = CSOrderByKey(CSSortDescending(@"key"));
XCTAssertEqualObjects(orderBy.sortDescriptors, @[[NSSortDescriptor sortDescriptorWithKey:@"key" ascending:NO]]);
}
{
CSOrderBy *orderBy = CSOrderByKeys(CSSortAscending(@"key1"), CSSortDescending(@"key2"), nil);
NSArray *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"key1" ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:@"key2" ascending:NO]];
XCTAssertEqualObjects(orderBy.sortDescriptors, sortDescriptors);
}
}
- (void)test_ThatGroupByClauses_BridgeCorrectly {
{
CSGroupBy *groupBy = CSGroupByKeyPath(@"key");
XCTAssertEqualObjects(groupBy.keyPaths, @[@"key"]);
}
{
CSGroupBy *groupBy = CSGroupByKeyPaths(@[@"key1", @"key2"]);
NSArray *keyPaths = @[@"key1", @"key2"];
XCTAssertEqualObjects(groupBy.keyPaths, keyPaths);
}
}
- (void)test_ThatTweakClauses_BridgeCorrectly {
CSTweak *tweak = CSTweakRequest(^(NSFetchRequest * _Nonnull fetchRequest) {
fetchRequest.fetchLimit = 100;
});
NSFetchRequest *request = [NSFetchRequest new];
tweak.block(request);
XCTAssertEqual(request.fetchLimit, 100);
}
- (void)test_ThatIntoClauses_BridgeCorrectly {
{
CSInto *into = CSIntoClass([TestEntity1 class]);
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
}
{
CSInto *into = CSIntoClass([TestEntity1 class], [NSNull null]);
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
XCTAssertNil(into.configuration);
}
{
CSInto *into = CSIntoClass([TestEntity1 class], @"Config1");
XCTAssertEqualObjects(into.entityClass, [TestEntity1 class]);
XCTAssertEqualObjects(into.configuration, @"Config1");
}
}
- (void)test_ThatDataStacks_BridgeCorrectly {
CSDataStack *dataStack = [[CSDataStack alloc]
initWithXcodeModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil];
XCTAssertNotNil(dataStack);
NSError *memoryError;
CSInMemoryStore *memoryStorage = [dataStack
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:&memoryError];
XCTAssertNotNil(memoryStorage);
XCTAssertEqualObjects([[memoryStorage class] storeType], [CSInMemoryStore storeType]);
XCTAssertEqualObjects([[memoryStorage class] storeType], NSInMemoryStoreType);
XCTAssertNil(memoryStorage.configuration);
XCTAssertNil(memoryStorage.storeOptions);
XCTAssertNil(memoryError);
NSError *sqliteError;
CSSQLiteStore *sqliteStorage = [dataStack
addSQLiteStorageAndWait:[CSSQLiteStore new]
error:&sqliteError];
XCTAssertNotNil(sqliteStorage);
XCTAssertEqualObjects([[sqliteStorage class] storeType], [CSSQLiteStore storeType]);
XCTAssertEqualObjects([[sqliteStorage class] storeType], NSSQLiteStoreType);
XCTAssertNil(sqliteStorage.configuration);
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);
}
- (void)test_ThatTransactions_BridgeCorrectly {
CSDataStack *dataStack = [[CSDataStack alloc]
initWithXcodeModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil];
XCTAssertNotNil(dataStack);
[dataStack
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:nil];
{
CSUnsafeDataTransaction *transaction = [dataStack beginUnsafe];
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
NSError *error;
BOOL result = [transaction commitAndWaitWithError:&error];
XCTAssertTrue(result);
XCTAssertNil(error);
}
{
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
NSError *error;
BOOL result =
[dataStack
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"];
[dataStack beginAsynchronous:^(CSAsynchronousDataTransaction * _Nonnull transaction) {
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
[transaction
commitWithSuccess:^{
[expectation fulfill];
}
failure:^(CSError *error){
XCTFail();
}];
}];
}
[self waitForExpectationsWithTimeout:10 handler:nil];
}
@end
#pragma clang diagnostic pop
+91
View File
@@ -0,0 +1,91 @@
//
// ConvenienceTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
@testable
import CoreStore
// MARK: - ConvenienceTests
@available(macOS 10.12, *)
class ConvenienceTests: BaseTestCase {
@objc
dynamic func test_ThatDataStacks_CanCreateFetchedResultsControllers() {
self.prepareStack { (stack) in
let controller = stack.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, stack.mainContext)
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
@objc
dynamic func test_ThatUnsafeDataTransactions_CanCreateFetchedResultsControllers() {
self.prepareStack { (stack) in
withExtendedLifetime(stack.beginUnsafe()) { (transaction: UnsafeDataTransaction) in
let controller = transaction.createFetchedResultsController(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testString)),
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))),
Tweak { $0.fetchLimit = 10 }
)
XCTAssertEqual(controller.managedObjectContext, transaction.context)
XCTAssertEqual(controller.fetchRequest.entity?.managedObjectClassName, NSStringFromClass(TestEntity1.self))
XCTAssertEqual(controller.sectionNameKeyPath, #keyPath(TestEntity1.testString))
XCTAssertEqual(
controller.fetchRequest.sortDescriptors!,
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testString))).sortDescriptors
)
XCTAssertEqual(
controller.fetchRequest.predicate,
Where<TestEntity1>("%@ > %d", #keyPath(TestEntity1.testEntityID), 100).predicate
)
XCTAssertEqual(controller.fetchRequest.fetchLimit, 10)
}
}
}
}
@@ -0,0 +1,5 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "BridgingTests.h"
+535
View File
@@ -0,0 +1,535 @@
//
// 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 {
@Field.Stored("species")
var species: String = "Swift"
@Field.Coded("color", coder: FieldCoders.NSCoding.self)
var color: Color? = .blue
@Field.Relationship("master")
var master: Person?
}
class Dog: Animal {
static let commonNicknames = ["Spot", "Benjie", "Max", "Milo"]
@Field.Stored(
"nickname",
dynamicInitialValue: {
commonNicknames.randomElement()!
}
)
var nickname: String
@Field.Stored("age")
var age: Int = 1
@Field.Relationship("friends")
var friends: [Dog]
@Field.Relationship("friendedBy", inverse: \.$friends)
var friendedBy: Set<Dog>
}
struct CustomType {
var string = "customString"
}
enum Job: String, CaseIterable {
case unemployed
case engineer
case doctor
case lawyer
init?(data: Data) {
guard
let rawValue = String(data: data, encoding: .utf8),
let value = Self.init(rawValue: rawValue)
else {
return nil
}
self = value
}
func toData() -> Data {
return Data(self.rawValue.utf8)
}
}
class Person: CoreStoreObject {
@Field.Stored(
"title",
customSetter: { (object, field, newValue) in
field.primitiveValue = newValue
object.$displayName.primitiveValue = nil
}
)
var title: String = "Mr."
@Field.Stored(
"name",
customSetter: { (object, field, newValue) in
field.primitiveValue = newValue
object.$displayName.primitiveValue = nil
}
)
var name: String = ""
@Field.Virtual(
"displayName",
customGetter: Person.getDisplayName(_:_:),
affectedByKeyPaths: Person.keyPathsAffectingDisplayName()
)
var displayName: String?
@Field.Virtual(
"customType",
customGetter: { (object, field) in
if let value = field.primitiveValue {
return value
}
let value = CustomType()
field.primitiveValue = value
return value
}
)
var customField: CustomType
@Field.Coded(
"job",
coder: (
encode: { $0.toData() },
decode: { $0.flatMap(Job.init(data:)) ?? .unemployed }
),
dynamicInitialValue: {
Job.allCases.randomElement()!
}
)
var job: Job
@Field.Relationship("spouse")
var spouse: Person?
@Field.Relationship("pets", inverse: \.$master)
var pets: Set<Animal>
@Field.Relationship("_spouseInverse", inverse: \.$spouse)
private var spouseInverse: Person?
private static func getDisplayName(_ object: ObjectProxy<Person>, _ field: ObjectProxy<Person>.FieldProxy<String?>) -> String? {
if let value = field.primitiveValue {
return value
}
let title = object.$title.value
let name = object.$name.value
let value = "\(title) \(name)"
field.primitiveValue = value
return value
}
private 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": [0xad6de93adc5565d, 0x7897e51253eba5a3, 0xd12b9ce0b13600f3, 0x5a4827cd794cd15e],
"Person": [0xf3e6ba6016bbedc6, 0x50dedf64f0eba490, 0xa32088a0ee83468d, 0xb72d1d0b37bd0992]
]
)
)
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, "Swift")
XCTAssertTrue(type(of: animal.species) == String.self)
XCTAssertEqual(animal.color, Color.blue)
animal.species = "Sparrow"
XCTAssertEqual(animal.species, "Sparrow")
animal.color = .yellow
XCTAssertEqual(animal.color, Color.yellow)
for property in Animal.metaProperties(includeSuperclasses: true) {
switch property.keyPath {
case String(keyPath: \Animal.$species):
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
case String(keyPath: \Animal.$master):
XCTAssertTrue(property is FieldContainer<Animal>.Relationship<Person?>)
case String(keyPath: \Animal.$color):
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
default:
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
}
}
let dog = transaction.create(Into<Dog>())
XCTAssertEqual(dog.species, "Swift")
XCTAssertEqual(dog.age, 1)
XCTAssertTrue(Dog.commonNicknames.contains(dog.nickname))
for property in Dog.metaProperties(includeSuperclasses: true) {
switch property.keyPath {
case String(keyPath: \Dog.$species):
XCTAssertTrue(property is FieldContainer<Animal>.Stored<String>)
case String(keyPath: \Dog.$master):
XCTAssertTrue(property is FieldContainer<Animal>.Relationship<Person?>)
case String(keyPath: \Dog.$color):
XCTAssertTrue(property is FieldContainer<Animal>.Coded<Color?>)
case String(keyPath: \Dog.$nickname):
XCTAssertTrue(property is FieldContainer<Dog>.Stored<String>)
case String(keyPath: \Dog.$age):
XCTAssertTrue(property is FieldContainer<Dog>.Stored<Int>)
case String(keyPath: \Dog.$friends):
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<[Dog]>)
case String(keyPath: \Dog.$friendedBy):
XCTAssertTrue(property is FieldContainer<Dog>.Relationship<Set<Dog>>)
default:
XCTFail("Unknown KeyPath: \"\(property.keyPath)\"")
}
}
let didSetObserver = dog.observe(\.$species, 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, "Dog")
didSetObserverDone.fulfill()
}
let willSetObserver = dog.observe(\.$species, 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, "Swift")
willSetPriorObserverDone.fulfill()
}
else {
XCTAssertEqual(change.newValue, "Dog")
XCTAssertEqual(object.species, "Dog")
willSetNotPriorObserverDone.fulfill()
}
}
dog.species = "Dog"
XCTAssertEqual(dog.species, "Dog")
didSetObserver.invalidate()
willSetObserver.invalidate()
dog.nickname = "Spot"
XCTAssertEqual(dog.nickname, "Spot")
let person = transaction.create(Into<Person>())
XCTAssertTrue(person.pets.isEmpty)
XCTAssertEqual(person.customField.string, "customString")
let initialJob = person.job
XCTAssertTrue(Job.allCases.contains(initialJob))
XCTAssertEqual(
person.rawObject!
.runtimeType()
.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, "John")
XCTAssertEqual(person.displayName, "Mr. John") // Custom getter
let personSnapshot1 = person.asSnapshot(in: transaction)!
XCTAssertEqual(person.name, personSnapshot1.$name)
XCTAssertEqual(person.title, personSnapshot1.$title)
XCTAssertEqual(person.displayName, personSnapshot1.$displayName)
XCTAssertEqual(person.job, personSnapshot1.$job)
person.title = "Sir"
XCTAssertEqual(person.displayName, "Sir John")
XCTAssertEqual(personSnapshot1.$name, "John")
XCTAssertEqual(personSnapshot1.$title, "Mr.")
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
person.customField.string = "newCustomString"
XCTAssertEqual(person.customField.string, "newCustomString")
person.job = .engineer
XCTAssertEqual(person.job, .engineer)
let personSnapshot2 = person.asSnapshot(in: transaction)!
XCTAssertEqual(person.name, personSnapshot2.$name)
XCTAssertEqual(person.title, personSnapshot2.$title)
XCTAssertEqual(person.displayName, personSnapshot2.$displayName)
XCTAssertEqual(person.job, personSnapshot2.$job)
var personSnapshot3 = personSnapshot2
personSnapshot3.$name = "James"
XCTAssertEqual(personSnapshot1.$name, "John")
XCTAssertEqual(personSnapshot1.$displayName, "Mr. John")
XCTAssertEqual(personSnapshot1.$job, initialJob)
XCTAssertEqual(personSnapshot2.$name, "John")
XCTAssertEqual(personSnapshot2.$displayName, "Sir John")
XCTAssertEqual(personSnapshot2.$job, .engineer)
XCTAssertEqual(personSnapshot3.$name, "James")
XCTAssertEqual(personSnapshot3.$displayName, "Sir John")
XCTAssertEqual(personSnapshot3.$job, .engineer)
person.pets.insert(dog)
XCTAssertEqual(person.pets.count, 1)
XCTAssertEqual(person.pets.first, dog)
XCTAssertEqual(person.pets.first?.master, person)
XCTAssertEqual(dog.master, person)
XCTAssertEqual(dog.master?.pets.first, dog)
},
success: { _ in
let person = try! stack.fetchOne(From<Person>())
XCTAssertNotNil(person)
let personPublisher = person!.asPublisher(in: stack)
XCTAssertEqual(personPublisher.$name, "John")
XCTAssertEqual(personPublisher.$displayName, "Sir John")
XCTAssertEqual(personPublisher.$job, .engineer)
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, "Sparrow")
XCTAssertEqual(bird!.color, Color.yellow)
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, "Spot")
XCTAssertEqual(dog!.species, "Dog")
let person = try transaction.fetchOne(From<Person>())
XCTAssertNotNil(person)
XCTAssertEqual(person!.name, "John")
XCTAssertEqual(person!.title, "Sir")
XCTAssertEqual(person!.displayName, "Sir John")
XCTAssertEqual(person!.customField.string, "customString")
XCTAssertEqual(person!.job, .engineer)
XCTAssertEqual(person!.pets.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(\.$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.waitForExpectations(timeout: 10, handler: { _ in })
self.addTeardownBlock {
dataStack.unsafeRemoveAllPersistentStoresAndWait()
}
}
@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("\(Self.self)_\((configuration ?? "-null-")).sqlite"),
configuration: configuration,
localStorageOptions: .recreateStoreOnModelMismatch
)
)
}
}
catch let error as NSError {
XCTFail(error.coreStoreDumpString)
}
closure(dataStack)
}
}
+175
View File
@@ -0,0 +1,175 @@
//
// ErrorTests.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: - ErrorTests
@available(*, deprecated, message: "CoreStore Objective-C API will be removed soon.")
final class ErrorTests: XCTestCase {
@objc
dynamic func test_ThatUnknownErrors_BridgeCorrectly() {
let error = CoreStoreError.unknown
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.unknownError.rawValue)
let userInfo: NSDictionary = [:]
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.unknownError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
dynamic func test_ThatDifferentStorageExistsAtURLErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let error = CoreStoreError.differentStorageExistsAtURL(existingPersistentStoreURL: dummyURL)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
let userInfo: NSDictionary = [
"existingPersistentStoreURL": dummyURL
]
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.differentStorageExistsAtURL.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
dynamic func test_ThatMappingModelNotFoundErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let schemaHistory = SchemaHistory(
XcodeDataModelSchema.from(
modelName: "Model",
bundle: Bundle(for: Self.self)
)
)
let version = "1.0.0"
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": schemaHistory.rawModel,
"targetModelVersion": version
]
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.mappingModelNotFound.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
dynamic func test_ThatProgressiveMigrationRequiredErrors_BridgeCorrectly() {
let dummyURL = URL(string: "file:///test1/test2.sqlite")!
let error = CoreStoreError.progressiveMigrationRequired(localStoreURL: dummyURL)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
let userInfo: NSDictionary = [
"localStoreURL": dummyURL
]
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.progressiveMigrationRequired.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
@objc
dynamic func test_ThatInternalErrorErrors_BridgeCorrectly() {
let internalError = NSError(
domain: "com.dummy",
code: 123,
userInfo: [
"key1": "value1",
"key2": 2,
"key3": Date()
]
)
let error = CoreStoreError(internalError)
XCTAssertEqual((error as NSError).domain, CoreStoreErrorDomain)
XCTAssertEqual((error as NSError).code, CoreStoreErrorCode.internalError.rawValue)
let userInfo: NSDictionary = [
"NSError": internalError
]
let objcError = error.bridgeToObjectiveC
XCTAssertEqual(error, objcError.bridgeToSwift)
XCTAssertEqual(objcError.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError.userInfo as NSDictionary, userInfo)
let objcError2 = objcError.bridgeToSwift.bridgeToObjectiveC
XCTAssertEqual(error, objcError2.bridgeToSwift)
XCTAssertEqual(objcError2.domain, CoreStoreErrorDomain)
XCTAssertEqual(objcError2.code, CoreStoreErrorCode.internalError.rawValue)
XCTAssertEqual(objcError2.userInfo as NSDictionary, userInfo)
}
}
File diff suppressed because it is too large Load Diff
+418
View File
@@ -0,0 +1,418 @@
//
// FromTests.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: - FromTests
final class FromTests: BaseTestCase {
@objc
dynamic func test_ThatFromClauses_ConfigureCorrectly() {
do {
let from = From<NSManagedObject>()
XCTAssert(from.entityClass === NSManagedObject.self)
XCTAssertNil(from.configurations)
}
do {
let from = From<TestEntity1>()
XCTAssert(from.entityClass === TestEntity1.self)
XCTAssertNil(from.configurations)
}
do {
let from = From<TestEntity1>("Config1")
XCTAssert(from.entityClass === TestEntity1.self)
XCTAssertEqual(from.configurations?.count, 1)
XCTAssertEqual(from.configurations?[0], "Config1")
}
do {
let from = From<TestEntity1>(nil, "Config1")
XCTAssert(from.entityClass === TestEntity1.self)
XCTAssertEqual(from.configurations?.count, 2)
XCTAssertEqual(from.configurations?[0], nil)
XCTAssertEqual(from.configurations?[1], "Config1")
}
}
@objc
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForDefaultConfigurations() {
self.prepareStack { (dataStack) in
do {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
try from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity1>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
}
@objc
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForSingleConfigurations() {
self.prepareStack(configurations: ["Config1"]) { (dataStack) in
do {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
}
@objc
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForDefaultAndCustomConfigurations() {
self.prepareStack(configurations: [nil, "Config1"]) { (dataStack) in
do {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
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 = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["PF_DEFAULT_CONFIGURATION_NAME"])
}
do {
let from = From<TestEntity2>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
}
}
@objc
dynamic func test_ThatFromClauses_ApplyToFetchRequestsCorrectlyForMultipleConfigurations() {
self.prepareStack(configurations: ["Config1", "Config2"]) { (dataStack) in
do {
let from = From<TestEntity1>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config1"])
}
do {
let from = From<TestEntity1>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>()
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
do {
let from = From<TestEntity2>("Config1")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
self.expectError(code: .persistentStoreNotFound) {
try from.applyToFetchRequest(request, context: dataStack.mainContext)
}
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertTrue(affectedConfigurations.isEmpty)
}
do {
let from = From<TestEntity2>("Config2")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
let storesFound: Void? = try? from.applyToFetchRequest(request, context: dataStack.mainContext)
XCTAssertNotNil(storesFound)
XCTAssertNotNil(request.entity)
XCTAssertNotNil(request.safeAffectedStores())
XCTAssert(from.entityClass == NSClassFromString(request.entity!.managedObjectClassName))
let affectedConfigurations = request.safeAffectedStores()?.map { $0.configurationName } ?? []
XCTAssertEqual(affectedConfigurations, ["Config2"])
}
}
}
}
+81
View File
@@ -0,0 +1,81 @@
//
// GroupByTests.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: - GroupByTests
final class GroupByTests: BaseTestCase {
@objc
dynamic func test_ThatGroupByClauses_ConfigureCorrectly() {
do {
let groupBy = GroupBy<NSManagedObject>()
XCTAssertEqual(groupBy, GroupBy([] as [String]))
XCTAssertNotEqual(groupBy, GroupBy("key"))
XCTAssertTrue(groupBy.keyPaths.isEmpty)
}
do {
let groupBy = GroupBy<NSManagedObject>("key1")
XCTAssertEqual(groupBy, GroupBy("key1"))
XCTAssertEqual(groupBy, GroupBy(["key1"]))
XCTAssertNotEqual(groupBy, GroupBy("key2"))
XCTAssertEqual(groupBy.keyPaths, ["key1"])
}
do {
let groupBy = GroupBy<NSManagedObject>("key1", "key2")
XCTAssertEqual(groupBy, GroupBy("key1", "key2"))
XCTAssertEqual(groupBy, GroupBy(["key1", "key2"]))
XCTAssertNotEqual(groupBy, GroupBy("key2", "key1"))
XCTAssertEqual(groupBy.keyPaths, ["key1", "key2"])
}
}
@objc
dynamic func test_ThatGroupByClauses_ApplyToFetchRequestsCorrectly() {
self.prepareStack { (dataStack) in
let groupBy = GroupBy<NSManagedObject>(#keyPath(TestEntity1.testString))
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
try From<TestEntity1>().applyToFetchRequest(request, context: dataStack.mainContext)
groupBy.applyToFetchRequest(request)
XCTAssertNotNil(request.propertiesToGroupBy)
let attributes = (request.propertiesToGroupBy ?? []) as! [NSAttributeDescription]
XCTAssertEqual(attributes.map { $0.name }, groupBy.keyPaths)
}
}
}
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
<?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>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>6.2.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
+139
View File
@@ -0,0 +1,139 @@
//
// IntoTests.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: - IntoTests
final class IntoTests: XCTestCase {
@objc
dynamic func test_ThatIntoClauseConstants_AreCorrect() {
XCTAssertEqual(DataStack.defaultConfigurationName, "PF_DEFAULT_CONFIGURATION_NAME")
}
@objc
dynamic func test_ThatIntoClauses_ConfigureCorrectly() {
do {
let into = Into<NSManagedObject>()
XCTAssert(into.entityClass === NSManagedObject.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
}
do {
let into = Into<TestEntity1>()
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
}
do {
let into = Into(TestEntity1.self)
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertNil(into.configuration)
XCTAssertTrue(into.inferStoreIfPossible)
}
do {
let into = Into<TestEntity1>("Config1")
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertEqual(into.configuration, "Config1")
XCTAssertFalse(into.inferStoreIfPossible)
}
do {
let into = Into(TestEntity1.self, "Config1")
XCTAssert(into.entityClass === TestEntity1.self)
XCTAssertEqual(into.configuration, "Config1")
XCTAssertFalse(into.inferStoreIfPossible)
}
}
@objc
dynamic func test_ThatIntoClauses_AreEquatable() {
do {
let into = Into<NSManagedObject>()
XCTAssertEqual(into, Into<NSManagedObject>())
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))
XCTAssertNotEqual(into, Into<TestEntity1>("Config1"))
}
do {
let into = Into(TestEntity1.self)
XCTAssert(into == Into<TestEntity1>())
XCTAssertEqual(into, Into(TestEntity1.self))
XCTAssertFalse(into == Into<TestEntity1>("Config1"))
}
do {
let into = Into<TestEntity1>("Config1")
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
}
do {
let into = Into(TestEntity1.self, "Config1")
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
}
do {
let into = Into(TestEntity1.self, "Config1")
XCTAssertEqual(into, Into<TestEntity1>("Config1"))
XCTAssertEqual(into, Into(TestEntity1.self, "Config1"))
XCTAssertNotEqual(into, Into<TestEntity1>("Config2"))
}
}
@objc
dynamic func test_ThatIntoClauses_BridgeCorrectly() {
do {
let into = Into<NSManagedObject>()
let objcInto = into.bridgeToObjectiveC
XCTAssertEqual(into, objcInto.bridgeToSwift)
}
}
}
+676
View File
@@ -0,0 +1,676 @@
//
// ListObserverTests.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: - ListObserverTests
@available(macOS 10.12, *)
class ListObserverTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatListObservers_CanReceiveInsertNotifications() {
self.prepareStack { (stack) in
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
XCTAssertFalse(monitor.hasSections())
XCTAssertFalse(monitor.hasObjects())
XCTAssertTrue(monitor.objectsInAllSections().isEmpty)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 0
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
[
"sectionInfo": monitor.sectionInfo(at: 0),
"sectionIndex": 0
] as NSDictionary
)
defer {
events += 1
}
return events == 1
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(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?.index(atPosition: 0), 0)
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 1))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "1"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:1")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!)
defer {
events += 1
}
return events == 2
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 3
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool 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")!
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
}
)
self.waitAndCheckExpectations()
}
}
@objc
dynamic func test_ThatListObservers_CanReceiveUpdateNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
XCTAssertTrue(monitor.hasSections())
XCTAssertEqual(monitor.numberOfSections(), 2)
XCTAssertTrue(monitor.hasObjects())
XCTAssertTrue(monitor.hasObjects(in: 0))
XCTAssertEqual(monitor.numberOfObjects(in: 0), 2)
XCTAssertEqual(monitor.numberOfObjects(in: 1), 3)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 0
}
)
_ = 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 {
case NSNumber(value: 101)?:
XCTAssertEqual(indexPath?.index(atPosition: 0), 1)
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
XCTAssertEqual(object?.testNumber, NSNumber(value: 11))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "11"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:11")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!)
case NSNumber(value: 102)?:
XCTAssertEqual(indexPath?.index(atPosition: 0), 0)
XCTAssertEqual(indexPath?.index(atPosition: 1), 0)
XCTAssertEqual(object?.testBoolean, NSNumber(value: false))
XCTAssertEqual(object?.testNumber, NSNumber(value: 22))
XCTAssertEqual(object?.testDecimal, NSDecimalNumber(string: "22"))
XCTAssertEqual(object?.testString, "nil:TestEntity1:22")
XCTAssertEqual(object?.testData, ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!)
XCTAssertEqual(object?.testDate, self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!)
default:
XCTFail()
}
defer {
events += 1
}
return events == 1 || events == 2
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 3)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 3
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
if let object = try transaction.fetchOne(
From<TestEntity1>(),
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
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 = 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()
}
}
@objc
dynamic func test_ThatListObservers_CanReceiveMoveNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 0
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["fromIndexPath", "toIndexPath", "object"]
)
let fromIndexPath = userInfo?["fromIndexPath"] as? NSIndexPath
XCTAssertEqual(fromIndexPath?.index(atPosition: 0), 0)
XCTAssertEqual(fromIndexPath?.index(atPosition: 1), 0)
let toIndexPath = userInfo?["toIndexPath"] as? NSIndexPath
XCTAssertEqual(toIndexPath?.index(atPosition: 0), 1)
XCTAssertEqual(toIndexPath?.index(atPosition: 1), 1)
let object = userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testEntityID, NSNumber(value: 102))
XCTAssertEqual(object?.testBoolean, NSNumber(value: true))
defer {
events += 1
}
return events == 1
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 2)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 2
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
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()
}
)
self.waitAndCheckExpectations()
}
}
@objc
dynamic func test_ThatListObservers_CanReceiveDeleteNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = TestListObserver()
let monitor = stack.monitorSectionedList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
monitor.addObserver(observer)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorWillChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 0
}
)
_ = 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 {
events += 1
}
return events == 1 || events == 2
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 3)
let userInfo = note.userInfo
XCTAssertNotNil(userInfo)
XCTAssertEqual(
Set(userInfo?.keys.map({ $0 as! String }) ?? []),
["sectionInfo", "sectionIndex"]
)
let sectionInfo = userInfo?["sectionInfo"] as? NSFetchedResultsSectionInfo
XCTAssertNotNil(sectionInfo)
XCTAssertEqual(sectionInfo?.name, "0")
let sectionIndex = userInfo?["sectionIndex"]
XCTAssertEqual(sectionIndex as? NSNumber, NSNumber(value: 0))
defer {
events += 1
}
return events == 3
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "listMonitorDidChange:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 4)
XCTAssertEqual((note.userInfo as NSDictionary?) ?? [:], NSDictionary())
defer {
events += 1
}
return events == 4
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
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()
}
}
}
// MARK: TestListObserver
@available(macOS 10.12, *)
class TestListObserver: ListSectionObserver {
// MARK: ListObserver
typealias ListEntityType = TestEntity1
func listMonitorWillChange(_ monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillChange:"),
object: self,
userInfo: [:]
)
}
func listMonitorDidChange(_ monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidChange:"),
object: self,
userInfo: [:]
)
}
func listMonitorWillRefetch(_ monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorWillRefetch:"),
object: self,
userInfo: [:]
)
}
func listMonitorDidRefetch(_ monitor: ListMonitor<TestEntity1>) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitorDidRefetch:"),
object: self,
userInfo: [:]
)
}
// MARK: ListObjectObserver
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertObject object: TestEntity1, toIndexPath indexPath: IndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertObject:toIndexPath:"),
object: self,
userInfo: [
"object": object,
"indexPath": indexPath
]
)
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteObject object: TestEntity1, fromIndexPath indexPath: IndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteObject:fromIndexPath:"),
object: self,
userInfo: [
"object": object,
"indexPath": indexPath
]
)
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didUpdateObject object: TestEntity1, atIndexPath indexPath: IndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didUpdateObject:atIndexPath:"),
object: self,
userInfo: [
"object": object,
"indexPath": indexPath
]
)
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didMoveObject object: TestEntity1, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didMoveObject:fromIndexPath:toIndexPath:"),
object: self,
userInfo: [
"object": object,
"fromIndexPath": fromIndexPath,
"toIndexPath": toIndexPath
]
)
}
// MARK: ListSectionObserver
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didInsertSection:toSectionIndex:"),
object: self,
userInfo: [
"sectionInfo": sectionInfo,
"sectionIndex": sectionIndex
]
)
}
func listMonitor(_ monitor: ListMonitor<TestEntity1>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "listMonitor:didDeleteSection:fromSectionIndex:"),
object: self,
userInfo: [
"sectionInfo": sectionInfo,
"sectionIndex": sectionIndex
]
)
}
}
+304
View File
@@ -0,0 +1,304 @@
//
// ListPublisherTests.swift
// CoreStore iOS
//
// 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.
//
#if canImport(UIKit) || canImport(AppKit)
import XCTest
@testable
import CoreStore
// MARK: - ListPublisherTests
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
class ListPublisherTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatListPublishers_CanReceiveInsertNotifications() {
self.prepareStack { (stack) in
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertFalse(listPublisher.snapshot.hasSections())
XCTAssertFalse(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.itemIDs.isEmpty)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 1)
didChangeExpectation.fulfill()
}
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool 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")!
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
}
)
self.waitAndCheckExpectations()
withExtendedLifetime(listPublisher, {})
withExtendedLifetime(observer, {})
}
}
@objc
dynamic func test_ThatListPublishers_CanReceiveUpdateNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
didChangeExpectation.fulfill()
}
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
if let object = try transaction.fetchOne(
From<TestEntity1>(),
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
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 = 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()
withExtendedLifetime(listPublisher, {})
withExtendedLifetime(observer, {})
}
}
@objc
dynamic func test_ThatListPublishers_CanReceiveMoveNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 1)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 4)
didChangeExpectation.fulfill()
}
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
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()
}
)
self.waitAndCheckExpectations()
withExtendedLifetime(listPublisher, {})
withExtendedLifetime(observer, {})
}
}
@objc
dynamic func test_ThatListPublishers_CanReceiveDeleteNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
let observer = NSObject()
let listPublisher = stack.publishList(
From<TestEntity1>(),
SectionBy(#keyPath(TestEntity1.testBoolean)),
OrderBy<TestEntity1>(.ascending(#keyPath(TestEntity1.testBoolean)), .ascending(#keyPath(TestEntity1.testEntityID)))
)
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 2)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 2)
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 1), 3)
let didChangeExpectation = self.expectation(description: "didChange")
listPublisher.addObserver(observer) { listPublisher in
XCTAssertTrue(listPublisher.snapshot.hasSections())
XCTAssertEqual(listPublisher.snapshot.numberOfSections, 1)
XCTAssertTrue(listPublisher.snapshot.hasItems())
XCTAssertTrue(listPublisher.snapshot.hasItems(inSectionIndex: 0))
XCTAssertEqual(listPublisher.snapshot.numberOfItems(inSectionIndex: 0), 3)
didChangeExpectation.fulfill()
}
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
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()
}
}
}
#endif
+147
View File
@@ -0,0 +1,147 @@
//
// MigrationChainTests.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: - MigrationChainTests
final class MigrationChainTests: XCTestCase {
@objc
dynamic func test_ThatNilMigrationChains_HaveNoVersions() {
let chain: MigrationChain = nil
XCTAssertTrue(chain.isValid)
XCTAssertTrue(chain.isEmpty)
XCTAssertFalse(chain.contains("version1"))
XCTAssertNil(chain.nextVersionFrom("version1"))
}
@objc
dynamic func test_ThatStringMigrationChains_HaveOneVersion() {
let chain: MigrationChain = "version1"
XCTAssertTrue(chain.isValid)
XCTAssertTrue(chain.isEmpty)
XCTAssertTrue(chain.contains("version1"))
XCTAssertFalse(chain.contains("version2"))
XCTAssertNil(chain.nextVersionFrom("version1"))
XCTAssertNil(chain.nextVersionFrom("version2"))
}
@objc
dynamic func test_ThatArrayMigrationChains_HaveLinearVersions() {
let chain: MigrationChain = ["version1", "version2", "version3", "version4"]
XCTAssertTrue(chain.isValid)
XCTAssertFalse(chain.isEmpty)
XCTAssertTrue(chain.contains("version1"))
XCTAssertTrue(chain.contains("version2"))
XCTAssertTrue(chain.contains("version3"))
XCTAssertTrue(chain.contains("version4"))
XCTAssertFalse(chain.contains("version5"))
XCTAssertEqual(chain.nextVersionFrom("version1"), "version2")
XCTAssertEqual(chain.nextVersionFrom("version2"), "version3")
XCTAssertEqual(chain.nextVersionFrom("version3"), "version4")
XCTAssertNil(chain.nextVersionFrom("version4"))
XCTAssertNil(chain.nextVersionFrom("version5"))
}
@objc
dynamic func test_ThatDictionaryMigrationChains_HaveTreeVersions() {
let chain: MigrationChain = [
"version1": "version4",
"version2": "version3",
"version3": "version4"
]
XCTAssertTrue(chain.isValid)
XCTAssertFalse(chain.isEmpty)
XCTAssertTrue(chain.contains("version1"))
XCTAssertTrue(chain.contains("version2"))
XCTAssertTrue(chain.contains("version3"))
XCTAssertTrue(chain.contains("version4"))
XCTAssertFalse(chain.contains("version5"))
XCTAssertEqual(chain.nextVersionFrom("version1"), "version4")
XCTAssertEqual(chain.nextVersionFrom("version2"), "version3")
XCTAssertEqual(chain.nextVersionFrom("version3"), "version4")
XCTAssertNil(chain.nextVersionFrom("version4"))
XCTAssertNil(chain.nextVersionFrom("version5"))
// The cases below will trigger assertion failures internally
// let linearLoopChain: MigrationChain = ["version1", "version2", "version1", "version3", "version4"]
// XCTAssertFalse(linearLoopChain.valid, "linearLoopChain.valid")
//
// let treeAmbiguousChain: MigrationChain = [
// "version1": "version4",
// "version2": "version3",
// "version1": "version2",
// "version3": "version4"
// ]
// XCTAssertFalse(treeAmbiguousChain.valid, "treeAmbiguousChain.valid")
}
@objc
dynamic func test_ThatMigrationChains_AreEquatable() {
do {
let chain1: MigrationChain = nil
let chain2: MigrationChain = []
let chain3: MigrationChain = [:]
XCTAssertEqual(chain1, chain2)
XCTAssertEqual(chain2, chain3)
XCTAssertEqual(chain3, chain1)
}
do {
let chain1: MigrationChain = "version1"
let chain2: MigrationChain = ["version1"]
XCTAssertEqual(chain1, chain2)
}
do {
let chain1: MigrationChain = ["version1", "version2", "version3", "version4"]
let chain2: MigrationChain = [
"version1": "version2",
"version2": "version3",
"version3": "version4"
]
XCTAssertEqual(chain1, chain2)
}
}
}
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14460.32" systemVersion="17G2307" minimumToolsVersion="Xcode 4.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="TestEntity1AAA" representedClassName="CoreStoreTests.TestEntity1" syncable="YES">
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testData" optional="YES" attributeType="Binary" syncable="YES"/>
<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" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="testToManyUnordered" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToOne" inverseEntity="TestEntity1AAA" syncable="YES"/>
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity1AAA" inverseName="testToManyUnordered" inverseEntity="TestEntity1AAA" syncable="YES"/>
</entity>
<entity name="TestEntity2" representedClassName="CoreStoreTests.TestEntity2" syncable="YES">
<attribute name="testBoolean" optional="YES" attributeType="Boolean" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testData" optional="YES" attributeType="Binary" 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" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testNil" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="testNumber" optional="YES" attributeType="Integer 32" usesScalarValueType="NO" syncable="YES"/>
<attribute name="testString" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="testToManyOrdered" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TestEntity2" inverseName="testToOne" inverseEntity="TestEntity2" syncable="YES"/>
<relationship name="testToOne" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TestEntity2" inverseName="testToManyOrdered" inverseEntity="TestEntity2" syncable="YES"/>
</entity>
<configuration name="Config1">
<memberEntity name="TestEntity1AAA"/>
</configuration>
<configuration name="Config2">
<memberEntity name="TestEntity2"/>
</configuration>
<elements>
<element name="TestEntity1AAA" positionX="-63" positionY="-18" width="128" height="195"/>
<element name="TestEntity2" positionX="-63" positionY="9" width="128" height="195"/>
</elements>
</model>
+244
View File
@@ -0,0 +1,244 @@
//
// ObjectObserverTests.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: - ObjectObserverTests
@available(macOS 10.12, *)
class ObjectObserverTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatObjectObservers_CanReceiveUpdateNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
guard let object = try stack.fetchOne(
From<TestEntity1>(),
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
}
let observer = TestObjectObserver()
let monitor = stack.monitorObject(object)
monitor.addObserver(observer)
XCTAssertEqual(monitor.object, object)
XCTAssertFalse(monitor.isObjectDeleted)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "objectMonitor:willUpdateObject:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
["object": object] as NSDictionary
)
defer {
events += 1
}
return events == 0
}
)
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 1)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
[
"object": object,
"changedPersistentKeys": Set(
[
#keyPath(TestEntity1.testNumber),
#keyPath(TestEntity1.testString)
]
)
] as NSDictionary
)
let object = note.userInfo?["object"] as? TestEntity1
XCTAssertEqual(object?.testNumber, NSNumber(value: 10))
XCTAssertEqual(object?.testString, "nil:TestEntity1:10")
defer {
events += 1
}
return events == 1
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
guard let object = transaction.edit(object) else {
XCTFail()
try transaction.cancel()
}
object.testNumber = NSNumber(value: 10)
object.testString = "nil:TestEntity1:10"
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
}
)
self.waitAndCheckExpectations()
}
}
@objc
dynamic func test_ThatObjectObservers_CanReceiveDeleteNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
guard let object = try stack.fetchOne(
From<TestEntity1>(),
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
}
let observer = TestObjectObserver()
let monitor = stack.monitorObject(object)
monitor.addObserver(observer)
XCTAssertEqual(monitor.object, object)
XCTAssertFalse(monitor.isObjectDeleted)
var events = 0
_ = self.expectation(
forNotification: NSNotification.Name(rawValue: "objectMonitor:didDeleteObject:"),
object: observer,
handler: { (note) -> Bool in
XCTAssertEqual(events, 0)
XCTAssertEqual(
((note.userInfo as NSDictionary?) ?? [:]),
["object": object] as NSDictionary
)
defer {
events += 1
}
return events == 0
}
)
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
guard let object = transaction.edit(object) else {
XCTFail()
try transaction.cancel()
}
transaction.delete(object)
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
XCTAssertTrue(monitor.isObjectDeleted)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
}
)
self.waitAndCheckExpectations()
}
}
}
// MARK: TestObjectObserver
@available(macOS 10.12, *)
class TestObjectObserver: ObjectObserver {
typealias ObjectEntityType = TestEntity1
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, willUpdateObject object: TestEntity1) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "objectMonitor:willUpdateObject:"),
object: self,
userInfo: [
"object": object
]
)
}
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didUpdateObject object: TestEntity1, changedPersistentKeys: Set<String>) {
NotificationCenter.default.post(
name: NSNotification.Name(rawValue: "objectMonitor:didUpdateObject:changedPersistentKeys:"),
object: self,
userInfo: [
"object": object,
"changedPersistentKeys": changedPersistentKeys
]
)
}
func objectMonitor(_ monitor: ObjectMonitor<TestEntity1>, didDeleteObject object: TestEntity1) {
NotificationCenter.default.post(
name: Notification.Name(rawValue: "objectMonitor:didDeleteObject:"),
object: self,
userInfo: [
"object": object
]
)
}
}
+155
View File
@@ -0,0 +1,155 @@
//
// ObjectPublisherTests.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: - ObjectPublisherTests
@available(macOS 10.12, *)
class ObjectPublisherTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatObjectPublishers_CanReceiveUpdateNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
guard let object = try stack.fetchOne(
From<TestEntity1>(),
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
}
let observer = NSObject()
let objectPublisher = stack.publishObject(object)
XCTAssertEqual(objectPublisher.object, object)
XCTAssertNotNil(objectPublisher.snapshot)
let didChangeExpectation = self.expectation(description: "didChange")
objectPublisher.addObserver(observer) { objectPublisher in
XCTAssertEqual(objectPublisher.object?.testNumber, NSNumber(value: 10))
XCTAssertEqual(objectPublisher.object?.testString, "nil:TestEntity1:10")
didChangeExpectation.fulfill()
}
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
guard let object = transaction.edit(object) else {
XCTFail()
try transaction.cancel()
}
object.testNumber = NSNumber(value: 10)
object.testString = "nil:TestEntity1:10"
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
}
)
self.waitAndCheckExpectations()
withExtendedLifetime(objectPublisher, {})
withExtendedLifetime(observer, {})
}
}
@objc
dynamic func test_ThatObjectPublishers_CanReceiveDeleteNotifications() {
self.prepareStack { (stack) in
self.prepareTestDataForStack(stack)
guard let object = try stack.fetchOne(
From<TestEntity1>(),
Where<TestEntity1>(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) else {
XCTFail()
return
}
let observer = NSObject()
let objectPublisher = stack.publishObject(object)
XCTAssertEqual(objectPublisher.object, object)
XCTAssertNotNil(objectPublisher.snapshot)
let didChangeExpectation = self.expectation(description: "didChange")
objectPublisher.addObserver(observer) { objectPublisher in
XCTAssertNil(objectPublisher.object)
XCTAssertNil(objectPublisher.snapshot)
didChangeExpectation.fulfill()
}
let saveExpectation = self.expectation(description: "save")
stack.perform(
asynchronous: { (transaction) -> Bool in
guard let object = transaction.edit(object) else {
XCTFail()
try transaction.cancel()
}
transaction.delete(object)
return transaction.hasChanges
},
success: { (hasChanges) in
XCTAssertTrue(hasChanges)
saveExpectation.fulfill()
},
failure: { _ in
XCTFail()
}
)
self.waitAndCheckExpectations()
withExtendedLifetime(objectPublisher, {})
withExtendedLifetime(observer, {})
}
}
}
+187
View File
@@ -0,0 +1,187 @@
//
// OrderByTests.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: - OrderByTests
final class OrderByTests: XCTestCase {
@objc
dynamic func test_ThatOrderByClauses_ConfigureCorrectly() {
do {
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<NSManagedObject>(sortDescriptor)
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 {
let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false)
]
let orderBy = OrderBy<NSManagedObject>(sortDescriptors)
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy<NSManagedObject>(
[
NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false)
]
)
)
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
do {
let orderBy = OrderBy<NSManagedObject>(.ascending("key1"))
let sortDescriptor = NSSortDescriptor(key: "key1", ascending: true)
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<NSManagedObject>(.ascending("key1"), .descending("key2"))
let sortDescriptors = [
NSSortDescriptor(key: "key1", ascending: true),
NSSortDescriptor(key: "key2", ascending: false)
]
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy<NSManagedObject>(
[
NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false)
]
)
)
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
do {
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<NSManagedObject>(sortDescriptors))
XCTAssertEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key2")))
XCTAssertNotEqual(
orderBy,
OrderBy<NSManagedObject>(
[
NSSortDescriptor(key: "key1", ascending: false),
NSSortDescriptor(key: "key2", ascending: false)
]
)
)
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .ascending("key2")))
XCTAssertNotEqual(orderBy, OrderBy<NSManagedObject>(.ascending("key1"), .descending("key3")))
XCTAssertEqual(orderBy.sortDescriptors, sortDescriptors)
}
}
@objc
dynamic func test_ThatOrderByClauseOperations_ComputeCorrectly() {
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<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)
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy1 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy2 + orderBy1)
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors + orderBy3.sortDescriptors)
}
do {
var plusOrderBy = orderBy1
plusOrderBy += orderBy2
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<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)
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy1 + orderBy2)
XCTAssertNotEqual(plusOrderBy, orderBy3 + orderBy2 + orderBy1)
XCTAssertEqual(plusOrderBy.sortDescriptors, orderBy1.sortDescriptors + orderBy2.sortDescriptors + orderBy3.sortDescriptors)
}
}
@objc
dynamic func test_ThatOrderByClauses_ApplyToFetchRequestsCorrectly() {
let orderBy = OrderBy<NSManagedObject>(.ascending("key"))
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
orderBy.applyToFetchRequest(request)
XCTAssertNotNil(request.sortDescriptors)
XCTAssertEqual(request.sortDescriptors ?? [], orderBy.sortDescriptors)
}
}
File diff suppressed because it is too large Load Diff
+54
View File
@@ -0,0 +1,54 @@
//
// SectionByTests.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: - SectionByTests
@available(macOS 10.12, *)
final class SectionByTests: XCTestCase {
@objc
dynamic func test_ThatSectionByClauses_ConfigureCorrectly() {
do {
let sectionBy = SectionBy<NSManagedObject>("key")
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key")
}
do {
let sectionBy = SectionBy<NSManagedObject>("key") { $0.flatMap { "\($0):suffix" } }
XCTAssertEqual(sectionBy.sectionKeyPath, "key")
XCTAssertEqual(sectionBy.sectionIndexTransformer("key"), "key:suffix")
XCTAssertNil(sectionBy.sectionIndexTransformer(nil))
}
}
}
+420
View File
@@ -0,0 +1,420 @@
//
// SelectTests.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: - SelectTests
final class SelectTests: XCTestCase {
@objc
dynamic func test_ThatAttributeSelectTerms_ConfigureCorrectly() {
do {
let term: SelectTerm<NSManagedObject> = "attribute"
XCTAssertEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._attribute(let key):
XCTAssertEqual(key, "attribute")
default:
XCTFail()
}
}
do {
let term = SelectTerm<NSManagedObject>.attribute("attribute")
XCTAssertNotEqual(term, SelectTerm.attribute("attribute2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._attribute(let key):
XCTAssertEqual(key, "attribute")
default:
XCTFail()
}
}
}
@objc
dynamic func test_ThatAverageSelectTerms_ConfigureCorrectly() {
do {
let term = SelectTerm<NSManagedObject>.average("attribute")
XCTAssertEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "average:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "average(attribute)")
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
}
}
do {
let term = SelectTerm<NSManagedObject>.average("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.average("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.average("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.average("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "average:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
}
}
}
@objc
dynamic func test_ThatCountSelectTerms_ConfigureCorrectly() {
do {
let term = SelectTerm<NSManagedObject>.count("attribute")
XCTAssertEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "count:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "count(attribute)")
XCTAssertTrue(nativeType == .integer64AttributeType)
default:
XCTFail()
}
}
do {
let term = SelectTerm<NSManagedObject>.count("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.count("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.count("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.count("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "count:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .integer64AttributeType)
default:
XCTFail()
}
}
}
@objc
dynamic func test_ThatMaximumSelectTerms_ConfigureCorrectly() {
do {
let term = SelectTerm<NSManagedObject>.maximum("attribute")
XCTAssertEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "max:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "max(attribute)")
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
}
}
do {
let term = SelectTerm<NSManagedObject>.maximum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.maximum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "max:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
}
}
}
@objc
dynamic func test_ThatMinimumSelectTerms_ConfigureCorrectly() {
do {
let term = SelectTerm<NSManagedObject>.minimum("attribute")
XCTAssertEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "min:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "min(attribute)")
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
}
}
do {
let term = SelectTerm<NSManagedObject>.minimum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.minimum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "min:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .undefinedAttributeType)
default:
XCTFail()
}
}
}
@objc
dynamic func test_ThatSumSelectTerms_ConfigureCorrectly() {
do {
let term = SelectTerm<NSManagedObject>.sum("attribute")
XCTAssertEqual(term, SelectTerm.sum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "sum:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "sum(attribute)")
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
}
}
do {
let term = SelectTerm<NSManagedObject>.sum("attribute", as: "alias")
XCTAssertEqual(term, SelectTerm.sum("attribute", as: "alias"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute", as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute2"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.objectID())
switch term {
case ._aggregate(let function, let keyPath, let alias, let nativeType):
XCTAssertEqual(function, "sum:")
XCTAssertEqual(keyPath, "attribute")
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .decimalAttributeType)
default:
XCTFail()
}
}
}
@objc
dynamic func test_ThatObjectIDSelectTerms_ConfigureCorrectly() {
do {
let term = SelectTerm<NSManagedObject>.objectID()
XCTAssertEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
switch term {
case ._identity(let alias, let nativeType):
XCTAssertEqual(alias, "objectID")
XCTAssertTrue(nativeType == .objectIDAttributeType)
default:
XCTFail()
}
}
do {
let term = SelectTerm<NSManagedObject>.objectID(as: "alias")
XCTAssertEqual(term, SelectTerm.objectID(as: "alias"))
XCTAssertNotEqual(term, SelectTerm.objectID(as: "alias2"))
XCTAssertNotEqual(term, SelectTerm.objectID())
XCTAssertNotEqual(term, SelectTerm.attribute("attribute"))
XCTAssertNotEqual(term, SelectTerm.average("attribute"))
XCTAssertNotEqual(term, SelectTerm.count("attribute"))
XCTAssertNotEqual(term, SelectTerm.maximum("attribute"))
XCTAssertNotEqual(term, SelectTerm.minimum("attribute"))
XCTAssertNotEqual(term, SelectTerm.sum("attribute"))
switch term {
case ._identity(let alias, let nativeType):
XCTAssertEqual(alias, "alias")
XCTAssertTrue(nativeType == .objectIDAttributeType)
default:
XCTFail()
}
}
}
@objc
dynamic func test_ThatSelectClauses_ConfigureCorrectly() {
let term1 = SelectTerm<NSManagedObject>.attribute("attribute1")
let term2 = SelectTerm<NSManagedObject>.attribute("attribute2")
let term3 = SelectTerm<NSManagedObject>.attribute("attribute3")
do {
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])
XCTAssertNotEqual(select.selectTerms, [term2, term3, term1])
XCTAssertNotEqual(select.selectTerms, [term3, term1, term2])
XCTAssertNotEqual(select.selectTerms, [term3, term2, term1])
}
do {
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])
XCTAssertNotEqual(select.selectTerms, [term2, term3, term1])
XCTAssertNotEqual(select.selectTerms, [term3, term1, term2])
XCTAssertNotEqual(select.selectTerms, [term3, term2, term1])
}
}
}
+378
View File
@@ -0,0 +1,378 @@
//
// SetupTests.swift
// CoreStore
//
// Copyright © 2018 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
@testable
import CoreStore
// MARK: - SetupTests
class SetupTests: BaseTestDataTestCase {
@objc
dynamic func test_ThatDataStacks_ConfigureCorrectly() {
do {
let schemaHistory = SchemaHistory(
XcodeDataModelSchema.from(
modelName: "Model",
bundle: Bundle(for: Self.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)
XCTAssertFalse(stack.rootSavingContext.isTransactionContext)
XCTAssertEqual(stack.mainContext.parent, stack.rootSavingContext)
XCTAssertTrue(stack.mainContext.isDataStackContext)
XCTAssertFalse(stack.mainContext.isTransactionContext)
XCTAssertEqual(stack.schemaHistory.rawModel, schemaHistory.rawModel)
XCTAssertTrue(stack.schemaHistory.migrationChain.isValid)
XCTAssertTrue(stack.schemaHistory.migrationChain.isEmpty)
XCTAssertTrue(stack.schemaHistory.migrationChain.rootVersions.isEmpty)
XCTAssertTrue(stack.schemaHistory.migrationChain.leafVersions.isEmpty)
}
do {
let migrationChain: MigrationChain = ["version1", "version2", "version3", "Model"]
let stack = self.expectLogger([.logWarning]) {
DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self),
migrationChain: migrationChain
)
}
XCTAssertEqual(stack.modelVersion, "Model")
XCTAssertEqual(stack.schemaHistory.migrationChain, migrationChain)
}
}
@objc
dynamic func test_ThatInMemoryStores_SetupCorrectly() {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
do {
let inMemoryStore = InMemoryStore()
do {
try stack.addStorageAndWait(inMemoryStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(inMemoryStore)
XCTAssertNotNil(persistentStore)
}
do {
let inMemoryStore = InMemoryStore(
configuration: "Config1"
)
do {
try stack.addStorageAndWait(inMemoryStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(inMemoryStore)
XCTAssertNotNil(persistentStore)
}
do {
let inMemoryStore = InMemoryStore(
configuration: "Config2"
)
do {
try stack.addStorageAndWait(inMemoryStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(inMemoryStore)
XCTAssertNotNil(persistentStore)
}
}
@objc
dynamic func test_ThatSQLiteStores_SetupCorrectly() {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
do {
let sqliteStore = SQLiteStore()
do {
try stack.addStorageAndWait(sqliteStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
XCTAssertNotNil(persistentStore)
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
}
do {
let sqliteStore = SQLiteStore(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
try stack.addStorageAndWait(sqliteStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
XCTAssertNotNil(persistentStore)
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
}
do {
let sqliteStore = SQLiteStore(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
try stack.addStorageAndWait(sqliteStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
XCTAssertNotNil(persistentStore)
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
}
}
@objc
dynamic func test_ThatSQLiteStores_DeleteFilesCorrectly() {
let fileManager = FileManager.default
let sqliteStore = SQLiteStore()
func createStore() throws -> [String: Any] {
do {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
try! stack.addStorageAndWait(sqliteStore)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: sqliteStore).storeType,
at: sqliteStore.fileURL,
options: sqliteStore.storeOptions
)
}
do {
let metadata = try createStore()
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
try sqliteStore.cs_eraseStorageAndWait(
metadata: metadata,
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
do {
let metadata = try createStore()
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
}
@objc
dynamic func test_ThatLegacySQLiteStores_SetupCorrectly() {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
do {
let sqliteStore = SQLiteStore.legacy()
do {
try stack.addStorageAndWait(sqliteStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
XCTAssertNotNil(persistentStore)
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
}
do {
let sqliteStore = SQLiteStore.legacy(
fileName: "ConfigStore1.sqlite",
configuration: "Config1",
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
try stack.addStorageAndWait(sqliteStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
XCTAssertNotNil(persistentStore)
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
}
do {
let sqliteStore = SQLiteStore.legacy(
fileName: "ConfigStore2.sqlite",
configuration: "Config2",
localStorageOptions: .recreateStoreOnModelMismatch
)
do {
try stack.addStorageAndWait(sqliteStore)
}
catch let error as NSError {
XCTFail(error.description)
}
let persistentStore = stack.persistentStoreForStorage(sqliteStore)
XCTAssertNotNil(persistentStore)
XCTAssert(sqliteStore.matchesPersistentStore(persistentStore!))
}
}
@objc
dynamic func test_ThatLegacySQLiteStores_DeleteFilesCorrectly() {
let fileManager = FileManager.default
let sqliteStore = SQLiteStore.legacy()
func createStore() throws -> [String: Any] {
do {
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
try! stack.addStorageAndWait(
SQLiteStore.legacy(
fileName: sqliteStore.fileURL.lastPathComponent,
configuration: sqliteStore.configuration,
migrationMappingProviders: sqliteStore.migrationMappingProviders,
localStorageOptions: .recreateStoreOnModelMismatch
)
)
self.prepareTestDataForStack(stack)
}
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertTrue(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
return try NSPersistentStoreCoordinator.metadataForPersistentStore(
ofType: type(of: sqliteStore).storeType,
at: sqliteStore.fileURL,
options: sqliteStore.storeOptions
)
}
do {
let metadata = try createStore()
let stack = DataStack(
xcodeModelName: "Model",
bundle: Bundle(for: Self.self)
)
try sqliteStore.cs_eraseStorageAndWait(
metadata: metadata,
soureModelHint: stack.schemaHistory.schema(for: metadata)?.rawModel()
)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
do {
let metadata = try createStore()
try sqliteStore.cs_eraseStorageAndWait(metadata: metadata, soureModelHint: nil)
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-wal")))
XCTAssertFalse(fileManager.fileExists(atPath: sqliteStore.fileURL.path.appending("-shm")))
}
catch {
XCTFail()
}
}
}
+270
View File
@@ -0,0 +1,270 @@
//
// StorageInterfaceTests.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: - StorageInterfaceTests
final class StorageInterfaceTests: XCTestCase {
@objc
dynamic func test_ThatDefaultInMemoryStores_ConfigureCorrectly() {
let store = InMemoryStore()
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertNil(store.configuration)
XCTAssertNil(store.storeOptions)
}
@objc
dynamic func test_ThatCustomInMemoryStores_ConfigureCorrectly() {
let store = InMemoryStore(configuration: "config1")
XCTAssertEqual(type(of: store).storeType, NSInMemoryStoreType)
XCTAssertEqual(store.configuration, "config1")
XCTAssertNil(store.storeOptions)
}
@objc
dynamic func test_ThatSQLiteStoreDefaultDirectories_AreCorrect() {
#if os(tvOS)
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif
let defaultSystemDirectory = FileManager.default
.urls(for: systemDirectorySearchPath, in: .userDomainMask).first!
let defaultRootDirectory = defaultSystemDirectory.appendingPathComponent(
Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
isDirectory: true
)
let applicationName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String) ?? "CoreData"
let defaultFileURL = defaultRootDirectory
.appendingPathComponent(applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
XCTAssertEqual(SQLiteStore.defaultRootDirectory, defaultRootDirectory)
XCTAssertEqual(SQLiteStore.defaultFileURL, defaultFileURL)
}
@objc
dynamic func test_ThatDefaultSQLiteStores_ConfigureCorrectly() {
let store = SQLiteStore()
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, SQLiteStore.defaultFileURL)
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
XCTAssertEqual(store.localStorageOptions, .none)
}
@objc
dynamic func test_ThatFileURLSQLiteStores_ConfigureCorrectly() {
let fileURL = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString, isDirectory: false)
.appendingPathExtension("db")
let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: Self.self)
)
let store = SQLiteStore(
fileURL: fileURL,
configuration: "config1",
migrationMappingProviders: [mappingProvider],
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, fileURL)
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@objc
dynamic func test_ThatFileNameSQLiteStores_ConfigureCorrectly() {
let fileName = UUID().uuidString + ".db"
let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: Self.self)
)
let store = SQLiteStore(
fileName: fileName,
configuration: "config1",
migrationMappingProviders: [mappingProvider],
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
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.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
@objc
dynamic func test_ThatLegacySQLiteStoreDefaultDirectories_AreCorrect() {
#if os(tvOS)
let systemDirectorySearchPath = FileManager.SearchPathDirectory.cachesDirectory
#else
let systemDirectorySearchPath = FileManager.SearchPathDirectory.applicationSupportDirectory
#endif
let legacyDefaultRootDirectory = FileManager.default.urls(
for: systemDirectorySearchPath,
in: .userDomainMask).first!
let legacyDefaultFileURL = legacyDefaultRootDirectory
.appendingPathComponent(DataStack.applicationName, isDirectory: false)
.appendingPathExtension("sqlite")
XCTAssertEqual(SQLiteStore.legacyDefaultRootDirectory, legacyDefaultRootDirectory)
XCTAssertEqual(SQLiteStore.legacyDefaultFileURL, legacyDefaultFileURL)
}
@objc
dynamic func test_ThatDefaultLegacySQLiteStores_ConfigureCorrectly() {
let store = SQLiteStore.legacy()
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertNil(store.configuration)
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL, SQLiteStore.legacyDefaultFileURL)
XCTAssertTrue(store.migrationMappingProviders.isEmpty)
XCTAssertEqual(store.localStorageOptions, .none)
}
@objc
dynamic func test_ThatFileNameLegacySQLiteStores_ConfigureCorrectly() {
let fileName = UUID().uuidString + ".db"
let mappingProvider = XcodeSchemaMappingProvider(
from: "V1", to: "V2",
mappingModelBundle: Bundle(for: Self.self)
)
let store = SQLiteStore.legacy(
fileName: fileName,
configuration: "config1",
migrationMappingProviders: [mappingProvider],
localStorageOptions: .recreateStoreOnModelMismatch
)
XCTAssertEqual(type(of: store).storeType, NSSQLiteStoreType)
XCTAssertEqual(store.configuration, "config1")
if #available(iOS 11.0, macOS 10.13, tvOS 11.0, *) {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"],
NSBinaryStoreInsecureDecodingCompatibilityOption: true] as NSDictionary
)
}
else {
XCTAssertEqual(
store.storeOptions as NSDictionary?,
[NSSQLitePragmasOption: ["journal_mode": "WAL"]] as NSDictionary
)
}
XCTAssertEqual(store.fileURL.deletingLastPathComponent(), SQLiteStore.legacyDefaultRootDirectory)
XCTAssertEqual(store.fileURL.lastPathComponent, fileName)
XCTAssertEqual(store.migrationMappingProviders as! [XcodeSchemaMappingProvider], [mappingProvider])
XCTAssertEqual(store.localStorageOptions, [.recreateStoreOnModelMismatch])
}
}
+41
View File
@@ -0,0 +1,41 @@
//
// TestEntity1.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
class TestEntity1: NSManagedObject {
@NSManaged var testEntityID: NSNumber?
@NSManaged var testString: String?
@NSManaged var testNumber: NSNumber?
@NSManaged var testDate: Date?
@NSManaged var testBoolean: NSNumber?
@NSManaged var testDecimal: NSDecimalNumber?
@NSManaged var testData: Data?
@NSManaged var testNil: String?
@NSManaged var testToOne: TestEntity1?
@NSManaged var testToManyUnordered: NSSet?
}
+41
View File
@@ -0,0 +1,41 @@
//
// TestEntity1.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
class TestEntity2: NSManagedObject {
@NSManaged var testEntityID: NSNumber?
@NSManaged var testString: String?
@NSManaged var testNumber: NSNumber?
@NSManaged var testDate: Date?
@NSManaged var testBoolean: NSNumber?
@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
+53
View File
@@ -0,0 +1,53 @@
//
// TweakTests.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: - TweakTests
final class TweakTests: XCTestCase {
@objc
dynamic func test_ThatTweakClauses_ApplyToFetchRequestsCorrectly() {
let predicate = NSPredicate(format: "%K == %@", "key", "value")
let tweak = Tweak {
$0.fetchOffset = 100
$0.fetchLimit = 200
$0.predicate = predicate
}
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
tweak.applyToFetchRequest(request)
XCTAssertEqual(request.fetchOffset, 100)
XCTAssertEqual(request.fetchLimit, 200)
XCTAssertNotNil(request.predicate)
XCTAssertEqual(request.predicate, predicate)
}
}
+55
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]
]
"""
)
}
}
+602
View File
@@ -0,0 +1,602 @@
//
// WhereTests.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: - XCTAssertAllEqual
private func XCTAssertAllEqual<O>(_ whereClauses: Where<O>...) {
XCTAssertAllEqual(whereClauses)
}
private func XCTAssertAllEqual<O>(_ whereClauses: [Where<O>]) {
for i in whereClauses.indices {
for j in whereClauses.indices where j != i {
XCTAssertEqual(whereClauses[i], whereClauses[j])
}
}
}
private func XCTAssertAllEqual<D: Equatable>(_ items: D...) {
for i in items.indices {
for j in items.indices where j != i {
XCTAssertEqual(items[i], items[j])
}
}
}
//MARK: - WhereTests
final class WhereTests: XCTestCase {
@objc
dynamic func test_ThatDynamicModelKeyPaths_CanBeCreated() {
XCTAssertAllEqual(String(keyPath: \TestEntity1.testEntityID), "testEntityID")
XCTAssertAllEqual(String(keyPath: \Animal.$color), "color")
}
@objc
dynamic func test_ThatExpressions_HaveCorrectKeyPaths() {
do {
do {
XCTAssertAllEqual(
#keyPath(TestEntity1.testToOne.testEntityID),
(\TestEntity1.testToOne ~ \.testEntityID).description,
String(keyPath: \TestEntity1.testToOne ~ \.testEntityID)
)
XCTAssertAllEqual(
#keyPath(TestEntity1.testToOne.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered).description,
String(keyPath: \TestEntity1.testToOne ~ \.testToOne ~ \.testToManyUnordered)
)
XCTAssertAllEqual(
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).description,
String(keyPath: \TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered)
)
}
do {
XCTAssertAllEqual(
"master.pets",
(\Animal.$master ~ \.$pets).description,
String(keyPath: \Animal.$master ~ \.$pets)
)
XCTAssertAllEqual(
"master.pets.species",
(\Animal.$master ~ \.$pets ~ \.$species).description,
String(keyPath: \Animal.$master ~ \.$pets ~ \.$species)
)
XCTAssertAllEqual(
"master.pets.master",
(\Animal.$master ~ \.$pets ~ \.$master).description,
String(keyPath: \Animal.$master ~ \.$pets ~ \.$master)
)
}
}
do {
do {
XCTAssertAllEqual(
#keyPath(TestEntity1.testToOne.testToManyUnordered) + ".@count",
(\TestEntity1.testToOne ~ \.testToManyUnordered).count().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).count())
)
XCTAssertAllEqual(
#keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered) + ".@count",
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).count())
)
}
do {
XCTAssertAllEqual(
"master.pets.@count",
(\Animal.$master ~ \.$pets).count().description,
String(keyPath: (\Animal.$master ~ \.$pets).count())
)
}
}
do {
do {
XCTAssertAllEqual(
"ANY " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).any().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).any())
)
XCTAssertAllEqual(
"ANY " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).any())
)
}
do {
XCTAssertAllEqual(
"ANY master.pets",
(\Animal.$master ~ \.$pets).any().description,
String(keyPath: (\Animal.$master ~ \.$pets).any())
)
XCTAssertAllEqual(
"ANY master.pets.species",
(\Animal.$master ~ \.$pets ~ \.$species).any().description,
String(keyPath: (\Animal.$master ~ \.$pets ~ \.$species).any())
)
}
}
do {
do {
XCTAssertAllEqual(
"ALL " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).all().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).all())
)
XCTAssertAllEqual(
"ALL " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).all())
)
}
do {
XCTAssertAllEqual(
"ALL master.pets",
(\Animal.$master ~ \.$pets).all().description,
String(keyPath: (\Animal.$master ~ \.$pets).all())
)
XCTAssertAllEqual(
"ALL master.pets.species",
(\Animal.$master ~ \.$pets ~ \.$species).all().description,
String(keyPath: (\Animal.$master ~ \.$pets ~ \.$species).all())
)
}
}
do {
do {
XCTAssertAllEqual(
"NONE " + #keyPath(TestEntity1.testToOne.testToManyUnordered),
(\TestEntity1.testToOne ~ \.testToManyUnordered).none().description,
String(keyPath: (\TestEntity1.testToOne ~ \.testToManyUnordered).none())
)
XCTAssertAllEqual(
"NONE " + #keyPath(TestEntity2.testToOne.testToOne.testToManyOrdered),
(\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none().description,
String(keyPath: (\TestEntity2.testToOne ~ \.testToOne ~ \.testToManyOrdered).none())
)
}
do {
XCTAssertAllEqual(
"NONE master.pets",
(\Animal.$master ~ \.$pets).none().description,
String(keyPath: (\Animal.$master ~ \.$pets).none())
)
XCTAssertAllEqual(
"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)
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause: Where<Animal> = (\.$master ~ \.$name) == dummy
let predicate = NSPredicate(format: "master.name == %@", dummy)
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
XCTAssertAllEqual(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)
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause: Where<Animal> = (\.$master ~ \.$spouse ~ \.$name) == dummy
let predicate = NSPredicate(format: "master.spouse.name == %@", dummy)
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
XCTAssertAllEqual(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)
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause: Where<Animal> = (\.$master ~ \.$pets).count() == count
let predicate = NSPredicate(format: "master.pets.@count == %d", count)
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
XCTAssertAllEqual(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)
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause: Where<Animal> = (\.$master ~ \.$pets ~ \.$species).any() == dummy
let predicate = NSPredicate(format: "ANY master.pets.species == %@", dummy)
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
XCTAssertAllEqual(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)
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause: Where<Animal> = (\.$master ~ \.$pets ~ \.$species).all() == dummy
let predicate = NSPredicate(format: "ALL master.pets.species == %@", dummy)
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
XCTAssertAllEqual(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)
XCTAssertAllEqual(whereClause, Where<TestEntity1>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause: Where<Animal> = (\.$master ~ \.$pets ~ \.$species).none() == dummy
let predicate = NSPredicate(format: "NONE master.pets.species == %@", dummy)
XCTAssertAllEqual(whereClause, Where<Animal>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
}
}
@objc
dynamic func test_ThatWhereClauses_ConfigureCorrectly() {
do {
let whereClause = Where<NSManagedObject>()
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(true))
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
XCTAssertAllEqual(whereClause.predicate, NSPredicate(value: true))
}
do {
let whereClause = Where<NSManagedObject>(true)
XCTAssertAllEqual(whereClause, Where<NSManagedObject>())
XCTAssertNotEqual(whereClause, Where<NSManagedObject>(false))
XCTAssertAllEqual(whereClause.predicate, NSPredicate(value: true))
}
do {
let predicate = NSPredicate(format: "%K == %@", "key", "value")
let whereClause = Where<NSManagedObject>(predicate)
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause = Where<NSManagedObject>("%K == %@", "key", "value")
let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause = Where<NSManagedObject>("%K == %@", argumentArray: ["key", "value"])
let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let predicate = NSPredicate(format: "%K == %@", "key", "value")
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
do {
let whereClause = Where<NSManagedObject>("key", isMemberOf: ["value1", "value2", "value3"])
let predicate = NSPredicate(format: "%K IN %@", "key", ["value1", "value2", "value3"])
XCTAssertAllEqual(whereClause, Where<NSManagedObject>(predicate))
XCTAssertAllEqual(whereClause.predicate, predicate)
}
}
@objc
dynamic func test_ThatWhereClauses_BridgeArgumentsCorrectly() {
do {
let value: Int = 100
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
)
}
do {
let value = NSNumber(value: 100)
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", value.intValue),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", value.intValue),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value.intValue)
)
}
do {
let value: Int64 = Int64.max
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", NSNumber(value: value)),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", NSNumber(value: value)),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: NSNumber(value: value))
)
}
do {
let value = NSNumber(value: Int64.max)
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %d", "key", value),
Where<NSManagedObject>("%K == %d", "key", value as AnyObject),
Where<NSManagedObject>("%K == %d", "key", value.int64Value),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", value.int64Value),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value.int64Value)
)
}
do {
let value: String = "value"
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %s", "key", value),
Where<NSManagedObject>("%K == %s", "key", value as AnyObject),
Where<NSManagedObject>("%K == %s", "key", NSString(string: value)),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as AnyObject),
Where<NSManagedObject>("%K == %@", "key", NSString(string: value)),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value as NSString),
Where<NSManagedObject>("key", isEqualTo: NSString(string: value))
)
}
do {
let value = NSString(string: "value")
XCTAssertAllEqual(
Where<NSManagedObject>("%K == %s", "key", value),
Where<NSManagedObject>("%K == %s", "key", value as String),
Where<NSManagedObject>("%K == %s", "key", value as String as AnyObject),
Where<NSManagedObject>("%K == %@", "key", value),
Where<NSManagedObject>("%K == %@", "key", value as String),
Where<NSManagedObject>("%K == %@", "key", value as String as AnyObject),
Where<NSManagedObject>("key", isEqualTo: value),
Where<NSManagedObject>("key", isEqualTo: value as String),
Where<NSManagedObject>("key", isEqualTo: value as String as NSString)
)
}
do {
let value: [Int] = [100, 200]
XCTAssertAllEqual(
Where<NSManagedObject>("%K IN %@", "key", value),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
Where<NSManagedObject>("key", isMemberOf: value)
)
}
do {
let value: [Int64] = [Int64.min, 100, Int64.max]
XCTAssertAllEqual(
Where<NSManagedObject>("%K IN %@", "key", value),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject),
Where<NSManagedObject>("%K IN %@", "key", value as [AnyObject]),
Where<NSManagedObject>("%K IN %@", "key", value as NSArray),
Where<NSManagedObject>("%K IN %@", "key", NSArray(array: value)),
Where<NSManagedObject>("%K IN %@", "key", value as AnyObject as! NSArray),
Where<NSManagedObject>("key", isMemberOf: value)
)
}
}
@objc
dynamic func test_ThatWhereClauseOperations_ComputeCorrectly() {
let whereClause1 = Where<NSManagedObject>("key1", isEqualTo: "value1")
let whereClause2 = Where<NSManagedObject>("key2", isEqualTo: "value2")
let whereClause3 = Where<NSManagedObject>("key3", isEqualTo: "value3")
do {
let notWhere = !whereClause1
let notPredicate = NSCompoundPredicate(
type: .not,
subpredicates: [whereClause1.predicate]
)
XCTAssertAllEqual(notWhere.predicate, notPredicate)
XCTAssertAllEqual(notWhere, !whereClause1)
}
do {
let andWhere = whereClause1 && whereClause2 && whereClause3
let andPredicate = NSCompoundPredicate(
type: .and,
subpredicates: [
NSCompoundPredicate(
type: .and,
subpredicates: [whereClause1.predicate, whereClause2.predicate]
),
whereClause3.predicate
]
)
XCTAssertAllEqual(andWhere.predicate, andPredicate)
XCTAssertAllEqual(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!
XCTAssertAllEqual(andWhere.predicate, finalNoneWhere.predicate)
XCTAssertAllEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
}
do {
let orWhere = whereClause1 || whereClause2 || whereClause3
let orPredicate = NSCompoundPredicate(
type: .or,
subpredicates: [
NSCompoundPredicate(
type: .or,
subpredicates: [whereClause1.predicate, whereClause2.predicate]
),
whereClause3.predicate
]
)
XCTAssertAllEqual(orWhere.predicate, orPredicate)
XCTAssertAllEqual(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!
XCTAssertAllEqual(orWhere.predicate, finalNoneWhere.predicate)
XCTAssertAllEqual(finalSomeWhere.predicate, unwrappedFinalSomeWhere.predicate)
}
}
@objc
dynamic func test_ThatWhereClauses_ApplyToFetchRequestsCorrectly() {
let whereClause = Where<NSManagedObject>("key", isEqualTo: "value")
let request = Internals.CoreStoreFetchRequest<NSFetchRequestResult>()
whereClause.applyToFetchRequest(request)
XCTAssertNotNil(request.predicate)
XCTAssertAllEqual(request.predicate, whereClause.predicate)
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5A3911824E5429200E7E8BD"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:Demo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5A3911824E5429200E7E8BD"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:Demo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5A3911824E5429200E7E8BD"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:Demo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+70
View File
@@ -0,0 +1,70 @@
<?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>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarTintParameters</key>
<dict>
<key>UINavigationBar</key>
<dict>
<key>Style</key>
<string>UIBarStyleDefault</string>
<key>Translucent</key>
<false/>
</dict>
</dict>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
+42
View File
@@ -0,0 +1,42 @@
# coding: utf-8
task :format do
require 'xcodeproj'
require 'fileutils'
project_path = 'Demo.xcodeproj'
ignore_targets = []
# http://www.rubydoc.info/github/CocoaPods/Xcodeproj
project = Xcodeproj::Project.open(project_path)
validTargets = project.targets.select { |target| target.respond_to?(:product_type) }
validTargets.each do |target|
if ignore_targets.include?(target.display_name)
next
end
case target.product_type
when 'com.apple.product-type.application', 'com.apple.product-type.framework'
target.source_build_phase.files.sort! do |f1, f2|
result = (f1.display_name.count "+") <=> (f2.display_name.count "+")
if result != 0
next -result
end
result = (f1.display_name.count "-") <=> (f2.display_name.count "-")
if result != 0
next -result
end
result = (f1.display_name.count ".") <=> (f2.display_name.count ".")
if result != 0
next result
end
(f1.display_name <=> f2.display_name)
end
end
end
project.save()
end
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController interfaceStyle="dark" id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Bp2-lt-3DL">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2020 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="Yn3-8H-uzI">
<rect key="frame" x="20" y="827" width="374" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="CoreStoreIcon" translatesAutoresizingMaskIntoConstraints="NO" id="IrK-8p-pit">
<rect key="frame" x="122" y="228.5" width="170" height="170"/>
<constraints>
<constraint firstAttribute="width" secondItem="IrK-8p-pit" secondAttribute="height" multiplier="1:1" id="WaM-8F-33r"/>
<constraint firstAttribute="width" constant="170" id="dlo-1N-ikz"/>
</constraints>
</imageView>
<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="8Vu-0U-3hd">
<rect key="frame" x="20" y="418.5" width="374" height="57.5"/>
<fontDescription key="fontDescription" name="HelveticaNeue-UltraLight" family="Helvetica Neue" pointSize="50"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="Yn3-8H-uzI" firstAttribute="leading" secondItem="Bp2-lt-3DL" secondAttribute="leading" constant="20" symbolic="YES" id="7Dq-xP-k2v"/>
<constraint firstItem="IrK-8p-pit" firstAttribute="centerY" secondItem="Bp2-lt-3DL" secondAttribute="centerY" multiplier="0.7" id="HUz-XL-l27"/>
<constraint firstItem="IrK-8p-pit" firstAttribute="centerX" secondItem="Bp2-lt-3DL" secondAttribute="centerX" id="TSf-yM-hl1"/>
<constraint firstAttribute="centerX" secondItem="8Vu-0U-3hd" secondAttribute="centerX" id="TX2-HT-cKs"/>
<constraint firstItem="Z3i-EZ-UGs" firstAttribute="bottom" secondItem="Yn3-8H-uzI" secondAttribute="bottom" constant="14" id="hAb-SJ-Qnm"/>
<constraint firstAttribute="centerX" secondItem="Yn3-8H-uzI" secondAttribute="centerX" id="pNf-eo-RXZ"/>
<constraint firstItem="8Vu-0U-3hd" firstAttribute="leading" secondItem="Bp2-lt-3DL" secondAttribute="leading" constant="20" symbolic="YES" id="pef-yD-C5e"/>
<constraint firstItem="8Vu-0U-3hd" firstAttribute="top" secondItem="IrK-8p-pit" secondAttribute="bottom" constant="20" id="xQP-tq-hNL"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Z3i-EZ-UGs"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="CoreStoreIcon" width="170" height="170"/>
</resources>
</document>
@@ -0,0 +1,115 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "Icon-60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "Icon-60@3x-1.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "Icon-76.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "Icon-76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "Icon-83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "Mask + Oval 1 + Oval 1 + Oval 1.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
},
{
"idiom" : "car",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "Icon-60@3x.png",
"idiom" : "car",
"scale" : "3x",
"size" : "60x60"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "CoreStoreIcon.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "original"
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
+33
View File
@@ -0,0 +1,33 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import UIKit
// MARK: - AppDelegate
@UIApplicationMain
@objc final class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: UIApplicationDelegate
@objc dynamic func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
return true
}
@objc dynamic func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
}
@@ -0,0 +1,69 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import Foundation
import UIKit
import Combine
// MARK: - ImageDownloader
final class ImageDownloader: ObservableObject {
// MARK: FilePrivate
private(set) var image: UIImage?
let url: URL?
init(url: URL?) {
self.url = url
guard let url = url else {
return
}
if let image = Self.cache[url] {
self.image = image
}
}
func fetchImage(completion: @escaping (UIImage) -> Void = { _ in }) {
guard let url = url else {
return
}
if let image = Self.cache[url] {
self.objectWillChange.send()
self.image = image
completion(image)
return
}
self.cancellable = URLSession.shared
.dataTaskPublisher(for: url)
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { _ in },
receiveValue: { output in
if let image = UIImage(data: output.data) {
Self.cache[url] = image
self.objectWillChange.send()
self.image = image
completion(image)
}
}
)
}
// MARK: Private
private static var cache: [URL: UIImage] = [:]
private var cancellable: AnyCancellable?
}
@@ -0,0 +1,58 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import SwiftUI
// MARK: - InstructionsView
struct InstructionsView: View {
// MARK: Internal
init(_ rows: (header: String, description: String)...) {
self.rows = rows.map({ .init(header: $0, description: $1) })
}
// MARK: View
var body: some View {
ZStack(alignment: .center) {
Color.white
.cornerRadius(10)
.shadow(color: Color(.sRGB, white: 0.5, opacity: 0.3), radius: 2, x: 1, y: 1)
VStack(alignment: .leading, spacing: 3) {
ForEach(self.rows, id: \.header) { row in
HStack(alignment: .firstTextBaseline, spacing: 5) {
Text(row.header)
.font(.callout)
.fontWeight(.bold)
Text(row.description)
.font(.footnote)
}
}
}
.foregroundColor(Color(.sRGB, white: 0, opacity: 0.8))
.padding(.horizontal, 10)
.padding(.vertical, 4)
}
.fixedSize()
}
// MARK: Private
private let rows: [InstructionsView.Row]
// MARK: - Row
struct Row: Hashable {
// MARK: Internal
let header: String
let description: String
}
}
+29
View File
@@ -0,0 +1,29 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import SwiftUI
// MARK: - LazyView
struct LazyView<Content: View>: View {
// MARK: Internal
init(_ load: @escaping () -> Content) {
self.load = load
}
// MARK: View
var body: Content {
self.load()
}
// MARK: Private
private let load: () -> Content
}
@@ -0,0 +1,71 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import SwiftUI
// MARK: - Menu
extension Menu {
// MARK: - Menu.ItemView
struct ItemView<Destination: View>: View {
// MARK: Internal
init(
title: String,
subtitle: String? = nil,
destination: @escaping () -> Destination
) {
self.title = title
self.subtitle = subtitle
self.destination = destination
}
// MARK: View
var body: some View {
NavigationLink(destination: LazyView(self.destination)) {
VStack(alignment: .leading) {
Text(self.title)
.font(.headline)
.foregroundColor(.primary)
self.subtitle.map {
Text($0)
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
}
// MARK: FilePrivate
fileprivate let title: String
fileprivate let subtitle: String?
fileprivate let destination: () -> Destination
}
}
#if DEBUG
struct _Demo_Menu_ItemView_Preview: PreviewProvider {
// MARK: PreviewProvider
static var previews: some View {
Menu.ItemView(
title: "Item Title",
subtitle: "A subtitle caption for this item",
destination: {
Color.blue
}
)
}
}
#endif
@@ -0,0 +1,132 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import Foundation
import SwiftUI
// MARK: - Menu
extension Menu {
// MARK: - Menu.MainView
struct MainView: View {
// MARK: View
var body: some View {
NavigationView {
List {
Section(header: Text("Modern (CoreStoreObject subclasses)")) {
Menu.ItemView(
title: "Placemarks",
subtitle: "Making changes using Transactions",
destination: {
Modern.PlacemarksDemo.MainView()
}
)
Menu.ItemView(
title: "Time Zones",
subtitle: "Fetching objects and Querying raw values",
destination: {
Modern.TimeZonesDemo.MainView()
}
)
Menu.ItemView(
title: "Colors (UIKit)",
subtitle: "Observing list changes and single-object changes using DiffableDataSources",
destination: {
Modern.ColorsDemo.MainView(
listView: { listPublisher, onPaletteTapped in
Modern.ColorsDemo.UIKit.ListView(
listPublisher: listPublisher,
onPaletteTapped: onPaletteTapped
)
.edgesIgnoringSafeArea(.all)
},
detailView: { objectPublisher in
Modern.ColorsDemo.UIKit.DetailView(objectPublisher)
}
)
}
)
Menu.ItemView(
title: "Colors (SwiftUI)",
subtitle: "Observing list changes and single-object changes using SwiftUI bindings",
destination: {
Modern.ColorsDemo.MainView(
listView: { listPublisher, onPaletteTapped in
Modern.ColorsDemo.SwiftUI.ListView(
listPublisher: listPublisher,
onPaletteTapped: onPaletteTapped
)
},
detailView: { objectPublisher in
Modern.ColorsDemo.SwiftUI.DetailView(objectPublisher)
}
)
}
)
Menu.ItemView(
title: "Pokedex API",
subtitle: "Importing JSON data from external source",
destination: {
Modern.PokedexDemo.MainView()
}
)
}
Section(header: Text("Classic (NSManagedObject subclasses)")) {
Menu.ItemView(
title: "Colors",
subtitle: "Observing list changes and single-object changes using ListMonitor",
destination: {
Classic.ColorsDemo.MainView()
}
)
}
Section(header: Text("Advanced")) {
Menu.ItemView(
title: "Accounts",
subtitle: "Switching between multiple persistent stores",
destination: { EmptyView() }
)
.disabled(true)
Menu.ItemView(
title: "Evolution",
subtitle: "Migrating and reverse-migrating stores",
destination: {
Advanced.EvolutionDemo.MainView()
}
)
Menu.ItemView(
title: "Logger",
subtitle: "Implementing a custom logger",
destination: { EmptyView() }
)
.disabled(true)
}
}
.listStyle(GroupedListStyle())
.navigationBarTitle("CoreStore Demos")
Menu.PlaceholderView()
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
}
}
#if DEBUG
struct _Demo_Menu_MainView_Preview: PreviewProvider {
// MARK: PreviewProvider
static var previews: some View {
Menu.MainView()
}
}
#endif
@@ -0,0 +1,44 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import Combine
import CoreStore
import SwiftUI
// MARK: - Menu
extension Menu {
// MARK: - Menu.PlaceholderView
struct PlaceholderView: UIViewControllerRepresentable {
// MARK: UIViewControllerRepresentable
typealias UIViewControllerType = UIViewController
func makeUIViewController(context: Self.Context) -> UIViewControllerType {
return UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController()!
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Self.Context) {}
static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Void) {}
}
}
#if DEBUG
struct _Demo_Menu_PlaceholderView_Preview: PreviewProvider {
// MARK: PreviewProvider
static var previews: some View {
return Menu.PlaceholderView()
}
}
#endif
@@ -0,0 +1,10 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import Foundation
// MARK: - Menu
enum Menu {}
+36
View File
@@ -0,0 +1,36 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import SwiftUI
import UIKit
// MARK: - SceneDelegate
@objc final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// MARK: UIWindowSceneDelegate
@objc dynamic var window: UIWindow?
// MARK: UISceneDelegate
@objc dynamic func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard case let scene as UIWindowScene = scene else {
return
}
let window = UIWindow(windowScene: scene)
window.rootViewController = UIHostingController(
rootView: Menu.MainView()
)
self.window = window
window.makeKeyAndVisible()
}
}
@@ -0,0 +1,10 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
// MARK: - Advanced
/**
Sample application of complex use cases
*/
enum Advanced {}
@@ -0,0 +1,30 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import CoreStore
import Foundation
// MARK: - Advanced.EvolutionDemo
extension Advanced.EvolutionDemo {
typealias CreatureType = Advanced_EvolutionDemo_CreatureType
}
// MARK: - Advanced.EvolutionDemo.CreatureType
protocol Advanced_EvolutionDemo_CreatureType: DynamicObject, CustomStringConvertible {
var dnaCode: Int64 { get set }
static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource
static func count(in transaction: BaseDataTransaction) throws -> Int
static func create(in transaction: BaseDataTransaction) -> Self
func mutate(in transaction: BaseDataTransaction)
}
@@ -0,0 +1,168 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import CoreStore
import Combine
// MARK: - Advanced.EvolutionDemo
extension Advanced.EvolutionDemo {
// MARK: - Advanced.EvolutionDemo.CreaturesDataSource
/**
A type-erasing adapter to support different `ListPublisher` types
*/
final class CreaturesDataSource: ObservableObject {
// MARK: Internal
init<T: NSManagedObject & Advanced.EvolutionDemo.CreatureType>(
listPublisher: ListPublisher<T>,
dataStack: DataStack
) {
self.numberOfItems = {
listPublisher.snapshot.numberOfItems
}
self.itemDescriptionAtIndex = { index in
listPublisher.snapshot[index].object?.description
}
self.addItems = { count in
dataStack.perform(
asynchronous: { transaction in
let nextDNACode = try transaction.fetchCount(From<T>())
for offset in 0 ..< count {
let object = transaction.create(Into<T>())
object.dnaCode = .init(nextDNACode + offset)
object.mutate(in: transaction)
}
},
completion: { _ in }
)
}
self.mutateItemAtIndex = { index in
let object = listPublisher.snapshot[index]
dataStack.perform(
asynchronous: { transaction in
object
.asEditable(in: transaction)?
.mutate(in: transaction)
},
completion: { _ in }
)
}
self.deleteAllItems = {
dataStack.perform(
asynchronous: { transaction in
try transaction.deleteAll(From<T>())
},
completion: { _ in }
)
}
listPublisher.addObserver(self) { [weak self] (listPublisher) in
self?.objectWillChange.send()
}
}
init<T: CoreStoreObject & Advanced.EvolutionDemo.CreatureType>(
listPublisher: ListPublisher<T>,
dataStack: DataStack
) {
self.numberOfItems = {
listPublisher.snapshot.numberOfItems
}
self.itemDescriptionAtIndex = { index in
listPublisher.snapshot[index].object?.description
}
self.addItems = { count in
dataStack.perform(
asynchronous: { transaction in
let nextDNACode = try transaction.fetchCount(From<T>())
for offset in 0 ..< count {
let object = transaction.create(Into<T>())
object.dnaCode = .init(nextDNACode + offset)
object.mutate(in: transaction)
}
},
completion: { _ in }
)
}
self.mutateItemAtIndex = { index in
let object = listPublisher.snapshot[index]
dataStack.perform(
asynchronous: { transaction in
object
.asEditable(in: transaction)?
.mutate(in: transaction)
},
completion: { _ in }
)
}
self.deleteAllItems = {
dataStack.perform(
asynchronous: { transaction in
try transaction.deleteAll(From<T>())
},
completion: { _ in }
)
}
listPublisher.addObserver(self) { [weak self] (listPublisher) in
self?.objectWillChange.send()
}
}
func numberOfCreatures() -> Int {
return self.numberOfItems()
}
func creatureDescription(at index: Int) -> String? {
return self.itemDescriptionAtIndex(index)
}
func mutate(at index: Int) {
self.mutateItemAtIndex(index)
}
func add(count: Int) {
self.addItems(count)
}
func clear() {
self.deleteAllItems()
}
// MARK: Private
private let numberOfItems: () -> Int
private let itemDescriptionAtIndex: (Int) -> String?
private let mutateItemAtIndex: (Int) -> Void
private let addItems: (Int) -> Void
private let deleteAllItems: () -> Void
}
}
@@ -0,0 +1,99 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import CoreStore
// MARK: - AdvancedEvolutionDemo
extension Advanced.EvolutionDemo {
// MARK: - GeologicalPeriod
enum GeologicalPeriod: RawRepresentable, CaseIterable, Hashable, CustomStringConvertible {
// MARK: Internal
case ageOfInvertebrates
case ageOfFishes
case ageOfReptiles
case ageOfMammals
var version: ModelVersion {
return self.rawValue
}
var creatureType: Advanced.EvolutionDemo.CreatureType.Type {
switch self {
case .ageOfInvertebrates:
return Advanced.EvolutionDemo.V1.Creature.self
case .ageOfFishes:
return Advanced.EvolutionDemo.V2.Creature.self
case .ageOfReptiles:
return Advanced.EvolutionDemo.V3.Creature.self
case .ageOfMammals:
return Advanced.EvolutionDemo.V4.Creature.self
}
}
// MARK: CustomStringConvertible
var description: String {
switch self {
case .ageOfInvertebrates:
return "Invertebrates"
case .ageOfFishes:
return "Fishes"
case .ageOfReptiles:
return "Reptiles"
case .ageOfMammals:
return "Mammals"
}
}
// MARK: RawRepresentable
typealias RawValue = ModelVersion
var rawValue: ModelVersion {
switch self {
case .ageOfInvertebrates:
return Advanced.EvolutionDemo.V1.name
case .ageOfFishes:
return Advanced.EvolutionDemo.V2.name
case .ageOfReptiles:
return Advanced.EvolutionDemo.V3.name
case .ageOfMammals:
return Advanced.EvolutionDemo.V4.name
}
}
init?(rawValue: ModelVersion) {
switch rawValue {
case Advanced.EvolutionDemo.V1.name:
self = .ageOfInvertebrates
case Advanced.EvolutionDemo.V2.name:
self = .ageOfFishes
case Advanced.EvolutionDemo.V3.name:
self = .ageOfReptiles
case Advanced.EvolutionDemo.V4.name:
self = .ageOfMammals
default:
return nil
}
}
}
}
@@ -0,0 +1,75 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import SwiftUI
// MARK: - Advanced.EvolutionDemo
extension Advanced.EvolutionDemo {
// MARK: - Advanced.EvolutionDemo.ItemView
struct ItemView: View {
// MARK: Internal
init(description: String?, mutate: @escaping () -> Void) {
self.description = description
self.mutate = mutate
}
// MARK: View
var body: some View {
HStack {
Text(self.description ?? "")
.font(.footnote)
.foregroundColor(.primary)
Spacer()
Button(
action: self.mutate,
label: {
Text("Mutate")
.foregroundColor(.accentColor)
.fontWeight(.bold)
}
)
.buttonStyle(PlainButtonStyle())
}
.disabled(self.description == nil)
}
// MARK: FilePrivate
fileprivate let description: String?
fileprivate let mutate: () -> Void
}
}
#if DEBUG
struct _Demo_Advanced_EvolutionDemo_ItemView_Preview: PreviewProvider {
// MARK: PreviewProvider
static var previews: some View {
Advanced.EvolutionDemo.ItemView(
description: """
dnaCode: 123
numberOfLimbs: 4
hasVertebrae: true
hasHead: true
hasTail: true
habitat: land
hasWings: false
""",
mutate: {}
)
}
}
#endif
@@ -0,0 +1,99 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import CoreStore
import SwiftUI
// MARK: - Advanced.EvolutionDemo
extension Advanced.EvolutionDemo {
// MARK: - Advanced.EvolutionDemo.ListView
struct ListView: View {
// MARK: View
var body: some View {
let dataSource = self.dataSource
return List {
ForEach(0 ..< dataSource.numberOfCreatures(), id: \.self) { (index) in
Advanced.EvolutionDemo.ItemView(
description: dataSource.creatureDescription(at: index),
mutate: {
dataSource.mutate(at: index)
}
)
}
}
.listStyle(PlainListStyle())
}
// MARK: Internal
init(
period: Advanced.EvolutionDemo.GeologicalPeriod,
dataStack: DataStack,
dataSource: Advanced.EvolutionDemo.CreaturesDataSource
) {
self.period = period
self.dataStack = dataStack
self.dataSource = dataSource
}
// MARK: Private
private let period: Advanced.EvolutionDemo.GeologicalPeriod
private let dataStack: DataStack
@ObservedObject
private var dataSource: Advanced.EvolutionDemo.CreaturesDataSource
}
}
#if DEBUG
struct _Demo_Advanced_EvolutionDemo_ListView_Preview: PreviewProvider {
// MARK: PreviewProvider
static var previews: some View {
let dataStack = DataStack(
CoreStoreSchema(
modelVersion: Advanced.EvolutionDemo.V4.name,
entities: [
Entity<Advanced.EvolutionDemo.V4.Creature>("Creature")
]
)
)
try! dataStack.addStorageAndWait(
SQLiteStore(fileName: "Advanced.EvolutionDemo.ListView.Preview.sqlite")
)
try! dataStack.perform(
synchronous: { transaction in
for dnaCode in 0 ..< 10 as Range<Int64> {
let object = transaction.create(Into<Advanced.EvolutionDemo.V4.Creature>())
object.dnaCode = dnaCode
object.mutate(in: transaction)
}
}
)
return Advanced.EvolutionDemo.ListView(
period: .ageOfMammals,
dataStack: dataStack,
dataSource: Advanced.EvolutionDemo.V4.Creature.dataSource(in: dataStack)
)
}
}
#endif
@@ -0,0 +1,78 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import CoreStore
import SwiftUI
// MARK: - Advanced.EvolutionDemo
extension Advanced.EvolutionDemo {
// MARK: - Advanced.EvolutionDemo.MainView
struct MainView: View {
// MARK: View
var body: some View {
let migrator = self.migrator
let listView: AnyView
if let current = migrator.current {
listView = AnyView(
Advanced.EvolutionDemo.ListView(
period: current.period,
dataStack: current.dataStack,
dataSource: current.dataSource
)
)
}
else {
listView = AnyView(
Advanced.EvolutionDemo.ProgressView(progress: migrator.progress)
)
}
return VStack(spacing: 0) {
HStack(alignment: .center, spacing: 0) {
Text("Age of")
.padding(.trailing)
Picker(selection: self.$migrator.currentPeriod, label: EmptyView()) {
ForEach(Advanced.EvolutionDemo.GeologicalPeriod.allCases, id: \.self) { period in
Text(period.description).tag(period)
}
}
.pickerStyle(SegmentedPickerStyle())
}
.padding()
listView
.edgesIgnoringSafeArea(.vertical)
}
.navigationBarTitle("Evolution")
.disabled(migrator.isBusy || migrator.current == nil)
}
// MARK: Private
@ObservedObject
private var migrator: Advanced.EvolutionDemo.Migrator = .init()
}
}
#if DEBUG
struct _Demo_Advanced_EvolutionDemo_MainView_Preview: PreviewProvider {
// MARK: PreviewProvider
static var previews: some View {
Advanced.EvolutionDemo.MainView()
}
}
#endif
@@ -0,0 +1,127 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import SwiftUI
// MARK: - Advanced.EvolutionDemo
extension Advanced.EvolutionDemo {
// MARK: - Advanced.EvolutionDemo.ProgressView
struct ProgressView: View {
// MARK: Internal
init(progress: Progress?) {
self.progressObserver = .init(progress)
}
// MARK: View
var body: some View {
guard self.progressObserver.isMigrating else {
return AnyView(
VStack(alignment: .center) {
Text("Preparing creatures...")
.padding()
Spacer()
}
.padding()
)
}
return AnyView(
VStack(alignment: .leading) {
Text("Migrating: \(self.progressObserver.localizedDescription)")
.font(.headline)
.padding([.top, .horizontal])
Text("Progressive step: \(self.progressObserver.localizedAdditionalDescription)")
.font(.subheadline)
.padding(.horizontal)
GeometryReader { geometry in
ZStack(alignment: .leading) {
Color.gray
.opacity(0.2)
.frame(width: geometry.size.width, height: 8)
.cornerRadius(4.0)
Color.blue
.frame(
width: geometry.size.width
* self.progressObserver.fractionCompleted,
height: 8
)
.cornerRadius(4.0)
}
}
.fixedSize(horizontal: false, vertical: true)
.padding()
Spacer()
}
.padding()
)
}
// MARK: FilePrivate
@ObservedObject
private var progressObserver: ProgressObserver
// MARK: - ProgressObserver
fileprivate final class ProgressObserver: ObservableObject {
private(set) var fractionCompleted: CGFloat = 0
private(set) var localizedDescription: String = ""
private(set) var localizedAdditionalDescription: String = ""
var isMigrating: Bool {
return self.progress != nil
}
init(_ progress: Progress?) {
self.progress = progress
progress?.setProgressHandler { [weak self] (progess) in
guard let self = self else {
return
}
self.objectWillChange.send()
self.fractionCompleted = CGFloat(progress?.fractionCompleted ?? 0)
self.localizedDescription = progress?.localizedDescription ?? ""
self.localizedAdditionalDescription = progress?.localizedAdditionalDescription ?? ""
}
}
// MARK: Private
private let progress: Progress?
}
}
}
#if DEBUG
struct _Demo_Advanced_EvolutionDemo_ProgressView_Preview: PreviewProvider {
// MARK: PreviewProvider
static var previews: some View {
let progress = Progress(totalUnitCount: 10)
progress.completedUnitCount = 3
return Advanced.EvolutionDemo.ProgressView(
progress: progress
)
}
}
#endif
@@ -0,0 +1,63 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import UIKit
import CoreStore
// MARK: - Advanced.EvolutionDemo.V1.Creature
@objc(Advanced_EvolutionDemo_V1_Creature)
final class Advanced_EvolutionDemo_V1_Creature: NSManagedObject, Advanced.EvolutionDemo.CreatureType {
@NSManaged
dynamic var dnaCode: Int64
@NSManaged
dynamic var numberOfFlagella: Int32
// MARK: CustomStringConvertible
override var description: String {
return """
dnaCode: \(self.dnaCode)
numberOfFlagella: \(self.numberOfFlagella)
"""
}
// MARK: Advanced.EvolutionDemo.CreatureType
static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource {
return .init(
listPublisher: dataStack.publishList(
From<Advanced.EvolutionDemo.V1.Creature>()
.orderBy(.descending(\.dnaCode))
),
dataStack: dataStack
)
}
static func count(in transaction: BaseDataTransaction) throws -> Int {
return try transaction.fetchCount(
From<Advanced.EvolutionDemo.V1.Creature>()
)
}
static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V1.Creature {
return transaction.create(
Into<Advanced.EvolutionDemo.V1.Creature>()
)
}
func mutate(in transaction: BaseDataTransaction) {
self.numberOfFlagella = .random(in: 1...200)
}
}
@@ -0,0 +1,27 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import CoreStore
// MARK: - Advanced.EvolutionDemo.V1
extension Advanced.EvolutionDemo.V1 {
// MARK: - Advanced.EvolutionDemo.V1.FromV2
enum FromV2 {
// MARK: Internal
static var mapping: XcodeSchemaMappingProvider {
return XcodeSchemaMappingProvider(
from: Advanced.EvolutionDemo.V2.name,
to: Advanced.EvolutionDemo.V1.name,
mappingModelBundle: Bundle(for: Advanced.EvolutionDemo.V1.Creature.self)
)
}
}
}
@@ -0,0 +1,25 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import CoreStore
// MARK: - Advanced.EvolutionDemo
extension Advanced.EvolutionDemo {
// MARK: - Advanced.EvolutionDemo.V1
/**
Namespace for V1 models (`Advanced.EvolutionDemo.GeologicalPeriod.ageOfInvertebrates`)
*/
enum V1 {
// MARK: Internal
static let name: ModelVersion = "Advanced.EvolutionDemo.V1"
typealias Creature = Advanced_EvolutionDemo_V1_Creature
}
}
@@ -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>_XCCurrentVersionName</key>
<string>Advanced.EvolutionDemo.V1.xcdatamodel</string>
</dict>
</plist>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19F101" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Creature" representedClassName="Advanced_EvolutionDemo_V1_Creature" syncable="YES">
<attribute name="dnaCode" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="numberOfFlagella" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="YES"/>
</entity>
<elements>
<element name="Creature" positionX="-27" positionY="18" width="128" height="73"/>
</elements>
</model>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19F101" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Creature" representedClassName="Advanced_EvolutionDemo_V2_Creature" syncable="YES">
<attribute name="dnaCode" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hasHead" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="hasTail" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="hasVertebrae" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="numberOfFlippers" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="YES"/>
</entity>
<elements>
<element name="Creature" positionX="-9" positionY="36" width="128" height="118"/>
</elements>
</model>
@@ -0,0 +1,78 @@
//
// Demo
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
import UIKit
import CoreStore
// MARK: - Advanced.EvolutionDemo.V2.Creature
@objc(Advanced_EvolutionDemo_V2_Creature)
final class Advanced_EvolutionDemo_V2_Creature: NSManagedObject, Advanced.EvolutionDemo.CreatureType {
@NSManaged
dynamic var dnaCode: Int64
@NSManaged
dynamic var numberOfFlippers: Int32
@NSManaged
dynamic var hasVertebrae: Bool
@NSManaged
dynamic var hasHead: Bool
@NSManaged
dynamic var hasTail: Bool
// MARK: CustomStringConvertible
override var description: String {
return """
dnaCode: \(self.dnaCode)
numberOfFlippers: \(self.numberOfFlippers)
hasVertebrae: \(self.hasVertebrae)
hasHead: \(self.hasHead)
hasTail: \(self.hasTail)
"""
}
// MARK: Advanced.EvolutionDemo.CreatureType
static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource {
return .init(
listPublisher: dataStack.publishList(
From<Advanced.EvolutionDemo.V2.Creature>()
.orderBy(.descending(\.dnaCode))
),
dataStack: dataStack
)
}
static func count(in transaction: BaseDataTransaction) throws -> Int {
return try transaction.fetchCount(
From<Advanced.EvolutionDemo.V2.Creature>()
)
}
static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V2.Creature {
return transaction.create(
Into<Advanced.EvolutionDemo.V2.Creature>()
)
}
func mutate(in transaction: BaseDataTransaction) {
self.numberOfFlippers = .random(in: 1...4) * 2
self.hasVertebrae = .random()
self.hasHead = true
self.hasTail = .random()
}
}

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