135 lines
4.1 KiB
Go
135 lines
4.1 KiB
Go
package data
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
// Default implementation of IRepository using an IDatastore.
|
|
type DefaultRepository[T IIdentifiable] struct {
|
|
ds IDatastore
|
|
prefix string
|
|
}
|
|
|
|
// Creates a new DefaultRepository for a generic type T given a IDatastore and
|
|
// a prefix. The type T must implement the IIdentifiable interface. The prefix
|
|
// will be used for the key for every entry using the created repository. The
|
|
// prefix should be not yet be in use in the given datastore and not contain a
|
|
// ':' character.
|
|
func NewDefaultRepository[T IIdentifiable](ds IDatastore, prefix string) (*DefaultRepository[T], error) {
|
|
if strings.Contains(prefix, ":") { return nil, errors.New("prefix should not contain ':'") }
|
|
return &DefaultRepository[T]{ ds: ds, prefix: prefix }, nil
|
|
}
|
|
|
|
// Creates a new entry in the repository with the given object t. Throws an
|
|
// error if there already exists an entry with the same id, the json encoding
|
|
// fails or the connection to the IDatastore fails.
|
|
func (repo *DefaultRepository[T]) Create(t T) error {
|
|
key := repo.prefix + ":" + t.Id()
|
|
exists, err := repo.ds.KeyExists(key)
|
|
if err != nil { return err }
|
|
if exists { return errors.New("entry with given id already exists") }
|
|
|
|
d, err := json.Marshal(t)
|
|
if err != nil { return err }
|
|
|
|
err = repo.ds.Set(key, string(d))
|
|
if err != nil { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
// Updates the entry with the same id as t in the repository with the values of
|
|
// t. Trows an error if the json encoding fails or the connection to the
|
|
// IDatastore fails.
|
|
func (repo *DefaultRepository[T]) Update(t T) error {
|
|
key := repo.prefix + ":" + t.Id()
|
|
exists, err := repo.ds.KeyExists(key)
|
|
if err != nil { return err }
|
|
if !exists { return errors.New("no entry with given id") }
|
|
|
|
d, err := json.Marshal(t)
|
|
if err != nil { return err }
|
|
|
|
err = repo.ds.Set(key, string(d))
|
|
if err != nil { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
// Delete the entry with the same id as t in the repository. Trows an error if
|
|
// the connection to the IDatastore fails or the key of t does not exist.
|
|
func (repo *DefaultRepository[T]) Delete(t T) error {
|
|
key := repo.prefix + ":" + t.Id()
|
|
|
|
exists, err := repo.ds.KeyExists(key)
|
|
if err != nil { return err }
|
|
if !exists { return errors.New("no entry with given id") }
|
|
|
|
err = repo.ds.Delete(key)
|
|
if err != nil { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
// Get all the objects of type T from the repository as a list. Trows an error
|
|
// if the connection to the IDatastore fails.
|
|
func (repo *DefaultRepository[T]) GetAll() ([]T, error) {
|
|
out := make([]T, 0)
|
|
|
|
allkeys, err := repo.ds.GetAllKeys()
|
|
if err != nil { return nil, err }
|
|
|
|
for key, _ := range allkeys {
|
|
splitkey := strings.Split(key, ":")
|
|
if splitkey[0] == repo.prefix {
|
|
|
|
// retrieve the object
|
|
obj, err := repo.GetById(splitkey[1])
|
|
if err != nil { return nil, err }
|
|
out = append(out, obj)
|
|
|
|
}
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
// Get the objects of type T from the repository that has the given id. Trows an error
|
|
// if the connection to the IDatastore or the decoding process fails.
|
|
func (repo *DefaultRepository[T]) GetById(id string) (T, error) {
|
|
var obj T
|
|
|
|
key := repo.prefix + ":" + id
|
|
value, err := repo.ds.Get(key)
|
|
if err != nil { return obj, err }
|
|
|
|
err = json.Unmarshal([]byte(value), &obj)
|
|
if err != nil { return obj, err }
|
|
|
|
return obj, nil
|
|
}
|
|
|
|
// Returns a slice of all elememts in the repo that have a
|
|
// ISearchCriteria.Weight greater than 0 sort by that weight. Throws an error
|
|
// when the elememts cannot be retrieved from the repo.
|
|
func (repo *DefaultRepository[T]) GetByCriteria(c ISortCriteria[T]) ([]T, error) {
|
|
all, err := repo.GetAll()
|
|
if err != nil { return nil, err }
|
|
|
|
filtered := make([]T, 0)
|
|
for _, elem := range all {
|
|
if c.Weight(elem) > 0 { filtered = append(filtered, elem) }
|
|
}
|
|
|
|
slices.SortFunc(filtered, func(a, b T) int {
|
|
wa, wb := c.Weight(a), c.Weight(b)
|
|
if wa > wb { return -1 }
|
|
return 1
|
|
})
|
|
|
|
return filtered, nil
|
|
}
|