mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
fix: errors during leaderboard generation
This commit is contained in:
parent
b1d7f87095
commit
efd6ba36e3
@ -11,7 +11,6 @@ type LeaderboardItem struct {
|
|||||||
ID uint `json:"-" gorm:"primary_key; size:32"`
|
ID uint `json:"-" gorm:"primary_key; size:32"`
|
||||||
User *User `json:"-" gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
User *User `json:"-" gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||||
UserID string `json:"user_id" gorm:"not null; index:idx_leaderboard_user"`
|
UserID string `json:"user_id" gorm:"not null; index:idx_leaderboard_user"`
|
||||||
Rank uint `json:"rank" gorm:"-:migration"`
|
|
||||||
Interval string `json:"interval" gorm:"not null; size:32; index:idx_leaderboard_combined"`
|
Interval string `json:"interval" gorm:"not null; size:32; index:idx_leaderboard_combined"`
|
||||||
By *uint8 `json:"aggregated_by" gorm:"index:idx_leaderboard_combined"` // pointer because nullable
|
By *uint8 `json:"aggregated_by" gorm:"index:idx_leaderboard_combined"` // pointer because nullable
|
||||||
Total time.Duration `json:"total" gorm:"not null" swaggertype:"primitive,integer"`
|
Total time.Duration `json:"total" gorm:"not null" swaggertype:"primitive,integer"`
|
||||||
@ -19,28 +18,35 @@ type LeaderboardItem struct {
|
|||||||
CreatedAt CustomTime `gorm:"type:timestamp; default:CURRENT_TIMESTAMP" swaggertype:"string" format:"date" example:"2006-01-02 15:04:05.000"`
|
CreatedAt CustomTime `gorm:"type:timestamp; default:CURRENT_TIMESTAMP" swaggertype:"string" format:"date" example:"2006-01-02 15:04:05.000"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l1 *LeaderboardItem) Equals(l2 *LeaderboardItem) bool {
|
// https://github.com/go-gorm/gorm/issues/5789
|
||||||
|
// https://github.com/go-gorm/gorm/issues/5284#issuecomment-1107775806
|
||||||
|
type LeaderboardItemRanked struct {
|
||||||
|
LeaderboardItem
|
||||||
|
Rank uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l1 *LeaderboardItemRanked) Equals(l2 *LeaderboardItemRanked) bool {
|
||||||
return l1.ID == l2.ID
|
return l1.ID == l2.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
type Leaderboard []*LeaderboardItem
|
type Leaderboard []*LeaderboardItemRanked
|
||||||
|
|
||||||
func (l *Leaderboard) Add(item *LeaderboardItem) {
|
func (l *Leaderboard) Add(item *LeaderboardItemRanked) {
|
||||||
if _, found := slice.Find[*LeaderboardItem](*l, func(i int, item2 *LeaderboardItem) bool {
|
if _, found := slice.Find[*LeaderboardItemRanked](*l, func(i int, item2 *LeaderboardItemRanked) bool {
|
||||||
return item.Equals(item2)
|
return item.Equals(item2)
|
||||||
}); !found {
|
}); !found {
|
||||||
*l = append(*l, item)
|
*l = append(*l, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Leaderboard) AddMany(items []*LeaderboardItem) {
|
func (l *Leaderboard) AddMany(items []*LeaderboardItemRanked) {
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
l.Add(item)
|
l.Add(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Leaderboard) UserIDs() []string {
|
func (l Leaderboard) UserIDs() []string {
|
||||||
return slice.Unique[string](slice.Map[*LeaderboardItem, string](l, func(i int, item *LeaderboardItem) string {
|
return slice.Unique[string](slice.Map[*LeaderboardItemRanked, string](l, func(i int, item *LeaderboardItemRanked) string {
|
||||||
return item.UserID
|
return item.UserID
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -50,7 +56,7 @@ func (l Leaderboard) HasUser(userId string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l Leaderboard) TopByKey(by uint8, key string) Leaderboard {
|
func (l Leaderboard) TopByKey(by uint8, key string) Leaderboard {
|
||||||
return slice.Filter[*LeaderboardItem](l, func(i int, item *LeaderboardItem) bool {
|
return slice.Filter[*LeaderboardItemRanked](l, func(i int, item *LeaderboardItemRanked) bool {
|
||||||
return item.By != nil && *item.By == by && item.Key != nil && strings.ToLower(*item.Key) == strings.ToLower(key)
|
return item.By != nil && *item.By == by && item.Key != nil && strings.ToLower(*item.Key) == strings.ToLower(key)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -87,7 +93,7 @@ func (l Leaderboard) TopKeys(by uint8) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l Leaderboard) TopKeysByUser(by uint8, userId string) []string {
|
func (l Leaderboard) TopKeysByUser(by uint8, userId string) []string {
|
||||||
return Leaderboard(slice.Filter[*LeaderboardItem](l, func(i int, item *LeaderboardItem) bool {
|
return Leaderboard(slice.Filter[*LeaderboardItemRanked](l, func(i int, item *LeaderboardItemRanked) bool {
|
||||||
return item.UserID == userId
|
return item.UserID == userId
|
||||||
})).TopKeys(by)
|
})).TopKeys(by)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ type LeaderboardViewModel struct {
|
|||||||
User *models.User
|
User *models.User
|
||||||
By string
|
By string
|
||||||
Key string
|
Key string
|
||||||
Items []*models.LeaderboardItem
|
Items []*models.LeaderboardItemRanked
|
||||||
TopKeys []string
|
TopKeys []string
|
||||||
UserLanguages map[string][]string
|
UserLanguages map[string][]string
|
||||||
ApiKey string
|
ApiKey string
|
||||||
@ -29,7 +29,7 @@ func (s *LeaderboardViewModel) WithError(m string) *LeaderboardViewModel {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *LeaderboardViewModel) ColorModifier(item *models.LeaderboardItem, principal *models.User) string {
|
func (s *LeaderboardViewModel) ColorModifier(item *models.LeaderboardItemRanked, principal *models.User) string {
|
||||||
if principal != nil && item.UserID == principal.ID {
|
if principal != nil && item.UserID == principal.ID {
|
||||||
return "self"
|
return "self"
|
||||||
}
|
}
|
||||||
|
@ -42,9 +42,10 @@ func (r *LeaderboardRepository) CountUsers() (int64, error) {
|
|||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LeaderboardRepository) GetAllAggregatedByInterval(key *models.IntervalKey, by *uint8, limit, skip int) ([]*models.LeaderboardItem, error) {
|
func (r *LeaderboardRepository) GetAllAggregatedByInterval(key *models.IntervalKey, by *uint8, limit, skip int) ([]*models.LeaderboardItemRanked, error) {
|
||||||
// TODO: distinct by (user, key) to filter out potential duplicates ?
|
// TODO: distinct by (user, key) to filter out potential duplicates ?
|
||||||
var items []*models.LeaderboardItem
|
|
||||||
|
var items []*models.LeaderboardItemRanked
|
||||||
subq := r.db.
|
subq := r.db.
|
||||||
Table("leaderboard_items").
|
Table("leaderboard_items").
|
||||||
Select("*, rank() over (partition by \"key\" order by total desc) as \"rank\"").
|
Select("*, rank() over (partition by \"key\" order by total desc) as \"rank\"").
|
||||||
@ -60,8 +61,8 @@ func (r *LeaderboardRepository) GetAllAggregatedByInterval(key *models.IntervalK
|
|||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LeaderboardRepository) GetAggregatedByUserAndInterval(userId string, key *models.IntervalKey, by *uint8, limit, skip int) ([]*models.LeaderboardItem, error) {
|
func (r *LeaderboardRepository) GetAggregatedByUserAndInterval(userId string, key *models.IntervalKey, by *uint8, limit, skip int) ([]*models.LeaderboardItemRanked, error) {
|
||||||
var items []*models.LeaderboardItem
|
var items []*models.LeaderboardItemRanked
|
||||||
subq := r.db.
|
subq := r.db.
|
||||||
Table("leaderboard_items").
|
Table("leaderboard_items").
|
||||||
Select("*, rank() over (partition by \"key\" order by total desc) as \"rank\"").
|
Select("*, rank() over (partition by \"key\" order by total desc) as \"rank\"").
|
||||||
|
@ -93,6 +93,6 @@ type ILeaderboardRepository interface {
|
|||||||
CountUsers() (int64, error)
|
CountUsers() (int64, error)
|
||||||
DeleteByUser(string) error
|
DeleteByUser(string) error
|
||||||
DeleteByUserAndInterval(string, *models.IntervalKey) error
|
DeleteByUserAndInterval(string, *models.IntervalKey) error
|
||||||
GetAllAggregatedByInterval(*models.IntervalKey, *uint8, int, int) ([]*models.LeaderboardItem, error)
|
GetAllAggregatedByInterval(*models.IntervalKey, *uint8, int, int) ([]*models.LeaderboardItemRanked, error)
|
||||||
GetAggregatedByUserAndInterval(string, *models.IntervalKey, *uint8, int, int) ([]*models.LeaderboardItem, error)
|
GetAggregatedByUserAndInterval(string, *models.IntervalKey, *uint8, int, int) ([]*models.LeaderboardItemRanked, error)
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func (h *LeaderboardHandler) buildViewModel(r *http.Request) *view.LeaderboardVi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userLeaderboards := slice.GroupWith[*models.LeaderboardItem, string](leaderboard, func(item *models.LeaderboardItem) string {
|
userLeaderboards := slice.GroupWith[*models.LeaderboardItemRanked, string](leaderboard, func(item *models.LeaderboardItemRanked) string {
|
||||||
return item.UserID
|
return item.UserID
|
||||||
})
|
})
|
||||||
userLanguages = map[string][]string{}
|
userLanguages = map[string][]string{}
|
||||||
|
@ -152,7 +152,7 @@ func (srv *LeaderboardService) GetAggregatedByInterval(interval *models.Interval
|
|||||||
// check cache
|
// check cache
|
||||||
cacheKey := srv.getHash(interval, by, "", pageParams)
|
cacheKey := srv.getHash(interval, by, "", pageParams)
|
||||||
if cacheResult, ok := srv.cache.Get(cacheKey); ok {
|
if cacheResult, ok := srv.cache.Get(cacheKey); ok {
|
||||||
return cacheResult.([]*models.LeaderboardItem), nil
|
return cacheResult.([]*models.LeaderboardItemRanked), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
items, err := srv.repository.GetAllAggregatedByInterval(interval, by, pageParams.Limit(), pageParams.Offset())
|
items, err := srv.repository.GetAllAggregatedByInterval(interval, by, pageParams.Limit(), pageParams.Offset())
|
||||||
@ -181,7 +181,7 @@ func (srv *LeaderboardService) GetAggregatedByIntervalAndUser(interval *models.I
|
|||||||
// check cache
|
// check cache
|
||||||
cacheKey := srv.getHash(interval, by, userId, nil)
|
cacheKey := srv.getHash(interval, by, userId, nil)
|
||||||
if cacheResult, ok := srv.cache.Get(cacheKey); ok {
|
if cacheResult, ok := srv.cache.Get(cacheKey); ok {
|
||||||
return cacheResult.([]*models.LeaderboardItem), nil
|
return cacheResult.([]*models.LeaderboardItemRanked), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
items, err := srv.repository.GetAggregatedByUserAndInterval(userId, interval, by, 0, 0)
|
items, err := srv.repository.GetAggregatedByUserAndInterval(userId, interval, by, 0, 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user