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 }