hiling_go/db/sqlc/locations.go

112 lines
3.4 KiB
Go

package db
import (
"context"
"database/sql"
"fmt"
)
type GetTopListLocationsParams struct {
Limit int32
Offset int32
OrderBy string
RegionType sql.NullInt16
}
type GetTopListLocationsRow struct {
RowNumber int32 `json:"row_number"`
ID int32 `json:"id"`
Name string `json:"name"`
RegionName string `json:"region_name"`
Thumbnail sql.NullString `json:"thumbnail"`
Address string `json:"address"`
GoogleMapsLink string `json:"google_maps_link"`
RegencyName string `json:"regency_name"`
CriticScore sql.NullInt32 `json:"critic_score"`
CriticCount int16 `json:"critic_count"`
UserScore sql.NullInt32 `json:"user_score"`
UserCount int16 `json:"user_count"`
TotalCount int16 `json:"total_count"`
CriticBayes int16 `json:"critic_bayes"`
UserBayes int16 `json:"user_bayes"`
AvgBayes int16 `json:"avg_bayes"`
}
func (q *Queries) GetTopListLocations(ctx context.Context, arg GetTopListLocationsParams) ([]GetTopListLocationsRow, error) {
regionType := ""
if arg.RegionType.Valid {
regionType = fmt.Sprintf("AND reg.id = %d", arg.RegionType.Int16)
}
// https://fulmicoton.com/posts/bayesian_rating/
getTopListQ := fmt.Sprintf(`SELECT
row_number() over (ORDER BY %s DESC) as row_number,
*
FROM(
SELECT
*,
(SELECT 5 * 4 + coalesce(critic_score, 0) * coalesce(critic_count, 0) / 5 + coalesce(critic_count, 0)) as critic_bayes,
(SELECT 50 + coalesce(user_score, 0) * coalesce(user_count, 0) / 50 + coalesce(user_count, 0)) as user_bayes,
((SELECT 50 + coalesce(user_score, 0) * coalesce(user_count, 0) / 50 + coalesce(user_count, 0)) + (SELECT 5 * 4 + coalesce(critic_score, 0) * coalesce(critic_count, 0) / 5 + coalesce(critic_count, 0)) ) / 2 as avg_bayes
FROM (
SELECT
l.id,
name,
l.address,
reg.region_name as region_name,
l.google_maps_link,
thumbnail,
re.regency_name,
(SELECT SUM(score) from reviews re where re.is_from_critic = true and re.location_id = l.id) as critic_score,
(SELECT COUNT(id) from reviews re where re.is_from_critic = true and re.location_id = l.id) as critic_count,
(SELECT SUM(score) from reviews re where re.is_from_critic = false and re.location_id = l.id) as user_score,
(SELECT COUNT(id) from reviews re where re.is_from_critic = false and re.location_id = l.id) as user_count
FROM locations l
JOIN regencies re on re.id = l.regency_id
JOIN provinces prov on prov.id = re.province_id
JOIN regions reg on reg.id = prov.region_id
WHERE approved_by IS NOT NULL %s ) iq1 ) iq2
LIMIT $1
OFFSET $2;`, arg.OrderBy, regionType)
rows, err := q.db.QueryContext(ctx, getTopListQ, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetTopListLocationsRow{}
for rows.Next() {
var i GetTopListLocationsRow
if err := rows.Scan(
&i.RowNumber,
&i.ID,
&i.Name,
&i.Address,
&i.RegionName,
&i.GoogleMapsLink,
&i.Thumbnail,
&i.RegencyName,
&i.CriticScore,
&i.CriticCount,
&i.UserScore,
&i.UserCount,
&i.CriticBayes,
&i.UserBayes,
&i.AvgBayes,
); err != nil {
return nil, err
}
i.TotalCount = i.UserCount + i.CriticCount
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}