// // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import GRDB public enum BatchingPreference { case batched(UInt = Batching.kDefaultBatchSize) case unbatched } extension SDSCodableModelDatabaseInterfaceImpl { /// Traverse all records, in no particular order. func enumerateModels( modelType: Model.Type, transaction: DBReadTransaction, batchingPreference: BatchingPreference, block: (Model, UnsafeMutablePointer) -> Void ) { let batchSize = batchSize(batchingPreference: batchingPreference) enumerateModels( modelType: modelType, transaction: transaction, sql: nil, arguments: nil, batchSize: batchSize, block: block ) } /// Traverse all records, in no particular order. func enumerateModels( modelType: Model.Type, transaction: DBReadTransaction, sql: String, arguments: StatementArguments, batchingPreference: BatchingPreference, block: (Model, UnsafeMutablePointer) -> Void ) { let batchSize = batchSize(batchingPreference: batchingPreference) enumerateModels( modelType: modelType, transaction: transaction, sql: sql, arguments: arguments, batchSize: batchSize, block: block ) } /// The batch size for enumeration. private func batchSize(batchingPreference: BatchingPreference) -> UInt { switch batchingPreference { case .batched(let size): return size case .unbatched: return 0 } } /// Traverse all records, in no particular order. /// - Parameter batchSize /// If nonzero, enumeration is performed in autoreleased batches. private func enumerateModels( modelType: Model.Type, transaction: DBReadTransaction, sql: String? = nil, arguments: StatementArguments? = nil, batchSize: UInt, block: (Model, UnsafeMutablePointer) -> Void ) { failIfThrows { var recordCursor: RecordCursor if let sql = sql, let arguments = arguments { recordCursor = try Model.fetchCursor( transaction.database, sql: sql, arguments: arguments ) } else { recordCursor = try modelType.fetchCursor(transaction.database) } try Batching.loop(batchSize: batchSize) { stop in guard let value = try recordCursor.next() else { stop.pointee = true return } value.anyDidEnumerateOne(transaction: transaction) block(value, stop) } } } }