@@ -4,14 +4,16 @@ mod test;
4
4
use serde:: Deserialize ;
5
5
6
6
use crate :: {
7
- bson:: { doc, Document } ,
7
+ bson:: doc,
8
8
cmap:: { Command , CommandResponse , StreamDescription } ,
9
9
coll:: { options:: EstimatedDocumentCountOptions , Namespace } ,
10
- error:: Result ,
11
- operation:: { append_options, Operation , Retryability } ,
10
+ error:: { Error , ErrorKind , Result } ,
11
+ operation:: { append_options, CursorBody , Operation , Retryability } ,
12
12
selection_criteria:: SelectionCriteria ,
13
13
} ;
14
14
15
+ const SERVER_4_9_0_WIRE_VERSION : i32 = 12 ;
16
+
15
17
pub ( crate ) struct Count {
16
18
ns : Namespace ,
17
19
options : Option < EstimatedDocumentCountOptions > ,
@@ -38,9 +40,30 @@ impl Operation for Count {
38
40
type O = i64 ;
39
41
const NAME : & ' static str = "count" ;
40
42
41
- fn build ( & self , _description : & StreamDescription ) -> Result < Command > {
42
- let mut body: Document = doc ! {
43
- Self :: NAME : self . ns. coll. clone( ) ,
43
+ fn build ( & self , description : & StreamDescription ) -> Result < Command > {
44
+ let mut body = match description. max_wire_version {
45
+ Some ( v) if v >= SERVER_4_9_0_WIRE_VERSION => {
46
+ doc ! {
47
+ "aggregate" : self . ns. coll. clone( ) ,
48
+ "pipeline" : [
49
+ {
50
+ "$collStats" : { "count" : { } } ,
51
+ } ,
52
+ {
53
+ "$group" : {
54
+ "_id" : 1 ,
55
+ "n" : { "$sum" : "$count" } ,
56
+ } ,
57
+ } ,
58
+ ] ,
59
+ "cursor" : { } ,
60
+ }
61
+ }
62
+ _ => {
63
+ doc ! {
64
+ Self :: NAME : self . ns. coll. clone( ) ,
65
+ }
66
+ }
44
67
} ;
45
68
46
69
append_options ( & mut body, self . options . as_ref ( ) ) ?;
@@ -52,8 +75,37 @@ impl Operation for Count {
52
75
) )
53
76
}
54
77
55
- fn handle_response ( & self , response : CommandResponse ) -> Result < Self :: O > {
56
- response. body :: < ResponseBody > ( ) . map ( |body| body. n )
78
+ fn handle_response (
79
+ & self ,
80
+ response : CommandResponse ,
81
+ description : & StreamDescription ,
82
+ ) -> Result < Self :: O > {
83
+ let response_body: ResponseBody = match description. max_wire_version {
84
+ Some ( v) if v >= SERVER_4_9_0_WIRE_VERSION => {
85
+ let CursorBody { mut cursor } = response. body ( ) ?;
86
+
87
+ cursor
88
+ . first_batch
89
+ . pop_front ( )
90
+ . and_then ( |doc| bson:: from_document ( doc) . ok ( ) )
91
+ . ok_or_else ( || {
92
+ Error :: from ( ErrorKind :: ResponseError {
93
+ message : "invalid server response to count operation" . into ( ) ,
94
+ } )
95
+ } ) ?
96
+ }
97
+ _ => response. body ( ) ?,
98
+ } ;
99
+
100
+ Ok ( response_body. n )
101
+ }
102
+
103
+ fn handle_error ( & self , error : Error ) -> Result < Self :: O > {
104
+ if error. is_ns_not_found ( ) {
105
+ Ok ( 0 )
106
+ } else {
107
+ Err ( error)
108
+ }
57
109
}
58
110
59
111
fn selection_criteria ( & self ) -> Option < & SelectionCriteria > {
0 commit comments