/**
* @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;