mongodb 3.2.5 → 3.3.0-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +0 -10
- package/index.js +4 -4
- package/lib/admin.js +56 -56
- package/lib/aggregation_cursor.js +7 -3
- package/lib/bulk/common.js +18 -13
- package/lib/change_stream.js +196 -89
- package/lib/collection.js +217 -169
- package/lib/command_cursor.js +17 -7
- package/lib/core/auth/auth_provider.js +158 -0
- package/lib/core/auth/defaultAuthProviders.js +29 -0
- package/lib/core/auth/gssapi.js +241 -0
- package/lib/core/auth/mongo_credentials.js +81 -0
- package/lib/core/auth/mongocr.js +51 -0
- package/lib/core/auth/plain.js +35 -0
- package/lib/core/auth/scram.js +293 -0
- package/lib/core/auth/sspi.js +131 -0
- package/lib/core/auth/x509.js +26 -0
- package/lib/core/connection/apm.js +236 -0
- package/lib/core/connection/command_result.js +36 -0
- package/lib/core/connection/commands.js +507 -0
- package/lib/core/connection/connect.js +370 -0
- package/lib/core/connection/connection.js +624 -0
- package/lib/core/connection/logger.js +246 -0
- package/lib/core/connection/msg.js +219 -0
- package/lib/core/connection/pool.js +1285 -0
- package/lib/core/connection/utils.js +57 -0
- package/lib/core/cursor.js +752 -0
- package/lib/core/error.js +186 -0
- package/lib/core/index.js +50 -0
- package/lib/core/sdam/monitoring.js +228 -0
- package/lib/core/sdam/server.js +467 -0
- package/lib/core/sdam/server_description.js +163 -0
- package/lib/core/sdam/server_selectors.js +244 -0
- package/lib/core/sdam/srv_polling.js +135 -0
- package/lib/core/sdam/topology.js +1151 -0
- package/lib/core/sdam/topology_description.js +408 -0
- package/lib/core/sessions.js +711 -0
- package/lib/core/tools/smoke_plugin.js +61 -0
- package/lib/core/topologies/mongos.js +1337 -0
- package/lib/core/topologies/read_preference.js +202 -0
- package/lib/core/topologies/replset.js +1507 -0
- package/lib/core/topologies/replset_state.js +1121 -0
- package/lib/core/topologies/server.js +984 -0
- package/lib/core/topologies/shared.js +453 -0
- package/lib/core/transactions.js +167 -0
- package/lib/core/uri_parser.js +631 -0
- package/lib/core/utils.js +165 -0
- package/lib/core/wireprotocol/command.js +170 -0
- package/lib/core/wireprotocol/compression.js +73 -0
- package/lib/core/wireprotocol/constants.js +13 -0
- package/lib/core/wireprotocol/get_more.js +86 -0
- package/lib/core/wireprotocol/index.js +18 -0
- package/lib/core/wireprotocol/kill_cursors.js +70 -0
- package/lib/core/wireprotocol/query.js +224 -0
- package/lib/core/wireprotocol/shared.js +115 -0
- package/lib/core/wireprotocol/write_command.js +50 -0
- package/lib/cursor.js +40 -46
- package/lib/db.js +141 -95
- package/lib/dynamic_loaders.js +32 -0
- package/lib/error.js +12 -10
- package/lib/gridfs/chunk.js +2 -2
- package/lib/gridfs/grid_store.js +31 -25
- package/lib/gridfs-stream/index.js +4 -4
- package/lib/gridfs-stream/upload.js +1 -1
- package/lib/mongo_client.js +37 -15
- package/lib/operations/add_user.js +96 -0
- package/lib/operations/aggregate.js +24 -13
- package/lib/operations/aggregate_operation.js +127 -0
- package/lib/operations/bulk_write.js +104 -0
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +28 -287
- package/lib/operations/collections.js +55 -0
- package/lib/operations/command.js +120 -0
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/common_functions.js +372 -0
- package/lib/operations/{mongo_client_ops.js → connect.js} +185 -157
- package/lib/operations/count.js +72 -0
- package/lib/operations/count_documents.js +46 -0
- package/lib/operations/create_collection.js +118 -0
- package/lib/operations/create_index.js +92 -0
- package/lib/operations/create_indexes.js +61 -0
- package/lib/operations/cursor_ops.js +3 -4
- package/lib/operations/db_ops.js +15 -12
- package/lib/operations/delete_many.js +25 -0
- package/lib/operations/delete_one.js +25 -0
- package/lib/operations/distinct.js +85 -0
- package/lib/operations/drop.js +53 -0
- package/lib/operations/drop_index.js +42 -0
- package/lib/operations/drop_indexes.js +23 -0
- package/lib/operations/estimated_document_count.js +33 -0
- package/lib/operations/execute_db_admin_command.js +34 -0
- package/lib/operations/execute_operation.js +165 -0
- package/lib/operations/explain.js +23 -0
- package/lib/operations/find_and_modify.js +98 -0
- package/lib/operations/find_one.js +33 -0
- package/lib/operations/find_one_and_delete.js +16 -0
- package/lib/operations/find_one_and_replace.js +18 -0
- package/lib/operations/find_one_and_update.js +19 -0
- package/lib/operations/geo_haystack_search.js +79 -0
- package/lib/operations/has_next.js +40 -0
- package/lib/operations/index_exists.js +39 -0
- package/lib/operations/index_information.js +23 -0
- package/lib/operations/indexes.js +22 -0
- package/lib/operations/insert_many.js +63 -0
- package/lib/operations/insert_one.js +75 -0
- package/lib/operations/is_capped.js +19 -0
- package/lib/operations/list_indexes.js +66 -0
- package/lib/operations/map_reduce.js +189 -0
- package/lib/operations/next.js +32 -0
- package/lib/operations/operation.js +63 -0
- package/lib/operations/options_operation.js +32 -0
- package/lib/operations/profiling_level.js +31 -0
- package/lib/operations/re_index.js +28 -0
- package/lib/operations/remove_user.js +52 -0
- package/lib/operations/rename.js +61 -0
- package/lib/operations/replace_one.js +47 -0
- package/lib/operations/set_profiling_level.js +48 -0
- package/lib/operations/stats.js +45 -0
- package/lib/operations/to_array.js +68 -0
- package/lib/operations/update_many.js +29 -0
- package/lib/operations/update_one.js +44 -0
- package/lib/operations/validate_collection.js +40 -0
- package/lib/read_concern.js +55 -0
- package/lib/topologies/mongos.js +3 -3
- package/lib/topologies/native_topology.js +22 -2
- package/lib/topologies/replset.js +3 -3
- package/lib/topologies/server.js +4 -4
- package/lib/topologies/topology_base.js +6 -6
- package/lib/url_parser.js +4 -3
- package/lib/utils.js +46 -59
- package/lib/write_concern.js +66 -0
- package/package.json +15 -6
- package/lib/.DS_Store +0 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const EventEmitter = require('events');
|
|
3
|
+
const MongoError = require('../error').MongoError;
|
|
4
|
+
const Pool = require('../connection/pool');
|
|
5
|
+
const relayEvents = require('../utils').relayEvents;
|
|
6
|
+
const wireProtocol = require('../wireprotocol');
|
|
7
|
+
const BSON = require('../connection/utils').retrieveBSON();
|
|
8
|
+
const createClientInfo = require('../topologies/shared').createClientInfo;
|
|
9
|
+
const Logger = require('../connection/logger');
|
|
10
|
+
const ServerDescription = require('./server_description').ServerDescription;
|
|
11
|
+
const ReadPreference = require('../topologies/read_preference');
|
|
12
|
+
const monitorServer = require('./monitoring').monitorServer;
|
|
13
|
+
const MongoParseError = require('../error').MongoParseError;
|
|
14
|
+
const MongoNetworkError = require('../error').MongoNetworkError;
|
|
15
|
+
const collationNotSupported = require('../utils').collationNotSupported;
|
|
16
|
+
const debugOptions = require('../connection/utils').debugOptions;
|
|
17
|
+
const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
|
|
18
|
+
|
|
19
|
+
// Used for filtering out fields for logging
|
|
20
|
+
const DEBUG_FIELDS = [
|
|
21
|
+
'reconnect',
|
|
22
|
+
'reconnectTries',
|
|
23
|
+
'reconnectInterval',
|
|
24
|
+
'emitError',
|
|
25
|
+
'cursorFactory',
|
|
26
|
+
'host',
|
|
27
|
+
'port',
|
|
28
|
+
'size',
|
|
29
|
+
'keepAlive',
|
|
30
|
+
'keepAliveInitialDelay',
|
|
31
|
+
'noDelay',
|
|
32
|
+
'connectionTimeout',
|
|
33
|
+
'checkServerIdentity',
|
|
34
|
+
'socketTimeout',
|
|
35
|
+
'ssl',
|
|
36
|
+
'ca',
|
|
37
|
+
'crl',
|
|
38
|
+
'cert',
|
|
39
|
+
'key',
|
|
40
|
+
'rejectUnauthorized',
|
|
41
|
+
'promoteLongs',
|
|
42
|
+
'promoteValues',
|
|
43
|
+
'promoteBuffers',
|
|
44
|
+
'servername'
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const STATE_DISCONNECTED = 0;
|
|
48
|
+
const STATE_CONNECTING = 1;
|
|
49
|
+
const STATE_CONNECTED = 2;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
*
|
|
53
|
+
* @fires Server#serverHeartbeatStarted
|
|
54
|
+
* @fires Server#serverHeartbeatSucceeded
|
|
55
|
+
* @fires Server#serverHeartbeatFailed
|
|
56
|
+
*/
|
|
57
|
+
class Server extends EventEmitter {
|
|
58
|
+
/**
|
|
59
|
+
* Create a server
|
|
60
|
+
*
|
|
61
|
+
* @param {ServerDescription} description
|
|
62
|
+
* @param {Object} options
|
|
63
|
+
*/
|
|
64
|
+
constructor(description, options, topology) {
|
|
65
|
+
super();
|
|
66
|
+
|
|
67
|
+
this.s = {
|
|
68
|
+
// the server description
|
|
69
|
+
description,
|
|
70
|
+
// a saved copy of the incoming options
|
|
71
|
+
options,
|
|
72
|
+
// the server logger
|
|
73
|
+
logger: Logger('Server', options),
|
|
74
|
+
// the bson parser
|
|
75
|
+
bson: options.bson || new BSON(),
|
|
76
|
+
// client metadata for the initial handshake
|
|
77
|
+
clientInfo: createClientInfo(options),
|
|
78
|
+
// state variable to determine if there is an active server check in progress
|
|
79
|
+
monitoring: false,
|
|
80
|
+
// the implementation of the monitoring method
|
|
81
|
+
monitorFunction: options.monitorFunction || monitorServer,
|
|
82
|
+
// the connection pool
|
|
83
|
+
pool: null,
|
|
84
|
+
// the server state
|
|
85
|
+
state: STATE_DISCONNECTED,
|
|
86
|
+
credentials: options.credentials,
|
|
87
|
+
topology
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get description() {
|
|
92
|
+
return this.s.description;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get name() {
|
|
96
|
+
return this.s.description.address;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get autoEncrypter() {
|
|
100
|
+
if (this.s.options && this.s.options.autoEncrypter) {
|
|
101
|
+
return this.s.options.autoEncrypter;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Initiate server connect
|
|
108
|
+
*/
|
|
109
|
+
connect(options) {
|
|
110
|
+
options = options || {};
|
|
111
|
+
|
|
112
|
+
// do not allow connect to be called on anything that's not disconnected
|
|
113
|
+
if (this.s.pool && !this.s.pool.isDisconnected() && !this.s.pool.isDestroyed()) {
|
|
114
|
+
throw new MongoError(`Server instance in invalid state ${this.s.pool.state}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// create a pool
|
|
118
|
+
const addressParts = this.description.address.split(':');
|
|
119
|
+
const poolOptions = Object.assign(
|
|
120
|
+
{ host: addressParts[0], port: parseInt(addressParts[1], 10) },
|
|
121
|
+
this.s.options,
|
|
122
|
+
options,
|
|
123
|
+
{ bson: this.s.bson }
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// NOTE: this should only be the case if we are connecting to a single server
|
|
127
|
+
poolOptions.reconnect = true;
|
|
128
|
+
|
|
129
|
+
this.s.pool = new Pool(this, poolOptions);
|
|
130
|
+
|
|
131
|
+
// setup listeners
|
|
132
|
+
this.s.pool.on('connect', connectEventHandler(this));
|
|
133
|
+
this.s.pool.on('close', errorEventHandler(this));
|
|
134
|
+
this.s.pool.on('error', errorEventHandler(this));
|
|
135
|
+
this.s.pool.on('parseError', parseErrorEventHandler(this));
|
|
136
|
+
|
|
137
|
+
// it is unclear whether consumers should even know about these events
|
|
138
|
+
// this.s.pool.on('timeout', timeoutEventHandler(this));
|
|
139
|
+
// this.s.pool.on('reconnect', reconnectEventHandler(this));
|
|
140
|
+
// this.s.pool.on('reconnectFailed', errorEventHandler(this));
|
|
141
|
+
|
|
142
|
+
// relay all command monitoring events
|
|
143
|
+
relayEvents(this.s.pool, this, ['commandStarted', 'commandSucceeded', 'commandFailed']);
|
|
144
|
+
|
|
145
|
+
this.s.state = STATE_CONNECTING;
|
|
146
|
+
|
|
147
|
+
// If auth settings have been provided, use them
|
|
148
|
+
if (options.auth) {
|
|
149
|
+
this.s.pool.connect.apply(this.s.pool, options.auth);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.s.pool.connect();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Destroy the server connection
|
|
158
|
+
*
|
|
159
|
+
* @param {Boolean} [options.force=false] Force destroy the pool
|
|
160
|
+
*/
|
|
161
|
+
destroy(options, callback) {
|
|
162
|
+
if (typeof options === 'function') (callback = options), (options = {});
|
|
163
|
+
options = Object.assign({}, { force: false }, options);
|
|
164
|
+
|
|
165
|
+
const done = err => {
|
|
166
|
+
this.emit('closed');
|
|
167
|
+
this.s.state = STATE_DISCONNECTED;
|
|
168
|
+
if (typeof callback === 'function') {
|
|
169
|
+
callback(err, null);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
if (!this.s.pool) {
|
|
174
|
+
return done();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
['close', 'error', 'timeout', 'parseError', 'connect'].forEach(event => {
|
|
178
|
+
this.s.pool.removeAllListeners(event);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (this.s.monitorId) {
|
|
182
|
+
clearTimeout(this.s.monitorId);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.s.pool.destroy(options.force, done);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Immediately schedule monitoring of this server. If there already an attempt being made
|
|
190
|
+
* this will be a no-op.
|
|
191
|
+
*/
|
|
192
|
+
monitor(options) {
|
|
193
|
+
options = options || {};
|
|
194
|
+
if (this.s.state !== STATE_CONNECTED || this.s.monitoring) return;
|
|
195
|
+
if (this.s.monitorId) clearTimeout(this.s.monitorId);
|
|
196
|
+
this.s.monitorFunction(this, options);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Execute a command
|
|
201
|
+
*
|
|
202
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
203
|
+
* @param {object} cmd The command hash
|
|
204
|
+
* @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
|
|
205
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
206
|
+
* @param {Boolean} [options.checkKeys=false] Specify if the bson parser should validate keys.
|
|
207
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
208
|
+
* @param {Boolean} [options.fullResult=false] Return the full envelope instead of just the result document.
|
|
209
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
210
|
+
* @param {opResultCallback} callback A callback function
|
|
211
|
+
*/
|
|
212
|
+
command(ns, cmd, options, callback) {
|
|
213
|
+
if (typeof options === 'function') {
|
|
214
|
+
(callback = options), (options = {}), (options = options || {});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const error = basicReadValidations(this, options);
|
|
218
|
+
if (error) {
|
|
219
|
+
return callback(error, null);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Clone the options
|
|
223
|
+
options = Object.assign({}, options, { wireProtocolCommand: false });
|
|
224
|
+
|
|
225
|
+
// Debug log
|
|
226
|
+
if (this.s.logger.isDebug()) {
|
|
227
|
+
this.s.logger.debug(
|
|
228
|
+
`executing command [${JSON.stringify({
|
|
229
|
+
ns,
|
|
230
|
+
cmd,
|
|
231
|
+
options: debugOptions(DEBUG_FIELDS, options)
|
|
232
|
+
})}] against ${this.name}`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// error if collation not supported
|
|
237
|
+
if (collationNotSupported(this, cmd)) {
|
|
238
|
+
callback(new MongoError(`server ${this.name} does not support collation`));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
wireProtocol.command(this, ns, cmd, options, (err, result) => {
|
|
243
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
244
|
+
this.emit('error', err);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
callback(err, result);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Execute a query against the server
|
|
253
|
+
*
|
|
254
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
255
|
+
* @param {object} cmd The command document for the query
|
|
256
|
+
* @param {object} options Optional settings
|
|
257
|
+
* @param {function} callback
|
|
258
|
+
*/
|
|
259
|
+
query(ns, cmd, cursorState, options, callback) {
|
|
260
|
+
wireProtocol.query(this, ns, cmd, cursorState, options, (err, result) => {
|
|
261
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
262
|
+
this.emit('error', err);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
callback(err, result);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Execute a `getMore` against the server
|
|
271
|
+
*
|
|
272
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
273
|
+
* @param {object} cursorState State data associated with the cursor calling this method
|
|
274
|
+
* @param {object} options Optional settings
|
|
275
|
+
* @param {function} callback
|
|
276
|
+
*/
|
|
277
|
+
getMore(ns, cursorState, batchSize, options, callback) {
|
|
278
|
+
wireProtocol.getMore(this, ns, cursorState, batchSize, options, (err, result) => {
|
|
279
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
280
|
+
this.emit('error', err);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
callback(err, result);
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Execute a `killCursors` command against the server
|
|
289
|
+
*
|
|
290
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
291
|
+
* @param {object} cursorState State data associated with the cursor calling this method
|
|
292
|
+
* @param {function} callback
|
|
293
|
+
*/
|
|
294
|
+
killCursors(ns, cursorState, callback) {
|
|
295
|
+
wireProtocol.killCursors(this, ns, cursorState, (err, result) => {
|
|
296
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
297
|
+
this.emit('error', err);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (typeof callback === 'function') {
|
|
301
|
+
callback(err, result);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Insert one or more documents
|
|
308
|
+
* @method
|
|
309
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
310
|
+
* @param {array} ops An array of documents to insert
|
|
311
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
312
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
313
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
314
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
315
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
316
|
+
* @param {opResultCallback} callback A callback function
|
|
317
|
+
*/
|
|
318
|
+
insert(ns, ops, options, callback) {
|
|
319
|
+
executeWriteOperation({ server: this, op: 'insert', ns, ops }, options, callback);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Perform one or more update operations
|
|
324
|
+
* @method
|
|
325
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
326
|
+
* @param {array} ops An array of updates
|
|
327
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
328
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
329
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
330
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
331
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
332
|
+
* @param {opResultCallback} callback A callback function
|
|
333
|
+
*/
|
|
334
|
+
update(ns, ops, options, callback) {
|
|
335
|
+
executeWriteOperation({ server: this, op: 'update', ns, ops }, options, callback);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Perform one or more remove operations
|
|
340
|
+
* @method
|
|
341
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
342
|
+
* @param {array} ops An array of removes
|
|
343
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
344
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
345
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
346
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
347
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
348
|
+
* @param {opResultCallback} callback A callback function
|
|
349
|
+
*/
|
|
350
|
+
remove(ns, ops, options, callback) {
|
|
351
|
+
executeWriteOperation({ server: this, op: 'remove', ns, ops }, options, callback);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
Object.defineProperty(Server.prototype, 'clusterTime', {
|
|
356
|
+
get: function() {
|
|
357
|
+
return this.s.topology.clusterTime;
|
|
358
|
+
},
|
|
359
|
+
set: function(clusterTime) {
|
|
360
|
+
this.s.topology.clusterTime = clusterTime;
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
function basicWriteValidations(server) {
|
|
365
|
+
if (!server.s.pool) {
|
|
366
|
+
return new MongoError('server instance is not connected');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (server.s.pool.isDestroyed()) {
|
|
370
|
+
return new MongoError('server instance pool was destroyed');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function basicReadValidations(server, options) {
|
|
377
|
+
const error = basicWriteValidations(server, options);
|
|
378
|
+
if (error) {
|
|
379
|
+
return error;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (options.readPreference && !(options.readPreference instanceof ReadPreference)) {
|
|
383
|
+
return new MongoError('readPreference must be an instance of ReadPreference');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function executeWriteOperation(args, options, callback) {
|
|
388
|
+
if (typeof options === 'function') (callback = options), (options = {});
|
|
389
|
+
options = options || {};
|
|
390
|
+
|
|
391
|
+
// TODO: once we drop Node 4, use destructuring either here or in arguments.
|
|
392
|
+
const server = args.server;
|
|
393
|
+
const op = args.op;
|
|
394
|
+
const ns = args.ns;
|
|
395
|
+
const ops = Array.isArray(args.ops) ? args.ops : [args.ops];
|
|
396
|
+
|
|
397
|
+
const error = basicWriteValidations(server, options);
|
|
398
|
+
if (error) {
|
|
399
|
+
callback(error, null);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (collationNotSupported(server, options)) {
|
|
404
|
+
callback(new MongoError(`server ${this.name} does not support collation`));
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return wireProtocol[op](server, ns, ops, options, (err, result) => {
|
|
409
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
410
|
+
server.emit('error', err);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
callback(err, result);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function connectEventHandler(server) {
|
|
418
|
+
return function(pool, conn) {
|
|
419
|
+
const ismaster = conn.ismaster;
|
|
420
|
+
server.s.lastIsMasterMS = conn.lastIsMasterMS;
|
|
421
|
+
if (conn.agreedCompressor) {
|
|
422
|
+
server.s.pool.options.agreedCompressor = conn.agreedCompressor;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (conn.zlibCompressionLevel) {
|
|
426
|
+
server.s.pool.options.zlibCompressionLevel = conn.zlibCompressionLevel;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (conn.ismaster.$clusterTime) {
|
|
430
|
+
const $clusterTime = conn.ismaster.$clusterTime;
|
|
431
|
+
server.s.sclusterTime = $clusterTime;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// log the connection event if requested
|
|
435
|
+
if (server.s.logger.isInfo()) {
|
|
436
|
+
server.s.logger.info(
|
|
437
|
+
`server ${server.name} connected with ismaster [${JSON.stringify(ismaster)}]`
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// emit an event indicating that our description has changed
|
|
442
|
+
server.emit('descriptionReceived', new ServerDescription(server.description.address, ismaster));
|
|
443
|
+
|
|
444
|
+
// we are connected and handshaked (guaranteed by the pool)
|
|
445
|
+
server.s.state = STATE_CONNECTED;
|
|
446
|
+
server.emit('connect', server);
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function errorEventHandler(server) {
|
|
451
|
+
return function(err) {
|
|
452
|
+
if (err) {
|
|
453
|
+
server.emit('error', new MongoNetworkError(err));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
server.emit('close');
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function parseErrorEventHandler(server) {
|
|
461
|
+
return function(err) {
|
|
462
|
+
server.s.state = STATE_DISCONNECTED;
|
|
463
|
+
server.emit('error', new MongoParseError(err));
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
module.exports = Server;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// An enumeration of server types we know about
|
|
4
|
+
const ServerType = {
|
|
5
|
+
Standalone: 'Standalone',
|
|
6
|
+
Mongos: 'Mongos',
|
|
7
|
+
PossiblePrimary: 'PossiblePrimary',
|
|
8
|
+
RSPrimary: 'RSPrimary',
|
|
9
|
+
RSSecondary: 'RSSecondary',
|
|
10
|
+
RSArbiter: 'RSArbiter',
|
|
11
|
+
RSOther: 'RSOther',
|
|
12
|
+
RSGhost: 'RSGhost',
|
|
13
|
+
Unknown: 'Unknown'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const WRITABLE_SERVER_TYPES = new Set([
|
|
17
|
+
ServerType.RSPrimary,
|
|
18
|
+
ServerType.Standalone,
|
|
19
|
+
ServerType.Mongos
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const DATA_BEARING_SERVER_TYPES = new Set([
|
|
23
|
+
ServerType.RSPrimary,
|
|
24
|
+
ServerType.RSSecondary,
|
|
25
|
+
ServerType.Mongos,
|
|
26
|
+
ServerType.Standalone
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
const ISMASTER_FIELDS = [
|
|
30
|
+
'minWireVersion',
|
|
31
|
+
'maxWireVersion',
|
|
32
|
+
'maxBsonObjectSize',
|
|
33
|
+
'maxMessageSizeBytes',
|
|
34
|
+
'maxWriteBatchSize',
|
|
35
|
+
'compression',
|
|
36
|
+
'me',
|
|
37
|
+
'hosts',
|
|
38
|
+
'passives',
|
|
39
|
+
'arbiters',
|
|
40
|
+
'tags',
|
|
41
|
+
'setName',
|
|
42
|
+
'setVersion',
|
|
43
|
+
'electionId',
|
|
44
|
+
'primary',
|
|
45
|
+
'logicalSessionTimeoutMinutes',
|
|
46
|
+
'saslSupportedMechs',
|
|
47
|
+
'__nodejs_mock_server__',
|
|
48
|
+
'$clusterTime'
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The client's view of a single server, based on the most recent ismaster outcome.
|
|
53
|
+
*
|
|
54
|
+
* Internal type, not meant to be directly instantiated
|
|
55
|
+
*/
|
|
56
|
+
class ServerDescription {
|
|
57
|
+
/**
|
|
58
|
+
* Create a ServerDescription
|
|
59
|
+
* @param {String} address The address of the server
|
|
60
|
+
* @param {Object} [ismaster] An optional ismaster response for this server
|
|
61
|
+
* @param {Object} [options] Optional settings
|
|
62
|
+
* @param {Number} [options.roundTripTime] The round trip time to ping this server (in ms)
|
|
63
|
+
*/
|
|
64
|
+
constructor(address, ismaster, options) {
|
|
65
|
+
options = options || {};
|
|
66
|
+
ismaster = Object.assign(
|
|
67
|
+
{
|
|
68
|
+
minWireVersion: 0,
|
|
69
|
+
maxWireVersion: 0,
|
|
70
|
+
hosts: [],
|
|
71
|
+
passives: [],
|
|
72
|
+
arbiters: [],
|
|
73
|
+
tags: []
|
|
74
|
+
},
|
|
75
|
+
ismaster
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
this.address = address;
|
|
79
|
+
this.error = options.error || null;
|
|
80
|
+
this.roundTripTime = options.roundTripTime || 0;
|
|
81
|
+
this.lastUpdateTime = Date.now();
|
|
82
|
+
this.lastWriteDate = ismaster.lastWrite ? ismaster.lastWrite.lastWriteDate : null;
|
|
83
|
+
this.opTime = ismaster.lastWrite ? ismaster.lastWrite.opTime : null;
|
|
84
|
+
this.type = parseServerType(ismaster);
|
|
85
|
+
|
|
86
|
+
// direct mappings
|
|
87
|
+
ISMASTER_FIELDS.forEach(field => {
|
|
88
|
+
if (typeof ismaster[field] !== 'undefined') this[field] = ismaster[field];
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// normalize case for hosts
|
|
92
|
+
if (this.me) this.me = this.me.toLowerCase();
|
|
93
|
+
this.hosts = this.hosts.map(host => host.toLowerCase());
|
|
94
|
+
this.passives = this.passives.map(host => host.toLowerCase());
|
|
95
|
+
this.arbiters = this.arbiters.map(host => host.toLowerCase());
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get allHosts() {
|
|
99
|
+
return this.hosts.concat(this.arbiters).concat(this.passives);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @return {Boolean} Is this server available for reads
|
|
104
|
+
*/
|
|
105
|
+
get isReadable() {
|
|
106
|
+
return this.type === ServerType.RSSecondary || this.isWritable;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @return {Boolean} Is this server data bearing
|
|
111
|
+
*/
|
|
112
|
+
get isDataBearing() {
|
|
113
|
+
return DATA_BEARING_SERVER_TYPES.has(this.type);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @return {Boolean} Is this server available for writes
|
|
118
|
+
*/
|
|
119
|
+
get isWritable() {
|
|
120
|
+
return WRITABLE_SERVER_TYPES.has(this.type);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Parses an `ismaster` message and determines the server type
|
|
126
|
+
*
|
|
127
|
+
* @param {Object} ismaster The `ismaster` message to parse
|
|
128
|
+
* @return {ServerType}
|
|
129
|
+
*/
|
|
130
|
+
function parseServerType(ismaster) {
|
|
131
|
+
if (!ismaster || !ismaster.ok) {
|
|
132
|
+
return ServerType.Unknown;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (ismaster.isreplicaset) {
|
|
136
|
+
return ServerType.RSGhost;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (ismaster.msg && ismaster.msg === 'isdbgrid') {
|
|
140
|
+
return ServerType.Mongos;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (ismaster.setName) {
|
|
144
|
+
if (ismaster.hidden) {
|
|
145
|
+
return ServerType.RSOther;
|
|
146
|
+
} else if (ismaster.ismaster) {
|
|
147
|
+
return ServerType.RSPrimary;
|
|
148
|
+
} else if (ismaster.secondary) {
|
|
149
|
+
return ServerType.RSSecondary;
|
|
150
|
+
} else if (ismaster.arbiterOnly) {
|
|
151
|
+
return ServerType.RSArbiter;
|
|
152
|
+
} else {
|
|
153
|
+
return ServerType.RSOther;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return ServerType.Standalone;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
ServerDescription,
|
|
162
|
+
ServerType
|
|
163
|
+
};
|