package tenant import ( "context" "database/sql" ) func (q *Queries) ListReactions(ctx context.Context, postSlug string) ([]Reaction, error) { rows, err := q.db.QueryContext(ctx, `SELECT id, user_id, anon_id, post_slug, emoji, created_at FROM reactions WHERE post_slug = ?`, postSlug) if err != nil { return nil, err } defer rows.Close() var reactions []Reaction for rows.Next() { r, err := scanReaction(rows) if err != nil { return nil, err } reactions = append(reactions, r) } return reactions, rows.Err() } func (q *Queries) GetReactionCounts(ctx context.Context, postSlug string) (map[string]int, error) { rows, err := q.db.QueryContext(ctx, `SELECT emoji, COUNT(*) as count FROM reactions WHERE post_slug = ? GROUP BY emoji`, postSlug) if err != nil { return nil, err } defer rows.Close() counts := make(map[string]int) for rows.Next() { var emoji string var count int64 if err := rows.Scan(&emoji, &count); err != nil { return nil, err } counts[emoji] = int(count) } return counts, rows.Err() } func (q *Queries) ToggleReaction(ctx context.Context, userID, anonID, postSlug, emoji string) (bool, error) { var exists bool if userID != "" { var dummy int64 err := q.db.QueryRowContext(ctx, `SELECT 1 FROM reactions WHERE user_id = ? AND post_slug = ? AND emoji = ?`, userID, postSlug, emoji).Scan(&dummy) exists = err == nil } else if anonID != "" { var dummy int64 err := q.db.QueryRowContext(ctx, `SELECT 1 FROM reactions WHERE anon_id = ? AND post_slug = ? AND emoji = ?`, anonID, postSlug, emoji).Scan(&dummy) exists = err == nil } else { return false, nil } if !exists { if userID != "" { _, err := q.db.ExecContext(ctx, `INSERT INTO reactions (user_id, post_slug, emoji) VALUES (?, ?, ?)`, userID, postSlug, emoji) return true, err } _, err := q.db.ExecContext(ctx, `INSERT INTO reactions (anon_id, post_slug, emoji) VALUES (?, ?, ?)`, anonID, postSlug, emoji) return true, err } if userID != "" { _, err := q.db.ExecContext(ctx, `DELETE FROM reactions WHERE user_id = ? AND post_slug = ? AND emoji = ?`, userID, postSlug, emoji) return false, err } _, err := q.db.ExecContext(ctx, `DELETE FROM reactions WHERE anon_id = ? AND post_slug = ? AND emoji = ?`, anonID, postSlug, emoji) return false, err } func (q *Queries) GetUserReactions(ctx context.Context, userID, postSlug string) ([]string, error) { rows, err := q.db.QueryContext(ctx, `SELECT emoji FROM reactions WHERE user_id = ? AND post_slug = ?`, userID, postSlug) if err != nil { return nil, err } defer rows.Close() var emojis []string for rows.Next() { var emoji string if err := rows.Scan(&emoji); err != nil { return nil, err } emojis = append(emojis, emoji) } return emojis, rows.Err() } func (q *Queries) GetAnonReactions(ctx context.Context, anonID, postSlug string) ([]string, error) { rows, err := q.db.QueryContext(ctx, `SELECT emoji FROM reactions WHERE anon_id = ? AND post_slug = ?`, anonID, postSlug) if err != nil { return nil, err } defer rows.Close() var emojis []string for rows.Next() { var emoji string if err := rows.Scan(&emoji); err != nil { return nil, err } emojis = append(emojis, emoji) } return emojis, rows.Err() } func (q *Queries) HasUserReacted(ctx context.Context, userID, postSlug string) (bool, error) { var dummy int64 err := q.db.QueryRowContext(ctx, `SELECT 1 FROM reactions WHERE user_id = ? AND post_slug = ? LIMIT 1`, userID, postSlug).Scan(&dummy) if err == sql.ErrNoRows { return false, nil } if err != nil { return false, nil } return true, nil } func (q *Queries) HasAnonReacted(ctx context.Context, anonID, postSlug string) (bool, error) { var dummy int64 err := q.db.QueryRowContext(ctx, `SELECT 1 FROM reactions WHERE anon_id = ? AND post_slug = ? LIMIT 1`, anonID, postSlug).Scan(&dummy) if err == sql.ErrNoRows { return false, nil } if err != nil { return false, nil } return true, nil } func scanReaction(s scanner) (Reaction, error) { var r Reaction var userID, anonID, createdAt sql.NullString err := s.Scan(&r.ID, &userID, &anonID, &r.PostSlug, &r.Emoji, &createdAt) if err != nil { return r, err } r.UserID = userID.String r.AnonID = anonID.String r.CreatedAt = parseTime(createdAt.String) return r, nil }