Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/GRDB/Documentation.docc/Extension/DatabaseRegionObservation.md
T
2025-01-28 12:28:03 +08:00

112 lines
4.1 KiB
Markdown

# ``GRDB/DatabaseRegionObservation``
`DatabaseRegionObservation` tracks changes in a database region, and notifies impactful transactions.
## Overview
`DatabaseRegionObservation` tracks insertions, updates, and deletions that impact the tracked region, whether performed with raw SQL, or <doc:QueryInterface>. This includes indirect changes triggered by [foreign keys actions](https://www.sqlite.org/foreignkeys.html#fk_actions) or [SQL triggers](https://www.sqlite.org/lang_createtrigger.html).
See <doc:GRDB/DatabaseRegionObservation#Dealing-with-Undetected-Changes> below for the list of exceptions.
`DatabaseRegionObservation` calls your application right after changes have been committed in the database, and before any other thread had any opportunity to perform further changes. *This is a pretty strong guarantee, that most applications do not really need.* Instead, most applications prefer to be notified with fresh values: make sure you check ``ValueObservation`` before using `DatabaseRegionObservation`.
## DatabaseRegionObservation Usage
Create a `DatabaseRegionObservation` with one or several requests to track:
```swift
// Tracks the full player table
let observation = DatabaseRegionObservation(tracking: Player.all())
```
Then start the observation from a ``DatabaseQueue`` or ``DatabasePool``:
```swift
let cancellable = try observation.start(in: dbQueue) { error in
// Handle error
} onChange: { (db: Database) in
print("Players were changed")
}
```
Enjoy the changes notifications:
```swift
try dbQueue.write { db in
try Player(name: "Arthur").insert(db)
}
// Prints "Players were changed"
```
You stop the observation by calling the ``DatabaseCancellable/cancel()`` method on the object returned by the `start` method. Cancellation is automatic when the cancellable is deallocated:
```swift
cancellable.cancel()
```
`DatabaseRegionObservation` can also be turned into a Combine publisher, or an RxSwift observable (see the companion library [RxGRDB](https://github.com/RxSwiftCommunity/RxGRDB)):
```swift
let cancellable = observation.publisher(in: dbQueue).sink { completion in
// Handle completion
} receiveValue: { (db: Database) in
print("Players were changed")
}
```
You can feed `DatabaseRegionObservation` with any type that conforms to the ``DatabaseRegionConvertible`` protocol: ``FetchRequest``, ``DatabaseRegion``, ``Table``, etc. For example:
```swift
// Observe the score column of the 'player' table
let observation = DatabaseRegionObservation(
tracking: Player.select(Column("score")))
// Observe the 'score' column of the 'player' table
let observation = DatabaseRegionObservation(
tracking: SQLRequest("SELECT score FROM player"))
// Observe both the 'player' and 'team' tables
let observation = DatabaseRegionObservation(
tracking: Table("player"), Table("team"))
// Observe the full database
let observation = DatabaseRegionObservation(
tracking: .fullDatabase)
```
## Dealing with Undetected Changes
`DatabaseRegionObservation` will not notify impactful transactions whenever the database is modified in an undetectable way:
- Changes performed by external database connections.
- Changes performed by SQLite statements that are not compiled and executed by GRDB.
- Changes to the database schema, changes to internal system tables such as `sqlite_master`.
- Changes to [`WITHOUT ROWID`](https://www.sqlite.org/withoutrowid.html) tables.
To have observations notify such undetected changes, applications can take explicit action: call the ``Database/notifyChanges(in:)`` `Database` method from a write transaction:
```swift
try dbQueue.write { db in
// Notify observations that some changes were performed in the database
try db.notifyChanges(in: .fullDatabase)
// Notify observations that some changes were performed in the player table
try db.notifyChanges(in: Player.all())
// Equivalent alternative
try db.notifyChanges(in: Table("player"))
}
```
## Topics
### Creating DatabaseRegionObservation
- ``init(tracking:)-5ldbe``
- ``init(tracking:)-2nqjd``
### Observing Database Transactions
- ``publisher(in:)``
- ``start(in:onError:onChange:)``