Files
galaxy-game/mail/internal/adapters/postgres/mailstore/malformed_command.go
T
2026-04-26 20:34:39 +02:00

149 lines
4.7 KiB
Go

package mailstore
import (
"context"
"errors"
"fmt"
"time"
pgtable "galaxy/mail/internal/adapters/postgres/jet/mail/table"
"galaxy/mail/internal/domain/malformedcommand"
pg "github.com/go-jet/jet/v2/postgres"
)
// Record stores entry idempotently by stream entry id. The helper satisfies
// worker.MalformedCommandRecorder.
func (store *Store) Record(ctx context.Context, entry malformedcommand.Entry) error {
if store == nil {
return errors.New("record malformed command: nil store")
}
if ctx == nil {
return errors.New("record malformed command: nil context")
}
if err := entry.Validate(); err != nil {
return fmt.Errorf("record malformed command: %w", err)
}
rawFields, err := marshalRawFields(entry.RawFields)
if err != nil {
return fmt.Errorf("record malformed command: %w", err)
}
operationCtx, cancel, err := store.operationContext(ctx, "record malformed command")
if err != nil {
return err
}
defer cancel()
stmt := pgtable.MalformedCommands.INSERT(
pgtable.MalformedCommands.StreamEntryID,
pgtable.MalformedCommands.DeliveryID,
pgtable.MalformedCommands.Source,
pgtable.MalformedCommands.IdempotencyKey,
pgtable.MalformedCommands.FailureCode,
pgtable.MalformedCommands.FailureMessage,
pgtable.MalformedCommands.RawFields,
pgtable.MalformedCommands.RecordedAt,
).VALUES(
entry.StreamEntryID,
entry.DeliveryID,
entry.Source,
entry.IdempotencyKey,
string(entry.FailureCode),
entry.FailureMessage,
rawFields,
entry.RecordedAt.UTC(),
).ON_CONFLICT(pgtable.MalformedCommands.StreamEntryID).DO_NOTHING()
query, args := stmt.Sql()
if _, err := store.db.ExecContext(operationCtx, query, args...); err != nil {
return fmt.Errorf("record malformed command: %w", err)
}
return nil
}
// GetMalformedCommand loads one malformed-command entry by stream entry id.
func (store *Store) GetMalformedCommand(ctx context.Context, streamEntryID string) (malformedcommand.Entry, bool, error) {
if store == nil {
return malformedcommand.Entry{}, false, errors.New("get malformed command: nil store")
}
if ctx == nil {
return malformedcommand.Entry{}, false, errors.New("get malformed command: nil context")
}
operationCtx, cancel, err := store.operationContext(ctx, "get malformed command")
if err != nil {
return malformedcommand.Entry{}, false, err
}
defer cancel()
stmt := pg.SELECT(
pgtable.MalformedCommands.DeliveryID,
pgtable.MalformedCommands.Source,
pgtable.MalformedCommands.IdempotencyKey,
pgtable.MalformedCommands.FailureCode,
pgtable.MalformedCommands.FailureMessage,
pgtable.MalformedCommands.RawFields,
pgtable.MalformedCommands.RecordedAt,
).FROM(pgtable.MalformedCommands).
WHERE(pgtable.MalformedCommands.StreamEntryID.EQ(pg.String(streamEntryID)))
query, args := stmt.Sql()
row := store.db.QueryRowContext(operationCtx, query, args...)
var (
deliveryID string
source string
idempotencyKey string
failureCode string
failureMessage string
rawFields []byte
)
entry := malformedcommand.Entry{StreamEntryID: streamEntryID}
if err := row.Scan(&deliveryID, &source, &idempotencyKey, &failureCode, &failureMessage, &rawFields, &entry.RecordedAt); err != nil {
if isNoRows(err) {
return malformedcommand.Entry{}, false, nil
}
return malformedcommand.Entry{}, false, fmt.Errorf("get malformed command: %w", err)
}
entry.DeliveryID = deliveryID
entry.Source = source
entry.IdempotencyKey = idempotencyKey
entry.FailureCode = malformedcommand.FailureCode(failureCode)
entry.FailureMessage = failureMessage
entry.RecordedAt = entry.RecordedAt.UTC()
fields, err := unmarshalRawFields(rawFields)
if err != nil {
return malformedcommand.Entry{}, false, fmt.Errorf("get malformed command: %w", err)
}
entry.RawFields = fields
return entry, true, nil
}
// DeleteMalformedCommandsOlderThan removes malformed-command rows whose
// recorded_at predates cutoff. The helper satisfies the SQLRetentionStore
// contract used by the periodic retention worker.
func (store *Store) DeleteMalformedCommandsOlderThan(ctx context.Context, cutoff time.Time) (int64, error) {
if store == nil {
return 0, errors.New("delete malformed commands: nil store")
}
operationCtx, cancel, err := store.operationContext(ctx, "delete malformed commands")
if err != nil {
return 0, err
}
defer cancel()
stmt := pgtable.MalformedCommands.DELETE().
WHERE(pgtable.MalformedCommands.RecordedAt.LT(pg.TimestampzT(cutoff.UTC())))
query, args := stmt.Sql()
result, err := store.db.ExecContext(operationCtx, query, args...)
if err != nil {
return 0, fmt.Errorf("delete malformed commands: %w", err)
}
rows, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("delete malformed commands: rows affected: %w", err)
}
return rows, nil
}