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.
Files changed (133) hide show
  1. package/HISTORY.md +0 -10
  2. package/index.js +4 -4
  3. package/lib/admin.js +56 -56
  4. package/lib/aggregation_cursor.js +7 -3
  5. package/lib/bulk/common.js +18 -13
  6. package/lib/change_stream.js +196 -89
  7. package/lib/collection.js +217 -169
  8. package/lib/command_cursor.js +17 -7
  9. package/lib/core/auth/auth_provider.js +158 -0
  10. package/lib/core/auth/defaultAuthProviders.js +29 -0
  11. package/lib/core/auth/gssapi.js +241 -0
  12. package/lib/core/auth/mongo_credentials.js +81 -0
  13. package/lib/core/auth/mongocr.js +51 -0
  14. package/lib/core/auth/plain.js +35 -0
  15. package/lib/core/auth/scram.js +293 -0
  16. package/lib/core/auth/sspi.js +131 -0
  17. package/lib/core/auth/x509.js +26 -0
  18. package/lib/core/connection/apm.js +236 -0
  19. package/lib/core/connection/command_result.js +36 -0
  20. package/lib/core/connection/commands.js +507 -0
  21. package/lib/core/connection/connect.js +370 -0
  22. package/lib/core/connection/connection.js +624 -0
  23. package/lib/core/connection/logger.js +246 -0
  24. package/lib/core/connection/msg.js +219 -0
  25. package/lib/core/connection/pool.js +1285 -0
  26. package/lib/core/connection/utils.js +57 -0
  27. package/lib/core/cursor.js +752 -0
  28. package/lib/core/error.js +186 -0
  29. package/lib/core/index.js +50 -0
  30. package/lib/core/sdam/monitoring.js +228 -0
  31. package/lib/core/sdam/server.js +467 -0
  32. package/lib/core/sdam/server_description.js +163 -0
  33. package/lib/core/sdam/server_selectors.js +244 -0
  34. package/lib/core/sdam/srv_polling.js +135 -0
  35. package/lib/core/sdam/topology.js +1151 -0
  36. package/lib/core/sdam/topology_description.js +408 -0
  37. package/lib/core/sessions.js +711 -0
  38. package/lib/core/tools/smoke_plugin.js +61 -0
  39. package/lib/core/topologies/mongos.js +1337 -0
  40. package/lib/core/topologies/read_preference.js +202 -0
  41. package/lib/core/topologies/replset.js +1507 -0
  42. package/lib/core/topologies/replset_state.js +1121 -0
  43. package/lib/core/topologies/server.js +984 -0
  44. package/lib/core/topologies/shared.js +453 -0
  45. package/lib/core/transactions.js +167 -0
  46. package/lib/core/uri_parser.js +631 -0
  47. package/lib/core/utils.js +165 -0
  48. package/lib/core/wireprotocol/command.js +170 -0
  49. package/lib/core/wireprotocol/compression.js +73 -0
  50. package/lib/core/wireprotocol/constants.js +13 -0
  51. package/lib/core/wireprotocol/get_more.js +86 -0
  52. package/lib/core/wireprotocol/index.js +18 -0
  53. package/lib/core/wireprotocol/kill_cursors.js +70 -0
  54. package/lib/core/wireprotocol/query.js +224 -0
  55. package/lib/core/wireprotocol/shared.js +115 -0
  56. package/lib/core/wireprotocol/write_command.js +50 -0
  57. package/lib/cursor.js +40 -46
  58. package/lib/db.js +141 -95
  59. package/lib/dynamic_loaders.js +32 -0
  60. package/lib/error.js +12 -10
  61. package/lib/gridfs/chunk.js +2 -2
  62. package/lib/gridfs/grid_store.js +31 -25
  63. package/lib/gridfs-stream/index.js +4 -4
  64. package/lib/gridfs-stream/upload.js +1 -1
  65. package/lib/mongo_client.js +37 -15
  66. package/lib/operations/add_user.js +96 -0
  67. package/lib/operations/aggregate.js +24 -13
  68. package/lib/operations/aggregate_operation.js +127 -0
  69. package/lib/operations/bulk_write.js +104 -0
  70. package/lib/operations/close.js +47 -0
  71. package/lib/operations/collection_ops.js +28 -287
  72. package/lib/operations/collections.js +55 -0
  73. package/lib/operations/command.js +120 -0
  74. package/lib/operations/command_v2.js +43 -0
  75. package/lib/operations/common_functions.js +372 -0
  76. package/lib/operations/{mongo_client_ops.js → connect.js} +185 -157
  77. package/lib/operations/count.js +72 -0
  78. package/lib/operations/count_documents.js +46 -0
  79. package/lib/operations/create_collection.js +118 -0
  80. package/lib/operations/create_index.js +92 -0
  81. package/lib/operations/create_indexes.js +61 -0
  82. package/lib/operations/cursor_ops.js +3 -4
  83. package/lib/operations/db_ops.js +15 -12
  84. package/lib/operations/delete_many.js +25 -0
  85. package/lib/operations/delete_one.js +25 -0
  86. package/lib/operations/distinct.js +85 -0
  87. package/lib/operations/drop.js +53 -0
  88. package/lib/operations/drop_index.js +42 -0
  89. package/lib/operations/drop_indexes.js +23 -0
  90. package/lib/operations/estimated_document_count.js +33 -0
  91. package/lib/operations/execute_db_admin_command.js +34 -0
  92. package/lib/operations/execute_operation.js +165 -0
  93. package/lib/operations/explain.js +23 -0
  94. package/lib/operations/find_and_modify.js +98 -0
  95. package/lib/operations/find_one.js +33 -0
  96. package/lib/operations/find_one_and_delete.js +16 -0
  97. package/lib/operations/find_one_and_replace.js +18 -0
  98. package/lib/operations/find_one_and_update.js +19 -0
  99. package/lib/operations/geo_haystack_search.js +79 -0
  100. package/lib/operations/has_next.js +40 -0
  101. package/lib/operations/index_exists.js +39 -0
  102. package/lib/operations/index_information.js +23 -0
  103. package/lib/operations/indexes.js +22 -0
  104. package/lib/operations/insert_many.js +63 -0
  105. package/lib/operations/insert_one.js +75 -0
  106. package/lib/operations/is_capped.js +19 -0
  107. package/lib/operations/list_indexes.js +66 -0
  108. package/lib/operations/map_reduce.js +189 -0
  109. package/lib/operations/next.js +32 -0
  110. package/lib/operations/operation.js +63 -0
  111. package/lib/operations/options_operation.js +32 -0
  112. package/lib/operations/profiling_level.js +31 -0
  113. package/lib/operations/re_index.js +28 -0
  114. package/lib/operations/remove_user.js +52 -0
  115. package/lib/operations/rename.js +61 -0
  116. package/lib/operations/replace_one.js +47 -0
  117. package/lib/operations/set_profiling_level.js +48 -0
  118. package/lib/operations/stats.js +45 -0
  119. package/lib/operations/to_array.js +68 -0
  120. package/lib/operations/update_many.js +29 -0
  121. package/lib/operations/update_one.js +44 -0
  122. package/lib/operations/validate_collection.js +40 -0
  123. package/lib/read_concern.js +55 -0
  124. package/lib/topologies/mongos.js +3 -3
  125. package/lib/topologies/native_topology.js +22 -2
  126. package/lib/topologies/replset.js +3 -3
  127. package/lib/topologies/server.js +4 -4
  128. package/lib/topologies/topology_base.js +6 -6
  129. package/lib/url_parser.js +4 -3
  130. package/lib/utils.js +46 -59
  131. package/lib/write_concern.js +66 -0
  132. package/package.json +15 -6
  133. package/lib/.DS_Store +0 -0
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ const OperationBase = require('./operation').OperationBase;
4
+ const handleCallback = require('../utils').handleCallback;
5
+
6
+ let collection;
7
+ function loadCollection() {
8
+ if (!collection) {
9
+ collection = require('../collection');
10
+ }
11
+ return collection;
12
+ }
13
+
14
+ class CollectionsOperation extends OperationBase {
15
+ constructor(db, options) {
16
+ super(options);
17
+
18
+ this.db = db;
19
+ }
20
+
21
+ execute(callback) {
22
+ const db = this.db;
23
+ let options = this.options;
24
+
25
+ let Collection = loadCollection();
26
+
27
+ options = Object.assign({}, options, { nameOnly: true });
28
+ // Let's get the collection names
29
+ db.listCollections({}, options).toArray((err, documents) => {
30
+ if (err != null) return handleCallback(callback, err, null);
31
+ // Filter collections removing any illegal ones
32
+ documents = documents.filter(doc => {
33
+ return doc.name.indexOf('$') === -1;
34
+ });
35
+
36
+ // Return the collection objects
37
+ handleCallback(
38
+ callback,
39
+ null,
40
+ documents.map(d => {
41
+ return new Collection(
42
+ db,
43
+ db.s.topology,
44
+ db.databaseName,
45
+ d.name,
46
+ db.s.pkFactory,
47
+ db.s.options
48
+ );
49
+ })
50
+ );
51
+ });
52
+ }
53
+ }
54
+
55
+ module.exports = CollectionsOperation;
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ const Aspect = require('./operation').Aspect;
4
+ const OperationBase = require('./operation').OperationBase;
5
+ const applyWriteConcern = require('../utils').applyWriteConcern;
6
+ const debugOptions = require('../utils').debugOptions;
7
+ const handleCallback = require('../utils').handleCallback;
8
+ const MongoError = require('../core').MongoError;
9
+ const ReadPreference = require('../core').ReadPreference;
10
+ const resolveReadPreference = require('../utils').resolveReadPreference;
11
+ const MongoDBNamespace = require('../utils').MongoDBNamespace;
12
+
13
+ const debugFields = [
14
+ 'authSource',
15
+ 'w',
16
+ 'wtimeout',
17
+ 'j',
18
+ 'native_parser',
19
+ 'forceServerObjectId',
20
+ 'serializeFunctions',
21
+ 'raw',
22
+ 'promoteLongs',
23
+ 'promoteValues',
24
+ 'promoteBuffers',
25
+ 'bufferMaxEntries',
26
+ 'numberOfRetries',
27
+ 'retryMiliSeconds',
28
+ 'readPreference',
29
+ 'pkFactory',
30
+ 'parentDb',
31
+ 'promiseLibrary',
32
+ 'noListener'
33
+ ];
34
+
35
+ class CommandOperation extends OperationBase {
36
+ constructor(db, options, collection, command) {
37
+ super(options);
38
+
39
+ if (!this.hasAspect(Aspect.WRITE_OPERATION)) {
40
+ if (collection != null) {
41
+ this.options.readPreference = resolveReadPreference(collection, options);
42
+ } else {
43
+ this.options.readPreference = resolveReadPreference(db, options);
44
+ }
45
+ } else {
46
+ if (collection != null) {
47
+ applyWriteConcern(this.options, { db, coll: collection }, this.options);
48
+ } else {
49
+ applyWriteConcern(this.options, { db }, this.options);
50
+ }
51
+ this.options.readPreference = ReadPreference.primary;
52
+ }
53
+
54
+ this.db = db;
55
+
56
+ if (command != null) {
57
+ this.command = command;
58
+ }
59
+
60
+ if (collection != null) {
61
+ this.collection = collection;
62
+ }
63
+ }
64
+
65
+ _buildCommand() {
66
+ if (this.command != null) {
67
+ return this.command;
68
+ }
69
+ }
70
+
71
+ execute(callback) {
72
+ const db = this.db;
73
+ const options = Object.assign({}, this.options);
74
+
75
+ // Did the user destroy the topology
76
+ if (db.serverConfig && db.serverConfig.isDestroyed()) {
77
+ return callback(new MongoError('topology was destroyed'));
78
+ }
79
+
80
+ let command;
81
+ try {
82
+ command = this._buildCommand();
83
+ } catch (e) {
84
+ return callback(e);
85
+ }
86
+
87
+ // Get the db name we are executing against
88
+ const dbName = options.dbName || options.authdb || db.databaseName;
89
+
90
+ // Convert the readPreference if its not a write
91
+ if (this.hasAspect(Aspect.WRITE_OPERATION)) {
92
+ if (options.writeConcern && (!options.session || !options.session.inTransaction())) {
93
+ command.writeConcern = options.writeConcern;
94
+ }
95
+ }
96
+
97
+ // Debug information
98
+ if (db.s.logger.isDebug()) {
99
+ db.s.logger.debug(
100
+ `executing command ${JSON.stringify(
101
+ command
102
+ )} against ${dbName}.$cmd with options [${JSON.stringify(
103
+ debugOptions(debugFields, options)
104
+ )}]`
105
+ );
106
+ }
107
+
108
+ const namespace =
109
+ this.namespace != null ? this.namespace : new MongoDBNamespace(dbName, '$cmd');
110
+
111
+ // Execute command
112
+ db.s.topology.command(namespace, command, options, (err, result) => {
113
+ if (err) return handleCallback(callback, err);
114
+ if (options.full) return handleCallback(callback, null, result);
115
+ handleCallback(callback, null, result.result);
116
+ });
117
+ }
118
+ }
119
+
120
+ module.exports = CommandOperation;
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ const OperationBase = require('./operation').OperationBase;
4
+ const resolveReadPreference = require('../utils').resolveReadPreference;
5
+
6
+ class CommandOperationV2 extends OperationBase {
7
+ constructor(parent, options) {
8
+ super(options);
9
+
10
+ this.ns = parent.s.namespace.withCollection('$cmd');
11
+ this.readPreference = resolveReadPreference(parent, options);
12
+
13
+ // TODO(NODE-2056): make logger another "inheritable" property
14
+ if (parent.s.logger) {
15
+ this.logger = parent.s.logger;
16
+ } else if (parent.s.db && parent.s.db.logger) {
17
+ this.logger = parent.s.db.logger;
18
+ }
19
+ }
20
+
21
+ executeCommand(server, cmd, callback) {
22
+ if (this.logger && this.logger.isDebug()) {
23
+ this.logger.debug(`executing command ${JSON.stringify(cmd)} against ${this.ns}`);
24
+ }
25
+
26
+ server.command(this.ns.toString(), cmd, this.options, (err, result) => {
27
+ if (err) {
28
+ callback(err, null);
29
+ return;
30
+ }
31
+
32
+ // full response was requested
33
+ if (this.options.full) {
34
+ callback(null, result);
35
+ return;
36
+ }
37
+
38
+ callback(null, result.result);
39
+ });
40
+ }
41
+ }
42
+
43
+ module.exports = CommandOperationV2;
@@ -0,0 +1,372 @@
1
+ 'use strict';
2
+
3
+ const applyRetryableWrites = require('../utils').applyRetryableWrites;
4
+ const applyWriteConcern = require('../utils').applyWriteConcern;
5
+ const decorateWithCollation = require('../utils').decorateWithCollation;
6
+ const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
7
+ const executeCommand = require('./db_ops').executeCommand;
8
+ const formattedOrderClause = require('../utils').formattedOrderClause;
9
+ const handleCallback = require('../utils').handleCallback;
10
+ const loadCursor = require('../dynamic_loaders').loadCursor;
11
+ const MongoError = require('../core').MongoError;
12
+ const ReadPreference = require('../core').ReadPreference;
13
+ const toError = require('../utils').toError;
14
+
15
+ /**
16
+ * Build the count command.
17
+ *
18
+ * @method
19
+ * @param {collectionOrCursor} an instance of a collection or cursor
20
+ * @param {object} query The query for the count.
21
+ * @param {object} [options] Optional settings. See Collection.prototype.count and Cursor.prototype.count for a list of options.
22
+ */
23
+ function buildCountCommand(collectionOrCursor, query, options) {
24
+ const skip = options.skip;
25
+ const limit = options.limit;
26
+ let hint = options.hint;
27
+ const maxTimeMS = options.maxTimeMS;
28
+ query = query || {};
29
+
30
+ // Final query
31
+ const cmd = {
32
+ count: options.collectionName,
33
+ query: query
34
+ };
35
+
36
+ // check if collectionOrCursor is a cursor by using cursor.s.numberOfRetries
37
+ if (collectionOrCursor.s.numberOfRetries) {
38
+ if (collectionOrCursor.s.options.hint) {
39
+ hint = collectionOrCursor.s.options.hint;
40
+ } else if (collectionOrCursor.s.cmd.hint) {
41
+ hint = collectionOrCursor.s.cmd.hint;
42
+ }
43
+ decorateWithCollation(cmd, collectionOrCursor, collectionOrCursor.s.cmd);
44
+ } else {
45
+ decorateWithCollation(cmd, collectionOrCursor, options);
46
+ }
47
+
48
+ // Add limit, skip and maxTimeMS if defined
49
+ if (typeof skip === 'number') cmd.skip = skip;
50
+ if (typeof limit === 'number') cmd.limit = limit;
51
+ if (typeof maxTimeMS === 'number') cmd.maxTimeMS = maxTimeMS;
52
+ if (hint) cmd.hint = hint;
53
+
54
+ // Do we have a readConcern specified
55
+ decorateWithReadConcern(cmd, collectionOrCursor);
56
+
57
+ return cmd;
58
+ }
59
+
60
+ function deleteCallback(err, r, callback) {
61
+ if (callback == null) return;
62
+ if (err && callback) return callback(err);
63
+ if (r == null) return callback(null, { result: { ok: 1 } });
64
+ r.deletedCount = r.result.n;
65
+ if (callback) callback(null, r);
66
+ }
67
+
68
+ /**
69
+ * Find and update a document.
70
+ *
71
+ * @method
72
+ * @param {Collection} a Collection instance.
73
+ * @param {object} query Query object to locate the object to modify.
74
+ * @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
75
+ * @param {object} doc The fields/vals to be updated.
76
+ * @param {object} [options] Optional settings. See Collection.prototype.findAndModify for a list of options.
77
+ * @param {Collection~findAndModifyCallback} [callback] The command result callback
78
+ * @deprecated use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead
79
+ */
80
+ function findAndModify(coll, query, sort, doc, options, callback) {
81
+ // Create findAndModify command object
82
+ const queryObject = {
83
+ findAndModify: coll.collectionName,
84
+ query: query
85
+ };
86
+
87
+ sort = formattedOrderClause(sort);
88
+ if (sort) {
89
+ queryObject.sort = sort;
90
+ }
91
+
92
+ queryObject.new = options.new ? true : false;
93
+ queryObject.remove = options.remove ? true : false;
94
+ queryObject.upsert = options.upsert ? true : false;
95
+
96
+ const projection = options.projection || options.fields;
97
+
98
+ if (projection) {
99
+ queryObject.fields = projection;
100
+ }
101
+
102
+ if (options.arrayFilters) {
103
+ queryObject.arrayFilters = options.arrayFilters;
104
+ delete options.arrayFilters;
105
+ }
106
+
107
+ if (doc && !options.remove) {
108
+ queryObject.update = doc;
109
+ }
110
+
111
+ if (options.maxTimeMS) queryObject.maxTimeMS = options.maxTimeMS;
112
+
113
+ // Either use override on the function, or go back to default on either the collection
114
+ // level or db
115
+ options.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
116
+
117
+ // No check on the documents
118
+ options.checkKeys = false;
119
+
120
+ // Final options for retryable writes and write concern
121
+ let finalOptions = Object.assign({}, options);
122
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
123
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
124
+
125
+ // Decorate the findAndModify command with the write Concern
126
+ if (finalOptions.writeConcern) {
127
+ queryObject.writeConcern = finalOptions.writeConcern;
128
+ }
129
+
130
+ // Have we specified bypassDocumentValidation
131
+ if (finalOptions.bypassDocumentValidation === true) {
132
+ queryObject.bypassDocumentValidation = finalOptions.bypassDocumentValidation;
133
+ }
134
+
135
+ finalOptions.readPreference = ReadPreference.primary;
136
+
137
+ // Have we specified collation
138
+ try {
139
+ decorateWithCollation(queryObject, coll, finalOptions);
140
+ } catch (err) {
141
+ return callback(err, null);
142
+ }
143
+
144
+ // Execute the command
145
+ executeCommand(coll.s.db, queryObject, finalOptions, (err, result) => {
146
+ if (err) return handleCallback(callback, err, null);
147
+
148
+ return handleCallback(callback, null, result);
149
+ });
150
+ }
151
+
152
+ /**
153
+ * Retrieves this collections index info.
154
+ *
155
+ * @method
156
+ * @param {Db} db The Db instance on which to retrieve the index info.
157
+ * @param {string} name The name of the collection.
158
+ * @param {object} [options] Optional settings. See Db.prototype.indexInformation for a list of options.
159
+ * @param {Db~resultCallback} [callback] The command result callback
160
+ */
161
+ function indexInformation(db, name, options, callback) {
162
+ // If we specified full information
163
+ const full = options['full'] == null ? false : options['full'];
164
+
165
+ // Did the user destroy the topology
166
+ if (db.serverConfig && db.serverConfig.isDestroyed())
167
+ return callback(new MongoError('topology was destroyed'));
168
+ // Process all the results from the index command and collection
169
+ function processResults(indexes) {
170
+ // Contains all the information
171
+ let info = {};
172
+ // Process all the indexes
173
+ for (let i = 0; i < indexes.length; i++) {
174
+ const index = indexes[i];
175
+ // Let's unpack the object
176
+ info[index.name] = [];
177
+ for (let name in index.key) {
178
+ info[index.name].push([name, index.key[name]]);
179
+ }
180
+ }
181
+
182
+ return info;
183
+ }
184
+
185
+ // Get the list of indexes of the specified collection
186
+ db
187
+ .collection(name)
188
+ .listIndexes(options)
189
+ .toArray((err, indexes) => {
190
+ if (err) return callback(toError(err));
191
+ if (!Array.isArray(indexes)) return handleCallback(callback, null, []);
192
+ if (full) return handleCallback(callback, null, indexes);
193
+ handleCallback(callback, null, processResults(indexes));
194
+ });
195
+ }
196
+
197
+ function prepareDocs(coll, docs, options) {
198
+ const forceServerObjectId =
199
+ typeof options.forceServerObjectId === 'boolean'
200
+ ? options.forceServerObjectId
201
+ : coll.s.db.options.forceServerObjectId;
202
+
203
+ // no need to modify the docs if server sets the ObjectId
204
+ if (forceServerObjectId === true) {
205
+ return docs;
206
+ }
207
+
208
+ return docs.map(doc => {
209
+ if (forceServerObjectId !== true && doc._id == null) {
210
+ doc._id = coll.s.pkFactory.createPk();
211
+ }
212
+
213
+ return doc;
214
+ });
215
+ }
216
+
217
+ // Get the next available document from the cursor, returns null if no more documents are available.
218
+ function nextObject(cursor, callback) {
219
+ let Cursor = loadCursor();
220
+
221
+ if (cursor.s.state === Cursor.CLOSED || (cursor.isDead && cursor.isDead())) {
222
+ return handleCallback(
223
+ callback,
224
+ MongoError.create({ message: 'Cursor is closed', driver: true })
225
+ );
226
+ }
227
+ if (cursor.s.state === Cursor.INIT && cursor.s.cmd.sort) {
228
+ try {
229
+ cursor.s.cmd.sort = formattedOrderClause(cursor.s.cmd.sort);
230
+ } catch (err) {
231
+ return handleCallback(callback, err);
232
+ }
233
+ }
234
+
235
+ // Get the next object
236
+ cursor._next((err, doc) => {
237
+ cursor.s.state = Cursor.OPEN;
238
+ if (err) return handleCallback(callback, err);
239
+ handleCallback(callback, null, doc);
240
+ });
241
+ }
242
+
243
+ function removeDocuments(coll, selector, options, callback) {
244
+ if (typeof options === 'function') {
245
+ (callback = options), (options = {});
246
+ } else if (typeof selector === 'function') {
247
+ callback = selector;
248
+ options = {};
249
+ selector = {};
250
+ }
251
+
252
+ // Create an empty options object if the provided one is null
253
+ options = options || {};
254
+
255
+ // Final options for retryable writes and write concern
256
+ let finalOptions = Object.assign({}, options);
257
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
258
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
259
+
260
+ // If selector is null set empty
261
+ if (selector == null) selector = {};
262
+
263
+ // Build the op
264
+ const op = { q: selector, limit: 0 };
265
+ if (options.single) {
266
+ op.limit = 1;
267
+ } else if (finalOptions.retryWrites) {
268
+ finalOptions.retryWrites = false;
269
+ }
270
+
271
+ // Have we specified collation
272
+ try {
273
+ decorateWithCollation(finalOptions, coll, options);
274
+ } catch (err) {
275
+ return callback(err, null);
276
+ }
277
+
278
+ // Execute the remove
279
+ coll.s.topology.remove(coll.s.namespace, [op], finalOptions, (err, result) => {
280
+ if (callback == null) return;
281
+ if (err) return handleCallback(callback, err, null);
282
+ if (result == null) return handleCallback(callback, null, null);
283
+ if (result.result.code) return handleCallback(callback, toError(result.result));
284
+ if (result.result.writeErrors)
285
+ return handleCallback(callback, toError(result.result.writeErrors[0]));
286
+ // Return the results
287
+ handleCallback(callback, null, result);
288
+ });
289
+ }
290
+
291
+ function updateDocuments(coll, selector, document, options, callback) {
292
+ if ('function' === typeof options) (callback = options), (options = null);
293
+ if (options == null) options = {};
294
+ if (!('function' === typeof callback)) callback = null;
295
+
296
+ // If we are not providing a selector or document throw
297
+ if (selector == null || typeof selector !== 'object')
298
+ return callback(toError('selector must be a valid JavaScript object'));
299
+ if (document == null || typeof document !== 'object')
300
+ return callback(toError('document must be a valid JavaScript object'));
301
+
302
+ // Final options for retryable writes and write concern
303
+ let finalOptions = Object.assign({}, options);
304
+ finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
305
+ finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
306
+
307
+ // Do we return the actual result document
308
+ // Either use override on the function, or go back to default on either the collection
309
+ // level or db
310
+ finalOptions.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
311
+
312
+ // Execute the operation
313
+ const op = { q: selector, u: document };
314
+ op.upsert = options.upsert !== void 0 ? !!options.upsert : false;
315
+ op.multi = options.multi !== void 0 ? !!options.multi : false;
316
+
317
+ if (finalOptions.arrayFilters) {
318
+ op.arrayFilters = finalOptions.arrayFilters;
319
+ delete finalOptions.arrayFilters;
320
+ }
321
+
322
+ if (finalOptions.retryWrites && op.multi) {
323
+ finalOptions.retryWrites = false;
324
+ }
325
+
326
+ // Have we specified collation
327
+ try {
328
+ decorateWithCollation(finalOptions, coll, options);
329
+ } catch (err) {
330
+ return callback(err, null);
331
+ }
332
+
333
+ // Update options
334
+ coll.s.topology.update(coll.s.namespace, [op], finalOptions, (err, result) => {
335
+ if (callback == null) return;
336
+ if (err) return handleCallback(callback, err, null);
337
+ if (result == null) return handleCallback(callback, null, null);
338
+ if (result.result.code) return handleCallback(callback, toError(result.result));
339
+ if (result.result.writeErrors)
340
+ return handleCallback(callback, toError(result.result.writeErrors[0]));
341
+ // Return the results
342
+ handleCallback(callback, null, result);
343
+ });
344
+ }
345
+
346
+ function updateCallback(err, r, callback) {
347
+ if (callback == null) return;
348
+ if (err) return callback(err);
349
+ if (r == null) return callback(null, { result: { ok: 1 } });
350
+ r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
351
+ r.upsertedId =
352
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0
353
+ ? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
354
+ : null;
355
+ r.upsertedCount =
356
+ Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
357
+ r.matchedCount =
358
+ Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
359
+ callback(null, r);
360
+ }
361
+
362
+ module.exports = {
363
+ buildCountCommand,
364
+ deleteCallback,
365
+ findAndModify,
366
+ indexInformation,
367
+ nextObject,
368
+ prepareDocs,
369
+ removeDocuments,
370
+ updateDocuments,
371
+ updateCallback
372
+ };