package store import ( "fmt" "sync" "github.com/google/uuid" ) type IDer interface { GetID() string SetID(string) } type Hasher interface { GetHash() string } type Storable interface { IDer Hasher } type Storer[T Storable] interface { Create(T) (T, error) ReadAll() []T Read(string) (T, error) Update(T, string) (T, error) Delete(string) (T, error) } type FilterStorer[T Storable] interface { Storer[T] Filter([]T, func(T) bool) []T } type Store[T Storable] struct { ids map[string]T hashes map[string]T lock sync.RWMutex } type FilterStore[T Storable] struct { *Store[T] } func NewFilterStore[T Storable]() *FilterStore[T] { return &FilterStore[T]{NewStore[T]()} } func (fs *FilterStore[T]) Filter(slice []T, f func(T) bool) []T { result := make([]T, 0) for _, item := range slice { if f(item) { result = append(result, item) } } return result } func NewStore[T Storable]() *Store[T] { store := new(Store[T]) store.ids = make(map[string]T) store.hashes = make(map[string]T) return store } func (s *Store[T]) Create(entity T) (T, error) { s.lock.Lock() defer s.lock.Unlock() if hash := entity.GetHash(); hash != "" { storedEntity, ok := s.hashes[hash] if ok { return storedEntity, nil } s.hashes[hash] = entity } id := entity.GetID() if id == "" { id = uuid.New().String() } entity.SetID(id) s.ids[id] = entity return entity, nil } func (s *Store[T]) ReadAll() []T { s.lock.Lock() defer s.lock.Unlock() result := make([]T, 0) for _, v := range s.ids { result = append(result, v) } return result } func (s *Store[T]) Read(id string) (T, error) { s.lock.RLock() defer s.lock.RUnlock() entity, ok := s.ids[id] if !ok { return entity, fmt.Errorf("Entity with ID %s was not found in the store.", id) } return entity, nil } func (s *Store[T]) Update(entity T, id string) (T, error) { sEntity, err := s.Read(id) if err != nil { return sEntity, err } s.lock.Lock() defer s.lock.Unlock() entity.SetID(id) s.ids[id] = entity if hash := entity.GetHash(); hash != "" { s.hashes[hash] = entity } return entity, nil } func (s *Store[T]) Delete(id string) (T, error) { sEntity, err := s.Read(id) if err != nil { return sEntity, err } s.lock.Lock() defer s.lock.Unlock() delete(s.ids, id) if hash := sEntity.GetHash(); hash != "" { delete(s.hashes, hash) } return sEntity, nil }