Skip to content

Commit 3ed6d21

Browse files
committed
util: create MapE utility function
Epic: None Release note: None
1 parent b328729 commit 3ed6d21

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

pkg/util/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ go_test(
5656
deps = [
5757
"//pkg/util/randutil",
5858
"//pkg/util/timeutil",
59+
"@com_github_cockroachdb_errors//:errors",
5960
"@com_github_stretchr_testify//require",
6061
],
6162
)

pkg/util/slices.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ func Map[T, K any](collection []T, fn func(T) K) []K {
8080
return out
8181
}
8282

83+
// MapE returns a new slice containing the results of fn for each element
84+
// within a collection. If fn returns an error for any element, the function
85+
// exits early and returns the error.
86+
func MapE[T, K any](collection []T, fn func(T) (K, error)) ([]K, error) {
87+
out := make([]K, len(collection))
88+
for i, el := range collection {
89+
value, err := fn(el)
90+
if err != nil {
91+
return nil, err
92+
}
93+
out[i] = value
94+
}
95+
return out, nil
96+
}
97+
8398
// MapFrom returns a map populated with keys and values returned by fn.
8499
// Usage:
85100
//

pkg/util/slices_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package util
88
import (
99
"testing"
1010

11+
"github.com/cockroachdb/errors"
1112
"github.com/stretchr/testify/require"
1213
)
1314

@@ -123,6 +124,46 @@ func TestMap(t *testing.T) {
123124
}))
124125
}
125126

127+
func TestMapErr(t *testing.T) {
128+
t.Run("empty slice", func(t *testing.T) {
129+
out, err := MapE(nil, func(i int) (int, error) {
130+
require.Fail(t, "should not be called")
131+
return 0, nil
132+
})
133+
require.NoError(t, err)
134+
require.Equal(t, []int{}, out)
135+
})
136+
137+
t.Run("map to same type", func(t *testing.T) {
138+
out, err := MapE([]int{1, 2, 3}, func(i int) (int, error) {
139+
return i * 2, nil
140+
})
141+
require.NoError(t, err)
142+
require.Equal(t, []int{2, 4, 6}, out)
143+
})
144+
145+
t.Run("map to different type", func(t *testing.T) {
146+
out, err := MapE([]int{1, 2, 3}, func(i int) (string, error) {
147+
return string(rune('a' + i - 1)), nil
148+
})
149+
require.NoError(t, err)
150+
require.Equal(t, []string{"a", "b", "c"}, out)
151+
})
152+
153+
t.Run("error case", func(t *testing.T) {
154+
out, err := MapE([]int{1, 2, 3}, func(i int) (int, error) {
155+
if i == 2 {
156+
return 0, errors.New("error on 2")
157+
} else if i == 3 {
158+
require.Fail(t, "should not be called")
159+
}
160+
return i * 2, nil
161+
})
162+
require.Error(t, err)
163+
require.Nil(t, out)
164+
})
165+
}
166+
126167
func TestMapFrom(t *testing.T) {
127168
require.Equal(t, map[int]bool{}, MapFrom(nil, func(i int) (int, bool) {
128169
require.Fail(t, "should not be called")

0 commit comments

Comments
 (0)