Does SQLite.swift has the ability to detect & notify table data change?

Viewed 703

I was wondering, does SQLite.swift have the capability, to detect & notify table data change? (Similar to what is offered by NSFetchedResultsController, to detect & notify entity data change)


For GRDB.swift, it offers the capability to observe table data change.

https://github.com/groue/GRDB.swift/blob/master/Documentation/DemoApps/GRDBDemoiOS/GRDBDemoiOS/ViewControllers/PlayerListViewController.swift#L98

private func configureDataSourceContent() {
    switch playerOrdering {
    case .byName:
        playersCancellable = AppDatabase.shared.observePlayersOrderedByName(
            onError: { error in fatalError("Unexpected error: \(error)") },
            onChange: { [weak self] players in
                guard let self = self else { return }
                self.updateDataSourceContent(with: players)
            })
    case .byScore:
        playersCancellable = AppDatabase.shared.observePlayersOrderedByScore(
            onError: { error in fatalError("Unexpected error: \(error)") },
            onChange: { [weak self] players in
                guard let self = self else { return }
                self.updateDataSourceContent(with: players)
            })
    }
}

SQLite itself does provide low level Data Change Notification Callbacks (https://www.sqlite.org/c3ref/update_hook.html).

Does SQLite.swift offer anything out of the box, by building on the top of sqlite3_update_hook? If not, is it possible for us to custom build such solution?

Thanks.

2 Answers

I believe, you are looking for this functionality (reproduced below for ready reference):

/// Registers a callback to be invoked whenever a row is inserted, updated,
    /// or deleted in a rowid table.
    ///
    /// - Parameter callback: A callback invoked with the `Operation` (one of
    ///   `.Insert`, `.Update`, or `.Delete`), database name, table name, and
    ///   rowid.
    public func updateHook(_ callback: ((_ operation: Operation, _ db: String, _ table: String, _ rowid: Int64) -> Void)?) {
        guard let callback = callback else {
            sqlite3_update_hook(handle, nil, nil)
            updateHook = nil
            return
        }

        let box: UpdateHook = {
            callback(
                Operation(rawValue: $0),
                String(cString: $1),
                String(cString: $2),
                $3
            )
        }
        sqlite3_update_hook(handle, { callback, operation, db, table, rowid in
            unsafeBitCast(callback, to: UpdateHook.self)(operation, db!, table!, rowid)
        }, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
        updateHook = box
    }
    fileprivate typealias UpdateHook = @convention(block) (Int32, UnsafePointer<Int8>, UnsafePointer<Int8>, Int64) -> Void
    fileprivate var updateHook: UpdateHook?

However, there seems to be an attempt to include what you are looking for. Have a look at this SQLite.swift issue. This is from 2017 and may have evolved!

Related