| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- // Package repository
- package repository
- import (
- "context"
- "errors"
- "fmt"
- "github.com/jackc/pgx/v5/pgconn"
- "github.com/jackc/pgx/v5/pgxpool"
- "gogs.fxtmmsk.ru/foxtime/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 {
- // Проверка нарушения уникальности через код ошибки pgx (23505 = unique_violation)
- var pgErr *pgconn.PgError
- if errors.As(err, &pgErr) && pgErr.Code == "23505" {
- return fmt.Errorf("you already reviewed this")
- }
- return fmt.Errorf("create review: %w", err)
- }
- // Обновляем рейтинг и количество отзывов у целевой сущности
- if review.TargetType == "service" {
- _, err = tx.Exec(ctx,
- `UPDATE services 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`,
- review.TargetType, review.TargetID)
- } else {
- _, err = tx.Exec(ctx,
- `UPDATE places 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`,
- 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
- }
|