Released September 9, 2022 • diff
- New: Support for GRDB 6
- Breaking Change: Swift 5.7+ and Xcode 14+ are required.
- Breaking Change: iOS 11.0+ / macOS 10.13+ / tvOS 11.0+ / watchOS 4.0+
Released October 17, 2021 • diff
- Breaking Change: Minimum iOS version is now iOS 11.0, and 32-bits devices are no longer supported. This brings compatibility with GRDB v5.12.0 and Xcode 13.
- Breaking Change: Minimum Swift version is now Swift 5.3.
Released January 3, 2021 • diff
- New: Support for RxSwift 6
Released September 20, 2020 • diff
Released June 7, 2020 • diff
- Fixed CocoaPods integration (fix #65)
Released June 6, 2020 • diff
- Breaking: The ValueObservation scheduler is now an argument of the
rx.observe(in:scheduler:)
method, which returns a regular Observable.
Released May 3, 2020 • diff
Check out the Migration Guide.
- #63: RxGRDB 1.0
Released December 11, 2019 • diff
- #60 by @sammygutierrez: Add SwiftPM support
- #61: Fix error handling of asynchronous writes
- #62: Test Xcode 11.2 and SPM on Travis
Released June 28, 2019 • diff
- #58: Expose
rx
joiner on database existentials
Released June 27, 2019 • diff
- #57: Deprecate PrimaryKeyScanner
The demo app has been refactored with the latest GRDB good practices, MVVM architecture, and some tests of the database layer
Released June 20, 2019 • diff
-
#55: Asynchronous database access
let dbQueue: DatabaseQueue = ... // Async write let write: Completable = dbQueue.rx.write { db in try Player(...).insert(db) } let newPlayerCount: Single<Int> = dbQueue.rx.writeAndReturn { db in try Player(...).insert(db) return try Player.fetchCount(db) } // Async read let players: Single<[Player]> = dbQueue.rx.read { db in try Player.fetchAll(db) }
-
Observation methods have been renamed from
fetch...
toobserve...
:-Player.all().rx.fetchOne(in: dbQueue) -Player.all().rx.fetchAll(in: dbQueue) -Player.all().rx.fetchCount(in: dbQueue) +Player.all().rx.observeFirst(in: dbQueue) +Player.all().rx.observeAll(in: dbQueue) +Player.all().rx.observeCount(in: dbQueue)
-
The way to provide a specific scheduler to a value observable has changed:
-Player.all().rx.fetchAll(in: dbQueue, scheduler: MainScheduler.asyncInstance) +Player.all().rx.observeAll(in: dbQueue, observeOn: MainScheduler.asyncInstance)
Released May 24, 2019 • diff
-
Support for Swift 5, GRDB 4.0, and RxSwift 5.0.
-
Reactive extension on DatabaseRegionObservation:
let players = Player.all() let teams = Team.all() let observation = DatabaseRegionObservation(tracking: players, teams) observation.rx.changes(in: dbQueue) .subscribe(onNext: { db: Database in print("Players or teams have changed.") })
- Swift 4.0 and Swift 4.1 are no longer supported.
- GRDB 3 and RxSwift 4 are no longer supported.
- iOS 8 is no longer supported. Minimum deployment target is now iOS 9.0.
- Deprecated APIs are no longer available.
DatabaseWriter.rx.changes
is removed, replaced withDatabaseRegionObservation.rx.changes
.- SQLCipher support is now available under the CocoaPods
RxGRDB/SQLCipher
name.
Released November 2, 2018 • diff
- #46: Implement RxGRDB on top GRDB.ValueObservation
- The
DatabaseWriter.rx.fetch
method has been removed. Instead, useValueObservation.rx.fetch
. - The
distinctUntilChanged
parameter is no longer available when one creates an RxGRDB observable. Filtering of consecutive identical database values is now the default behavior.
- One can now create a values observable from a DatabaseReader.
Released October 25, 2018 • diff
- Fixed GRDB Cocoapods dependency.
Released Septembre 17, 2018 • diff
- #39: Xcode 10 & GRDB 3.3.0
Released June 7, 2018 • diff
- Support for GRDB 3.0
- The new DatabaseRegionConvertible protocol allows better request encapsulation (documentation)
-
"Fetch tokens" and the
mapFetch
operator were ill-advised, and have been removed. Now please use the newDatabaseWriter.fetch(from:startImmediately:scheduler:values:)
method instead, which produces exactly the same observable:// Old way -let values = dbQueue.rx - .fetchTokens(in: [request, ...]) - .mapFetch { db in - try fetchResults(db) - } // New way +let values = dbQueue.rx.fetch(from: [request, ...]) { db in + try fetchResults(db) +}
Released March 26, 2018 • diff
-
Unless they are provided an explicit scheduler, values observables subscribed from the main queue are now guaranteed a synchronous emission of their initial value (#28).
-
The RxGRDB repository now uses CocoaPods for its inner dependencies GRBD and RxSwift. After you have downloaded the RxGRDB repository, run
pod repo update; pod install
in order to download all dependencies, build targets, or run tests (#29).
- The Values Observables chapter now describes the scheduling of fetched values.
Released February 25, 2018 • diff
- Values observables can now be scheduled on any RxSwift scheduler (fixes #22).
- "Change Tokens" have been renamed "Fetch Tokens" in order to better reflect their purpose, and to enhance the distinction between observables that emit values on any schedulers ("values observables") and have "fetch" in their definition, from observables that emit database connections on a GRDB dispatch queue ("changes observables") and have "changes" in their definition).
- The Scheduling Guide has been augmented with a chapter on data consistency.
+struct FetchToken { }
-struct ChangeToken { }
extension Reactive where Base: DatabaseWriter {
+ func fetchTokens(in requests: [Request], startImmediately: Bool = true, scheduler: ImmediateSchedulerType = MainScheduler.instance) -> Observable<FetchToken>
- func changeTokens(in requests: [Request], startImmediately: Bool = true, scheduler: ImmediateSchedulerType = MainScheduler.instance) -> Observable<ChangeToken>
}
Released February 20, 2018 • diff
- Fixes a bug that would have values observables fail to observe some database changes.
Released January 18, 2018 • diff
This version enhances the scheduling of database notifications, and the tracking of specific database rows.
-
The tracking of requests that target specific rows, identified by their row ids, has been enhanced:
In previous version of RxGRDB, tracking
Player.filter(key: 1)
would trigger change notifications for all changes to the players table.Now RxGRDB is able to precisely track the player of ID 1, and won't emit any notification for changes performed on other players.
- RxGRDB observables used to require subscription and observation to happen on the same dispatch queue. It was easy to fail this precondition, and misuse the library. This has been fixed.
- The demo application used to misuse MKMapView by converting database changes into annotation coordinate updates on the wrong dispatch queue. This has been fixed.
- GRDB dependency has been bumped to v2.6.
- Database observation scheduling used to be managed through raw dispatch queues. One now uses regular RxSwift schedulers. The
synchronizedStart
parameter has been renamed tostartImmediately
in order to reflect the fact that not all schedulers can start synchronously. See the updated documentation of RxGRDB reactive methods. - The
Diffable
protocol was ill-advised, and has been removed. - The
primaryKeySortedDiff
operator has been replaced byPrimaryKeyDiffScanner
(documentation)
extension Reactive where Base: Request {
- func changes(
- in writer: DatabaseWriter,
- synchronizedStart: Bool = true)
- -> Observable<Database>
+ func changes(
+ in writer: DatabaseWriter,
+ startImmediately: Bool = true)
+ -> Observable<Database>
- func fetchCount(
- in writer: DatabaseWriter,
- synchronizedStart: Bool = true,
- resultQueue: DispatchQueue = DispatchQueue.main)
- -> Observable<Int>
+ func fetchCount(
+ in writer: DatabaseWriter,
+ startImmediately: Bool = true,
+ scheduler: SerialDispatchQueueScheduler = MainScheduler.instance)
+ -> Observable<Int>
}
extension Reactive where Base: TypedRequest {
- func fetchAll(
- in writer: DatabaseWriter,
- synchronizedStart: Bool = true,
- resultQueue: DispatchQueue = DispatchQueue.main,
- distinctUntilChanged: Bool = false)
- -> Observable<[Base.RowDecoder]>
+ func fetchAll(
+ in writer: DatabaseWriter,
+ startImmediately: Bool = true,
+ scheduler: SerialDispatchQueueScheduler = MainScheduler.instance,
+ distinctUntilChanged: Bool = false)
+ -> Observable<[Base.RowDecoder]>
- func fetchOne(
- in writer: DatabaseWriter,
- synchronizedStart: Bool = true,
- resultQueue: DispatchQueue = DispatchQueue.main,
- distinctUntilChanged: Bool = false)
- -> Observable<Base.RowDecoder?>
+ func fetchOne(
+ in writer: DatabaseWriter,
+ startImmediately: Bool = true,
+ scheduler: SerialDispatchQueueScheduler = MainScheduler.instance,
+ distinctUntilChanged: Bool = false)
+ -> Observable<Base.RowDecoder?>
}
extension ObservableType where E == ChangeToken {
- func mapFetch<R>(
- resultQueue: DispatchQueue = DispatchQueue.main,
- _ fetch: @escaping (Database) throws -> R)
- -> Observable<R>
+ func mapFetch<R>(_ fetch: @escaping (Database) throws -> R) -> Observable<R>
}
extension Reactive where Base: DatabaseWriter {
- public func changes(
- in requests: [Request],
- synchronizedStart: Bool = true)
- -> Observable<Database>
+ public func changes(
+ in requests: [Request],
+ startImmediately: Bool = true)
+ -> Observable<Database>
- func changeTokens(
- in requests: [Request],
- synchronizedStart: Bool = true)
- -> Observable<ChangeToken>
+ func changeTokens(
+ in requests: [Request],
+ startImmediately: Bool = true,
+ scheduler: SerialDispatchQueueScheduler = MainScheduler.instance)
+ -> Observable<ChangeToken>
}
-protocol Diffable {
- func updated(with row: Row) -> Self
-}
-extension Reactive where Base: TypedRequest, Base.RowDecoder: RowConvertible & MutablePersistable & Diffable {
- func primaryKeySortedDiff(
- in writer: DatabaseWriter,
- initialElements: [Base.RowDecoder] = [])
- -> Observable<PrimaryKeySortedDiff<Base.RowDecoder>>
-}
-struct PrimaryKeySortedDiff<Element> { ... }
+struct PrimaryKeyDiffScanner<Record: RowConvertible & MutablePersistable> {
+ let diff: PrimaryKeyDiff<Record>
+ init<Request>(
+ database: Database,
+ request: Request,
+ initialRecords: [Record],
+ updateRecord: ((Record, Row) -> Record)? = nil)
+ throws
+ where Request: TypedRequest, Request.RowDecoder == Record
+ func diffed(from rows: [Row]) -> PrimaryKeyDiffScanner
+}
+struct PrimaryKeyDiff<Record> {
+ let inserted: [Record]
+ let updated: [Record]
+ let deleted: [Record]
+ var isEmpty: Bool
+}
Released October 18, 2017 • diff
- Support for Swift 4
- Support for various diff algorithms (Documentation)
- New demo application for various diff algorithms.
- Observables that emit fetched values used to emit their first element on the wrong dispatch queue when their
synchronizedStart
option is true. That first element is now correctly emitted on the subscription dispatch queue.
- Requirements have changed: Xcode 9+, Swift 4, GRDB 2.0
Released July 13, 2017
- Fixed: Support for macOS, broken in v0.5.0
- New: GRDB dependency bumped to v1.2
Released July 8, 2017
RxGRDB has learned how to observe multiple requests and fetch from other requests. Documentation
To get a single notification when a transaction has modified several requests, use DatabaseWriter.rx.changes
:
// Observable<Database>
dbQueue.rx.changes(in: [request, ...])
To turn a change notification into consistent results fetched from multiple requests, use DatabaseWriter.rx.changeTokens
and the mapFetch
operator:
dbQueue.rx
.changeTokens(in: [request, ...])
.mapFetch { (db: Database) in
return ...
}
+extension Reactive where Base: DatabaseWriter {
+ func changes(in requests: [Request], synchronizedStart: Bool = true) -> Observable<Database>
+ func changeTokens(in requests: [Request], synchronizedStart: Bool = true) -> Observable<ChangeToken>
+}
+struct ChangeToken {
+ var database: Database { get }
+}
+extension ObservableType where E == ChangeToken {
+ func func mapFetch<R>(resultQueue: DispatchQueue = DispatchQueue.main, _ fetch: @escaping (Database) throws -> R) -> Observable<R>
+}
Released June 20, 2017
- Podspec requirement for RxSwift changed to
~> 3.3
- Added missing support for new AdaptedRequest and AdaptedTypedRequest of GRDB 1.0
Released June 20, 2017
- RxGRDB now requires GRDB v1.0
Released May 22, 2017
-
The new
distinctUntilChanged
parameter has RxGRDB avoid notifying consecutive identical values.request.rx.fetchAll(in: dbQueue, distinctUntilChanged: true)...
-
Tracking of requests that fetch an array of optional values:
// Email column may be NULL: let request = Person.select(email).bound(to: Optional<String>.self) request.rx.fetchAll(in: dbQueue) .subscribe(onNext: { emails: [String?] in ... })
Released May 17, 2017
- Support for SQLCipher.
Released April 6, 2017
- RxGRDB observables now support the
retry
operator, and no longer crash when disposed on a database queue.
Released April 5, 2017
synchronizedStart
optionRequest.rx.fetchCount(in:synchronizedStart)
Released April 5, 2017
Initial release