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,165 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const requireOptional = require('require_optional');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate a UUIDv4
|
|
8
|
+
*/
|
|
9
|
+
const uuidV4 = () => {
|
|
10
|
+
const result = crypto.randomBytes(16);
|
|
11
|
+
result[6] = (result[6] & 0x0f) | 0x40;
|
|
12
|
+
result[8] = (result[8] & 0x3f) | 0x80;
|
|
13
|
+
return result;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the duration calculated from two high resolution timers in milliseconds
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} started A high resolution timestamp created from `process.hrtime()`
|
|
20
|
+
* @returns {Number} The duration in milliseconds
|
|
21
|
+
*/
|
|
22
|
+
const calculateDurationInMs = started => {
|
|
23
|
+
const hrtime = process.hrtime(started);
|
|
24
|
+
return (hrtime[0] * 1e9 + hrtime[1]) / 1e6;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Relays events for a given listener and emitter
|
|
29
|
+
*
|
|
30
|
+
* @param {EventEmitter} listener the EventEmitter to listen to the events from
|
|
31
|
+
* @param {EventEmitter} emitter the EventEmitter to relay the events to
|
|
32
|
+
*/
|
|
33
|
+
function relayEvents(listener, emitter, events) {
|
|
34
|
+
events.forEach(eventName => listener.on(eventName, event => emitter.emit(eventName, event)));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function retrieveKerberos() {
|
|
38
|
+
let kerberos;
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
kerberos = requireOptional('kerberos');
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (err.code === 'MODULE_NOT_FOUND') {
|
|
44
|
+
throw new Error('The `kerberos` module was not found. Please install it and try again.');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return kerberos;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Throw an error if an attempt to use EJSON is made when it is not installed
|
|
54
|
+
const noEJSONError = function() {
|
|
55
|
+
throw new Error('The `mongodb-extjson` module was not found. Please install it and try again.');
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Facilitate loading EJSON optionally
|
|
59
|
+
function retrieveEJSON() {
|
|
60
|
+
let EJSON = null;
|
|
61
|
+
try {
|
|
62
|
+
EJSON = requireOptional('mongodb-extjson');
|
|
63
|
+
} catch (error) {} // eslint-disable-line
|
|
64
|
+
if (!EJSON) {
|
|
65
|
+
EJSON = {
|
|
66
|
+
parse: noEJSONError,
|
|
67
|
+
deserialize: noEJSONError,
|
|
68
|
+
serialize: noEJSONError,
|
|
69
|
+
stringify: noEJSONError,
|
|
70
|
+
setBSONModule: noEJSONError,
|
|
71
|
+
BSON: noEJSONError
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return EJSON;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* A helper function for determining `maxWireVersion` between legacy and new topology
|
|
80
|
+
* instances
|
|
81
|
+
*
|
|
82
|
+
* @private
|
|
83
|
+
* @param {(Topology|Server)} topologyOrServer
|
|
84
|
+
*/
|
|
85
|
+
function maxWireVersion(topologyOrServer) {
|
|
86
|
+
if (topologyOrServer.ismaster) {
|
|
87
|
+
return topologyOrServer.ismaster.maxWireVersion;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (topologyOrServer.description) {
|
|
91
|
+
return topologyOrServer.description.maxWireVersion;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/*
|
|
98
|
+
* Checks that collation is supported by server.
|
|
99
|
+
*
|
|
100
|
+
* @param {Server} [server] to check against
|
|
101
|
+
* @param {object} [cmd] object where collation may be specified
|
|
102
|
+
* @param {function} [callback] callback function
|
|
103
|
+
* @return true if server does not support collation
|
|
104
|
+
*/
|
|
105
|
+
function collationNotSupported(server, cmd) {
|
|
106
|
+
return cmd && cmd.collation && maxWireVersion(server) < 5;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Checks if a given value is a Promise
|
|
111
|
+
*
|
|
112
|
+
* @param {*} maybePromise
|
|
113
|
+
* @return true if the provided value is a Promise
|
|
114
|
+
*/
|
|
115
|
+
function isPromiseLike(maybePromise) {
|
|
116
|
+
return maybePromise && typeof maybePromise.then === 'function';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Applies the function `eachFn` to each item in `arr`, in parallel.
|
|
121
|
+
*
|
|
122
|
+
* @param {array} arr an array of items to asynchronusly iterate over
|
|
123
|
+
* @param {function} eachFn A function to call on each item of the array. The callback signature is `(item, callback)`, where the callback indicates iteration is complete.
|
|
124
|
+
* @param {function} callback The callback called after every item has been iterated
|
|
125
|
+
*/
|
|
126
|
+
function eachAsync(arr, eachFn, callback) {
|
|
127
|
+
if (arr.length === 0) {
|
|
128
|
+
callback(null);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const length = arr.length;
|
|
133
|
+
let completed = 0;
|
|
134
|
+
function eachCallback(err) {
|
|
135
|
+
if (err) {
|
|
136
|
+
callback(err, null);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (++completed === length) {
|
|
141
|
+
callback(null);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (let idx = 0; idx < length; ++idx) {
|
|
146
|
+
eachFn(arr[idx], eachCallback);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function isUnifiedTopology(topology) {
|
|
151
|
+
return topology.description != null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = {
|
|
155
|
+
uuidV4,
|
|
156
|
+
calculateDurationInMs,
|
|
157
|
+
relayEvents,
|
|
158
|
+
collationNotSupported,
|
|
159
|
+
retrieveEJSON,
|
|
160
|
+
retrieveKerberos,
|
|
161
|
+
maxWireVersion,
|
|
162
|
+
isPromiseLike,
|
|
163
|
+
eachAsync,
|
|
164
|
+
isUnifiedTopology
|
|
165
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Query = require('../connection/commands').Query;
|
|
4
|
+
const Msg = require('../connection/msg').Msg;
|
|
5
|
+
const MongoError = require('../error').MongoError;
|
|
6
|
+
const getReadPreference = require('./shared').getReadPreference;
|
|
7
|
+
const isSharded = require('./shared').isSharded;
|
|
8
|
+
const databaseNamespace = require('./shared').databaseNamespace;
|
|
9
|
+
const isTransactionCommand = require('../transactions').isTransactionCommand;
|
|
10
|
+
const applySession = require('../sessions').applySession;
|
|
11
|
+
|
|
12
|
+
function isClientEncryptionEnabled(server) {
|
|
13
|
+
return server.autoEncrypter;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function command(server, ns, cmd, options, callback) {
|
|
17
|
+
if (typeof options === 'function') (callback = options), (options = {});
|
|
18
|
+
options = options || {};
|
|
19
|
+
|
|
20
|
+
if (cmd == null) {
|
|
21
|
+
return callback(new MongoError(`command ${JSON.stringify(cmd)} does not return a cursor`));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!isClientEncryptionEnabled(server)) {
|
|
25
|
+
_command(server, ns, cmd, options, callback);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_cryptCommand(server, ns, cmd, options, callback);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function _command(server, ns, cmd, options, callback) {
|
|
33
|
+
const bson = server.s.bson;
|
|
34
|
+
const pool = server.s.pool;
|
|
35
|
+
const readPreference = getReadPreference(cmd, options);
|
|
36
|
+
const shouldUseOpMsg = supportsOpMsg(server);
|
|
37
|
+
const session = options.session;
|
|
38
|
+
|
|
39
|
+
let clusterTime = server.clusterTime;
|
|
40
|
+
let finalCmd = Object.assign({}, cmd);
|
|
41
|
+
if (hasSessionSupport(server) && session) {
|
|
42
|
+
if (
|
|
43
|
+
session.clusterTime &&
|
|
44
|
+
session.clusterTime.clusterTime.greaterThan(clusterTime.clusterTime)
|
|
45
|
+
) {
|
|
46
|
+
clusterTime = session.clusterTime;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const err = applySession(session, finalCmd, options);
|
|
50
|
+
if (err) {
|
|
51
|
+
return callback(err);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// if we have a known cluster time, gossip it
|
|
56
|
+
if (clusterTime) {
|
|
57
|
+
finalCmd.$clusterTime = clusterTime;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
isSharded(server) &&
|
|
62
|
+
!shouldUseOpMsg &&
|
|
63
|
+
readPreference &&
|
|
64
|
+
readPreference.preference !== 'primary'
|
|
65
|
+
) {
|
|
66
|
+
finalCmd = {
|
|
67
|
+
$query: finalCmd,
|
|
68
|
+
$readPreference: readPreference.toJSON()
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const commandOptions = Object.assign(
|
|
73
|
+
{
|
|
74
|
+
command: true,
|
|
75
|
+
numberToSkip: 0,
|
|
76
|
+
numberToReturn: -1,
|
|
77
|
+
checkKeys: false
|
|
78
|
+
},
|
|
79
|
+
options
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// This value is not overridable
|
|
83
|
+
commandOptions.slaveOk = readPreference.slaveOk();
|
|
84
|
+
|
|
85
|
+
const cmdNs = `${databaseNamespace(ns)}.$cmd`;
|
|
86
|
+
const message = shouldUseOpMsg
|
|
87
|
+
? new Msg(bson, cmdNs, finalCmd, commandOptions)
|
|
88
|
+
: new Query(bson, cmdNs, finalCmd, commandOptions);
|
|
89
|
+
|
|
90
|
+
const inTransaction = session && (session.inTransaction() || isTransactionCommand(finalCmd));
|
|
91
|
+
const commandResponseHandler = inTransaction
|
|
92
|
+
? function(err) {
|
|
93
|
+
if (
|
|
94
|
+
!cmd.commitTransaction &&
|
|
95
|
+
err &&
|
|
96
|
+
err instanceof MongoError &&
|
|
97
|
+
err.hasErrorLabel('TransientTransactionError')
|
|
98
|
+
) {
|
|
99
|
+
session.transaction.unpinServer();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return callback.apply(null, arguments);
|
|
103
|
+
}
|
|
104
|
+
: callback;
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
pool.write(message, commandOptions, commandResponseHandler);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
commandResponseHandler(err);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function hasSessionSupport(topology) {
|
|
114
|
+
if (topology == null) return false;
|
|
115
|
+
if (topology.description) {
|
|
116
|
+
return topology.description.maxWireVersion >= 6;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return topology.ismaster == null ? false : topology.ismaster.maxWireVersion >= 6;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function supportsOpMsg(topologyOrServer) {
|
|
123
|
+
const description = topologyOrServer.ismaster
|
|
124
|
+
? topologyOrServer.ismaster
|
|
125
|
+
: topologyOrServer.description;
|
|
126
|
+
|
|
127
|
+
if (description == null) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return description.maxWireVersion >= 6 && description.__nodejs_mock_server__ == null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function _cryptCommand(server, ns, cmd, options, callback) {
|
|
135
|
+
const shouldBypassAutoEncryption = !!server.s.options.bypassAutoEncryption;
|
|
136
|
+
const autoEncrypter = server.autoEncrypter;
|
|
137
|
+
function commandResponseHandler(err, response) {
|
|
138
|
+
if (err || response == null) {
|
|
139
|
+
callback(err, response);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
autoEncrypter.decrypt(response.result, (err, decrypted) => {
|
|
144
|
+
if (err) {
|
|
145
|
+
callback(err, null);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
response.result = decrypted;
|
|
150
|
+
response.message.documents = [decrypted];
|
|
151
|
+
callback(null, response);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (shouldBypassAutoEncryption) {
|
|
156
|
+
_command(server, ns, cmd, options, commandResponseHandler);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
autoEncrypter.encrypt(ns, cmd, (err, encrypted) => {
|
|
161
|
+
if (err) {
|
|
162
|
+
callback(err, null);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
_command(server, ns, encrypted, options, commandResponseHandler);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = command;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Snappy = require('../connection/utils').retrieveSnappy(),
|
|
4
|
+
zlib = require('zlib');
|
|
5
|
+
|
|
6
|
+
var compressorIDs = {
|
|
7
|
+
snappy: 1,
|
|
8
|
+
zlib: 2
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
var uncompressibleCommands = [
|
|
12
|
+
'ismaster',
|
|
13
|
+
'saslStart',
|
|
14
|
+
'saslContinue',
|
|
15
|
+
'getnonce',
|
|
16
|
+
'authenticate',
|
|
17
|
+
'createUser',
|
|
18
|
+
'updateUser',
|
|
19
|
+
'copydbSaslStart',
|
|
20
|
+
'copydbgetnonce',
|
|
21
|
+
'copydb'
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
// Facilitate compressing a message using an agreed compressor
|
|
25
|
+
var compress = function(self, dataToBeCompressed, callback) {
|
|
26
|
+
switch (self.options.agreedCompressor) {
|
|
27
|
+
case 'snappy':
|
|
28
|
+
Snappy.compress(dataToBeCompressed, callback);
|
|
29
|
+
break;
|
|
30
|
+
case 'zlib':
|
|
31
|
+
// Determine zlibCompressionLevel
|
|
32
|
+
var zlibOptions = {};
|
|
33
|
+
if (self.options.zlibCompressionLevel) {
|
|
34
|
+
zlibOptions.level = self.options.zlibCompressionLevel;
|
|
35
|
+
}
|
|
36
|
+
zlib.deflate(dataToBeCompressed, zlibOptions, callback);
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
throw new Error(
|
|
40
|
+
'Attempt to compress message using unknown compressor "' +
|
|
41
|
+
self.options.agreedCompressor +
|
|
42
|
+
'".'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Decompress a message using the given compressor
|
|
48
|
+
var decompress = function(compressorID, compressedData, callback) {
|
|
49
|
+
if (compressorID < 0 || compressorID > compressorIDs.length) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
'Server sent message compressed using an unsupported compressor. (Received compressor ID ' +
|
|
52
|
+
compressorID +
|
|
53
|
+
')'
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
switch (compressorID) {
|
|
57
|
+
case compressorIDs.snappy:
|
|
58
|
+
Snappy.uncompress(compressedData, callback);
|
|
59
|
+
break;
|
|
60
|
+
case compressorIDs.zlib:
|
|
61
|
+
zlib.inflate(compressedData, callback);
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
callback(null, compressedData);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
module.exports = {
|
|
69
|
+
compressorIDs: compressorIDs,
|
|
70
|
+
uncompressibleCommands: uncompressibleCommands,
|
|
71
|
+
compress: compress,
|
|
72
|
+
decompress: decompress
|
|
73
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MIN_SUPPORTED_SERVER_VERSION = '2.6';
|
|
4
|
+
const MAX_SUPPORTED_SERVER_VERSION = '4.2';
|
|
5
|
+
const MIN_SUPPORTED_WIRE_VERSION = 2;
|
|
6
|
+
const MAX_SUPPORTED_WIRE_VERSION = 8;
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
MIN_SUPPORTED_SERVER_VERSION,
|
|
10
|
+
MAX_SUPPORTED_SERVER_VERSION,
|
|
11
|
+
MIN_SUPPORTED_WIRE_VERSION,
|
|
12
|
+
MAX_SUPPORTED_WIRE_VERSION
|
|
13
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const GetMore = require('../connection/commands').GetMore;
|
|
4
|
+
const retrieveBSON = require('../connection/utils').retrieveBSON;
|
|
5
|
+
const MongoError = require('../error').MongoError;
|
|
6
|
+
const MongoNetworkError = require('../error').MongoNetworkError;
|
|
7
|
+
const BSON = retrieveBSON();
|
|
8
|
+
const Long = BSON.Long;
|
|
9
|
+
const collectionNamespace = require('./shared').collectionNamespace;
|
|
10
|
+
const maxWireVersion = require('../utils').maxWireVersion;
|
|
11
|
+
const applyCommonQueryOptions = require('./shared').applyCommonQueryOptions;
|
|
12
|
+
const command = require('./command');
|
|
13
|
+
|
|
14
|
+
function getMore(server, ns, cursorState, batchSize, options, callback) {
|
|
15
|
+
options = options || {};
|
|
16
|
+
|
|
17
|
+
const wireVersion = maxWireVersion(server);
|
|
18
|
+
function queryCallback(err, result) {
|
|
19
|
+
if (err) return callback(err);
|
|
20
|
+
const response = result.message;
|
|
21
|
+
|
|
22
|
+
// If we have a timed out query or a cursor that was killed
|
|
23
|
+
if (response.cursorNotFound) {
|
|
24
|
+
return callback(new MongoNetworkError('cursor killed or timed out'), null);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (wireVersion < 4) {
|
|
28
|
+
const cursorId =
|
|
29
|
+
typeof response.cursorId === 'number'
|
|
30
|
+
? Long.fromNumber(response.cursorId)
|
|
31
|
+
: response.cursorId;
|
|
32
|
+
|
|
33
|
+
cursorState.documents = response.documents;
|
|
34
|
+
cursorState.cursorId = cursorId;
|
|
35
|
+
|
|
36
|
+
callback(null, null, response.connection);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// We have an error detected
|
|
41
|
+
if (response.documents[0].ok === 0) {
|
|
42
|
+
return callback(new MongoError(response.documents[0]));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Ensure we have a Long valid cursor id
|
|
46
|
+
const cursorId =
|
|
47
|
+
typeof response.documents[0].cursor.id === 'number'
|
|
48
|
+
? Long.fromNumber(response.documents[0].cursor.id)
|
|
49
|
+
: response.documents[0].cursor.id;
|
|
50
|
+
|
|
51
|
+
cursorState.documents = response.documents[0].cursor.nextBatch;
|
|
52
|
+
cursorState.cursorId = cursorId;
|
|
53
|
+
|
|
54
|
+
callback(null, response.documents[0], response.connection);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (wireVersion < 4) {
|
|
58
|
+
const bson = server.s.bson;
|
|
59
|
+
const getMoreOp = new GetMore(bson, ns, cursorState.cursorId, { numberToReturn: batchSize });
|
|
60
|
+
const queryOptions = applyCommonQueryOptions({}, cursorState);
|
|
61
|
+
server.s.pool.write(getMoreOp, queryOptions, queryCallback);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const getMoreCmd = {
|
|
66
|
+
getMore: cursorState.cursorId,
|
|
67
|
+
collection: collectionNamespace(ns),
|
|
68
|
+
batchSize: Math.abs(batchSize)
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
if (cursorState.cmd.tailable && typeof cursorState.cmd.maxAwaitTimeMS === 'number') {
|
|
72
|
+
getMoreCmd.maxTimeMS = cursorState.cmd.maxAwaitTimeMS;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const commandOptions = Object.assign(
|
|
76
|
+
{
|
|
77
|
+
returnFieldSelector: null,
|
|
78
|
+
documentsReturnedIn: 'nextBatch'
|
|
79
|
+
},
|
|
80
|
+
options
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
command(server, ns, getMoreCmd, commandOptions, queryCallback);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = getMore;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const writeCommand = require('./write_command');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
insert: function insert(server, ns, ops, options, callback) {
|
|
6
|
+
writeCommand(server, 'insert', 'documents', ns, ops, options, callback);
|
|
7
|
+
},
|
|
8
|
+
update: function update(server, ns, ops, options, callback) {
|
|
9
|
+
writeCommand(server, 'update', 'updates', ns, ops, options, callback);
|
|
10
|
+
},
|
|
11
|
+
remove: function remove(server, ns, ops, options, callback) {
|
|
12
|
+
writeCommand(server, 'delete', 'deletes', ns, ops, options, callback);
|
|
13
|
+
},
|
|
14
|
+
killCursors: require('./kill_cursors'),
|
|
15
|
+
getMore: require('./get_more'),
|
|
16
|
+
query: require('./query'),
|
|
17
|
+
command: require('./command')
|
|
18
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const KillCursor = require('../connection/commands').KillCursor;
|
|
4
|
+
const MongoError = require('../error').MongoError;
|
|
5
|
+
const MongoNetworkError = require('../error').MongoNetworkError;
|
|
6
|
+
const collectionNamespace = require('./shared').collectionNamespace;
|
|
7
|
+
const maxWireVersion = require('../utils').maxWireVersion;
|
|
8
|
+
const command = require('./command');
|
|
9
|
+
|
|
10
|
+
function killCursors(server, ns, cursorState, callback) {
|
|
11
|
+
callback = typeof callback === 'function' ? callback : () => {};
|
|
12
|
+
const cursorId = cursorState.cursorId;
|
|
13
|
+
|
|
14
|
+
if (maxWireVersion(server) < 4) {
|
|
15
|
+
const bson = server.s.bson;
|
|
16
|
+
const pool = server.s.pool;
|
|
17
|
+
const killCursor = new KillCursor(bson, ns, [cursorId]);
|
|
18
|
+
const options = {
|
|
19
|
+
immediateRelease: true,
|
|
20
|
+
noResponse: true
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (typeof cursorState.session === 'object') {
|
|
24
|
+
options.session = cursorState.session;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (pool && pool.isConnected()) {
|
|
28
|
+
try {
|
|
29
|
+
pool.write(killCursor, options, callback);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if (typeof callback === 'function') {
|
|
32
|
+
callback(err, null);
|
|
33
|
+
} else {
|
|
34
|
+
console.warn(err);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const killCursorCmd = {
|
|
43
|
+
killCursors: collectionNamespace(ns),
|
|
44
|
+
cursors: [cursorId]
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const options = {};
|
|
48
|
+
if (typeof cursorState.session === 'object') options.session = cursorState.session;
|
|
49
|
+
|
|
50
|
+
command(server, ns, killCursorCmd, options, (err, result) => {
|
|
51
|
+
if (err) {
|
|
52
|
+
return callback(err);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const response = result.message;
|
|
56
|
+
if (response.cursorNotFound) {
|
|
57
|
+
return callback(new MongoNetworkError('cursor killed or timed out'), null);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!Array.isArray(response.documents) || response.documents.length === 0) {
|
|
61
|
+
return callback(
|
|
62
|
+
new MongoError(`invalid killCursors result returned for cursor id ${cursorId}`)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
callback(null, response.documents[0]);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = killCursors;
|