196 lines
4.4 KiB
Go
196 lines
4.4 KiB
Go
package nigiri
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
)
|
|
|
|
// StoreManager interface for stores that can load/save
|
|
type StoreManager interface {
|
|
LoadData(path string) error
|
|
SaveData(path string) error
|
|
Clear()
|
|
}
|
|
|
|
// Collection manages multiple stores in a directory
|
|
type Collection struct {
|
|
baseDir string
|
|
stores map[string]StoreManager
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// NewCollection creates a new collection in the specified directory
|
|
func NewCollection(baseDir string) *Collection {
|
|
return &Collection{
|
|
baseDir: baseDir,
|
|
stores: make(map[string]StoreManager),
|
|
}
|
|
}
|
|
|
|
// Register adds a store to the collection with a given name
|
|
func (c *Collection) Register(name string, store StoreManager) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
c.stores[name] = store
|
|
}
|
|
|
|
// Unregister removes a store from the collection
|
|
func (c *Collection) Unregister(name string) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
delete(c.stores, name)
|
|
}
|
|
|
|
// GetStore retrieves a registered store by name
|
|
func (c *Collection) GetStore(name string) (StoreManager, bool) {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
store, exists := c.stores[name]
|
|
return store, exists
|
|
}
|
|
|
|
// LoadAll loads all registered stores from their JSON files
|
|
func (c *Collection) LoadAll() error {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
if err := os.MkdirAll(c.baseDir, 0755); err != nil {
|
|
return fmt.Errorf("failed to create base directory: %w", err)
|
|
}
|
|
|
|
var firstError error
|
|
for name, store := range c.stores {
|
|
path := filepath.Join(c.baseDir, name+".json")
|
|
if err := store.LoadData(path); err != nil && firstError == nil {
|
|
firstError = fmt.Errorf("failed to load %s: %w", name, err)
|
|
}
|
|
}
|
|
|
|
return firstError
|
|
}
|
|
|
|
// SaveAll saves all registered stores to their JSON files
|
|
func (c *Collection) SaveAll() error {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
if err := os.MkdirAll(c.baseDir, 0755); err != nil {
|
|
return fmt.Errorf("failed to create base directory: %w", err)
|
|
}
|
|
|
|
var firstError error
|
|
for name, store := range c.stores {
|
|
path := filepath.Join(c.baseDir, name+".json")
|
|
if err := store.SaveData(path); err != nil && firstError == nil {
|
|
firstError = fmt.Errorf("failed to save %s: %w", name, err)
|
|
}
|
|
}
|
|
|
|
return firstError
|
|
}
|
|
|
|
// LoadStore loads a specific store by name
|
|
func (c *Collection) LoadStore(name string) error {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
store, exists := c.stores[name]
|
|
if !exists {
|
|
return fmt.Errorf("store %s not registered", name)
|
|
}
|
|
|
|
path := filepath.Join(c.baseDir, name+".json")
|
|
return store.LoadData(path)
|
|
}
|
|
|
|
// SaveStore saves a specific store by name
|
|
func (c *Collection) SaveStore(name string) error {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
store, exists := c.stores[name]
|
|
if !exists {
|
|
return fmt.Errorf("store %s not registered", name)
|
|
}
|
|
|
|
if err := os.MkdirAll(c.baseDir, 0755); err != nil {
|
|
return fmt.Errorf("failed to create base directory: %w", err)
|
|
}
|
|
|
|
path := filepath.Join(c.baseDir, name+".json")
|
|
return store.SaveData(path)
|
|
}
|
|
|
|
// ClearAll clears all registered stores
|
|
func (c *Collection) ClearAll() {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
for _, store := range c.stores {
|
|
store.Clear()
|
|
}
|
|
}
|
|
|
|
// ClearStore clears a specific store by name
|
|
func (c *Collection) ClearStore(name string) error {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
store, exists := c.stores[name]
|
|
if !exists {
|
|
return fmt.Errorf("store %s not registered", name)
|
|
}
|
|
|
|
store.Clear()
|
|
return nil
|
|
}
|
|
|
|
// ListStores returns names of all registered stores
|
|
func (c *Collection) ListStores() []string {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
names := make([]string, 0, len(c.stores))
|
|
for name := range c.stores {
|
|
names = append(names, name)
|
|
}
|
|
return names
|
|
}
|
|
|
|
// GetPath returns the file path for a store name
|
|
func (c *Collection) GetPath(name string) string {
|
|
return filepath.Join(c.baseDir, name+".json")
|
|
}
|
|
|
|
// StoreExists checks if a store file exists on disk
|
|
func (c *Collection) StoreExists(name string) bool {
|
|
path := c.GetPath(name)
|
|
_, err := os.Stat(path)
|
|
return err == nil
|
|
}
|
|
|
|
// RemoveStoreFile removes the JSON file for a store
|
|
func (c *Collection) RemoveStoreFile(name string) error {
|
|
path := c.GetPath(name)
|
|
err := os.Remove(path)
|
|
if os.IsNotExist(err) {
|
|
return nil // Already doesn't exist
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Helper function to create typed store accessor
|
|
func GetTypedStore[T any](collection *Collection, name string) (*BaseStore[T], bool) {
|
|
store, exists := collection.GetStore(name)
|
|
if !exists {
|
|
return nil, false
|
|
}
|
|
|
|
if typedStore, ok := store.(*BaseStore[T]); ok {
|
|
return typedStore, true
|
|
}
|
|
return nil, false
|
|
}
|