173 lines
3.6 KiB
Go
173 lines
3.6 KiB
Go
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
|
|
}
|