package storage import ( "fmt" "sort" "time" bolt "go.etcd.io/bbolt" ) func (s *Storage) CreateCategory(name string, order int) error { return s.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(bucketCategories) if b.Get([]byte(name)) != nil { return fmt.Errorf("category %q already exists", name) } cat := Category{ Name: name, Order: order, CreatedAt: time.Now(), } data, err := encodeJSON(cat) if err != nil { return err } return b.Put([]byte(name), data) }) } func (s *Storage) DeleteCategory(name string) error { return s.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(bucketCategories) if b.Get([]byte(name)) == nil { return fmt.Errorf("category %q not found", name) } return b.Delete([]byte(name)) }) } func (s *Storage) GetCategory(name string) (*Category, error) { var cat *Category err := s.db.View(func(tx *bolt.Tx) error { b := tx.Bucket(bucketCategories) data := b.Get([]byte(name)) if data == nil { return fmt.Errorf("category %q not found", name) } cat = &Category{} return decodeJSON(data, cat) }) return cat, err } func (s *Storage) ListCategories() ([]Category, error) { var categories []Category err := s.db.View(func(tx *bolt.Tx) error { b := tx.Bucket(bucketCategories) return b.ForEach(func(k, v []byte) error { var cat Category if err := decodeJSON(v, &cat); err != nil { return err } categories = append(categories, cat) return nil }) }) if err != nil { return nil, err } sort.Slice(categories, func(i, j int) bool { if categories[i].Order != categories[j].Order { return categories[i].Order < categories[j].Order } return categories[i].CreatedAt.Before(categories[j].CreatedAt) }) return categories, nil } func (s *Storage) UpdateCategoryOrder(name string, order int) error { return s.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(bucketCategories) data := b.Get([]byte(name)) if data == nil { return fmt.Errorf("category %q not found", name) } var cat Category if err := decodeJSON(data, &cat); err != nil { return err } cat.Order = order newData, err := encodeJSON(cat) if err != nil { return err } return b.Put([]byte(name), newData) }) } func (s *Storage) RenameCategory(oldName, newName string) error { return s.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(bucketCategories) // 检查旧分类是否存在 data := b.Get([]byte(oldName)) if data == nil { return fmt.Errorf("category %q not found", oldName) } // 检查新名称是否已存在 if b.Get([]byte(newName)) != nil { return fmt.Errorf("category %q already exists", newName) } // 解码旧分类 var cat Category if err := decodeJSON(data, &cat); err != nil { return err } // 更新名称 cat.Name = newName newData, err := encodeJSON(cat) if err != nil { return err } // 删除旧键,写入新键 if err := b.Delete([]byte(oldName)); err != nil { return err } if err := b.Put([]byte(newName), newData); err != nil { return err } // 同步更新所有条目的分类名 entries := tx.Bucket(bucketEntries) return entries.ForEach(func(k, v []byte) error { var entry Entry if err := decodeJSON(v, &entry); err != nil { return err } if entry.Category == oldName { entry.Category = newName newEntryData, err := encodeJSON(entry) if err != nil { return err } return entries.Put(k, newEntryData) } return nil }) }) } func (s *Storage) CategoryExists(name string) bool { exists := false s.db.View(func(tx *bolt.Tx) error { b := tx.Bucket(bucketCategories) exists = b.Get([]byte(name)) != nil return nil }) return exists }