From d8fc720dde1ffb53135b144e59707a01a3340215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gwendal=20Roue=CC=81?= Date: Sun, 11 Feb 2024 15:29:14 +0100 Subject: [PATCH] Rename LockedBox to Mutex --- GRDB.xcodeproj/project.pbxproj | 12 ++- GRDB/Core/Database.swift | 42 +++++---- GRDB/Core/DatabasePool.swift | 6 +- GRDB/Core/DatabaseRegionObservation.swift | 10 +- GRDB/Utils/LockedBox.swift | 72 --------------- GRDB/Utils/Mutex.swift | 54 +++++++++++ .../Observers/ValueConcurrentObserver.swift | 6 +- GRDB/ValueObservation/ValueObservation.swift | 37 ++++---- GRDBCustom.xcodeproj/project.pbxproj | 12 ++- TODO.md | 2 +- .../GRDBTests.xcodeproj/project.pbxproj | 6 ++ .../GRDBTests.xcodeproj/project.pbxproj | 6 ++ .../AssociationPrefetchingSQLTests.swift | 92 +++++++++---------- .../DatabaseDataEncodingStrategyTests.swift | 4 +- .../DatabaseDateEncodingStrategyTests.swift | 4 +- Tests/GRDBTests/DatabaseErrorTests.swift | 4 +- Tests/GRDBTests/DatabaseSavepointTests.swift | 12 +-- Tests/GRDBTests/DatabaseTests.swift | 4 +- .../DatabaseUUIDEncodingStrategyTests.swift | 6 +- Tests/GRDBTests/DerivableRequestTests.swift | 44 ++++----- Tests/GRDBTests/FTS3RecordTests.swift | 4 +- Tests/GRDBTests/FTS4RecordTests.swift | 4 +- Tests/GRDBTests/FTS5RecordTests.swift | 4 +- .../GRDBTests/ForeignKeyDefinitionTests.swift | 44 ++++----- Tests/GRDBTests/GRDBTestCase.swift | 20 ++-- ...MutablePersistableRecordChangesTests.swift | 32 +++---- .../MutablePersistableRecordTests.swift | 24 ++--- Tests/GRDBTests/Mutex.swift | 54 +++++++++++ Tests/GRDBTests/PersistableRecordTests.swift | 22 ++--- Tests/GRDBTests/TableDefinitionTests.swift | 16 ++-- ...bleRecord+QueryInterfaceRequestTests.swift | 2 +- Tests/GRDBTests/TableRecordUpdateTests.swift | 2 +- Tests/GRDBTests/TableTests.swift | 4 +- .../ValueObservationPrintTests.swift | 5 +- Tests/GRDBTests/ValueObservationTests.swift | 5 +- 35 files changed, 375 insertions(+), 302 deletions(-) delete mode 100644 GRDB/Utils/LockedBox.swift create mode 100644 GRDB/Utils/Mutex.swift create mode 100644 Tests/GRDBTests/Mutex.swift diff --git a/GRDB.xcodeproj/project.pbxproj b/GRDB.xcodeproj/project.pbxproj index 213fe83be5..4185082bb9 100755 --- a/GRDB.xcodeproj/project.pbxproj +++ b/GRDB.xcodeproj/project.pbxproj @@ -105,6 +105,7 @@ 563C67B324628BEA00E94EDC /* DatabasePoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563C67B224628BEA00E94EDC /* DatabasePoolTests.swift */; }; 563CBBE12A595131008905CE /* SQLIndexGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563CBBE02A595131008905CE /* SQLIndexGenerator.swift */; }; 563DE4F3231A91E2005081B7 /* DatabaseConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563DE4EC231A91E2005081B7 /* DatabaseConfigurationTests.swift */; }; + 563EA3E12C7B3A22001BE0D4 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EA3E02C7B3A22001BE0D4 /* Mutex.swift */; }; 563EF415215F87EB007DAACD /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EF414215F87EB007DAACD /* OrderedDictionary.swift */; }; 563EF42D2161180D007DAACD /* AssociationAggregate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EF42C2161180D007DAACD /* AssociationAggregate.swift */; }; 563EF43F216131D1007DAACD /* AssociationAggregateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EF43E216131D1007DAACD /* AssociationAggregateTests.swift */; }; @@ -186,7 +187,7 @@ 566B912B1FA4D0CC0012D5B0 /* StatementAuthorizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566B912A1FA4D0CC0012D5B0 /* StatementAuthorizer.swift */; }; 566B91331FA4D3810012D5B0 /* TransactionObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566B91321FA4D3810012D5B0 /* TransactionObserver.swift */; }; 566B9C2025C6CC24004542CF /* RowDecodingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566B9C1F25C6CC24004542CF /* RowDecodingError.swift */; }; - 566BE71E2342542F00A8254B /* LockedBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566BE7172342542F00A8254B /* LockedBox.swift */; }; + 566BE71E2342542F00A8254B /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566BE7172342542F00A8254B /* Mutex.swift */; }; 566DDE0D288D763C0000DCFB /* Fixits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566DDE0C288D763C0000DCFB /* Fixits.swift */; }; 56703297212B5450007D270F /* DatabaseUUIDEncodingStrategyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56703290212B544F007D270F /* DatabaseUUIDEncodingStrategyTests.swift */; }; 56713FDD2691F409006153C3 /* JSONRequiredEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56713FDC2691F409006153C3 /* JSONRequiredEncoder.swift */; }; @@ -534,6 +535,7 @@ 563C67B224628BEA00E94EDC /* DatabasePoolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePoolTests.swift; sourceTree = ""; }; 563CBBE02A595131008905CE /* SQLIndexGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLIndexGenerator.swift; sourceTree = ""; }; 563DE4EC231A91E2005081B7 /* DatabaseConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseConfigurationTests.swift; sourceTree = ""; }; + 563EA3E02C7B3A22001BE0D4 /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; 563EF414215F87EB007DAACD /* OrderedDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderedDictionary.swift; sourceTree = ""; }; 563EF42C2161180D007DAACD /* AssociationAggregate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssociationAggregate.swift; sourceTree = ""; }; 563EF43E216131D1007DAACD /* AssociationAggregateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssociationAggregateTests.swift; sourceTree = ""; }; @@ -628,7 +630,7 @@ 566B912A1FA4D0CC0012D5B0 /* StatementAuthorizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatementAuthorizer.swift; sourceTree = ""; }; 566B91321FA4D3810012D5B0 /* TransactionObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionObserver.swift; sourceTree = ""; }; 566B9C1F25C6CC24004542CF /* RowDecodingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RowDecodingError.swift; sourceTree = ""; }; - 566BE7172342542F00A8254B /* LockedBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockedBox.swift; sourceTree = ""; }; + 566BE7172342542F00A8254B /* Mutex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; 566DDE0C288D763C0000DCFB /* Fixits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fixits.swift; sourceTree = ""; }; 56703290212B544F007D270F /* DatabaseUUIDEncodingStrategyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseUUIDEncodingStrategyTests.swift; sourceTree = ""; }; 56713FDC2691F409006153C3 /* JSONRequiredEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONRequiredEncoder.swift; sourceTree = ""; }; @@ -1010,6 +1012,7 @@ children = ( 56677C14241D14450050755D /* FailureTestCase.swift */, 5623E0901B4AFACC00B20B7F /* GRDBTestCase.swift */, + 563EA3E02C7B3A22001BE0D4 /* Mutex.swift */, 562EA81E1F17B26F00FA528C /* Compilation */, 56A238111B9C74A90082EB20 /* Core */, 567B5BDA2AD3281B00629622 /* Dump */, @@ -1318,7 +1321,7 @@ 56717270261C68E900423B6F /* CaseInsensitiveIdentifier.swift */, 563EF4492161F179007DAACD /* Inflections.swift */, 569BBA482291707D00478429 /* Inflections+English.swift */, - 566BE7172342542F00A8254B /* LockedBox.swift */, + 566BE7172342542F00A8254B /* Mutex.swift */, 563B8FC424A1D3B9007A48C9 /* OnDemandFuture.swift */, 563EF414215F87EB007DAACD /* OrderedDictionary.swift */, 5659F4971EA8D989004A4992 /* Pool.swift */, @@ -2058,6 +2061,7 @@ 5615B275222B107900061C1C /* AssociationHasOneThroughFetchableRecordTests.swift in Sources */, 56D4966F1D81309E008276D7 /* RecordPrimaryKeyNoneTests.swift in Sources */, 56D496621D81304E008276D7 /* StatementArguments+FoundationTests.swift in Sources */, + 563EA3E12C7B3A22001BE0D4 /* Mutex.swift in Sources */, 56176C5D1EACCCC7000F3F2B /* FTS5TokenizerTests.swift in Sources */, 56D496B21D8133CE008276D7 /* DatabaseQueueInMemoryTests.swift in Sources */, 562393601DEE06D300A6B01F /* CursorTests.swift in Sources */, @@ -2265,7 +2269,7 @@ 5690C3401D23E82A00E59934 /* Data.swift in Sources */, 5659F4881EA8D94E004A4992 /* Utils.swift in Sources */, 567B5BE82AD3284100629622 /* DumpFormat.swift in Sources */, - 566BE71E2342542F00A8254B /* LockedBox.swift in Sources */, + 566BE71E2342542F00A8254B /* Mutex.swift in Sources */, 56A238931B9C750B0082EB20 /* DatabaseMigrator.swift in Sources */, 5603CEBB2AC862EC00CF097D /* SQLJSONExpressible.swift in Sources */, 56F89DF72A57EAA9002FE2AA /* ColumnDefinition.swift in Sources */, diff --git a/GRDB/Core/Database.swift b/GRDB/Core/Database.swift index ec881c14e0..68956eaa1f 100644 --- a/GRDB/Core/Database.swift +++ b/GRDB/Core/Database.swift @@ -292,7 +292,7 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib var isInsideTransactionBlock = false /// Support for `checkForSuspensionViolation(from:)` - @LockedBox var isSuspended = false + let isSuspendedMutex = Mutex(false) /// Support for `checkForSuspensionViolation(from:)` /// This cache is never cleared: we assume journal mode never changes. @@ -1125,22 +1125,25 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib /// /// Suspension ends with `resume()`. func suspend() { - $isSuspended.update { isSuspended in + let needsInterrupt = isSuspendedMutex.withLock { isSuspended in if isSuspended { - return + return false } - // Prevent future lock acquisition isSuspended = true - - // Interrupt the database because this may trigger an - // SQLITE_INTERRUPT error which may itself abort a transaction and - // release a lock. See + return true + } + + if needsInterrupt { + // Interrupting the database can trigger an SQLITE_INTERRUPT + // error which may itself abort a transaction and + // release a database lock, which is our goal. + // See + // + // Maybe interrupt will not release any lock. To address this, + // we'll issue a rollback on next database access which requires + // a lock. See `checkForSuspensionViolation(from:).` interrupt() - - // Now what about the eventual remaining lock? We'll issue a - // rollback on next database access which requires a lock, in - // checkForSuspensionViolation(from:). } } @@ -1152,7 +1155,7 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib /// /// See suspend(). func resume() { - isSuspended = false + isSuspendedMutex.store(false) } /// Support for `checkForSuspensionViolation(from:)` @@ -1182,9 +1185,9 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib /// /// See `suspend()` and ``Configuration/observesSuspensionNotifications``. func checkForSuspensionViolation(from statement: Statement) throws { - try $isSuspended.read { isSuspended in + let needsAbort = try isSuspendedMutex.withLock { isSuspended in guard isSuspended else { - return + return false } if try journalMode() == "wal" && statement.isReadonly { @@ -1195,7 +1198,7 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib // Those are not read-only: // - INSERT ... // - BEGIN IMMEDIATE TRANSACTION - return + return false } if statement.releasesDatabaseLock { @@ -1204,9 +1207,14 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib // - ROLLBACK // - ROLLBACK TRANSACTION TO SAVEPOINT // - RELEASE SAVEPOINT - return + return false } + // Assume statement can acquire a write lock: abort. + return true + } + + if needsAbort { // Attempt at releasing an eventual lock with ROLLBACk, // as explained in Database.suspend(). // diff --git a/GRDB/Core/DatabasePool.swift b/GRDB/Core/DatabasePool.swift index 9b15f063ae..e7e4ff6098 100644 --- a/GRDB/Core/DatabasePool.swift +++ b/GRDB/Core/DatabasePool.swift @@ -11,7 +11,7 @@ public final class DatabasePool { /// It is constant, until close() sets it to nil. private var readerPool: Pool? - @LockedBox var databaseSnapshotCount = 0 + let databaseSnapshotCountMutex = Mutex(0) /// If Database Suspension is enabled, this array contains the necessary `NotificationCenter` observers. private var suspensionObservers: [NSObjectProtocol] = [] @@ -144,7 +144,7 @@ public final class DatabasePool { } } -// @unchecked because of databaseSnapshotCount, readerPool and suspensionObservers +// @unchecked because of readerPool and suspensionObservers extension DatabasePool: @unchecked Sendable { } extension DatabasePool { @@ -845,7 +845,7 @@ extension DatabasePool { path: path, configuration: DatabasePool.readerConfiguration(writer.configuration), defaultLabel: "GRDB.DatabasePool", - purpose: "snapshot.\($databaseSnapshotCount.increment())") + purpose: "snapshot.\(databaseSnapshotCountMutex.increment())") } #if SQLITE_ENABLE_SNAPSHOT || (!GRDBCUSTOMSQLITE && !GRDBCIPHER) diff --git a/GRDB/Core/DatabaseRegionObservation.swift b/GRDB/Core/DatabaseRegionObservation.swift index 242214bc44..3579586f81 100644 --- a/GRDB/Core/DatabaseRegionObservation.swift +++ b/GRDB/Core/DatabaseRegionObservation.swift @@ -89,16 +89,16 @@ extension DatabaseRegionObservation { onChange: @escaping (Database) -> Void) -> AnyDatabaseCancellable { - @LockedBox var state = ObservationState.pending + let stateMutex = Mutex(ObservationState.pending) // Use unsafeReentrantWrite so that observation can start from any // dispatch queue. writer.unsafeReentrantWrite { db in do { let region = try observedRegion(db).observableRegion(db) - $state.update { + stateMutex.withLock { state in let observer = DatabaseRegionObserver(region: region, onChange: { - if case .cancelled = state { + if case .cancelled = stateMutex.load() { return } onChange($0) @@ -111,7 +111,7 @@ extension DatabaseRegionObservation { // the observer. db.add(transactionObserver: observer, extent: .observerLifetime) - $0 = .started(observer) + state = .started(observer) } } catch { onError(error) @@ -122,7 +122,7 @@ extension DatabaseRegionObservation { // Deallocates the transaction observer. This makes sure that the // `onChange` callback will never be called again, because the // observation was started with the `.observerLifetime` extent. - state = .cancelled + stateMutex.store(.cancelled) } } } diff --git a/GRDB/Utils/LockedBox.swift b/GRDB/Utils/LockedBox.swift deleted file mode 100644 index aef512604d..0000000000 --- a/GRDB/Utils/LockedBox.swift +++ /dev/null @@ -1,72 +0,0 @@ -import Foundation - -/// A LockedBox protects a value with an NSLock. -@propertyWrapper -final class LockedBox { - private var _wrappedValue: T - private var lock = NSLock() - - var wrappedValue: T { - get { read { $0 } } - set { update { $0 = newValue } } - } - - var projectedValue: LockedBox { self } - - init(wrappedValue: T) { - _wrappedValue = wrappedValue - } - - /// Runs the provided closure while holding a lock on the value. - /// - /// For example: - /// - /// // Prints "0" - /// @LockedBox var count = 0 - /// $count.read { print($0) } - /// - /// - parameter block: A closure that accepts the value. - @inline(__always) - @usableFromInline - func read(_ block: (T) throws -> U) rethrows -> U { - lock.lock() - defer { lock.unlock() } - return try block(_wrappedValue) - } - - /// Runs the provided closure while holding a lock on the value. - /// - /// For example: - /// - /// // Prints "1" - /// @LockedBox var count = 0 - /// $count.update { $0 += 1 } - /// print(count) - /// - /// - parameter block: A closure that can modify the value. - func update(_ block: (inout T) throws -> U) rethrows -> U { - lock.lock() - defer { lock.unlock() } - return try block(&_wrappedValue) - } -} - -extension LockedBox where T: Numeric { - @discardableResult - func increment() -> T { - update { n in - n += 1 - return n - } - } - - @discardableResult - func decrement() -> T { - update { n in - n -= 1 - return n - } - } -} - -extension LockedBox: @unchecked Sendable where T: Sendable { } diff --git a/GRDB/Utils/Mutex.swift b/GRDB/Utils/Mutex.swift new file mode 100644 index 0000000000..1fb69c2e22 --- /dev/null +++ b/GRDB/Utils/Mutex.swift @@ -0,0 +1,54 @@ +import Foundation + +/// A Mutex protects a value with an NSLock. +/// +/// We'll replace it with the SE-0433 Mutex when it is available. +/// +final class Mutex { + private var _value: T + private var lock = NSLock() + + init(_ value: T) { + _value = value + } + + /// Runs the provided closure while holding a lock on the value. + /// + /// - parameter body: A closure that can modify the value. + func withLock(_ body: (inout T) throws -> U) rethrows -> U { + lock.lock() + defer { lock.unlock() } + return try body(&_value) + } +} + +// Inspired by +extension Mutex { + func load() -> T { + withLock { $0 } + } + + func store(_ value: T) { + withLock { $0 = value } + } +} + +extension Mutex where T: Numeric { + @discardableResult + func increment() -> T { + withLock { n in + n += 1 + return n + } + } + + @discardableResult + func decrement() -> T { + withLock { n in + n -= 1 + return n + } + } +} + +extension Mutex: @unchecked Sendable where T: Sendable { } diff --git a/GRDB/ValueObservation/Observers/ValueConcurrentObserver.swift b/GRDB/ValueObservation/Observers/ValueConcurrentObserver.swift index a72c4aba8b..e57aef0983 100644 --- a/GRDB/ValueObservation/Observers/ValueConcurrentObserver.swift +++ b/GRDB/ValueObservation/Observers/ValueConcurrentObserver.swift @@ -146,7 +146,7 @@ final class ValueConcurrentObserver ValueObservation> { - let lock = NSLock() + let streamMutex = Mutex(stream ?? PrintOutputStream()) let prefix = prefix.isEmpty ? "" : "\(prefix): " - var stream = stream ?? PrintOutputStream() return handleEvents( willStart: { - lock.lock(); defer { lock.unlock() } - stream.write("\(prefix)start") }, + streamMutex.withLock { $0.write("\(prefix)start") } + }, willFetch: { - lock.lock(); defer { lock.unlock() } - stream.write("\(prefix)fetch") }, - willTrackRegion: { - lock.lock(); defer { lock.unlock() } - stream.write("\(prefix)tracked region: \($0)") }, + streamMutex.withLock { $0.write("\(prefix)fetch") } + }, + willTrackRegion: { region in + streamMutex.withLock { $0.write("\(prefix)tracked region: \(region)") } + }, databaseDidChange: { - lock.lock(); defer { lock.unlock() } - stream.write("\(prefix)database did change") }, - didReceiveValue: { - lock.lock(); defer { lock.unlock() } - stream.write("\(prefix)value: \($0)") }, - didFail: { - lock.lock(); defer { lock.unlock() } - stream.write("\(prefix)failure: \($0)") }, + streamMutex.withLock { $0.write("\(prefix)database did change") } + }, + didReceiveValue: { value in + streamMutex.withLock { $0.write("\(prefix)value: \(value)") } + }, + didFail: { error in + streamMutex.withLock { $0.write("\(prefix)failure: \(error)") } + }, didCancel: { - lock.lock(); defer { lock.unlock() } - stream.write("\(prefix)cancel") }) + streamMutex.withLock { $0.write("\(prefix)cancel") } + }) } // MARK: - Fetching Values diff --git a/GRDBCustom.xcodeproj/project.pbxproj b/GRDBCustom.xcodeproj/project.pbxproj index 7a9c12418e..04d29555ff 100755 --- a/GRDBCustom.xcodeproj/project.pbxproj +++ b/GRDBCustom.xcodeproj/project.pbxproj @@ -80,6 +80,7 @@ 563C67B824628C0C00E94EDC /* DatabasePoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563C67B624628C0C00E94EDC /* DatabasePoolTests.swift */; }; 563CBBE42A595141008905CE /* SQLIndexGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563CBBE22A595141008905CE /* SQLIndexGenerator.swift */; }; 563DE4F8231A91F6005081B7 /* DatabaseConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563DE4F6231A91F6005081B7 /* DatabaseConfigurationTests.swift */; }; + 563EA3E32C7B3A3A001BE0D4 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EA3E22C7B3A3A001BE0D4 /* Mutex.swift */; }; 563EF420215F8A76007DAACD /* OrderedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EF41E215F8A76007DAACD /* OrderedDictionary.swift */; }; 563EF442216131F5007DAACD /* AssociationAggregateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EF441216131F5007DAACD /* AssociationAggregateTests.swift */; }; 563EF44D2161F196007DAACD /* Inflections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EF44C2161F196007DAACD /* Inflections.swift */; }; @@ -185,7 +186,7 @@ 566B91351FA4D3810012D5B0 /* TransactionObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566B91321FA4D3810012D5B0 /* TransactionObserver.swift */; }; 566BD7332927AFD600595649 /* ValueConcurrentObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566BD7312927AFD600595649 /* ValueConcurrentObserver.swift */; }; 566BD7342927AFD600595649 /* ValueWriteOnlyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566BD7322927AFD600595649 /* ValueWriteOnlyObserver.swift */; }; - 566BE7152342541F00A8254B /* LockedBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566BE7132342541F00A8254B /* LockedBox.swift */; }; + 566BE7152342541F00A8254B /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566BE7132342541F00A8254B /* Mutex.swift */; }; 566DDE12288D76400000DCFB /* Fixits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566DDE11288D76400000DCFB /* Fixits.swift */; }; 5670329B212B5462007D270F /* DatabaseUUIDEncodingStrategyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56703299212B5461007D270F /* DatabaseUUIDEncodingStrategyTests.swift */; }; 567071F4208A00BE006AD95A /* SQLiteDateParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 567071F2208A00BE006AD95A /* SQLiteDateParser.swift */; }; @@ -545,6 +546,7 @@ 563C67B624628C0C00E94EDC /* DatabasePoolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePoolTests.swift; sourceTree = ""; }; 563CBBE22A595141008905CE /* SQLIndexGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLIndexGenerator.swift; sourceTree = ""; }; 563DE4F6231A91F6005081B7 /* DatabaseConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseConfigurationTests.swift; sourceTree = ""; }; + 563EA3E22C7B3A3A001BE0D4 /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; 563EF41E215F8A76007DAACD /* OrderedDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderedDictionary.swift; sourceTree = ""; }; 563EF441216131F5007DAACD /* AssociationAggregateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssociationAggregateTests.swift; sourceTree = ""; }; 563EF44C2161F196007DAACD /* Inflections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Inflections.swift; sourceTree = ""; }; @@ -655,7 +657,7 @@ 566B91321FA4D3810012D5B0 /* TransactionObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionObserver.swift; sourceTree = ""; }; 566BD7312927AFD600595649 /* ValueConcurrentObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueConcurrentObserver.swift; sourceTree = ""; }; 566BD7322927AFD600595649 /* ValueWriteOnlyObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueWriteOnlyObserver.swift; sourceTree = ""; }; - 566BE7132342541F00A8254B /* LockedBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockedBox.swift; sourceTree = ""; }; + 566BE7132342541F00A8254B /* Mutex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; 566DDE11288D76400000DCFB /* Fixits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fixits.swift; sourceTree = ""; }; 56703299212B5461007D270F /* DatabaseUUIDEncodingStrategyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseUUIDEncodingStrategyTests.swift; sourceTree = ""; }; 567071F2208A00BE006AD95A /* SQLiteDateParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteDateParser.swift; sourceTree = ""; }; @@ -1032,6 +1034,7 @@ children = ( 567E4207242AB3CB00CAAD2C /* FailureTestCase.swift */, 5623E0901B4AFACC00B20B7F /* GRDBTestCase.swift */, + 563EA3E22C7B3A3A001BE0D4 /* Mutex.swift */, 562EA81E1F17B26F00FA528C /* Compilation */, 56A238111B9C74A90082EB20 /* Core */, 567B5BFC2AD3285C00629622 /* Dump */, @@ -1339,7 +1342,7 @@ 564D4F91261E1D3300F55856 /* CaseInsensitiveIdentifier.swift */, 563EF44C2161F196007DAACD /* Inflections.swift */, 569BBA4B229170B300478429 /* Inflections+English.swift */, - 566BE7132342541F00A8254B /* LockedBox.swift */, + 566BE7132342541F00A8254B /* Mutex.swift */, 563B8FBC24A1D388007A48C9 /* OnDemandFuture.swift */, 563EF41E215F8A76007DAACD /* OrderedDictionary.swift */, 5659F4971EA8D989004A4992 /* Pool.swift */, @@ -2097,7 +2100,7 @@ 5656A8A72295BF44001FF3FF /* DatabasePromise.swift in Sources */, 5656A86D2295BD56001FF3FF /* HasManyThroughAssociation.swift in Sources */, 56894FE3260658A400268F4D /* Decimal.swift in Sources */, - 566BE7152342541F00A8254B /* LockedBox.swift in Sources */, + 566BE7152342541F00A8254B /* Mutex.swift in Sources */, F3BA806D1CFB2E55003DC1BA /* DatabaseSchemaCache.swift in Sources */, F3BA80841CFB2E67003DC1BA /* StandardLibrary.swift in Sources */, 5656A87F2295BD56001FF3FF /* SQLForeignKeyRequest.swift in Sources */, @@ -2301,6 +2304,7 @@ F3BA81321CFB3064003DC1BA /* RecordPrimaryKeySingleWithReplaceConflictResolutionTests.swift in Sources */, 5653EB7420961FB200F46237 /* AssociationRowScopeSearchTests.swift in Sources */, 5691578E231BF2BE00E1D237 /* PoolTests.swift in Sources */, + 563EA3E32C7B3A3A001BE0D4 /* Mutex.swift in Sources */, 5623935A1DEE013C00A6B01F /* FilterCursorTests.swift in Sources */, 56419C7E24A51D6E004967E1 /* DatabaseWriterWritePublisherTests.swift in Sources */, 5665FA3D2129EED8004D8612 /* DatabaseDateEncodingStrategyTests.swift in Sources */, diff --git a/TODO.md b/TODO.md index 2c3b92375d..e2e85fa2b1 100644 --- a/TODO.md +++ b/TODO.md @@ -91,7 +91,7 @@ - [ ] GRDB7/BREAKING: AsyncValueObservation does not need any scheduler (83c0e643) - [X] GRDB7/BREAKING: Stop exporting SQLite (679d6463) - [X] GRDB7/BREAKING: Remove Configuration.defaultTransactionKind (2661ff46) -- [ ] GRDB7: Replace LockedBox with Mutex (00ccab06) +- [X] GRDB7: Replace LockedBox with Mutex (00ccab06) - [ ] GRDB7: Sendable: BusyCallback (e0d8e20b) - [ ] GRDB7: Sendable: BusyMode (e0d8e20b) - [ ] GRDB7: Sendable: TransactionClock (f7dc72a5) diff --git a/Tests/CocoaPods/SQLCipher3/GRDBTests.xcodeproj/project.pbxproj b/Tests/CocoaPods/SQLCipher3/GRDBTests.xcodeproj/project.pbxproj index 2869b204eb..2058f693fb 100644 --- a/Tests/CocoaPods/SQLCipher3/GRDBTests.xcodeproj/project.pbxproj +++ b/Tests/CocoaPods/SQLCipher3/GRDBTests.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 5623B61E2AED39F700436239 /* DatabaseQueueTemporaryCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5623B61B2AED39F700436239 /* DatabaseQueueTemporaryCopyTests.swift */; }; 5623B61F2AED39F700436239 /* DatabaseQueueInMemoryCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5623B61C2AED39F700436239 /* DatabaseQueueInMemoryCopyTests.swift */; }; 5623B6202AED39F700436239 /* DatabaseQueueInMemoryCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5623B61C2AED39F700436239 /* DatabaseQueueInMemoryCopyTests.swift */; }; + 563EA3E52C7B3A4F001BE0D4 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EA3E42C7B3A4F001BE0D4 /* Mutex.swift */; }; + 563EA3E62C7B3A4F001BE0D4 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EA3E42C7B3A4F001BE0D4 /* Mutex.swift */; }; 56419D6724A54062004967E1 /* DatabasePoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56419C9C24A54053004967E1 /* DatabasePoolTests.swift */; }; 56419D6824A54062004967E1 /* DatabasePoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56419C9C24A54053004967E1 /* DatabasePoolTests.swift */; }; 56419D6924A54062004967E1 /* ResultCodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56419C9D24A54053004967E1 /* ResultCodeTests.swift */; }; @@ -510,6 +512,7 @@ 561F38F82AC9CE6D0051EEE9 /* DatabaseDataEncodingStrategyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseDataEncodingStrategyTests.swift; sourceTree = ""; }; 5623B61B2AED39F700436239 /* DatabaseQueueTemporaryCopyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseQueueTemporaryCopyTests.swift; sourceTree = ""; }; 5623B61C2AED39F700436239 /* DatabaseQueueInMemoryCopyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseQueueInMemoryCopyTests.swift; sourceTree = ""; }; + 563EA3E42C7B3A4F001BE0D4 /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; 56419C9C24A54053004967E1 /* DatabasePoolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePoolTests.swift; sourceTree = ""; }; 56419C9D24A54053004967E1 /* ResultCodeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultCodeTests.swift; sourceTree = ""; }; 56419C9E24A54053004967E1 /* DatabaseQueueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseQueueTests.swift; sourceTree = ""; }; @@ -996,6 +999,7 @@ 56419D2F24A5405E004967E1 /* MutablePersistableRecordEncodableTests.swift */, 56419D4424A5405F004967E1 /* MutablePersistableRecordPersistenceConflictPolicyTests.swift */, 56419D3B24A5405F004967E1 /* MutablePersistableRecordTests.swift */, + 563EA3E42C7B3A4F001BE0D4 /* Mutex.swift */, 56419CFD24A5405A004967E1 /* NumericOverflowTests.swift */, 56419D4F24A54060004967E1 /* OrderedDictionaryTests.swift */, 56419D4524A5405F004967E1 /* PersistableRecordTests.swift */, @@ -1435,6 +1439,7 @@ 56419E0924A54062004967E1 /* DatabaseValueConversionTests.swift in Sources */, 56419DB124A54062004967E1 /* AssociationBelongsToDecodableRecordTests.swift in Sources */, 56419D9324A54062004967E1 /* PrimaryKeyInfoTests.swift in Sources */, + 563EA3E62C7B3A4F001BE0D4 /* Mutex.swift in Sources */, 567B5C392AD32A2D00629622 /* FoundationDecimalTests.swift in Sources */, 5641A1BA24A540D6004967E1 /* Inverted.swift in Sources */, 5641A1B624A540D6004967E1 /* Prefix.swift in Sources */, @@ -1683,6 +1688,7 @@ 56419E0A24A54062004967E1 /* DatabaseValueConversionTests.swift in Sources */, 56419DB224A54062004967E1 /* AssociationBelongsToDecodableRecordTests.swift in Sources */, 56419D9424A54062004967E1 /* PrimaryKeyInfoTests.swift in Sources */, + 563EA3E52C7B3A4F001BE0D4 /* Mutex.swift in Sources */, 567B5C3A2AD32A2D00629622 /* FoundationDecimalTests.swift in Sources */, 5641A1BB24A540D6004967E1 /* Inverted.swift in Sources */, 5641A1B724A540D6004967E1 /* Prefix.swift in Sources */, diff --git a/Tests/CocoaPods/SQLCipher4/GRDBTests.xcodeproj/project.pbxproj b/Tests/CocoaPods/SQLCipher4/GRDBTests.xcodeproj/project.pbxproj index f8c3e463fe..d499535f3c 100644 --- a/Tests/CocoaPods/SQLCipher4/GRDBTests.xcodeproj/project.pbxproj +++ b/Tests/CocoaPods/SQLCipher4/GRDBTests.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 5623B6242AED3A2200436239 /* DatabaseQueueInMemoryCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5623B6212AED3A2200436239 /* DatabaseQueueInMemoryCopyTests.swift */; }; 5623B6252AED3A2200436239 /* DatabaseQueueTemporaryCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5623B6222AED3A2200436239 /* DatabaseQueueTemporaryCopyTests.swift */; }; 5623B6262AED3A2200436239 /* DatabaseQueueTemporaryCopyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5623B6222AED3A2200436239 /* DatabaseQueueTemporaryCopyTests.swift */; }; + 563EA3E82C7B3A78001BE0D4 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EA3E72C7B3A78001BE0D4 /* Mutex.swift */; }; + 563EA3E92C7B3A78001BE0D4 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 563EA3E72C7B3A78001BE0D4 /* Mutex.swift */; }; 56419FC824A540A1004967E1 /* FetchRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56419EFD24A54093004967E1 /* FetchRequestTests.swift */; }; 56419FC924A540A1004967E1 /* FetchRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56419EFD24A54093004967E1 /* FetchRequestTests.swift */; }; 56419FCA24A540A1004967E1 /* DatabasePoolBackupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56419EFE24A54093004967E1 /* DatabasePoolBackupTests.swift */; }; @@ -512,6 +514,7 @@ 561F38FE2AC9CE870051EEE9 /* DatabaseDataDecodingStrategyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseDataDecodingStrategyTests.swift; sourceTree = ""; }; 5623B6212AED3A2200436239 /* DatabaseQueueInMemoryCopyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseQueueInMemoryCopyTests.swift; sourceTree = ""; }; 5623B6222AED3A2200436239 /* DatabaseQueueTemporaryCopyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseQueueTemporaryCopyTests.swift; sourceTree = ""; }; + 563EA3E72C7B3A78001BE0D4 /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; 56419EFD24A54093004967E1 /* FetchRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchRequestTests.swift; sourceTree = ""; }; 56419EFE24A54093004967E1 /* DatabasePoolBackupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePoolBackupTests.swift; sourceTree = ""; }; 56419EFF24A54093004967E1 /* TableRecordDeleteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRecordDeleteTests.swift; sourceTree = ""; }; @@ -1000,6 +1003,7 @@ 56419F0224A54093004967E1 /* MutablePersistableRecordEncodableTests.swift */, 56419F3124A54096004967E1 /* MutablePersistableRecordPersistenceConflictPolicyTests.swift */, 56419F0124A54093004967E1 /* MutablePersistableRecordTests.swift */, + 563EA3E72C7B3A78001BE0D4 /* Mutex.swift */, 56419F0824A54093004967E1 /* NumericOverflowTests.swift */, 56419F0324A54093004967E1 /* OrderedDictionaryTests.swift */, 56419F1A24A54094004967E1 /* PersistableRecordTests.swift */, @@ -1441,6 +1445,7 @@ 5641A08E24A540A1004967E1 /* DatabaseLogErrorTests.swift in Sources */, 5641A01624A540A1004967E1 /* UtilsTests.swift in Sources */, 5641A12A24A540A1004967E1 /* FlattenCursorTests.swift in Sources */, + 563EA3E82C7B3A78001BE0D4 /* Mutex.swift in Sources */, 5641A10424A540A1004967E1 /* DatabaseValueTests.swift in Sources */, 5641A06824A540A1004967E1 /* RowFetchTests.swift in Sources */, 5641A0E024A540A1004967E1 /* QueryInterfaceExtensibilityTests.swift in Sources */, @@ -1689,6 +1694,7 @@ 5641A08F24A540A1004967E1 /* DatabaseLogErrorTests.swift in Sources */, 5641A01724A540A1004967E1 /* UtilsTests.swift in Sources */, 5641A12B24A540A1004967E1 /* FlattenCursorTests.swift in Sources */, + 563EA3E92C7B3A78001BE0D4 /* Mutex.swift in Sources */, 5641A10524A540A1004967E1 /* DatabaseValueTests.swift in Sources */, 5641A06924A540A1004967E1 /* RowFetchTests.swift in Sources */, 5641A0E124A540A1004967E1 /* QueryInterfaceExtensibilityTests.swift in Sources */, diff --git a/Tests/GRDBTests/AssociationPrefetchingSQLTests.swift b/Tests/GRDBTests/AssociationPrefetchingSQLTests.swift index 5a96828c6f..3813344ffe 100644 --- a/Tests/GRDBTests/AssociationPrefetchingSQLTests.swift +++ b/Tests/GRDBTests/AssociationPrefetchingSQLTests.swift @@ -80,7 +80,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -105,7 +105,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -131,7 +131,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("bs2")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -170,7 +170,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .order(Column("colb2"))) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -221,7 +221,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .hasMany(Child.self)) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -244,7 +244,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .hasMany(Child.self)) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -263,7 +263,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .filter(Column("parentA") == "foo") .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -286,7 +286,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey() .limit(1) - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -318,7 +318,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -352,7 +352,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -404,7 +404,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("cs2")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -502,7 +502,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .including(all: Child.hasMany(GrandChild.self))) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -534,7 +534,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .including(all: Child.hasMany(GrandChild.self))) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -550,7 +550,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .including(all: Child.hasMany(GrandChild.self))) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -576,7 +576,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .filter(Column("name") == "foo") .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -617,7 +617,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -646,7 +646,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -699,7 +699,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("cs2")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -741,7 +741,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -777,7 +777,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("ds3")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -821,7 +821,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -856,7 +856,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -894,7 +894,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -936,7 +936,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -970,7 +970,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey()) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1010,7 +1010,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .including(all: A.hasMany(C.self)) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1052,7 +1052,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .including(all: A.hasMany(C.self)) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1098,7 +1098,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .including(all: A.hasMany(C.self)) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1139,7 +1139,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { ) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1191,7 +1191,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("a2")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1249,7 +1249,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { ) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1301,7 +1301,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("c2")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1361,7 +1361,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey() .filter(Column("cold2") != 8) - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1399,7 +1399,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey() .filter(Column("cold2") != 8) - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1437,7 +1437,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { ) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1492,7 +1492,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("a2")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1553,7 +1553,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { ) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1608,7 +1608,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .forKey("c2")) .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1671,7 +1671,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey() .filter(Column("cold2") != 8) - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1712,7 +1712,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .orderByPrimaryKey() .filter(Column("cold2") != 8) - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1755,7 +1755,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { .filter(sql: "1 + 1") .orderByPrimaryKey() - sqlQueries.removeAll() + clearSQLQueries() _ = try Row.fetchAll(db, request) let selectQueries = sqlQueries.filter(isSelectQuery) @@ -1802,7 +1802,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { do { // Group an association - sqlQueries.removeAll() + clearSQLQueries() let association = Team.players.select(max(Column("score"))).group(Column("category")) let request = Team.including(all: association) _ = try Row.fetchAll(db, request) @@ -1821,7 +1821,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { do { // Filter an association with an association aggregate - sqlQueries.removeAll() + clearSQLQueries() let association = Team.players.having(Player.awards.isEmpty) let request = Team.including(all: association) _ = try Row.fetchAll(db, request) @@ -1842,7 +1842,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { do { // Annotate an association with an association aggregate - sqlQueries.removeAll() + clearSQLQueries() let association = Team.players.annotated(with: Player.awards.count) let request = Team.including(all: association) _ = try Row.fetchAll(db, request) @@ -1880,7 +1880,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { try db.execute(sql: "INSERT INTO team DEFAULT VALUES") do { - sqlQueries.removeAll() + clearSQLQueries() let association = Team.players.distinct() let request = Team.including(all: association) _ = try Row.fetchAll(db, request) @@ -1916,7 +1916,7 @@ class AssociationPrefetchingSQLTests: GRDBTestCase { try db.execute(sql: "INSERT INTO team DEFAULT VALUES") do { - sqlQueries.removeAll() + clearSQLQueries() let cte = CommonTableExpression(named: "cte", sql: "SELECT 42") let association = Team.players.with(cte).filter(Column("playerId") == cte.all()) let request = Team.including(all: association) diff --git a/Tests/GRDBTests/DatabaseDataEncodingStrategyTests.swift b/Tests/GRDBTests/DatabaseDataEncodingStrategyTests.swift index b9219589f4..f6e4758821 100644 --- a/Tests/GRDBTests/DatabaseDataEncodingStrategyTests.swift +++ b/Tests/GRDBTests/DatabaseDataEncodingStrategyTests.swift @@ -266,7 +266,7 @@ extension DatabaseDataEncodingStrategyTests { } do { - sqlQueries.removeAll() + clearSQLQueries() try Table>("t").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit } @@ -286,7 +286,7 @@ extension DatabaseDataEncodingStrategyTests { } do { - sqlQueries.removeAll() + clearSQLQueries() try Table>("t").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit } diff --git a/Tests/GRDBTests/DatabaseDateEncodingStrategyTests.swift b/Tests/GRDBTests/DatabaseDateEncodingStrategyTests.swift index 6db6c0b4cc..4aec3e6107 100644 --- a/Tests/GRDBTests/DatabaseDateEncodingStrategyTests.swift +++ b/Tests/GRDBTests/DatabaseDateEncodingStrategyTests.swift @@ -376,7 +376,7 @@ extension DatabaseDateEncodingStrategyTests { } do { - sqlQueries.removeAll() + clearSQLQueries() try Table>("t").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit } @@ -396,7 +396,7 @@ extension DatabaseDateEncodingStrategyTests { } do { - sqlQueries.removeAll() + clearSQLQueries() try Table>("t").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit } diff --git a/Tests/GRDBTests/DatabaseErrorTests.swift b/Tests/GRDBTests/DatabaseErrorTests.swift index 8bba886ff5..e968b44074 100644 --- a/Tests/GRDBTests/DatabaseErrorTests.swift +++ b/Tests/GRDBTests/DatabaseErrorTests.swift @@ -17,7 +17,7 @@ class DatabaseErrorTests: GRDBTestCase { try dbQueue.inTransaction { db in try db.execute(sql: "CREATE TABLE persons (id INTEGER PRIMARY KEY)") try db.execute(sql: "CREATE TABLE pets (masterId INTEGER NOT NULL REFERENCES persons(id), name TEXT)") - sqlQueries.removeAll() + clearSQLQueries() try db.execute(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)", arguments: [1, "Bobby"]) XCTFail() return .commit @@ -44,7 +44,7 @@ class DatabaseErrorTests: GRDBTestCase { XCTAssertTrue(db.isInsideTransaction) try db.execute(sql: "CREATE TABLE persons (id INTEGER PRIMARY KEY)") try db.execute(sql: "CREATE TABLE pets (masterId INTEGER NOT NULL REFERENCES persons(id), name TEXT)") - sqlQueries.removeAll() + clearSQLQueries() try db.execute(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)", arguments: [1, "Bobby"]) XCTFail() return .commit diff --git a/Tests/GRDBTests/DatabaseSavepointTests.swift b/Tests/GRDBTests/DatabaseSavepointTests.swift index bc727f28eb..b2fe86d256 100644 --- a/Tests/GRDBTests/DatabaseSavepointTests.swift +++ b/Tests/GRDBTests/DatabaseSavepointTests.swift @@ -101,7 +101,7 @@ class DatabaseSavepointTests: GRDBTestCase { let dbQueue = try makeDatabaseQueue() let observer = Observer() dbQueue.add(transactionObserver: observer) - sqlQueries.removeAll() + clearSQLQueries() try dbQueue.writeWithoutTransaction { db in try insertItem(db, name: "item1") try db.inSavepoint { @@ -130,7 +130,7 @@ class DatabaseSavepointTests: GRDBTestCase { let dbQueue = try makeDatabaseQueue() let observer = Observer() dbQueue.add(transactionObserver: observer) - sqlQueries.removeAll() + clearSQLQueries() try dbQueue.writeWithoutTransaction { db in try insertItem(db, name: "item1") try db.inSavepoint { @@ -159,7 +159,7 @@ class DatabaseSavepointTests: GRDBTestCase { let dbQueue = try makeDatabaseQueue() let observer = Observer() dbQueue.add(transactionObserver: observer) - sqlQueries.removeAll() + clearSQLQueries() try dbQueue.writeWithoutTransaction { db in try insertItem(db, name: "item1") try db.inSavepoint { @@ -196,7 +196,7 @@ class DatabaseSavepointTests: GRDBTestCase { try dbQueue.inDatabase { db in try db.execute(sql: "DELETE FROM items") } observer.reset() - sqlQueries.removeAll() + clearSQLQueries() try dbQueue.writeWithoutTransaction { db in try insertItem(db, name: "item1") try db.inSavepoint { @@ -233,7 +233,7 @@ class DatabaseSavepointTests: GRDBTestCase { try dbQueue.inDatabase { db in try db.execute(sql: "DELETE FROM items") } observer.reset() - sqlQueries.removeAll() + clearSQLQueries() try dbQueue.writeWithoutTransaction { db in try insertItem(db, name: "item1") try db.inSavepoint { @@ -271,7 +271,7 @@ class DatabaseSavepointTests: GRDBTestCase { try dbQueue.inDatabase { db in try db.execute(sql: "DELETE FROM items") } observer.reset() - sqlQueries.removeAll() + clearSQLQueries() try dbQueue.writeWithoutTransaction { db in try insertItem(db, name: "item1") try db.inSavepoint { diff --git a/Tests/GRDBTests/DatabaseTests.swift b/Tests/GRDBTests/DatabaseTests.swift index 064deb00a3..6b37ab2ad1 100644 --- a/Tests/GRDBTests/DatabaseTests.swift +++ b/Tests/GRDBTests/DatabaseTests.swift @@ -602,7 +602,7 @@ class DatabaseTests : GRDBTestCase { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() try db.inSavepoint { .commit } try db.inTransaction { .commit } try db.inTransaction(.immediate) { .commit } @@ -610,7 +610,7 @@ class DatabaseTests : GRDBTestCase { } try db.readOnly { - sqlQueries.removeAll() + clearSQLQueries() try db.inSavepoint { .commit } try db.inTransaction { .commit } XCTAssertEqual(Set(sqlQueries), ["BEGIN DEFERRED TRANSACTION", "COMMIT TRANSACTION"]) diff --git a/Tests/GRDBTests/DatabaseUUIDEncodingStrategyTests.swift b/Tests/GRDBTests/DatabaseUUIDEncodingStrategyTests.swift index 85c573377a..5ed9f6bb08 100644 --- a/Tests/GRDBTests/DatabaseUUIDEncodingStrategyTests.swift +++ b/Tests/GRDBTests/DatabaseUUIDEncodingStrategyTests.swift @@ -357,7 +357,7 @@ extension DatabaseUUIDEncodingStrategyTests { } do { - sqlQueries.removeAll() + clearSQLQueries() try Table>("t").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit } @@ -377,7 +377,7 @@ extension DatabaseUUIDEncodingStrategyTests { } do { - sqlQueries.removeAll() + clearSQLQueries() try Table>("t").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit } @@ -397,7 +397,7 @@ extension DatabaseUUIDEncodingStrategyTests { } do { - sqlQueries.removeAll() + clearSQLQueries() try Table>("t").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit } diff --git a/Tests/GRDBTests/DerivableRequestTests.swift b/Tests/GRDBTests/DerivableRequestTests.swift index 1cb5f91b25..98b0c87fb2 100644 --- a/Tests/GRDBTests/DerivableRequestTests.swift +++ b/Tests/GRDBTests/DerivableRequestTests.swift @@ -180,7 +180,7 @@ class DerivableRequestTests: GRDBTestCase { .forKey("fullName"))) // ... for one table - sqlQueries.removeAll() + clearSQLQueries() let authorNames = try Author.all() .orderByFullName() .fetchAll(db) @@ -192,7 +192,7 @@ class DerivableRequestTests: GRDBTestCase { "firstName" COLLATE swiftLocalizedCaseInsensitiveCompare """) - sqlQueries.removeAll() + clearSQLQueries() let reversedAuthorNames = try Author.all() .orderByFullName() .reversed() @@ -205,7 +205,7 @@ class DerivableRequestTests: GRDBTestCase { "firstName" COLLATE swiftLocalizedCaseInsensitiveCompare DESC """) - sqlQueries.removeAll() + clearSQLQueries() _ /* unorderedAuthors */ = try Author.all() .orderByFullName() .unordered() @@ -214,7 +214,7 @@ class DerivableRequestTests: GRDBTestCase { SELECT * FROM "author" """) - sqlQueries.removeAll() + clearSQLQueries() _ /* stableOrderAuthors */ = try Author.all() .withStableOrder() .fetchAll(db) @@ -222,7 +222,7 @@ class DerivableRequestTests: GRDBTestCase { SELECT * FROM "author" ORDER BY "id" """) - sqlQueries.removeAll() + clearSQLQueries() _ /* stableOrderAuthors */ = try Author.all() .orderByFullName() .withStableOrder() @@ -232,7 +232,7 @@ class DerivableRequestTests: GRDBTestCase { """) // ... for one view - sqlQueries.removeAll() + clearSQLQueries() _ /* authorViewNames */ = try Table("authorView").all() .order(Column("fullName")) .fetchAll(db) @@ -241,7 +241,7 @@ class DerivableRequestTests: GRDBTestCase { ORDER BY "fullName" """) - sqlQueries.removeAll() + clearSQLQueries() _ /* reversedAuthorViewNames */ = try Table("authorView").all() .order(Column("fullName")) .reversed() @@ -251,7 +251,7 @@ class DerivableRequestTests: GRDBTestCase { ORDER BY "fullName" DESC """) - sqlQueries.removeAll() + clearSQLQueries() _ /* unorderedAuthorViews */ = try Table("authorView").all() .order(Column("fullName")) .unordered() @@ -260,7 +260,7 @@ class DerivableRequestTests: GRDBTestCase { SELECT * FROM "authorView" """) - sqlQueries.removeAll() + clearSQLQueries() _ /* stableOrderAuthorViews */ = try Table("authorView").all() .withStableOrder() .fetchAll(db) @@ -268,7 +268,7 @@ class DerivableRequestTests: GRDBTestCase { SELECT * FROM "authorView" ORDER BY 1, 2, 3, 4, 5 """) - sqlQueries.removeAll() + clearSQLQueries() _ /* stableOrderAuthorViews */ = try Table("authorView").all() .order(Column("fullName")) .withStableOrder() @@ -278,7 +278,7 @@ class DerivableRequestTests: GRDBTestCase { """) // ... for two tables (2) - sqlQueries.removeAll() + clearSQLQueries() let bookTitles = try Book .joining(required: Book.author.orderByFullName()) .orderByTitle() @@ -294,7 +294,7 @@ class DerivableRequestTests: GRDBTestCase { "author"."firstName" COLLATE swiftLocalizedCaseInsensitiveCompare """) - sqlQueries.removeAll() + clearSQLQueries() let reversedBookTitles = try Book .joining(required: Book.author.orderByFullName()) .orderByTitle() @@ -311,7 +311,7 @@ class DerivableRequestTests: GRDBTestCase { "author"."firstName" COLLATE swiftLocalizedCaseInsensitiveCompare DESC """) - sqlQueries.removeAll() + clearSQLQueries() _ /* unorderedBooks */ = try Book .joining(required: Book.author.orderByFullName()) .orderByTitle() @@ -322,7 +322,7 @@ class DerivableRequestTests: GRDBTestCase { JOIN "author" ON "author"."id" = "book"."authorId" """) - sqlQueries.removeAll() + clearSQLQueries() _ /* stableOrderBooks */ = try Book .joining(required: Book.author.orderByFullName()) .orderByTitle() @@ -346,7 +346,7 @@ class DerivableRequestTests: GRDBTestCase { try libraryMigrator.migrate(dbQueue) try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let request = Author.all().selectCountry() let authorCountries = try Set(String.fetchAll(db, request)) XCTAssertEqual(authorCountries, ["FR", "US"]) @@ -356,7 +356,7 @@ class DerivableRequestTests: GRDBTestCase { } do { - sqlQueries.removeAll() + clearSQLQueries() let request = Book.including(required: Book.author.selectCountry()) _ = try Row.fetchAll(db, request) XCTAssertEqual(lastSQLQuery, """ @@ -373,7 +373,7 @@ class DerivableRequestTests: GRDBTestCase { try libraryMigrator.migrate(dbQueue) try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let frenchBookTitles = try Book.all() .filter(authorCountry: "FR") .order(Column("title")) @@ -389,7 +389,7 @@ class DerivableRequestTests: GRDBTestCase { } do { - sqlQueries.removeAll() + clearSQLQueries() let frenchAuthorFullNames = try Author .joining(required: Author.books.filter(authorCountry: "FR")) .order(Column("firstName")) @@ -436,7 +436,7 @@ class DerivableRequestTests: GRDBTestCase { // matchingFts4 do { - sqlQueries.removeAll() + clearSQLQueries() let title = try Book.all() .matchingFts4(FTS3Pattern(rawPattern: "moby dick")) .fetchOne(db) @@ -448,7 +448,7 @@ class DerivableRequestTests: GRDBTestCase { LIMIT 1 """)) - sqlQueries.removeAll() + clearSQLQueries() let fullName = try Author .joining(required: Author.books.matchingFts4(FTS3Pattern(rawPattern: "moby dick"))) .fetchOne(db) @@ -465,7 +465,7 @@ class DerivableRequestTests: GRDBTestCase { #if SQLITE_ENABLE_FTS5 // matchingFts5 do { - sqlQueries.removeAll() + clearSQLQueries() let title = try Book.all() .matchingFts5(FTS3Pattern(rawPattern: "cote swann")) .fetchOne(db) @@ -477,7 +477,7 @@ class DerivableRequestTests: GRDBTestCase { LIMIT 1 """)) - sqlQueries.removeAll() + clearSQLQueries() let fullName = try Author .joining(required: Author.books.matchingFts5(FTS3Pattern(rawPattern: "cote swann"))) .fetchOne(db) diff --git a/Tests/GRDBTests/FTS3RecordTests.swift b/Tests/GRDBTests/FTS3RecordTests.swift index b37c08bb54..c1c5168686 100644 --- a/Tests/GRDBTests/FTS3RecordTests.swift +++ b/Tests/GRDBTests/FTS3RecordTests.swift @@ -102,14 +102,14 @@ class FTS3RecordTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let pattern = try FTS3Pattern(rawPattern: "Herman Melville") XCTAssertEqual(try Book.matching(pattern).fetchCount(db), 1) XCTAssertTrue(sqlQueries.contains("SELECT COUNT(*) FROM \"books\" WHERE \"books\" MATCH 'Herman Melville'")) } do { - sqlQueries = [] + clearSQLQueries() XCTAssertEqual(try Book.fetchCount(db), 1) XCTAssertTrue(sqlQueries.contains("SELECT COUNT(*) FROM \"books\"")) } diff --git a/Tests/GRDBTests/FTS4RecordTests.swift b/Tests/GRDBTests/FTS4RecordTests.swift index 646c3852ef..1c81bc6a49 100644 --- a/Tests/GRDBTests/FTS4RecordTests.swift +++ b/Tests/GRDBTests/FTS4RecordTests.swift @@ -102,14 +102,14 @@ class FTS4RecordTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let pattern = try FTS3Pattern(rawPattern: "Herman Melville") XCTAssertEqual(try Book.matching(pattern).fetchCount(db), 1) XCTAssertTrue(sqlQueries.contains("SELECT COUNT(*) FROM \"books\" WHERE \"books\" MATCH 'Herman Melville'")) } do { - sqlQueries = [] + clearSQLQueries() XCTAssertEqual(try Book.fetchCount(db), 1) XCTAssertTrue(sqlQueries.contains("SELECT COUNT(*) FROM \"books\"")) } diff --git a/Tests/GRDBTests/FTS5RecordTests.swift b/Tests/GRDBTests/FTS5RecordTests.swift index b25b0a0135..6656b2ef92 100644 --- a/Tests/GRDBTests/FTS5RecordTests.swift +++ b/Tests/GRDBTests/FTS5RecordTests.swift @@ -101,14 +101,14 @@ class FTS5RecordTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let pattern = FTS5Pattern(matchingAllTokensIn: "Herman Melville")! XCTAssertEqual(try Book.matching(pattern).fetchCount(db), 1) XCTAssertTrue(sqlQueries.contains("SELECT COUNT(*) FROM \"books\" WHERE \"books\" MATCH 'herman melville'")) } do { - sqlQueries = [] + clearSQLQueries() XCTAssertEqual(try Book.fetchCount(db), 1) XCTAssertTrue(sqlQueries.contains("SELECT COUNT(*) FROM \"books\"")) } diff --git a/Tests/GRDBTests/ForeignKeyDefinitionTests.swift b/Tests/GRDBTests/ForeignKeyDefinitionTests.swift index d6bacfc5a6..8a4940476c 100644 --- a/Tests/GRDBTests/ForeignKeyDefinitionTests.swift +++ b/Tests/GRDBTests/ForeignKeyDefinitionTests.swift @@ -20,7 +20,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.column("name", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent") @@ -99,7 +99,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.column("name", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child", options: .ifNotExists) { t in t.column("a") t.belongsTo("parent") @@ -155,7 +155,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.column("name", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent").unique() @@ -197,7 +197,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.column("name", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent", indexed: false) @@ -239,7 +239,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.column("name", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent").notNull() @@ -295,7 +295,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.column("name", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent", onDelete: .cascade, onUpdate: .setNull, deferred: true) @@ -411,7 +411,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.primaryKey("id", .integer) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent") @@ -494,7 +494,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.primaryKey("id", .integer) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child", options: .ifNotExists) { t in t.column("a") t.belongsTo("parent") @@ -556,7 +556,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.primaryKey("id", .integer) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent").unique() @@ -604,7 +604,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.primaryKey("id", .integer) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent", indexed: false) @@ -652,7 +652,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.primaryKey("id", .integer) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent").notNull() @@ -714,7 +714,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { t.primaryKey("id", .integer) } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent", onDelete: .cascade, onUpdate: .setNull, deferred: true) @@ -757,7 +757,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { func testTable_belongsTo_singleColumnPrimaryKey_autoreference_singular() throws { try makeDatabaseQueue().inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "employee") { t in t.autoIncrementedPrimaryKey("id") t.column("a") @@ -786,7 +786,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } do { - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "node") { t in t.primaryKey { t.column("code") } t.column("a") @@ -820,7 +820,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { func testTable_belongsTo_singleColumnPrimaryKey_autoreference_plural() throws { try makeDatabaseQueue().inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "employees") { t in t.autoIncrementedPrimaryKey("id") t.column("a") @@ -849,7 +849,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } do { - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "nodes") { t in t.primaryKey { t.column("code") } t.column("a") @@ -913,7 +913,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent") @@ -1025,7 +1025,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child", options: .ifNotExists) { t in t.column("a") t.belongsTo("parent") @@ -1107,7 +1107,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent").unique() @@ -1189,7 +1189,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent", indexed: false) @@ -1257,7 +1257,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent").notNull() @@ -1339,7 +1339,7 @@ class ForeignKeyDefinitionTests: GRDBTestCase { } } - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "child") { t in t.column("a") t.belongsTo("parent", onDelete: .cascade, onUpdate: .setNull, deferred: true) diff --git a/Tests/GRDBTests/GRDBTestCase.swift b/Tests/GRDBTests/GRDBTestCase.swift index 837cf89b46..5c7ca7a8b7 100644 --- a/Tests/GRDBTests/GRDBTestCase.swift +++ b/Tests/GRDBTests/GRDBTestCase.swift @@ -64,10 +64,12 @@ class GRDBTestCase: XCTestCase { // The default path for database pool directory private var dbDirectoryPath: String! - // Populated by default configuration - @LockedBox var sqlQueries: [String] = [] + let _sqlQueriesMutex: Mutex<[String]> = Mutex([]) - // Populated by default configuration + // Automatically updated by default dbConfiguration + var sqlQueries: [String] {_sqlQueriesMutex.load() } + + // Automatically updated by default dbConfiguration var lastSQLQuery: String? { sqlQueries.last } override func setUp() { @@ -112,9 +114,11 @@ class GRDBTestCase: XCTestCase { } } - dbConfiguration.prepareDatabase { db in + dbConfiguration.prepareDatabase { [_sqlQueriesMutex] db in db.trace { event in - self.sqlQueries.append(event.expandedDescription) + _sqlQueriesMutex.withLock { + $0.append(event.expandedDescription) + } } #if GRDBCIPHER_USE_ENCRYPTION @@ -122,7 +126,7 @@ class GRDBTestCase: XCTestCase { #endif } - sqlQueries = [] + clearSQLQueries() } override func tearDown() { @@ -130,6 +134,10 @@ class GRDBTestCase: XCTestCase { do { try FileManager.default.removeItem(atPath: dbDirectoryPath) } catch { } } + func clearSQLQueries() { + _sqlQueriesMutex.store([]) + } + func assertNoError(file: StaticString = #file, line: UInt = #line, _ test: () throws -> Void) { do { try test() diff --git a/Tests/GRDBTests/MutablePersistableRecordChangesTests.swift b/Tests/GRDBTests/MutablePersistableRecordChangesTests.swift index f530149f8a..e3a3485037 100644 --- a/Tests/GRDBTests/MutablePersistableRecordChangesTests.swift +++ b/Tests/GRDBTests/MutablePersistableRecordChangesTests.swift @@ -319,14 +319,14 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { try record.insert(db) do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { _ in } XCTAssertFalse(modified) XCTAssert(sqlQueries.isEmpty) } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Arthur" } @@ -335,7 +335,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = nil } @@ -346,7 +346,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Bob" $0.lastName = "Johnson" @@ -391,14 +391,14 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { try record.insert(db) do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { _ in } XCTAssertFalse(modified) XCTAssert(sqlQueries.isEmpty) } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Arthur" } @@ -407,7 +407,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = nil } @@ -418,7 +418,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Bob" $0.lastName = "Johnson" @@ -457,14 +457,14 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { try record.insert(db) do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { _ in } XCTAssertFalse(modified) XCTAssert(sqlQueries.isEmpty) } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Arthur" } @@ -473,7 +473,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = nil } @@ -484,7 +484,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Bob" $0.lastName = "Johnson" @@ -519,14 +519,14 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { try record.insert(db) do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { _ in } XCTAssertFalse(modified) XCTAssert(sqlQueries.isEmpty) } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Arthur" } @@ -535,7 +535,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = nil } @@ -546,7 +546,7 @@ class MutablePersistableRecordChangesTests: GRDBTestCase { } do { - sqlQueries = [] + clearSQLQueries() let modified = try record.updateChanges(db) { $0.firstName = "Bob" $0.lastName = "Johnson" diff --git a/Tests/GRDBTests/MutablePersistableRecordTests.swift b/Tests/GRDBTests/MutablePersistableRecordTests.swift index 7348cbbbb6..a5da3c08d4 100644 --- a/Tests/GRDBTests/MutablePersistableRecordTests.swift +++ b/Tests/GRDBTests/MutablePersistableRecordTests.swift @@ -1282,7 +1282,7 @@ extension MutablePersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() var partialPlayer = PartialPlayer(name: "Arthur") let fullPlayer = try partialPlayer.insertAndFetch(db, as: FullPlayer.self) @@ -1332,7 +1332,7 @@ extension MutablePersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() var partialPlayer = PartialPlayer(name: "Arthur") let score = try partialPlayer.insertAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement)! @@ -1368,7 +1368,7 @@ extension MutablePersistableRecordTests { do { // Test onConflict: .ignore - sqlQueries.removeAll() + clearSQLQueries() var player = FullPlayer(id: 1, name: "Barbara", score: 100) try XCTAssertTrue(player.exists(db)) let score = try player.insertAndFetch(db, onConflict: .ignore, selection: [Column("score")]) { (statement: Statement) in @@ -1444,7 +1444,7 @@ extension MutablePersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() var partialPlayer = PartialPlayer(name: "Arthur") let fullPlayer = try partialPlayer.saveAndFetch(db, as: FullPlayer.self) @@ -1482,7 +1482,7 @@ extension MutablePersistableRecordTests { do { var partialPlayer = PartialPlayer(id: 1, name: "Arthur") try partialPlayer.delete(db) - sqlQueries.removeAll() + clearSQLQueries() let fullPlayer = try partialPlayer.saveAndFetch(db, as: FullPlayer.self) XCTAssert(sqlQueries.contains(""" @@ -1519,7 +1519,7 @@ extension MutablePersistableRecordTests { } do { - sqlQueries.removeAll() + clearSQLQueries() var partialPlayer = PartialPlayer(id: 1, name: "Arthur") let fullPlayer = try partialPlayer.saveAndFetch(db, as: FullPlayer.self) @@ -1570,7 +1570,7 @@ extension MutablePersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() var partialPlayer = PartialPlayer(name: "Arthur") let score = try partialPlayer.saveAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement) @@ -1608,7 +1608,7 @@ extension MutablePersistableRecordTests { do { var partialPlayer = PartialPlayer(id: 1, name: "Arthur") try partialPlayer.delete(db) - sqlQueries.removeAll() + clearSQLQueries() let score = try partialPlayer.saveAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement) } @@ -1645,7 +1645,7 @@ extension MutablePersistableRecordTests { } do { - sqlQueries.removeAll() + clearSQLQueries() var partialPlayer = PartialPlayer(id: 1, name: "Arthur") let score = try partialPlayer.saveAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement) @@ -2405,7 +2405,7 @@ extension MutablePersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() var player = FullPlayer(id: 1, name: "Arthur", score: 1000) let upsertedPlayer = try player.upsertAndFetch(db) @@ -2449,7 +2449,7 @@ extension MutablePersistableRecordTests { } do { - sqlQueries.removeAll() + clearSQLQueries() var player = FullPlayer(id: 1, name: "Barbara", score: 100) let upsertedPlayer = try player.upsertAndFetch(db) @@ -2508,7 +2508,7 @@ extension MutablePersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() var partialPlayer = PartialPlayer(name: "Arthur") let fullPlayer = try partialPlayer.upsertAndFetch(db, as: FullPlayer.self) diff --git a/Tests/GRDBTests/Mutex.swift b/Tests/GRDBTests/Mutex.swift new file mode 100644 index 0000000000..1fb69c2e22 --- /dev/null +++ b/Tests/GRDBTests/Mutex.swift @@ -0,0 +1,54 @@ +import Foundation + +/// A Mutex protects a value with an NSLock. +/// +/// We'll replace it with the SE-0433 Mutex when it is available. +/// +final class Mutex { + private var _value: T + private var lock = NSLock() + + init(_ value: T) { + _value = value + } + + /// Runs the provided closure while holding a lock on the value. + /// + /// - parameter body: A closure that can modify the value. + func withLock(_ body: (inout T) throws -> U) rethrows -> U { + lock.lock() + defer { lock.unlock() } + return try body(&_value) + } +} + +// Inspired by +extension Mutex { + func load() -> T { + withLock { $0 } + } + + func store(_ value: T) { + withLock { $0 = value } + } +} + +extension Mutex where T: Numeric { + @discardableResult + func increment() -> T { + withLock { n in + n += 1 + return n + } + } + + @discardableResult + func decrement() -> T { + withLock { n in + n -= 1 + return n + } + } +} + +extension Mutex: @unchecked Sendable where T: Sendable { } diff --git a/Tests/GRDBTests/PersistableRecordTests.swift b/Tests/GRDBTests/PersistableRecordTests.swift index 5c9bc6761b..c391e27da0 100644 --- a/Tests/GRDBTests/PersistableRecordTests.swift +++ b/Tests/GRDBTests/PersistableRecordTests.swift @@ -1340,7 +1340,7 @@ extension PersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let partialPlayer = PartialPlayer(name: "Arthur") let fullPlayer = try partialPlayer.insertAndFetch(db, as: FullPlayer.self) @@ -1389,7 +1389,7 @@ extension PersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let partialPlayer = PartialPlayer(name: "Arthur") let score = try partialPlayer.insertAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement)! @@ -1442,7 +1442,7 @@ extension PersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let partialPlayer = PartialPlayer(name: "Arthur") let fullPlayer = try partialPlayer.saveAndFetch(db, as: FullPlayer.self) @@ -1479,7 +1479,7 @@ extension PersistableRecordTests { do { let partialPlayer = PartialPlayer(id: 1, name: "Arthur") try partialPlayer.delete(db) - sqlQueries.removeAll() + clearSQLQueries() let fullPlayer = try partialPlayer.saveAndFetch(db, as: FullPlayer.self) XCTAssert(sqlQueries.contains(""" @@ -1515,7 +1515,7 @@ extension PersistableRecordTests { } do { - sqlQueries.removeAll() + clearSQLQueries() let partialPlayer = PartialPlayer(id: 1, name: "Arthur") let fullPlayer = try partialPlayer.saveAndFetch(db, as: FullPlayer.self) @@ -1565,7 +1565,7 @@ extension PersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let partialPlayer = PartialPlayer(name: "Arthur") let score = try partialPlayer.saveAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement) @@ -1602,7 +1602,7 @@ extension PersistableRecordTests { do { let partialPlayer = PartialPlayer(id: 1, name: "Arthur") try partialPlayer.delete(db) - sqlQueries.removeAll() + clearSQLQueries() let score = try partialPlayer.saveAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement) } @@ -1638,7 +1638,7 @@ extension PersistableRecordTests { } do { - sqlQueries.removeAll() + clearSQLQueries() let partialPlayer = PartialPlayer(id: 1, name: "Arthur") let score = try partialPlayer.saveAndFetch(db, selection: [Column("score")]) { (statement: Statement) in try Int.fetchOne(statement) @@ -1974,7 +1974,7 @@ extension PersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let player = FullPlayer(id: 1, name: "Arthur", score: 1000) let upsertedPlayer = try player.upsertAndFetch(db) @@ -2018,7 +2018,7 @@ extension PersistableRecordTests { } do { - sqlQueries.removeAll() + clearSQLQueries() let player = FullPlayer(id: 1, name: "Barbara", score: 100) let upsertedPlayer = try player.upsertAndFetch(db) @@ -2077,7 +2077,7 @@ extension PersistableRecordTests { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in do { - sqlQueries.removeAll() + clearSQLQueries() let partialPlayer = PartialPlayer(name: "Arthur") let fullPlayer = try partialPlayer.upsertAndFetch(db, as: FullPlayer.self) diff --git a/Tests/GRDBTests/TableDefinitionTests.swift b/Tests/GRDBTests/TableDefinitionTests.swift index 1079b39d61..3c138d6e59 100644 --- a/Tests/GRDBTests/TableDefinitionTests.swift +++ b/Tests/GRDBTests/TableDefinitionTests.swift @@ -204,7 +204,7 @@ class TableDefinitionTests: GRDBTestCase { func testColumnIndexed() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "test") { t in t.column("a", .integer).indexed() t.column("b", .integer).indexed() @@ -219,7 +219,7 @@ class TableDefinitionTests: GRDBTestCase { func testColumnIndexedInheritsIfNotExistsFlag() throws { let dbQueue = try makeDatabaseQueue() try dbQueue.inDatabase { db in - sqlQueries.removeAll() + clearSQLQueries() try db.create(table: "test", options: [.ifNotExists]) { t in t.column("a", .integer).indexed() t.column("b", .integer).indexed() @@ -733,7 +733,7 @@ class TableDefinitionTests: GRDBTestCase { t.column("a", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.alter(table: "test") { t in t.add(column: "b", .text) t.add(column: "c", .integer).notNull().defaults(to: 1) @@ -760,7 +760,7 @@ class TableDefinitionTests: GRDBTestCase { t.column("a", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.alter(table: "hiddenRowIdTable") { t in t.add(column: "ref").references("hiddenRowIdTable") } @@ -775,7 +775,7 @@ class TableDefinitionTests: GRDBTestCase { t.column("a", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.alter(table: "explicitPrimaryKey") { t in t.add(column: "ref").references("explicitPrimaryKey") } @@ -816,7 +816,7 @@ class TableDefinitionTests: GRDBTestCase { t.column("a", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.alter(table: "test") { t in t.rename(column: "a", to: "b") t.add(column: "c") @@ -870,7 +870,7 @@ class TableDefinitionTests: GRDBTestCase { t.column("c", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.alter(table: "test") { t in t.add(column: "d", .integer).generatedAs(sql: "a*abs(b)", .virtual) t.add(column: "e", .text).generatedAs(sql: "substr(c,b,b+1)", .virtual) @@ -904,7 +904,7 @@ class TableDefinitionTests: GRDBTestCase { t.column("b", .text) } - sqlQueries.removeAll() + clearSQLQueries() try db.alter(table: "test") { t in t.drop(column: "b") } diff --git a/Tests/GRDBTests/TableRecord+QueryInterfaceRequestTests.swift b/Tests/GRDBTests/TableRecord+QueryInterfaceRequestTests.swift index 6d01e8f7a0..737220992c 100644 --- a/Tests/GRDBTests/TableRecord+QueryInterfaceRequestTests.swift +++ b/Tests/GRDBTests/TableRecord+QueryInterfaceRequestTests.swift @@ -386,7 +386,7 @@ class TableRecordQueryInterfaceRequestTests: GRDBTestCase { try XCTAssertFalse(Player.exists(db, id: 1)) XCTAssertEqual(lastSQLQuery, "SELECT EXISTS (SELECT * FROM \"player\" WHERE \"id\" = 1)") - sqlQueries.removeAll() + clearSQLQueries() try XCTAssertFalse(Player.exists(db, id: nil)) XCTAssertNil(lastSQLQuery) // Database not hit diff --git a/Tests/GRDBTests/TableRecordUpdateTests.swift b/Tests/GRDBTests/TableRecordUpdateTests.swift index dd375bc8d3..ac7bf5f84b 100644 --- a/Tests/GRDBTests/TableRecordUpdateTests.swift +++ b/Tests/GRDBTests/TableRecordUpdateTests.swift @@ -480,7 +480,7 @@ class TableRecordUpdateTests: GRDBTestCase { func testUpdateAllWithoutAssignmentDoesNotAccessTheDatabase() throws { try makeDatabaseQueue().write { db in try Player.createTable(db) - sqlQueries.removeAll() + clearSQLQueries() try XCTAssertEqual(Player.updateAll(db, []), 0) try XCTAssertEqual(Player.all().updateAll(db, []), 0) XCTAssert(sqlQueries.isEmpty) diff --git a/Tests/GRDBTests/TableTests.swift b/Tests/GRDBTests/TableTests.swift index 7278fa11f3..fa7325771c 100644 --- a/Tests/GRDBTests/TableTests.swift +++ b/Tests/GRDBTests/TableTests.swift @@ -830,7 +830,7 @@ class TableTests: GRDBTestCase { DELETE FROM "country" WHERE "code" = 'FR' """) - sqlQueries.removeAll() + clearSQLQueries() try Table("country").deleteOne(db, id: nil) XCTAssertNil(lastSQLQuery) // Database not hit @@ -939,7 +939,7 @@ class TableTests: GRDBTestCase { SELECT EXISTS (SELECT * FROM "country" WHERE "code" = 'FR') """) - sqlQueries.removeAll() + clearSQLQueries() try XCTAssertFalse(Table("country").exists(db, id: nil)) XCTAssertNil(lastSQLQuery) // Database not hit } diff --git a/Tests/GRDBTests/ValueObservationPrintTests.swift b/Tests/GRDBTests/ValueObservationPrintTests.swift index 74e2450be1..c2940c757b 100644 --- a/Tests/GRDBTests/ValueObservationPrintTests.swift +++ b/Tests/GRDBTests/ValueObservationPrintTests.swift @@ -4,9 +4,10 @@ import Dispatch class ValueObservationPrintTests: GRDBTestCase { class TestStream: TextOutputStream { - @LockedBox var strings: [String] = [] + private var stringsMutex: Mutex<[String]> = Mutex([]) + var strings: [String] { stringsMutex.load() } func write(_ string: String) { - strings.append(string) + stringsMutex.withLock { $0.append(string) } } } diff --git a/Tests/GRDBTests/ValueObservationTests.swift b/Tests/GRDBTests/ValueObservationTests.swift index 326d536476..c947a44d63 100644 --- a/Tests/GRDBTests/ValueObservationTests.swift +++ b/Tests/GRDBTests/ValueObservationTests.swift @@ -174,9 +174,10 @@ class ValueObservationTests: GRDBTestCase { func testTrackingExplicitRegion() throws { class TestStream: TextOutputStream { - @LockedBox var strings: [String] = [] + private var stringsMutex: Mutex<[String]> = Mutex([]) + var strings: [String] { stringsMutex.load() } func write(_ string: String) { - strings.append(string) + stringsMutex.withLock { $0.append(string) } } }