4040import com .mongodb .operation .OperationHelper .CallableWithConnectionAndSource ;
4141import org .bson .BsonBoolean ;
4242import org .bson .BsonDocument ;
43+ import org .bson .BsonDocumentReader ;
4344import org .bson .BsonInt32 ;
4445import org .bson .BsonInt64 ;
4546import org .bson .BsonString ;
4647import org .bson .BsonValue ;
4748import org .bson .codecs .BsonDocumentCodec ;
4849import org .bson .codecs .Decoder ;
50+ import org .bson .codecs .DecoderContext ;
4951
52+ import java .util .Collections ;
5053import java .util .HashMap ;
5154import java .util .List ;
5255import java .util .Map ;
6568import static com .mongodb .operation .OperationHelper .cursorDocumentToQueryResult ;
6669import static com .mongodb .operation .OperationHelper .releasingCallback ;
6770import static com .mongodb .operation .OperationHelper .serverIsAtLeastVersionThreeDotTwo ;
68- import static com .mongodb .operation .OperationHelper .serverIsAtLeastVersionThreeDotZero ;
6971import static com .mongodb .operation .OperationHelper .withConnection ;
7072
7173/**
@@ -482,7 +484,8 @@ public BatchCursor<T> execute(final ReadBinding binding) {
482484 public BatchCursor <T > call (final ConnectionSource source , final Connection connection ) {
483485 if (serverIsAtLeastVersionThreeDotTwo (connection .getDescription ())) {
484486 try {
485- return executeWrappedCommandProtocol (binding , namespace .getDatabaseName (), asCommandDocument (),
487+ return executeWrappedCommandProtocol (binding , namespace .getDatabaseName (),
488+ wrapInExplainIfNecessary (asCommandDocument ()),
486489 CommandResultDocumentCodec .create (decoder , FIRST_BATCH ),
487490 connection , transformer (source , connection ));
488491 } catch (MongoCommandException e ) {
@@ -518,7 +521,8 @@ public void call(final AsyncConnectionSource source, final AsyncConnection conne
518521 errorHandlingCallback (callback ).onResult (null , t );
519522 } else {
520523 if (serverIsAtLeastVersionThreeDotTwo (connection .getDescription ())) {
521- executeWrappedCommandProtocolAsync (binding , namespace .getDatabaseName (), asCommandDocument (),
524+ executeWrappedCommandProtocolAsync (binding , namespace .getDatabaseName (),
525+ wrapInExplainIfNecessary (asCommandDocument ()),
522526 CommandResultDocumentCodec .create (decoder , FIRST_BATCH ),
523527 connection , asyncTransformer (source , connection ),
524528 releasingCallback (exceptionTransformingCallback (errorHandlingCallback (callback )),
@@ -595,7 +599,7 @@ public BsonDocument call(final ConnectionSource connectionSource, final Connecti
595599 connectionSource .getServerDescription (),
596600 connection );
597601 try {
598- if (serverIsAtLeastVersionThreeDotZero (connection .getDescription ())) {
602+ if (serverIsAtLeastVersionThreeDotTwo (connection .getDescription ())) {
599603 try {
600604 return new CommandReadOperation <BsonDocument >(getNamespace ().getDatabaseName (),
601605 new BsonDocument ("explain" , asCommandDocument ()),
@@ -800,6 +804,18 @@ private BsonDocument asCommandDocument() {
800804 return document ;
801805 }
802806
807+ private BsonDocument wrapInExplainIfNecessary (final BsonDocument findCommandDocument ) {
808+ if (isExplain ()) {
809+ return new BsonDocument ("explain" , findCommandDocument );
810+ } else {
811+ return findCommandDocument ;
812+ }
813+ }
814+
815+ private boolean isExplain () {
816+ return modifiers != null && modifiers .get ("$explain" , BsonBoolean .FALSE ).equals (BsonBoolean .TRUE );
817+ }
818+
803819 private boolean isTailableCursor () {
804820 return cursorType .isTailable ();
805821 }
@@ -808,13 +824,12 @@ private boolean isAwaitData() {
808824 return cursorType == CursorType .TailableAwait ;
809825 }
810826
811- private CommandTransformer <BsonDocument , BatchCursor <T >> transformer (final ConnectionSource source , final Connection
812- connection ) {
827+ private CommandTransformer <BsonDocument , BatchCursor <T >> transformer (final ConnectionSource source ,
828+ final Connection connection ) {
813829 return new CommandTransformer <BsonDocument , BatchCursor <T >>() {
814830 @ Override
815831 public BatchCursor <T > apply (final BsonDocument result , final ServerAddress serverAddress ) {
816- QueryResult <T > queryResult = cursorDocumentToQueryResult (result .getDocument ("cursor" ),
817- connection .getDescription ().getServerAddress ());
832+ QueryResult <T > queryResult = documentToQueryResult (result , serverAddress );
818833 return new QueryBatchCursor <T >(queryResult , limit , batchSize , getMaxTimeForCursor (), decoder , source , connection );
819834 }
820835 };
@@ -825,17 +840,27 @@ private long getMaxTimeForCursor() {
825840 }
826841
827842 private CommandTransformer <BsonDocument , AsyncBatchCursor <T >> asyncTransformer (final AsyncConnectionSource source ,
828- final AsyncConnection connection ) {
843+ final AsyncConnection connection ) {
829844 return new CommandTransformer <BsonDocument , AsyncBatchCursor <T >>() {
830845 @ Override
831846 public AsyncBatchCursor <T > apply (final BsonDocument result , final ServerAddress serverAddress ) {
832- QueryResult <T > queryResult = cursorDocumentToQueryResult (result .getDocument ("cursor" ),
833- connection .getDescription ().getServerAddress ());
847+ QueryResult <T > queryResult = documentToQueryResult (result , serverAddress );
834848 return new AsyncQueryBatchCursor <T >(queryResult , limit , batchSize , getMaxTimeForCursor (), decoder , source , connection );
835849 }
836850 };
837851 }
838852
853+ private QueryResult <T > documentToQueryResult (final BsonDocument result , final ServerAddress serverAddress ) {
854+ QueryResult <T > queryResult ;
855+ if (isExplain ()) {
856+ T decodedDocument = decoder .decode (new BsonDocumentReader (result ), DecoderContext .builder ().build ());
857+ queryResult = new QueryResult <T >(getNamespace (), Collections .singletonList (decodedDocument ), 0 , serverAddress );
858+ } else {
859+ queryResult = cursorDocumentToQueryResult (result .getDocument ("cursor" ), serverAddress );
860+ }
861+ return queryResult ;
862+ }
863+
839864 private static class ExplainResultCallback implements SingleResultCallback <AsyncBatchCursor <BsonDocument >> {
840865 private final SingleResultCallback <BsonDocument > callback ;
841866
0 commit comments