feature/fanout #3
			
				
			
		
		
		
	|  | @ -2,4 +2,4 @@ | ||||||
| CREATE DATABASE relation; | CREATE DATABASE relation; | ||||||
| 
 | 
 | ||||||
| // 創建 User 節點 UID 是唯一鍵 | // 創建 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; |   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 | 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 | 	SetNoMoreDataErrorCode | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | const ( | ||||||
|  | 	MarkRelationErrorCode ErrorCode = iota + 30 | ||||||
|  | 	GetFollowerErrorCode | ||||||
|  | 	GetFollowerCountErrorCode | ||||||
|  | 	GetFolloweeErrorCode | ||||||
|  | 	GetFolloweeCountErrorCode | ||||||
|  | 	RemoveRelationErrorCode | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| func CommentError(ec ErrorCode, s ...string) *ers.LibError { | func CommentError(ec ErrorCode, s ...string) *ers.LibError { | ||||||
| 	return ers.NewError(code.CloudEPTweeting, code.DBError, | 	return ers.NewError(code.CloudEPTweeting, code.DBError, | ||||||
| 		ec.ToUint32(), | 		ec.ToUint32(), | ||||||
|  |  | ||||||
|  | @ -4,4 +4,23 @@ import "context" | ||||||
| 
 | 
 | ||||||
| type SocialNetworkRepository interface { | type SocialNetworkRepository interface { | ||||||
| 	CreateUserNode(ctx context.Context, uid string) error | 	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" | 	"app-cloudep-tweeting-service/internal/domain/repository" | ||||||
| 	client4J "app-cloudep-tweeting-service/internal/lib/neo4j" | 	client4J "app-cloudep-tweeting-service/internal/lib/neo4j" | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"fmt" | ||||||
| 	"github.com/neo4j/neo4j-go-driver/v5/neo4j" | 	"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() | 	session, err := s.neo4jClient.Conn() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
|  | @ -36,18 +37,356 @@ func (s SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string) | ||||||
| 		"uid": uid, | 		"uid": uid, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, err = session.NewSession(ctx, neo4j.SessionConfig{ | 	run, err := session.NewSession(ctx, neo4j.SessionConfig{ | ||||||
| 		AccessMode: neo4j.AccessModeWrite, | 		AccessMode: neo4j.AccessModeWrite, | ||||||
| 	}).Run(ctx, "CREATE (n:User {uid: $uid}) RETURN n", params) | 	}).Run(ctx, "CREATE (n:User {uid: $uid}) RETURN n", params) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// // 處理結果
 | 	// 處理結果
 | ||||||
| 	// if run.Next(ctx) {
 | 	if run.Next(ctx) { | ||||||
| 	// 	node := run.Record().AsMap()
 | 		_ = run.Record().AsMap() | ||||||
| 	// 	fmt.Printf("Created Node: %v\n", node)
 | 	} | ||||||
| 	// }
 |  | ||||||
| 
 | 
 | ||||||
| 	return nil | 	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) { | // MarkFollowRelation 關注
 | ||||||
| 	l := socialnetworkservicelogic.NewAddUserToNetworkLogic(ctx, s.svcCtx) | func (s *SocialNetworkServiceServer) MarkFollowRelation(ctx context.Context, in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) { | ||||||
| 	return l.AddUserToNetwork(in) | 	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