Flags, expunge, move, copy and folder deletion each existed twice: once for IMAP (FlagRepository, ExpungeRepository, CopyRepository) and once for the webmail (WebmailRepository). They kept the cached numbers true on their own and drifted: - reading a message over IMAP never moved the folder's unread counter - deleting in the webmail, or deleting a folder, never gave the quota back - an IMAP expunge could push a counter below zero MailStore now holds each state change once, in one transaction, with the same rules everywhere: counters never go negative, a change that alters what a client can observe raises the folder's modseq (one that alters nothing does not), the quota follows the bytes, and a message is located by folder. The four repositories are thin adapters that only translate how each path names a message. The contract test added before this change (which failed on 8 of its cases) now passes, as does the full suite.
25 lines
713 B
Go
25 lines
713 B
Go
package postgres
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"lambdamail/protocols/internal/application/port"
|
|
)
|
|
|
|
// FlagRepository implements port.FlagRepository (IMAP STORE). The work is done
|
|
// by MailStore, which every path shares; this only names the message the way
|
|
// IMAP does, by folder and UID.
|
|
type FlagRepository struct {
|
|
store *MailStore
|
|
}
|
|
|
|
func NewFlagRepository(pool *pgxpool.Pool) *FlagRepository {
|
|
return &FlagRepository{store: NewMailStore(pool)}
|
|
}
|
|
|
|
func (r *FlagRepository) SetFlags(ctx context.Context, folderID string, uid uint32, op port.FlagOp, flags []string, unchangedSince uint64) (bool, error) {
|
|
return r.store.SetFlags(ctx, folderID, uid, op, flags, unchangedSince)
|
|
}
|