Skip to content

Commit

Permalink
feat: user followers is now nested on user document (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
ayoubfaouzi authored Sep 28, 2024
1 parent 117fae7 commit 2f2c683
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 31 deletions.
7 changes: 6 additions & 1 deletion db/action-follow.n1ql
Original file line number Diff line number Diff line change
@@ -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;
8 changes: 7 additions & 1 deletion db/action-unfollow.n1ql
Original file line number Diff line number Diff line change
@@ -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;
9 changes: 4 additions & 5 deletions internal/entity/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Expand All @@ -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"`
Expand Down
2 changes: 2 additions & 0 deletions internal/user/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
14 changes: 7 additions & 7 deletions internal/user/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down
21 changes: 4 additions & 17 deletions internal/user/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
}

Expand All @@ -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
}
Expand Down

0 comments on commit 2f2c683

Please sign in to comment.