Signal-iOS/SignalServiceKit/Calls/CallLinkRecordStore.swift
2024-10-09 14:05:34 -05:00

129 lines
5.4 KiB
Swift

//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import GRDB
public import SignalRingRTC
public protocol CallLinkRecordStore {
func fetch(rowId: Int64, tx: any DBReadTransaction) throws -> CallLinkRecord?
func fetch(roomId: Data, tx: any DBReadTransaction) throws -> CallLinkRecord?
func fetchOrInsert(rootKey: CallLinkRootKey, tx: any DBWriteTransaction) throws -> (record: CallLinkRecord, inserted: Bool)
func update(_ callLinkRecord: CallLinkRecord, tx: any DBWriteTransaction) throws
func delete(_ callLinkRecord: CallLinkRecord, tx: any DBWriteTransaction) throws
func fetchAll(tx: any DBReadTransaction) throws -> [CallLinkRecord]
func fetchUpcoming(earlierThan expirationTimestamp: Date?, limit: Int, tx: any DBReadTransaction) throws -> [CallLinkRecord]
func fetchWhere(adminDeletedAtTimestampMsIsLessThan thresholdMs: UInt64, tx: any DBReadTransaction) throws -> [CallLinkRecord]
func fetchAnyPendingRecord(tx: any DBReadTransaction) throws -> CallLinkRecord?
}
public class CallLinkRecordStoreImpl: CallLinkRecordStore {
public init() {}
public func fetch(rowId: Int64, tx: any DBReadTransaction) throws -> CallLinkRecord? {
let db = tx.databaseConnection
do {
return try CallLinkRecord.fetchOne(db, key: rowId)
} catch {
throw error.grdbErrorForLogging
}
}
public func fetch(roomId: Data, tx: any DBReadTransaction) throws -> CallLinkRecord? {
let db = tx.databaseConnection
do {
return try CallLinkRecord.filter(Column(CallLinkRecord.CodingKeys.roomId) == roomId).fetchOne(db)
} catch {
throw error.grdbErrorForLogging
}
}
public func fetchOrInsert(rootKey: CallLinkRootKey, tx: any DBWriteTransaction) throws -> (record: CallLinkRecord, inserted: Bool) {
if let existingRecord = try fetch(roomId: rootKey.deriveRoomId(), tx: tx) {
return (existingRecord, false)
}
return (try CallLinkRecord.insertRecord(rootKey: rootKey, tx: tx), true)
}
public func update(_ callLinkRecord: CallLinkRecord, tx: any DBWriteTransaction) throws {
let db = tx.databaseConnection
do {
try callLinkRecord.update(db)
} catch {
throw error.grdbErrorForLogging
}
}
public func delete(_ callLinkRecord: CallLinkRecord, tx: any DBWriteTransaction) throws {
let db = tx.databaseConnection
do {
try callLinkRecord.delete(db)
} catch {
throw error.grdbErrorForLogging
}
}
public func fetchAll(tx: any DBReadTransaction) throws -> [CallLinkRecord] {
let db = tx.databaseConnection
do {
return try CallLinkRecord.fetchAll(db)
} catch {
throw error.grdbErrorForLogging
}
}
public func fetchUpcoming(earlierThan expirationTimestamp: Date?, limit: Int, tx: any DBReadTransaction) throws -> [CallLinkRecord] {
let db = tx.databaseConnection
do {
let isUpcomingColumn = Column(CallLinkRecord.CodingKeys.isUpcoming)
let expirationColumn = Column(CallLinkRecord.CodingKeys.expiration)
var baseQuery = CallLinkRecord.filter(isUpcomingColumn == true).order(expirationColumn.desc).limit(limit)
if let expirationTimestamp {
baseQuery = baseQuery.filter(expirationColumn < expirationTimestamp)
}
return try baseQuery.fetchAll(db)
} catch {
throw error.grdbErrorForLogging
}
}
public func fetchWhere(adminDeletedAtTimestampMsIsLessThan thresholdMs: UInt64, tx: any DBReadTransaction) throws -> [CallLinkRecord] {
let db = tx.databaseConnection
do {
return try CallLinkRecord.filter(Column(CallLinkRecord.CodingKeys.adminDeletedAtTimestampMs) < Int64(bitPattern: thresholdMs)).fetchAll(db)
} catch {
throw error.grdbErrorForLogging
}
}
public func fetchAnyPendingRecord(tx: any DBReadTransaction) throws -> CallLinkRecord? {
let db = tx.databaseConnection
do {
return try CallLinkRecord.filter(Column(CallLinkRecord.CodingKeys.pendingFetchCounter) > 0).fetchOne(db)
} catch {
throw error.grdbErrorForLogging
}
}
}
#if TESTABLE_BUILD
final class MockCallLinkRecordStore: CallLinkRecordStore {
func fetch(rowId: Int64, tx: any DBReadTransaction) throws -> CallLinkRecord? { fatalError() }
func fetch(roomId: Data, tx: any DBReadTransaction) throws -> CallLinkRecord? { fatalError() }
func fetchOrInsert(rootKey: CallLinkRootKey, tx: any DBWriteTransaction) throws -> (record: CallLinkRecord, inserted: Bool) { fatalError() }
func update(_ callLinkRecord: CallLinkRecord, tx: any DBWriteTransaction) throws { fatalError() }
func delete(_ callLinkRecord: CallLinkRecord, tx: any DBWriteTransaction) throws { fatalError() }
func fetchAll(tx: any DBReadTransaction) throws -> [CallLinkRecord] { fatalError() }
func fetchUpcoming(earlierThan expirationTimestamp: Date?, limit: Int, tx: any DBReadTransaction) throws -> [CallLinkRecord] { fatalError() }
func fetchWhere(adminDeletedAtTimestampMsIsLessThan thresholdMs: UInt64, tx: any DBReadTransaction) throws -> [CallLinkRecord] { fatalError() }
func fetchAnyPendingRecord(tx: any DBReadTransaction) throws -> CallLinkRecord? { fatalError() }
}
#endif