159 líneas
2,4 KiB
Go
159 líneas
2,4 KiB
Go
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
|
|
}
|