Nigiri/persistence.go

133 lines
2.9 KiB
Go

package nigiri
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"reflect"
"sort"
)
func (bs *BaseStore[T]) LoadFromJSON(filename string) error {
bs.mu.Lock()
defer bs.mu.Unlock()
data, err := os.ReadFile(filename)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return fmt.Errorf("failed to read JSON: %w", err)
}
if len(data) == 0 {
return nil
}
// Create slice of pointers to T
sliceType := reflect.SliceOf(reflect.PointerTo(bs.itemType))
slicePtr := reflect.New(sliceType)
if err := json.Unmarshal(data, slicePtr.Interface()); err != nil {
return fmt.Errorf("failed to unmarshal JSON: %w", err)
}
// Clear existing data
bs.items = make(map[int]*T)
bs.maxID = 0
// Clear unique indices
for fieldName := range bs.uniqueIndices {
bs.uniqueIndices[fieldName] = make(map[any]int)
}
// Extract items using reflection
slice := slicePtr.Elem()
for i := 0; i < slice.Len(); i++ {
item := slice.Index(i).Interface().(*T)
// Get ID using reflection
itemValue := reflect.ValueOf(item).Elem()
idField := itemValue.FieldByName("ID")
if !idField.IsValid() {
return fmt.Errorf("item type must have an ID field")
}
id := int(idField.Int())
bs.items[id] = item
if id > bs.maxID {
bs.maxID = id
}
// Update unique indices
bs.updateUniqueIndices(id, item, true)
}
return nil
}
func (bs *BaseStore[T]) SaveToJSON(filename string) error {
bs.mu.RLock()
defer bs.mu.RUnlock()
// Get sorted IDs for consistent ordering
ids := make([]int, 0, len(bs.items))
for id := range bs.items {
ids = append(ids, id)
}
sort.Ints(ids)
// Build items slice in ID order
items := make([]*T, 0, len(bs.items))
for _, id := range ids {
items = append(items, bs.items[id])
}
data, err := json.MarshalIndent(items, "", "\t")
if err != nil {
return fmt.Errorf("failed to marshal to JSON: %w", err)
}
// Atomic write
tempFile := filename + ".tmp"
if err := os.WriteFile(tempFile, data, 0644); err != nil {
return fmt.Errorf("failed to write temp JSON: %w", err)
}
if err := os.Rename(tempFile, filename); err != nil {
os.Remove(tempFile)
return fmt.Errorf("failed to rename temp JSON: %w", err)
}
return nil
}
func (bs *BaseStore[T]) LoadData(dataPath string) error {
if err := bs.LoadFromJSON(dataPath); err != nil {
if os.IsNotExist(err) {
fmt.Println("No existing data found, starting with empty store")
return nil
}
return fmt.Errorf("failed to load from JSON: %w", err)
}
fmt.Printf("Loaded %d items from %s\n", len(bs.items), dataPath)
bs.RebuildIndices()
return nil
}
func (bs *BaseStore[T]) SaveData(dataPath string) error {
dataDir := filepath.Dir(dataPath)
if err := os.MkdirAll(dataDir, 0755); err != nil {
return fmt.Errorf("failed to create data directory: %w", err)
}
if err := bs.SaveToJSON(dataPath); err != nil {
return fmt.Errorf("failed to save to JSON: %w", err)
}
fmt.Printf("Saved %d items to %s\n", len(bs.items), dataPath)
return nil
}