aboutsummaryrefslogtreecommitdiff
path: root/backend/handlers
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-09-02 16:12:46 +0300
committerArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-09-02 16:12:46 +0300
commitf2bfade4812a9f7b1f97593754c95359ce99e2f1 (patch)
tree49dddf4df3a80ccf5961bd2719b72707eb19bcf2 /backend/handlers
parentfix: remove redundant log (diff)
downloadlphub-f2bfade4812a9f7b1f97593754c95359ce99e2f1.tar.gz
lphub-f2bfade4812a9f7b1f97593754c95359ce99e2f1.tar.bz2
lphub-f2bfade4812a9f7b1f97593754c95359ce99e2f1.zip
fix: optimize rankings
Former-commit-id: 16b247861acea7b5c70a872db7b0397f9dc5c879
Diffstat (limited to 'backend/handlers')
-rw-r--r--backend/handlers/home.go149
1 files changed, 78 insertions, 71 deletions
diff --git a/backend/handlers/home.go b/backend/handlers/home.go
index 6e9a0df..53be1de 100644
--- a/backend/handlers/home.go
+++ b/backend/handlers/home.go
@@ -3,6 +3,7 @@ package handlers
3import ( 3import (
4 "log" 4 "log"
5 "net/http" 5 "net/http"
6 "sort"
6 "strings" 7 "strings"
7 8
8 "github.com/gin-gonic/gin" 9 "github.com/gin-gonic/gin"
@@ -16,8 +17,9 @@ type SearchResponse struct {
16} 17}
17 18
18type RankingsResponse struct { 19type RankingsResponse struct {
19 RankingsSP []models.UserRanking `json:"rankings_sp"` 20 Overall []models.UserRanking `json:"rankings_overall"`
20 RankingsMP []models.UserRanking `json:"rankings_mp"` 21 Singleplayer []models.UserRanking `json:"rankings_singleplayer"`
22 Multiplayer []models.UserRanking `json:"rankings_multiplayer"`
21} 23}
22 24
23func Home(c *gin.Context) { 25func Home(c *gin.Context) {
@@ -40,96 +42,101 @@ func Home(c *gin.Context) {
40// @Failure 400 {object} models.Response 42// @Failure 400 {object} models.Response
41// @Router /rankings [get] 43// @Router /rankings [get]
42func Rankings(c *gin.Context) { 44func Rankings(c *gin.Context) {
43 rows, err := database.DB.Query(`SELECT steam_id, user_name FROM users`) 45 response := RankingsResponse{
46 Overall: []models.UserRanking{},
47 Singleplayer: []models.UserRanking{},
48 Multiplayer: []models.UserRanking{},
49 }
50 // Singleplayer rankings
51 sql := `SELECT u.steam_id, u.user_name, COUNT(DISTINCT map_id),
52 (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g.is_coop = FALSE AND is_disabled = false),
53 (SELECT SUM(min_score_count) AS total_min_score_count FROM (
54 SELECT
55 user_id,
56 MIN(score_count) AS min_score_count
57 FROM records_sp
58 GROUP BY user_id, map_id
59 ) AS subquery
60 WHERE user_id = u.steam_id)
61 FROM records_sp sp JOIN users u ON u.steam_id = sp.user_id GROUP BY u.steam_id, u.user_name`
62 rows, err := database.DB.Query(sql)
44 if err != nil { 63 if err != nil {
45 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) 64 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
46 return 65 return
47 } 66 }
48 var spRankings []models.UserRanking
49 var mpRankings []models.UserRanking
50 for rows.Next() { 67 for rows.Next() {
51 var userID, username string 68 ranking := models.UserRanking{}
52 err := rows.Scan(&userID, &username) 69 var currentCount int
70 var totalCount int
71 err = rows.Scan(&ranking.UserID, &ranking.UserName, &currentCount, &totalCount, &ranking.TotalScore)
53 if err != nil { 72 if err != nil {
54 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) 73 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
55 return 74 return
56 } 75 }
57 // Getting all sp records for each user 76 if currentCount != totalCount {
58 var uniqueSingleUserRecords, totalSingleMaps int 77 continue
59 sql := `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps
60 WHERE is_coop = FALSE AND is_disabled = false) FROM records_sp WHERE user_id = $1`
61 err = database.DB.QueryRow(sql, userID).Scan(&uniqueSingleUserRecords, &totalSingleMaps)
62 if err != nil {
63 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
64 return
65 } 78 }
66 // Has all singleplayer records 79 response.Singleplayer = append(response.Singleplayer, ranking)
67 if uniqueSingleUserRecords == totalSingleMaps { 80 }
68 var ranking models.UserRanking 81 // Multiplayer rankings
69 ranking.UserID = userID 82 sql = `SELECT u.steam_id, u.user_name, COUNT(DISTINCT map_id),
70 ranking.UserName = username 83 (SELECT COUNT(maps.name) FROM maps INNER JOIN games g ON maps.game_id = g.id WHERE g.is_coop = FALSE AND is_disabled = false),
71 sql := `SELECT DISTINCT map_id, score_count FROM records_sp WHERE user_id = $1 ORDER BY map_id, score_count` 84 (SELECT SUM(min_score_count) AS total_min_score_count FROM (
72 rows, err := database.DB.Query(sql, userID) 85 SELECT
73 if err != nil { 86 host_id,
74 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) 87 partner_id,
75 return 88 MIN(score_count) AS min_score_count
76 } 89 FROM records_mp
77 totalScore := 0 90 GROUP BY host_id, partner_id, map_id
78 var maps []int 91 ) AS subquery
79 for rows.Next() { 92 WHERE host_id = u.steam_id OR partner_id = u.steam_id)
80 var mapID, scoreCount int 93 FROM records_mp mp JOIN users u ON u.steam_id = mp.host_id OR u.steam_id = mp.partner_id GROUP BY u.steam_id, u.user_name`
81 rows.Scan(&mapID, &scoreCount) 94 rows, err = database.DB.Query(sql)
82 if len(maps) != 0 && maps[len(maps)-1] == mapID { 95 if err != nil {
83 continue 96 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
84 } 97 return
85 totalScore += scoreCount 98 }
86 maps = append(maps, mapID) 99 for rows.Next() {
87 } 100 ranking := models.UserRanking{}
88 ranking.TotalScore = totalScore 101 var currentCount int
89 spRankings = append(spRankings, ranking) 102 var totalCount int
90 } 103 err = rows.Scan(&ranking.UserID, &ranking.UserName, &currentCount, &totalCount, &ranking.TotalScore)
91 // Getting all mp records for each user
92 var uniqueMultiUserRecords, totalMultiMaps int
93 sql = `SELECT COUNT(DISTINCT map_id), (SELECT COUNT(map_name) FROM maps
94 WHERE is_coop = TRUE AND is_disabled = false) FROM records_mp WHERE host_id = $1 OR partner_id = $2`
95 err = database.DB.QueryRow(sql, userID, userID).Scan(&uniqueMultiUserRecords, &totalMultiMaps)
96 if err != nil { 104 if err != nil {
97 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) 105 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error()))
98 return 106 return
99 } 107 }
100 // Has all singleplayer records 108 if currentCount != totalCount {
101 if uniqueMultiUserRecords == totalMultiMaps { 109 continue
102 var ranking models.UserRanking 110 }
103 ranking.UserID = userID 111 response.Multiplayer = append(response.Multiplayer, ranking)
104 ranking.UserName = username 112 }
105 sql := `SELECT DISTINCT map_id, score_count FROM records_mp WHERE host_id = $1 OR partner_id = $2 ORDER BY map_id, score_count` 113 // Has both so they are qualified for overall ranking
106 rows, err := database.DB.Query(sql, userID, userID) 114 for _, spRanking := range response.Singleplayer {
107 if err != nil { 115 for _, mpRanking := range response.Multiplayer {
108 c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) 116 if spRanking.UserID == mpRanking.UserID {
109 return 117 totalScore := spRanking.TotalScore + mpRanking.TotalScore
110 } 118 overallRanking := models.UserRanking{
111 totalScore := 0 119 UserID: spRanking.UserID,
112 var maps []int 120 UserName: spRanking.UserName,
113 for rows.Next() { 121 TotalScore: totalScore,
114 var mapID, scoreCount int
115 rows.Scan(&mapID, &scoreCount)
116 if len(maps) != 0 && maps[len(maps)-1] == mapID {
117 continue
118 } 122 }
119 totalScore += scoreCount 123 response.Overall = append(response.Overall, overallRanking)
120 maps = append(maps, mapID)
121 } 124 }
122 ranking.TotalScore = totalScore
123 mpRankings = append(mpRankings, ranking)
124 } 125 }
125 } 126 }
127 sort.Slice(response.Singleplayer, func(i, j int) bool {
128 return response.Singleplayer[i].TotalScore < response.Singleplayer[j].TotalScore
129 })
130 sort.Slice(response.Multiplayer, func(i, j int) bool {
131 return response.Multiplayer[i].TotalScore < response.Multiplayer[j].TotalScore
132 })
133 sort.Slice(response.Overall, func(i, j int) bool {
134 return response.Overall[i].TotalScore < response.Overall[j].TotalScore
135 })
126 c.JSON(http.StatusOK, models.Response{ 136 c.JSON(http.StatusOK, models.Response{
127 Success: true, 137 Success: true,
128 Message: "Successfully retrieved rankings.", 138 Message: "Successfully retrieved rankings.",
129 Data: RankingsResponse{ 139 Data: response,
130 RankingsSP: spRankings,
131 RankingsMP: mpRankings,
132 },
133 }) 140 })
134} 141}
135 142