Skip to content

Commit

Permalink
paginated get all tags by category id
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettladley committed Feb 2, 2024
1 parent 402c995 commit bc51c81
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 0 deletions.
14 changes: 14 additions & 0 deletions backend/src/controllers/category_tag.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package controllers

import (
"strconv"

"github.com/GenerateNU/sac/backend/src/services"

"github.com/gofiber/fiber/v2"
Expand All @@ -14,6 +16,18 @@ func NewCategoryTagController(categoryTagService services.CategoryTagServiceInte
return &CategoryTagController{categoryTagService: categoryTagService}
}

func (t *CategoryTagController) GetTagsByCategory(c *fiber.Ctx) error {
defaultLimit := 10
defaultPage := 1

tags, err := t.categoryTagService.GetTagsByCategory(c.Params("categoryID"), c.Query("limit", strconv.Itoa(defaultLimit)), c.Query("page", strconv.Itoa(defaultPage)))
if err != nil {
return err.FiberError(c)
}

return c.Status(fiber.StatusOK).JSON(&tags)
}

func (t *CategoryTagController) GetTagByCategory(c *fiber.Ctx) error {
tag, err := t.categoryTagService.GetTagByCategory(c.Params("categoryID"), c.Params("tagID"))
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions backend/src/errors/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ var (
StatusCode: fiber.StatusInternalServerError,
Message: "failed to create tag",
}
FailedToGetTags = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get tags",
}
FailedToGetTag = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get tag",
Expand Down
1 change: 1 addition & 0 deletions backend/src/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,6 @@ func categoryTagRoutes(router fiber.Router, categoryTagService services.Category

categoryTags := router.Group("/:categoryID/tags")

categoryTags.Get("/", categoryTagController.GetTagsByCategory)
categoryTags.Get("/:tagID", categoryTagController.GetTagByCategory)
}
22 changes: 22 additions & 0 deletions backend/src/services/category_tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

type CategoryTagServiceInterface interface {
GetTagsByCategory(categoryID string, limit string, page string) ([]models.Tag, *errors.Error)
GetTagByCategory(categoryID string, tagID string) (*models.Tag, *errors.Error)
}

Expand All @@ -22,6 +23,27 @@ func NewCategoryTagService(db *gorm.DB, validate *validator.Validate) *CategoryT
return &CategoryTagService{DB: db, Validate: validate}
}

func (t *CategoryTagService) GetTagsByCategory(categoryID string, limit string, page string) ([]models.Tag, *errors.Error) {
categoryIDAsUUID, err := utilities.ValidateID(categoryID)
if err != nil {
return nil, err
}

limitAsInt, err := utilities.ValidateNonNegative(limit)
if err != nil {
return nil, &errors.FailedToValidateLimit
}

pageAsInt, err := utilities.ValidateNonNegative(page)
if err != nil {
return nil, &errors.FailedToValidatePage
}

offset := (*pageAsInt - 1) * *limitAsInt

return transactions.GetTagsByCategory(t.DB, *categoryIDAsUUID, *limitAsInt, offset)
}

func (t *CategoryTagService) GetTagByCategory(categoryID string, tagID string) (*models.Tag, *errors.Error) {
categoryIDAsUUID, idErr := utilities.ValidateID(categoryID)

Expand Down
9 changes: 9 additions & 0 deletions backend/src/transactions/category_tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import (
"gorm.io/gorm"
)

func GetTagsByCategory(db *gorm.DB, categoryID uuid.UUID, limit int, offset int) ([]models.Tag, *errors.Error) {
var tags []models.Tag
if err := db.Where("category_id = ?", categoryID).Limit(limit).Offset(offset).Find(&tags).Error; err != nil {
return nil, &errors.FailedToGetTags
}

return tags, nil
}

func GetTagByCategory(db *gorm.DB, categoryID uuid.UUID, tagID uuid.UUID) (*models.Tag, *errors.Error) {
var tag models.Tag
if err := db.Where("category_id = ? AND id = ?", categoryID, tagID).First(&tag).Error; err != nil {
Expand Down
181 changes: 181 additions & 0 deletions backend/tests/api/category_tag_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,182 @@
package tests

import (
"fmt"
"net/http"
"testing"

"github.com/GenerateNU/sac/backend/src/errors"
"github.com/GenerateNU/sac/backend/src/models"
"github.com/goccy/go-json"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"github.com/huandu/go-assert"
)

func AssertTagsWithBodyRespDB(app TestApp, assert *assert.A, resp *http.Response, body *[]map[string]interface{}) []uuid.UUID {
var respTags []models.Tag

err := json.NewDecoder(resp.Body).Decode(&respTags)

assert.NilError(err)

var dbTags []models.Tag

err = app.Conn.Find(&dbTags).Error

assert.NilError(err)

assert.Equal(len(dbTags), len(respTags))

for i, dbTag := range dbTags {
assert.Equal(dbTag.ID, respTags[i].ID)
assert.Equal(dbTag.Name, respTags[i].Name)
assert.Equal(dbTag.CategoryID, respTags[i].CategoryID)
}

tagIDs := make([]uuid.UUID, len(dbTags))
for i, dbTag := range dbTags {
tagIDs[i] = dbTag.ID
}

return tagIDs
}

func TestGetCategoryTagsWorks(t *testing.T) {
appAssert, categoryUUID, tagID := CreateSampleTag(t)

body := SampleTagFactory(categoryUUID)
(*body)["id"] = tagID

TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags", categoryUUID),
}.TestOnStatusAndDB(t, &appAssert,
DBTesterWithStatus{
Status: fiber.StatusOK,
DBTester: func(app TestApp, assert *assert.A, resp *http.Response) {
AssertTagsWithBodyRespDB(app, assert, resp, &[]map[string]interface{}{*body})
},
},
).Close()
}

func TestGetCategoryTagsFailsCategoryBadRequest(t *testing.T) {
appAssert, _ := CreateSampleCategory(t, nil)

badRequests := []string{
"0",
"-1",
"1.1",
"foo",
"null",
}

for _, badRequest := range badRequests {
TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags", badRequest),
}.TestOnError(t, &appAssert, errors.FailedToValidateID)
}

appAssert.Close()
}

func TestGetCategoryTagsFailsCategoryNotFound(t *testing.T) {
appAssert, _ := CreateSampleCategory(t, nil)

uuid := uuid.New()

TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags", uuid),
}.TestOnErrorAndDB(t, &appAssert, ErrorWithDBTester{
Error: errors.CategoryNotFound,
DBTester: func(app TestApp, assert *assert.A, resp *http.Response) {
var category models.Category
err := app.Conn.Where("id = ?", uuid).First(&category).Error
assert.Error(err)

var respBody []map[string]interface{}
err = json.NewDecoder(resp.Body).Decode(&respBody)
assert.NilError(err)
assert.Equal(0, len(respBody))
},
}).Close()
}

func TestGetCategoryTagWorks(t *testing.T) {
existingAppAssert, categoryUUID, tagUUID := CreateSampleTag(t)

TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", categoryUUID, tagUUID),
}.TestOnStatusAndDB(t, &existingAppAssert,
DBTesterWithStatus{
Status: fiber.StatusOK,
DBTester: func(app TestApp, assert *assert.A, resp *http.Response) {
AssertTagWithBodyRespDB(app, assert, resp, SampleTagFactory(categoryUUID))
},
},
).Close()
}

func TestGetCategoryTagFailsCategoryBadRequest(t *testing.T) {
appAssert, _, tagUUID := CreateSampleTag(t)

badRequests := []string{
"0",
"-1",
"1.1",
"foo",
"null",
}

for _, badRequest := range badRequests {
TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", badRequest, tagUUID),
}.TestOnError(t, &appAssert, errors.FailedToValidateID)
}

appAssert.Close()
}

func TestGetCategoryTagFailsTagBadRequest(t *testing.T) {
appAssert, categoryUUID := CreateSampleCategory(t, nil)

badRequests := []string{
"0",
"-1",
"1.1",
"foo",
"null",
}

for _, badRequest := range badRequests {
TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", categoryUUID, badRequest),
}.TestOnError(t, &appAssert, errors.FailedToValidateID)
}

appAssert.Close()
}

func TestGetCategoryTagFailsCategoryNotFound(t *testing.T) {
appAssert, _, tagUUID := CreateSampleTag(t)

TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", uuid.New(), tagUUID),
}.TestOnError(t, &appAssert, errors.TagNotFound).Close()
}

func TestGetCategoryTagFailsTagNotFound(t *testing.T) {
appAssert, categoryUUID := CreateSampleCategory(t, nil)

TestRequest{
Method: fiber.MethodGet,
Path: fmt.Sprintf("/api/v1/categories/%s/tags/%s", categoryUUID, uuid.New()),
}.TestOnError(t, &appAssert, errors.TagNotFound).Close()
}

0 comments on commit bc51c81

Please sign in to comment.