TM-SGNL-iOS/SignalServiceKit/Network/Receiving/IncomingGroupsV2MessageJob+SDS.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

605 lines
23 KiB
Swift

//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public import GRDB
// NOTE: This file is generated by /Scripts/sds_codegen/sds_generate.py.
// Do not manually edit it, instead run `sds_codegen.sh`.
// MARK: - Record
public struct IncomingGroupsV2MessageJobRecord: SDSRecord {
public weak var delegate: SDSRecordDelegate?
public var tableMetadata: SDSTableMetadata {
IncomingGroupsV2MessageJobSerializer.table
}
public static var databaseTableName: String {
IncomingGroupsV2MessageJobSerializer.table.tableName
}
public var id: Int64?
// This defines all of the columns used in the table
// where this model (and any subclasses) are persisted.
public let recordType: SDSRecordType
public let uniqueId: String
// Properties
public let createdAt: Double
public let envelopeData: Data
public let plaintextData: Data?
public let wasReceivedByUD: Bool
public let groupId: Data?
public let serverDeliveryTimestamp: UInt64
public enum CodingKeys: String, CodingKey, ColumnExpression, CaseIterable {
case id
case recordType
case uniqueId
case createdAt
case envelopeData
case plaintextData
case wasReceivedByUD
case groupId
case serverDeliveryTimestamp
}
public static func columnName(_ column: IncomingGroupsV2MessageJobRecord.CodingKeys, fullyQualified: Bool = false) -> String {
fullyQualified ? "\(databaseTableName).\(column.rawValue)" : column.rawValue
}
public func didInsert(with rowID: Int64, for column: String?) {
guard let delegate = delegate else {
owsFailDebug("Missing delegate.")
return
}
delegate.updateRowId(rowID)
}
}
// MARK: - Row Initializer
public extension IncomingGroupsV2MessageJobRecord {
static var databaseSelection: [SQLSelectable] {
CodingKeys.allCases
}
init(row: Row) {
id = row[0]
recordType = row[1]
uniqueId = row[2]
createdAt = row[3]
envelopeData = row[4]
plaintextData = row[5]
wasReceivedByUD = row[6]
groupId = row[7]
serverDeliveryTimestamp = row[8]
}
}
// MARK: - StringInterpolation
public extension String.StringInterpolation {
mutating func appendInterpolation(incomingGroupsV2MessageJobColumn column: IncomingGroupsV2MessageJobRecord.CodingKeys) {
appendLiteral(IncomingGroupsV2MessageJobRecord.columnName(column))
}
mutating func appendInterpolation(incomingGroupsV2MessageJobColumnFullyQualified column: IncomingGroupsV2MessageJobRecord.CodingKeys) {
appendLiteral(IncomingGroupsV2MessageJobRecord.columnName(column, fullyQualified: true))
}
}
// MARK: - Deserialization
extension IncomingGroupsV2MessageJob {
// This method defines how to deserialize a model, given a
// database row. The recordType column is used to determine
// the corresponding model class.
class func fromRecord(_ record: IncomingGroupsV2MessageJobRecord) throws -> IncomingGroupsV2MessageJob {
guard let recordId = record.id else {
throw SDSError.invalidValue()
}
switch record.recordType {
case .incomingGroupsV2MessageJob:
let uniqueId: String = record.uniqueId
let createdAtInterval: Double = record.createdAt
let createdAt: Date = SDSDeserialization.requiredDoubleAsDate(createdAtInterval, name: "createdAt")
let envelopeData: Data = record.envelopeData
let groupId: Data? = SDSDeserialization.optionalData(record.groupId, name: "groupId")
let plaintextData: Data? = SDSDeserialization.optionalData(record.plaintextData, name: "plaintextData")
let serverDeliveryTimestamp: UInt64 = record.serverDeliveryTimestamp
let wasReceivedByUD: Bool = record.wasReceivedByUD
return IncomingGroupsV2MessageJob(grdbId: recordId,
uniqueId: uniqueId,
createdAt: createdAt,
envelopeData: envelopeData,
groupId: groupId,
plaintextData: plaintextData,
serverDeliveryTimestamp: serverDeliveryTimestamp,
wasReceivedByUD: wasReceivedByUD)
default:
owsFailDebug("Unexpected record type: \(record.recordType)")
throw SDSError.invalidValue()
}
}
}
// MARK: - SDSModel
extension IncomingGroupsV2MessageJob: SDSModel {
public var serializer: SDSSerializer {
// Any subclass can be cast to it's superclass,
// so the order of this switch statement matters.
// We need to do a "depth first" search by type.
switch self {
default:
return IncomingGroupsV2MessageJobSerializer(model: self)
}
}
public func asRecord() -> SDSRecord {
serializer.asRecord()
}
public var sdsTableName: String {
IncomingGroupsV2MessageJobRecord.databaseTableName
}
public static var table: SDSTableMetadata {
IncomingGroupsV2MessageJobSerializer.table
}
}
// MARK: - DeepCopyable
extension IncomingGroupsV2MessageJob: DeepCopyable {
public func deepCopy() throws -> AnyObject {
guard let id = self.grdbId?.int64Value else {
throw OWSAssertionError("Model missing grdbId.")
}
// Any subclass can be cast to its superclass, so the order of these if
// statements matters. We need to do a "depth first" search by type.
do {
let modelToCopy = self
assert(type(of: modelToCopy) == IncomingGroupsV2MessageJob.self)
let uniqueId: String = modelToCopy.uniqueId
let createdAt: Date = modelToCopy.createdAt
let envelopeData: Data = modelToCopy.envelopeData
let groupId: Data? = modelToCopy.groupId
let plaintextData: Data? = modelToCopy.plaintextData
let serverDeliveryTimestamp: UInt64 = modelToCopy.serverDeliveryTimestamp
let wasReceivedByUD: Bool = modelToCopy.wasReceivedByUD
return IncomingGroupsV2MessageJob(grdbId: id,
uniqueId: uniqueId,
createdAt: createdAt,
envelopeData: envelopeData,
groupId: groupId,
plaintextData: plaintextData,
serverDeliveryTimestamp: serverDeliveryTimestamp,
wasReceivedByUD: wasReceivedByUD)
}
}
}
// MARK: - Table Metadata
extension IncomingGroupsV2MessageJobSerializer {
// This defines all of the columns used in the table
// where this model (and any subclasses) are persisted.
static var idColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "id", columnType: .primaryKey) }
static var recordTypeColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "recordType", columnType: .int64) }
static var uniqueIdColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "uniqueId", columnType: .unicodeString, isUnique: true) }
// Properties
static var createdAtColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "createdAt", columnType: .double) }
static var envelopeDataColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "envelopeData", columnType: .blob) }
static var plaintextDataColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "plaintextData", columnType: .blob, isOptional: true) }
static var wasReceivedByUDColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "wasReceivedByUD", columnType: .int) }
static var groupIdColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "groupId", columnType: .blob, isOptional: true) }
static var serverDeliveryTimestampColumn: SDSColumnMetadata { SDSColumnMetadata(columnName: "serverDeliveryTimestamp", columnType: .int64) }
public static var table: SDSTableMetadata {
SDSTableMetadata(
tableName: "model_IncomingGroupsV2MessageJob",
columns: [
idColumn,
recordTypeColumn,
uniqueIdColumn,
createdAtColumn,
envelopeDataColumn,
plaintextDataColumn,
wasReceivedByUDColumn,
groupIdColumn,
serverDeliveryTimestampColumn,
]
)
}
}
// MARK: - Save/Remove/Update
@objc
public extension IncomingGroupsV2MessageJob {
func anyInsert(transaction: SDSAnyWriteTransaction) {
sdsSave(saveMode: .insert, transaction: transaction)
}
// Avoid this method whenever feasible.
//
// If the record has previously been saved, this method does an overwriting
// update of the corresponding row, otherwise if it's a new record, this
// method inserts a new row.
//
// For performance, when possible, you should explicitly specify whether
// you are inserting or updating rather than calling this method.
func anyUpsert(transaction: SDSAnyWriteTransaction) {
let isInserting: Bool
if IncomingGroupsV2MessageJob.anyFetch(uniqueId: uniqueId, transaction: transaction) != nil {
isInserting = false
} else {
isInserting = true
}
sdsSave(saveMode: isInserting ? .insert : .update, transaction: transaction)
}
// This method is used by "updateWith..." methods.
//
// This model may be updated from many threads. We don't want to save
// our local copy (this instance) since it may be out of date. We also
// want to avoid re-saving a model that has been deleted. Therefore, we
// use "updateWith..." methods to:
//
// a) Update a property of this instance.
// b) If a copy of this model exists in the database, load an up-to-date copy,
// and update and save that copy.
// b) If a copy of this model _DOES NOT_ exist in the database, do _NOT_ save
// this local instance.
//
// After "updateWith...":
//
// a) Any copy of this model in the database will have been updated.
// b) The local property on this instance will always have been updated.
// c) Other properties on this instance may be out of date.
//
// All mutable properties of this class have been made read-only to
// prevent accidentally modifying them directly.
//
// This isn't a perfect arrangement, but in practice this will prevent
// data loss and will resolve all known issues.
func anyUpdate(transaction: SDSAnyWriteTransaction, block: (IncomingGroupsV2MessageJob) -> Void) {
block(self)
guard let dbCopy = type(of: self).anyFetch(uniqueId: uniqueId,
transaction: transaction) else {
return
}
// Don't apply the block twice to the same instance.
// It's at least unnecessary and actually wrong for some blocks.
// e.g. `block: { $0 in $0.someField++ }`
if dbCopy !== self {
block(dbCopy)
}
dbCopy.sdsSave(saveMode: .update, transaction: transaction)
}
// This method is an alternative to `anyUpdate(transaction:block:)` methods.
//
// We should generally use `anyUpdate` to ensure we're not unintentionally
// clobbering other columns in the database when another concurrent update
// has occurred.
//
// There are cases when this doesn't make sense, e.g. when we know we've
// just loaded the model in the same transaction. In those cases it is
// safe and faster to do a "overwriting" update
func anyOverwritingUpdate(transaction: SDSAnyWriteTransaction) {
sdsSave(saveMode: .update, transaction: transaction)
}
func anyRemove(transaction: SDSAnyWriteTransaction) {
sdsRemove(transaction: transaction)
}
}
// MARK: - IncomingGroupsV2MessageJobCursor
@objc
public class IncomingGroupsV2MessageJobCursor: NSObject, SDSCursor {
private let transaction: GRDBReadTransaction
private let cursor: RecordCursor<IncomingGroupsV2MessageJobRecord>?
init(transaction: GRDBReadTransaction, cursor: RecordCursor<IncomingGroupsV2MessageJobRecord>?) {
self.transaction = transaction
self.cursor = cursor
}
public func next() throws -> IncomingGroupsV2MessageJob? {
guard let cursor = cursor else {
return nil
}
guard let record = try cursor.next() else {
return nil
}
return try IncomingGroupsV2MessageJob.fromRecord(record)
}
public func all() throws -> [IncomingGroupsV2MessageJob] {
var result = [IncomingGroupsV2MessageJob]()
while true {
guard let model = try next() else {
break
}
result.append(model)
}
return result
}
}
// MARK: - Obj-C Fetch
@objc
public extension IncomingGroupsV2MessageJob {
class func grdbFetchCursor(transaction: GRDBReadTransaction) -> IncomingGroupsV2MessageJobCursor {
let database = transaction.database
do {
let cursor = try IncomingGroupsV2MessageJobRecord.fetchCursor(database)
return IncomingGroupsV2MessageJobCursor(transaction: transaction, cursor: cursor)
} catch {
DatabaseCorruptionState.flagDatabaseReadCorruptionIfNecessary(
userDefaults: CurrentAppContext().appUserDefaults(),
error: error
)
owsFailDebug("Read failed: \(error)")
return IncomingGroupsV2MessageJobCursor(transaction: transaction, cursor: nil)
}
}
// Fetches a single model by "unique id".
class func anyFetch(uniqueId: String,
transaction: SDSAnyReadTransaction) -> IncomingGroupsV2MessageJob? {
assert(!uniqueId.isEmpty)
switch transaction.readTransaction {
case .grdbRead(let grdbTransaction):
let sql = "SELECT * FROM \(IncomingGroupsV2MessageJobRecord.databaseTableName) WHERE \(incomingGroupsV2MessageJobColumn: .uniqueId) = ?"
return grdbFetchOne(sql: sql, arguments: [uniqueId], transaction: grdbTransaction)
}
}
// Traverses all records.
// Records are not visited in any particular order.
class func anyEnumerate(
transaction: SDSAnyReadTransaction,
block: (IncomingGroupsV2MessageJob, UnsafeMutablePointer<ObjCBool>) -> Void
) {
anyEnumerate(transaction: transaction, batched: false, block: block)
}
// Traverses all records.
// Records are not visited in any particular order.
class func anyEnumerate(
transaction: SDSAnyReadTransaction,
batched: Bool = false,
block: (IncomingGroupsV2MessageJob, UnsafeMutablePointer<ObjCBool>) -> Void
) {
let batchSize = batched ? Batching.kDefaultBatchSize : 0
anyEnumerate(transaction: transaction, batchSize: batchSize, block: block)
}
// Traverses all records.
// Records are not visited in any particular order.
//
// If batchSize > 0, the enumeration is performed in autoreleased batches.
class func anyEnumerate(
transaction: SDSAnyReadTransaction,
batchSize: UInt,
block: (IncomingGroupsV2MessageJob, UnsafeMutablePointer<ObjCBool>) -> Void
) {
switch transaction.readTransaction {
case .grdbRead(let grdbTransaction):
let cursor = IncomingGroupsV2MessageJob.grdbFetchCursor(transaction: grdbTransaction)
Batching.loop(batchSize: batchSize,
loopBlock: { stop in
do {
guard let value = try cursor.next() else {
stop.pointee = true
return
}
block(value, stop)
} catch let error {
owsFailDebug("Couldn't fetch model: \(error)")
}
})
}
}
// Traverses all records' unique ids.
// Records are not visited in any particular order.
class func anyEnumerateUniqueIds(
transaction: SDSAnyReadTransaction,
block: (String, UnsafeMutablePointer<ObjCBool>) -> Void
) {
anyEnumerateUniqueIds(transaction: transaction, batched: false, block: block)
}
// Traverses all records' unique ids.
// Records are not visited in any particular order.
class func anyEnumerateUniqueIds(
transaction: SDSAnyReadTransaction,
batched: Bool = false,
block: (String, UnsafeMutablePointer<ObjCBool>) -> Void
) {
let batchSize = batched ? Batching.kDefaultBatchSize : 0
anyEnumerateUniqueIds(transaction: transaction, batchSize: batchSize, block: block)
}
// Traverses all records' unique ids.
// Records are not visited in any particular order.
//
// If batchSize > 0, the enumeration is performed in autoreleased batches.
class func anyEnumerateUniqueIds(
transaction: SDSAnyReadTransaction,
batchSize: UInt,
block: (String, UnsafeMutablePointer<ObjCBool>) -> Void
) {
switch transaction.readTransaction {
case .grdbRead(let grdbTransaction):
grdbEnumerateUniqueIds(transaction: grdbTransaction,
sql: """
SELECT \(incomingGroupsV2MessageJobColumn: .uniqueId)
FROM \(IncomingGroupsV2MessageJobRecord.databaseTableName)
""",
batchSize: batchSize,
block: block)
}
}
// Does not order the results.
class func anyFetchAll(transaction: SDSAnyReadTransaction) -> [IncomingGroupsV2MessageJob] {
var result = [IncomingGroupsV2MessageJob]()
anyEnumerate(transaction: transaction) { (model, _) in
result.append(model)
}
return result
}
// Does not order the results.
class func anyAllUniqueIds(transaction: SDSAnyReadTransaction) -> [String] {
var result = [String]()
anyEnumerateUniqueIds(transaction: transaction) { (uniqueId, _) in
result.append(uniqueId)
}
return result
}
class func anyCount(transaction: SDSAnyReadTransaction) -> UInt {
switch transaction.readTransaction {
case .grdbRead(let grdbTransaction):
return IncomingGroupsV2MessageJobRecord.ows_fetchCount(grdbTransaction.database)
}
}
class func anyRemoveAllWithInstantiation(transaction: SDSAnyWriteTransaction) {
// To avoid mutationDuringEnumerationException, we need to remove the
// instances outside the enumeration.
let uniqueIds = anyAllUniqueIds(transaction: transaction)
for uniqueId in uniqueIds {
autoreleasepool {
guard let instance = anyFetch(uniqueId: uniqueId, transaction: transaction) else {
owsFailDebug("Missing instance.")
return
}
instance.anyRemove(transaction: transaction)
}
}
}
class func anyExists(
uniqueId: String,
transaction: SDSAnyReadTransaction
) -> Bool {
assert(!uniqueId.isEmpty)
switch transaction.readTransaction {
case .grdbRead(let grdbTransaction):
let sql = "SELECT EXISTS ( SELECT 1 FROM \(IncomingGroupsV2MessageJobRecord.databaseTableName) WHERE \(incomingGroupsV2MessageJobColumn: .uniqueId) = ? )"
let arguments: StatementArguments = [uniqueId]
do {
return try Bool.fetchOne(grdbTransaction.database, sql: sql, arguments: arguments) ?? false
} catch {
DatabaseCorruptionState.flagDatabaseReadCorruptionIfNecessary(
userDefaults: CurrentAppContext().appUserDefaults(),
error: error
)
owsFail("Missing instance.")
}
}
}
}
// MARK: - Swift Fetch
public extension IncomingGroupsV2MessageJob {
class func grdbFetchCursor(sql: String,
arguments: StatementArguments = StatementArguments(),
transaction: GRDBReadTransaction) -> IncomingGroupsV2MessageJobCursor {
do {
let sqlRequest = SQLRequest<Void>(sql: sql, arguments: arguments, cached: true)
let cursor = try IncomingGroupsV2MessageJobRecord.fetchCursor(transaction.database, sqlRequest)
return IncomingGroupsV2MessageJobCursor(transaction: transaction, cursor: cursor)
} catch {
DatabaseCorruptionState.flagDatabaseReadCorruptionIfNecessary(
userDefaults: CurrentAppContext().appUserDefaults(),
error: error
)
owsFailDebug("Read failed: \(error)")
return IncomingGroupsV2MessageJobCursor(transaction: transaction, cursor: nil)
}
}
class func grdbFetchOne(sql: String,
arguments: StatementArguments = StatementArguments(),
transaction: GRDBReadTransaction) -> IncomingGroupsV2MessageJob? {
assert(!sql.isEmpty)
do {
let sqlRequest = SQLRequest<Void>(sql: sql, arguments: arguments, cached: true)
guard let record = try IncomingGroupsV2MessageJobRecord.fetchOne(transaction.database, sqlRequest) else {
return nil
}
return try IncomingGroupsV2MessageJob.fromRecord(record)
} catch {
owsFailDebug("error: \(error)")
return nil
}
}
}
// MARK: - SDSSerializer
// The SDSSerializer protocol specifies how to insert and update the
// row that corresponds to this model.
class IncomingGroupsV2MessageJobSerializer: SDSSerializer {
private let model: IncomingGroupsV2MessageJob
public init(model: IncomingGroupsV2MessageJob) {
self.model = model
}
// MARK: - Record
func asRecord() -> SDSRecord {
let id: Int64? = model.grdbId?.int64Value
let recordType: SDSRecordType = .incomingGroupsV2MessageJob
let uniqueId: String = model.uniqueId
// Properties
let createdAt: Double = archiveDate(model.createdAt)
let envelopeData: Data = model.envelopeData
let plaintextData: Data? = model.plaintextData
let wasReceivedByUD: Bool = model.wasReceivedByUD
let groupId: Data? = model.groupId
let serverDeliveryTimestamp: UInt64 = model.serverDeliveryTimestamp
return IncomingGroupsV2MessageJobRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, createdAt: createdAt, envelopeData: envelopeData, plaintextData: plaintextData, wasReceivedByUD: wasReceivedByUD, groupId: groupId, serverDeliveryTimestamp: serverDeliveryTimestamp)
}
}