| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- package repository
- import (
- "context"
- "fmt"
- "github.com/jackc/pgx/v5/pgxpool"
- "github.com/photoplaces/backend/internal/models"
- )
- type ReviewRepo struct {
- pool *pgxpool.Pool
- }
- func NewReviewRepo(pool *pgxpool.Pool) *ReviewRepo {
- return &ReviewRepo{pool: pool}
- }
- func (r *ReviewRepo) Create(ctx context.Context, review *models.Review) error {
- tx, err := r.pool.Begin(ctx)
- if err != nil {
- return err
- }
- defer tx.Rollback(ctx)
- err = tx.QueryRow(ctx,
- `INSERT INTO reviews (user_id, target_type, target_id, rating, text)
- VALUES ($1, $2, $3, $4, $5)
- RETURNING id, created_at, updated_at`,
- review.UserID, review.TargetType, review.TargetID, review.Rating, review.Text,
- ).Scan(&review.ID, &review.CreatedAt, &review.UpdatedAt)
- if err != nil {
- if isUniqueViolation(err) {
- return fmt.Errorf("you already reviewed this")
- }
- return fmt.Errorf("create review: %w", err)
- }
- tableName := "places"
- if review.TargetType == "service" {
- tableName = "services"
- }
- _, err = tx.Exec(ctx,
- fmt.Sprintf(`UPDATE %s SET
- reviews_count = (SELECT COUNT(*) FROM reviews WHERE target_type = $1 AND target_id = $2 AND deleted_at IS NULL),
- rating = (SELECT COALESCE(AVG(rating), 0) FROM reviews WHERE target_type = $1 AND target_id = $2 AND deleted_at IS NULL)
- WHERE id = $2`, tableName),
- review.TargetType, review.TargetID)
- if err != nil {
- return fmt.Errorf("update rating: %w", err)
- }
- return tx.Commit(ctx)
- }
- func (r *ReviewRepo) List(ctx context.Context, targetType, targetID string) ([]*models.Review, error) {
- rows, err := r.pool.Query(ctx,
- `SELECT r.id, r.user_id, r.target_type, r.target_id, r.rating, r.text,
- r.created_at, r.updated_at,
- u.name, u.avatar_url
- FROM reviews r
- JOIN users u ON u.id = r.user_id
- WHERE r.target_type = $1 AND r.target_id = $2 AND r.deleted_at IS NULL
- ORDER BY r.created_at DESC`, targetType, targetID)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
- var reviews []*models.Review
- for rows.Next() {
- var rev models.Review
- var userName, userAvatar *string
- if err := rows.Scan(
- &rev.ID, &rev.UserID, &rev.TargetType, &rev.TargetID, &rev.Rating, &rev.Text,
- &rev.CreatedAt, &rev.UpdatedAt,
- &userName, &userAvatar,
- ); err != nil {
- return nil, err
- }
- rev.User = &models.User{Name: userName, AvatarURL: userAvatar}
- reviews = append(reviews, &rev)
- }
- return reviews, nil
- }
- func isUniqueViolation(err error) bool {
- return err != nil && contains(err.Error(), "unique")
- }
- func contains(s, substr string) bool {
- return len(s) >= len(substr) && searchString(s, substr)
- }
- func searchString(s, sub string) bool {
- for i := 0; i <= len(s)-len(sub); i++ {
- if s[i:i+len(sub)] == sub {
- return true
- }
- }
- return false
- }
|