fix FK constraint: skip duplicate messages before thread reconstruction
- insertMessages checks (mailboxId, uid) existence before INSERT, returns only actually inserted records - syncMailbox only runs ThreadReconstructor on newly inserted messages, preventing FK violations from stale UUIDs referencing ignored records - improve error logging to show full error description Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -207,10 +207,10 @@ final class MailViewModel {
|
||||
try await coordinator.syncNow()
|
||||
syncState = coordinator.syncState
|
||||
} catch {
|
||||
let desc = "\(type(of: error)): \(error.localizedDescription)"
|
||||
let desc = "\(error)"
|
||||
print("[MailViewModel] syncNow failed: \(desc)")
|
||||
errorMessage = desc
|
||||
syncState = .error(desc)
|
||||
errorMessage = error.localizedDescription
|
||||
syncState = .error(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,12 +55,23 @@ public final class MailStore: Sendable {
|
||||
|
||||
// MARK: - Messages
|
||||
|
||||
public func insertMessages(_ messages: [MessageRecord]) throws {
|
||||
/// Insert messages, skipping duplicates by (mailboxId, uid). Returns only the records that were actually inserted.
|
||||
@discardableResult
|
||||
public func insertMessages(_ messages: [MessageRecord]) throws -> [MessageRecord] {
|
||||
try dbWriter.write { db in
|
||||
var inserted: [MessageRecord] = []
|
||||
for message in messages {
|
||||
// INSERT OR IGNORE: skip if (mailboxId, uid) already exists from a prior sync
|
||||
try message.insert(db, onConflict: .ignore)
|
||||
// Check if a message with this (mailboxId, uid) already exists
|
||||
let exists = try MessageRecord.fetchOne(db, sql:
|
||||
"SELECT id FROM message WHERE mailboxId = ? AND uid = ?",
|
||||
arguments: [message.mailboxId, message.uid]
|
||||
)
|
||||
if exists == nil {
|
||||
try message.insert(db)
|
||||
inserted.append(message)
|
||||
}
|
||||
}
|
||||
return inserted
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,12 +163,13 @@ public final class SyncCoordinator {
|
||||
let records = envelopes.map { envelope -> MessageRecord in
|
||||
envelopeToRecord(envelope, accountId: accountConfig.id, mailboxId: mailboxId)
|
||||
}
|
||||
try store.insertMessages(records)
|
||||
let inserted = try store.insertMessages(records)
|
||||
|
||||
let reconstructor = ThreadReconstructor(store: store)
|
||||
try reconstructor.processMessages(records)
|
||||
|
||||
emit(.newMessages(count: envelopes.count, mailbox: remoteMailbox.name))
|
||||
if !inserted.isEmpty {
|
||||
let reconstructor = ThreadReconstructor(store: store)
|
||||
try reconstructor.processMessages(inserted)
|
||||
emit(.newMessages(count: inserted.count, mailbox: remoteMailbox.name))
|
||||
}
|
||||
}
|
||||
|
||||
// Reconcile flags for recent existing messages (read/unread state from other devices)
|
||||
|
||||
Reference in New Issue
Block a user