package data import ( "encoding/json" "errors" "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 } func (repo *DefaultRepository[T]) GetByCriteria(c ISearchCriteria[T]) ([]T, error) { // TODO return nil, nil }