package mail import ( "context" "errors" "time" "github.com/jackc/pgx/v5" ) var ErrInvalidOutboxStatus = errors.New("invalid outbox status") func (s *Service) SendOutboxNow(ctx context.Context, userID, outboxID string) (string, error) { var status string err := s.db.QueryRow(ctx, ` UPDATE outbox SET status = 'queued', scheduled_at = NULL, updated_at = NOW() WHERE id = $1 AND user_id = $2 AND status = 'scheduled' RETURNING status `, outboxID, userID).Scan(&status) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return "", s.outboxActionError(ctx, userID, outboxID) } return "", err } return status, nil } func (s *Service) RescheduleOutbox(ctx context.Context, userID, outboxID string, scheduledAt time.Time) (string, error) { var status string err := s.db.QueryRow(ctx, ` UPDATE outbox SET status = 'scheduled', scheduled_at = $3, updated_at = NOW() WHERE id = $1 AND user_id = $2 AND status IN ('scheduled', 'queued') RETURNING status `, outboxID, userID, scheduledAt).Scan(&status) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return "", s.outboxActionError(ctx, userID, outboxID) } return "", err } return status, nil } func (s *Service) CancelScheduledOutbox(ctx context.Context, userID, outboxID string) (string, error) { var status string err := s.db.QueryRow(ctx, ` UPDATE outbox SET status = 'cancelled', scheduled_at = NULL, updated_at = NOW() WHERE id = $1 AND user_id = $2 AND status = 'scheduled' RETURNING status `, outboxID, userID).Scan(&status) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return "", s.outboxActionError(ctx, userID, outboxID) } return "", err } return status, nil } func (s *Service) outboxActionError(ctx context.Context, userID, outboxID string) error { var status string err := s.db.QueryRow(ctx, ` SELECT status FROM outbox WHERE id = $1 AND user_id = $2 `, outboxID, userID).Scan(&status) if errors.Is(err, pgx.ErrNoRows) { return ErrNotFound } if err != nil { return err } return ErrInvalidOutboxStatus }