diff --git a/service/post/rpc/internal/logic/search_logic.go b/service/post/rpc/internal/logic/search_logic.go index 327413d..529955f 100644 --- a/service/post/rpc/internal/logic/search_logic.go +++ b/service/post/rpc/internal/logic/search_logic.go @@ -2,8 +2,11 @@ package logic import ( "context" + "errors" + "github.com/linehk/go-microservices-blogger/errcode" "github.com/linehk/go-microservices-blogger/service/post/rpc/internal/svc" + "github.com/linehk/go-microservices-blogger/service/post/rpc/model" "github.com/linehk/go-microservices-blogger/service/post/rpc/post" "github.com/zeromicro/go-zero/core/logx" @@ -24,7 +27,26 @@ func NewSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SearchLogi } func (l *SearchLogic) Search(in *post.SearchReq) (*post.SearchResp, error) { - // todo: add your logic here and delete this line + postModelList, err := l.svcCtx.PostModel.SearchByTitle(l.ctx, in.GetBlogId(), in.GetQ()) + if errors.Is(err, model.ErrNotFound) { + l.Error(errcode.Msg(errcode.PostNotExist)) + return nil, errcode.Wrap(errcode.PostNotExist) + } + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + + var searchResp post.SearchResp + searchResp.Kind = "blogger#postList" + searchResp.NextPageToken = "" + for _, postModel := range postModelList { + postResp, err := Get(l.ctx, l.svcCtx, l.Logger, postModel) + if err != nil { + return nil, err + } + searchResp.Items = append(searchResp.Items, postResp) + } - return &post.SearchResp{}, nil + return &searchResp, nil } diff --git a/service/post/rpc/internal/test/search_logic_test.go b/service/post/rpc/internal/test/search_logic_test.go new file mode 100644 index 0000000..18e8b85 --- /dev/null +++ b/service/post/rpc/internal/test/search_logic_test.go @@ -0,0 +1,57 @@ +package test + +import ( + "context" + "testing" + + "github.com/google/uuid" + "github.com/linehk/go-microservices-blogger/errcode" + "github.com/linehk/go-microservices-blogger/service/comment/rpc/commentservice" + "github.com/linehk/go-microservices-blogger/service/post/rpc/internal/logic" + "github.com/linehk/go-microservices-blogger/service/post/rpc/internal/svc" + "github.com/linehk/go-microservices-blogger/service/post/rpc/model" + "github.com/linehk/go-microservices-blogger/service/post/rpc/post" + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" +) + +func TestSearch(t *testing.T) { + ctrl := gomock.NewController(t) + ctx := context.Background() + postRepo := model.NewMockPostModel(ctrl) + imageRepo := model.NewMockImageModel(ctrl) + authorRepo := model.NewMockAuthorModel(ctrl) + commentService := commentservice.NewMockCommentService(ctrl) + labelRepo := model.NewMockLabelModel(ctrl) + locationRepo := model.NewMockLocationModel(ctrl) + logicService := logic.NewSearchLogic(ctx, &svc.ServiceContext{ + AuthorModel: authorRepo, + ImageModel: imageRepo, + LabelModel: labelRepo, + LocationModel: locationRepo, + PostModel: postRepo, + CommentService: commentService, + }) + defer ctrl.Finish() + + blogId := uuid.NewString() + title := "title" + searchReq := &post.SearchReq{ + BlogId: blogId, + Q: title, + } + + // PostNotExist + expectedErr := errcode.Wrap(errcode.PostNotExist) + postRepo.EXPECT().SearchByTitle(ctx, blogId, title).Return(nil, model.ErrNotFound) + actual, actualErr := logicService.Search(searchReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().SearchByTitle(ctx, blogId, title).Return(nil, expectedErr) + actual, actualErr = logicService.Search(searchReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) +} diff --git a/service/post/rpc/model/mock_post_model.go b/service/post/rpc/model/mock_post_model.go index ef084b8..76e6acd 100644 --- a/service/post/rpc/model/mock_post_model.go +++ b/service/post/rpc/model/mock_post_model.go @@ -144,6 +144,21 @@ func (mr *MockPostModelMockRecorder) ListByBlogUuid(arg0, arg1 any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListByBlogUuid", reflect.TypeOf((*MockPostModel)(nil).ListByBlogUuid), arg0, arg1) } +// SearchByTitle mocks base method. +func (m *MockPostModel) SearchByTitle(arg0 context.Context, arg1, arg2 string) ([]*Post, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchByTitle", arg0, arg1, arg2) + ret0, _ := ret[0].([]*Post) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchByTitle indicates an expected call of SearchByTitle. +func (mr *MockPostModelMockRecorder) SearchByTitle(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchByTitle", reflect.TypeOf((*MockPostModel)(nil).SearchByTitle), arg0, arg1, arg2) +} + // Update mocks base method. func (m *MockPostModel) Update(arg0 context.Context, arg1 *Post) error { m.ctrl.T.Helper() diff --git a/service/post/rpc/model/post_model.go b/service/post/rpc/model/post_model.go index c8be8bc..e6b64e6 100755 --- a/service/post/rpc/model/post_model.go +++ b/service/post/rpc/model/post_model.go @@ -19,6 +19,7 @@ type ( postModel FindOneByBlogUuidAndPostUuid(ctx context.Context, blogUuid, postUuid string) (*Post, error) ListByBlogUuid(ctx context.Context, blogUuid string) ([]*Post, error) + SearchByTitle(ctx context.Context, blogUuid, title string) ([]*Post, error) } customPostModel struct { @@ -36,6 +37,7 @@ func NewPostModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) Po var ( cachePublicPostBlogUuidAndPostUuid = "cache:public:post:blogUuid:%s:postUuid:%s" cachePublicPostBlogUuidPrefix = "cache:public:post:blogUuid:" + cachePublicPostBlogUuidAndTitle = "cache:public:post:blogUuid:%s:title:%s" ) func (c *customPostModel) FindOneByBlogUuidAndPostUuid(ctx context.Context, blogUuid, postUuid string) (*Post, error) { @@ -77,3 +79,23 @@ func (c *customPostModel) ListByBlogUuid(ctx context.Context, blogUuid string) ( return nil, err } } + +func (c *customPostModel) SearchByTitle(ctx context.Context, blogUuid, title string) ([]*Post, error) { + publicPostBlogUuidAndTitleKey := fmt.Sprintf(cachePublicPostBlogUuidAndTitle, blogUuid, title) + var resp []*Post + err := c.QueryRowIndexCtx(ctx, &resp, publicPostBlogUuidAndTitleKey, c.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) { + query := fmt.Sprintf("select %s from %s where blog_uuid = $1 and title like $2", postRows, c.table) + if err := conn.QueryRowCtx(ctx, &resp, query, blogUuid, "'"+title+"%'"); err != nil { + return nil, err + } + return resp[0].Id, nil + }, c.queryPrimary) + switch err { + case nil: + return resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +}