Models: - Convert Conversation and ChatMessage to SwiftData @Model classes with a one-to-many relationship and cascade delete. - Rename ChatMessage.id to clientID and drop Conversation.id in favor of jid (the string id would clash with PersistentIdentifier). - Keep MessageReaction as a Codable value stored in an array attribute. Persistence: - Add ArchiveStore, a per-account ModelContainer/ModelContext that replaces the JSON ChatArchive with load/save/erase. - Add ArchiveMetadataRecord for the durable MAM checkpoints, cursor, locally deleted message IDs and roster contact JIDs. - Add LegacyArchiveImporter to import the old JSON snapshot once and delete the file afterwards, preserving existing history. AppModel: - Replace ChatArchive with ArchiveStore and persist via context.save(); insert new models and delete the replaced object on upsert merges so SwiftData never keeps an orphaned duplicate. Tests: - Replace ChatArchiveTests with ArchiveStoreTests (store round-trip and legacy import) and drop the now-obsolete Codable round-trip assertions.
38 lines
1.3 KiB
Swift
38 lines
1.3 KiB
Swift
import Foundation
|
|
import SwiftData
|
|
|
|
/// Codable representation of a single durable MAM checkpoint, keyed by the
|
|
/// archive it belongs to (account or a specific MUC).
|
|
struct MAMCheckpointEntry: Codable, Equatable, Sendable {
|
|
let key: MAMArchiveKey
|
|
let checkpoint: MAMArchiveCheckpoint
|
|
}
|
|
|
|
/// Singleton per-account metadata that used to live in the JSON snapshot:
|
|
/// locally deleted message IDs, roster contact JIDs and MAM checkpoints.
|
|
@Model
|
|
final class ArchiveMetadata {
|
|
@Attribute(.unique) var accountJID: String
|
|
var locallyDeletedMessageIDs: [String]
|
|
var rosterContactJIDs: [String]
|
|
var lastSuccessfulMAMSync: Date?
|
|
var lastSuccessfulMAMCursor: String?
|
|
var mamCheckpoints: [MAMCheckpointEntry]
|
|
|
|
init(
|
|
accountJID: String,
|
|
locallyDeletedMessageIDs: [String] = [],
|
|
rosterContactJIDs: [String] = [],
|
|
lastSuccessfulMAMSync: Date? = nil,
|
|
lastSuccessfulMAMCursor: String? = nil,
|
|
mamCheckpoints: [MAMCheckpointEntry] = []
|
|
) {
|
|
self.accountJID = accountJID
|
|
self.locallyDeletedMessageIDs = locallyDeletedMessageIDs
|
|
self.rosterContactJIDs = rosterContactJIDs
|
|
self.lastSuccessfulMAMSync = lastSuccessfulMAMSync
|
|
self.lastSuccessfulMAMCursor = lastSuccessfulMAMCursor
|
|
self.mamCheckpoints = mamCheckpoints
|
|
}
|
|
}
|