diff --git a/biz/adaptor/server.go b/biz/adaptor/server.go index 0662b08..162e9e4 100644 --- a/biz/adaptor/server.go +++ b/biz/adaptor/server.go @@ -2,51 +2,104 @@ package adaptor import ( "context" + "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/content" - "github.com/xh-polaris/meowchat-collection/biz/application/service" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/config" - - "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/collection" + "github.com/xh-polaris/meowchat-content/biz/application/service" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" ) -type CollectionServerImpl struct { +type ContentServerImpl struct { *config.Config - CatService service.CatService - ImageService service.ImageService + CatService service.ICatService + ImageService service.IImageService + MomentService service.IMomentService + PostService service.IPostService } -func (s *CollectionServerImpl) SearchCat(ctx context.Context, req *collection.SearchCatReq) (res *collection.SearchCatResp, err error) { +func (s *ContentServerImpl) SearchCat(ctx context.Context, req *content.SearchCatReq) (res *content.SearchCatResp, err error) { return s.CatService.SearchCat(ctx, req) } -func (s *CollectionServerImpl) ListCat(ctx context.Context, req *collection.ListCatReq) (res *collection.ListCatResp, err error) { +func (s *ContentServerImpl) ListCat(ctx context.Context, req *content.ListCatReq) (res *content.ListCatResp, err error) { return s.CatService.ListCat(ctx, req) } -func (s *CollectionServerImpl) RetrieveCat(ctx context.Context, req *collection.RetrieveCatReq) (res *collection.RetrieveCatResp, err error) { +func (s *ContentServerImpl) RetrieveCat(ctx context.Context, req *content.RetrieveCatReq) (res *content.RetrieveCatResp, err error) { return s.CatService.RetrieveCat(ctx, req) } -func (s *CollectionServerImpl) CreateCat(ctx context.Context, req *collection.CreateCatReq) (res *collection.CreateCatResp, err error) { +func (s *ContentServerImpl) CreateCat(ctx context.Context, req *content.CreateCatReq) (res *content.CreateCatResp, err error) { return s.CatService.CreateCat(ctx, req) } -func (s *CollectionServerImpl) UpdateCat(ctx context.Context, req *collection.UpdateCatReq) (res *collection.UpdateCatResp, err error) { +func (s *ContentServerImpl) UpdateCat(ctx context.Context, req *content.UpdateCatReq) (res *content.UpdateCatResp, err error) { return s.CatService.UpdateCat(ctx, req) } -func (s *CollectionServerImpl) DeleteCat(ctx context.Context, req *collection.DeleteCatReq) (res *collection.DeleteCatResp, err error) { +func (s *ContentServerImpl) DeleteCat(ctx context.Context, req *content.DeleteCatReq) (res *content.DeleteCatResp, err error) { return s.CatService.DeleteCat(ctx, req) } -func (s *CollectionServerImpl) CreateImage(ctx context.Context, req *collection.CreateImageReq) (res *collection.CreateImageResp, err error) { +func (s *ContentServerImpl) CreateImage(ctx context.Context, req *content.CreateImageReq) (res *content.CreateImageResp, err error) { return s.ImageService.CreateImage(ctx, req) } -func (s *CollectionServerImpl) DeleteImage(ctx context.Context, req *collection.DeleteImageReq) (res *collection.DeleteImageResp, err error) { +func (s *ContentServerImpl) DeleteImage(ctx context.Context, req *content.DeleteImageReq) (res *content.DeleteImageResp, err error) { return s.ImageService.DeleteImage(ctx, req) } -func (s *CollectionServerImpl) ListImage(ctx context.Context, req *collection.ListImageReq) (res *collection.ListImageResp, err error) { +func (s *ContentServerImpl) ListImage(ctx context.Context, req *content.ListImageReq) (res *content.ListImageResp, err error) { return s.ImageService.ListImage(ctx, req) } + +func (s *ContentServerImpl) ListMoment(ctx context.Context, req *content.ListMomentReq) (res *content.ListMomentResp, err error) { + return s.MomentService.ListMoment(ctx, req) +} + +func (s *ContentServerImpl) CountMoment(ctx context.Context, req *content.CountMomentReq) (res *content.CountMomentResp, err error) { + return s.MomentService.CountMoment(ctx, req) +} + +func (s *ContentServerImpl) RetrieveMoment(ctx context.Context, req *content.RetrieveMomentReq) (res *content.RetrieveMomentResp, err error) { + return s.MomentService.RetrieveMoment(ctx, req) +} + +func (s *ContentServerImpl) CreateMoment(ctx context.Context, req *content.CreateMomentReq) (res *content.CreateMomentResp, err error) { + return s.MomentService.CreateMoment(ctx, req) +} + +func (s *ContentServerImpl) UpdateMoment(ctx context.Context, req *content.UpdateMomentReq) (res *content.UpdateMomentResp, err error) { + return s.MomentService.UpdateMoment(ctx, req) +} + +func (s *ContentServerImpl) DeleteMoment(ctx context.Context, req *content.DeleteMomentReq) (res *content.DeleteMomentResp, err error) { + return s.MomentService.DeleteMoment(ctx, req) +} + +func (s *ContentServerImpl) CreatePost(ctx context.Context, req *content.CreatePostReq) (res *content.CreatePostResp, err error) { + return s.PostService.CreatePost(ctx, req) +} + +func (s *ContentServerImpl) RetrievePost(ctx context.Context, req *content.RetrievePostReq) (res *content.RetrievePostResp, err error) { + return s.PostService.RetrievePost(ctx, req) +} + +func (s *ContentServerImpl) UpdatePost(ctx context.Context, req *content.UpdatePostReq) (res *content.UpdatePostResp, err error) { + return s.PostService.UpdatePost(ctx, req) +} + +func (s *ContentServerImpl) DeletePost(ctx context.Context, req *content.DeletePostReq) (res *content.DeletePostResp, err error) { + return s.PostService.DeletePost(ctx, req) +} + +func (s *ContentServerImpl) ListPost(ctx context.Context, req *content.ListPostReq) (res *content.ListPostResp, err error) { + return s.PostService.ListPost(ctx, req) +} + +func (s *ContentServerImpl) CountPost(ctx context.Context, req *content.CountPostReq) (res *content.CountPostResp, err error) { + return s.PostService.CountPost(ctx, req) +} + +func (s *ContentServerImpl) SetOfficial(ctx context.Context, req *content.SetOfficialReq) (res *content.SetOfficialResp, err error) { + return s.PostService.SetOfficial(ctx, req) +} diff --git a/biz/application/service/cat.go b/biz/application/service/cat.go index 97e93a9..cf1821a 100644 --- a/biz/application/service/cat.go +++ b/biz/application/service/cat.go @@ -3,45 +3,45 @@ package service import ( "context" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/consts" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/data/db" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/mapper" - "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/collection" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + catmapper "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/cat" "github.com/google/wire" "github.com/jinzhu/copier" + "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/content" "go.mongodb.org/mongo-driver/bson/primitive" ) -type CatService interface { - SearchCat(ctx context.Context, req *collection.SearchCatReq) (res *collection.SearchCatResp, err error) - ListCat(ctx context.Context, req *collection.ListCatReq) (res *collection.ListCatResp, err error) - RetrieveCat(ctx context.Context, req *collection.RetrieveCatReq) (res *collection.RetrieveCatResp, err error) - CreateCat(ctx context.Context, req *collection.CreateCatReq) (res *collection.CreateCatResp, err error) - UpdateCat(ctx context.Context, req *collection.UpdateCatReq) (res *collection.UpdateCatResp, err error) - DeleteCat(ctx context.Context, req *collection.DeleteCatReq) (res *collection.DeleteCatResp, err error) +type ICatService interface { + SearchCat(ctx context.Context, req *content.SearchCatReq) (res *content.SearchCatResp, err error) + ListCat(ctx context.Context, req *content.ListCatReq) (res *content.ListCatResp, err error) + RetrieveCat(ctx context.Context, req *content.RetrieveCatReq) (res *content.RetrieveCatResp, err error) + CreateCat(ctx context.Context, req *content.CreateCatReq) (res *content.CreateCatResp, err error) + UpdateCat(ctx context.Context, req *content.UpdateCatReq) (res *content.UpdateCatResp, err error) + DeleteCat(ctx context.Context, req *content.DeleteCatReq) (res *content.DeleteCatResp, err error) } -type CatServiceImpl struct { - CatModel mapper.CatModel +type CatService struct { + CatMongoMapper catmapper.IMongoMapper + CatEsMapper catmapper.IEsMapper } var CatSet = wire.NewSet( - wire.Struct(new(CatServiceImpl), "*"), - wire.Bind(new(CatService), new(*CatServiceImpl)), + wire.Struct(new(CatService), "*"), + wire.Bind(new(ICatService), new(*CatService)), ) -func (s *CatServiceImpl) SearchCat(ctx context.Context, req *collection.SearchCatReq) (res *collection.SearchCatResp, err error) { - data, total, err := s.CatModel.Search(ctx, req.CommunityId, req.Keyword, req.Skip, req.Count) +func (s *CatService) SearchCat(ctx context.Context, req *content.SearchCatReq) (res *content.SearchCatResp, err error) { + data, total, err := s.CatEsMapper.Search(ctx, req.CommunityId, req.Keyword, int(req.Skip), int(req.Count)) if err != nil { return nil, err } if err != nil { return nil, err } - var cats []*collection.Cat + var cats []*content.Cat for _, val := range data { - cat := &collection.Cat{} + cat := &content.Cat{} err = copier.Copy(cat, val) if err != nil { return nil, err @@ -50,17 +50,17 @@ func (s *CatServiceImpl) SearchCat(ctx context.Context, req *collection.SearchCa cat.CreateAt = val.CreateAt.Unix() cats = append(cats, cat) } - return &collection.SearchCatResp{Cats: cats, Total: total}, nil + return &content.SearchCatResp{Cats: cats, Total: total}, nil } -func (s *CatServiceImpl) ListCat(ctx context.Context, req *collection.ListCatReq) (res *collection.ListCatResp, err error) { - data, total, err := s.CatModel.FindManyByCommunityId(ctx, req.CommunityId, req.Skip, req.Count) +func (s *CatService) ListCat(ctx context.Context, req *content.ListCatReq) (res *content.ListCatResp, err error) { + data, total, err := s.CatMongoMapper.FindManyByCommunityId(ctx, req.CommunityId, req.Skip, req.Count) if err != nil { return nil, err } - var cats []*collection.Cat + var cats []*content.Cat for _, val := range data { - cat := &collection.Cat{} + cat := &content.Cat{} err = copier.Copy(cat, val) if err != nil { return nil, err @@ -69,43 +69,43 @@ func (s *CatServiceImpl) ListCat(ctx context.Context, req *collection.ListCatReq cat.CreateAt = val.CreateAt.Unix() cats = append(cats, cat) } - return &collection.ListCatResp{Cats: cats, Total: total}, nil + return &content.ListCatResp{Cats: cats, Total: total}, nil } -func (s *CatServiceImpl) RetrieveCat(ctx context.Context, req *collection.RetrieveCatReq) (res *collection.RetrieveCatResp, err error) { - data, err := s.CatModel.FindOne(ctx, req.CatId) +func (s *CatService) RetrieveCat(ctx context.Context, req *content.RetrieveCatReq) (res *content.RetrieveCatResp, err error) { + data, err := s.CatMongoMapper.FindOne(ctx, req.CatId) switch err { case nil: - case mapper.ErrNotFound: + case consts.ErrNotFound: return nil, consts.ErrNoSuchCat default: return nil, err } - cat := &collection.Cat{} + cat := &content.Cat{} err = copier.Copy(cat, data) if err != nil { return nil, err } cat.Id = data.ID.Hex() cat.CreateAt = data.CreateAt.Unix() - return &collection.RetrieveCatResp{Cat: cat}, nil + return &content.RetrieveCatResp{Cat: cat}, nil } -func (s *CatServiceImpl) CreateCat(ctx context.Context, req *collection.CreateCatReq) (res *collection.CreateCatResp, err error) { - cat := &db.Cat{} +func (s *CatService) CreateCat(ctx context.Context, req *content.CreateCatReq) (res *content.CreateCatResp, err error) { + cat := &catmapper.Cat{} err = copier.Copy(cat, req.Cat) if err != nil { return nil, err } - err = s.CatModel.Insert(ctx, cat) + err = s.CatMongoMapper.Insert(ctx, cat) if err != nil { return nil, err } - return &collection.CreateCatResp{CatId: cat.ID.Hex()}, nil + return &content.CreateCatResp{CatId: cat.ID.Hex()}, nil } -func (s *CatServiceImpl) UpdateCat(ctx context.Context, req *collection.UpdateCatReq) (res *collection.UpdateCatResp, err error) { - cat := &db.Cat{} +func (s *CatService) UpdateCat(ctx context.Context, req *content.UpdateCatReq) (res *content.UpdateCatResp, err error) { + cat := &catmapper.Cat{} err = copier.Copy(cat, req.Cat) if err != nil { return nil, err @@ -114,17 +114,17 @@ func (s *CatServiceImpl) UpdateCat(ctx context.Context, req *collection.UpdateCa if err != nil { return nil, consts.ErrInvalidId } - err = s.CatModel.Update(ctx, cat) + err = s.CatMongoMapper.Update(ctx, cat) if err != nil { return nil, err } - return &collection.UpdateCatResp{}, nil + return &content.UpdateCatResp{}, nil } -func (s *CatServiceImpl) DeleteCat(ctx context.Context, req *collection.DeleteCatReq) (res *collection.DeleteCatResp, err error) { - err = s.CatModel.Delete(ctx, req.CatId) +func (s *CatService) DeleteCat(ctx context.Context, req *content.DeleteCatReq) (res *content.DeleteCatResp, err error) { + err = s.CatMongoMapper.Delete(ctx, req.CatId) if err != nil { return nil, err } - return &collection.DeleteCatResp{}, nil + return &content.DeleteCatResp{}, nil } diff --git a/biz/application/service/image.go b/biz/application/service/image.go index 7bf30f8..b6293d0 100644 --- a/biz/application/service/image.go +++ b/biz/application/service/image.go @@ -3,32 +3,31 @@ package service import ( "context" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/data/db" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/mapper" + imagemapper "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/image" "github.com/google/wire" - "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/collection" + "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/content" ) -type ImageService interface { - CreateImage(ctx context.Context, req *collection.CreateImageReq) (*collection.CreateImageResp, error) - DeleteImage(ctx context.Context, req *collection.DeleteImageReq) (*collection.DeleteImageResp, error) - ListImage(ctx context.Context, req *collection.ListImageReq) (*collection.ListImageResp, error) +type IImageService interface { + CreateImage(ctx context.Context, req *content.CreateImageReq) (*content.CreateImageResp, error) + DeleteImage(ctx context.Context, req *content.DeleteImageReq) (*content.DeleteImageResp, error) + ListImage(ctx context.Context, req *content.ListImageReq) (*content.ListImageResp, error) } -type ImageServiceImpl struct { - ImageModel mapper.ImageModel +type ImageService struct { + ImageModel imagemapper.IMongoMapper } var ImageSet = wire.NewSet( - wire.Struct(new(ImageServiceImpl), "*"), - wire.Bind(new(ImageService), new(*ImageServiceImpl)), + wire.Struct(new(ImageService), "*"), + wire.Bind(new(IImageService), new(*ImageService)), ) -func (s *ImageServiceImpl) CreateImage(ctx context.Context, req *collection.CreateImageReq) (*collection.CreateImageResp, error) { - data := make([]*db.Image, len(req.Images)) +func (s *ImageService) CreateImage(ctx context.Context, req *content.CreateImageReq) (*content.CreateImageResp, error) { + data := make([]*imagemapper.Image, len(req.Images)) for i := 0; i < len(data); i++ { - data[i] = &db.Image{ + data[i] = &imagemapper.Image{ CatId: req.Images[i].CatId, ImageUrl: req.Images[i].Url, } @@ -41,19 +40,19 @@ func (s *ImageServiceImpl) CreateImage(ctx context.Context, req *collection.Crea for i := 0; i < len(data); i++ { id[i] = data[i].ID.Hex() } - return &collection.CreateImageResp{ImageIds: id}, nil + return &content.CreateImageResp{ImageIds: id}, nil } -func (s *ImageServiceImpl) DeleteImage(ctx context.Context, req *collection.DeleteImageReq) (*collection.DeleteImageResp, error) { +func (s *ImageService) DeleteImage(ctx context.Context, req *content.DeleteImageReq) (*content.DeleteImageResp, error) { err := s.ImageModel.Delete(ctx, req.ImageId) if err != nil { return nil, err } - return &collection.DeleteImageResp{}, nil + return &content.DeleteImageResp{}, nil } -func (s *ImageServiceImpl) ListImage(ctx context.Context, req *collection.ListImageReq) (*collection.ListImageResp, error) { +func (s *ImageService) ListImage(ctx context.Context, req *content.ListImageReq) (*content.ListImageResp, error) { res, err := s.ImageModel.ListImage(ctx, req.CatId, req.PrevId, req.Limit, req.Offset, req.Backward) if err != nil { return nil, err @@ -66,9 +65,9 @@ func (s *ImageServiceImpl) ListImage(ctx context.Context, req *collection.ListIm } } - imageList := make([]*collection.Image, len(res)) + imageList := make([]*content.Image, len(res)) for i, image := range res { - imageList[i] = &collection.Image{ + imageList[i] = &content.Image{ Id: image.ID.Hex(), Url: image.ImageUrl, CatId: image.CatId, @@ -79,5 +78,5 @@ func (s *ImageServiceImpl) ListImage(ctx context.Context, req *collection.ListIm if err != nil { return nil, err } - return &collection.ListImageResp{Images: imageList, Total: total}, nil + return &content.ListImageResp{Images: imageList, Total: total}, nil } diff --git a/biz/application/service/moment.go b/biz/application/service/moment.go new file mode 100644 index 0000000..2dc07fc --- /dev/null +++ b/biz/application/service/moment.go @@ -0,0 +1,152 @@ +package service + +import ( + "context" + "github.com/google/wire" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/moment" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/util/convertor" + "github.com/xh-polaris/paginator-go/esp" + "github.com/xh-polaris/paginator-go/mongop" + "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/content" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type IMomentService interface { + ListMoment(ctx context.Context, req *content.ListMomentReq) (*content.ListMomentResp, error) + CountMoment(ctx context.Context, req *content.CountMomentReq) (*content.CountMomentResp, error) + RetrieveMoment(ctx context.Context, req *content.RetrieveMomentReq) (*content.RetrieveMomentResp, error) + CreateMoment(ctx context.Context, req *content.CreateMomentReq) (*content.CreateMomentResp, error) + UpdateMoment(ctx context.Context, req *content.UpdateMomentReq) (*content.UpdateMomentResp, error) + DeleteMoment(ctx context.Context, req *content.DeleteMomentReq) (*content.DeleteMomentResp, error) +} + +type MomentService struct { + MomentMongoMapper moment.IMongoMapper + MomentEsMapper moment.IEsMapper +} + +var MomentSet = wire.NewSet( + wire.Struct(new(MomentService), "*"), + wire.Bind(new(IMomentService), new(*MomentService)), +) + +func (s *MomentService) ListMoment(ctx context.Context, req *content.ListMomentReq) (*content.ListMomentResp, error) { + resp := new(content.ListMomentResp) + var moments []*moment.Moment + var total int64 + var err error + + filter := convertor.ParseMomentFilter(req.FilterOptions) + p := convertor.ParsePagination(req.PaginationOptions) + if req.SearchOptions == nil { + moments, total, err = s.MomentMongoMapper.FindManyAndCount(ctx, filter, p, &mongop.IdSorter{}) + if err != nil { + return nil, err + } + } else { + switch o := req.SearchOptions.Type.(type) { + case *content.SearchOptions_AllFieldsKey: + moments, total, err = s.MomentEsMapper.Search(ctx, convertor.ConvertMomentAllFieldsSearchQuery(o), filter, p, &esp.ScoreSorter{}) + case *content.SearchOptions_MultiFieldsKey: + moments, total, err = s.MomentEsMapper.Search(ctx, convertor.ConvertMomentMultiFieldsSearchQuery(o), filter, p, &esp.ScoreSorter{}) + } + if err != nil { + return nil, err + } + } + + resp.Total = total + if p.LastToken != nil { + resp.Token = *p.LastToken + } + resp.Moments = make([]*content.Moment, 0, len(moments)) + for _, moment_ := range moments { + resp.Moments = append(resp.Moments, convertor.ConvertMoment(moment_)) + } + + return resp, nil +} + +func (s *MomentService) CountMoment(ctx context.Context, req *content.CountMomentReq) (*content.CountMomentResp, error) { + resp := new(content.CountMomentResp) + var err error + filter := convertor.ParseMomentFilter(req.FilterOptions) + if req.SearchOptions == nil { + resp.Total, err = s.MomentMongoMapper.Count(ctx, filter) + if err != nil { + return nil, err + } + } else { + switch o := req.SearchOptions.Type.(type) { + case *content.SearchOptions_AllFieldsKey: + resp.Total, err = s.MomentEsMapper.CountWithQuery(ctx, convertor.ConvertMomentAllFieldsSearchQuery(o), filter) + case *content.SearchOptions_MultiFieldsKey: + resp.Total, err = s.MomentEsMapper.CountWithQuery(ctx, convertor.ConvertMomentMultiFieldsSearchQuery(o), filter) + } + if err != nil { + return nil, err + } + } + + return resp, nil +} + +func (s *MomentService) RetrieveMoment(ctx context.Context, req *content.RetrieveMomentReq) (*content.RetrieveMomentResp, error) { + data, err := s.MomentMongoMapper.FindOne(ctx, req.MomentId) + if err != nil { + return nil, err + } + m := convertor.ConvertMoment(data) + return &content.RetrieveMomentResp{Moment: m}, nil +} + +func (s *MomentService) CreateMoment(ctx context.Context, req *content.CreateMomentReq) (*content.CreateMomentResp, error) { + m := req.Moment + data := &moment.Moment{ + Photos: m.Photos, + Title: m.Title, + Text: m.Text, + CommunityId: m.CommunityId, + UserId: m.UserId, + CatId: m.CatId, + } + + err := s.MomentMongoMapper.Insert(ctx, data) + if err != nil { + return nil, err + } + + return &content.CreateMomentResp{MomentId: data.ID.Hex()}, nil +} + +func (s *MomentService) UpdateMoment(ctx context.Context, req *content.UpdateMomentReq) (*content.UpdateMomentResp, error) { + m := req.Moment + momentId, err := primitive.ObjectIDFromHex(m.Id) + if err != nil { + return nil, consts.ErrInvalidObjectId + } + + err = s.MomentMongoMapper.Update(ctx, &moment.Moment{ + ID: momentId, + CatId: m.CatId, + CommunityId: m.CommunityId, + Photos: m.Photos, + Title: m.Title, + Text: m.Text, + UserId: m.UserId, + }) + if err != nil { + return nil, err + } + + return &content.UpdateMomentResp{}, nil +} + +func (s *MomentService) DeleteMoment(ctx context.Context, req *content.DeleteMomentReq) (*content.DeleteMomentResp, error) { + err := s.MomentMongoMapper.Delete(ctx, req.MomentId) + if err != nil { + return nil, err + } + return &content.DeleteMomentResp{}, nil +} diff --git a/biz/application/service/post.go b/biz/application/service/post.go new file mode 100644 index 0000000..b633b3e --- /dev/null +++ b/biz/application/service/post.go @@ -0,0 +1,161 @@ +package service + +import ( + "context" + "github.com/google/wire" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/post" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/util/convertor" + "github.com/xh-polaris/paginator-go/esp" + "github.com/xh-polaris/paginator-go/mongop" + "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/content" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type IPostService interface { + CreatePost(ctx context.Context, req *content.CreatePostReq) (*content.CreatePostResp, error) + RetrievePost(ctx context.Context, req *content.RetrievePostReq) (*content.RetrievePostResp, error) + UpdatePost(ctx context.Context, req *content.UpdatePostReq) (*content.UpdatePostResp, error) + DeletePost(ctx context.Context, req *content.DeletePostReq) (*content.DeletePostResp, error) + ListPost(ctx context.Context, req *content.ListPostReq) (*content.ListPostResp, error) + CountPost(ctx context.Context, req *content.CountPostReq) (*content.CountPostResp, error) + SetOfficial(ctx context.Context, req *content.SetOfficialReq) (*content.SetOfficialResp, error) +} + +type PostService struct { + PostMongoMapper post.IMongoMapper + PostEsMapper post.IEsMapper +} + +var PostSet = wire.NewSet( + wire.Struct(new(PostService), "*"), + wire.Bind(new(IPostService), new(*PostService)), +) + +func (s *PostService) CreatePost(ctx context.Context, req *content.CreatePostReq) (*content.CreatePostResp, error) { + p := &post.Post{ + Title: req.Title, + Text: req.Text, + CoverUrl: req.CoverUrl, + Tags: req.Tags, + UserId: req.UserId, + } + err := s.PostMongoMapper.Insert(ctx, p) + if err != nil { + return nil, err + } + return &content.CreatePostResp{PostId: p.ID.Hex()}, nil +} + +func (s *PostService) RetrievePost(ctx context.Context, req *content.RetrievePostReq) (*content.RetrievePostResp, error) { + data, err := s.PostMongoMapper.FindOne(ctx, req.PostId) + switch err { + case nil: + case consts.ErrNotFound: + return nil, consts.ErrNoSuchPost + default: + return nil, err + } + return &content.RetrievePostResp{Post: convertor.ConvertPost(data)}, nil +} + +func (s *PostService) UpdatePost(ctx context.Context, req *content.UpdatePostReq) (*content.UpdatePostResp, error) { + oid, err := primitive.ObjectIDFromHex(req.Id) + if err != nil { + return nil, consts.ErrInvalidObjectId + } + err = s.PostMongoMapper.Update(ctx, &post.Post{ + ID: oid, + Title: req.Title, + Text: req.Text, + CoverUrl: req.CoverUrl, + Tags: req.Tags, + }) + if err != nil { + return nil, err + } + + return &content.UpdatePostResp{}, nil +} + +func (s *PostService) DeletePost(ctx context.Context, req *content.DeletePostReq) (*content.DeletePostResp, error) { + err := s.PostMongoMapper.Delete(ctx, req.Id) + if err != nil { + return nil, err + } + return &content.DeletePostResp{}, nil +} + +func (s *PostService) ListPost(ctx context.Context, req *content.ListPostReq) (*content.ListPostResp, error) { + resp := new(content.ListPostResp) + var posts []*post.Post + var total int64 + var err error + + filter := convertor.ParsePostFilter(req.FilterOptions) + + p := convertor.ParsePagination(req.PaginationOptions) + + if req.SearchOptions == nil { + posts, total, err = s.PostMongoMapper.FindManyAndCount(ctx, filter, p, &mongop.IdSorter{}) + if err != nil { + return nil, err + } + } else { + switch o := req.SearchOptions.Type.(type) { + case *content.SearchOptions_AllFieldsKey: + posts, total, err = s.PostEsMapper.Search(ctx, convertor.ConvertPostAllFieldsSearchQuery(o), filter, p, &esp.ScoreSorter{}) + case *content.SearchOptions_MultiFieldsKey: + posts, total, err = s.PostEsMapper.Search(ctx, convertor.ConvertPostMultiFieldsSearchQuery(o), filter, p, &esp.ScoreSorter{}) + } + if err != nil { + return nil, err + } + } + + resp.Total = total + if p.LastToken != nil { + resp.Token = *p.LastToken + } + resp.Posts = make([]*content.Post, 0, len(posts)) + for _, post_ := range posts { + resp.Posts = append(resp.Posts, convertor.ConvertPost(post_)) + } + return resp, nil +} + +func (s *PostService) CountPost(ctx context.Context, req *content.CountPostReq) (*content.CountPostResp, error) { + var total int64 + var err error + + filter := convertor.ParsePostFilter(req.FilterOptions) + + if req.SearchOptions == nil { + total, err = s.PostMongoMapper.Count(ctx, filter) + if err != nil { + return nil, err + } + } else { + switch o := req.SearchOptions.Type.(type) { + case *content.SearchOptions_AllFieldsKey: + total, err = s.PostEsMapper.CountWithQuery(ctx, convertor.ConvertPostAllFieldsSearchQuery(o), filter) + case *content.SearchOptions_MultiFieldsKey: + total, err = s.PostEsMapper.CountWithQuery(ctx, convertor.ConvertPostMultiFieldsSearchQuery(o), filter) + } + if err != nil { + return nil, err + } + } + + return &content.CountPostResp{Total: total}, nil +} + +func (s *PostService) SetOfficial(ctx context.Context, req *content.SetOfficialReq) (*content.SetOfficialResp, error) { + err := s.PostMongoMapper.UpdateFlags(ctx, req.PostId, map[post.Flag]bool{ + post.OfficialFlag: !req.IsRemove, + }) + if err != nil { + return nil, err + } + return &content.SetOfficialResp{}, nil +} diff --git a/biz/infrastructure/consts/error.go b/biz/infrastructure/consts/error.go index 9e5e798..cbf5212 100644 --- a/biz/infrastructure/consts/error.go +++ b/biz/infrastructure/consts/error.go @@ -1,8 +1,19 @@ package consts -import "google.golang.org/grpc/status" +import ( + "errors" + "github.com/zeromicro/go-zero/core/stores/mon" + "google.golang.org/grpc/status" +) + +var ( + ErrNoSuchCat = status.Error(10101, "no such cat") + ErrInvalidId = status.Error(10102, "invalid id") + ErrNoSuchPost = status.Error(10301, "no such post") + ErrPaginatorTokenExpired = status.Error(10303, "paginator token has been expired") +) var ( - ErrNoSuchCat = status.Error(10101, "no such cat") - ErrInvalidId = status.Error(10102, "invalid id") + ErrNotFound = mon.ErrNotFound + ErrInvalidObjectId = errors.New("invalid objectId") ) diff --git a/biz/infrastructure/consts/field.go b/biz/infrastructure/consts/field.go new file mode 100644 index 0000000..8ff7813 --- /dev/null +++ b/biz/infrastructure/consts/field.go @@ -0,0 +1,17 @@ +package consts + +const ( + ID = "_id" + CatId = "catId" + CommunityId = "communityId" + Photos = "photos" + Title = "title" + Text = "text" + Tags = "tags" + UserId = "userId" + CoverUrl = "coverUrl" + Flags = "flags" + Score = "_score" + UpdateAt = "updateAt" + CreateAt = "createAt" +) diff --git a/biz/infrastructure/data/db/cat.go b/biz/infrastructure/data/db/cat.go deleted file mode 100644 index 24c9d88..0000000 --- a/biz/infrastructure/data/db/cat.go +++ /dev/null @@ -1,24 +0,0 @@ -package db - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -type Cat struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Age string `bson:"age,omitempty"` - CommunityId string `bson:"communityId,omitempty"` - Color string `bson:"color,omitempty"` - Details string `bson:"details,omitempty"` - Name string `bson:"name,omitempty"` - Sex string `bson:"sex,omitempty"` - Status int64 `bson:"status,omitempty"` - Area string `bson:"area,omitempty"` - IsSnipped bool `bson:"isSnipped,omitempty"` - IsSterilized bool `bson:"isSterilized,omitempty"` - Avatars []string `bson:"avatars,omitempty"` - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` -} diff --git a/biz/infrastructure/data/db/image.go b/biz/infrastructure/data/db/image.go deleted file mode 100644 index 577225c..0000000 --- a/biz/infrastructure/data/db/image.go +++ /dev/null @@ -1,15 +0,0 @@ -package db - -import ( - "time" - - "go.mongodb.org/mongo-driver/bson/primitive" -) - -type Image struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` - CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` - CatId string `bson:"catId,omitempty" json:"catId,omitempty"` - ImageUrl string `bson:"imageUrl,omitempty" json:"imageUrl,omitempty"` -} diff --git a/biz/infrastructure/mapper/cat/es.go b/biz/infrastructure/mapper/cat/es.go new file mode 100644 index 0000000..fe49cd9 --- /dev/null +++ b/biz/infrastructure/mapper/cat/es.go @@ -0,0 +1,111 @@ +package cat + +import ( + "context" + "crypto/tls" + "fmt" + "github.com/bytedance/sonic" + "github.com/elastic/go-elasticsearch/v8" + "github.com/elastic/go-elasticsearch/v8/typedapi/core/search" + "github.com/elastic/go-elasticsearch/v8/typedapi/types" + "github.com/elastic/go-elasticsearch/v8/typedapi/types/enums/sortorder" + "github.com/mitchellh/mapstructure" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "go.mongodb.org/mongo-driver/bson/primitive" + "log" + "net/http" + "time" +) + +type ( + IEsMapper interface { + Search(ctx context.Context, communityId, keyword string, skip, count int) ([]*Cat, int64, error) + } + + EsMapper struct { + es *elasticsearch.TypedClient + indexName string + } +) + +func NewEsMapper(config *config.Config) IEsMapper { + esClient, err := elasticsearch.NewTypedClient(elasticsearch.Config{ + Username: config.Elasticsearch.Username, + Password: config.Elasticsearch.Password, + Addresses: config.Elasticsearch.Addresses, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + }) + if err != nil { + log.Fatal(err) + } + return &EsMapper{ + es: esClient, + indexName: fmt.Sprintf("%s.%s-alias", config.Mongo.DB, CollectionName), + } +} + +func (m *EsMapper) Search(ctx context.Context, communityId, keyword string, skip, count int) ([]*Cat, int64, error) { + res, err := m.es.Search().From(skip).Size(count).Index(m.indexName).Request(&search.Request{ + Query: &types.Query{ + Bool: &types.BoolQuery{ + Must: []types.Query{ + { + Term: map[string]types.TermQuery{ + consts.CommunityId: { + Value: communityId, + }, + }, + MultiMatch: &types.MultiMatchQuery{ + Query: keyword, + Fields: []string{"details", "name^5", "area", "color"}, + }, + }, + }, + }, + }, + Sort: types.Sort{ + &types.SortOptions{ + SortOptions: map[string]types.FieldSort{ + consts.Score: { + Order: &sortorder.Desc, + }, + consts.CreateAt: { + Order: &sortorder.Desc, + }, + }, + }, + }, + }).Do(ctx) + + total := res.Hits.Total.Value + cats := make([]*Cat, 0, 10) + for _, hit := range res.Hits.Hits { + cat := &Cat{} + source := make(map[string]any) + err = sonic.Unmarshal(hit.Source_, &source) + if err != nil { + return nil, 0, err + } + if source[consts.CreateAt], err = time.Parse("2006-01-02T15:04:05Z07:00", source[consts.CreateAt].(string)); err != nil { + return nil, 0, err + } + if source[consts.UpdateAt], err = time.Parse("2006-01-02T15:04:05Z07:00", source[consts.UpdateAt].(string)); err != nil { + return nil, 0, err + } + err = mapstructure.Decode(source, cat) + if err != nil { + return nil, 0, err + } + + oid := hit.Id_ + cat.ID, err = primitive.ObjectIDFromHex(oid) + if err != nil { + return nil, 0, err + } + cats = append(cats, cat) + } + return cats, total, nil +} diff --git a/biz/infrastructure/mapper/cat/mongo.go b/biz/infrastructure/mapper/cat/mongo.go new file mode 100644 index 0000000..feb7d75 --- /dev/null +++ b/biz/infrastructure/mapper/cat/mongo.go @@ -0,0 +1,121 @@ +package cat + +import ( + "context" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "time" + + "github.com/zeromicro/go-zero/core/stores/monc" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const prefixCatCacheKey = "cache:cat:" +const CollectionName = "cat" + +var _ IMongoMapper = (*MongoMapper)(nil) + +type ( + IMongoMapper interface { + Insert(ctx context.Context, data *Cat) error + FindOne(ctx context.Context, id string) (*Cat, error) + Update(ctx context.Context, data *Cat) error + Delete(ctx context.Context, id string) error + FindManyByCommunityId(ctx context.Context, communityId string, skip int64, count int64) ([]*Cat, int64, error) + } + + MongoMapper struct { + conn *monc.Model + } + + Cat struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Age string `bson:"age,omitempty"` + CommunityId string `bson:"communityId,omitempty"` + Color string `bson:"color,omitempty"` + Details string `bson:"details,omitempty"` + Name string `bson:"name,omitempty"` + Sex string `bson:"sex,omitempty"` + Status int64 `bson:"status,omitempty"` + Area string `bson:"area,omitempty"` + IsSnipped bool `bson:"isSnipped,omitempty"` + IsSterilized bool `bson:"isSterilized,omitempty"` + Avatars []string `bson:"avatars,omitempty"` + UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` + } +) + +func NewMongoMapper(config *config.Config) IMongoMapper { + conn := monc.MustNewModel(config.Mongo.URL, config.Mongo.DB, CollectionName, config.Cache) + return &MongoMapper{ + conn: conn, + } +} + +func (m *MongoMapper) Insert(ctx context.Context, data *Cat) error { + if data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() + } + + key := prefixCatCacheKey + data.ID.Hex() + _, err := m.conn.InsertOne(ctx, key, data) + return err +} + +func (m *MongoMapper) FindOne(ctx context.Context, id string) (*Cat, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, consts.ErrInvalidObjectId + } + + var data Cat + key := prefixCatCacheKey + id + err = m.conn.FindOne(ctx, key, &data, bson.M{consts.ID: oid}) + switch err { + case nil: + return &data, nil + case monc.ErrNotFound: + return nil, consts.ErrNotFound + default: + return nil, err + } +} + +func (m *MongoMapper) Update(ctx context.Context, data *Cat) error { + data.UpdateAt = time.Now() + key := prefixCatCacheKey + data.ID.Hex() + _, err := m.conn.UpdateOne(ctx, key, bson.M{consts.ID: data.ID}, bson.M{"$set": data}) + return err +} + +func (m *MongoMapper) Delete(ctx context.Context, id string) error { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return consts.ErrInvalidObjectId + } + key := prefixCatCacheKey + id + _, err = m.conn.DeleteOne(ctx, key, bson.M{consts.ID: oid}) + return err +} + +func (m *MongoMapper) FindManyByCommunityId(ctx context.Context, communityId string, skip int64, count int64) ([]*Cat, int64, error) { + data := make([]*Cat, 0, 20) + err := m.conn.Find(ctx, &data, bson.M{consts.CommunityId: communityId}, &options.FindOptions{ + Skip: &skip, + Limit: &count, + Sort: bson.M{consts.ID: -1}, + }) + if err != nil { + return nil, 0, err + } + total, err := m.conn.CountDocuments(ctx, bson.M{consts.CommunityId: communityId}) + if err != nil { + return nil, 0, err + } + return data, total, nil +} diff --git a/biz/infrastructure/mapper/cat_model.go b/biz/infrastructure/mapper/cat_model.go deleted file mode 100644 index caf579a..0000000 --- a/biz/infrastructure/mapper/cat_model.go +++ /dev/null @@ -1,176 +0,0 @@ -package mapper - -import ( - "bytes" - "context" - "crypto/tls" - "encoding/json" - "fmt" - "github.com/google/wire" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/config" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/data/db" - "log" - "net/http" - "time" - - "github.com/elastic/go-elasticsearch/v8" - "github.com/mitchellh/mapstructure" - "github.com/zeromicro/go-zero/core/logx" - "github.com/zeromicro/go-zero/core/stores/monc" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo/options" -) - -const CatCollectionName = "cat" - -var _ CatModel = (*customCatModel)(nil) - -type ( - // CatModel is an interface to be customized, add more methods here, - // and implement the added methods in customCatModel. - CatModel interface { - catModel - FindManyByCommunityId(ctx context.Context, communityId string, skip int64, count int64) ([]*db.Cat, int64, error) - Search(ctx context.Context, communityId, keyword string, skip, count int64) ([]*db.Cat, int64, error) - } - - customCatModel struct { - *defaultCatModel - es *elasticsearch.Client - indexName string - } -) - -// NewCatModel returns a mapper for the mongo. -func NewCatModel(config *config.Config) CatModel { - conn := monc.MustNewModel(config.Mongo.URL, config.Mongo.DB, CatCollectionName, config.Cache) - esClient, err := elasticsearch.NewClient(elasticsearch.Config{ - Username: config.Elasticsearch.Username, - Password: config.Elasticsearch.Password, - Addresses: config.Elasticsearch.Addresses, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }, - }) - if err != nil { - log.Fatal(err) - } - return &customCatModel{ - defaultCatModel: newDefaultCatModel(conn), - es: esClient, - indexName: fmt.Sprintf("%s.%s-alias", config.Mongo.DB, CatCollectionName), - } -} - -var CatSet = wire.NewSet( - NewCatModel, -) - -func (m *customCatModel) FindManyByCommunityId(ctx context.Context, communityId string, skip int64, count int64) ([]*db.Cat, int64, error) { - data := make([]*db.Cat, 0, 20) - err := m.conn.Find(ctx, &data, bson.M{"communityId": communityId}, &options.FindOptions{ - Skip: &skip, - Limit: &count, - Sort: bson.M{"_id": -1}, - }) - if err != nil { - return nil, 0, err - } - total, err := m.conn.CountDocuments(ctx, bson.M{"communityId": communityId}) - if err != nil { - return nil, 0, err - } - return data, total, nil -} - -func (m *customCatModel) Search(ctx context.Context, communityId, keyword string, skip, count int64) ([]*db.Cat, int64, error) { - search := m.es.Search - query := map[string]any{ - "from": skip, - "size": count, - "query": map[string]any{ - "bool": map[string]any{ - "must": []any{ - map[string]any{ - "term": map[string]any{ - "communityId": communityId, - }, - }, - map[string]any{ - "multi_match": map[string]any{ - "query": keyword, - "fields": []string{"details", "name^5", "area", "color"}, - }, - }, - }, - }, - }, - "sort": map[string]any{ - "_score": map[string]any{ - "order": "desc", - }, - "createAt": map[string]any{ - "order": "desc", - }, - }, - } - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(query); err != nil { - return nil, 0, err - } - res, err := search( - search.WithIndex(m.indexName), - search.WithContext(ctx), - search.WithBody(&buf), - ) - if err != nil { - return nil, 0, err - } - defer res.Body.Close() - - if res.IsError() { - var e map[string]interface{} - if err := json.NewDecoder(res.Body).Decode(&e); err != nil { - return nil, 0, err - } else { - logx.Errorf("[%s] %s: %s", - res.Status(), - e["error"].(map[string]interface{})["type"], - e["error"].(map[string]interface{})["reason"], - ) - } - } - var r map[string]any - if err := json.NewDecoder(res.Body).Decode(&r); err != nil { - return nil, 0, err - } - hits := r["hits"].(map[string]any)["hits"].([]any) - total := int64(r["hits"].(map[string]any)["total"].(map[string]any)["value"].(float64)) - cats := make([]*db.Cat, 0, 10) - for i := range hits { - hit := hits[i].(map[string]any) - cat := &db.Cat{} - source := hit["_source"].(map[string]any) - if source["createAt"], err = time.Parse("2006-01-02T15:04:05Z07:00", source["createAt"].(string)); err != nil { - return nil, 0, err - } - if source["updateAt"], err = time.Parse("2006-01-02T15:04:05Z07:00", source["updateAt"].(string)); err != nil { - return nil, 0, err - } - hit["_source"] = source - err := mapstructure.Decode(hit["_source"], cat) - if err != nil { - return nil, 0, err - } - oid := hit["_id"].(string) - id, err := primitive.ObjectIDFromHex(oid) - if err != nil { - return nil, 0, err - } - cat.ID = id - cats = append(cats, cat) - } - return cats, total, nil -} diff --git a/biz/infrastructure/mapper/cat_model_gen.go b/biz/infrastructure/mapper/cat_model_gen.go deleted file mode 100644 index 5f38dda..0000000 --- a/biz/infrastructure/mapper/cat_model_gen.go +++ /dev/null @@ -1,77 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -package mapper - -import ( - "context" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/data/db" - "time" - - "github.com/zeromicro/go-zero/core/stores/monc" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" -) - -var prefixCatCacheKey = "cache:cat:" - -type catModel interface { - Insert(ctx context.Context, data *db.Cat) error - FindOne(ctx context.Context, id string) (*db.Cat, error) - Update(ctx context.Context, data *db.Cat) error - Delete(ctx context.Context, id string) error -} - -type defaultCatModel struct { - conn *monc.Model -} - -func newDefaultCatModel(conn *monc.Model) *defaultCatModel { - return &defaultCatModel{conn: conn} -} - -func (m *defaultCatModel) Insert(ctx context.Context, data *db.Cat) error { - if data.ID.IsZero() { - data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() - } - - key := prefixCatCacheKey + data.ID.Hex() - _, err := m.conn.InsertOne(ctx, key, data) - return err -} - -func (m *defaultCatModel) FindOne(ctx context.Context, id string) (*db.Cat, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, ErrInvalidObjectId - } - - var data db.Cat - key := prefixCatCacheKey + id - err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid}) - switch err { - case nil: - return &data, nil - case monc.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - -func (m *defaultCatModel) Update(ctx context.Context, data *db.Cat) error { - data.UpdateAt = time.Now() - key := prefixCatCacheKey + data.ID.Hex() - _, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data}) - return err -} - -func (m *defaultCatModel) Delete(ctx context.Context, id string) error { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return ErrInvalidObjectId - } - key := prefixCatCacheKey + id - _, err = m.conn.DeleteOne(ctx, key, bson.M{"_id": oid}) - return err -} diff --git a/biz/infrastructure/mapper/error.go b/biz/infrastructure/mapper/error.go deleted file mode 100644 index 61fda3d..0000000 --- a/biz/infrastructure/mapper/error.go +++ /dev/null @@ -1,12 +0,0 @@ -package mapper - -import ( - "errors" - - "github.com/zeromicro/go-zero/core/stores/mon" -) - -var ( - ErrNotFound = mon.ErrNotFound - ErrInvalidObjectId = errors.New("invalid objectId") -) diff --git a/biz/infrastructure/mapper/image/mongo.go b/biz/infrastructure/mapper/image/mongo.go new file mode 100644 index 0000000..7716432 --- /dev/null +++ b/biz/infrastructure/mapper/image/mongo.go @@ -0,0 +1,168 @@ +package image + +import ( + "context" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "math" + "time" + + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/zeromicro/go-zero/core/stores/monc" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" +) + +var _ IMongoMapper = (*MongoMapper)(nil) + +const prefixImageCacheKey = "cache:image:" +const CollectionName = "image" + +type ( + // IMongoMapper is an interface to be customized, add more methods here, + // and implement the added methods in MongoMapper. + IMongoMapper interface { + Insert(ctx context.Context, data *Image) error + FindOne(ctx context.Context, id string) (*Image, error) + Update(ctx context.Context, data *Image) error + Delete(ctx context.Context, id string) error + ListImage(ctx context.Context, catId string, lastId *string, limit, offset int64, backward bool) ([]*Image, error) + InsertMany(ctx context.Context, image []*Image) error + CountImage(ctx context.Context, catId string) (int64, error) + } + + MongoMapper struct { + conn *monc.Model + } + + Image struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` + CatId string `bson:"catId,omitempty" json:"catId,omitempty"` + ImageUrl string `bson:"imageUrl,omitempty" json:"imageUrl,omitempty"` + } +) + +func NewMongoMapper(config *config.Config) IMongoMapper { + conn := monc.MustNewModel(config.Mongo.URL, config.Mongo.DB, CollectionName, config.Cache) + return &MongoMapper{ + conn: conn, + } +} + +func (m *MongoMapper) Insert(ctx context.Context, data *Image) error { + if data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() + } + + key := prefixImageCacheKey + data.ID.Hex() + _, err := m.conn.InsertOne(ctx, key, data) + return err +} + +func (m *MongoMapper) FindOne(ctx context.Context, id string) (*Image, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, consts.ErrInvalidObjectId + } + + var data Image + key := prefixImageCacheKey + id + err = m.conn.FindOne(ctx, key, &data, bson.M{consts.ID: oid}) + switch err { + case nil: + return &data, nil + case monc.ErrNotFound: + return nil, consts.ErrNotFound + default: + return nil, err + } +} + +func (m *MongoMapper) Update(ctx context.Context, data *Image) error { + data.UpdateAt = time.Now() + key := prefixImageCacheKey + data.ID.Hex() + _, err := m.conn.ReplaceOne(ctx, key, bson.M{consts.ID: data.ID}, data) + return err +} + +func (m *MongoMapper) Delete(ctx context.Context, id string) error { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return consts.ErrInvalidObjectId + } + key := prefixImageCacheKey + id + _, err = m.conn.DeleteOne(ctx, key, bson.M{consts.ID: oid}) + return err +} + +func (m *MongoMapper) InsertMany(ctx context.Context, image []*Image) error { + for i := 0; i < len(image); i++ { + if image[i].ID.IsZero() { + image[i].ID = primitive.NewObjectID() + image[i].CreateAt = time.Now() + image[i].UpdateAt = time.Now() + } + } + data := make([]interface{}, len(image)) + for i := 0; i < len(image); i++ { + data[i] = image[i] + } + _, err := m.conn.InsertMany(ctx, data) + return err +} + +func (m *MongoMapper) ListImage(ctx context.Context, catId string, lastId *string, limit, offset int64, backward bool) ([]*Image, error) { + var data []*Image + var oid primitive.ObjectID + var err error + + // 构造lastId + if lastId == nil { + if backward { + oid = primitive.NewObjectIDFromTimestamp(time.Unix(math.MinInt32, 0)) + } else { + oid = primitive.NewObjectIDFromTimestamp(time.Unix(math.MaxInt32, 0)) + } + } else { + oid, err = primitive.ObjectIDFromHex(*lastId) + if err != nil { + return nil, consts.ErrInvalidObjectId + } + } + + // 构造请求,新的数据在前面,数值越大越新 + opts := options.FindOptions{ + Limit: &limit, + Skip: &offset, + Sort: bson.M{consts.ID: -1}, + } + filter := bson.M{consts.CatId: catId} + if backward { + filter[consts.ID] = bson.M{"$gt": oid} + } else { + filter[consts.ID] = bson.M{"$lt": oid} + } + + err = m.conn.Find(ctx, &data, filter, &opts) + if err != nil { + return nil, err + } else if len(data) <= 0 { + return data, nil + } else if backward { + return data, nil + } else { + return data, nil + } +} + +func (m *MongoMapper) CountImage(ctx context.Context, catId string) (int64, error) { + total, err := m.conn.CountDocuments(ctx, bson.M{consts.CatId: catId}) + if err != nil { + return 0, err + } + return total, nil +} diff --git a/biz/infrastructure/mapper/image_model.go b/biz/infrastructure/mapper/image_model.go deleted file mode 100644 index 79ea37e..0000000 --- a/biz/infrastructure/mapper/image_model.go +++ /dev/null @@ -1,115 +0,0 @@ -package mapper - -import ( - "context" - "github.com/google/wire" - "math" - "time" - - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/config" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/data/db" - - "github.com/zeromicro/go-zero/core/stores/monc" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo/options" -) - -var _ ImageModel = (*customImageModel)(nil) - -const ImageCollectionName = "image" - -type ( - // ImageModel is an interface to be customized, add more methods here, - // and implement the added methods in customImageModel. - ImageModel interface { - imageModel - ListImage(ctx context.Context, catId string, lastId *string, limit, offset int64, backward bool) ([]*db.Image, error) - InsertMany(ctx context.Context, image []*db.Image) error - CountImage(ctx context.Context, catId string) (int64, error) - } - - customImageModel struct { - *defaultImageModel - } -) - -// NewImageModel returns a mapper for the mongo. -func NewImageModel(config *config.Config) ImageModel { - conn := monc.MustNewModel(config.Mongo.URL, config.Mongo.DB, ImageCollectionName, config.Cache) - return &customImageModel{ - defaultImageModel: newDefaultImageModel(conn), - } -} - -var ImageSet = wire.NewSet( - NewImageModel, -) - -func (c *customImageModel) InsertMany(ctx context.Context, image []*db.Image) error { - for i := 0; i < len(image); i++ { - if image[i].ID.IsZero() { - image[i].ID = primitive.NewObjectID() - image[i].CreateAt = time.Now() - image[i].UpdateAt = time.Now() - } - } - data := make([]interface{}, len(image)) - for i := 0; i < len(image); i++ { - data[i] = image[i] - } - _, err := c.conn.InsertMany(ctx, data) - return err -} - -func (c *customImageModel) ListImage(ctx context.Context, catId string, lastId *string, limit, offset int64, backward bool) ([]*db.Image, error) { - var data []*db.Image - var oid primitive.ObjectID - var err error - - // 构造lastId - if lastId == nil { - if backward { - oid = primitive.NewObjectIDFromTimestamp(time.Unix(math.MinInt32, 0)) - } else { - oid = primitive.NewObjectIDFromTimestamp(time.Unix(math.MaxInt32, 0)) - } - } else { - oid, err = primitive.ObjectIDFromHex(*lastId) - if err != nil { - return nil, ErrInvalidObjectId - } - } - - // 构造请求,新的数据在前面,数值越大越新 - opts := options.FindOptions{ - Limit: &limit, - Skip: &offset, - Sort: bson.M{"_id": -1}, - } - filter := bson.M{"catId": catId} - if backward { - filter["_id"] = bson.M{"$gt": oid} - } else { - filter["_id"] = bson.M{"$lt": oid} - } - - err = c.conn.Find(ctx, &data, filter, &opts) - if err != nil { - return nil, err - } else if len(data) <= 0 { - return data, nil - } else if backward { - return data, nil - } else { - return data, nil - } -} - -func (c *customImageModel) CountImage(ctx context.Context, catId string) (int64, error) { - total, err := c.conn.CountDocuments(ctx, bson.M{"catId": catId}) - if err != nil { - return 0, err - } - return total, nil -} diff --git a/biz/infrastructure/mapper/image_model_gen.go b/biz/infrastructure/mapper/image_model_gen.go deleted file mode 100644 index db5b199..0000000 --- a/biz/infrastructure/mapper/image_model_gen.go +++ /dev/null @@ -1,77 +0,0 @@ -// Code generated by goctl. DO NOT EDIT. -package mapper - -import ( - "context" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/data/db" - "time" - - "github.com/zeromicro/go-zero/core/stores/monc" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" -) - -var prefixImageCacheKey = "cache:image:" - -type imageModel interface { - Insert(ctx context.Context, data *db.Image) error - FindOne(ctx context.Context, id string) (*db.Image, error) - Update(ctx context.Context, data *db.Image) error - Delete(ctx context.Context, id string) error -} - -type defaultImageModel struct { - conn *monc.Model -} - -func newDefaultImageModel(conn *monc.Model) *defaultImageModel { - return &defaultImageModel{conn: conn} -} - -func (m *defaultImageModel) Insert(ctx context.Context, data *db.Image) error { - if data.ID.IsZero() { - data.ID = primitive.NewObjectID() - data.CreateAt = time.Now() - data.UpdateAt = time.Now() - } - - key := prefixImageCacheKey + data.ID.Hex() - _, err := m.conn.InsertOne(ctx, key, data) - return err -} - -func (m *defaultImageModel) FindOne(ctx context.Context, id string) (*db.Image, error) { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return nil, ErrInvalidObjectId - } - - var data db.Image - key := prefixImageCacheKey + id - err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid}) - switch err { - case nil: - return &data, nil - case monc.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - -func (m *defaultImageModel) Update(ctx context.Context, data *db.Image) error { - data.UpdateAt = time.Now() - key := prefixImageCacheKey + data.ID.Hex() - _, err := m.conn.ReplaceOne(ctx, key, bson.M{"_id": data.ID}, data) - return err -} - -func (m *defaultImageModel) Delete(ctx context.Context, id string) error { - oid, err := primitive.ObjectIDFromHex(id) - if err != nil { - return ErrInvalidObjectId - } - key := prefixImageCacheKey + id - _, err = m.conn.DeleteOne(ctx, key, bson.M{"_id": oid}) - return err -} diff --git a/biz/infrastructure/mapper/moment/es.go b/biz/infrastructure/mapper/moment/es.go new file mode 100644 index 0000000..30be3d9 --- /dev/null +++ b/biz/infrastructure/mapper/moment/es.go @@ -0,0 +1,134 @@ +package moment + +import ( + "context" + "crypto/tls" + "encoding/json" + "fmt" + "github.com/elastic/go-elasticsearch/v8/typedapi/core/count" + "github.com/elastic/go-elasticsearch/v8/typedapi/core/search" + "github.com/elastic/go-elasticsearch/v8/typedapi/types" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "github.com/xh-polaris/paginator-go" + "github.com/xh-polaris/paginator-go/esp" + "log" + "net/http" + "time" + + "github.com/elastic/go-elasticsearch/v8" + "github.com/mitchellh/mapstructure" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type ( + IEsMapper interface { + Search(ctx context.Context, query []types.Query, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Moment, int64, error) + CountWithQuery(ctx context.Context, query []types.Query, fopts *FilterOptions) (int64, error) + } + + EsMapper struct { + es *elasticsearch.TypedClient + indexName string + } +) + +func NewEsMapper(config *config.Config) IEsMapper { + esClient, err := elasticsearch.NewTypedClient(elasticsearch.Config{ + Username: config.Elasticsearch.Username, + Password: config.Elasticsearch.Password, + Addresses: config.Elasticsearch.Addresses, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + }) + if err != nil { + log.Fatal(err) + } + return &EsMapper{ + es: esClient, + indexName: fmt.Sprintf("%s.%s-alias", config.Mongo.DB, CollectionName), + } +} + +func (m *EsMapper) Search(ctx context.Context, query []types.Query, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Moment, int64, error) { + p := esp.NewEsPaginator(paginator.NewRawStore(sorter), popts) + s, sa, err := p.MakeSortOptions(ctx) + if err != nil { + return nil, 0, err + } + f := makeEsFilter(fopts) + res, err := m.es.Search().From(int(*popts.Offset)).Size(int(*popts.Limit)).Index(m.indexName).Request(&search.Request{ + Query: &types.Query{ + Bool: &types.BoolQuery{ + Must: query, + Filter: f, + }, + }, + Sort: s, + SearchAfter: sa, + }).Do(ctx) + if err != nil { + return nil, 0, err + } + + hits := res.Hits.Hits + total := res.Hits.Total.Value + datas := make([]*Moment, 0, len(hits)) + for i := range hits { + hit := hits[i] + var source map[string]any + err = json.Unmarshal(hit.Source_, &source) + if err != nil { + return nil, 0, err + } + if source[consts.CreateAt], err = time.Parse("2006-01-02T15:04:05Z07:00", source[consts.CreateAt].(string)); err != nil { + return nil, 0, err + } + if source[consts.UpdateAt], err = time.Parse("2006-01-02T15:04:05Z07:00", source[consts.UpdateAt].(string)); err != nil { + return nil, 0, err + } + data := &Moment{} + err = mapstructure.Decode(source, data) + if err != nil { + return nil, 0, err + } + oid := hit.Id_ + data.ID, err = primitive.ObjectIDFromHex(oid) + if err != nil { + return nil, 0, err + } + data.Score_ = float64(hit.Score_) + datas = append(datas, data) + } + // 如果是反向查询,反转数据 + if *popts.Backward { + for i := 0; i < len(datas)/2; i++ { + datas[i], datas[len(datas)-i-1] = datas[len(datas)-i-1], datas[i] + } + } + if len(datas) > 0 { + err = p.StoreSorter(ctx, datas[0], datas[len(datas)-1]) + if err != nil { + return nil, 0, err + } + } + return datas, total, nil +} + +func (m *EsMapper) CountWithQuery(ctx context.Context, query []types.Query, fopts *FilterOptions) (int64, error) { + f := makeEsFilter(fopts) + res, err := m.es.Count().Index(m.indexName).Request(&count.Request{ + Query: &types.Query{ + Bool: &types.BoolQuery{ + Must: query, + Filter: f, + }, + }, + }).Do(ctx) + if err != nil { + return 0, err + } + + return res.Count, nil +} diff --git a/biz/infrastructure/mapper/moment/filter.go b/biz/infrastructure/mapper/moment/filter.go new file mode 100644 index 0000000..012b61d --- /dev/null +++ b/biz/infrastructure/mapper/moment/filter.go @@ -0,0 +1,99 @@ +package moment + +import ( + "github.com/elastic/go-elasticsearch/v8/typedapi/types" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "go.mongodb.org/mongo-driver/bson" +) + +type FilterOptions struct { + OnlyUserId *string + OnlyCommunityId *string + OnlyCommunityIds []string +} + +type MongoFilter struct { + m bson.M + *FilterOptions +} + +func makeMongoFilter(options *FilterOptions) bson.M { + return (&MongoFilter{ + m: bson.M{}, + FilterOptions: options, + }).toBson() +} + +func (f *MongoFilter) toBson() bson.M { + f.CheckOnlyUserId() + f.CheckOnlyCommunityId() + f.CheckOnlyCommunityIds() + return f.m +} + +func (f *MongoFilter) CheckOnlyUserId() { + if f.OnlyUserId != nil { + f.m[consts.UserId] = *f.OnlyUserId + } +} + +func (f *MongoFilter) CheckOnlyCommunityId() { + if f.OnlyCommunityId != nil { + f.m[consts.CommunityId] = *f.OnlyCommunityId + } +} + +func (f *MongoFilter) CheckOnlyCommunityIds() { + if f.OnlyCommunityIds != nil { + f.m[consts.CommunityId] = f.OnlyCommunityIds + } +} + +type EsFilter struct { + q []types.Query + *FilterOptions +} + +func makeEsFilter(opts *FilterOptions) []types.Query { + return (&EsFilter{ + q: make([]types.Query, 0), + FilterOptions: opts, + }).toQuery() +} + +func (f *EsFilter) toQuery() []types.Query { + f.checkOnlyUserId() + f.checkOnlyCommunityId() + f.checkOnlyCommunityIds() + return f.q +} + +func (f *EsFilter) checkOnlyUserId() { + if f.OnlyUserId != nil { + f.q = append(f.q, types.Query{ + Term: map[string]types.TermQuery{ + consts.UserId: {Value: *f.OnlyUserId}, + }, + }) + } +} + +func (f *EsFilter) checkOnlyCommunityId() { + if f.OnlyCommunityId != nil { + f.q = append(f.q, types.Query{ + Term: map[string]types.TermQuery{ + consts.CommunityId: {Value: *f.OnlyCommunityId}, + }, + }) + } +} + +func (f *EsFilter) checkOnlyCommunityIds() { + if f.OnlyCommunityIds != nil { + f.q = append(f.q, types.Query{ + Term: map[string]types.TermQuery{ + consts.CommunityId: {Value: f.OnlyCommunityIds}, + }, + }) + } +} diff --git a/biz/infrastructure/mapper/moment/mongo.go b/biz/infrastructure/mapper/moment/mongo.go new file mode 100644 index 0000000..52e162a --- /dev/null +++ b/biz/infrastructure/mapper/moment/mongo.go @@ -0,0 +1,177 @@ +package moment + +import ( + "context" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "github.com/xh-polaris/paginator-go" + "github.com/xh-polaris/paginator-go/mongop" + "github.com/zeromicro/go-zero/core/stores/monc" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" + "sync" + "time" +) + +const prefixMomentCacheKey = "cache:moment:" +const CollectionName = "moment" + +type ( + IMongoMapper interface { + Insert(ctx context.Context, data *Moment) error + FindOne(ctx context.Context, id string) (*Moment, error) + Update(ctx context.Context, data *Moment) error + Delete(ctx context.Context, id string) error + FindMany(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Moment, error) + Count(ctx context.Context, filter *FilterOptions) (int64, error) + FindManyAndCount(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Moment, int64, error) + } + + MongoMapper struct { + conn *monc.Model + } + + Moment struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"` + CatId string `bson:"catId,omitempty"` + CommunityId string `bson:"communityId,omitempty"` + Photos []string `bson:"photos,omitempty"` + Title string `bson:"title,omitempty"` + Text string `bson:"text,omitempty"` + UserId string `bson:"userId,omitempty"` + UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` + // 仅ES查询时使用 + Score_ float64 `bson:"_score,omitempty" json:"_score,omitempty"` + } +) + +func NewMongoMapper(config *config.Config) IMongoMapper { + conn := monc.MustNewModel(config.Mongo.URL, config.Mongo.DB, CollectionName, config.Cache) + return &MongoMapper{ + conn: conn, + } +} + +func (m *MongoMapper) FindMany(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Moment, error) { + p := mongop.NewMongoPaginator(paginator.NewRawStore(sorter), popts) + + filter := makeMongoFilter(fopts) + sort, err := p.MakeSortOptions(ctx, filter) + if err != nil { + return nil, err + } + + var data []*Moment + if err = m.conn.Find(ctx, &data, filter, &options.FindOptions{ + Sort: sort, + Limit: popts.Limit, + Skip: popts.Offset, + }); err != nil { + return nil, err + } + + // 如果是反向查询,反转数据 + if *popts.Backward { + for i := 0; i < len(data)/2; i++ { + data[i], data[len(data)-i-1] = data[len(data)-i-1], data[i] + } + } + if len(data) > 0 { + err = p.StoreSorter(ctx, data[0], data[len(data)-1]) + if err != nil { + return nil, err + } + } + return data, nil +} + +func (m *MongoMapper) Count(ctx context.Context, filter *FilterOptions) (int64, error) { + f := makeMongoFilter(filter) + return m.conn.CountDocuments(ctx, f) +} + +func (m *MongoMapper) FindManyAndCount(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Moment, int64, error) { + var data []*Moment + var total int64 + wg := sync.WaitGroup{} + wg.Add(2) + c := make(chan error) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + go func() { + defer wg.Done() + var err error + data, err = m.FindMany(ctx, fopts, popts, sorter) + if err != nil { + c <- err + return + } + }() + go func() { + defer wg.Done() + var err error + total, err = m.Count(ctx, fopts) + if err != nil { + c <- err + return + } + }() + go func() { + wg.Wait() + defer close(c) + }() + if err := <-c; err != nil { + return nil, 0, err + } + return data, total, nil +} + +func (m *MongoMapper) Insert(ctx context.Context, data *Moment) error { + if data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() + } + + key := prefixMomentCacheKey + data.ID.Hex() + _, err := m.conn.InsertOne(ctx, key, data) + return err +} + +func (m *MongoMapper) FindOne(ctx context.Context, id string) (*Moment, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, consts.ErrInvalidObjectId + } + + var data Moment + key := prefixMomentCacheKey + id + err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid}) + switch err { + case nil: + return &data, nil + case monc.ErrNotFound: + return nil, consts.ErrNotFound + default: + return nil, err + } +} + +func (m *MongoMapper) Update(ctx context.Context, data *Moment) error { + data.UpdateAt = time.Now() + key := prefixMomentCacheKey + data.ID.Hex() + _, err := m.conn.UpdateByID(ctx, key, data.ID, bson.M{"$set": data}) + return err +} + +func (m *MongoMapper) Delete(ctx context.Context, id string) error { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return consts.ErrInvalidObjectId + } + key := prefixMomentCacheKey + id + _, err = m.conn.DeleteOne(ctx, key, bson.M{"_id": oid}) + return err +} diff --git a/biz/infrastructure/mapper/post/es.go b/biz/infrastructure/mapper/post/es.go new file mode 100644 index 0000000..aecc797 --- /dev/null +++ b/biz/infrastructure/mapper/post/es.go @@ -0,0 +1,134 @@ +package post + +import ( + "context" + "crypto/tls" + "fmt" + "github.com/bytedance/sonic" + "github.com/elastic/go-elasticsearch/v8" + "github.com/elastic/go-elasticsearch/v8/typedapi/core/count" + "github.com/elastic/go-elasticsearch/v8/typedapi/core/search" + "github.com/elastic/go-elasticsearch/v8/typedapi/types" + "github.com/mitchellh/mapstructure" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "github.com/xh-polaris/paginator-go" + "github.com/xh-polaris/paginator-go/esp" + "go.mongodb.org/mongo-driver/bson/primitive" + "log" + "net/http" + "time" +) + +type ( + IEsMapper interface { + Search(ctx context.Context, query []types.Query, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Post, int64, error) + CountWithQuery(ctx context.Context, query []types.Query, fopts *FilterOptions) (int64, error) + } + + EsMapper struct { + es *elasticsearch.TypedClient + indexName string + } +) + +func NewEsMapper(config *config.Config) IEsMapper { + esClient, err := elasticsearch.NewTypedClient(elasticsearch.Config{ + Username: config.Elasticsearch.Username, + Password: config.Elasticsearch.Password, + Addresses: config.Elasticsearch.Addresses, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + }) + if err != nil { + log.Fatal(err) + } + return &EsMapper{ + es: esClient, + indexName: fmt.Sprintf("%s.%s-alias", config.Mongo.DB, CollectionName), + } +} + +func (m *EsMapper) CountWithQuery(ctx context.Context, query []types.Query, fopts *FilterOptions) (int64, error) { + filter := newPostFilter(fopts) + res, err := m.es.Count().Index(m.indexName).Request(&count.Request{ + Query: &types.Query{ + Bool: &types.BoolQuery{ + Must: query, + Filter: filter, + }, + }, + }).Do(ctx) + if err != nil { + return 0, err + } + + return res.Count, nil +} + +func (m *EsMapper) Search(ctx context.Context, query []types.Query, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Post, int64, error) { + p := esp.NewEsPaginator(paginator.NewRawStore(sorter), popts) + filter := newPostFilter(fopts) + s, sa, err := p.MakeSortOptions(ctx) + if err != nil { + return nil, 0, err + } + res, err := m.es.Search().From(int(*popts.Offset)).Size(int(*popts.Limit)).Index(m.indexName).Request(&search.Request{ + Query: &types.Query{ + Bool: &types.BoolQuery{ + Must: query, + Filter: filter, + }, + }, + SearchAfter: sa, + Sort: s, + }).Do(ctx) + if err != nil { + return nil, 0, err + } + + hits := res.Hits.Hits + total := res.Hits.Total.Value + posts := make([]*Post, 0, len(hits)) + for i := range hits { + hit := hits[i] + post := &Post{} + source := make(map[string]any) + err = sonic.Unmarshal(hit.Source_, &source) + if err != nil { + return nil, 0, err + } + if source[consts.CreateAt], err = time.Parse("2006-01-02T15:04:05Z07:00", source[consts.CreateAt].(string)); err != nil { + return nil, 0, err + } + if source[consts.UpdateAt], err = time.Parse("2006-01-02T15:04:05Z07:00", source[consts.UpdateAt].(string)); err != nil { + return nil, 0, err + } + err = mapstructure.Decode(source, post) + if err != nil { + return nil, 0, err + } + + oid := hit.Id_ + post.ID, err = primitive.ObjectIDFromHex(oid) + if err != nil { + return nil, 0, err + } + post.Score_ = float64(hit.Score_) + posts = append(posts, post) + } + // 如果是反向查询,反转数据 + if *popts.Backward { + for i := 0; i < len(posts)/2; i++ { + posts[i], posts[len(posts)-i-1] = posts[len(posts)-i-1], posts[i] + } + } + if len(posts) > 0 { + err = p.StoreSorter(ctx, posts[0], posts[len(posts)-1]) + if err != nil { + return nil, 0, err + } + } + return posts, total, nil +} diff --git a/biz/infrastructure/mapper/post/filter.go b/biz/infrastructure/mapper/post/filter.go new file mode 100644 index 0000000..7961fe8 --- /dev/null +++ b/biz/infrastructure/mapper/post/filter.go @@ -0,0 +1,139 @@ +package post + +import ( + "encoding/json" + "fmt" + "github.com/elastic/go-elasticsearch/v8/typedapi/types" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "go.mongodb.org/mongo-driver/bson" +) + +type FilterOptions struct { + OnlyUserId *string + OnlyOfficial *bool +} + +type BaseFilter struct { + MustFlags *Flag + MustNotFlags *Flag + *FilterOptions +} + +func (f *BaseFilter) CheckOnlyOfficial() { + if f.OnlyOfficial != nil { + f.MustFlags = f.MustFlags.SetFlag(OfficialFlag, *f.OnlyOfficial) + } +} + +type MongoFilter struct { + m bson.M + *BaseFilter +} + +func MakeBsonFilter(options *FilterOptions) bson.M { + return (&MongoFilter{ + m: bson.M{}, + BaseFilter: &BaseFilter{ + FilterOptions: options, + }, + }).toBson() +} + +func (f *MongoFilter) toBson() bson.M { + f.CheckOnlyUserId() + f.CheckOnlyOfficial() + f.CheckFlags() + return f.m +} + +func (f *MongoFilter) CheckFlags() { + if f.MustFlags != nil && *f.MustFlags != 0 { + f.m[consts.Flags] = bson.M{"$bitsAllSet": *f.MustFlags} + } + if f.MustNotFlags != nil && *f.MustNotFlags != 0 { + or, exist := f.m["$or"] + if !exist { + or = bson.A{} + } + + _ = append(or.(bson.A), bson.M{ + consts.Flags: bson.M{ + "$bitsAllClear": *f.MustNotFlags}, + }, bson.M{ + consts.Flags: bson.M{ + "$exists": false, + }, + }) + f.m["$or"] = or + } +} + +func (f *MongoFilter) CheckOnlyUserId() { + if f.OnlyUserId != nil { + f.m[consts.UserId] = *f.OnlyUserId + } +} + +type postFilter struct { + q []types.Query + *BaseFilter +} + +func newPostFilter(options *FilterOptions) []types.Query { + return (&postFilter{ + q: make([]types.Query, 0), + BaseFilter: &BaseFilter{ + FilterOptions: options, + }, + }).toEsQuery() +} + +func (f *postFilter) toEsQuery() []types.Query { + f.CheckOnlyUserId() + f.CheckOnlyOfficial() + f.CheckFlags() + return f.q +} + +func (f *postFilter) CheckFlags() { + if f.MustFlags != nil && *f.MustFlags != 0 { + raw, _ := json.Marshal(*f.MustFlags) + f.q = append(f.q, types.Query{ + //TODO 也许会造成潜在的性能风险 + Script: &types.ScriptQuery{ + Script: types.InlineScript{ + Source: fmt.Sprintf("doc['%s'].size() != 0 && "+ + "(doc['%s'].value & params.%s) == params.%s", consts.Flags, consts.Flags, consts.Flags, consts.Flags), + Params: map[string]json.RawMessage{ + consts.Flags: raw, + }, + }, + }, + }) + } + if f.MustNotFlags != nil && *f.MustNotFlags != 0 { + raw, _ := json.Marshal(*f.MustNotFlags) + f.q = append(f.q, types.Query{ + //TODO 也许会造成潜在的性能风险 + Script: &types.ScriptQuery{ + Script: types.InlineScript{ + Source: fmt.Sprintf("doc['%s'].size() == 0 || "+ + "(doc['%s'].value & params.%s) == 0", consts.Flags, consts.Flags, consts.Flags), + Params: map[string]json.RawMessage{ + consts.Flags: raw, + }, + }, + }, + }) + } +} + +func (f *postFilter) CheckOnlyUserId() { + if f.OnlyUserId != nil { + f.q = append(f.q, types.Query{ + Term: map[string]types.TermQuery{ + consts.UserId: {Value: *f.OnlyUserId}, + }, + }) + } +} diff --git a/biz/infrastructure/mapper/post/model.go b/biz/infrastructure/mapper/post/model.go new file mode 100644 index 0000000..510b5cc --- /dev/null +++ b/biz/infrastructure/mapper/post/model.go @@ -0,0 +1,231 @@ +package post + +import ( + "context" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "sync" + "time" + + "github.com/xh-polaris/paginator-go" + "github.com/xh-polaris/paginator-go/mongop" + + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/monc" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const prefixPostCacheKey = "cache:post:" +const CollectionName = "post" + +type ( + IMongoMapper interface { + Insert(ctx context.Context, data *Post) error + FindOne(ctx context.Context, id string) (*Post, error) + Update(ctx context.Context, data *Post) error + Delete(ctx context.Context, id string) error + FindMany(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Post, error) + Count(ctx context.Context, fopts *FilterOptions) (int64, error) + FindManyAndCount(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Post, int64, error) + UpdateFlags(ctx context.Context, id string, flags map[Flag]bool) error + } + + MongoMapper struct { + conn *monc.Model + paginatorCache cache.Cache + } + + Post struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"` + Title string `bson:"title,omitempty" ` + Text string `bson:"text,omitempty"` + CoverUrl string `bson:"coverUrl,omitempty"` + Tags []string `bson:"tags,omitempty"` + UserId string `bson:"userId,omitempty"` + Flags *Flag `bson:"flags,omitempty"` + UpdateAt time.Time `bson:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty"` + // 仅ES查询时使用 + Score_ float64 `bson:"_score,omitempty" json:"_score,omitempty"` + } + + Flag int64 +) + +const ( + OfficialFlag = 1 << 0 +) + +func (f *Flag) SetFlag(flag Flag, b bool) *Flag { + if f == nil { + f = new(Flag) + } + if b { + *f |= flag + } else { + *f &= ^flag + } + return f +} + +func (f *Flag) GetFlag(flag Flag) bool { + return f != nil && (*f&flag) > 0 +} + +func NewMongoMapper(config *config.Config) IMongoMapper { + conn := monc.MustNewModel(config.Mongo.URL, config.Mongo.DB, CollectionName, config.Cache) + return &MongoMapper{ + conn: conn, + } +} + +func (m *MongoMapper) UpdateFlags(ctx context.Context, id string, flags map[Flag]bool) error { + var or, and Flag + for flag, v := range flags { + if v { + or += flag + } else { + and += flag + } + } + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return consts.ErrInvalidObjectId + } + _, err = m.conn.UpdateOne(ctx, prefixPostCacheKey+id, bson.M{consts.ID: oid}, bson.M{ + "$bit": bson.M{ + consts.Flags: bson.M{ + "and": ^and, + "or": or, + }, + }, + }) + if err != nil { + return err + } + return nil +} + +func (m *MongoMapper) FindMany(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Post, error) { + p := mongop.NewMongoPaginator(paginator.NewRawStore(sorter), popts) + + filter := MakeBsonFilter(fopts) + sort, err := p.MakeSortOptions(ctx, filter) + if err != nil { + return nil, err + } + + var data []*Post + if err := m.conn.Find(ctx, &data, filter, &options.FindOptions{ + Sort: sort, + Limit: popts.Limit, + Skip: popts.Offset, + }); err != nil { + return nil, err + } + + // 如果是反向查询,反转数据 + if *popts.Backward { + for i := 0; i < len(data)/2; i++ { + data[i], data[len(data)-i-1] = data[len(data)-i-1], data[i] + } + } + if len(data) > 0 { + err = p.StoreSorter(ctx, data[0], data[len(data)-1]) + if err != nil { + return nil, err + } + } + return data, nil +} + +func (m *MongoMapper) Count(ctx context.Context, filter *FilterOptions) (int64, error) { + f := MakeBsonFilter(filter) + return m.conn.CountDocuments(ctx, f) +} + +func (m *MongoMapper) FindManyAndCount(ctx context.Context, fopts *FilterOptions, popts *paginator.PaginationOptions, sorter any) ([]*Post, int64, error) { + var posts []*Post + var total int64 + wg := sync.WaitGroup{} + wg.Add(2) + c := make(chan error) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + go func() { + defer wg.Done() + var err error + posts, err = m.FindMany(ctx, fopts, popts, sorter) + if err != nil { + c <- err + return + } + }() + go func() { + defer wg.Done() + var err error + total, err = m.Count(ctx, fopts) + if err != nil { + c <- err + return + } + }() + go func() { + wg.Wait() + defer close(c) + }() + if err := <-c; err != nil { + return nil, 0, err + } + return posts, total, nil +} + +func (m *MongoMapper) Insert(ctx context.Context, data *Post) error { + if data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() + } + + key := prefixPostCacheKey + data.ID.Hex() + _, err := m.conn.InsertOne(ctx, key, data) + return err +} + +func (m *MongoMapper) FindOne(ctx context.Context, id string) (*Post, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, consts.ErrInvalidObjectId + } + + var data Post + key := prefixPostCacheKey + id + err = m.conn.FindOne(ctx, key, &data, bson.M{consts.ID: oid}) + switch err { + case nil: + return &data, nil + case monc.ErrNotFound: + return nil, consts.ErrNotFound + default: + return nil, err + } +} + +func (m *MongoMapper) Update(ctx context.Context, data *Post) error { + data.UpdateAt = time.Now() + key := prefixPostCacheKey + data.ID.Hex() + _, err := m.conn.UpdateOne(ctx, key, bson.M{consts.ID: data.ID}, bson.M{"$set": data}) + return err +} + +func (m *MongoMapper) Delete(ctx context.Context, id string) error { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return consts.ErrInvalidObjectId + } + key := prefixPostCacheKey + id + _, err = m.conn.DeleteOne(ctx, key, bson.M{consts.ID: oid}) + return err +} diff --git a/biz/infrastructure/util/convertor/convertor.go b/biz/infrastructure/util/convertor/convertor.go new file mode 100644 index 0000000..c39d32f --- /dev/null +++ b/biz/infrastructure/util/convertor/convertor.go @@ -0,0 +1,166 @@ +package convertor + +import ( + "github.com/elastic/go-elasticsearch/v8/typedapi/types" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/consts" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/moment" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/post" + "github.com/xh-polaris/paginator-go" + "github.com/xh-polaris/service-idl-gen-go/kitex_gen/basic" + "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/content" +) + +func ConvertMomentSlice(data []*moment.Moment) []*content.Moment { + res := make([]*content.Moment, len(data)) + for i, d := range data { + m := &content.Moment{ + Id: d.ID.Hex(), + CreateAt: d.CreateAt.Unix(), + Photos: d.Photos, + Title: d.Title, + Text: d.Text, + UserId: d.UserId, + CommunityId: d.CommunityId, + CatId: d.CatId, + } + res[i] = m + } + return res +} + +func ConvertMoment(data *moment.Moment) *content.Moment { + return &content.Moment{ + Id: data.ID.Hex(), + CreateAt: data.CreateAt.Unix(), + Photos: data.Photos, + Title: data.Title, + Text: data.Text, + UserId: data.UserId, + CommunityId: data.CommunityId, + CatId: data.CatId, + } +} + +func ConvertPost(in *post.Post) *content.Post { + return &content.Post{ + Id: in.ID.Hex(), + CreateAt: in.CreateAt.Unix(), + UpdateAt: in.UpdateAt.Unix(), + Title: in.Title, + Text: in.Text, + CoverUrl: in.CoverUrl, + Tags: in.Tags, + UserId: in.UserId, + IsOfficial: in.Flags.GetFlag(post.OfficialFlag), + } +} + +func ConvertMomentAllFieldsSearchQuery(in *content.SearchOptions_AllFieldsKey) []types.Query { + return []types.Query{{ + MultiMatch: &types.MultiMatchQuery{ + Query: in.AllFieldsKey, + Fields: []string{consts.Title + "^3", consts.Text}, + }}, + } +} + +func ConvertMomentMultiFieldsSearchQuery(in *content.SearchOptions_MultiFieldsKey) []types.Query { + var q []types.Query + if in.MultiFieldsKey.Title != nil { + q = append(q, types.Query{ + Match: map[string]types.MatchQuery{ + consts.Title: { + Query: *in.MultiFieldsKey.Title + "^3", + }, + }, + }) + } + if in.MultiFieldsKey.Text != nil { + q = append(q, types.Query{ + Match: map[string]types.MatchQuery{ + consts.Text: { + Query: *in.MultiFieldsKey.Text, + }, + }, + }) + } + return q +} + +func ConvertPostAllFieldsSearchQuery(in *content.SearchOptions_AllFieldsKey) []types.Query { + return []types.Query{{ + MultiMatch: &types.MultiMatchQuery{ + Query: in.AllFieldsKey, + Fields: []string{consts.Title + "^3", consts.Text, consts.Tags}, + }}, + } +} + +func ConvertPostMultiFieldsSearchQuery(in *content.SearchOptions_MultiFieldsKey) []types.Query { + var q []types.Query + if in.MultiFieldsKey.Title != nil { + q = append(q, types.Query{ + Match: map[string]types.MatchQuery{ + consts.Title: { + Query: *in.MultiFieldsKey.Title + "^3", + }, + }, + }) + } + if in.MultiFieldsKey.Text != nil { + q = append(q, types.Query{ + Match: map[string]types.MatchQuery{ + consts.Text: { + Query: *in.MultiFieldsKey.Text, + }, + }, + }) + } + if in.MultiFieldsKey.Tag != nil { + q = append(q, types.Query{ + Match: map[string]types.MatchQuery{ + consts.Tags: { + Query: *in.MultiFieldsKey.Tag, + }, + }, + }) + } + return q +} + +func ParseMomentFilter(opts *content.MomentFilterOptions) (filter *moment.FilterOptions) { + if opts == nil { + filter = &moment.FilterOptions{} + } else { + filter = &moment.FilterOptions{ + OnlyUserId: opts.OnlyUserId, + OnlyCommunityId: opts.OnlyCommunityId, + OnlyCommunityIds: opts.OnlyCommunityIds, + } + } + return +} + +func ParsePostFilter(fopts *content.PostFilterOptions) *post.FilterOptions { + if fopts != nil { + return &post.FilterOptions{ + OnlyUserId: fopts.OnlyUserId, + OnlyOfficial: fopts.OnlyOfficial, + } + } + return &post.FilterOptions{} +} + +func ParsePagination(opts *basic.PaginationOptions) (p *paginator.PaginationOptions) { + if opts == nil { + p = &paginator.PaginationOptions{} + } else { + p = &paginator.PaginationOptions{ + Limit: opts.Limit, + Offset: opts.Offset, + Backward: opts.Backward, + LastToken: opts.LastToken, + } + } + return +} diff --git a/biz/infrastructure/util/lib.go b/biz/infrastructure/util/lib.go index a3dfa49..50fb669 100644 --- a/biz/infrastructure/util/lib.go +++ b/biz/infrastructure/util/lib.go @@ -2,7 +2,7 @@ package util import ( "github.com/cloudwego/hertz/pkg/common/json" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/util/log" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/util/log" ) func JSONF(v any) string { diff --git a/go.mod b/go.mod index f49102e..2dd83f4 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,18 @@ -module github.com/xh-polaris/meowchat-collection +module github.com/xh-polaris/meowchat-content go 1.18 require ( + github.com/bytedance/sonic v1.8.8 github.com/cloudwego/hertz v0.6.6 github.com/cloudwego/kitex v0.6.1 - github.com/elastic/go-elasticsearch/v8 v8.5.0 + github.com/elastic/go-elasticsearch/v8 v8.7.0 github.com/google/wire v0.5.0 github.com/jinzhu/copier v0.3.5 github.com/kitex-contrib/obs-opentelemetry v0.2.3 github.com/mitchellh/mapstructure v1.1.2 - github.com/xh-polaris/service-idl-gen-go v0.0.0-20230726095359-2c4cbd95c322 + github.com/xh-polaris/paginator-go v1.0.2 + github.com/xh-polaris/service-idl-gen-go v0.0.0-20230804160714-3a65faec50b7 github.com/zeromicro/go-zero v1.5.4 go.mongodb.org/mongo-driver v1.12.0 google.golang.org/grpc v1.56.2 @@ -21,7 +23,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bufbuild/protocompile v0.4.0 // indirect github.com/bytedance/gopkg v0.0.0-20230531144706-a12972768317 // indirect - github.com/bytedance/sonic v1.8.8 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect @@ -30,10 +31,10 @@ require ( github.com/cloudwego/configmanager v0.2.0 // indirect github.com/cloudwego/fastpb v0.0.4 // indirect github.com/cloudwego/frugal v0.1.6 // indirect - github.com/cloudwego/netpoll v0.4.0 // indirect + github.com/cloudwego/netpoll v0.4.1 // indirect github.com/cloudwego/thriftgo v0.2.11 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/elastic/elastic-transport-go/v8 v8.0.0-20211216131617-bbee439d559c // indirect + github.com/elastic/elastic-transport-go/v8 v8.2.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -41,6 +42,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/pprof v0.0.0-20230509042627-b1315fad0c5a // indirect + github.com/google/uuid v1.3.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect github.com/jhump/protoreflect v1.15.1 // indirect github.com/json-iterator/go v1.1.12 // indirect diff --git a/go.sum b/go.sum index a6c29f4..4676a6a 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,9 @@ github.com/cloudwego/kitex v0.6.1/go.mod h1:zI1GBrjT0qloTikcCfQTgxg3Ws+yQMyaChEE github.com/cloudwego/netpoll v0.2.4/go.mod h1:1T2WVuQ+MQw6h6DpE45MohSvDTKdy2DlzCx2KsnPI4E= github.com/cloudwego/netpoll v0.3.1/go.mod h1:1T2WVuQ+MQw6h6DpE45MohSvDTKdy2DlzCx2KsnPI4E= github.com/cloudwego/netpoll v0.3.2/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= -github.com/cloudwego/netpoll v0.4.0 h1:kJ2jMsT5FtlGSNtInnprJf386TFE/rGWzl8kp0wWxx4= github.com/cloudwego/netpoll v0.4.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= +github.com/cloudwego/netpoll v0.4.1 h1:/pGsY7Rs09KqEXEniB9fcsEWfi1iY+66bKUO3/NO6hc= +github.com/cloudwego/netpoll v0.4.1/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= github.com/cloudwego/thriftgo v0.1.2/go.mod h1:LzeafuLSiHA9JTiWC8TIMIq64iadeObgRUhmVG1OC/w= github.com/cloudwego/thriftgo v0.2.4/go.mod h1:8i9AF5uDdWHGqzUhXDlubCjx4MEfKvWXGQlMWyR0tM4= github.com/cloudwego/thriftgo v0.2.7/go.mod h1:8i9AF5uDdWHGqzUhXDlubCjx4MEfKvWXGQlMWyR0tM4= @@ -127,10 +128,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/elastic/elastic-transport-go/v8 v8.0.0-20211216131617-bbee439d559c h1:onA2RpIyeCPvYAj1LFYiiMTrSpqVINWMfYFRS7lofJs= -github.com/elastic/elastic-transport-go/v8 v8.0.0-20211216131617-bbee439d559c/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI= -github.com/elastic/go-elasticsearch/v8 v8.5.0 h1:p6j6RFztHvkIg0NaUlfR0OnRmVdCG6Zyfy+bPKMpKp4= -github.com/elastic/go-elasticsearch/v8 v8.5.0/go.mod h1:Usvydt+x0dv9a1TzEUaovqbJor8rmOHy5dSmPeMAE2k= +github.com/elastic/elastic-transport-go/v8 v8.2.0 h1:hkK5IIs/15mpSXzd5THWVlWTKJyMw6cbCWM3T/B2S5E= +github.com/elastic/elastic-transport-go/v8 v8.2.0/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI= +github.com/elastic/go-elasticsearch/v8 v8.7.0 h1:ZvbT1YHppBC0QxGnMmaDUxoDa26clwhRaB3Gp5E3UcY= +github.com/elastic/go-elasticsearch/v8 v8.7.0/go.mod h1:lVb8SvJV8McVkdswpL8YR5QKIkhlWaoSq60YpHilOLI= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -233,6 +234,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -381,12 +383,10 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xh-polaris/service-idl-gen-go v0.0.0-20230724054410-07c6f1e1392c h1:cWTYpm48Dg1UeVjnMiARUkd700eWvZl+nCNWF4P6jLk= -github.com/xh-polaris/service-idl-gen-go v0.0.0-20230724054410-07c6f1e1392c/go.mod h1:9eW1OifTS21ckiibbz1Wz6eepVJ51J2PkG2+ntyivTU= -github.com/xh-polaris/service-idl-gen-go v0.0.0-20230725125041-e1d178786dad h1:ONuGCfTcnwtqifRkEt5peciqWSE4QXbLu/EHSHBXdsc= -github.com/xh-polaris/service-idl-gen-go v0.0.0-20230725125041-e1d178786dad/go.mod h1:9eW1OifTS21ckiibbz1Wz6eepVJ51J2PkG2+ntyivTU= -github.com/xh-polaris/service-idl-gen-go v0.0.0-20230726095359-2c4cbd95c322 h1:o5WGHHU31j4IPE4X6JWvqPimBScJ4Jb7ftTfylUteSI= -github.com/xh-polaris/service-idl-gen-go v0.0.0-20230726095359-2c4cbd95c322/go.mod h1:9eW1OifTS21ckiibbz1Wz6eepVJ51J2PkG2+ntyivTU= +github.com/xh-polaris/paginator-go v1.0.2 h1:F5B6cLBFQGXBQJiRV304sFJCvSJp4/9bj6qbjTkWOMc= +github.com/xh-polaris/paginator-go v1.0.2/go.mod h1:OHQXys5KVV8LCqUFk9sHvrBR5LaTUy+WgQdqe5P/OOs= +github.com/xh-polaris/service-idl-gen-go v0.0.0-20230804160714-3a65faec50b7 h1:1uKdYUi6GmEXNhw4MtiHANST/+Ipk5QXgDQyxraaYYI= +github.com/xh-polaris/service-idl-gen-go v0.0.0-20230804160714-3a65faec50b7/go.mod h1:KjBt4ZOfugCsdAbFlrniKMDrpJAJobm8KEezTvKVnJM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/main.go b/main.go index f3d35eb..147ee49 100644 --- a/main.go +++ b/main.go @@ -3,17 +3,17 @@ package main import ( "net" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/util/log" - "github.com/xh-polaris/meowchat-collection/provider" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/util/log" + "github.com/xh-polaris/meowchat-content/provider" "github.com/cloudwego/kitex/pkg/rpcinfo" "github.com/cloudwego/kitex/server" "github.com/kitex-contrib/obs-opentelemetry/tracing" - "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/collection/collection" + content "github.com/xh-polaris/service-idl-gen-go/kitex_gen/meowchat/content/contentservice" ) func main() { - s, err := provider.NewCollectionServerImpl() + s, err := provider.NewContentServerImpl() if err != nil { panic(err) } @@ -21,7 +21,7 @@ func main() { if err != nil { panic(err) } - svr := collection.NewServer( + svr := content.NewServer( s, server.WithServiceAddr(addr), server.WithSuite(tracing.NewServerSuite()), diff --git a/provider/provider.go b/provider/provider.go index c4fd371..b83ae3b 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -2,10 +2,13 @@ package provider import ( "github.com/google/wire" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/cat" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/image" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/moment" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/post" - "github.com/xh-polaris/meowchat-collection/biz/application/service" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/mapper" + "github.com/xh-polaris/meowchat-content/biz/application/service" ) var AllProvider = wire.NewSet( @@ -16,6 +19,8 @@ var AllProvider = wire.NewSet( var ApplicationSet = wire.NewSet( service.CatSet, service.ImageSet, + service.MomentSet, + service.PostSet, ) var InfrastructureSet = wire.NewSet( @@ -24,6 +29,11 @@ var InfrastructureSet = wire.NewSet( ) var MapperSet = wire.NewSet( - mapper.CatSet, - mapper.ImageSet, + cat.NewMongoMapper, + cat.NewEsMapper, + image.NewMongoMapper, + moment.NewMongoMapper, + moment.NewEsMapper, + post.NewMongoMapper, + post.NewEsMapper, ) diff --git a/provider/wire.go b/provider/wire.go index 02fcbb8..413f919 100644 --- a/provider/wire.go +++ b/provider/wire.go @@ -6,12 +6,12 @@ package provider import ( "github.com/google/wire" - "github.com/xh-polaris/meowchat-collection/biz/adaptor" + "github.com/xh-polaris/meowchat-content/biz/adaptor" ) -func NewCollectionServerImpl() (*adaptor.CollectionServerImpl, error) { +func NewContentServerImpl() (*adaptor.ContentServerImpl, error) { wire.Build( - wire.Struct(new(adaptor.CollectionServerImpl), "*"), + wire.Struct(new(adaptor.ContentServerImpl), "*"), AllProvider, ) return nil, nil diff --git a/provider/wire_gen.go b/provider/wire_gen.go index a626571..81faee5 100644 --- a/provider/wire_gen.go +++ b/provider/wire_gen.go @@ -7,31 +7,50 @@ package provider import ( - "github.com/xh-polaris/meowchat-collection/biz/adaptor" - "github.com/xh-polaris/meowchat-collection/biz/application/service" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/config" - "github.com/xh-polaris/meowchat-collection/biz/infrastructure/mapper" + "github.com/xh-polaris/meowchat-content/biz/adaptor" + "github.com/xh-polaris/meowchat-content/biz/application/service" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/config" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/cat" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/image" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/moment" + "github.com/xh-polaris/meowchat-content/biz/infrastructure/mapper/post" ) // Injectors from wire.go: -func NewCollectionServerImpl() (*adaptor.CollectionServerImpl, error) { +func NewContentServerImpl() (*adaptor.ContentServerImpl, error) { configConfig, err := config.NewConfig() if err != nil { return nil, err } - catModel := mapper.NewCatModel(configConfig) - catServiceImpl := &service.CatServiceImpl{ - CatModel: catModel, + iMongoMapper := cat.NewMongoMapper(configConfig) + iEsMapper := cat.NewEsMapper(configConfig) + catService := &service.CatService{ + CatMongoMapper: iMongoMapper, + CatEsMapper: iEsMapper, } - imageModel := mapper.NewImageModel(configConfig) - imageServiceImpl := &service.ImageServiceImpl{ - ImageModel: imageModel, + imageIMongoMapper := image.NewMongoMapper(configConfig) + imageService := &service.ImageService{ + ImageModel: imageIMongoMapper, } - collectionServerImpl := &adaptor.CollectionServerImpl{ - Config: configConfig, - CatService: catServiceImpl, - ImageService: imageServiceImpl, + momentIMongoMapper := moment.NewMongoMapper(configConfig) + momentIEsMapper := moment.NewEsMapper(configConfig) + momentService := &service.MomentService{ + MomentMongoMapper: momentIMongoMapper, + MomentEsMapper: momentIEsMapper, } - return collectionServerImpl, nil + postIMongoMapper := post.NewMongoMapper(configConfig) + postIEsMapper := post.NewEsMapper(configConfig) + postService := &service.PostService{ + PostMongoMapper: postIMongoMapper, + PostEsMapper: postIEsMapper, + } + contentServerImpl := &adaptor.ContentServerImpl{ + Config: configConfig, + CatService: catService, + ImageService: imageService, + MomentService: momentService, + PostService: postService, + } + return contentServerImpl, nil }