package store import ( "context" "database/sql" "fmt" "strings" "time" "github.com/google/uuid" "plumber/internal/pacific" "plumber/internal/store/sqlc" ) // RankedQuestion is a question row with score / vote annotations for lists. type RankedQuestion struct { ID string AuthorID string AuthorName string Title string Body string City string HuntDate string Hidden bool CreatedAt string Score int Answered bool UserVote int db *sql.DB } // NewQuestion returns a question bound to db (not yet inserted). func NewQuestion(db *sql.DB) *RankedQuestion { return &RankedQuestion{db: db} } // Create inserts the question. Sets ID, HuntDate, and CreatedAt when empty. func (q *RankedQuestion) Create(ctx context.Context) error { if q == nil || q.db == nil { return fmt.Errorf("question: no database") } q.Title = strings.TrimSpace(q.Title) q.Body = strings.TrimSpace(q.Body) q.City = strings.TrimSpace(q.City) if q.ID == "" { q.ID = uuid.NewString() } if q.HuntDate == "" { q.HuntDate = pacific.Today() } if q.CreatedAt == "" { q.CreatedAt = time.Now().UTC().Format(time.RFC3339) } return sqlc.New(q.db).CreateQuestion(ctx, sqlc.CreateQuestionParams{ ID: q.ID, AuthorID: q.AuthorID, Title: q.Title, Body: q.Body, City: q.City, HuntDate: q.HuntDate, CreatedAt: q.CreatedAt, }) } // Hide marks the question hidden. func (q *RankedQuestion) Hide(ctx context.Context) error { if q == nil || q.db == nil { return fmt.Errorf("question: no database") } if err := sqlc.New(q.db).HideQuestion(ctx, q.ID); err != nil { return err } q.Hidden = true return nil } func rankedFrom( db *sql.DB, id, authorID, authorName, title, body, city, huntDate, createdAt string, hidden int32, score, answered, userVote int64, ) RankedQuestion { return RankedQuestion{ ID: id, AuthorID: authorID, AuthorName: authorName, Title: title, Body: body, City: city, HuntDate: huntDate, Hidden: hidden != 0, CreatedAt: createdAt, Score: int(score), Answered: answered != 0, UserVote: int(userVote), db: db, } } func ListHunt(ctx context.Context, db *sql.DB, huntDate, viewerID string) ([]RankedQuestion, error) { rows, err := sqlc.New(db).ListHunt(ctx, sqlc.ListHuntParams{ UserID: viewerID, HuntDate: huntDate, }) if err != nil { return nil, err } out := make([]RankedQuestion, 0, len(rows)) for _, r := range rows { out = append(out, rankedFrom(db, r.ID, r.AuthorID, r.AuthorName, r.Title, r.Body, r.City, r.HuntDate, r.CreatedAt, r.Hidden, r.Score, r.Answered, r.UserVote)) } return out, nil } func GetQuestion(ctx context.Context, db *sql.DB, id, viewerID string) (*RankedQuestion, error) { r, err := sqlc.New(db).GetQuestion(ctx, sqlc.GetQuestionParams{ UserID: viewerID, ID: id, }) if err != nil { return nil, err } q := rankedFrom(db, r.ID, r.AuthorID, r.AuthorName, r.Title, r.Body, r.City, r.HuntDate, r.CreatedAt, r.Hidden, r.Score, r.Answered, r.UserVote) return &q, nil } func ListQuestionsByAuthor(ctx context.Context, db *sql.DB, authorID string) ([]RankedQuestion, error) { rows, err := sqlc.New(db).ListQuestionsByAuthor(ctx, authorID) if err != nil { return nil, err } out := make([]RankedQuestion, 0, len(rows)) for _, r := range rows { out = append(out, rankedFrom(db, r.ID, r.AuthorID, r.AuthorName, r.Title, r.Body, r.City, r.HuntDate, r.CreatedAt, r.Hidden, r.Score, r.Answered, r.UserVote)) } return out, nil } func ListQuestionsAnsweredBy(ctx context.Context, db *sql.DB, adminID string) ([]RankedQuestion, error) { rows, err := sqlc.New(db).ListQuestionsAnsweredBy(ctx, adminID) if err != nil { return nil, err } out := make([]RankedQuestion, 0, len(rows)) for _, r := range rows { out = append(out, rankedFrom(db, r.ID, r.AuthorID, r.AuthorName, r.Title, r.Body, r.City, r.HuntDate, r.CreatedAt, r.Hidden, r.Score, r.Answered, r.UserVote)) } return out, nil }