package imap import ( "context" "github.com/jackc/pgx/v5/pgxpool" ) type folderSyncState struct { FolderID string UIDValidity uint32 HighestModSeq uint64 LastUID uint32 } func loadFolderSyncState(ctx context.Context, db *pgxpool.Pool, accountID, remoteName string) (folderSyncState, bool, error) { var state folderSyncState err := db.QueryRow(ctx, ` SELECT id, uidvalidity, highest_modseq, last_uid FROM mail_folders WHERE account_id = $1 AND remote_name = $2 `, accountID, remoteName).Scan(&state.FolderID, &state.UIDValidity, &state.HighestModSeq, &state.LastUID) if err != nil { return folderSyncState{}, false, err } return state, true, nil } func saveFolderSyncState(ctx context.Context, db *pgxpool.Pool, folderID string, uidValidity uint32, highestModSeq uint64, lastUID uint32, messageCount int) error { _, err := db.Exec(ctx, ` UPDATE mail_folders SET uidvalidity = $2, highest_modseq = $3, last_uid = $4, message_count = $5, updated_at = NOW() WHERE id = $1 `, folderID, uidValidity, highestModSeq, lastUID, messageCount) return err } func resetFolderMessages(ctx context.Context, db *pgxpool.Pool, folderID string) error { _, err := db.Exec(ctx, `DELETE FROM messages WHERE folder_id = $1`, folderID) return err } // resetAccountSyncCursors zeroes last_uid and highest_modseq for all folders // of an account so the next sync re-fetches every message from the IMAP server. // Existing messages are kept; ON CONFLICT DO UPDATE overwrites body_html. func resetAccountSyncCursors(ctx context.Context, db *pgxpool.Pool, accountID string) error { _, err := db.Exec(ctx, ` UPDATE mail_folders SET last_uid = 0, highest_modseq = 0, updated_at = NOW() WHERE account_id = $1 `, accountID) return err }