Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved support for values observation #435

Merged
merged 109 commits into from
Nov 2, 2018
Merged
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
33927e7
FetchResultsObserver
groue Oct 23, 2018
ce95ff7
Move towards observation from reader
groue Oct 24, 2018
e5d97c1
Looking for a good API
groue Oct 25, 2018
fda04a1
ValueObservation: extract callbacks
groue Oct 25, 2018
fe0f238
Cleanup
groue Oct 25, 2018
0df4815
Move ValueObservation support to DatabaseReader
groue Oct 25, 2018
2341523
API cleanup
groue Oct 26, 2018
9c71356
Honor ValueObservation.readonly
groue Oct 26, 2018
08b103f
DatabaseReader and DatabaseWriter are no longer available for user types
groue Oct 26, 2018
abe6957
Typo
groue Oct 26, 2018
69853d7
Now that user implementations of DatabaseWriter are no longer support…
groue Oct 26, 2018
f694437
Add missing public qualifiers
groue Oct 27, 2018
31b688d
ValueObservationn has a QoS
groue Oct 27, 2018
ff4f6f3
Cleanup
groue Oct 27, 2018
697b2af
Wrap long lines
groue Oct 27, 2018
de227bd
Bake uniquing right into ValueObservation: introduce ValueReducer
groue Oct 27, 2018
052d2e3
Value (string, int, etc.) observation, with uniquing
groue Oct 27, 2018
82efe7c
AnyValueReducer
groue Oct 27, 2018
7c44626
ValueObservation creation is always done with a factory initializer
groue Oct 27, 2018
ec5451e
Cleanup
groue Oct 27, 2018
a043c4c
QoS are hard
groue Oct 27, 2018
fc3aca7
Replace InitialDispatch with ValueScheduling
groue Oct 28, 2018
09581c6
ValueObservation factory requires a DatabaseRegionConvertible. Introd…
groue Oct 28, 2018
26ba576
whitespace
groue Oct 28, 2018
e0a9cce
First tests for ValueObservation: focus on reducers
groue Oct 28, 2018
2b78479
More ValueReducer tests: error
groue Oct 28, 2018
627e8ec
Fix wrong documentation
groue Oct 28, 2018
a519a4a
Documentation
groue Oct 28, 2018
087989f
More ValueObseervation tests: extent
groue Oct 28, 2018
cbe505f
Cleanup
groue Oct 28, 2018
471808f
More ValueObseervation tests: fetch, with and without uniquing
groue Oct 28, 2018
f303664
Cleanup
groue Oct 28, 2018
f2c3c21
Read-only observation is enforced. When not read-only, savepoint is e…
groue Oct 28, 2018
31e6dde
ValueObservation: test scheduling
groue Oct 28, 2018
62f6cfe
ValueObservation: count tests
groue Oct 28, 2018
0010be4
ValueObservation: row tests
groue Oct 28, 2018
0d5adfe
ValueObservation: FetchableRecord & DatabaseValueConvertible tests
groue Oct 28, 2018
de2823b
ValueObservation: StatementColumnConvertible tests
groue Oct 28, 2018
1581773
Documentation
groue Oct 28, 2018
470e153
Documentation
groue Oct 28, 2018
840f835
Documentation
groue Oct 29, 2018
489454b
add(observation:observation) -> start(observation)
groue Oct 29, 2018
22ed0fb
Documentation
groue Oct 29, 2018
03d2bc4
Documentation
groue Oct 29, 2018
29b54dd
Documentation
groue Oct 29, 2018
38e4027
Documentation
groue Oct 29, 2018
1d47853
Documentation
groue Oct 29, 2018
8d6ec62
Backport Sequence.allSatisfy in Swift 4.1
groue Oct 29, 2018
9332630
Documentation
groue Oct 29, 2018
f59dba7
Try with "tracking"
groue Oct 29, 2018
5a540e8
Documentation
groue Oct 29, 2018
191607f
Documentation
groue Oct 29, 2018
a4b3572
Documentation
groue Oct 29, 2018
f582683
Move remove(transactionObserver:) to DatabaseReader
groue Oct 29, 2018
f771247
Move Sequence.allSatisfy where it is used: tests
groue Oct 29, 2018
1985b91
Fix SPM build
groue Oct 29, 2018
a489959
Typo
groue Oct 29, 2018
669b9c4
Test for the ValueReducer documented in README
groue Oct 29, 2018
72c5769
ValueScheduling.unsafe
groue Oct 29, 2018
e5f43e3
ValueScheduling.unsafe guarantees that initial value is notified on t…
groue Oct 29, 2018
4e40d75
Documentation
groue Oct 29, 2018
7353946
Documentation
groue Oct 29, 2018
1065070
Documentation (todo: document error handling)
groue Oct 29, 2018
739c325
Documentation
groue Oct 29, 2018
77de519
More tests for read/write observations
groue Oct 29, 2018
53f98a7
Documentation
groue Oct 29, 2018
f68b1cd
Documentation
groue Oct 29, 2018
6f86cbf
Documentation
groue Oct 29, 2018
b4b824c
dbQueue.start(observation) -> observation.start(in: dbQueue)
groue Oct 29, 2018
4e3b7c1
Documentation
groue Oct 29, 2018
cdd7579
Documentation
groue Oct 29, 2018
d3838d1
ValueObservation error handling
groue Oct 29, 2018
22b5990
Documentation
groue Oct 29, 2018
c4d3287
Documentation
groue Oct 30, 2018
8e13cb4
Cleanup
groue Oct 30, 2018
cca716e
Cleanup
groue Oct 30, 2018
3d21773
CHANGELOG
groue Oct 30, 2018
741f0b2
CHANGELOG
groue Oct 30, 2018
a276a49
CHANGELOG
groue Oct 30, 2018
0e51a0f
Documentation
groue Oct 30, 2018
6fa72eb
Documentation
groue Oct 30, 2018
04de619
Documentation
groue Oct 31, 2018
9babbcb
README: foster ValueObservation
groue Oct 31, 2018
bb02d9d
ValueObservation.map
groue Oct 31, 2018
30363b4
Tests for ValueObservation.map
groue Oct 31, 2018
44af4e6
Documentation
groue Oct 31, 2018
eb95562
Documentation
groue Oct 31, 2018
7e8ebed
Documentation
groue Oct 31, 2018
38e1cc9
Use ValueObservation is demo application
groue Nov 1, 2018
5194204
Avoid the "No output has been received in the last 10m0s" error on Tr…
groue Nov 1, 2018
74ca85e
More links to the demo app
groue Nov 1, 2018
d53412d
Documentation
groue Nov 1, 2018
1867ee9
Documentation
groue Nov 1, 2018
f7b79e0
Attempt at addressing https://github.com/groue/GRDB.swift/issues/430
groue Nov 1, 2018
842eaf0
ValueObservation: perform uniquing by default
groue Nov 1, 2018
087a899
Rename ValueObservation.tracking(withUniquing:fetch) to ValueObservat…
groue Nov 1, 2018
ab7970d
Documentation
groue Nov 1, 2018
bc274a6
Documentation
groue Nov 2, 2018
257fc8b
Cleanup
groue Nov 2, 2018
2bc8f33
Cleanup
groue Nov 2, 2018
c48d2e4
Documentation
groue Nov 2, 2018
c300cf2
Documentation
groue Nov 2, 2018
7d9e870
Rename ValueObservation.isReadOnly to requiresWriteAccess
groue Nov 2, 2018
a1a5165
Documentation
groue Nov 2, 2018
50213c9
Documentation
groue Nov 2, 2018
8c5e3df
Documentation
groue Nov 2, 2018
296a1d5
CHANGELOG
groue Nov 2, 2018
b3c7fec
Documentation
groue Nov 2, 2018
07bf588
Adding more reactive engines is no longer hard
groue Nov 2, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 122 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,127 @@
Release Notes
=============

## Next Version

This release comes with **[ValueObservation](README.md#valueobservation)**, a new type which tracks the results of database requests, and notifies fresh values whenever the database changes:

```swift
let observer = ValueObversation
.trackingOne(Player.filter(key: 42))
.start(in: dbQueue) { player: Player? in
print("Player has changed")
}
```

ValueObservation also aims at providing support for third-party code that needs to react to database changes. For example, [RxSwiftCommunity/RxGRDB#46](https://github.com/RxSwiftCommunity/RxGRDB/pull/46) is the pull request which implements RxGRDB, the companion library based on [RxSwift](https://github.com/ReactiveX/RxSwift), on top of ValueObservation.


### New

- [#435](https://github.com/groue/GRDB.swift/pull/435): Improved support for values observation
- It is now possible to observe database change from a [DatabaseReader](https://groue.github.io/GRDB.swift/docs/3.5/Protocols/DatabaseReader.html).


### Breaking Change

It used to be possible to define custom types that adopt the [DatabaseReader and DatabaseWriter protocols](README.md#databasewriter-and-databasereader-protocols), with a major drawback: it was impossible to add concurrency-related APIs to GRDB without breaking user code. Now all types that adopt those protocols are defined by GRDB: DatabaseQueue, DatabasePool, DatabaseSnapshot, AnyDatabaseReader, and AnyDatabaseWriter. **Expanding this set is no longer supported.**


### Documentation Diff

- [ValueObservation](README.md#valueobservation): this new chapter describes the new way to observe database values.


### API diff

```diff
protocol DatabaseReader: class {
+ func add<Reducer: ValueReducer>(
+ observation: ValueObservation<Reducer>,
+ onError: ((Error) -> Void)?,
+ onChange: @escaping (Reducer.Value) -> Void)
+ throws -> TransactionObserver
+ func remove(transactionObserver: TransactionObserver)
}

protocol DatabaseWriter: DatabaseReader {
- func remove(transactionObserver: TransactionObserver)
}

+protocol DatabaseRegionConvertible {
+ func databaseRegion(_ db: Database) throws -> DatabaseRegion
+}
+
+extension DatabaseRegion: DatabaseRegionConvertible { }
+
+struct AnyDatabaseRegionConvertible: DatabaseRegionConvertible {
+ init(_ region: @escaping (Database) throws -> DatabaseRegion)
+ init(_ region: DatabaseRegionConvertible)
+}

-protocol FetchRequest { ... }
+protocol FetchRequest: DatabaseRegionConvertible { ... }

+enum ValueScheduling {
+ case mainQueue
+ case onQueue(DispatchQueue, startImmediately: Bool)
+ case unsafe(startImmediately: Bool)
+}

+protocol ValueReducer {
+ associatedtype Fetched
+ associatedtype Value
+ func fetch(_ db: Database) throws -> Fetched
+ mutating func value(_ fetched: Fetched) -> Value?
+}
+
+extension ValueReducer {
+ func map<T>(_ transform: @escaping (Value) -> T?) -> MapValueReducer<Self, T>
+}
+
+struct AnyValueReducer<Fetched, Value>: ValueReducer {
+ init(fetch: @escaping (Database) throws -> Fetched, value: @escaping (Fetched) -> Value?)
+ init<Reducer: ValueReducer>(_ reducer: Reducer) where Reducer.Fetched == Fetched, Reducer.Value == Value
+}

+struct ValueObservation<Reducer> {
+ var extent: Database.TransactionObservationExtent
+ var requiresWriteAccess: Bool
+ var scheduling: ValueScheduling
+ static func tracking(_ regions: DatabaseRegionConvertible..., reducer: Reducer) -> ValueObservation
+}
+
+extension ValueObservation where Reducer: ValueReducer {
+ func map<T>(_ transform: @escaping (Reducer.Value) -> T)
+ -> ValueObservation<MapValueReducer<Reducer, T>>
+ func start(
+ in reader: DatabaseReader,
+ onError: ((Error) -> Void)? = nil,
+ onChange: @escaping (Reducer.Value) -> Void) throws -> TransactionObserver
+}
+
+extension ValueObservation where Reducer == Void {
+ static func tracking<Value>(
+ _ regions: DatabaseRegionConvertible...,
+ fetch: @escaping (Database) throws -> Value)
+ -> ValueObservation<ValueReducers.Raw<Value>>
+
+ static func tracking<Value>(
+ _ regions: DatabaseRegionConvertible...,
+ fetchDistinct: @escaping (Database) throws -> Value)
+ -> ValueObservation<ValueReducers.Distinct<Value>>
+ where Value: Equatable
+
+ static func trackingCount<Request: FetchRequest>(_ request: Request)
+ -> ValueObservation<ValueReducers.Raw<Int>>
+ static func trackingAll<Request: FetchRequest>(_ request: Request)
+ -> ValueObservation<ValueReducers.Raw<[Request.RowDecoder]>>
+ static func trackingOne<Request: FetchRequest>(_ request: Request)
+ -> ValueObservation<ValueReducers.Raw<Request.RowDecoder?>>
+}
```


## 3.4.0

Released October 8, 2018 &bull; [diff](https://github.com/groue/GRDB.swift/compare/v3.3.1...v3.4.0)
@@ -74,7 +195,7 @@ This release comes with **Association Aggregates**. They let you compute values
+}

+extension SQLSpecificExpressible {
+ public func aliased(_ key: CodingKey) -> SQLSelectable
+ func aliased(_ key: CodingKey) -> SQLSelectable
+}
```

32 changes: 12 additions & 20 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -75,7 +75,6 @@ The ideas, in alphabetical order:
- [CloudKit]
- [Concurrency]
- [Custom FTS5 Auxiliary Functions]
- [Database Observation]
- [Date and Time Functions]
- [Decode NSDecimalNumber from Text Columns]
- [Documentation]
@@ -86,6 +85,7 @@ The ideas, in alphabetical order:
- [JSON]
- [Linux]
- [More SQL Generation]
- [Reactive Database Observation]
- [Records: Splitting Database Encoding from Ability to Write in the Database]
- [SQL Console in the Debugger]
- [SQLCipher in a Shared App Container]
@@ -160,24 +160,6 @@ Applications can define their own [custom FTS5 auxiliary functions](https://www.
See issue [#421](https://github.com/groue/GRDB.swift/issues/421) for more information.


### Database Observation

:muscle: Hard

[Database Observation](README#database-changes-observation) is currently available in three flavors:

- The [TransactionObserver](README.md#transactionobserver-protocol) protocol: versatile, but low-level and challenging in terms of concurrency, especially when used in conjunction with database pools.

- [FetchedRecordsController]: high-level and easier to use.

- [RxGRDB]: high-level and easier to use, depends on [RxSwift](https://github.com/ReactiveX/RxSwift).

Suggested contributions are:

- Enhancements to FetchedRecordsController (see below).
- More choices of reactive engines.


### Date and Time Functions

:baby: Starter Task
@@ -257,7 +239,7 @@ let stringRequest = Player.select(Column("name"), as: String.self)
let rowRequest = SQLRequest<Row>("SELECT ...")
```

This limitation does not apply to [RxGRDB], the reactive sibling of FetchedRecordsController. It would be nice if FetchedRecordsController would become just as versatile.
This limitation does not apply to [ValueObservation] and [RxGRDB]. It would be nice if FetchedRecordsController would become just as versatile.


### FetchedRecordsController Support for Sections
@@ -312,6 +294,15 @@ There are several SQLite features that GRDB could natively support:
- [More ideas](https://www.sqlite.org/lang.html)


### Reactive Database Observation

:baby: Starter Task

We already have the [RxGRDB] companion library, which offers [RxSwift](https://github.com/ReactiveX/RxSwift) bindings.

We need more choices of reactive engines.


### Records: Splitting Database Encoding from Ability to Write in the Database

:baby: Starter Task :pencil: Documentation
@@ -416,3 +407,4 @@ Features that blur this focus are non-goals:
[PersistableRecord]: README.md#persistablerecord-protocol
[Record Comparison]: README.md#record-comparison
[Requesting Associated Records]: Documentation/AssociationsBasics.md#requesting-associated-records
[ValueObservation]: README.md#valueobservation
Loading