Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/20251209161427.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:sparkles: `[collection]` Added a helper `ForAll` to iterate over a whole collection but returned an aggregated error
27 changes: 27 additions & 0 deletions utils/collection/search.go → utils/collection/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,33 @@ func ForEach[S ~[]E, E any](s S, f func(E)) {
})
}

// ForAll iterates over every element in the provided sequence and invokes f
// on each item in order. If f returns an error for one or more elements,
// ForAll continues processing the remaining elements and returns a single
// aggregated error containing all collected errors. If no errors occur, the returned error is nil.
func ForAll[S ~[]E, E any](s S, f func(E) error) error {
return ForAllSequence[E](slices.Values(s), f)
}

// ForAllSequence iterates over every element in the provided sequence and invokes f
// on each item in order. If f returns an error for one or more elements,
// ForAllSequence continues processing the remaining elements and returns a single
// aggregated error containing all collected errors. If no errors occur, the returned error is nil.
func ForAllSequence[T any](s iter.Seq[T], f func(T) error) error {
var err error
err = commonerrors.Join(err, Each[T](s, func(e T) error {
subErr := f(e)
if commonerrors.Any(subErr, commonerrors.ErrEOF) {
return subErr
}
if subErr != nil {
err = commonerrors.Join(err, commonerrors.Newf(subErr, "error during iteration over value [%v]", e))
}
return nil
}))
return err
}

// Each iterates over a sequence and executes the passed function against each element.
// If passed func returns an error, the iteration stops and the error is returned, unless it is EOF.
func Each[T any](s iter.Seq[T], f func(T) error) error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,28 @@ func TestForEachSequence(t *testing.T) {
}))
assert.ElementsMatch(t, visited, []int{9, 22, 35, 48, 61, 74, 87, 100, 113, 126, 139})
}

func TestForAll(t *testing.T) {
var visited []int
list := Range(9, 1000, field.ToOptionalInt(13))
errortest.AssertError(t, ForAll(list, func(i int) error {
visited = append(visited, i)
if i > 150 {
return commonerrors.ErrUnsupported
}
return nil
}), commonerrors.ErrUnsupported)
assert.ElementsMatch(t, visited, []int{9, 22, 35, 48, 61, 74, 87, 100, 113, 126, 139, 152, 165, 178, 191, 204, 217, 230, 243, 256, 269, 282, 295, 308, 321, 334, 347, 360, 373, 386, 399, 412, 425, 438, 451, 464, 477, 490, 503, 516, 529, 542, 555, 568, 581, 594, 607, 620, 633, 646, 659, 672, 685, 698, 711, 724, 737, 750, 763, 776, 789, 802, 815, 828, 841, 854, 867, 880, 893, 906, 919, 932, 945, 958, 971, 984, 997})
visited = []int{}
assert.NoError(t, ForAll(list, func(i int) error {
visited = append(visited, i)
if i > 150 {
return commonerrors.ErrEOF
}
return nil
}))
assert.ElementsMatch(t, visited, []int{9, 22, 35, 48, 61, 74, 87, 100, 113, 126, 139, 152})
assert.NoError(t, ForAll(list, func(i int) error {
return nil
}))
}
Loading