From f329b6ed45c13da782ac3d3b42e09ba01f9eb9c2 Mon Sep 17 00:00:00 2001 From: Charly Fau Date: Fri, 24 Jun 2022 13:28:53 -0300 Subject: [PATCH] Fix return of find in repositories to error instead of boolean to be more generic Add more methods to list --- lists/generators.go | 16 +++++ lists/lists.go | 89 ++++++++++++++++++++++++++++ nils/nils.go | 9 +++ repositories/in_memory_repository.go | 8 +-- types/types.go | 9 +++ 5 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 lists/generators.go create mode 100644 nils/nils.go diff --git a/lists/generators.go b/lists/generators.go new file mode 100644 index 0000000..87c0617 --- /dev/null +++ b/lists/generators.go @@ -0,0 +1,16 @@ +package lists + +// Generate use provided generator to generate array of N elements +func Generate[T any](times int, generator func(i int) T) []T { + if times <= 0 { + return []T{} + } + + elements := make([]T, times) + + for idx := range elements { + elements[idx] = generator(idx) + } + + return elements +} diff --git a/lists/lists.go b/lists/lists.go index 7726277..e792816 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -16,6 +16,19 @@ func Map[S any, T any](ss []S, m types.Mapper[S, T]) []T { return tt } +// MapNonNil apply mapper to all elements of 'ss' and return slice of all non-nil results +func MapNonNil[S any, T any](ss []S, mapper types.Mapper[S, *T]) []*T { + us := make([]*T, len(ss)) + + for idx, s := range ss { + if t := mapper(s); t != nil { + us[idx] = t + } + } + + return us +} + func FlatMap[S any, T any](ss []S, m types.Mapper[S, []T]) []T { tt := make([]T, 0, len(ss)) for _, s := range ss { @@ -34,6 +47,37 @@ func Filter[S any](ss []S, p types.Predicate[S]) []S { return tt } +// FilterNot removes (filter out) all elements the satisfies predicate +func FilterNot[S any](ss []S, p types.Predicate[S]) []S { + var tt []S + for _, s := range ss { + if !p(s) { + tt = append(tt, s) + } + } + return tt +} + +// Remove all occurrences of the given element from the slice +func Remove[T types.Comparable[T]](ts []T, toRemove T) []T { + return FilterNot(ts, func(t T) bool { return toRemove.Compare(t) == 0 }) +} + +// Any returns true if at lease one element satisfies predicate +func Any[T any](ts []T, predicate func(t T) bool) bool { + for _, t := range ts { + if predicate(t) { + return true + } + } + return false +} + +// FilterNonNil returns all the elements of array that are non nil +func FilterNonNil[T any](ts []*T) []*T { + return Filter(ts, func(t *T) bool { return t != nil }) +} + func Count[S any](ss []S, p types.Predicate[S]) int { var count = 0 for _, s := range ss { @@ -81,3 +125,48 @@ func IndexBy2[S any](ss []S, p types.Predicate[S]) (int, bool) { idx := IndexBy(ss, p) return idx, idx >= 0 } + +func Has[T types.Comparable[T]](ts []T, other T) bool { + for _, t := range ts { + if t.Compare(other) == 0 { + return true + } + } + return false +} + +func Has2[T comparable](ts []T, other T) bool { + for _, t := range ts { + if t == other { + return true + } + } + return false +} + +func DeepCloneSlice[T types.Cloneable[T]](source []T) []T { + return Map(source, func(t T) T { return t.Clone() }) +} + +func CloneSlice[T any](source []T) []T { + target := make([]T, len(source)) + + copy(target, source) + + return target +} + +func Reduce[Value any, Element any]( + initialValue Value, + elements []Element, + reducer func(Value, Element) Value, +) Value { + + accum := initialValue + + for _, element := range elements { + accum = reducer(accum, element) + } + + return accum +} diff --git a/nils/nils.go b/nils/nils.go new file mode 100644 index 0000000..45f4649 --- /dev/null +++ b/nils/nils.go @@ -0,0 +1,9 @@ +package nils + +func IsNil(t *any) bool { + return t == nil +} + +func IsNotNil(t *any) bool { + return t != nil +} diff --git a/repositories/in_memory_repository.go b/repositories/in_memory_repository.go index f221d1b..5750c66 100644 --- a/repositories/in_memory_repository.go +++ b/repositories/in_memory_repository.go @@ -85,21 +85,21 @@ func (r *InMemoryRepository[Key, Entity]) Delete(key Key) error { return nil } -func (r *InMemoryRepository[Key, Entity]) FindById(key Key) (Entity, bool) { +func (r *InMemoryRepository[Key, Entity]) FindById(key Key) (Entity, error) { r.lock.RLock() defer r.lock.RUnlock() r.init() if !r.AllowEmptyKey && key == r.emptyKey { var entity Entity - return entity, false + return entity, invalidKey } if entity, found := r.elementsById[key]; found { - return entity, true + return entity, nil } var empty Entity - return empty, false + return empty, notFound } func (r *InMemoryRepository[Key, Entity]) FindBy(predicate types.Predicate[Entity]) []Entity { diff --git a/types/types.go b/types/types.go index e1be863..1b9f9ec 100644 --- a/types/types.go +++ b/types/types.go @@ -14,3 +14,12 @@ type Iterable[T any] interface { ForEach(Function1[T]) Iterator() Iterator[T] } + +type Cloneable[T any] interface { + Clone() T +} + +type Comparable[T any] interface { + // Compare returns -1, 0, 1 if this is less than, equal to, to greater than other + Compare(other T) int +}