128 lines
2.8 KiB
Go
128 lines
2.8 KiB
Go
package models
|
|
|
|
import (
|
|
"context"
|
|
|
|
"git.handmade.network/hmn/hmn/src/db"
|
|
"git.handmade.network/hmn/hmn/src/oops"
|
|
"github.com/jackc/pgx/v4/pgxpool"
|
|
)
|
|
|
|
type CategoryKind int
|
|
|
|
const (
|
|
CatKindBlog CategoryKind = iota + 1
|
|
CatKindForum
|
|
CatKindStatic
|
|
CatKindAnnotation
|
|
CatKindWiki
|
|
CatKindLibraryResource
|
|
)
|
|
|
|
type Category struct {
|
|
ID int `db:"id"`
|
|
|
|
ParentID *int `db:"parent_id"`
|
|
ProjectID *int `db:"project_id"` // TODO: Make not null
|
|
|
|
Slug *string `db:"slug"` // TODO: Make not null
|
|
Name *string `db:"name"` // TODO: Make not null
|
|
Blurb *string `db:"blurb"` // TODO: Make not null
|
|
Kind CategoryKind `db:"kind"`
|
|
Color1 string `db:"color_1"`
|
|
Color2 string `db:"color_2"`
|
|
Depth int `db:"depth"` // TODO: What is this?
|
|
}
|
|
|
|
type CategoryTree map[int]*CategoryTreeNode
|
|
|
|
type CategoryTreeNode struct {
|
|
Category
|
|
Parent *CategoryTreeNode
|
|
}
|
|
|
|
func (node *CategoryTreeNode) GetLineage() []*Category {
|
|
current := node
|
|
length := 0
|
|
for current != nil {
|
|
current = current.Parent
|
|
length += 1
|
|
}
|
|
result := make([]*Category, length)
|
|
current = node
|
|
for i := length - 1; i >= 0; i -= 1 {
|
|
result[i] = ¤t.Category
|
|
current = current.Parent
|
|
}
|
|
return result
|
|
}
|
|
|
|
func GetFullCategoryTree(ctx context.Context, conn *pgxpool.Pool) CategoryTree {
|
|
type categoryRow struct {
|
|
Cat Category `db:"cat"`
|
|
}
|
|
rows, err := db.Query(ctx, conn, categoryRow{},
|
|
`
|
|
SELECT $columns
|
|
FROM
|
|
handmade_category as cat
|
|
`,
|
|
)
|
|
if err != nil {
|
|
panic(oops.New(err, "Failed to fetch category tree"))
|
|
}
|
|
|
|
rowsSlice := rows.ToSlice()
|
|
catTreeMap := make(map[int]*CategoryTreeNode, len(rowsSlice))
|
|
for _, row := range rowsSlice {
|
|
cat := row.(*categoryRow).Cat
|
|
catTreeMap[cat.ID] = &CategoryTreeNode{Category: cat}
|
|
}
|
|
|
|
for _, node := range catTreeMap {
|
|
if node.ParentID != nil {
|
|
node.Parent = catTreeMap[*node.ParentID]
|
|
}
|
|
}
|
|
return catTreeMap
|
|
}
|
|
|
|
type CategoryLineageBuilder struct {
|
|
Tree CategoryTree
|
|
CategoryCache map[int][]*Category
|
|
SlugCache map[int][]string
|
|
}
|
|
|
|
func MakeCategoryLineageBuilder(fullCategoryTree CategoryTree) *CategoryLineageBuilder {
|
|
return &CategoryLineageBuilder{
|
|
Tree: fullCategoryTree,
|
|
CategoryCache: make(map[int][]*Category),
|
|
SlugCache: make(map[int][]string),
|
|
}
|
|
}
|
|
|
|
func (cl *CategoryLineageBuilder) GetLineage(catId int) []*Category {
|
|
_, ok := cl.CategoryCache[catId]
|
|
if !ok {
|
|
cl.CategoryCache[catId] = cl.Tree[catId].GetLineage()
|
|
}
|
|
return cl.CategoryCache[catId]
|
|
}
|
|
|
|
func (cl *CategoryLineageBuilder) GetLineageSlugs(catId int) []string {
|
|
_, ok := cl.SlugCache[catId]
|
|
if !ok {
|
|
lineage := cl.GetLineage(catId)
|
|
result := make([]string, 0, len(lineage))
|
|
for _, cat := range lineage {
|
|
name := ""
|
|
if cat.Slug != nil {
|
|
name = *cat.Slug
|
|
}
|
|
result = append(result, name)
|
|
}
|
|
cl.SlugCache[catId] = result
|
|
}
|
|
return cl.SlugCache[catId]
|
|
}
|