Add tree structure to categories API

Introduced a new method `GetTreeCategories` to provide a hierarchical structure for categories. Fixed typos in variable names and integrated utility functions for converting flat lists to nested dictionaries and vice versa. Added `TreeCategories` model for representing nested category structures.
This commit is contained in:
Павел Синицин 2024-09-07 21:18:36 +03:00
parent 25e131269d
commit 8c3541a892
Signed by: spavelit
GPG Key ID: 2FEC8CEAE5A95DD1
6 changed files with 130 additions and 12 deletions

View File

@ -9,13 +9,14 @@ type Api struct {
Client *client.Client
}
type IApi interface {
type Method interface {
GetParentCategories() ([]model.Category, error)
GetCategories() ([]model.Category, error)
GetTreeCategories() ([]model.TreeCategories, error)
GetProducts() ([]model.Product, error)
}
func NewApi(credentials client.Credentials) IApi {
func NewApi(credentials client.Credentials) Method {
return &Api{
Client: client.NewClient(credentials),
}

View File

@ -2,25 +2,26 @@ package api
import (
"errors"
"gitea.24example.ru/spavelit/bpiek/model"
"gitea.24example.ru/spavelit/bpiek/utils"
)
var categories []model.Category
var parentCategories []model.Category
var treeCategories []model.TreeCategories
func (a *Api) GetCategories() ([]model.Category, error) {
if len(categories) > 0 {
return categories, nil
}
parentCategoris, err := a.GetParentCategories()
parentCategories, err := a.GetParentCategories()
if err != nil {
return nil, err
}
for _, category := range parentCategoris {
for _, category := range parentCategories {
categoriesAndProduct, err := a.GetCategoriesAndProductsBySlugParentCategory(category.Slug)
if err != nil {
return nil, err
@ -75,3 +76,36 @@ func (a *Api) GetCategoriesAndProductsBySlugParentCategory(slug string) (*model.
return apiResponse.Result().(*model.CategoriesAndProductsBySlugParentCategoryResponse), nil
}
func (a *Api) GetTreeCategories() ([]model.TreeCategories, error) {
if len(treeCategories) > 0 {
return treeCategories, nil
}
tree := map[string]interface{}{}
parentCategories, err := a.GetParentCategories()
if err != nil {
return nil, err
}
for _, parent := range parentCategories {
tree[parent.Slug] = map[string]interface{}{
"name": parent.Name,
"slug": parent.Slug,
"url": parent.Url,
"children": map[string]interface{}{},
}
categoriesAndProduct, err := a.GetCategoriesAndProductsBySlugParentCategory(parent.Slug)
if err != nil {
return nil, err
}
utils.ConvertListToNestedDict(categoriesAndProduct.Categories, tree)
}
treeCategories = utils.ConvertToNestedList(tree)
return treeCategories, nil
}

View File

@ -10,13 +10,13 @@ func (a *Api) GetProducts() ([]model.Product, error) {
return products, nil
}
parentCategoris, err := a.GetParentCategories()
parentCategories, err := a.GetParentCategories()
if err != nil {
return nil, err
}
for _, category := range parentCategoris {
for _, category := range parentCategories {
categoriesAndProduct, err := a.GetCategoriesAndProductsBySlugParentCategory(category.Slug)
if err != nil {
return nil, err

View File

@ -6,3 +6,10 @@ type Category struct {
Url string `json:"url"`
ApiUrl string `json:"apiUrl"`
}
type TreeCategories struct {
Slug string `json:"slug"`
Name string `json:"name"`
Url string `json:"url"`
Children []TreeCategories `json:"children"`
}

View File

@ -30,8 +30,3 @@ type RemainsAndPlanresiduesResponse struct {
Date string `json:"date"`
Products []ShortProduct `json:"products"`
}
type TreeCategoriesResponse struct {
Category
Children []Category `json:"children"`
}

81
utils/utils.go Normal file
View File

@ -0,0 +1,81 @@
package utils
import (
"fmt"
"gitea.24example.ru/spavelit/bpiek/model"
"strings"
)
func updateNested(d map[string]interface{}, keys []string, value map[string]interface{}) {
for _, key := range keys[:len(keys)-1] {
if _, exists := d[key]; !exists {
d[key] = map[string]interface{}{}
}
d = d[key].(map[string]interface{})
}
d[keys[len(keys)-1]] = value
}
func ConvertListToNestedDict(list []model.Category, tree map[string]interface{}) {
var tmpCategories []model.TreeCategories
for _, item := range list {
tmpCategories = append(tmpCategories, model.TreeCategories{
Name: item.Name,
Slug: item.Slug,
Url: item.Url,
Children: []model.TreeCategories{},
})
}
idx := 0
for idx < len(tmpCategories) {
category := tmpCategories[idx]
if category.Url == "/" || category.Url == "" {
idx++
continue
}
paths := strings.Split(strings.Trim(category.Url, "/"), "/")
var strBuilder strings.Builder
for i, path := range paths {
if len(paths) == i+1 {
strBuilder.WriteString(path)
break
}
strBuilder.WriteString(fmt.Sprintf("%s,children,", path))
}
updateNested(
tree,
strings.Split(strBuilder.String(), ","),
map[string]interface{}{
"name": category.Name,
"slug": category.Slug,
"url": category.Url,
"children": map[string]interface{}{},
},
)
tmpCategories = append(tmpCategories[:idx], tmpCategories[idx+1:]...)
}
}
func ConvertToNestedList(nestedDict map[string]interface{}) []model.TreeCategories {
var result []model.TreeCategories
for _, value := range nestedDict {
if valueMap, ok := value.(map[string]interface{}); ok {
childCategories := ConvertToNestedList(valueMap["children"].(map[string]interface{}))
category := model.TreeCategories{
Name: valueMap["name"].(string),
Slug: valueMap["slug"].(string),
Url: valueMap["url"].(string),
Children: childCategories,
}
result = append(result, category)
} else if category, ok := value.(model.TreeCategories); ok {
result = append(result, category)
}
}
return result
}