feat: add folloers/following list

This commit is contained in:
Krispire Admin
2026-06-09 13:20:14 +05:30
parent 0188a34cf6
commit da2bbc323d
5 changed files with 126 additions and 0 deletions
+60
View File
@@ -93,6 +93,66 @@ func (r *FollowRepo) Status(ctx context.Context, followerID, followingID string)
}
// CountFollowers counts accepted edges pointing at userID.
// ListFollowers returns the accepted followers of userID (users who follow
// them), newest first, optionally filtered by a name/handle search `q`.
// Returns the page plus the total matching count (for pagination).
func (r *FollowRepo) ListFollowers(ctx context.Context, userID, q string, limit, offset int) ([]model.UserSummary, int, error) {
return r.listRelations(ctx, "f.following_id = $1", "f.follower_id", userID, q, limit, offset)
}
// ListFollowing returns the users userID follows (accepted), newest first,
// optionally filtered by `q`. Returns the page plus the total count.
func (r *FollowRepo) ListFollowing(ctx context.Context, userID, q string, limit, offset int) ([]model.UserSummary, int, error) {
return r.listRelations(ctx, "f.follower_id = $1", "f.following_id", userID, q, limit, offset)
}
// listRelations powers both directions: `whereOwn` pins the row to userID on
// one side, `joinCol` is the follows column holding the *other* user (the one
// we join to users and return). `q` filters by name/handle (ILIKE); empty `q`
// disables the filter. The column expressions are fixed internal constants —
// never user input — so this stays injection-safe.
func (r *FollowRepo) listRelations(
ctx context.Context, whereOwn, joinCol, userID, q string, limit, offset int,
) ([]model.UserSummary, int, error) {
like := "%" + q + "%"
var total int
countSQL := `
SELECT count(*)
FROM follows f JOIN users u ON u.id = ` + joinCol + `
WHERE ` + whereOwn + ` AND f.status = 'accepted'
AND ($2 = '' OR u.name ILIKE $3 OR u.handle ILIKE $3)`
if err := r.pg.Pool.QueryRow(ctx, countSQL, userID, q, like).Scan(&total); err != nil {
return nil, 0, fmt.Errorf("count relations: %w", err)
}
if total == 0 {
return []model.UserSummary{}, 0, nil
}
listSQL := `
SELECT u.handle, u.name, u.avatar_url
FROM follows f JOIN users u ON u.id = ` + joinCol + `
WHERE ` + whereOwn + ` AND f.status = 'accepted'
AND ($2 = '' OR u.name ILIKE $3 OR u.handle ILIKE $3)
ORDER BY f.created_at DESC, u.handle ASC
LIMIT $4 OFFSET $5`
rows, err := r.pg.Pool.Query(ctx, listSQL, userID, q, like, limit, offset)
if err != nil {
return nil, 0, fmt.Errorf("list relations: %w", err)
}
defer rows.Close()
out := make([]model.UserSummary, 0, limit)
for rows.Next() {
var s model.UserSummary
if err := rows.Scan(&s.Handle, &s.Name, &s.AvatarURL); err != nil {
return nil, 0, fmt.Errorf("scan relation: %w", err)
}
out = append(out, s)
}
return out, total, rows.Err()
}
func (r *FollowRepo) CountFollowers(ctx context.Context, userID string) (int, error) {
var n int
err := r.pg.Pool.QueryRow(ctx, `