package models import ( "time" "git.kirsle.net/apps/gosocial/pkg/log" ) // Like table. type Like struct { ID uint64 `gorm:"primaryKey"` UserID uint64 `gorm:"index"` // who it belongs to TableName string TableID uint64 CreatedAt time.Time UpdatedAt time.Time } // LikeableTables are the set of table names that allow likes (used by the JSON API). var LikeableTables = map[string]interface{}{ "photos": nil, "users": nil, } // AddLike to something. func AddLike(user *User, tableName string, tableID uint64) error { // Already has a like? var like = &Like{} exist := DB.Model(like).Where( "user_id = ? AND table_name = ? AND table_id = ?", user.ID, tableName, tableID, ).First(&like) if exist.Error == nil { return nil } // Create it. like = &Like{ UserID: user.ID, TableName: tableName, TableID: tableID, } return DB.Create(like).Error } // Unlike something. func Unlike(user *User, tableName string, tableID uint64) error { result := DB.Where( "user_id = ? AND table_name = ? AND table_id = ?", user.ID, tableName, tableID, ).Delete(&Like{}) return result.Error } // CountLikes on something. func CountLikes(tableName string, tableID uint64) int64 { var count int64 DB.Model(&Like{}).Where( "table_name = ? AND table_id = ?", tableName, tableID, ).Count(&count) return count } // LikedIDs filters a set of table IDs to ones the user likes. func LikedIDs(user *User, tableName string, tableIDs []uint64) ([]uint64, error) { var result = []uint64{} if r := DB.Table( "likes", ).Select( "table_id", ).Where( "user_id = ? AND table_name = ? AND table_id IN ?", user.ID, tableName, tableIDs, ).Scan(&result); r.Error != nil { return result, r.Error } return result, nil } // LikeMap maps table IDs to Likes metadata. type LikeMap map[uint64]*LikeStats // Get like stats from the map. func (lm LikeMap) Get(id uint64) *LikeStats { if stats, ok := lm[id]; ok { return stats } return &LikeStats{} } // LikeStats holds mapped statistics about liked objects. type LikeStats struct { Count int64 // how many total UserLikes bool // current user likes it } // MapLikes over a set of table IDs. func MapLikes(user *User, tableName string, tableIDs []uint64) LikeMap { var result = LikeMap{} // Initialize the result set. for _, id := range tableIDs { result[id] = &LikeStats{} } // Hold the result of the grouped count query. type group struct { ID uint64 Likes int64 } var groups = []group{} // Map the counts of likes to each of these IDs. if res := DB.Table( "likes", ).Select( "table_id AS id, count(id) AS likes", ).Where( "table_name = ? AND table_id IN ?", tableName, tableIDs, ).Group("table_id").Scan(&groups); res.Error != nil { log.Error("MapLikes: count query: %s", res.Error) } // Map the counts back in. for _, row := range groups { if stats, ok := result[row.ID]; ok { stats.Count = row.Likes } } // Does the CURRENT USER like any of these IDs? if likedIDs, err := LikedIDs(user, tableName, tableIDs); err == nil { log.Error("USER LIKES IDS: %+v", likedIDs) for _, id := range likedIDs { if stats, ok := result[id]; ok { stats.UserLikes = true } } } return result }