package categories import ( "database/sql" _ "github.com/lib/pq" "fmt" "strings" ) type Category struct { Id int Name string Parent sql.NullInt64 Children []*Category } var CategoriesTree []*Category var CategoriesFlat map[int]*Category // Cavet: slight cheat. All parents must have Category_id < their children. func LoadCategories(db *sql.DB) { CategoriesTree = []*Category{} CategoriesFlat = make(map[int]*Category) rows, err := db.Query("select categories.id, categories.name, categories.parent_id from categories order by coalesce(parent_id, id), parent_id is not null") if err != nil { fmt.Println("DB Error loading Categories:", err) return } defer rows.Close() for rows.Next() { category := &Category{Children: []*Category{}} err = rows.Scan(&category.Id, &category.Name, &category.Parent) if err != nil { fmt.Println("Categories DB Error: ", err) } CategoriesFlat[category.Id] = category if category.Parent.Valid { pid := int(category.Parent.Int64) CategoriesFlat[pid].Children = append(CategoriesFlat[pid].Children, category) } else { CategoriesTree = append(CategoriesTree, category) } } } func Add(db *sql.DB, name string, parent int) error { var err error if parent < 0 { _, err = db.Exec("INSERT INTO categories (name) VALUES ($1)", name) } else { _, err = db.Exec("INSERT INTO categories (name, parent_id) VALUES ($1, $2)", name, parent) } if err != nil { fmt.Println("Categories DB Error Add(): " , err) } return err } func (category *Category) ChangeParent(db *sql.DB, parent *Category) error { var err error if parent == nil { _, err = db.Exec("UPDATE categories SET parent_id = NULL WHERE id = $1", category.Id) } else { _, err = db.Exec("UPDATE categories SET parent_id = $2 WHERE id = $1", category.Id, parent.Id) } if err != nil { fmt.Println("Categories DB Error: ", err) } return err } // get the number of parents a category has func (category *Category) Depth() int { depth := 0 current := category for current.Parent.Valid { current = CategoriesFlat[int(current.Parent.Int64)] depth ++ } return depth } // Helper function for templates (add form select list) func (category *Category) ToString() string { return strings.Repeat("- ", category.Depth()) + category.Name }