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,224 @@
1
+ 'use strict';
2
+
3
+ const Query = require('../connection/commands').Query;
4
+ const MongoError = require('../error').MongoError;
5
+ const getReadPreference = require('./shared').getReadPreference;
6
+ const collectionNamespace = require('./shared').collectionNamespace;
7
+ const isSharded = require('./shared').isSharded;
8
+ const maxWireVersion = require('../utils').maxWireVersion;
9
+ const applyCommonQueryOptions = require('./shared').applyCommonQueryOptions;
10
+ const command = require('./command');
11
+
12
+ function query(server, ns, cmd, cursorState, options, callback) {
13
+ options = options || {};
14
+ if (cursorState.cursorId != null) {
15
+ return callback();
16
+ }
17
+
18
+ if (cmd == null) {
19
+ return callback(new MongoError(`command ${JSON.stringify(cmd)} does not return a cursor`));
20
+ }
21
+
22
+ if (maxWireVersion(server) < 4) {
23
+ const query = prepareLegacyFindQuery(server, ns, cmd, cursorState, options);
24
+ const queryOptions = applyCommonQueryOptions({}, cursorState);
25
+ if (typeof query.documentsReturnedIn === 'string') {
26
+ queryOptions.documentsReturnedIn = query.documentsReturnedIn;
27
+ }
28
+
29
+ server.s.pool.write(query, queryOptions, callback);
30
+ return;
31
+ }
32
+
33
+ const readPreference = getReadPreference(cmd, options);
34
+ const findCmd = prepareFindCommand(server, ns, cmd, cursorState, options);
35
+
36
+ // NOTE: This actually modifies the passed in cmd, and our code _depends_ on this
37
+ // side-effect. Change this ASAP
38
+ cmd.virtual = false;
39
+
40
+ const commandOptions = Object.assign(
41
+ {
42
+ documentsReturnedIn: 'firstBatch',
43
+ numberToReturn: 1,
44
+ slaveOk: readPreference.slaveOk()
45
+ },
46
+ options
47
+ );
48
+
49
+ if (cmd.readPreference) commandOptions.readPreference = readPreference;
50
+ command(server, ns, findCmd, commandOptions, callback);
51
+ }
52
+
53
+ function prepareFindCommand(server, ns, cmd, cursorState) {
54
+ cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
55
+ let findCmd = {
56
+ find: collectionNamespace(ns)
57
+ };
58
+
59
+ if (cmd.query) {
60
+ if (cmd.query['$query']) {
61
+ findCmd.filter = cmd.query['$query'];
62
+ } else {
63
+ findCmd.filter = cmd.query;
64
+ }
65
+ }
66
+
67
+ let sortValue = cmd.sort;
68
+ if (Array.isArray(sortValue)) {
69
+ const sortObject = {};
70
+
71
+ if (sortValue.length > 0 && !Array.isArray(sortValue[0])) {
72
+ let sortDirection = sortValue[1];
73
+ if (sortDirection === 'asc') {
74
+ sortDirection = 1;
75
+ } else if (sortDirection === 'desc') {
76
+ sortDirection = -1;
77
+ }
78
+
79
+ sortObject[sortValue[0]] = sortDirection;
80
+ } else {
81
+ for (let i = 0; i < sortValue.length; i++) {
82
+ let sortDirection = sortValue[i][1];
83
+ if (sortDirection === 'asc') {
84
+ sortDirection = 1;
85
+ } else if (sortDirection === 'desc') {
86
+ sortDirection = -1;
87
+ }
88
+
89
+ sortObject[sortValue[i][0]] = sortDirection;
90
+ }
91
+ }
92
+
93
+ sortValue = sortObject;
94
+ }
95
+
96
+ if (cmd.sort) findCmd.sort = sortValue;
97
+ if (cmd.fields) findCmd.projection = cmd.fields;
98
+ if (cmd.hint) findCmd.hint = cmd.hint;
99
+ if (cmd.skip) findCmd.skip = cmd.skip;
100
+ if (cmd.limit) findCmd.limit = cmd.limit;
101
+ if (cmd.limit < 0) {
102
+ findCmd.limit = Math.abs(cmd.limit);
103
+ findCmd.singleBatch = true;
104
+ }
105
+
106
+ if (typeof cmd.batchSize === 'number') {
107
+ if (cmd.batchSize < 0) {
108
+ if (cmd.limit !== 0 && Math.abs(cmd.batchSize) < Math.abs(cmd.limit)) {
109
+ findCmd.limit = Math.abs(cmd.batchSize);
110
+ }
111
+
112
+ findCmd.singleBatch = true;
113
+ }
114
+
115
+ findCmd.batchSize = Math.abs(cmd.batchSize);
116
+ }
117
+
118
+ if (cmd.comment) findCmd.comment = cmd.comment;
119
+ if (cmd.maxScan) findCmd.maxScan = cmd.maxScan;
120
+ if (cmd.maxTimeMS) findCmd.maxTimeMS = cmd.maxTimeMS;
121
+ if (cmd.min) findCmd.min = cmd.min;
122
+ if (cmd.max) findCmd.max = cmd.max;
123
+ findCmd.returnKey = cmd.returnKey ? cmd.returnKey : false;
124
+ findCmd.showRecordId = cmd.showDiskLoc ? cmd.showDiskLoc : false;
125
+ if (cmd.snapshot) findCmd.snapshot = cmd.snapshot;
126
+ if (cmd.tailable) findCmd.tailable = cmd.tailable;
127
+ if (cmd.oplogReplay) findCmd.oplogReplay = cmd.oplogReplay;
128
+ if (cmd.noCursorTimeout) findCmd.noCursorTimeout = cmd.noCursorTimeout;
129
+ if (cmd.awaitData) findCmd.awaitData = cmd.awaitData;
130
+ if (cmd.awaitdata) findCmd.awaitData = cmd.awaitdata;
131
+ if (cmd.partial) findCmd.partial = cmd.partial;
132
+ if (cmd.collation) findCmd.collation = cmd.collation;
133
+ if (cmd.readConcern) findCmd.readConcern = cmd.readConcern;
134
+
135
+ // If we have explain, we need to rewrite the find command
136
+ // to wrap it in the explain command
137
+ if (cmd.explain) {
138
+ findCmd = {
139
+ explain: findCmd
140
+ };
141
+ }
142
+
143
+ return findCmd;
144
+ }
145
+
146
+ function prepareLegacyFindQuery(server, ns, cmd, cursorState, options) {
147
+ options = options || {};
148
+ const bson = server.s.bson;
149
+ const readPreference = getReadPreference(cmd, options);
150
+ cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
151
+
152
+ let numberToReturn = 0;
153
+ if (
154
+ cursorState.limit < 0 ||
155
+ (cursorState.limit !== 0 && cursorState.limit < cursorState.batchSize) ||
156
+ (cursorState.limit > 0 && cursorState.batchSize === 0)
157
+ ) {
158
+ numberToReturn = cursorState.limit;
159
+ } else {
160
+ numberToReturn = cursorState.batchSize;
161
+ }
162
+
163
+ const numberToSkip = cursorState.skip || 0;
164
+
165
+ const findCmd = {};
166
+ if (isSharded(server) && readPreference) {
167
+ findCmd['$readPreference'] = readPreference.toJSON();
168
+ }
169
+
170
+ if (cmd.sort) findCmd['$orderby'] = cmd.sort;
171
+ if (cmd.hint) findCmd['$hint'] = cmd.hint;
172
+ if (cmd.snapshot) findCmd['$snapshot'] = cmd.snapshot;
173
+ if (typeof cmd.returnKey !== 'undefined') findCmd['$returnKey'] = cmd.returnKey;
174
+ if (cmd.maxScan) findCmd['$maxScan'] = cmd.maxScan;
175
+ if (cmd.min) findCmd['$min'] = cmd.min;
176
+ if (cmd.max) findCmd['$max'] = cmd.max;
177
+ if (typeof cmd.showDiskLoc !== 'undefined') findCmd['$showDiskLoc'] = cmd.showDiskLoc;
178
+ if (cmd.comment) findCmd['$comment'] = cmd.comment;
179
+ if (cmd.maxTimeMS) findCmd['$maxTimeMS'] = cmd.maxTimeMS;
180
+ if (cmd.explain) {
181
+ // nToReturn must be 0 (match all) or negative (match N and close cursor)
182
+ // nToReturn > 0 will give explain results equivalent to limit(0)
183
+ numberToReturn = -Math.abs(cmd.limit || 0);
184
+ findCmd['$explain'] = true;
185
+ }
186
+
187
+ findCmd['$query'] = cmd.query;
188
+ if (cmd.readConcern && cmd.readConcern.level !== 'local') {
189
+ throw new MongoError(
190
+ `server find command does not support a readConcern level of ${cmd.readConcern.level}`
191
+ );
192
+ }
193
+
194
+ if (cmd.readConcern) {
195
+ cmd = Object.assign({}, cmd);
196
+ delete cmd['readConcern'];
197
+ }
198
+
199
+ const serializeFunctions =
200
+ typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
201
+ const ignoreUndefined =
202
+ typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
203
+
204
+ const query = new Query(bson, ns, findCmd, {
205
+ numberToSkip: numberToSkip,
206
+ numberToReturn: numberToReturn,
207
+ pre32Limit: typeof cmd.limit !== 'undefined' ? cmd.limit : undefined,
208
+ checkKeys: false,
209
+ returnFieldSelector: cmd.fields,
210
+ serializeFunctions: serializeFunctions,
211
+ ignoreUndefined: ignoreUndefined
212
+ });
213
+
214
+ if (typeof cmd.tailable === 'boolean') query.tailable = cmd.tailable;
215
+ if (typeof cmd.oplogReplay === 'boolean') query.oplogReplay = cmd.oplogReplay;
216
+ if (typeof cmd.noCursorTimeout === 'boolean') query.noCursorTimeout = cmd.noCursorTimeout;
217
+ if (typeof cmd.awaitData === 'boolean') query.awaitData = cmd.awaitData;
218
+ if (typeof cmd.partial === 'boolean') query.partial = cmd.partial;
219
+
220
+ query.slaveOk = readPreference.slaveOk();
221
+ return query;
222
+ }
223
+
224
+ module.exports = query;
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ const ReadPreference = require('../topologies/read_preference');
4
+ const MongoError = require('../error').MongoError;
5
+ const ServerType = require('../sdam/server_description').ServerType;
6
+ const TopologyDescription = require('../sdam/topology_description').TopologyDescription;
7
+
8
+ const MESSAGE_HEADER_SIZE = 16;
9
+ const COMPRESSION_DETAILS_SIZE = 9; // originalOpcode + uncompressedSize, compressorID
10
+
11
+ // OPCODE Numbers
12
+ // Defined at https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#request-opcodes
13
+ var opcodes = {
14
+ OP_REPLY: 1,
15
+ OP_UPDATE: 2001,
16
+ OP_INSERT: 2002,
17
+ OP_QUERY: 2004,
18
+ OP_GETMORE: 2005,
19
+ OP_DELETE: 2006,
20
+ OP_KILL_CURSORS: 2007,
21
+ OP_COMPRESSED: 2012,
22
+ OP_MSG: 2013
23
+ };
24
+
25
+ var getReadPreference = function(cmd, options) {
26
+ // Default to command version of the readPreference
27
+ var readPreference = cmd.readPreference || new ReadPreference('primary');
28
+ // If we have an option readPreference override the command one
29
+ if (options.readPreference) {
30
+ readPreference = options.readPreference;
31
+ }
32
+
33
+ if (typeof readPreference === 'string') {
34
+ readPreference = new ReadPreference(readPreference);
35
+ }
36
+
37
+ if (!(readPreference instanceof ReadPreference)) {
38
+ throw new MongoError('read preference must be a ReadPreference instance');
39
+ }
40
+
41
+ return readPreference;
42
+ };
43
+
44
+ // Parses the header of a wire protocol message
45
+ var parseHeader = function(message) {
46
+ return {
47
+ length: message.readInt32LE(0),
48
+ requestId: message.readInt32LE(4),
49
+ responseTo: message.readInt32LE(8),
50
+ opCode: message.readInt32LE(12)
51
+ };
52
+ };
53
+
54
+ function applyCommonQueryOptions(queryOptions, options) {
55
+ Object.assign(queryOptions, {
56
+ raw: typeof options.raw === 'boolean' ? options.raw : false,
57
+ promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
58
+ promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
59
+ promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
60
+ monitoring: typeof options.monitoring === 'boolean' ? options.monitoring : false,
61
+ fullResult: typeof options.fullResult === 'boolean' ? options.fullResult : false
62
+ });
63
+
64
+ if (typeof options.socketTimeout === 'number') {
65
+ queryOptions.socketTimeout = options.socketTimeout;
66
+ }
67
+
68
+ if (options.session) {
69
+ queryOptions.session = options.session;
70
+ }
71
+
72
+ if (typeof options.documentsReturnedIn === 'string') {
73
+ queryOptions.documentsReturnedIn = options.documentsReturnedIn;
74
+ }
75
+
76
+ return queryOptions;
77
+ }
78
+
79
+ function isSharded(topologyOrServer) {
80
+ if (topologyOrServer.type === 'mongos') return true;
81
+ if (topologyOrServer.description && topologyOrServer.description.type === ServerType.Mongos) {
82
+ return true;
83
+ }
84
+
85
+ // NOTE: This is incredibly inefficient, and should be removed once command construction
86
+ // happens based on `Server` not `Topology`.
87
+ if (topologyOrServer.description && topologyOrServer.description instanceof TopologyDescription) {
88
+ const servers = Array.from(topologyOrServer.description.servers.values());
89
+ return servers.some(server => server.type === ServerType.Mongos);
90
+ }
91
+
92
+ return false;
93
+ }
94
+
95
+ function databaseNamespace(ns) {
96
+ return ns.split('.')[0];
97
+ }
98
+ function collectionNamespace(ns) {
99
+ return ns
100
+ .split('.')
101
+ .slice(1)
102
+ .join('.');
103
+ }
104
+
105
+ module.exports = {
106
+ getReadPreference,
107
+ MESSAGE_HEADER_SIZE,
108
+ COMPRESSION_DETAILS_SIZE,
109
+ opcodes,
110
+ parseHeader,
111
+ applyCommonQueryOptions,
112
+ isSharded,
113
+ databaseNamespace,
114
+ collectionNamespace
115
+ };
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const MongoError = require('../error').MongoError;
4
+ const collectionNamespace = require('./shared').collectionNamespace;
5
+ const command = require('./command');
6
+
7
+ function writeCommand(server, type, opsField, ns, ops, options, callback) {
8
+ if (ops.length === 0) throw new MongoError(`${type} must contain at least one document`);
9
+ if (typeof options === 'function') {
10
+ callback = options;
11
+ options = {};
12
+ }
13
+
14
+ options = options || {};
15
+ const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
16
+ const writeConcern = options.writeConcern;
17
+
18
+ const writeCommand = {};
19
+ writeCommand[type] = collectionNamespace(ns);
20
+ writeCommand[opsField] = ops;
21
+ writeCommand.ordered = ordered;
22
+
23
+ if (writeConcern && Object.keys(writeConcern).length > 0) {
24
+ writeCommand.writeConcern = writeConcern;
25
+ }
26
+
27
+ if (options.collation) {
28
+ for (let i = 0; i < writeCommand[opsField].length; i++) {
29
+ if (!writeCommand[opsField][i].collation) {
30
+ writeCommand[opsField][i].collation = options.collation;
31
+ }
32
+ }
33
+ }
34
+
35
+ if (options.bypassDocumentValidation === true) {
36
+ writeCommand.bypassDocumentValidation = options.bypassDocumentValidation;
37
+ }
38
+
39
+ const commandOptions = Object.assign(
40
+ {
41
+ checkKeys: type === 'insert',
42
+ numberToReturn: 1
43
+ },
44
+ options
45
+ );
46
+
47
+ command(server, ns, writeCommand, commandOptions, callback);
48
+ }
49
+
50
+ module.exports = writeCommand;
package/lib/cursor.js CHANGED
@@ -6,18 +6,22 @@ const inherits = require('util').inherits;
6
6
  const deprecate = require('util').deprecate;
7
7
  const handleCallback = require('./utils').handleCallback;
8
8
  const SUPPORTS = require('./utils').SUPPORTS;
9
- const ReadPreference = require('mongodb-core').ReadPreference;
10
- const MongoError = require('mongodb-core').MongoError;
9
+ const MongoDBNamespace = require('./utils').MongoDBNamespace;
10
+ const ReadPreference = require('./core').ReadPreference;
11
+ const MongoError = require('./core').MongoError;
11
12
  const Readable = require('stream').Readable;
12
- const CoreCursor = require('mongodb-core').Cursor;
13
- const Map = require('mongodb-core').BSON.Map;
14
- const executeOperation = require('./utils').executeOperation;
13
+ const CoreCursor = require('./core').Cursor;
14
+ const Map = require('./core').BSON.Map;
15
15
 
16
- const count = require('./operations/cursor_ops').count;
17
16
  const each = require('./operations/cursor_ops').each;
18
- const hasNext = require('./operations/cursor_ops').hasNext;
19
- const next = require('./operations/cursor_ops').next;
20
- const toArray = require('./operations/cursor_ops').toArray;
17
+
18
+ const CountOperation = require('./operations/count');
19
+ const ExplainOperation = require('./operations/explain');
20
+ const HasNextOperation = require('./operations/has_next');
21
+ const NextOperation = require('./operations/next');
22
+ const ToArrayOperation = require('./operations/to_array');
23
+
24
+ const executeOperation = require('./operations/execute_operation');
21
25
 
22
26
  /**
23
27
  * @fileOverview The **Cursor** class is an internal class that embodies a cursor on MongoDB
@@ -53,7 +57,7 @@ const toArray = require('./operations/cursor_ops').toArray;
53
57
  */
54
58
 
55
59
  /**
56
- * Namespace provided by the mongodb-core and node.js
60
+ * Namespace provided by the code module
57
61
  * @external CoreCursor
58
62
  * @external Readable
59
63
  */
@@ -102,10 +106,12 @@ const fields = ['numberOfRetries', 'tailableRetryInterval'];
102
106
  *
103
107
  * collection.find({}).maxTimeMS(1000).maxScan(100).skip(1).toArray(..)
104
108
  */
105
- function Cursor(bson, ns, cmd, options, topology, topologyOptions) {
109
+ function Cursor(topology, ns, cmd, options) {
106
110
  CoreCursor.apply(this, Array.prototype.slice.call(arguments, 0));
107
111
  const state = Cursor.INIT;
108
112
  const streamOptions = {};
113
+ const bson = topology.s.bson;
114
+ const topologyOptions = topology.s.options;
109
115
 
110
116
  // Tailable cursor options
111
117
  const numberOfRetries = options.numberOfRetries || 5;
@@ -131,7 +137,7 @@ function Cursor(bson, ns, cmd, options, topology, topologyOptions) {
131
137
  // BSON
132
138
  bson: bson,
133
139
  // Namespace
134
- ns: ns,
140
+ namespace: MongoDBNamespace.fromString(ns),
135
141
  // Command
136
142
  cmd: cmd,
137
143
  // Options
@@ -210,9 +216,6 @@ if (SUPPORTS.ASYNC_ITERATOR) {
210
216
 
211
217
  // Map core cursor _next method so we can apply mapping
212
218
  Cursor.prototype._next = function() {
213
- if (this._initImplicitSession) {
214
- this._initImplicitSession();
215
- }
216
219
  return CoreCursor.prototype.next.apply(this, arguments);
217
220
  };
218
221
 
@@ -220,11 +223,14 @@ for (let name in CoreCursor.prototype) {
220
223
  Cursor.prototype[name] = CoreCursor.prototype[name];
221
224
  }
222
225
 
223
- Cursor.prototype._initImplicitSession = function() {
226
+ Cursor.prototype._initializeCursor = function(callback) {
227
+ // implicitly create a session if one has not been provided
224
228
  if (!this.s.explicitlyIgnoreSession && !this.s.session && this.s.topology.hasSessionSupport()) {
225
229
  this.s.session = this.s.topology.startSession({ owner: this });
226
230
  this.cursorState.session = this.s.session;
227
231
  }
232
+
233
+ CoreCursor.prototype._initializeCursor.apply(this, [callback]);
228
234
  };
229
235
 
230
236
  Cursor.prototype._endSession = function() {
@@ -242,9 +248,9 @@ Cursor.prototype._endSession = function() {
242
248
  * @return {Promise} returns Promise if no callback passed
243
249
  */
244
250
  Cursor.prototype.hasNext = function(callback) {
245
- return executeOperation(this.s.topology, hasNext, [this, callback], {
246
- skipSessions: true
247
- });
251
+ const hasNextOperation = new HasNextOperation(this);
252
+
253
+ return executeOperation(this.s.topology, hasNextOperation, callback);
248
254
  };
249
255
 
250
256
  /**
@@ -255,9 +261,9 @@ Cursor.prototype.hasNext = function(callback) {
255
261
  * @return {Promise} returns Promise if no callback passed
256
262
  */
257
263
  Cursor.prototype.next = function(callback) {
258
- return executeOperation(this.s.topology, next, [this, callback], {
259
- skipSessions: true
260
- });
264
+ const nextOperation = new NextOperation(this);
265
+
266
+ return executeOperation(this.s.topology, nextOperation, callback);
261
267
  };
262
268
 
263
269
  /**
@@ -826,9 +832,9 @@ Cursor.prototype.toArray = function(callback) {
826
832
  });
827
833
  }
828
834
 
829
- return executeOperation(this.s.topology, toArray, [this, callback], {
830
- skipSessions: true
831
- });
835
+ const toArrayOperation = new ToArrayOperation(this);
836
+
837
+ return executeOperation(this.s.topology, toArrayOperation, callback);
832
838
  };
833
839
 
834
840
  /**
@@ -866,9 +872,9 @@ Cursor.prototype.count = function(applySkipLimit, opts, callback) {
866
872
  opts = Object.assign({}, opts, { session: this.s.session });
867
873
  }
868
874
 
869
- return executeOperation(this.s.topology, count, [this, applySkipLimit, opts, callback], {
870
- skipSessions: !!this.s.session
871
- });
875
+ const countOperation = new CountOperation(this, applySkipLimit, opts);
876
+
877
+ return executeOperation(this.s.topology, countOperation, callback);
872
878
  };
873
879
 
874
880
  /**
@@ -1001,9 +1007,9 @@ Cursor.prototype.explain = function(callback) {
1001
1007
  delete this.s.cmd['readConcern'];
1002
1008
  }
1003
1009
 
1004
- return executeOperation(this.s.topology, this._next.bind(this), [callback], {
1005
- skipSessions: true
1006
- });
1010
+ const explainOperation = new ExplainOperation(this);
1011
+
1012
+ return executeOperation(this.s.topology, explainOperation, callback);
1007
1013
  };
1008
1014
 
1009
1015
  Cursor.prototype._read = function() {
@@ -1074,23 +1080,11 @@ Object.defineProperty(Cursor.prototype, 'readPreference', {
1074
1080
  Object.defineProperty(Cursor.prototype, 'namespace', {
1075
1081
  enumerable: true,
1076
1082
  get: function() {
1077
- if (!this || !this.s) {
1078
- return null;
1083
+ if (!(this && this.s)) {
1084
+ return;
1079
1085
  }
1080
1086
 
1081
- // TODO: refactor this logic into core
1082
- const ns = this.s.ns || '';
1083
- const firstDot = ns.indexOf('.');
1084
- if (firstDot < 0) {
1085
- return {
1086
- database: this.s.ns,
1087
- collection: ''
1088
- };
1089
- }
1090
- return {
1091
- database: ns.substr(0, firstDot),
1092
- collection: ns.substr(firstDot + 1)
1093
- };
1087
+ return this.s.namespace.toString();
1094
1088
  }
1095
1089
  });
1096
1090