Skip to content

Commit

Permalink
Merge pull request #552 from groue/GRDB-4.1
Browse files Browse the repository at this point in the history
GRDB 4.1
  • Loading branch information
groue authored Jun 20, 2019
2 parents 6a5d3fe + cb517dc commit de3f32b
Show file tree
Hide file tree
Showing 132 changed files with 7,778 additions and 4,106 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ SQLiteCustom/GRDBCustomSQLite-USER.xcconfig

# CocoaPods test
Pods
Podfile.lock

# SPM
.build
Expand Down
140 changes: 140 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ All notable changes to this project will be documented in this file.

GRDB adheres to [Semantic Versioning](https://semver.org/), with one expection: APIs flagged [**:fire: EXPERIMENTAL**](README.md#what-are-experimental-features). Those are unstable, and may break between any two minor releases of the library.

<!--
[Next Release](#next-release)
-->

#### 4.x Releases

- `4.1.x` Releases - [4.1.0](#410)
- `4.0.x` Releases - [4.0.0](#400) | [4.0.1](#401)

#### 3.x Releases
Expand Down Expand Up @@ -46,6 +51,141 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one expection:

- [0.110.0](#01100), ...

<!--
## Next Release
-->

## 4.1.0

Released June 20, 2019 &bull; [diff](https://github.com/groue/GRDB.swift/compare/v4.0.1...v4.1.0)

- [#537](https://github.com/groue/GRDB.swift/pull/537): Remove useless parenthesis from generated SQL
- [#538](https://github.com/groue/GRDB.swift/pull/538) by [@Timac](https://github.com/Timac): Add FAQ to clarify "Wrong number of statement arguments" error with "like '%?%'"
- [#539](https://github.com/groue/GRDB.swift/pull/539): Expose joining methods on both requests and associations
- [#540](https://github.com/groue/GRDB.swift/pull/540): Update SQLite to 3.28.0 (thanks to [@swiftlyfalling](https://github.com/swiftlyfalling/SQLiteLib))
- [#542](https://github.com/groue/GRDB.swift/pull/542): Move eager loading of hasMany associations to FetchRequest
- [#546](https://github.com/groue/GRDB.swift/pull/546) by [@robcas3](https://github.com/robcas3): Fix SPM errors with Xcode 11 beta
- [#549](https://github.com/groue/GRDB.swift/pull/549) Support for Combine
- [#550](https://github.com/groue/GRDB.swift/pull/550) Asynchronous Database Access Methods
- [#555](https://github.com/groue/GRDB.swift/pull/555) Avoid a crash when read-only access can't be established

### Documentation Diff

Good practices evolve: the [Define Record Requests](Documentation/GoodPracticesForDesigningRecordTypes.md#define-record-requests) chapter of the The [Good Practices for Designing Record Types](Documentation/GoodPracticesForDesigningRecordTypes.md) has been rewritten.

The [Examples of Record Definitions](README.md#examples-of-record-definitions) has been extended with a sample record optimized for fetching performance.

The [ValueObservation](README.md#valueobservation) chapter has been updated with new APIs for building observation, and combining observations together in order to avoid data races.

The [ValueObservation Error Handling](README.md#valueobservation-error-handling) chapter explains with more details how to deal with observation errors.

### API Diff

<details>
<summary>Asynchronous database access methods</summary>

```diff
protocol DatabaseReader {
+ var configuration: Configuration { get }
+
+ #if compiler(>=5.0)
+ func asyncRead(_ block: @escaping (Result<Database, Error>) -> Void)
+ #endif
}

protocol DatabaseWriter {
+ func asyncWriteWithoutTransaction(_ updates: @escaping (Database) -> Void)
+
+ #if compiler(>=5.0)
+ func asyncWrite<T>(_ updates: @escaping (Database) throws -> T, completion: @escaping (Database, Result<T, Error>) -> Void)
+ #endif
}
```

</details>

<details>
<summary>ValueObservation changes</summary>

```diff
+extension FetchRequest {
+ func observationForCount() -> ValueObservation<...>
+}
+extension FetchRequest where RowDecoder: ... {
+ func observationForAll() -> ValueObservation<...>
+ func observationForFirst() -> ValueObservation<...>
+)
+extension TableRecord {
+ static func observationForCount() -> ValueObservation<...>
+ static func observationForAll() -> ValueObservation<...>
+ static func observationForFirst() -> ValueObservation<...>
+}
extension ValueObservation where ... {
+ @available(*, deprecated)
static func trackingCount<Request: FetchRequest>(_ request: Request) -> ValueObservation<...>
+ @available(*, deprecated)
static func trackingAll<Request: FetchRequest>(_ request: Request) -> ValueObservation<...>
+ @available(*, deprecated)
static func trackingOne<Request: FetchRequest>(_ request: Request) -> ValueObservation<...>
}
extension ValueObservation where Reducer: ValueReducer {
- func start(in reader: DatabaseReader, onError: ((Error) -> Void)? = nil, onChange: @escaping (Reducer.Value) -> Void) throws -> TransactionObserver
+ func start(in reader: DatabaseReader, onChange: @escaping (Reducer.Value) -> Void) throws -> TransactionObserver
+ func start(in reader: DatabaseReader, onError: @escaping (Error) -> Void, onChange: @escaping (Reducer.Value) -> Void) -> TransactionObserver
+ func combine<..., Combined>(..., transform: @escaping (...) -> Combined) -> ValueObservation<...>
}
extension ValueObservation where Reducer: ValueReducer, Reducer.Value: Equatable {
+ @available(*, deprecated)
func distinctUntilChanged() -> ValueObservation<...>
+ func removeDuplicates() -> ValueObservation<...>
}
```

</details>

<details>
<summary>Joining methods on both requests and associations</summary>

```diff
+protocol JoinableRequest {
+ associatedtype RowDecoder
+}
+
+extension JoinableRequest {
+ func including<A: AssociationToMany>(all association: A) -> Self where A.OriginRowDecoder == RowDecoder
+ func including<A: Association>(optional association: A) -> Self where A.OriginRowDecoder == RowDecoder
+ func including<A: Association>(required association: A) -> Self where A.OriginRowDecoder == RowDecoder
+ func joining<A: Association>(optional association: A) -> Self where A.OriginRowDecoder == RowDecoder
+ func joining<A: Association>(required association: A) -> Self where A.OriginRowDecoder == RowDecoder
+}

-protocol DerivableRequest: SelectionRequest, FilteredRequest, OrderedRequest { }
+protocol DerivableRequest: SelectionRequest, FilteredRequest, OrderedRequest, JoinableRequest { }
```

</details>

<details>
<summary>FetchRequest changes</summary>

```diff
+struct PreparedRequest {
+ var statement: SelectStatement
+ var adapter: RowAdapter?
+ init(statement: SelectStatement, adapter: RowAdapter? = nil)
+}

protocol FetchRequest {
+ // deprecated
func prepare(_ db: Database, forSingleResult singleResult: Bool) throws -> (SelectStatement, RowAdapter?)
+ func makePreparedRequest(_ db: Database, forSingleResult singleResult: Bool) throws -> PreparedRequest
}
```

The core FetchRequest preparation method is now `makePreparedRequest(_:forSingleResult:)`. The former core method `prepare(_:forSingleResult:)` will remain a requirement of the FetchRequest protocol until GRDB 5 due to semantic versioning constraints. Both methods are provided with a default implementation which makes each one depend on the other: this creates an infinite loop unless you provide at least one of them. If you have a choice, implement only `makePreparedRequest(_:forSingleResult:)`.

</details>


## 4.0.1

Expand Down
2 changes: 2 additions & 0 deletions DemoApps/GRDBDemoiOS/GRDBDemoiOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,13 @@
568E5FCA1E926430002582E0 = {
CreatedOnToolsVersion = 8.3;
DevelopmentTeam = AMD8W895CT;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
56B036021E8D9EBE003B6DA4 = {
CreatedOnToolsVersion = 8.3;
DevelopmentTeam = AMD8W895CT;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
};
Expand Down
11 changes: 7 additions & 4 deletions DemoApps/GRDBDemoiOS/GRDBDemoiOS/PlayersViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,18 @@ class PlayersViewController: UITableViewController {

private func configureTitle() {
// Track changes in the number of players
playerCountObserver = try! ValueObservation
.trackingCount(playersRequest)
.start(in: dbQueue) { [unowned self] count in
playerCountObserver = playersRequest.observationForCount().start(
in: dbQueue,
onError: { error in
fatalError("Unexpected error: \(error)")
},
onChange: { [unowned self] count in
switch count {
case 0: self.navigationItem.title = "No Player"
case 1: self.navigationItem.title = "1 Player"
default: self.navigationItem.title = "\(count) Players"
}
}
})
}

private func configureTableView() {
Expand Down
9 changes: 5 additions & 4 deletions Documentation/AssociationsBasics.md
Original file line number Diff line number Diff line change
Expand Up @@ -827,11 +827,12 @@ Those requests can also turn out useful when you want to track their changes wit
```swift
// Track changes in the author's books:
let author: Author = ...
ValueObservation
.trackingAll(author.books)
.start(in: dbQueue) { (books: [Book]) in
author.books.observationForAll().start(
in: dbQueue,
onError: { error in ... },
onChange: { (books: [Book]) in
print("Author's book have changed")
}
})
```


Expand Down
4 changes: 2 additions & 2 deletions Documentation/CustomSQLiteBuilds.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Custom SQLite Builds

By default, GRDB uses the version of SQLite that ships with the target operating system.

**You can build GRDB with a custom build of [SQLite 3.27.2](https://www.sqlite.org/changes.html).**
**You can build GRDB with a custom build of [SQLite 3.28.0](https://www.sqlite.org/changes.html).**

A custom SQLite build can activate extra SQLite features, and extra GRDB features as well, such as support for the [FTS5 full-text search engine](../../../#full-text-search), and [SQLite Pre-Update Hooks](../../../#support-for-sqlite-pre-update-hooks).

Expand All @@ -15,7 +15,7 @@ GRDB builds SQLite with [swiftlyfalling/SQLiteLib](https://github.com/swiftlyfal

```sh
cd [GRDB directory]
git checkout v4.0.1
git checkout v4.1.0
git submodule update --init SQLiteCustom/src
````

Expand Down
13 changes: 8 additions & 5 deletions Documentation/GRDB3MigrationGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ To guarantee asynchronous notifications, and never ever block your main thread,

```swift
// On main queue
var observation = ValueObservation.trackingAll(Player.all())
var observation = Player.observationForAll()
observation.scheduling = .async(onQueue: .main, startImmediately: true)
let observer = try observation.start(in: dbQueue) { (players: [Player]) in
// On main queue
print("fresh players: \(players)")s
}
let observer = try observation.start(
in: dbQueue,
onError: { error in ... },
onChange: { (players: [Player]) in
// On main queue
print("fresh players: \(players)")s
})
// <- here "fresh players" is not printed yet.
```

Expand Down
Loading

0 comments on commit de3f32b

Please sign in to comment.