1
- import { command , CommandOptions } from './command' ;
2
- import { Query } from '../commands' ;
3
- import { MongoError } from '../../error' ;
4
- import { maxWireVersion , collectionNamespace , Callback , decorateWithExplain } from '../../utils' ;
5
- import { getReadPreference , isSharded , applyCommonQueryOptions } from './shared' ;
6
- import { Document , pluckBSONSerializeOptions } from '../../bson' ;
1
+ import { OpQueryOptions , Query } from '../commands' ;
2
+ import type { Callback , MongoDBNamespace } from '../../utils' ;
3
+ import { BSONSerializeOptions , Document , pluckBSONSerializeOptions } from '../../bson' ;
7
4
import type { Server } from '../../sdam/server' ;
8
- import type { ReadPreferenceLike } from '../../read_preference' ;
9
- import type { FindOptions } from '../../operations/find' ;
10
- import { Explain } from '../../explain' ;
5
+ import { ReadPreference } from '../../read_preference' ;
11
6
12
7
/** @internal */
13
- export interface QueryOptions extends CommandOptions {
14
- readPreference ?: ReadPreferenceLike ;
8
+ export interface QueryOptions extends BSONSerializeOptions {
9
+ readPreference : ReadPreference ;
10
+ documentsReturnedIn ?: string ;
11
+ batchSize ?: number ;
12
+ limit ?: number ;
13
+ skip ?: number ;
14
+ projection ?: Document ;
15
+ tailable ?: boolean ;
16
+ awaitData ?: boolean ;
17
+ noCursorTimeout ?: boolean ;
18
+ /** @deprecated use `noCursorTimeout` instead */
19
+ timeout ?: boolean ;
20
+ partial ?: boolean ;
21
+ oplogReplay ?: boolean ;
15
22
}
16
23
17
24
export function query (
18
25
server : Server ,
19
- ns : string ,
20
- cmd : Document ,
21
- options : FindOptions ,
26
+ ns : MongoDBNamespace ,
27
+ findCommand : Document ,
28
+ options : QueryOptions ,
22
29
callback : Callback
23
30
) : void {
24
31
options = options || { } ;
25
32
26
- if ( cmd == null ) {
27
- return callback ( new MongoError ( `command ${ JSON . stringify ( cmd ) } does not return a cursor` ) ) ;
28
- }
29
-
30
- if ( maxWireVersion ( server ) < 4 ) {
31
- const query = prepareLegacyFindQuery ( server , ns , cmd , options ) ;
32
- const queryOptions = applyCommonQueryOptions (
33
- { } ,
34
- Object . assign ( options , { ...pluckBSONSerializeOptions ( options ) } )
35
- ) ;
36
-
37
- queryOptions . fullResult = true ;
38
- if ( typeof query . documentsReturnedIn === 'string' ) {
39
- queryOptions . documentsReturnedIn = query . documentsReturnedIn ;
40
- }
41
-
42
- server . s . pool . write ( query , queryOptions , callback ) ;
43
- return ;
44
- }
45
-
46
- const readPreference = getReadPreference ( cmd , options ) ;
47
- let findCmd = prepareFindCommand ( server , ns , cmd ) ;
48
-
49
- // If we have explain, we need to rewrite the find command
50
- // to wrap it in the explain command
51
- const explain = Explain . fromOptions ( options ) ;
52
- if ( explain ) {
53
- findCmd = decorateWithExplain ( findCmd , explain ) ;
54
- }
55
-
56
- // NOTE: This actually modifies the passed in cmd, and our code _depends_ on this
57
- // side-effect. Change this ASAP
58
- cmd . virtual = false ;
59
-
60
- const commandOptions = Object . assign (
61
- {
62
- documentsReturnedIn : 'firstBatch' ,
63
- numberToReturn : 1 ,
64
- slaveOk : readPreference . slaveOk ( )
65
- } ,
66
- options
67
- ) ;
68
-
69
- command ( server , ns , findCmd , commandOptions , callback ) ;
70
- }
71
-
72
- function prepareFindCommand ( server : Server , ns : string , cmd : Document ) {
73
- const findCmd : Document = {
74
- find : collectionNamespace ( ns )
75
- } ;
76
-
77
- if ( cmd . query ) {
78
- if ( cmd . query [ '$query' ] ) {
79
- findCmd . filter = cmd . query [ '$query' ] ;
80
- } else {
81
- findCmd . filter = cmd . query ;
82
- }
83
- }
84
-
85
- let sortValue = cmd . sort ;
86
- if ( Array . isArray ( sortValue ) ) {
87
- const sortObject : Document = { } ;
88
-
89
- if ( sortValue . length > 0 && ! Array . isArray ( sortValue [ 0 ] ) ) {
90
- let sortDirection = sortValue [ 1 ] ;
91
- if ( sortDirection === 'asc' ) {
92
- sortDirection = 1 ;
93
- } else if ( sortDirection === 'desc' ) {
94
- sortDirection = - 1 ;
95
- }
96
-
97
- sortObject [ sortValue [ 0 ] ] = sortDirection ;
98
- } else {
99
- for ( let i = 0 ; i < sortValue . length ; i ++ ) {
100
- let sortDirection = sortValue [ i ] [ 1 ] ;
101
- if ( sortDirection === 'asc' ) {
102
- sortDirection = 1 ;
103
- } else if ( sortDirection === 'desc' ) {
104
- sortDirection = - 1 ;
105
- }
106
-
107
- sortObject [ sortValue [ i ] [ 0 ] ] = sortDirection ;
108
- }
109
- }
110
-
111
- sortValue = sortObject ;
112
- }
113
-
114
- if ( typeof cmd . allowDiskUse === 'boolean' ) {
115
- findCmd . allowDiskUse = cmd . allowDiskUse ;
116
- }
117
-
118
- if ( cmd . sort ) findCmd . sort = sortValue ;
119
- if ( cmd . fields ) findCmd . projection = cmd . fields ;
120
- if ( cmd . hint ) findCmd . hint = cmd . hint ;
121
- if ( cmd . skip ) findCmd . skip = cmd . skip ;
122
- if ( cmd . limit ) findCmd . limit = cmd . limit ;
123
- if ( cmd . limit < 0 ) {
124
- findCmd . limit = Math . abs ( cmd . limit ) ;
125
- findCmd . singleBatch = true ;
126
- }
127
-
128
- if ( typeof cmd . batchSize === 'number' ) {
129
- if ( cmd . batchSize < 0 ) {
130
- if ( cmd . limit !== 0 && Math . abs ( cmd . batchSize ) < Math . abs ( cmd . limit ) ) {
131
- findCmd . limit = Math . abs ( cmd . batchSize ) ;
132
- }
133
-
134
- findCmd . singleBatch = true ;
135
- }
136
-
137
- findCmd . batchSize = Math . abs ( cmd . batchSize ) ;
138
- }
139
-
140
- if ( cmd . comment ) findCmd . comment = cmd . comment ;
141
- if ( cmd . maxScan ) findCmd . maxScan = cmd . maxScan ;
142
- if ( cmd . maxTimeMS ) findCmd . maxTimeMS = cmd . maxTimeMS ;
143
- if ( cmd . min ) findCmd . min = cmd . min ;
144
- if ( cmd . max ) findCmd . max = cmd . max ;
145
- findCmd . returnKey = cmd . returnKey ? cmd . returnKey : false ;
146
- findCmd . showRecordId = cmd . showDiskLoc ? cmd . showDiskLoc : false ;
147
- if ( cmd . snapshot ) findCmd . snapshot = cmd . snapshot ;
148
- if ( cmd . tailable ) findCmd . tailable = cmd . tailable ;
149
- if ( cmd . oplogReplay ) findCmd . oplogReplay = cmd . oplogReplay ;
150
- if ( cmd . noCursorTimeout ) findCmd . noCursorTimeout = cmd . noCursorTimeout ;
151
- if ( cmd . awaitData ) findCmd . awaitData = cmd . awaitData ;
152
- if ( cmd . awaitdata ) findCmd . awaitData = cmd . awaitdata ;
153
- if ( cmd . partial ) findCmd . partial = cmd . partial ;
154
- if ( cmd . collation ) findCmd . collation = cmd . collation ;
155
- if ( cmd . readConcern ) findCmd . readConcern = cmd . readConcern ;
156
-
157
- return findCmd ;
158
- }
159
-
160
- function prepareLegacyFindQuery (
161
- server : Server ,
162
- ns : string ,
163
- cmd : Document ,
164
- options : FindOptions
165
- ) : Query {
166
- options = options || { } ;
167
-
168
- const readPreference = getReadPreference ( cmd , options ) ;
169
- const batchSize = cmd . batchSize || options . batchSize || 0 ;
170
- const limit = cmd . limit || options . limit ;
171
- const numberToSkip = cmd . skip || options . skip || 0 ;
172
-
33
+ const isExplain = typeof findCommand . $explain !== 'undefined' ;
34
+ const readPreference = options . readPreference ?? ReadPreference . primary ;
35
+ const batchSize = options . batchSize || 0 ;
36
+ const limit = options . limit ;
37
+ const numberToSkip = options . skip || 0 ;
173
38
let numberToReturn = 0 ;
174
39
if (
175
40
limit &&
@@ -180,66 +45,57 @@ function prepareLegacyFindQuery(
180
45
numberToReturn = batchSize ;
181
46
}
182
47
183
- const findCmd : Document = { } ;
184
- if ( isSharded ( server ) && readPreference ) {
185
- findCmd [ '$readPreference' ] = readPreference . toJSON ( ) ;
48
+ if ( isExplain ) {
49
+ // nToReturn must be 0 (match all) or negative (match N and close cursor)
50
+ // nToReturn > 0 will give explain results equivalent to limit(0)
51
+ numberToReturn = - Math . abs ( limit || 0 ) ;
186
52
}
187
53
188
- if ( cmd . sort ) findCmd [ '$orderby' ] = cmd . sort ;
189
- if ( cmd . hint ) findCmd [ '$hint' ] = cmd . hint ;
190
- if ( cmd . snapshot ) findCmd [ '$snapshot' ] = cmd . snapshot ;
191
- if ( typeof cmd . returnKey !== 'undefined' ) findCmd [ '$returnKey' ] = cmd . returnKey ;
192
- if ( cmd . maxScan ) findCmd [ '$maxScan' ] = cmd . maxScan ;
193
- if ( cmd . min ) findCmd [ '$min' ] = cmd . min ;
194
- if ( cmd . max ) findCmd [ '$max' ] = cmd . max ;
195
- if ( typeof cmd . showDiskLoc !== 'undefined' ) {
196
- findCmd [ '$showDiskLoc' ] = cmd . showDiskLoc ;
197
- } else if ( typeof cmd . showRecordId !== 'undefined' ) {
198
- findCmd [ '$showDiskLoc' ] = cmd . showRecordId ;
54
+ const queryOptions : OpQueryOptions = {
55
+ numberToSkip,
56
+ numberToReturn,
57
+ pre32Limit : typeof limit === 'number' ? limit : undefined ,
58
+ checkKeys : false ,
59
+ slaveOk : readPreference . slaveOk ( )
60
+ } ;
61
+
62
+ if ( options . projection ) {
63
+ queryOptions . returnFieldSelector = options . projection ;
199
64
}
200
65
201
- if ( cmd . comment ) findCmd [ '$comment' ] = cmd . comment ;
202
- if ( cmd . maxTimeMS ) findCmd [ '$maxTimeMS' ] = cmd . maxTimeMS ;
203
- if ( options . explain ) {
204
- // nToReturn must be 0 (match all) or negative (match N and close cursor)
205
- // nToReturn > 0 will give explain results equivalent to limit(0)
206
- numberToReturn = - Math . abs ( cmd . limit || 0 ) ;
207
- findCmd [ '$explain' ] = true ;
66
+ const query = new Query ( ns . toString ( ) , findCommand , queryOptions ) ;
67
+ if ( typeof options . tailable === 'boolean' ) {
68
+ query . tailable = options . tailable ;
208
69
}
209
70
210
- findCmd [ '$query' ] = cmd . query ;
211
- if ( cmd . readConcern && cmd . readConcern . level !== 'local' ) {
212
- throw new MongoError (
213
- `server find command does not support a readConcern level of ${ cmd . readConcern . level } `
214
- ) ;
71
+ if ( typeof options . oplogReplay === 'boolean' ) {
72
+ query . oplogReplay = options . oplogReplay ;
215
73
}
216
74
217
- if ( cmd . readConcern ) {
218
- cmd = Object . assign ( { } , cmd ) ;
219
- delete cmd [ 'readConcern' ] ;
75
+ if ( typeof options . timeout === 'boolean' ) {
76
+ query . noCursorTimeout = options . timeout ;
77
+ } else if ( typeof options . noCursorTimeout === 'boolean' ) {
78
+ query . noCursorTimeout = options . noCursorTimeout ;
220
79
}
221
80
222
- const serializeFunctions =
223
- typeof options . serializeFunctions === 'boolean' ? options . serializeFunctions : false ;
224
- const ignoreUndefined =
225
- typeof options . ignoreUndefined === 'boolean' ? options . ignoreUndefined : false ;
81
+ if ( typeof options . awaitData === 'boolean' ) {
82
+ query . awaitData = options . awaitData ;
83
+ }
226
84
227
- const query = new Query ( ns , findCmd , {
228
- numberToSkip,
229
- numberToReturn,
230
- pre32Limit : typeof limit === 'number' ? limit : undefined ,
231
- checkKeys : false ,
232
- returnFieldSelector : cmd . fields ,
233
- serializeFunctions,
234
- ignoreUndefined
235
- } ) ;
85
+ if ( typeof options . partial === 'boolean' ) {
86
+ query . partial = options . partial ;
87
+ }
236
88
237
- if ( typeof cmd . tailable === 'boolean' ) query . tailable = cmd . tailable ;
238
- if ( typeof cmd . oplogReplay === 'boolean' ) query . oplogReplay = cmd . oplogReplay ;
239
- if ( typeof cmd . noCursorTimeout === 'boolean' ) query . noCursorTimeout = cmd . noCursorTimeout ;
240
- if ( typeof cmd . awaitData === 'boolean' ) query . awaitData = cmd . awaitData ;
241
- if ( typeof cmd . partial === 'boolean' ) query . partial = cmd . partial ;
89
+ server . s . pool . write (
90
+ query ,
91
+ { fullResult : true , ...pluckBSONSerializeOptions ( options ) } ,
92
+ ( err , result ) => {
93
+ if ( err || ! result ) return callback ( err , result ) ;
94
+ if ( isExplain && result . documents && result . documents [ 0 ] ) {
95
+ return callback ( undefined , result . documents [ 0 ] ) ;
96
+ }
242
97
243
- query . slaveOk = readPreference . slaveOk ( ) ;
244
- return query ;
98
+ callback ( undefined , result ) ;
99
+ }
100
+ ) ;
245
101
}
0 commit comments