fix social network server
This commit is contained in:
parent
350bbf086c
commit
e352f006b0
|
@ -2,4 +2,4 @@
|
|||
CREATE DATABASE relation;
|
||||
|
||||
// 創建 User 節點 UID 是唯一鍵
|
||||
CREATE CONSTRAINT FOR (u:User) REQUIRE u.UID IS UNIQUE
|
||||
CREATE CONSTRAINT FOR (u:User) REQUIRE u.uid IS UNIQUE
|
|
@ -251,7 +251,48 @@ message AddUserToNetworkReq
|
|||
string uid = 1;
|
||||
}
|
||||
|
||||
message DoFollowerRelationReq
|
||||
{
|
||||
string follower_uid = 1;
|
||||
string followee_uid = 2;
|
||||
}
|
||||
|
||||
message FollowReq
|
||||
{
|
||||
string uid = 1;
|
||||
int64 page_size = 2;
|
||||
int64 page_index = 3;
|
||||
}
|
||||
|
||||
message FollowResp
|
||||
{
|
||||
repeated string uid = 1;
|
||||
Pager page = 2;
|
||||
}
|
||||
|
||||
message FollowCountReq
|
||||
{
|
||||
string uid = 1;
|
||||
}
|
||||
|
||||
message FollowCountResp
|
||||
{
|
||||
string uid = 1;
|
||||
int64 total = 2;
|
||||
}
|
||||
|
||||
service SocialNetworkService
|
||||
{
|
||||
rpc AddUserToNetwork(AddUserToNetworkReq) returns (OKResp);
|
||||
// MarkFollowRelation 關注
|
||||
rpc MarkFollowRelation(DoFollowerRelationReq) returns (OKResp);
|
||||
// RemoveFollowRelation 取消關注
|
||||
rpc RemoveFollowRelation(DoFollowerRelationReq) returns (OKResp);
|
||||
// GetFollower 取得跟隨者名單
|
||||
rpc GetFollower(FollowReq) returns (FollowResp);
|
||||
// GetFollowee 取得我跟隨的名單
|
||||
rpc GetFollowee(FollowReq) returns (FollowResp);
|
||||
// GetFollowerCount 取得跟隨者數量
|
||||
rpc GetFollowerCount(FollowCountReq) returns (FollowCountResp);
|
||||
// GetFolloweeCount 取得我跟隨的數量
|
||||
rpc GetFolloweeCount(FollowCountReq) returns (FollowCountResp);
|
||||
}
|
|
@ -41,6 +41,15 @@ const (
|
|||
SetNoMoreDataErrorCode
|
||||
)
|
||||
|
||||
const (
|
||||
MarkRelationErrorCode ErrorCode = iota + 30
|
||||
GetFollowerErrorCode
|
||||
GetFollowerCountErrorCode
|
||||
GetFolloweeErrorCode
|
||||
GetFolloweeCountErrorCode
|
||||
RemoveRelationErrorCode
|
||||
)
|
||||
|
||||
func CommentError(ec ErrorCode, s ...string) *ers.LibError {
|
||||
return ers.NewError(code.CloudEPTweeting, code.DBError,
|
||||
ec.ToUint32(),
|
||||
|
|
|
@ -4,4 +4,23 @@ import "context"
|
|||
|
||||
type SocialNetworkRepository interface {
|
||||
CreateUserNode(ctx context.Context, uid string) error
|
||||
MarkFollowerRelation(ctx context.Context, fromUID, toUID string) error
|
||||
RemoveFollowerRelation(ctx context.Context, fromUID, toUID string) error
|
||||
GetFollower(ctx context.Context, req FollowReq) (FollowResp, error)
|
||||
GetFollowee(ctx context.Context, req FollowReq) (FollowResp, error)
|
||||
GetFollowerCount(ctx context.Context, uid string) (int64, error)
|
||||
GetFolloweeCount(ctx context.Context, uid string) (int64, error)
|
||||
GetDegreeBetweenUsers(ctx context.Context, uid1, uid2 string) (int64, error)
|
||||
GetUIDsWithinNDegrees(ctx context.Context, uid string, degrees, pageSize, pageIndex int64) ([]string, int64, error)
|
||||
}
|
||||
|
||||
type FollowReq struct {
|
||||
UID string
|
||||
PageSize int64
|
||||
PageIndex int64
|
||||
}
|
||||
|
||||
type FollowResp struct {
|
||||
UIDs []string
|
||||
Total int64
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package socialnetworkservicelogic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||
"app-cloudep-tweeting-service/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AddUserToNetworkLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewAddUserToNetworkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddUserToNetworkLogic {
|
||||
return &AddUserToNetworkLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AddUserToNetworkLogic) AddUserToNetwork(in *tweeting.AddUserToNetworkReq) (*tweeting.OKResp, error) {
|
||||
// todo: add your logic here and delete this line
|
||||
err := l.svcCtx.SocialNetworkRepository.CreateUserNode(l.ctx, in.GetUid())
|
||||
if err != nil {
|
||||
fmt.Println("gg88g88g8", err)
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println(err)
|
||||
|
||||
return &tweeting.OKResp{}, nil
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package socialnetworkservicelogic
|
||||
|
||||
import (
|
||||
"app-cloudep-tweeting-service/internal/domain"
|
||||
ers "code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
|
||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||
"app-cloudep-tweeting-service/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetFolloweeCountLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewGetFolloweeCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFolloweeCountLogic {
|
||||
return &GetFolloweeCountLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
// GetFolloweeCount 取得我跟隨的數量
|
||||
func (l *GetFolloweeCountLogic) GetFolloweeCount(in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||
// 驗證資料
|
||||
if err := l.svcCtx.Validate.ValidateAll(&getFollowCountReq{
|
||||
UID: in.Uid,
|
||||
}); err != nil {
|
||||
// 錯誤代碼 05-011-00
|
||||
return nil, ers.InvalidFormat(err.Error())
|
||||
}
|
||||
|
||||
followeeCount, err := l.svcCtx.SocialNetworkRepository.GetFolloweeCount(l.ctx, in.GetUid())
|
||||
if err != nil {
|
||||
// 錯誤代碼 05-021-34
|
||||
e := domain.CommentErrorL(
|
||||
domain.GetFolloweeCountErrorCode,
|
||||
logx.WithContext(l.ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "req", Value: in},
|
||||
{Key: "func", Value: "SocialNetworkRepository.GetFolloweeCount"},
|
||||
{Key: "err", Value: err},
|
||||
},
|
||||
"failed to count follower").Wrap(err)
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return &tweeting.FollowCountResp{
|
||||
Uid: in.GetUid(),
|
||||
Total: followeeCount,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package socialnetworkservicelogic
|
||||
|
||||
import (
|
||||
"app-cloudep-tweeting-service/internal/domain"
|
||||
"app-cloudep-tweeting-service/internal/domain/repository"
|
||||
ers "code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
|
||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||
"app-cloudep-tweeting-service/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetFolloweeLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewGetFolloweeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFolloweeLogic {
|
||||
return &GetFolloweeLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
// GetFollowee 取得我跟隨的名單
|
||||
func (l *GetFolloweeLogic) GetFollowee(in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||
// 驗證資料
|
||||
if err := l.svcCtx.Validate.ValidateAll(&getFollowReq{
|
||||
UID: in.Uid,
|
||||
PageSize: in.PageSize,
|
||||
PageIndex: in.PageIndex,
|
||||
}); err != nil {
|
||||
// 錯誤代碼 05-011-00
|
||||
return nil, ers.InvalidFormat(err.Error())
|
||||
}
|
||||
|
||||
followee, err := l.svcCtx.SocialNetworkRepository.GetFollowee(l.ctx, repository.FollowReq{
|
||||
UID: in.GetUid(),
|
||||
PageIndex: in.GetPageIndex(),
|
||||
PageSize: in.GetPageSize(),
|
||||
})
|
||||
if err != nil {
|
||||
// 錯誤代碼 05-021-33
|
||||
e := domain.CommentErrorL(
|
||||
domain.GetFolloweeErrorCode,
|
||||
logx.WithContext(l.ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "req", Value: in},
|
||||
{Key: "func", Value: "SocialNetworkRepository.GetFollowee"},
|
||||
{Key: "err", Value: err},
|
||||
},
|
||||
"failed to get relation: ", in.GetUid()).Wrap(err)
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return &tweeting.FollowResp{
|
||||
Uid: followee.UIDs,
|
||||
Page: &tweeting.Pager{
|
||||
Total: followee.Total,
|
||||
Index: in.GetPageIndex(),
|
||||
Size: in.GetPageSize(),
|
||||
},
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package socialnetworkservicelogic
|
||||
|
||||
import (
|
||||
"app-cloudep-tweeting-service/internal/domain"
|
||||
ers "code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
|
||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||
"app-cloudep-tweeting-service/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetFollowerCountLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewGetFollowerCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFollowerCountLogic {
|
||||
return &GetFollowerCountLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
type getFollowCountReq struct {
|
||||
UID string `validate:"required"`
|
||||
}
|
||||
|
||||
// GetFollowerCount 取得跟隨者數量
|
||||
func (l *GetFollowerCountLogic) GetFollowerCount(in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||
// 驗證資料
|
||||
if err := l.svcCtx.Validate.ValidateAll(&getFollowCountReq{
|
||||
UID: in.Uid,
|
||||
}); err != nil {
|
||||
// 錯誤代碼 05-011-00
|
||||
return nil, ers.InvalidFormat(err.Error())
|
||||
}
|
||||
|
||||
followerCount, err := l.svcCtx.SocialNetworkRepository.GetFollowerCount(l.ctx, in.GetUid())
|
||||
if err != nil {
|
||||
// 錯誤代碼 05-021-32
|
||||
e := domain.CommentErrorL(
|
||||
domain.GetFollowerCountErrorCode,
|
||||
logx.WithContext(l.ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "req", Value: in},
|
||||
{Key: "func", Value: "SocialNetworkRepository.GetFollowerCount"},
|
||||
{Key: "err", Value: err},
|
||||
},
|
||||
"failed to count follower").Wrap(err)
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return &tweeting.FollowCountResp{
|
||||
Uid: in.GetUid(),
|
||||
Total: followerCount,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package socialnetworkservicelogic
|
||||
|
||||
import (
|
||||
"app-cloudep-tweeting-service/internal/domain"
|
||||
"app-cloudep-tweeting-service/internal/domain/repository"
|
||||
ers "code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
|
||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||
"app-cloudep-tweeting-service/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetFollowerLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewGetFollowerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFollowerLogic {
|
||||
return &GetFollowerLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
type getFollowReq struct {
|
||||
UID string `validate:"required"`
|
||||
PageSize int64 `validate:"required"`
|
||||
PageIndex int64 `validate:"required"`
|
||||
}
|
||||
|
||||
// GetFollower 取得跟隨者名單
|
||||
func (l *GetFollowerLogic) GetFollower(in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||
// 驗證資料
|
||||
if err := l.svcCtx.Validate.ValidateAll(&getFollowReq{
|
||||
UID: in.Uid,
|
||||
PageSize: in.PageSize,
|
||||
PageIndex: in.PageIndex,
|
||||
}); err != nil {
|
||||
// 錯誤代碼 05-011-00
|
||||
return nil, ers.InvalidFormat(err.Error())
|
||||
}
|
||||
|
||||
follower, err := l.svcCtx.SocialNetworkRepository.GetFollower(l.ctx, repository.FollowReq{
|
||||
UID: in.GetUid(),
|
||||
PageIndex: in.GetPageIndex(),
|
||||
PageSize: in.GetPageSize(),
|
||||
})
|
||||
if err != nil {
|
||||
// 錯誤代碼 05-021-31
|
||||
e := domain.CommentErrorL(
|
||||
domain.GetFollowerErrorCode,
|
||||
logx.WithContext(l.ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "req", Value: in},
|
||||
{Key: "func", Value: "SocialNetworkRepository.GetFollower"},
|
||||
{Key: "err", Value: err},
|
||||
},
|
||||
"failed to get relation: ", in.GetUid()).Wrap(err)
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return &tweeting.FollowResp{
|
||||
Uid: follower.UIDs,
|
||||
Page: &tweeting.Pager{
|
||||
Total: follower.Total,
|
||||
Index: in.GetPageIndex(),
|
||||
Size: in.GetPageSize(),
|
||||
},
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package socialnetworkservicelogic
|
||||
|
||||
import (
|
||||
"app-cloudep-tweeting-service/internal/domain"
|
||||
ers "code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
|
||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||
"app-cloudep-tweeting-service/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type MarkFollowRelationLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewMarkFollowRelationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MarkFollowRelationLogic {
|
||||
return &MarkFollowRelationLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
type doFollowReq struct {
|
||||
FollowerUID string `json:"follower_uid" validate:"required"` // 追隨者,跟隨你的人(別人關注你)
|
||||
FolloweeUID string `json:"followee_uid" validate:"required"` // 追蹤者,你跟隨的人(你關注別)
|
||||
}
|
||||
|
||||
// MarkFollowRelation 關注
|
||||
func (l *MarkFollowRelationLogic) MarkFollowRelation(in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||
// 驗證資料
|
||||
if err := l.svcCtx.Validate.ValidateAll(&doFollowReq{
|
||||
FollowerUID: in.GetFollowerUid(),
|
||||
FolloweeUID: in.GetFolloweeUid(),
|
||||
}); err != nil {
|
||||
// 錯誤代碼 05-011-00
|
||||
return nil, ers.InvalidFormat(err.Error())
|
||||
}
|
||||
|
||||
// 這裡要幫建立關係, follower 追蹤 -> followee
|
||||
err := l.svcCtx.SocialNetworkRepository.MarkFollowerRelation(l.ctx, in.GetFollowerUid(), in.GetFolloweeUid())
|
||||
if err != nil {
|
||||
// 錯誤代碼 05-021-30
|
||||
e := domain.CommentErrorL(
|
||||
domain.MarkRelationErrorCode,
|
||||
logx.WithContext(l.ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "req", Value: in},
|
||||
{Key: "func", Value: "SocialNetworkRepository.MarkFollowerRelationBetweenUsers"},
|
||||
{Key: "err", Value: err},
|
||||
},
|
||||
"failed to mark relation form -> to", in.GetFollowerUid(), in.GetFolloweeUid()).Wrap(err)
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return &tweeting.OKResp{}, nil
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package socialnetworkservicelogic
|
||||
|
||||
import (
|
||||
"app-cloudep-tweeting-service/internal/domain"
|
||||
ers "code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
|
||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||
"app-cloudep-tweeting-service/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type RemoveFollowRelationLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewRemoveFollowRelationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RemoveFollowRelationLogic {
|
||||
return &RemoveFollowRelationLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveFollowRelation 取消關注
|
||||
func (l *RemoveFollowRelationLogic) RemoveFollowRelation(in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||
// 驗證資料
|
||||
if err := l.svcCtx.Validate.ValidateAll(&doFollowReq{
|
||||
FollowerUID: in.GetFollowerUid(),
|
||||
FolloweeUID: in.GetFolloweeUid(),
|
||||
}); err != nil {
|
||||
// 錯誤代碼 05-011-00
|
||||
return nil, ers.InvalidFormat(err.Error())
|
||||
}
|
||||
|
||||
// 這裡要幫刪除關係, follower 追蹤 -> followee
|
||||
err := l.svcCtx.SocialNetworkRepository.RemoveFollowerRelation(l.ctx, in.GetFollowerUid(), in.GetFolloweeUid())
|
||||
if err != nil {
|
||||
// 錯誤代碼 05-021-35
|
||||
e := domain.CommentErrorL(
|
||||
domain.RemoveRelationErrorCode,
|
||||
logx.WithContext(l.ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "req", Value: in},
|
||||
{Key: "func", Value: "SocialNetworkRepository.RemoveFollowerRelation"},
|
||||
{Key: "err", Value: err},
|
||||
},
|
||||
"failed to remove relation form -> to", in.GetFollowerUid(), in.GetFolloweeUid()).Wrap(err)
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return &tweeting.OKResp{}, nil
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"app-cloudep-tweeting-service/internal/domain/repository"
|
||||
client4J "app-cloudep-tweeting-service/internal/lib/neo4j"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
|
||||
)
|
||||
|
||||
|
@ -25,7 +26,7 @@ func MustSocialNetworkRepository(param SocialNetworkParam) repository.SocialNetw
|
|||
}
|
||||
}
|
||||
|
||||
func (s SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string) error {
|
||||
func (s *SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string) error {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -36,18 +37,356 @@ func (s SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string)
|
|||
"uid": uid,
|
||||
}
|
||||
|
||||
_, err = session.NewSession(ctx, neo4j.SessionConfig{
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeWrite,
|
||||
}).Run(ctx, "CREATE (n:User {uid: $uid}) RETURN n", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// // 處理結果
|
||||
// if run.Next(ctx) {
|
||||
// node := run.Record().AsMap()
|
||||
// fmt.Printf("Created Node: %v\n", node)
|
||||
// }
|
||||
// 處理結果
|
||||
if run.Next(ctx) {
|
||||
_ = run.Record().AsMap()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SocialNetworkRepository) MarkFollowerRelation(ctx context.Context, fromUID, toUID string) error {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"fromUID": fromUID,
|
||||
"toUID": toUID,
|
||||
}
|
||||
|
||||
// 這是有向的關係 form -> to
|
||||
query := `
|
||||
MERGE (from:User {uid: $fromUID})
|
||||
MERGE (to:User {uid: $toUID})
|
||||
MERGE (from)-[:FRIENDS_WITH]->(to)
|
||||
RETURN from, to
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeWrite,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 處理結果
|
||||
if run.Next(ctx) {
|
||||
_ = run.Record().AsMap()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SocialNetworkRepository) GetFollower(ctx context.Context, req repository.FollowReq) (repository.FollowResp, error) {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return repository.FollowResp{}, err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"uid": req.UID,
|
||||
"skip": (req.PageIndex - 1) * req.PageSize,
|
||||
"limit": req.PageSize,
|
||||
}
|
||||
|
||||
query := `
|
||||
MATCH (follower:User)-[:FRIENDS_WITH]->(user:User {uid: $uid})
|
||||
RETURN follower.uid AS uid
|
||||
SKIP $skip LIMIT $limit
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeRead,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return repository.FollowResp{}, err
|
||||
}
|
||||
|
||||
var uids []string
|
||||
for run.Next(ctx) {
|
||||
record := run.Record()
|
||||
if uid, ok := record.Get("uid"); ok {
|
||||
uids = append(uids, uid.(string))
|
||||
}
|
||||
}
|
||||
|
||||
total, err := s.GetFollowerCount(ctx, req.UID)
|
||||
if err != nil {
|
||||
return repository.FollowResp{}, err
|
||||
}
|
||||
|
||||
return repository.FollowResp{
|
||||
UIDs: uids,
|
||||
Total: total,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SocialNetworkRepository) GetFollowee(ctx context.Context, req repository.FollowReq) (repository.FollowResp, error) {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return repository.FollowResp{}, err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"uid": req.UID,
|
||||
"skip": (req.PageIndex - 1) * req.PageSize,
|
||||
"limit": req.PageSize,
|
||||
}
|
||||
|
||||
query := `
|
||||
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH]->(followee:User)
|
||||
RETURN followee.uid AS uid
|
||||
SKIP $skip LIMIT $limit
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeRead,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return repository.FollowResp{}, err
|
||||
}
|
||||
|
||||
var uids []string
|
||||
for run.Next(ctx) {
|
||||
record := run.Record()
|
||||
if uid, ok := record.Get("uid"); ok {
|
||||
uids = append(uids, uid.(string))
|
||||
}
|
||||
}
|
||||
|
||||
total, err := s.GetFolloweeCount(ctx, req.UID)
|
||||
if err != nil {
|
||||
return repository.FollowResp{}, err
|
||||
}
|
||||
|
||||
return repository.FollowResp{
|
||||
UIDs: uids,
|
||||
Total: total,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *SocialNetworkRepository) GetFollowerCount(ctx context.Context, uid string) (int64, error) {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"uid": uid,
|
||||
}
|
||||
|
||||
query := `
|
||||
MATCH (:User)-[:FRIENDS_WITH]->(user:User {uid: $uid})
|
||||
RETURN count(*) AS followerCount
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeRead,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var count int64
|
||||
if run.Next(ctx) {
|
||||
record := run.Record()
|
||||
if followerCount, ok := record.Get("followerCount"); ok {
|
||||
count = followerCount.(int64)
|
||||
}
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SocialNetworkRepository) GetFolloweeCount(ctx context.Context, uid string) (int64, error) {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"uid": uid,
|
||||
}
|
||||
|
||||
query := `
|
||||
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH]->(:User)
|
||||
RETURN count(*) AS followeeCount
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeRead,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var count int64
|
||||
if run.Next(ctx) {
|
||||
record := run.Record()
|
||||
if followeeCount, ok := record.Get("followeeCount"); ok {
|
||||
count = followeeCount.(int64)
|
||||
}
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SocialNetworkRepository) RemoveFollowerRelation(ctx context.Context, fromUID, toUID string) error {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"fromUID": fromUID,
|
||||
"toUID": toUID,
|
||||
}
|
||||
|
||||
query := `
|
||||
MATCH (from:User {uid: $fromUID})-[r:FRIENDS_WITH]->(to:User {uid: $toUID})
|
||||
DELETE r
|
||||
`
|
||||
|
||||
_, err = session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeWrite,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove follower relation: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDegreeBetweenUsers 取得這兩個點之間的度數 (最短路徑長度)
|
||||
func (s *SocialNetworkRepository) GetDegreeBetweenUsers(ctx context.Context, uid1, uid2 string) (int64, error) {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"uid1": uid1,
|
||||
"uid2": uid2,
|
||||
}
|
||||
|
||||
query := `
|
||||
MATCH (user1:User {uid: $uid1}), (user2:User {uid: $uid2})
|
||||
MATCH p = shortestPath((user1)-[*]-(user2))
|
||||
RETURN length(p) AS degree
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeRead,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get degree between users: %w", err)
|
||||
}
|
||||
|
||||
var degree int64
|
||||
if run.Next(ctx) {
|
||||
record := run.Record()
|
||||
if deg, ok := record.Get("degree"); ok {
|
||||
degree = deg.(int64)
|
||||
}
|
||||
}
|
||||
|
||||
return degree, nil
|
||||
}
|
||||
|
||||
// GetUIDsWithinNDegrees 取得某個節點在 n 度內關係所有 UID
|
||||
func (s *SocialNetworkRepository) GetUIDsWithinNDegrees(ctx context.Context, uid string, degrees, pageSize, pageIndex int64) ([]string, int64, error) {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"uid": uid,
|
||||
"degrees": degrees,
|
||||
"skip": (pageIndex - 1) * pageSize,
|
||||
"limit": pageSize,
|
||||
}
|
||||
|
||||
// 查詢結果帶分頁
|
||||
query := `
|
||||
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH*1..$degrees]-(related:User)
|
||||
WITH DISTINCT related.uid AS uid
|
||||
SKIP $skip LIMIT $limit
|
||||
RETURN uid
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeRead,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to get uids within %d degrees of user: %w", degrees, err)
|
||||
}
|
||||
|
||||
var uids []string
|
||||
for run.Next(ctx) {
|
||||
record := run.Record()
|
||||
if uid, ok := record.Get("uid"); ok {
|
||||
uids = append(uids, uid.(string))
|
||||
}
|
||||
}
|
||||
|
||||
// 計算總數
|
||||
totalCount, err := s.getTotalUIDsWithinNDegrees(ctx, uid, degrees)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return uids, totalCount, nil
|
||||
}
|
||||
|
||||
func (s *SocialNetworkRepository) getTotalUIDsWithinNDegrees(ctx context.Context, uid string, degrees int64) (int64, error) {
|
||||
session, err := s.neo4jClient.Conn()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer session.Close(ctx)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"uid": uid,
|
||||
"degrees": degrees,
|
||||
}
|
||||
|
||||
query := `
|
||||
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH*1..$degrees]-(related:User)
|
||||
RETURN count(DISTINCT related.uid) AS totalCount
|
||||
`
|
||||
|
||||
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||
AccessMode: neo4j.AccessModeRead,
|
||||
}).Run(ctx, query, params)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get total uids within %d degrees of user: %w", degrees, err)
|
||||
}
|
||||
|
||||
var totalCount int64
|
||||
if run.Next(ctx) {
|
||||
record := run.Record()
|
||||
if count, ok := record.Get("totalCount"); ok {
|
||||
totalCount = count.(int64)
|
||||
}
|
||||
}
|
||||
|
||||
return totalCount, nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,38 @@ func NewSocialNetworkServiceServer(svcCtx *svc.ServiceContext) *SocialNetworkSer
|
|||
}
|
||||
}
|
||||
|
||||
func (s *SocialNetworkServiceServer) AddUserToNetwork(ctx context.Context, in *tweeting.AddUserToNetworkReq) (*tweeting.OKResp, error) {
|
||||
l := socialnetworkservicelogic.NewAddUserToNetworkLogic(ctx, s.svcCtx)
|
||||
return l.AddUserToNetwork(in)
|
||||
// MarkFollowRelation 關注
|
||||
func (s *SocialNetworkServiceServer) MarkFollowRelation(ctx context.Context, in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||
l := socialnetworkservicelogic.NewMarkFollowRelationLogic(ctx, s.svcCtx)
|
||||
return l.MarkFollowRelation(in)
|
||||
}
|
||||
|
||||
// RemoveFollowRelation 取消關注
|
||||
func (s *SocialNetworkServiceServer) RemoveFollowRelation(ctx context.Context, in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||
l := socialnetworkservicelogic.NewRemoveFollowRelationLogic(ctx, s.svcCtx)
|
||||
return l.RemoveFollowRelation(in)
|
||||
}
|
||||
|
||||
// GetFollower 取得跟隨者名單
|
||||
func (s *SocialNetworkServiceServer) GetFollower(ctx context.Context, in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||
l := socialnetworkservicelogic.NewGetFollowerLogic(ctx, s.svcCtx)
|
||||
return l.GetFollower(in)
|
||||
}
|
||||
|
||||
// GetFollowee 取得我跟隨的名單
|
||||
func (s *SocialNetworkServiceServer) GetFollowee(ctx context.Context, in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||
l := socialnetworkservicelogic.NewGetFolloweeLogic(ctx, s.svcCtx)
|
||||
return l.GetFollowee(in)
|
||||
}
|
||||
|
||||
// GetFollowerCount 取得跟隨者數量
|
||||
func (s *SocialNetworkServiceServer) GetFollowerCount(ctx context.Context, in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||
l := socialnetworkservicelogic.NewGetFollowerCountLogic(ctx, s.svcCtx)
|
||||
return l.GetFollowerCount(in)
|
||||
}
|
||||
|
||||
// GetFolloweeCount 取得我跟隨的數量
|
||||
func (s *SocialNetworkServiceServer) GetFolloweeCount(ctx context.Context, in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||
l := socialnetworkservicelogic.NewGetFolloweeCountLogic(ctx, s.svcCtx)
|
||||
return l.GetFolloweeCount(in)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue