diff --git a/service/post/rpc/internal/logic/insert_logic.go b/service/post/rpc/internal/logic/insert_logic.go index 48ede10..caef7f1 100644 --- a/service/post/rpc/internal/logic/insert_logic.go +++ b/service/post/rpc/internal/logic/insert_logic.go @@ -2,8 +2,15 @@ package logic import ( "context" + "database/sql" + "errors" + "github.com/google/uuid" + "github.com/linehk/go-microservices-blogger/errcode" + commentmodel "github.com/linehk/go-microservices-blogger/service/comment/rpc/model" "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 +31,154 @@ func NewInsertLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InsertLogi } func (l *InsertLogic) Insert(in *post.InsertReq) (*post.Post, error) { - // todo: add your logic here and delete this line + postUuid := uuid.NewString() + postReq := in.GetPost() + postModel := &model.Post{ + Uuid: postUuid, + BlogUuid: sql.NullString{String: in.GetBlogId(), Valid: true}, + Published: sql.NullTime{Time: postReq.GetPublished().AsTime(), Valid: true}, + Updated: sql.NullTime{Time: postReq.GetUpdated().AsTime(), Valid: true}, + Url: postReq.GetUrl(), + SelfLink: sql.NullString{String: postReq.GetSelfLink(), Valid: true}, + Title: sql.NullString{String: postReq.GetTitle(), Valid: true}, + TitleLink: sql.NullString{String: postReq.GetTitleLink(), Valid: true}, + Content: sql.NullString{String: postReq.GetContent(), Valid: true}, + CustomMetaData: sql.NullString{String: postReq.GetCustomMetaData(), Valid: true}, + Status: sql.NullString{String: postReq.GetStatus(), Valid: true}, + } + _, err := l.svcCtx.PostModel.Insert(l.ctx, postModel) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + + for _, imageReq := range postReq.GetImages() { + imageUuid := uuid.NewString() + imageModel := &model.Image{ + Uuid: imageUuid, + PostUuid: sql.NullString{String: postUuid, Valid: true}, + AuthorUuid: "", + Url: sql.NullString{String: imageReq.Url, Valid: true}, + } + _, err := l.svcCtx.ImageModel.Insert(l.ctx, imageModel) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + } + + authorUuid := uuid.NewString() + authorModel := &model.Author{ + Uuid: authorUuid, + PostUuid: postUuid, + PageUuid: "", + CommentUuid: "", + DisplayName: sql.NullString{String: postReq.GetAuthor().GetDisplayName(), Valid: true}, + Url: sql.NullString{String: postReq.GetAuthor().GetUrl(), Valid: true}, + } + _, err = l.svcCtx.AuthorModel.Insert(l.ctx, authorModel) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + + authorImageUuid := uuid.NewString() + authorImage := &model.Image{ + Uuid: authorImageUuid, + PostUuid: sql.NullString{String: "", Valid: true}, + AuthorUuid: authorUuid, + Url: sql.NullString{String: postReq.GetAuthor().GetImage().GetUrl(), Valid: true}, + } + _, err = l.svcCtx.ImageModel.Insert(l.ctx, authorImage) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } - return &post.Post{}, nil + for _, commentReq := range postReq.GetReplies().GetItems() { + commentUuid := uuid.NewString() + commentModel := &commentmodel.Comment{ + Uuid: commentUuid, + BlogUuid: sql.NullString{String: in.GetBlogId(), Valid: true}, + PostUuid: sql.NullString{String: postUuid, Valid: true}, + Status: sql.NullString{String: commentReq.GetStatus(), Valid: true}, + Published: sql.NullTime{Time: commentReq.GetPublished().AsTime(), Valid: true}, + Updated: sql.NullTime{Time: commentReq.GetUpdated().AsTime(), Valid: true}, + Selflink: sql.NullString{String: commentReq.GetSelfLink(), Valid: true}, + Content: sql.NullString{String: commentReq.GetContent(), Valid: true}, + } + _, err := l.svcCtx.CommentModel.Insert(l.ctx, commentModel) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + + commentAuthorUuid := uuid.NewString() + commentAuthor := &model.Author{ + Uuid: commentAuthorUuid, + PostUuid: "", + PageUuid: "", + CommentUuid: commentUuid, + DisplayName: sql.NullString{String: commentReq.GetAuthor().GetDisplayName(), Valid: true}, + Url: sql.NullString{String: commentReq.GetAuthor().GetUrl(), Valid: true}, + } + _, err = l.svcCtx.AuthorModel.Insert(l.ctx, commentAuthor) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + + commentAuthorImageUuid := uuid.NewString() + commentAuthorImage := &model.Image{ + Uuid: commentAuthorImageUuid, + PostUuid: sql.NullString{String: "", Valid: true}, + AuthorUuid: commentAuthorUuid, + Url: sql.NullString{String: commentReq.GetAuthor().GetImage().GetUrl(), Valid: true}, + } + _, err = l.svcCtx.ImageModel.Insert(l.ctx, commentAuthorImage) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + } + + for _, labelReq := range postReq.GetLabels() { + labelUuid := uuid.NewString() + labelModel := &model.Label{ + Uuid: labelUuid, + PostUuid: sql.NullString{String: postUuid, Valid: true}, + LabelValue: sql.NullString{String: labelReq, Valid: true}, + } + _, err = l.svcCtx.LabelModel.Insert(l.ctx, labelModel) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + } + + locationUuid := uuid.NewString() + locationModel := &model.Location{ + Uuid: locationUuid, + PostUuid: postUuid, + Name: sql.NullString{String: postReq.GetLocation().GetName(), Valid: true}, + Lat: sql.NullFloat64{Float64: float64(postReq.GetLocation().GetLat()), Valid: true}, + Lng: sql.NullFloat64{Float64: float64(postReq.GetLocation().GetLng()), Valid: true}, + Span: sql.NullString{String: postReq.GetLocation().GetSpan(), Valid: true}, + } + _, err = l.svcCtx.LocationModel.Insert(l.ctx, locationModel) + if err != nil { + l.Error(errcode.Msg(errcode.Database)) + return nil, errcode.Wrap(errcode.Database) + } + + newPostModel, err := l.svcCtx.PostModel.FindOneByBlogUuidAndPostUuid(l.ctx, in.GetBlogId(), postUuid) + 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) + } + return Get(l.ctx, l.svcCtx, l.Logger, newPostModel) } diff --git a/service/post/rpc/internal/svc/service_context.go b/service/post/rpc/internal/svc/service_context.go index dda9a00..9a2dd98 100644 --- a/service/post/rpc/internal/svc/service_context.go +++ b/service/post/rpc/internal/svc/service_context.go @@ -2,6 +2,7 @@ package svc import ( "github.com/linehk/go-microservices-blogger/service/comment/rpc/commentservice" + commentmodel "github.com/linehk/go-microservices-blogger/service/comment/rpc/model" "github.com/linehk/go-microservices-blogger/service/post/rpc/internal/config" "github.com/linehk/go-microservices-blogger/service/post/rpc/model" "github.com/zeromicro/go-zero/core/stores/postgres" @@ -19,6 +20,7 @@ type ServiceContext struct { PostModel model.PostModel PostUserInfoModel model.PostUserInfoModel CommentService commentservice.CommentService + CommentModel commentmodel.CommentModel } func NewServiceContext(c config.Config) *ServiceContext { @@ -36,5 +38,6 @@ func NewServiceContext(c config.Config) *ServiceContext { PostModel: model.NewPostModel(conn, c.Cache), PostUserInfoModel: model.NewPostUserInfoModel(conn, c.Cache), CommentService: commentservice.NewCommentService(zrpc.MustNewClient(c.CommentConf)), + CommentModel: commentmodel.NewCommentModel(conn, c.Cache), } } diff --git a/service/post/rpc/internal/test/insert_logic_test.go b/service/post/rpc/internal/test/insert_logic_test.go new file mode 100644 index 0000000..ce4e5bb --- /dev/null +++ b/service/post/rpc/internal/test/insert_logic_test.go @@ -0,0 +1,288 @@ +package test + +import ( + "context" + "testing" + "time" + + "github.com/google/uuid" + "github.com/linehk/go-microservices-blogger/errcode" + "github.com/linehk/go-microservices-blogger/service/comment/rpc/commentservice" + commentmodel "github.com/linehk/go-microservices-blogger/service/comment/rpc/model" + "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" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestInsert(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) + commentRepo := commentmodel.NewMockCommentModel(ctrl) + logicService := logic.NewInsertLogic(ctx, &svc.ServiceContext{ + AuthorModel: authorRepo, + ImageModel: imageRepo, + LabelModel: labelRepo, + LocationModel: locationRepo, + PostModel: postRepo, + CommentService: commentService, + CommentModel: commentRepo, + }) + defer ctrl.Finish() + + blogId := uuid.NewString() + published := time.Now() + updated := time.Now() + postUrl := "Url" + postSelfLink := "postSelfLink" + postTitle := "Title" + postTitleLink := "postTitleLink" + postContent := "Content" + customMetaData := "CustomMetaData" + postStatus := "Status" + + imageUrl1 := "imageUrl1" + imageUrl2 := "imageUrl2" + + displayName := "DisplayName" + authorUrl := "authorUrl" + + authorImageUrl := "authorImageUrl" + + commentStatus1 := "Status1" + commentStatus2 := "Status2" + commentSelfLink1 := "commentSelfLink1" + commentSelfLink2 := "commentSelfLink2" + commentContent1 := "commentContent1" + commentContent2 := "commentContent2" + commentAuthorDisplayName := "commentAuthorDisplayName" + commentAuthorUrl := "commentAuthorUrl" + commentAuthorImageUrl := "commentAuthorImageUrl" + + labelValue1 := "labelValue1" + labelValue2 := "labelValue2" + + locationName := "locationName" + locationLat := 1.1 + locationLng := 2.2 + locationSpan := "locationSpan" + + insertReq := &post.InsertReq{ + BlogId: blogId, + IsDraft: false, + Post: &post.Post{ + Published: timestamppb.New(published), + Updated: timestamppb.New(updated), + Url: postUrl, + SelfLink: postSelfLink, + Title: postTitle, + TitleLink: postTitleLink, + Content: postContent, + Images: []*post.Image{{Url: imageUrl1}, {Url: imageUrl2}}, + CustomMetaData: customMetaData, + Author: &post.Author{ + DisplayName: displayName, + Url: authorUrl, + Image: &post.Image{Url: authorImageUrl}, + }, + Replies: &post.Reply{ + Items: []*post.Comment{{ + Status: commentStatus1, + Published: timestamppb.New(published), + Updated: timestamppb.New(updated), + SelfLink: commentSelfLink1, + Content: commentContent1, + Author: &post.Author{ + DisplayName: commentAuthorDisplayName, + Url: commentAuthorUrl, + Image: &post.Image{Url: commentAuthorImageUrl}, + }, + }, { + Status: commentStatus2, + Published: timestamppb.New(published), + Updated: timestamppb.New(updated), + SelfLink: commentSelfLink2, + Content: commentContent2, + Author: &post.Author{ + DisplayName: commentAuthorDisplayName, + Url: commentAuthorUrl, + Image: &post.Image{Url: commentAuthorImageUrl}, + }, + }}, + }, + Labels: []string{labelValue1, labelValue2}, + Location: &post.Location{ + Name: locationName, + Lat: float32(locationLat), + Lng: float32(locationLng), + Span: locationSpan, + }, + Status: postStatus, + }, + } + + // PostModel Database + expectedErr := errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr := logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // ImageModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // AuthorModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // ImageModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // CommentModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // AuthorModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // ImageModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // LabelModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + labelRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // LocationModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + labelRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + labelRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + locationRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // PostNotExist + expectedErr = errcode.Wrap(errcode.PostNotExist) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + labelRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + labelRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + locationRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + postRepo.EXPECT().FindOneByBlogUuidAndPostUuid(ctx, blogId, gomock.Any()).Return(nil, model.ErrNotFound) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) + + // PostModel Database + expectedErr = errcode.Wrap(errcode.Database) + postRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + commentRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + authorRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + imageRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + labelRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + labelRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + locationRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil, nil) + postRepo.EXPECT().FindOneByBlogUuidAndPostUuid(ctx, blogId, gomock.Any()).Return(nil, expectedErr) + actual, actualErr = logicService.Insert(insertReq) + assert.Nil(t, actual) + assert.Equal(t, expectedErr, actualErr) +}