TM-SGNL-iOS/SignalServiceKit/Calls/CallLinkRecordStore.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

171 lines
7.1 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 insertFromBackup(
rootKey: CallLinkRootKey,
adminPasskey: Data?,
name: String,
restrictions: CallLinkRecord.Restrictions,
expiration: UInt64,
isUpcoming: Bool,
tx: DBWriteTransaction
) 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 enumerateAll(tx: any DBReadTransaction, block: (CallLinkRecord) throws -> Void) throws
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 insertFromBackup(
rootKey: CallLinkRootKey,
adminPasskey: Data?,
name: String,
restrictions: CallLinkRecord.Restrictions,
expiration: UInt64,
isUpcoming: Bool,
tx: DBWriteTransaction
) throws -> CallLinkRecord {
return try CallLinkRecord.insertFromBackup(
rootKey: rootKey,
adminPasskey: adminPasskey,
name: name,
restrictions: restrictions,
expiration: expiration,
isUpcoming: isUpcoming,
tx: tx
)
}
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 enumerateAll(tx: any DBReadTransaction, block: (CallLinkRecord) throws -> Void) throws {
do {
let cursor = try CallLinkRecord.fetchCursor(tx.databaseConnection)
while let next = try cursor.next() {
try block(next)
}
} 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 insertFromBackup(rootKey: SignalRingRTC.CallLinkRootKey, adminPasskey: Data?, name: String, restrictions: CallLinkRecord.Restrictions, expiration: UInt64, isUpcoming: Bool, tx: any DBWriteTransaction) 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 enumerateAll(tx: any DBReadTransaction, block: (CallLinkRecord) throws -> Void) throws { 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