From 2f2c683a73ecd380d3b50171e475a4e5420eab90 Mon Sep 17 00:00:00 2001 From: Noteworthy Date: Sun, 29 Sep 2024 08:37:03 +1000 Subject: [PATCH] feat: user followers is now nested on user document (#88) --- db/action-follow.n1ql | 7 ++++++- db/action-unfollow.n1ql | 8 +++++++- internal/entity/user.go | 9 ++++----- internal/user/api.go | 2 ++ internal/user/repository.go | 14 +++++++------- internal/user/service.go | 21 ++++----------------- 6 files changed, 30 insertions(+), 31 deletions(-) diff --git a/db/action-follow.n1ql b/db/action-follow.n1ql index 7a79f0d..17f168a 100644 --- a/db/action-follow.n1ql +++ b/db/action-follow.n1ql @@ -1,6 +1,11 @@ /* N1QL query to prepend a username to the user's following. */ UPDATE `bucket_name` -USE KEYS $user +USE KEYS LOWER($user) SET `following` = ARRAY_PREPEND({"username": $username, "ts": $ts}, `following`) WHERE NOT ANY item IN `following` SATISFIES item.username = $username END; + +UPDATE `bucket_name` +USE KEYS LOWER($username) +SET `followers` = ARRAY_PREPEND({"username": $user, "ts": $ts}, `followers`) +WHERE NOT ANY item IN `followers` SATISFIES item.username = $user END; diff --git a/db/action-unfollow.n1ql b/db/action-unfollow.n1ql index 9be7c9c..5ee3b41 100644 --- a/db/action-unfollow.n1ql +++ b/db/action-unfollow.n1ql @@ -1,7 +1,13 @@ /* N1QL query to remove a user from a user's following. */ UPDATE `bucket_name` -USE KEYS $user +USE KEYS LOWER($user) SET `following` = ARRAY item FOR item IN `following` WHEN item.username != $username END WHERE ANY item IN `following` SATISFIES item.username = $username END; + +UPDATE `bucket_name` +USE KEYS LOWER($username) +SET `followers` = ARRAY item FOR item IN `followers` + WHEN item.username != $user END +WHERE ANY item IN `followers` SATISFIES item.username = $user END; diff --git a/internal/entity/user.go b/internal/entity/user.go index 5401a1e..a785575 100644 --- a/internal/entity/user.go +++ b/internal/entity/user.go @@ -18,8 +18,8 @@ type UserSubmission struct { Timestamp int64 `json:"ts"` } -// UserFollowing represents users which current user is following. -type UserFollowing struct { +// UserFollows represents users' following or followrs. +type UserFollows struct { Username string `json:"username"` Timestamp int64 `json:"ts"` } @@ -38,9 +38,8 @@ type User struct { MemberSince int64 `json:"member_since"` LastSeen int64 `json:"last_seen"` Admin bool `json:"admin"` - Following []UserFollowing `json:"following"` - Followers []string `json:"followers"` - FollowersCount int `json:"followers_count"` + Following []UserFollows `json:"following"` + Followers []UserFollows `json:"followers"` Likes []UserLike `json:"likes"` Submissions []UserSubmission `json:"submissions"` CommentsCount int `json:"comments_count"` diff --git a/internal/user/api.go b/internal/user/api.go index 7a63efc..740c393 100644 --- a/internal/user/api.go +++ b/internal/user/api.go @@ -93,11 +93,13 @@ func (r resource) get(c echo.Context) error { LikesCount int `json:"likes_count"` SubmissionsCount int `json:"submissions_count"` FollowingCount int `json:"following_count"` + FollowersCount int `json:"followers_count"` }{ User: user, LikesCount: len(user.Likes), SubmissionsCount: len(user.Submissions), FollowingCount: len(user.Following), + FollowersCount: len(user.Followers), } return c.JSON(http.StatusOK, response) } diff --git a/internal/user/repository.go b/internal/user/repository.go index b4c131b..325e01e 100644 --- a/internal/user/repository.go +++ b/internal/user/repository.go @@ -47,9 +47,9 @@ type Repository interface { Activities(ctx context.Context, id string, offset, limit int) ([]interface{}, error) CountActivities(ctx context.Context) (int, error) Like(ctx context.Context, id string, userLike entity.UserLike) error - Follow(ctx context.Context, id string, userLike entity.UserFollowing) error + Follow(ctx context.Context, username string, userLike entity.UserFollows) error Unlike(ctx context.Context, id, sha256 string) error - Unfollow(ctx context.Context, id, username string) error + Unfollow(ctx context.Context, username, targetUsername string) error } // repository persists users in database. @@ -438,26 +438,26 @@ func (r repository) Unlike(ctx context.Context, id, sha256 string) error { return r.db.Query(ctx, query, params, &results) } -func (r repository) Follow(ctx context.Context, id string, userFollow entity.UserFollowing) error { +func (r repository) Follow(ctx context.Context, username string, userFollow entity.UserFollows) error { var results interface{} params := make(map[string]interface{}, 1) params["username"] = userFollow.Username params["ts"] = userFollow.Timestamp - params["user"] = id + params["user"] = username query := r.db.N1QLQuery[dbcontext.ActionFollow] return r.db.Query(ctx, query, params, &results) } -func (r repository) Unfollow(ctx context.Context, id, username string) error { +func (r repository) Unfollow(ctx context.Context, username, targetUsername string) error { var results interface{} params := make(map[string]interface{}, 1) - params["username"] = username - params["user"] = id + params["username"] = targetUsername + params["user"] = username query := r.db.N1QLQuery[dbcontext.ActionUnfollow] return r.db.Query(ctx, query, params, &results) diff --git a/internal/user/service.go b/internal/user/service.go index f84c1a0..88db1b0 100644 --- a/internal/user/service.go +++ b/internal/user/service.go @@ -352,7 +352,7 @@ func (s service) CountFollowers(ctx context.Context, id string) (int, error) { if err != nil { return 0, err } - return user.FollowersCount, err + return len(user.Followers), err } func (s service) CountComments(ctx context.Context, id string) (int, error) { @@ -403,20 +403,13 @@ func (s service) Follow(ctx context.Context, id string) error { return err } - newFollow := entity.UserFollowing{ + newFollow := entity.UserFollows{ Username: targetUser.Username, Timestamp: time.Now().Unix(), } - if err = s.repo.Follow(ctx, curUser.ID(), newFollow); err != nil { + if err = s.repo.Follow(ctx, curUser.Username, newFollow); err != nil { return err } - - if !isStringInSlice(curUsername, targetUser.Followers) { - targetUser.Followers = append(targetUser.Followers, curUsername) - targetUser.FollowersCount += 1 - return s.repo.Update(ctx, targetUser.User) - } - return nil } @@ -438,16 +431,10 @@ func (s service) UnFollow(ctx context.Context, id string) error { return errUserSelfFollow } - if err = s.repo.Unfollow(ctx, curUser.ID(), targetUser.Username); err != nil { + if err = s.repo.Unfollow(ctx, curUser.Username, targetUser.Username); err != nil { return err } - if isStringInSlice(curUsername, targetUser.Followers) { - targetUser.Followers = removeStringFromSlice( - targetUser.Followers, curUsername) - targetUser.FollowersCount -= 1 - } - if err = s.repo.Update(ctx, curUser.User); err != nil { return err }