Source: test/db/DBObjectEditTemplate.js

/**
 * @version  1.0
 * @author Boris GBAHOUE
 * @file Test template => edit a DBObject
 * @module amiwo/test/db
*/

// =============================================================
// BASE SETUP
// =============================================================
// call the packages we need
const debug                     = require('debug')('amiwo:test');
const util                      = require('util');
const u                         = require('../../util');
const when                      = require('when');

// load our objects
const Template                  = require('../Template');
const DBObject                  = require('../../db/DBObject');
const ResponseJSON              = require('../../rest/ResponseJSON');
const DBObjectFactory           = require('../../db/DBObjectFactory');

// =============================================================
// CONSTRUCTOR
// =============================================================
/**
 * @class
 * 
 * @constructor
 * @augments module:amiwo/test~Template
 * @param {String} name: valid DBObject name
 * @param {Object} data: data set
 * @param {Object} uri:  [{route, method}] object if not POST @ '/api/<name>'
 * @param {Object} [options]
 * @param {boolean} options.check: set to true to check if data from edited object match data
 * @param {String} options.returnedProp: name of the property which contains the object / objectId
 * @param {boolean} options.id: true => returns an ID only; false => return a full object
 * 
*/
function DBObjectEditTemplate(name, data, uri, options) {
    Template.call(this);

    this._name = name;
    this._data = data;
    this._options = options || {};
    this._uri = uri;
}

/**
* Inherit from `Template`.
*/
util.inherits(DBObjectEditTemplate, Template);

// =============================================================
// PUBLIC METHODS
// =============================================================
/**
 * Edit a new DBObject from class 'this._name' by calling the associated route
 * 
 * @return {Promise} promise wrapping the created DBObject
 */
DBObjectEditTemplate.prototype.execute = function() {
    var self = this;
    var object;
    
    return when.resolve()
    .then(function() {
        // Send a request to back server to edit the DBObject
        var options = {
            method: self._uri.method,
            uri: self._uri.route,
            json: true // Automatically stringifies the body to JSON
        };
        
        if (self._uri.method.toUpperCase() == "GET") {
            options.qs = self._data;
        } else {
            options.body = self._data;
        }

        return u.request(options);

    }).then(function(json) {
        // Expects a proper ResponseJSON
        if (!ResponseJSON.isValid(json)) return when.reject(new Error("::DBOBJECTEDITTEMPLATE::"+self._name.toUpperCase()+"::ERROR Invalid JSON returned from "+self._uri.method+"@"+self._uri.route));
        if (json.connection == "ko") return when.reject(new Error("::DBOBJECTEDITTEMPLATE::"+self._name.toUpperCase()+"::ERROR Error JSON returned from "+self._uri.method+"@"+self._uri.route));

        // Get the full object (if needed)
        var object = json.data[self._options.returnedProp];
        var promise;
        if (self._options.id) {
            promise = DBObjectFactory.createObject(self._name).findById(object);
        } else {
            promise = when.resolve(object);
        }
        
        return promise;
    }).then(function(object) {
        if (self._options.check) {
            for (var key in self._data) {
                var tmp = self.$compare(key, object[$swap(key)], self._data[key]); // for breakpoints
                if (self.$compare(key, object[$swap(key)], self._data[key])) continue;
                // else => values don't match => error
                return when.reject(new Error("::DBOBJECTEDITTEMPLATE::"+self._name.toUpperCase()+"::ERROR "+key+" don't match: create object = "+JSON.stringify(object[$swap(key)])+" vs input = "+JSON.stringify(self._data[key])))
            }
        }
        
        debug("::AMIWO::TESTS::%s::EDITTEMPLATE::LOG\t\t* %s successfully edited", self._name.toUpperCase(), self._name);
        return when.resolve(object);
    });
}

// =============================================================
// PRIVATE METHODS
// =============================================================
/**
 * @memberOf DBObjectEditTemplate
 * @private
 */
function $swap(str) {
    if (u.isEmpty(str)) return str;

    // Handle eventId, userId, chatLineId, ...    
    if (str.toLowerCase().indexOf('id') > -1) return "_id";
    return str;
}

/**
 * Compare 'createdValue' with 'inputValue' handling special cases
 * 
 * @returns {boolean}
 * @protected
 */
DBObjectEditTemplate.prototype.$compare = function(key, createdValue, inputValue) {
    //  - handle Objects (i.e. Array or Object)
    if (Array.isArray(createdValue)) {
        if ((createdValue == null) || (inputValue == null)) return false;
        if (!Array.isArray(inputValue) || (inputValue.length != createdValue.length)) return false;
        
        for (var i=0; i < createdValue.length; i++) {
            if (this.$compare(key, createdValue[i], inputValue[i])) continue;
            // we reach here if values don't match
            return false;
        }
        return true;
    } else if (createdValue instanceof Object) {
        return this._options.compareFn(key, createdValue, inputValue, $isDBObject(createdValue));
    } else {
        return this._options.compareFn(key, createdValue, inputValue);
    }
}
/**
 * Checks if 'obj' is an instanceof of DBObject or a leanified DBObject
 * 
 * @memberOf DBObjectEditTemplate
 * @private
 */
function $isDBObject(obj) {
    if (obj == null) return false;
    
    if (obj instanceof DBObject) return true;
    
    var propToTest = ["_version"];
    if ($DB_IMPLEM.toLowerCase() == "mongo") {
        propToTest.concat(["_v", "_id"]);
    }
    return u.hasOwnProperties(obj, propToTest);
}

module.exports = DBObjectEditTemplate;