PageRenderTime 58ms CodeModel.GetById 9ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

/node_modules/mongoose/node_modules/mongodb/lib/bulk/common.js

https://bitbucket.org/coleman333/smartsite
JavaScript | 465 lines | 271 code | 60 blank | 134 comment | 84 complexity | 56ecd331584bb0287aca61a5bdf1e9da MD5 | raw file
  1'use strict';
  2
  3var Long = require('mongodb-core').BSON.Long,
  4  MongoError = require('mongodb-core').MongoError,
  5  util = require('util');
  6
  7// Error codes
  8var UNKNOWN_ERROR = 8;
  9var INVALID_BSON_ERROR = 22;
 10var WRITE_CONCERN_ERROR = 64;
 11var MULTIPLE_ERROR = 65;
 12
 13// Insert types
 14var INSERT = 1;
 15var UPDATE = 2;
 16var REMOVE = 3;
 17
 18// Get write concern
 19var writeConcern = function(target, col, options) {
 20  var writeConcern = {};
 21
 22  // Collection level write concern
 23  if (col.writeConcern && col.writeConcern.w != null) writeConcern.w = col.writeConcern.w;
 24  if (col.writeConcern && col.writeConcern.j != null) writeConcern.j = col.writeConcern.j;
 25  if (col.writeConcern && col.writeConcern.fsync != null)
 26    writeConcern.fsync = col.writeConcern.fsync;
 27  if (col.writeConcern && col.writeConcern.wtimeout != null)
 28    writeConcern.wtimeout = col.writeConcern.wtimeout;
 29
 30  // Options level write concern
 31  if (options && options.w != null) writeConcern.w = options.w;
 32  if (options && options.wtimeout != null) writeConcern.wtimeout = options.wtimeout;
 33  if (options && options.j != null) writeConcern.j = options.j;
 34  if (options && options.fsync != null) writeConcern.fsync = options.fsync;
 35
 36  // Return write concern
 37  return writeConcern;
 38};
 39
 40/**
 41 * Helper function to define properties
 42 * @ignore
 43 */
 44var defineReadOnlyProperty = function(self, name, value) {
 45  Object.defineProperty(self, name, {
 46    enumerable: true,
 47    get: function() {
 48      return value;
 49    }
 50  });
 51};
 52
 53/**
 54 * Keeps the state of a unordered batch so we can rewrite the results
 55 * correctly after command execution
 56 * @ignore
 57 */
 58var Batch = function(batchType, originalZeroIndex) {
 59  this.originalZeroIndex = originalZeroIndex;
 60  this.currentIndex = 0;
 61  this.originalIndexes = [];
 62  this.batchType = batchType;
 63  this.operations = [];
 64  this.size = 0;
 65  this.sizeBytes = 0;
 66};
 67
 68/**
 69 * Wraps a legacy operation so we can correctly rewrite it's error
 70 * @ignore
 71 */
 72var LegacyOp = function(batchType, operation, index) {
 73  this.batchType = batchType;
 74  this.index = index;
 75  this.operation = operation;
 76};
 77
 78/**
 79 * Create a new BulkWriteResult instance (INTERNAL TYPE, do not instantiate directly)
 80 *
 81 * @class
 82 * @property {boolean} ok Did bulk operation correctly execute
 83 * @property {number} nInserted number of inserted documents
 84 * @property {number} nUpdated number of documents updated logically
 85 * @property {number} nUpserted Number of upserted documents
 86 * @property {number} nModified Number of documents updated physically on disk
 87 * @property {number} nRemoved Number of removed documents
 88 * @return {BulkWriteResult} a BulkWriteResult instance
 89 */
 90var BulkWriteResult = function(bulkResult) {
 91  defineReadOnlyProperty(this, 'ok', bulkResult.ok);
 92  defineReadOnlyProperty(this, 'nInserted', bulkResult.nInserted);
 93  defineReadOnlyProperty(this, 'nUpserted', bulkResult.nUpserted);
 94  defineReadOnlyProperty(this, 'nMatched', bulkResult.nMatched);
 95  defineReadOnlyProperty(this, 'nModified', bulkResult.nModified);
 96  defineReadOnlyProperty(this, 'nRemoved', bulkResult.nRemoved);
 97
 98  /**
 99   * Return an array of inserted ids
100   *
101   * @return {object[]}
102   */
103  this.getInsertedIds = function() {
104    return bulkResult.insertedIds;
105  };
106
107  /**
108   * Return an array of upserted ids
109   *
110   * @return {object[]}
111   */
112  this.getUpsertedIds = function() {
113    return bulkResult.upserted;
114  };
115
116  /**
117   * Return the upserted id at position x
118   *
119   * @param {number} index the number of the upserted id to return, returns undefined if no result for passed in index
120   * @return {object}
121   */
122  this.getUpsertedIdAt = function(index) {
123    return bulkResult.upserted[index];
124  };
125
126  /**
127   * Return raw internal result
128   *
129   * @return {object}
130   */
131  this.getRawResponse = function() {
132    return bulkResult;
133  };
134
135  /**
136   * Returns true if the bulk operation contains a write error
137   *
138   * @return {boolean}
139   */
140  this.hasWriteErrors = function() {
141    return bulkResult.writeErrors.length > 0;
142  };
143
144  /**
145   * Returns the number of write errors off the bulk operation
146   *
147   * @return {number}
148   */
149  this.getWriteErrorCount = function() {
150    return bulkResult.writeErrors.length;
151  };
152
153  /**
154   * Returns a specific write error object
155   *
156   * @param {number} index of the write error to return, returns null if there is no result for passed in index
157   * @return {WriteError}
158   */
159  this.getWriteErrorAt = function(index) {
160    if (index < bulkResult.writeErrors.length) {
161      return bulkResult.writeErrors[index];
162    }
163    return null;
164  };
165
166  /**
167   * Retrieve all write errors
168   *
169   * @return {object[]}
170   */
171  this.getWriteErrors = function() {
172    return bulkResult.writeErrors;
173  };
174
175  /**
176   * Retrieve lastOp if available
177   *
178   * @return {object}
179   */
180  this.getLastOp = function() {
181    return bulkResult.lastOp;
182  };
183
184  /**
185   * Retrieve the write concern error if any
186   *
187   * @return {WriteConcernError}
188   */
189  this.getWriteConcernError = function() {
190    if (bulkResult.writeConcernErrors.length === 0) {
191      return null;
192    } else if (bulkResult.writeConcernErrors.length === 1) {
193      // Return the error
194      return bulkResult.writeConcernErrors[0];
195    } else {
196      // Combine the errors
197      var errmsg = '';
198      for (var i = 0; i < bulkResult.writeConcernErrors.length; i++) {
199        var err = bulkResult.writeConcernErrors[i];
200        errmsg = errmsg + err.errmsg;
201
202        // TODO: Something better
203        if (i === 0) errmsg = errmsg + ' and ';
204      }
205
206      return new WriteConcernError({ errmsg: errmsg, code: WRITE_CONCERN_ERROR });
207    }
208  };
209
210  this.toJSON = function() {
211    return bulkResult;
212  };
213
214  this.toString = function() {
215    return 'BulkWriteResult(' + this.toJSON(bulkResult) + ')';
216  };
217
218  this.isOk = function() {
219    return bulkResult.ok === 1;
220  };
221};
222
223/**
224 * Create a new WriteConcernError instance (INTERNAL TYPE, do not instantiate directly)
225 *
226 * @class
227 * @property {number} code Write concern error code.
228 * @property {string} errmsg Write concern error message.
229 * @return {WriteConcernError} a WriteConcernError instance
230 */
231var WriteConcernError = function(err) {
232  if (!(this instanceof WriteConcernError)) return new WriteConcernError(err);
233
234  // Define properties
235  defineReadOnlyProperty(this, 'code', err.code);
236  defineReadOnlyProperty(this, 'errmsg', err.errmsg);
237
238  this.toJSON = function() {
239    return { code: err.code, errmsg: err.errmsg };
240  };
241
242  this.toString = function() {
243    return 'WriteConcernError(' + err.errmsg + ')';
244  };
245};
246
247/**
248 * Create a new WriteError instance (INTERNAL TYPE, do not instantiate directly)
249 *
250 * @class
251 * @property {number} code Write concern error code.
252 * @property {number} index Write concern error original bulk operation index.
253 * @property {string} errmsg Write concern error message.
254 * @return {WriteConcernError} a WriteConcernError instance
255 */
256var WriteError = function(err) {
257  if (!(this instanceof WriteError)) return new WriteError(err);
258
259  // Define properties
260  defineReadOnlyProperty(this, 'code', err.code);
261  defineReadOnlyProperty(this, 'index', err.index);
262  defineReadOnlyProperty(this, 'errmsg', err.errmsg);
263
264  //
265  // Define access methods
266  this.getOperation = function() {
267    return err.op;
268  };
269
270  this.toJSON = function() {
271    return { code: err.code, index: err.index, errmsg: err.errmsg, op: err.op };
272  };
273
274  this.toString = function() {
275    return 'WriteError(' + JSON.stringify(this.toJSON()) + ')';
276  };
277};
278
279/**
280 * Merges results into shared data structure
281 * @ignore
282 */
283var mergeBatchResults = function(ordered, batch, bulkResult, err, result) {
284  // If we have an error set the result to be the err object
285  if (err) {
286    result = err;
287  } else if (result && result.result) {
288    result = result.result;
289  } else if (result == null) {
290    return;
291  }
292
293  // Do we have a top level error stop processing and return
294  if (result.ok === 0 && bulkResult.ok === 1) {
295    bulkResult.ok = 0;
296
297    var writeError = {
298      index: 0,
299      code: result.code || 0,
300      errmsg: result.message,
301      op: batch.operations[0]
302    };
303
304    bulkResult.writeErrors.push(new WriteError(writeError));
305    return;
306  } else if (result.ok === 0 && bulkResult.ok === 0) {
307    return;
308  }
309
310  // Deal with opTime if available
311  if (result.opTime || result.lastOp) {
312    var opTime = result.lastOp || result.opTime;
313    var lastOpTS = null;
314    var lastOpT = null;
315
316    // We have a time stamp
317    if (opTime && opTime._bsontype === 'Timestamp') {
318      if (bulkResult.lastOp == null) {
319        bulkResult.lastOp = opTime;
320      } else if (opTime.greaterThan(bulkResult.lastOp)) {
321        bulkResult.lastOp = opTime;
322      }
323    } else {
324      // Existing TS
325      if (bulkResult.lastOp) {
326        lastOpTS =
327          typeof bulkResult.lastOp.ts === 'number'
328            ? Long.fromNumber(bulkResult.lastOp.ts)
329            : bulkResult.lastOp.ts;
330        lastOpT =
331          typeof bulkResult.lastOp.t === 'number'
332            ? Long.fromNumber(bulkResult.lastOp.t)
333            : bulkResult.lastOp.t;
334      }
335
336      // Current OpTime TS
337      var opTimeTS = typeof opTime.ts === 'number' ? Long.fromNumber(opTime.ts) : opTime.ts;
338      var opTimeT = typeof opTime.t === 'number' ? Long.fromNumber(opTime.t) : opTime.t;
339
340      // Compare the opTime's
341      if (bulkResult.lastOp == null) {
342        bulkResult.lastOp = opTime;
343      } else if (opTimeTS.greaterThan(lastOpTS)) {
344        bulkResult.lastOp = opTime;
345      } else if (opTimeTS.equals(lastOpTS)) {
346        if (opTimeT.greaterThan(lastOpT)) {
347          bulkResult.lastOp = opTime;
348        }
349      }
350    }
351  }
352
353  // If we have an insert Batch type
354  if (batch.batchType === INSERT && result.n) {
355    bulkResult.nInserted = bulkResult.nInserted + result.n;
356  }
357
358  // If we have an insert Batch type
359  if (batch.batchType === REMOVE && result.n) {
360    bulkResult.nRemoved = bulkResult.nRemoved + result.n;
361  }
362
363  var nUpserted = 0;
364
365  // We have an array of upserted values, we need to rewrite the indexes
366  if (Array.isArray(result.upserted)) {
367    nUpserted = result.upserted.length;
368
369    for (var i = 0; i < result.upserted.length; i++) {
370      bulkResult.upserted.push({
371        index: result.upserted[i].index + batch.originalZeroIndex,
372        _id: result.upserted[i]._id
373      });
374    }
375  } else if (result.upserted) {
376    nUpserted = 1;
377
378    bulkResult.upserted.push({
379      index: batch.originalZeroIndex,
380      _id: result.upserted
381    });
382  }
383
384  // If we have an update Batch type
385  if (batch.batchType === UPDATE && result.n) {
386    var nModified = result.nModified;
387    bulkResult.nUpserted = bulkResult.nUpserted + nUpserted;
388    bulkResult.nMatched = bulkResult.nMatched + (result.n - nUpserted);
389
390    if (typeof nModified === 'number') {
391      bulkResult.nModified = bulkResult.nModified + nModified;
392    } else {
393      bulkResult.nModified = null;
394    }
395  }
396
397  if (Array.isArray(result.writeErrors)) {
398    for (i = 0; i < result.writeErrors.length; i++) {
399      writeError = {
400        index: batch.originalZeroIndex + result.writeErrors[i].index,
401        code: result.writeErrors[i].code,
402        errmsg: result.writeErrors[i].errmsg,
403        op: batch.operations[result.writeErrors[i].index]
404      };
405
406      bulkResult.writeErrors.push(new WriteError(writeError));
407    }
408  }
409
410  if (result.writeConcernError) {
411    bulkResult.writeConcernErrors.push(new WriteConcernError(result.writeConcernError));
412  }
413};
414
415//
416// Clone the options
417var cloneOptions = function(options) {
418  var clone = {};
419  var keys = Object.keys(options);
420  for (var i = 0; i < keys.length; i++) {
421    clone[keys[i]] = options[keys[i]];
422  }
423
424  return clone;
425};
426
427/**
428 * Creates a new BulkWriteError
429 *
430 * @class
431 * @param {Error|string|object} message The error message
432 * @param {BulkWriteResult} result The result of the bulk write operation
433 * @return {BulkWriteError} A BulkWriteError instance
434 * @extends {MongoError}
435 */
436const BulkWriteError = function(error, result) {
437  var message = error.err || error.errmsg || error.errMessage || error;
438  MongoError.call(this, message);
439
440  var keys = typeof error === 'object' ? Object.keys(error) : [];
441  for (var i = 0; i < keys.length; i++) {
442    this[keys[i]] = error[keys[i]];
443  }
444
445  this.name = 'BulkWriteError';
446  this.result = result;
447};
448util.inherits(BulkWriteError, MongoError);
449
450// Exports symbols
451exports.BulkWriteError = BulkWriteError;
452exports.BulkWriteResult = BulkWriteResult;
453exports.WriteError = WriteError;
454exports.Batch = Batch;
455exports.LegacyOp = LegacyOp;
456exports.mergeBatchResults = mergeBatchResults;
457exports.cloneOptions = cloneOptions;
458exports.writeConcern = writeConcern;
459exports.INVALID_BSON_ERROR = INVALID_BSON_ERROR;
460exports.WRITE_CONCERN_ERROR = WRITE_CONCERN_ERROR;
461exports.MULTIPLE_ERROR = MULTIPLE_ERROR;
462exports.UNKNOWN_ERROR = UNKNOWN_ERROR;
463exports.INSERT = INSERT;
464exports.UPDATE = UPDATE;
465exports.REMOVE = REMOVE;