Skip to content

Commit 1ff4ce5

Browse files
committed
Ensure MappingIterables delegate to wrapped iterable
JAVA-2894
1 parent 25cabc3 commit 1ff4ce5

File tree

4 files changed

+166
-12
lines changed

4 files changed

+166
-12
lines changed

driver-async/src/main/com/mongodb/async/client/MappingIterable.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
import com.mongodb.Block;
2020
import com.mongodb.Function;
21-
import com.mongodb.async.SingleResultCallback;
2221
import com.mongodb.async.AsyncBatchCursor;
22+
import com.mongodb.async.SingleResultCallback;
2323

2424
import java.util.Collection;
2525

@@ -34,10 +34,6 @@ class MappingIterable<U, V> implements MongoIterable<V> {
3434
this.mapper = notNull("mapper", mapper);
3535
}
3636

37-
MongoIterable<U> getMapped() {
38-
return iterable;
39-
}
40-
4137
@Override
4238
public void first(final SingleResultCallback<V> callback) {
4339
notNull("callback", callback);
@@ -46,6 +42,8 @@ public void first(final SingleResultCallback<V> callback) {
4642
public void onResult(final U result, final Throwable t) {
4743
if (t != null) {
4844
callback.onResult(null, t);
45+
} else if (result == null) {
46+
callback.onResult(null, null);
4947
} else {
5048
callback.onResult(mapper.apply(result), null);
5149
}
@@ -125,4 +123,8 @@ public void onResult(final AsyncBatchCursor<U> batchCursor, final Throwable t) {
125123
}
126124
});
127125
}
126+
127+
MongoIterable<U> getMapped() {
128+
return iterable;
129+
}
128130
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.async.client
18+
19+
import com.mongodb.Block
20+
import com.mongodb.Function
21+
import com.mongodb.async.SingleResultCallback
22+
import spock.lang.Specification
23+
24+
import static com.mongodb.CustomMatchers.isTheSameAs
25+
import static spock.util.matcher.HamcrestSupport.expect
26+
27+
class MappingIterableSpecification extends Specification {
28+
29+
def 'should follow the MongoIterable interface as expected'() {
30+
given:
31+
def callback = Stub(SingleResultCallback)
32+
def iterable = Mock(MongoIterable)
33+
def mapper = { doc -> doc }
34+
def mappingIterable = new MappingIterable(iterable, mapper)
35+
36+
when:
37+
mappingIterable.first(callback)
38+
39+
then:
40+
1 * iterable.first(_)
41+
42+
when:
43+
mappingIterable.forEach( { } as Block, callback)
44+
45+
then:
46+
1 * iterable.forEach(_, _)
47+
48+
when:
49+
mappingIterable.into([], callback)
50+
51+
then:
52+
1 * iterable.forEach(_, _) // Use foreach to populate the target
53+
54+
when:
55+
mappingIterable.batchSize(5)
56+
57+
then:
58+
1 * iterable.batchSize(5)
59+
60+
when:
61+
mappingIterable.getBatchSize()
62+
63+
then:
64+
1 * iterable.getBatchSize() >> 5
65+
66+
when:
67+
mappingIterable.batchCursor(callback)
68+
69+
then:
70+
1 * iterable.batchCursor(_)
71+
72+
when:
73+
def newMapper = { } as Function
74+
75+
then:
76+
expect mappingIterable.map(newMapper), isTheSameAs(new MappingIterable(mappingIterable, newMapper))
77+
}
78+
79+
}

driver-sync/src/main/com/mongodb/client/internal/MappingIterable.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ class MappingIterable<U, V> implements MongoIterable<V> {
3434
this.mapper = mapper;
3535
}
3636

37-
MongoIterable<U> getMapped() {
38-
return iterable;
39-
}
40-
4137
@Override
4238
public MongoCursor<V> iterator() {
4339
return new MongoMappingCursor<U, V>(iterable.iterator(), mapper);
@@ -46,11 +42,11 @@ public MongoCursor<V> iterator() {
4642
@Nullable
4743
@Override
4844
public V first() {
49-
MongoCursor<V> iterator = iterator();
50-
if (!iterator.hasNext()) {
45+
U first = iterable.first();
46+
if (first == null) {
5147
return null;
5248
}
53-
return iterator.next();
49+
return mapper.apply(first);
5450
}
5551

5652
@Override
@@ -84,4 +80,8 @@ public MappingIterable<U, V> batchSize(final int batchSize) {
8480
public <W> MongoIterable<W> map(final Function<V, W> newMap) {
8581
return new MappingIterable<V, W>(this, newMap);
8682
}
83+
84+
MongoIterable<U> getMapped() {
85+
return iterable;
86+
}
8787
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.client.internal
18+
19+
import com.mongodb.Block
20+
import com.mongodb.Function
21+
import com.mongodb.client.MongoCursor
22+
import com.mongodb.client.MongoIterable
23+
import spock.lang.Specification
24+
25+
import static com.mongodb.CustomMatchers.isTheSameAs
26+
import static spock.util.matcher.HamcrestSupport.expect
27+
28+
class MappingIterableSpecification extends Specification {
29+
30+
def 'should follow the MongoIterable interface as expected'() {
31+
given:
32+
def iterable = Mock(MongoIterable)
33+
def mapper = { doc -> doc }
34+
def mappingIterable = new MappingIterable(iterable, mapper)
35+
36+
when:
37+
mappingIterable.first()
38+
39+
then:
40+
1 * iterable.first()
41+
42+
when:
43+
mappingIterable.forEach( { } as Block)
44+
45+
then:
46+
1 * iterable.forEach(_)
47+
48+
when:
49+
mappingIterable.into([])
50+
51+
then:
52+
1 * iterable.forEach(_) // Use foreach to populate the target
53+
54+
when:
55+
mappingIterable.batchSize(5)
56+
57+
then:
58+
1 * iterable.batchSize(5)
59+
60+
when:
61+
mappingIterable.iterator()
62+
63+
then:
64+
1 * iterable.iterator() >> Stub(MongoCursor)
65+
66+
when:
67+
def newMapper = { } as Function
68+
69+
then:
70+
expect mappingIterable.map(newMapper), isTheSameAs(new MappingIterable(mappingIterable, newMapper))
71+
}
72+
73+
}

0 commit comments

Comments
 (0)