92 lines
2.3 KiB
Swift
92 lines
2.3 KiB
Swift
//
|
|
// Copyright 2023 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
public import GRDB
|
|
public import LibSignalClient
|
|
|
|
@objc
|
|
public class DBReadTransaction: NSObject {
|
|
public let database: Database
|
|
public let startDate: MonotonicDate
|
|
|
|
init(database: Database) {
|
|
self.database = database
|
|
self.startDate = MonotonicDate()
|
|
}
|
|
}
|
|
|
|
@objc
|
|
public class DBWriteTransaction: DBReadTransaction, LibSignalClient.StoreContext {
|
|
private enum TransactionState {
|
|
case open
|
|
case finalizing
|
|
case finalized
|
|
}
|
|
|
|
typealias FinalizationBlock = (DBWriteTransaction) -> Void
|
|
typealias CompletionBlock = () -> Void
|
|
|
|
private var transactionState: TransactionState
|
|
private var finalizationBlocks: [String: FinalizationBlock]
|
|
private(set) var completionBlocks: [CompletionBlock]
|
|
|
|
override init(database: Database) {
|
|
self.transactionState = .open
|
|
self.finalizationBlocks = [:]
|
|
self.completionBlocks = []
|
|
|
|
super.init(database: database)
|
|
}
|
|
|
|
deinit {
|
|
owsAssertDebug(
|
|
transactionState == .finalized,
|
|
"Write transaction deallocated without finalization!",
|
|
)
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
func finalizeTransaction() {
|
|
guard transactionState == .open else {
|
|
owsFailDebug("Write transaction finalized multiple times!")
|
|
return
|
|
}
|
|
|
|
transactionState = .finalizing
|
|
|
|
for (_, finalizationBlock) in finalizationBlocks {
|
|
finalizationBlock(self)
|
|
}
|
|
|
|
finalizationBlocks.removeAll()
|
|
transactionState = .finalized
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
/// Schedule the given block to run when this transaction is finalized.
|
|
///
|
|
/// - Important
|
|
/// `block` must not capture any database models, as they may no longer be
|
|
/// valid by time the transaction finalizes.
|
|
func addFinalizationBlock(key: String, block: @escaping FinalizationBlock) {
|
|
finalizationBlocks[key] = block
|
|
}
|
|
|
|
/// Run the given block synchronously after the transaction is finalized.
|
|
public func addSyncCompletion(block: @escaping () -> Void) {
|
|
completionBlocks.append(block)
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
public extension LibSignalClient.StoreContext {
|
|
var asTransaction: DBWriteTransaction {
|
|
return self as! DBWriteTransaction
|
|
}
|
|
}
|