migrate persistence from JSON to SwiftData
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.
This commit is contained in:
1 parent
0317277d46
commit
cbb820a86e
30 files changed
+726
-665
No files matched your search
@@ -24,7 +24,7 @@ enum ChatMediaImageCache {
|
||||
for message: ChatMessage,
|
||||
data: Data
|
||||
) -> ChatMediaPlatformImage? {
|
||||
let cacheKey = "\(message.conversationID)\u{1F}\(message.id)" as NSString
|
||||
let cacheKey = "\(message.conversationID)\u{1F}\(message.clientID)" as NSString
|
||||
if let cached = cache.object(forKey: cacheKey) {
|
||||
return cached
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ final class PhoneWatchBridge: NSObject, WCSessionDelegate {
|
||||
messages: [ChatMessage]
|
||||
) -> Data? {
|
||||
let visibleConversations = Array(conversations.prefix(20))
|
||||
let visibleConversationIDs = Set(visibleConversations.map(\.id))
|
||||
let visibleConversationIDs = Set(visibleConversations.map(\.jid))
|
||||
var recentMessagesByConversation: [String: [ChatMessage]] = [:]
|
||||
|
||||
// Keep a bounded, chronologically sorted window. MAM can append an old
|
||||
@@ -103,10 +103,10 @@ final class PhoneWatchBridge: NSObject, WCSessionDelegate {
|
||||
jid: conversation.jid,
|
||||
name: conversation.displayName,
|
||||
unread: conversation.unreadCount,
|
||||
messages: (recentMessagesByConversation[conversation.id] ?? [])
|
||||
messages: (recentMessagesByConversation[conversation.jid] ?? [])
|
||||
.map {
|
||||
PhoneWatchSnapshot.Message(
|
||||
id: $0.id,
|
||||
id: $0.clientID,
|
||||
body: $0.previewText,
|
||||
timestamp: $0.timestamp,
|
||||
outgoing: $0.direction == .outgoing,
|
||||
@@ -128,7 +128,7 @@ final class PhoneWatchBridge: NSObject, WCSessionDelegate {
|
||||
let middle = lowerBound + (upperBound - lowerBound) / 2
|
||||
let existing = sortedMessages[middle]
|
||||
let existingComesFirst = existing.timestamp < message.timestamp
|
||||
|| (existing.timestamp == message.timestamp && existing.id < message.id)
|
||||
|| (existing.timestamp == message.timestamp && existing.clientID < message.clientID)
|
||||
if existingComesFirst {
|
||||
lowerBound = middle + 1
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user