package nigiri import ( "fmt" "os" "path/filepath" "regexp" "sync" ) type StoreManager interface { LoadData(path string) error SaveData(path string) error Clear() EntityExists(id int) bool SetValidator(validator any) } type Collection struct { baseDir string stores map[string]StoreManager migrator *Migrator mu sync.RWMutex } func NewCollection(baseDir string) *Collection { return &Collection{ baseDir: baseDir, stores: make(map[string]StoreManager), migrator: nil, // Lazy initialized } } // Add registers store and auto-loads if file exists func (c *Collection) Add(name string, store StoreManager) error { c.mu.Lock() defer c.mu.Unlock() c.stores[name] = store store.SetValidator(c) // Auto-load if file exists path := filepath.Join(c.baseDir, name+".json") if _, err := os.Stat(path); err == nil { return store.LoadData(path) } return nil } // Get returns typed store func Get[T any](c *Collection, name string) *BaseStore[T] { c.mu.RLock() defer c.mu.RUnlock() if store, exists := c.stores[name]; exists { if typed, ok := store.(*BaseStore[T]); ok { return typed } } return nil } // Load loads all stores func (c *Collection) Load() error { c.mu.RLock() defer c.mu.RUnlock() os.MkdirAll(c.baseDir, 0755) for name, store := range c.stores { path := filepath.Join(c.baseDir, name+".json") if err := store.LoadData(path); err != nil { return fmt.Errorf("load %s: %w", name, err) } } return nil } // Save saves all stores func (c *Collection) Save() error { c.mu.RLock() defer c.mu.RUnlock() os.MkdirAll(c.baseDir, 0755) for name, store := range c.stores { path := filepath.Join(c.baseDir, name+".json") if err := store.SaveData(path); err != nil { return fmt.Errorf("save %s: %w", name, err) } } return nil } // Clear clears all stores func (c *Collection) Clear() { c.mu.RLock() defer c.mu.RUnlock() for _, store := range c.stores { store.Clear() } } // EntityExists implements relationship validation func (c *Collection) EntityExists(entityName string, id int) bool { c.mu.RLock() defer c.mu.RUnlock() if store, exists := c.stores[entityName]; exists { return store.EntityExists(id) } return false } // Migration methods func (c *Collection) GetMigrator() *Migrator { if c.migrator == nil { c.migrator = NewMigrator() } return c.migrator } func (c *Collection) RegisterMigrationCommand(name string, pattern *regexp.Regexp, handler MigrationHandler) { c.GetMigrator().RegisterCommand(name, pattern, handler) } func (c *Collection) MigrateStore(storeName, command string) error { c.mu.Lock() defer c.mu.Unlock() path := filepath.Join(c.baseDir, storeName+".json") return c.GetMigrator().MigrateFile(path, command) } func (c *Collection) RunMigrationScript(scriptFile string) error { return c.GetMigrator().RunScript(c.baseDir, scriptFile) } func (c *Collection) CreateMigrationCLI() *MigrationCLI { return NewMigrationCLI(c) }