Skip to content

Commit 9754325

Browse files
author
Divjot Arora
committed
Iterator implementation for bson/array
GODRIVER-293 Change-Id: I60ead2ab754fed4a3dc2999dc21e9efe23247721
1 parent 95b9288 commit 9754325

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

bson/array.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,9 @@ func (a *Array) MarshalBSON() ([]byte, error) {
328328
}
329329
return b, nil
330330
}
331+
332+
// Iterator returns a ArrayIterator that can be used to iterate through the
333+
// elements of this Array.
334+
func (a *Array) Iterator() (*ArrayIterator, error) {
335+
return NewArrayIterator(a)
336+
}

bson/array_iterator.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package bson
2+
3+
// ArrayIterator facilitates iterating over a bson.Array.
4+
type ArrayIterator struct {
5+
array *Array
6+
pos uint
7+
val *Value
8+
err error
9+
}
10+
11+
// NewArrayIterator constructs a new ArrayIterator over a given Array
12+
func NewArrayIterator(array *Array) (*ArrayIterator, error) {
13+
iter := &ArrayIterator{}
14+
iter.array = array
15+
16+
return iter, nil
17+
}
18+
19+
// Next fetches the next value in the Array, returning whether or not it could be fetched successfully. If true is
20+
// returned, call Value to get the value. If false is returned, call Err to check if an error occurred.
21+
func (iter *ArrayIterator) Next() bool {
22+
v, err := iter.array.Lookup(iter.pos)
23+
24+
if err != nil {
25+
// error if out of bounds
26+
// don't assign iter.err
27+
return false
28+
}
29+
30+
_, err = v.validate(false)
31+
if err != nil {
32+
iter.err = err
33+
return false
34+
}
35+
36+
iter.val = v
37+
iter.pos++
38+
39+
return true
40+
}
41+
42+
// Value returns the current value of the ArrayIterator. The pointer returned will _always_ be the same for a given
43+
// ArrayIterator. The returned value will be nil if this function is called before the first successful call to Next().
44+
func (iter *ArrayIterator) Value() *Value {
45+
return iter.val
46+
}
47+
48+
// Err returns the error that occurred while iterating, or nil if none occurred.
49+
func (iter *ArrayIterator) Err() error {
50+
return iter.err
51+
}

bson/array_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,54 @@ func TestArray(t *testing.T) {
222222
})
223223
}
224224
})
225+
t.Run("Iterator", func(t *testing.T) {
226+
iteratorTests := []struct {
227+
name string
228+
values [][]*Value
229+
}{
230+
{"one-one", tapag.oneOne()},
231+
{"two-one", tapag.twoOne()},
232+
}
233+
234+
for _, tc := range iteratorTests {
235+
t.Run(tc.name, func(t *testing.T) {
236+
a := NewArray()
237+
for _, elems := range tc.values {
238+
a.Prepend(elems...)
239+
}
240+
241+
iter, err := a.Iterator()
242+
if err != nil {
243+
t.Errorf("Got error creating array iterator: %s", err)
244+
}
245+
246+
for _, elem := range tc.values {
247+
if !iter.Next() {
248+
t.Errorf("ArrayIterator.Next() returned false")
249+
}
250+
251+
if err = iter.Err(); err != nil {
252+
t.Errorf("ArrayIterator.Err() returned non-nil error: %s", err)
253+
}
254+
255+
for _, val := range elem {
256+
got := iter.Value()
257+
if !valueEqual(got, val) {
258+
t.Errorf("Returned element does not match expected element. got %#v; want %#v", got, val)
259+
}
260+
}
261+
}
262+
263+
if iter.Next() {
264+
t.Errorf("ArrayIterator.Next() returned true. expected false")
265+
}
266+
267+
if err = iter.Err(); err != nil {
268+
t.Errorf("ArrayIterator.Err() returned non-nil error: %s", err)
269+
}
270+
})
271+
}
272+
})
225273
}
226274

227275
type testArrayPrependAppendGenerator struct{}

0 commit comments

Comments
 (0)