package store import ( "context" "database/sql" "errors" "fmt" "github.com/jackc/pgx/v5/pgconn" "plumber/internal/store/sqlc" ) // ErrDuplicateUsername is returned when inserting a username that already exists. var ErrDuplicateUsername = errors.New("username taken") // ErrHiddenOrMissing is returned when voting on a hidden or unknown question. var ErrHiddenOrMissing = errors.New("question not votable") // SetVote sets the user's vote to value (1, -1, or 0 to clear) on a visible question. func SetVote(ctx context.Context, db *sql.DB, userID, questionID string, value int) error { if value != 1 && value != -1 && value != 0 { return fmt.Errorf("invalid vote") } q := sqlc.New(db) if value == 0 { visible, err := q.QuestionIsVisible(ctx, questionID) if err != nil { return err } if !visible { return ErrHiddenOrMissing } return q.DeleteVote(ctx, sqlc.DeleteVoteParams{ UserID: userID, QuestionID: questionID, }) } n, err := q.UpsertVoteOnVisible(ctx, sqlc.UpsertVoteOnVisibleParams{ UserID: userID, QuestionID: questionID, Value: int32(value), }) if err != nil { return mapUniqueViolation(err) } if n == 0 { return ErrHiddenOrMissing } return nil } // Vote is kept as an alias for SetVote for callers that still use the old name. func Vote(ctx context.Context, db *sql.DB, userID, questionID string, value int) error { return SetVote(ctx, db, userID, questionID, value) } func mapUniqueViolation(err error) error { var pgErr *pgconn.PgError if errors.As(err, &pgErr) && pgErr.Code == "23505" { return ErrDuplicateUsername } return err }