common.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. "use strict";
  2. var utils = require('../utils');
  3. // Error codes
  4. var UNKNOWN_ERROR = 8;
  5. var INVALID_BSON_ERROR = 22;
  6. var WRITE_CONCERN_ERROR = 64;
  7. var MULTIPLE_ERROR = 65;
  8. // Insert types
  9. var INSERT = 1;
  10. var UPDATE = 2;
  11. var REMOVE = 3
  12. // Get write concern
  13. var writeConcern = function(target, col, options) {
  14. if(options.w != null || options.j != null || options.fsync != null) {
  15. target.writeConcern = options;
  16. } else if(col.writeConcern.w != null || col.writeConcern.j != null || col.writeConcern.fsync != null) {
  17. target.writeConcern = col.writeConcern;
  18. }
  19. return target
  20. }
  21. /**
  22. * Helper function to define properties
  23. * @ignore
  24. */
  25. var defineReadOnlyProperty = function(self, name, value) {
  26. Object.defineProperty(self, name, {
  27. enumerable: true
  28. , get: function() {
  29. return value;
  30. }
  31. });
  32. }
  33. /**
  34. * Keeps the state of a unordered batch so we can rewrite the results
  35. * correctly after command execution
  36. * @ignore
  37. */
  38. var Batch = function(batchType, originalZeroIndex) {
  39. this.originalZeroIndex = originalZeroIndex;
  40. this.currentIndex = 0;
  41. this.originalIndexes = [];
  42. this.batchType = batchType;
  43. this.operations = [];
  44. this.size = 0;
  45. this.sizeBytes = 0;
  46. }
  47. /**
  48. * Wraps a legacy operation so we can correctly rewrite it's error
  49. * @ignore
  50. */
  51. var LegacyOp = function(batchType, operation, index) {
  52. this.batchType = batchType;
  53. this.index = index;
  54. this.operation = operation;
  55. }
  56. /**
  57. * Create a new BulkWriteResult instance (INTERNAL TYPE, do not instantiate directly)
  58. *
  59. * @class
  60. * @property {boolean} ok Did bulk operation correctly execute
  61. * @property {number} nInserted number of inserted documents
  62. * @property {number} nUpdated number of documents updated logically
  63. * @property {number} nUpserted Number of upserted documents
  64. * @property {number} nModified Number of documents updated physically on disk
  65. * @property {number} nRemoved Number of removed documents
  66. * @return {BulkWriteResult} a BulkWriteResult instance
  67. */
  68. var BulkWriteResult = function(bulkResult) {
  69. defineReadOnlyProperty(this, "ok", bulkResult.ok);
  70. defineReadOnlyProperty(this, "nInserted", bulkResult.nInserted);
  71. defineReadOnlyProperty(this, "nUpserted", bulkResult.nUpserted);
  72. defineReadOnlyProperty(this, "nMatched", bulkResult.nMatched);
  73. defineReadOnlyProperty(this, "nModified", bulkResult.nModified);
  74. defineReadOnlyProperty(this, "nRemoved", bulkResult.nRemoved);
  75. /**
  76. * Return an array of inserted ids
  77. *
  78. * @return {object[]}
  79. */
  80. this.getInsertedIds = function() {
  81. return bulkResult.insertedIds;
  82. }
  83. /**
  84. * Return an array of upserted ids
  85. *
  86. * @return {object[]}
  87. */
  88. this.getUpsertedIds = function() {
  89. return bulkResult.upserted;
  90. }
  91. /**
  92. * Return the upserted id at position x
  93. *
  94. * @param {number} index the number of the upserted id to return, returns undefined if no result for passed in index
  95. * @return {object}
  96. */
  97. this.getUpsertedIdAt = function(index) {
  98. return bulkResult.upserted[index];
  99. }
  100. /**
  101. * Return raw internal result
  102. *
  103. * @return {object}
  104. */
  105. this.getRawResponse = function() {
  106. return bulkResult;
  107. }
  108. /**
  109. * Returns true if the bulk operation contains a write error
  110. *
  111. * @return {boolean}
  112. */
  113. this.hasWriteErrors = function() {
  114. return bulkResult.writeErrors.length > 0;
  115. }
  116. /**
  117. * Returns the number of write errors off the bulk operation
  118. *
  119. * @return {number}
  120. */
  121. this.getWriteErrorCount = function() {
  122. return bulkResult.writeErrors.length;
  123. }
  124. /**
  125. * Returns a specific write error object
  126. *
  127. * @return {WriteError}
  128. */
  129. this.getWriteErrorAt = function(index) {
  130. if(index < bulkResult.writeErrors.length) {
  131. return bulkResult.writeErrors[index];
  132. }
  133. return null;
  134. }
  135. /**
  136. * Retrieve all write errors
  137. *
  138. * @return {object[]}
  139. */
  140. this.getWriteErrors = function() {
  141. return bulkResult.writeErrors;
  142. }
  143. /**
  144. * Retrieve lastOp if available
  145. *
  146. * @return {object}
  147. */
  148. this.getLastOp = function() {
  149. return bulkResult.lastOp;
  150. }
  151. /**
  152. * Retrieve the write concern error if any
  153. *
  154. * @return {WriteConcernError}
  155. */
  156. this.getWriteConcernError = function() {
  157. if(bulkResult.writeConcernErrors.length == 0) {
  158. return null;
  159. } else if(bulkResult.writeConcernErrors.length == 1) {
  160. // Return the error
  161. return bulkResult.writeConcernErrors[0];
  162. } else {
  163. // Combine the errors
  164. var errmsg = "";
  165. for(var i = 0; i < bulkResult.writeConcernErrors.length; i++) {
  166. var err = bulkResult.writeConcernErrors[i];
  167. errmsg = errmsg + err.errmsg;
  168. // TODO: Something better
  169. if(i == 0) errmsg = errmsg + " and ";
  170. }
  171. return new WriteConcernError({ errmsg : errmsg, code : WRITE_CONCERN_ERROR });
  172. }
  173. }
  174. this.toJSON = function() {
  175. return bulkResult;
  176. }
  177. this.toString = function() {
  178. return "BulkWriteResult(" + this.toJSON(bulkResult) + ")";
  179. }
  180. this.isOk = function() {
  181. return bulkResult.ok == 1;
  182. }
  183. }
  184. /**
  185. * Create a new WriteConcernError instance (INTERNAL TYPE, do not instantiate directly)
  186. *
  187. * @class
  188. * @property {number} code Write concern error code.
  189. * @property {string} errmsg Write concern error message.
  190. * @return {WriteConcernError} a WriteConcernError instance
  191. */
  192. var WriteConcernError = function(err) {
  193. if(!(this instanceof WriteConcernError)) return new WriteConcernError(err);
  194. // Define properties
  195. defineReadOnlyProperty(this, "code", err.code);
  196. defineReadOnlyProperty(this, "errmsg", err.errmsg);
  197. this.toJSON = function() {
  198. return {code: err.code, errmsg: err.errmsg};
  199. }
  200. this.toString = function() {
  201. return "WriteConcernError(" + err.errmsg + ")";
  202. }
  203. }
  204. /**
  205. * Create a new WriteError instance (INTERNAL TYPE, do not instantiate directly)
  206. *
  207. * @class
  208. * @property {number} code Write concern error code.
  209. * @property {number} index Write concern error original bulk operation index.
  210. * @property {string} errmsg Write concern error message.
  211. * @return {WriteConcernError} a WriteConcernError instance
  212. */
  213. var WriteError = function(err) {
  214. if(!(this instanceof WriteError)) return new WriteError(err);
  215. // Define properties
  216. defineReadOnlyProperty(this, "code", err.code);
  217. defineReadOnlyProperty(this, "index", err.index);
  218. defineReadOnlyProperty(this, "errmsg", err.errmsg);
  219. //
  220. // Define access methods
  221. this.getOperation = function() {
  222. return err.op;
  223. }
  224. this.toJSON = function() {
  225. return {code: err.code, index: err.index, errmsg: err.errmsg, op: err.op};
  226. }
  227. this.toString = function() {
  228. return "WriteError(" + JSON.stringify(this.toJSON()) + ")";
  229. }
  230. }
  231. /**
  232. * Merges results into shared data structure
  233. * @ignore
  234. */
  235. var mergeBatchResults = function(ordered, batch, bulkResult, err, result) {
  236. // If we have an error set the result to be the err object
  237. if(err) {
  238. result = err;
  239. } else if(result && result.result) {
  240. result = result.result;
  241. } else if(result == null) {
  242. return;
  243. }
  244. // Do we have a top level error stop processing and return
  245. if(result.ok == 0 && bulkResult.ok == 1) {
  246. bulkResult.ok = 0;
  247. // bulkResult.error = utils.toError(result);
  248. var writeError = {
  249. index: 0
  250. , code: result.code || 0
  251. , errmsg: result.message
  252. , op: batch.operations[0]
  253. };
  254. bulkResult.writeErrors.push(new WriteError(writeError));
  255. return;
  256. } else if(result.ok == 0 && bulkResult.ok == 0) {
  257. return;
  258. }
  259. // Add lastop if available
  260. if(result.lastOp) {
  261. bulkResult.lastOp = result.lastOp;
  262. }
  263. // If we have an insert Batch type
  264. if(batch.batchType == INSERT && result.n) {
  265. bulkResult.nInserted = bulkResult.nInserted + result.n;
  266. }
  267. // If we have an insert Batch type
  268. if(batch.batchType == REMOVE && result.n) {
  269. bulkResult.nRemoved = bulkResult.nRemoved + result.n;
  270. }
  271. var nUpserted = 0;
  272. // We have an array of upserted values, we need to rewrite the indexes
  273. if(Array.isArray(result.upserted)) {
  274. nUpserted = result.upserted.length;
  275. for(var i = 0; i < result.upserted.length; i++) {
  276. bulkResult.upserted.push({
  277. index: result.upserted[i].index + batch.originalZeroIndex
  278. , _id: result.upserted[i]._id
  279. });
  280. }
  281. } else if(result.upserted) {
  282. nUpserted = 1;
  283. bulkResult.upserted.push({
  284. index: batch.originalZeroIndex
  285. , _id: result.upserted
  286. });
  287. }
  288. // If we have an update Batch type
  289. if(batch.batchType == UPDATE && result.n) {
  290. var nModified = result.nModified;
  291. bulkResult.nUpserted = bulkResult.nUpserted + nUpserted;
  292. bulkResult.nMatched = bulkResult.nMatched + (result.n - nUpserted);
  293. if(typeof nModified == 'number') {
  294. bulkResult.nModified = bulkResult.nModified + nModified;
  295. } else {
  296. bulkResult.nModified = null;
  297. }
  298. }
  299. if(Array.isArray(result.writeErrors)) {
  300. for(var i = 0; i < result.writeErrors.length; i++) {
  301. var writeError = {
  302. index: batch.originalZeroIndex + result.writeErrors[i].index
  303. , code: result.writeErrors[i].code
  304. , errmsg: result.writeErrors[i].errmsg
  305. , op: batch.operations[result.writeErrors[i].index]
  306. };
  307. bulkResult.writeErrors.push(new WriteError(writeError));
  308. }
  309. }
  310. if(result.writeConcernError) {
  311. bulkResult.writeConcernErrors.push(new WriteConcernError(result.writeConcernError));
  312. }
  313. }
  314. //
  315. // Clone the options
  316. var cloneOptions = function(options) {
  317. var clone = {};
  318. var keys = Object.keys(options);
  319. for(var i = 0; i < keys.length; i++) {
  320. clone[keys[i]] = options[keys[i]];
  321. }
  322. return clone;
  323. }
  324. // Exports symbols
  325. exports.BulkWriteResult = BulkWriteResult;
  326. exports.WriteError = WriteError;
  327. exports.Batch = Batch;
  328. exports.LegacyOp = LegacyOp;
  329. exports.mergeBatchResults = mergeBatchResults;
  330. exports.cloneOptions = cloneOptions;
  331. exports.writeConcern = writeConcern;
  332. exports.INVALID_BSON_ERROR = INVALID_BSON_ERROR;
  333. exports.WRITE_CONCERN_ERROR = WRITE_CONCERN_ERROR;
  334. exports.MULTIPLE_ERROR = MULTIPLE_ERROR;
  335. exports.UNKNOWN_ERROR = UNKNOWN_ERROR;
  336. exports.INSERT = INSERT;
  337. exports.UPDATE = UPDATE;
  338. exports.REMOVE = REMOVE;