Swiftpack.co - Swift Packages by JohnEstropia

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.

Packages published by JohnEstropia

JohnEstropia/CoreStore 9.2.0
Unleashing the real power of Core Data with the elegance and safety of Swift
⭐️ 3,932
🕓 28 weeks ago
🔖 Release Notes

Releases

The markdown parsing is broken/disabled for release notes. Sorry about that, I'm chasing the source of a crash that's been bringing this website down for the last couple of days.
Xcode 14 (Swift 2.7), min iOS 13 support
1 year ago
Swift 2.7 is bundled with Xcode 14, and CoreStore 9.0.0 will be the officially supported version from here on out. ## Breaking changes: - Removal of Objective-C support (which had been deprecated for a long time now) - Migration to Swift 2.7 from Swift 2.4 - Bumped minimum supported version to iOS 13 from iOS 11. While this double jump had never been done in CoreStore before, we are aiming to fully utilize Combine utilities internally and to make the shift to Swift concurrency (which requires at least iOS 13) as smooth as possible. **Full Changelog**: https://github.com/JohnEstropia/CoreStore/compare/8.1.0...9.0.0
Reactive Programming and SwiftUI
3 years ago
# Reactive Programming ## RxSwift RxSwift utilities are available through the [RxCoreStore](https://github.com/JohnEstropia/RxCoreStore) external module. ## Combine Combine publishers are available from the `DataStack`, `ListPublisher`, and `ObjectPublisher`'s `.reactive` namespace property. ### `DataStack.reactive` Adding a storage through `DataStack.reactive.addStorage(_:)` returns a publisher that reports a `MigrationProgress` `enum` value. The `.migrating` value is only emitted if the storage goes through a migration. ```swift dataStack.reactive .addStorage( SQLiteStore(fileName: "core_data.sqlite") ) .sink( receiveCompletion: { result in // ... }, receiveValue: { (progress) in print("\(round(progress.fractionCompleted * 100)) %") // 0.0 ~ 1.0 switch progress { case .migrating(let storage, let nsProgress): // ... case .finished(let storage, let migrationRequired): // ... } } ) .store(in: &cancellables) ``` Transactions are also available as publishers through `DataStack.reactive.perform(_:)`, which returns a Combine `Future` that emits any type returned from the closure parameter: ```swift dataStack.reactive .perform( asynchronous: { (transaction) -> (inserted: Set<NSManagedObject>, deleted: Set<NSManagedObject>) in // ... return ( transaction.insertedObjects(), transaction.deletedObjects() ) } ) .sink( receiveCompletion: { result in // ... }, receiveValue: { value in let inserted = dataStack.fetchExisting(value0.inserted) let deleted = dataStack.fetchExisting(value0.deleted) // ... } ) .store(in: &cancellables) ``` For importing convenience, `ImportableObject` and `ImportableUniqueObjects` can be imported directly through `DataStack.reactive.import[Unique]Object(_:source:)` and `DataStack.reactive.import[Unique]Objects(_:sourceArray:)` without having to create a transaction block. In this case the publisher emits objects that are already usable directly from the main queue: ```swift dataStack.reactive .importUniqueObjects( Into<Person>(), sourceArray: [ ["name": "John"], ["name": "Bob"], ["name": "Joe"] ] ) .sink( receiveCompletion: { result in // ... }, receiveValue: { (people) in XCTAssertEqual(people?.count, 3) // ... } ) .store(in: &cancellables) ``` ### `ListPublisher.reactive` `ListPublisher`s can be used to emit `ListSnapshot`s through Combine using `ListPublisher.reactive.snapshot(emitInitialValue:)`. The snapshot values are emitted in the main queue: ```swift listPublisher.reactive .snapshot(emitInitialValue: true) .sink( receiveCompletion: { result in // ... }, receiveValue: { (listSnapshot) in dataSource.apply( listSnapshot, animatingDifferences: true ) } ) .store(in: &cancellables) ``` ### `ObjectPublisher.reactive` `ObjectPublisher`s can be used to emit `ObjectSnapshot`s through Combine using `ObjectPublisher.reactive.snapshot(emitInitialValue:)`. The snapshot values are emitted in the main queue: ```swift objectPublisher.reactive .snapshot(emitInitialValue: true) .sink( receiveCompletion: { result in // ... }, receiveValue: { (objectSnapshot) in tableViewCell.setObject(objectSnapshot) } ) .store(in: &tableViewCell.cancellables) ``` # SwiftUI Utilities Observing list and object changes in SwiftUI can be done through a couple of approaches. One is by creating [views that autoupdates their contents](#swiftui-views), or by declaring [property wrappers that trigger view updates](#swiftui-property-wrappers). Both approaches are implemented almost the same internally, but this lets you be flexible depending on the structure of your custom `View`s. ## SwiftUI Views CoreStore provides `View` containers that automatically update their contents when data changes. ### `ListReader` A `ListReader` observes changes to a `ListPublisher` and creates its content views dynamically. The builder closure receives a `ListSnapshot` value that can be used to create the contents: ```swift let people: ListPublisher<Person> var body: some View { List { ListReader(self.people) { listSnapshot in ForEach(objectIn: listSnapshot) { person in // ... } } } .animation(.default) } ``` As shown above, a typical use case is to use it together with CoreStore's [`ForEach` extensions](#foreach). A `KeyPath` can also be optionally provided to extract specific properties of the `ListSnapshot`: ```swift let people: ListPublisher<Person> var body: some View { ListReader(self.people, keyPath: \.count) { count in Text("Number of members: \(count)") } } ``` ### `ObjectReader` An `ObjectReader` observes changes to an `ObjectPublisher` and creates its content views dynamically. The builder closure receives an `ObjectSnapshot` value that can be used to create the contents: ```swift let person: ObjectPublisher<Person> var body: some View { ObjectReader(self.person) { objectSnapshot in // ... } .animation(.default) } ``` A `KeyPath` can also be optionally provided to extract specific properties of the `ObjectSnapshot`: ```swift let person: ObjectPublisher<Person> var body: some View { ObjectReader(self.person, keyPath: \.fullName) { fullName in Text("Name: \(fullName)") } } ``` By default, an `ObjectReader` does not create its views wheen the object observed is deleted from the store. In those cases, the `placeholder:` argument can be used to provide a custom `View` to display when the object is deleted: ```swift let person: ObjectPublisher<Person> var body: some View { ObjectReader( self.person, content: { objectSnapshot in // ... }, placeholder: { Text("Record not found") } ) } ``` ## SwiftUI Property Wrappers As an alternative to `ListReader` and `ObjectReader`, CoreStore also provides property wrappers that trigger view updates when the data changes. ### `ListState` A `@ListState` property exposes a `ListSnapshot` value that automatically updates to the latest changes. ```swift @ListState var people: ListSnapshot<Person> init(listPublisher: ListPublisher<Person>) { self._people = .init(listPublisher) } var body: some View { List { ForEach(objectIn: self.people) { objectSnapshot in // ... } } .animation(.default) } ``` As shown above, a typical use case is to use it together with CoreStore's [`ForEach` extensions](#foreach). If a `ListPublisher` instance is not available yet, the fetch can be done inline by providing the fetch clauses and the `DataStack` instance. By doing so the property can be declared without an initial value: ```swift @ListState( From<Person>() .sectionBy(\.age) .where(\.isMember == true) .orderBy(.ascending(\.lastName)) ) var people: ListSnapshot<Person> var body: some View { List { ForEach(sectionIn: self.people) { section in Section(header: Text(section.sectionID)) { ForEach(objectIn: section) { person in // ... } } } } .animation(.default) } ``` For other initialization variants, refer to the *ListState.swift* source documentations. ### `ObjectState` An `@ObjectState` property exposes an optional `ObjectSnapshot` value that automatically updates to the latest changes. ```swift @ObjectState var person: ObjectSnapshot<Person>? init(objectPublisher: ObjectPublisher<Person>) { self._person = .init(objectPublisher) } var body: some View { HStack { if let person = self.person { AsyncImage(person.$avatarURL) Text(person.$fullName) } else { Text("Record removed") } } } ``` As shown above, the property's value will be `nil` if the object has been deleted, so this can be used to display placeholders if needed. ## SwiftUI Extensions For convenience, CoreStore provides extensions to the standard SwiftUI types. ### `ForEach` Several `ForEach` initializer overloads are available. Choose depending on your input data and the expected closure data. Refer to the table below (Take note of the argument labels as they are important): <table> <tr><th>Data</th><th>Example</th></tr> <tr> <td> Signature: <pre lang=swift> ForEach(_: [ObjectSnapshot&lt;O&gt;]) </pre> Closure: <pre lang=swift> ObjectSnapshot&lt;O&gt; </pre> </td> <td><pre lang=swift> let array: [ObjectSnapshot&lt;Person&gt;] <br /> var body: some View { <br /> List { <br /> ForEach(self.array) { objectSnapshot in <br /> // ... } } } </pre></td> </tr> <tr> <td> Signature: <pre lang=swift> ForEach(objectIn: ListSnapshot&lt;O&gt;) </pre> Closure: <pre lang=swift> ObjectPublisher&lt;O&gt; </pre> </td> <td><pre lang=swift> let listSnapshot: ListSnapshot&lt;Person&gt; <br /> var body: some View { <br /> List { <br /> ForEach(objectIn: self.listSnapshot) { objectPublisher in <br /> // ... } } } </pre></td> </tr> <tr> <td> Signature: <pre lang=swift> ForEach(objectIn: [ObjectSnapshot&lt;O&gt;]) </pre> Closure: <pre lang=swift> ObjectPublisher&lt;O&gt; </pre> </td> <td><pre lang=swift> let array: [ObjectSnapshot&lt;Person&gt;] <br /> var body: some View { <br /> List { <br /> ForEach(objectIn: self.array) { objectPublisher in <br /> // ... } } } </pre></td> </tr> <tr> <td> Signature: <pre lang=swift> ForEach(sectionIn: ListSnapshot&lt;O&gt;) </pre> Closure: <pre lang=swift> [ListSnapshot&lt;O&gt;.SectionInfo] </pre> </td> <td><pre lang=swift> let listSnapshot: ListSnapshot&lt;Person&gt; <br /> var body: some View { <br /> List { <br /> ForEach(sectionIn: self.listSnapshot) { sectionInfo in <br /> // ... } } } </pre></td> </tr> <tr> <td> Signature: <pre lang=swift> ForEach(objectIn: ListSnapshot&lt;O&gt;.SectionInfo) </pre> Closure: <pre lang=swift> ObjectPublisher&lt;O&gt; </pre> </td> <td><pre lang=swift> let listSnapshot: ListSnapshot&lt;Person&gt; <br /> var body: some View { <br /> List { <br /> ForEach(sectionIn: self.listSnapshot) { sectionInfo in <br /> ForEach(objectIn: sectionInfo) { objectPublisher in <br /> // ... } } } } </pre></td> </tr> </table>
New Demo app, Swift 5.3 / Xcode 12 / iOS 14 Support
3 years ago
## New Demo app The old *CoreStoreDemo* app has been renamed to *LegacyDemo*, and a new *Demo* app now showcases CoreStore features through SwiftUI: <img width=320 src="https://user-images.githubusercontent.com/3029684/93660694-6a0fb080-fa8c-11ea-979f-78fca77fc9e2.png" /> Don't worry, standard UIKit samples are also available (thanks to `UIViewControllerRepresentable`) Feel free to suggest improvements to the Demo app! ## Swift 5.3 / Xcode 12 / iOS 14 Support CoreStore now compiles using Xcode 12 and Swift 5.3! ⚠️ There was a bug in Swift 5.3 `propertyWrappers` where [Segmentation Faults happen during compile time](https://bugs.swift.org/browse/SR-13069). CoreStore was able to work around this issue through [runtime `fatalError`s](https://github.com/JohnEstropia/CoreStore/blob/3b6f226389efe1116fa1818bf062aea42d89dd0a/Sources/Field.Stored.swift#L72), but the result is that missing required parameters for `@Field` properties may not be caught during compile-time. The runtime checks crash if there are missing parameters, so please take care to debug your models!
dynamicInitialValue support for @Field.Stored and @Field.Coded properties
3 years ago
# Default values vs. Initial values One common mistake when assigning default values to `CoreStoreObject` properties is to assign it a value and expect it to be evaluated whenever an object is created: ```swift // ❌ class Person: CoreStoreObject { @Field.Stored("identifier") var identifier: UUID = UUID() // Wrong! @Field.Stored("createdDate") var createdDate: Date = Date() // Wrong! } ``` This default value will be evaluated only when the `DataStack` sets up the schema, and all instances will end up having the same values. This syntax for "default values" are usually used only for actual reasonable constant values, or sentinel values such as `""` or `0`. For actual "initial values", `@Field.Stored` and `@Field.Coded` now supports dynamic evaluation during object creation via the `dynamicInitialValue:` argument: ```swift // ✅ class Person: CoreStoreObject { @Field.Stored("identifier", dynamicInitialValue: { UUID() }) var identifier: UUID @Field.Stored("createdDate", dynamicInitialValue: { Date() }) var createdDate: Date } ``` When using this feature, a "default value" should not be assigned (i.e. no `=` expression).
Swift 5.2 / Xcode 11.4, New `Field` PropertyWrappers
4 years ago
# Maintenance updates - Xcode 11.4 and Swift 5.2 support # New Property Wrappers syntax ⚠️ These changes apply only to `CoreStoreObject` subclasses, not`NSManagedObject`s. ‼️ Please take note of the warnings below before migrating or else the model's hash might change. **If conversion is too risky, the current `Value.Required`, `Value.Optional`, `Transformable.Required`, `Transformable.Optional`, `Relationship.ToOne`, `Relationship.ToManyOrdered`, and `Relationship.ToManyUnordered` will all be supported for while so you can opt to use them as is for now.** ‼️ If you are confident about conversion, I cannot stress this enough, but please make sure to set your schema's `VersionLock` before converting! ### `@Field.Stored` (replacement for non "transient" `Value.Required` and `Value.Optional`) ```swift class Person: CoreStoreObject { @Field.Stored("title") var title: String = "Mr." @Field.Stored("nickname") var nickname: String? } ``` ⚠️ Only `Value.Required` and `Value.Optional` that are NOT transient values can be converted to `Field.Stored`. ⚠️ When converting, make sure that all parameters, including the default values, are exactly the same or else the model's hash might change. ### `@Field.Virtual` (replacement for "transient" versions of `Value.Required` and`Value.Optional`) ```swift class Animal: CoreStoreObject { @Field.Virtual( "pluralName", customGetter: { (object, field) in return object.$species.value + "s" } ) var pluralName: String @Field.Stored("species") var species: String = "" } ``` ⚠️ Only `Value.Required` and `Value.Optional` that ARE transient values can be converted to `Field.Virtual`. ⚠️ When converting, make sure that all parameters, including the default values, are exactly the same or else the model's hash might change. ### `@Field.Coded` (replacement for `Transformable.Required` and`Transformable.Optional`, with additional support for custom encoders such as JSON) ```swift class Person: CoreStoreObject { @Field.Coded( "bloodType", coder: { encode: { $0.toData() }, decode: { BloodType(fromData: $0) } } ) var bloodType: BloodType? } ``` ‼️ The current `Transformable.Required` and `Transformable.Optional` mechanism have no safe conversion to `@Field.Coded`. Please use `@Field.Coded` only for newly added attributes. ### `@Field.Relationship` (replacement for `Relationship.ToOne`, `Relationship.ToManyOrdered`, and `Relationship.ToManyUnordered`) ```swift class Pet: CoreStoreObject { @Field.Relationship("master") var master: Person? } class Person: CoreStoreObject { @Field.Relationship("pets", inverse: \.$master) var pets: Set<Pet> } ``` ⚠️ `Relationship.ToOne<T>` maps to `T?`, `Relationship.ToManyOrdered` maps to `Array<T>`, and `Relationship.ToManyUnordered` maps to `Set<T>` ⚠️ When converting, make sure that all parameters, including the default values, are exactly the same or else the model's hash might change. ## Usage Before diving into the properties themselves, note that they will effectively force you to use a different syntax for queries: - Before: `From<Person>.where(\.title == "Mr.")` - After: `From<Person>.where(\.$title == "Mr.")` There are a several advantages to using these Property Wrappers: - The `@propertyWrapper` versions will be magnitudes performant and efficient than their current implementations. Currently `Mirror` reflection is used a lot to inject the `NSManagedObject` reference into the properties. With `@propertyWrapper`s this will be synthesized by the compiler for us. (See https://github.com/apple/swift/pull/25884) - The `@propertyWrapper` versions, being `struct`s, will give the compiler a lot more room for optimizations which were not possible before due to the need for mutable classes. - You can now add computed properties that are accessible to both `ObjectSnapshot`s and `ObjectPublisher`s by declaring them as `@Field.Virtual`. Note that for `ObjectSnapshot`s, the computed values are evaluated only once during creation and are not recomputed afterwards. The only disadvantage will be: - You need to update your code by hand to migrate to the new `@propertyWrapper`s (But the legacy ones will remain available for quite a while, so while it is recommended to migrate soon, no need to panic)
Swift 5.1 (Breaking Changes), ListPublisher, ObjectPublisher, DiffableDataSources
4 years ago
⚠️This update will break current code. Make sure to read the changes below: # Breaking Changes Starting version `7.0.0`, CoreStore will be using a lot of Swift 5.1 features, both internally and in its public API. You can keep using the last [`6.3.2`](https://github.com/JohnEstropia/CoreStore/tree/6.3.2) release if you still need Swift 5.0. # Deprecations The `CoreStore`-namespaced API has been deprecated in favor of `DataStack` method calls. If you are using the global utilities such as `CoreStore.defaultStack` and `CoreStore.logger`, a new `CoreStoreDefaults` namespace has been provided: - `CoreStore.defaultStack` -> `CoreStoreDefaults.dataStack` - `CoreStore.logger` -> `CoreStoreDefaults.logger` - `CoreStore.addStorage(...)` -> `CoreStoreDefaults.dataStack.addStorage(...)` - `CoreStore.fetchAll(...)` -> `CoreStoreDefaults.dataStack.fetchAll(...)` - etc. If you have been using your own properties to store `DataStack` references, then you should not be affected by this change. # New features ## Backwards-portable DiffableDataSources implementation `UITableViews` and `UICollectionViews` now have a new ally: `ListPublisher`s provide diffable snapshots that make reloading animations very easy and very safe. Say goodbye to `UITableViews` and `UICollectionViews` reload errors! ### DiffableDataSource.CollectionView (iOS and macOS) and DiffableDataSource.TableView (iOS) ```swift self.dataSource = DiffableDataSource.CollectionView<Person>( collectionView: self.collectionView, dataStack: CoreStoreDefaults.dataStack, cellProvider: { (collectionView, indexPath, person) in let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PersonCell") as! PersonCell cell.setPerson(person) return cell } ) ``` This is now the recommended method of reloading `UITableView`s and `UICollectionView`s because it uses list diffing to update your list views. This means that it is a lot less prone to cause layout errors. ### ListPublisher and ListSnapshot `ListPublisher` is a more lightweight counterpart of `ListMonitor`. Unlike `ListMonitor`, it does not keep track of minute inserts, deletes, moves, and updates. It simply updates its `snapshot` property which is a `struct` storing the list state at a specific point in time. This `ListSnapshot` is then usable with the `DiffableDataSource` utilities (See section above). ```swift self.listPublisher = dataStack.listPublisher( From<Person>() .sectionBy(\.age") { "Age \($0)" } // sections are optional .where(\.title == "Engineer") .orderBy(.ascending(\.lastName)) ) self.listPublisher.addObserver(self) { [weak self] (listPublisher) in self?.dataSource?.apply( listPublisher.snapshot, animatingDifferences: true ) } ``` `ListSnapshot`s store only `NSManagedObjectID`s and their sections. ### ObjectPublisher and ObjectSnapshot `ObjectPublisher` is a more lightweight counterpart of `ObjectMonitor`. Unlike `ObjectMonitor`, it does not keep track of per-property changes. You can create an `ObjectPublisher` from the object directly: ```swift let objectPublisher: ObjectPublisher<Person> = person.asPublisher(in: dataStack) ``` or by indexing a `ListPublisher`'s `ListSnapshot`: ```swift let objectPublisher = self.listPublisher.snapshot[indexPath] ``` The `ObjectPublisher` exposes a `snapshot` property which returns an `ObjectSnapshot`, which is a lazily generated `struct` containing fully-copied property values. ```swift objectPublisher.addObserver(self) { [weak self] (objectPublisher) in let snapshot: ObjectSnapshot<Person> = objectPublisher.snapshot // handle changes } ``` This snapshot is completely thread-safe, and any mutations to it will not affect the actual object. ## Intent-based Object representations CoreStore is slowly moving to abstract object utilities based on usage intent. `NSManageObject', `CoreStoreObject`, `ObjectPublisher`, and `ObjectSnapshot` all conform to the `ObjectRepresentation` protocol, which allows conversion of each type to another: ```swift public protocol ObjectRepresentation { associatedtype ObjectType : CoreStore.DynamicObject func objectID() -> ObjectType.ObjectID func asPublisher(in dataStack: DataStack) -> ObjectPublisher<ObjectType> func asReadOnly(in dataStack: DataStack) -> ObjectType? func asEditable(in transaction: BaseDataTransaction) -> ObjectType? func asSnapshot(in dataStack: DataStack) -> ObjectSnapshot<ObjectType>? func asSnapshot(in transaction: BaseDataTransaction) -> ObjectSnapshot<ObjectType>? } ``` `ObjectMonitor` being excluded in this family was intentional; its initialization is complex enough to be an API of its own.
Swift 5 + Deprecation Cleanup
5 years ago
- CoreStore now builds on Swift 5 and Xcode 10.2 - `SetupResult<T>`, `MigrationResult`, and `AsynchronousDataTransaction.Result<T>` have all been converted into `typealias`es for `Swift.Result<T, CoreStoreError>`. The benefit is we can now use the utility methods on `Swift.Result` such as `map()`, `mapError()`, etc. Their Objective-C counterparts (`CSSetupResult`, etc.) remain available and can still be used as before. - Bunch of deprecated/obsoleted stuff deleted - CoreData iCloud support had been deprecated for a while now and CoreStore finally removes its support in this version. If you wish to continue using it please continue to use the 6.2.x versions but it will be unlikely to get bugfixes from here on out so please try to migrate your app's data as soon as possible (iOS and macOS already had this deprecated for years)
Min Deployment = iOS 10 (Breaking changes)
5 years ago
⚠️This update will break current code. Make sure to read the changes below: ## Breaking changes - Minimum Deployment Version is raised to `iOS 10`, `macOS 10.12`, `tvOS 10`, `watchOS 3` - `ICloudStore` and `ICloudStoreObserver`s are now officially deprecated (iCloud Core Data had been deprecated quite a long time ago). - Fetching and Querying methods now `throws` an error of type `CoreStoreError.persistentStoreNotFound(DynamicObject.Type)` when the specified entity does not exist in any storage. This is to distinguish difference between non-existing objects versus non-existing stores. ```swift // Before if let object = CoreStore.fetchOne(...) { // ... } else { // May be nil because `addStorage()` hasn't completed yet or because nothing really matches the query } ``` ```swift // After do { if let object = try CoreStore.fetchOne(...) { // ... } else { // `addStorage()` has completed but nothing matches the query } } catch { // method was called before `addStorage()` completed } ``` If you are sure you won't encounter cases where fetches happen before a storage is added to the `DataStack`, simply add `try!` to your `fetch*()` and `query*()` method calls. ## Conveniences - `CoreStoreObject`s (as well as their `PartialObject` counterparts) now conform to `CustomDebugStringConvertable` by default. - `CoreStoreObject`s now assert on property names that possibly collide with reserved names such as `description` - `CoreStoreObject` properties can now be observed individually without the need for `ObjectMonitor`s. The API is a bit similar to the standard KVO API: ```swift // NSManagedObject let observer = person.observe(\.friends, options: [.new, .old]) { (person, change) in // ... } // CoreStoreObject let observer = person.friends.observe(options: [.new, .old]) { (person, change) in // ... } ``` You may still use `ObjectMonitor`s especially for observing multiple changes at once. - CoreStore now has its own Playgrounds file! You can find this at the top of the workspace (run `pod try CoreStore` if you don't have it locally). You will need to build the `CoreStore iOS` schema at least once to create the framework used by the Playgrounds. ## Improvements - Fixed queue assertion for `UnsafeDataTransaction`s (https://github.com/JohnEstropia/CoreStore/pull/275) - `ListMonitor` access performance boost (https://github.com/JohnEstropia/CoreStore/pull/287, https://github.com/JohnEstropia/CoreStore/pull/288) - Added a new `CoreStoreError.asynchronousMigrationRequired(URL)` for cases when `addStorageAndWait()` is used together with `.allowSynchronousLightweightMigration` but migrations are only allowed asynchronously (#277) - [CoreStore docs](https://johnestropia.github.io/CoreStore) are now powered by [jazzy](https://github.com/realm/jazzy) - Fixed issue with `InferredSchemaMappingProvider` not respecting renaming identifiers (https://github.com/JohnEstropia/CoreStore/pull/301)
Swift 4: Generic Clauses, Fetch and Query Chain Builders, Smart KeyPaths
6 years ago
This release builds on Swift 4. ## Generic Clauses Most fetch and query clauses such as `Where`, `OrderBy`, etc. are now generic types. In effect, clauses using the previous fetching/querying calls need to indicate their generic type: ```swift var people = CoreStore.fetchAll( From<MyPersonEntity>(), Where<MyPersonEntity>("%K > %d", "age", 30), OrderBy<MyPersonEntity>(.ascending("name")) ) ``` This is quite repetitive. To make this even more convenient, CoreStore now has fetch/query builders. ## Fetch and Query Chain Builders ```swift var people = CoreStore.fetchAll( From<MyPersonEntity>() .where(format: "%K > %d", "age", 30) .orderBy(.ascending("name")) ) ``` This way the generic type is propagated onto subsequent clauses. But we can improve this further. ## Smart KeyPaths Using Swift 4's type-safe keypaths, we can make our fetch/query expressions even more solid. ```swift var people = CoreStore.fetchAll( From<MyPersonEntity>() .where(\.age > 30) .orderBy(.ascending(\.name)) ) ``` All CoreStore API that accepts a string keypath now accepts these Smart Keypaths. (If I missed some, please post a github issue)
Swift 3.2 Support (Xcode 9)
6 years ago
- `typealias KeyPath = String` was changed to `typealias RawKeyPath = String`
iOS macOS watchOS tvOS

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics