diff --git a/cmd/api/api.go b/cmd/api/api.go index f3c78d4..be04af6 100644 --- a/cmd/api/api.go +++ b/cmd/api/api.go @@ -104,6 +104,7 @@ func Execute() { }) r.Group("articles", nil, func(r *router.Router) { + r.Get("", articleHandler.Search) r.Get(":id", articleHandler.GetByID) }) }) diff --git a/doc/postman_collection.json b/doc/postman_collection.json index 3648bc7..591f3e7 100644 --- a/doc/postman_collection.json +++ b/doc/postman_collection.json @@ -763,6 +763,41 @@ }, "response": [] }, + { + "name": "Search", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{base}}/articles?length=10&page=1&keyword=&recent=true", + "host": [ + "{{base}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "length", + "value": "10" + }, + { + "key": "page", + "value": "1" + }, + { + "key": "keyword", + "value": "" + }, + { + "key": "recent", + "value": "true" + } + ] + } + }, + "response": [] + }, { "name": "GetByID", "request": { diff --git a/domain/repository/article.go b/domain/repository/article.go index 16e52ca..18b27a6 100644 --- a/domain/repository/article.go +++ b/domain/repository/article.go @@ -12,6 +12,8 @@ type ArticleSearchOption struct { ExcludeUserIDs []uint Draft bool + Keyword *string + Recent bool } diff --git a/infrastructure/persistence/article.go b/infrastructure/persistence/article.go index de5ea2b..003735f 100644 --- a/infrastructure/persistence/article.go +++ b/infrastructure/persistence/article.go @@ -56,25 +56,32 @@ func (u article) Search(ctx context.Context, paging *util.Paging, option reposit query := db. Model(&entity.Article{}). Preload("User"). - Scopes(func(db *gorm.DB) *gorm.DB { + Scopes(func(query *gorm.DB) *gorm.DB { if len(option.UserIDs) > 0 { - db.Where("user_id IN ?", option.UserIDs) + query.Where("user_id IN ?", option.UserIDs) } if len(option.ExcludeUserIDs) > 0 { - db.Where("user_id NOT IN ?", option.ExcludeUserIDs) + query.Where("user_id NOT IN ?", option.ExcludeUserIDs) } if !option.Draft { - db.Where("draft = ?", false). + query.Where("draft = ?", false). Where("published_at <= ?", time.Now()) } + if option.Keyword != nil { + query.Where( + db.Or("title LIKE ?", "%"+*option.Keyword+"%"). + Or("body LIKE ?", "%"+*option.Keyword+"%"), + ) + } + if option.Recent { - db.Order("created_at desc") + query.Order("published_at desc") } else { - db.Order("created_at asc") + query.Order("published_at asc") } - return db + return query }) count, err := paging.GetCount(query) @@ -82,7 +89,7 @@ func (u article) Search(ctx context.Context, paging *util.Paging, option reposit return nil, 0, err } - err = query.Order("published_at desc").Find(&articles).Error + err = query.Scopes(paging.Query()).Find(&articles).Error if err != nil { return nil, 0, err } diff --git a/interface/handler/article.go b/interface/handler/article.go index 9148021..85c8ba7 100644 --- a/interface/handler/article.go +++ b/interface/handler/article.go @@ -4,10 +4,12 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/nimil-jp/gin-utils/util" "github.com/nimil-jp/gin-utils/context" "go-gin-ddd/resource/request" + "go-gin-ddd/resource/response" "go-gin-ddd/usecase" ) @@ -37,6 +39,23 @@ func (u Article) Create(ctx context.Context, c *gin.Context) error { return nil } +func (u Article) Search(ctx context.Context, c *gin.Context) error { + paging := util.NewPaging(c) + + recent, err := boolQuery(c, "recent") + if err != nil { + recent = true + } + + articles, count, err := u.articleUseCase.Search(ctx, paging, c.Query("keyword"), recent) + if err != nil { + return err + } + + c.JSONP(http.StatusOK, response.NewSearchResponse(articles, count)) + return nil +} + func (u Article) GetByID(ctx context.Context, c *gin.Context) error { id, err := uintParam(c, "id") if err != nil { diff --git a/usecase/article.go b/usecase/article.go index 297a597..1c7a5a1 100644 --- a/usecase/article.go +++ b/usecase/article.go @@ -5,6 +5,7 @@ import ( "github.com/nimil-jp/gin-utils/context" "github.com/nimil-jp/gin-utils/errors" + "github.com/nimil-jp/gin-utils/util" "go-gin-ddd/domain/entity" "go-gin-ddd/domain/repository" @@ -13,6 +14,7 @@ import ( type IArticle interface { Create(ctx context.Context, req *request.ArticleCreate) (uint, error) + Search(ctx context.Context, paging *util.Paging, keyword string, recent bool) ([]*entity.Article, uint, error) GetByID(ctx context.Context, id uint) (*entity.Article, error) Update(ctx context.Context, id uint, req *request.ArticleUpdate) error Delete(ctx context.Context, id uint) error @@ -32,6 +34,15 @@ func (a article) Create(ctx context.Context, req *request.ArticleCreate) (uint, return a.articleRepo.Create(ctx, entity.NewArticle(ctx, req)) } +func (a article) Search(ctx context.Context, paging *util.Paging, keyword string, recent bool) ([]*entity.Article, uint, error) { + return a.articleRepo.Search(ctx, paging, repository.ArticleSearchOption{ + ExcludeUserIDs: []uint{ctx.UID()}, + Draft: false, + Keyword: &keyword, + Recent: recent, + }) +} + func (a article) GetByID(ctx context.Context, id uint) (*entity.Article, error) { article, err := a.articleRepo.GetByID(ctx, id) if err != nil {