all files / lib/waterline/model/lib/associationMethods/ update.js

89.19% Statements 33/37
71.43% Branches 15/21
100% Functions 3/3
94.29% Lines 33/35
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101                                    145× 145× 145×   145×         145×           145× 145×     145×         145× 145×         539×         532×     532× 532×     532× 532× 532×       145×                       145×   145× 418× 145× 145×         145×   145×    
 
/**
 * Module dependencies
 */
 
var _ = require('lodash');
var utils = require('../../../utils/helpers');
var nestedOperations = require('../../../utils/nestedOperations');
var hop = utils.object.hasOwnProperty;
 
/**
 * Update the current instance with the currently set values
 *
 * Called in the model instance context.
 *
 * @param {Object} collection
 * @param {Object} proto
 * @param {Array} mutatedModels
 * @param {Function} callback
 */
 
var Update = module.exports = function(collection, proto, mutatedModels, cb) {
 
  var values = typeof proto.toObject === 'function' ? proto.toObject() : proto;
  var attributes = collection.waterline.schema[collection.identity].attributes;
  var primaryKey = this.findPrimaryKey(attributes, values);
 
  Iif (!primaryKey) {
    return cb(new Error('No Primary Key set to update the record with! ' +
      'Try setting an attribute as a primary key or include an ID property.'));
  }
 
  Iif (!values[primaryKey]) {
    return cb(new Error('No Primary Key set to update the record with! ' +
      'Primary Key must have a value, it can\'t be an optional value.'));
  }
 
  // Build Search Criteria
  var criteria = {};
  criteria[primaryKey] = values[primaryKey];
 
  // Clone values so they can be mutated
  var _values = _.cloneDeep(values);
 
  // For any nested model associations (objects not collection arrays) that were not changed,
  // lets set the value to just the foreign key so that an update query is not performed on the
  // associatied model.
  var keys = _.keys(_values);
  keys.forEach(function(key) {
 
    // Nix any collection attributes so that they do not get sync'd during the update process.
    // One reason for this is that the result set is not guaranteed to be complete,
    // so the sync could exclude items.
    if (attributes[key] && hop(attributes[key], 'collection') && attributes[key].collection) {
 
      delete _values[key];
      return;
    }
 
    // If the key was changed, keep it expanded
    Iif (mutatedModels.indexOf(key) !== -1) return;
 
    // Reduce it down to a foreign key value
    var vals = {};
    vals[key] = _values[key];
 
    // Delete and replace the value with a reduced version
    delete _values[key];
    var reduced = nestedOperations.reduceAssociations.call(collection, collection.identity, collection.waterline.schema, vals);
    _values = _.merge(_values, reduced);
  });
 
  // Update the collection with the new values
  collection.update(criteria, _values, cb);
};
 
 
/**
 * Find Primary Key
 *
 * @param {Object} attributes
 * @param {Object} values
 * @api private
 */
 
Update.prototype.findPrimaryKey = function(attributes, values) {
  var primaryKey = null;
 
  for (var attribute in attributes) {
    if (hop(attributes[attribute], 'primaryKey') && attributes[attribute].primaryKey) {
      primaryKey = attribute;
      break;
    }
  }
 
  // If no primary key check for an ID property
  Iif (!primaryKey && hop(values, 'id')) primaryKey = 'id';
 
  return primaryKey;
};