Merge pull request #35 from strongloop/replace

Implement replace
This commit is contained in:
Amir-61 2016-03-28 17:06:11 -04:00
commit 505d219129
1 changed files with 138 additions and 26 deletions

View File

@ -8,6 +8,8 @@ var Transaction = require('./transaction');
module.exports = SQLConnector;
function NOOP() {}
/**
* Base class for connectors that connect to relational databases using SQL
* @class
@ -554,14 +556,8 @@ SQLConnector.prototype.buildDelete = function(model, where, options) {
* @param {Function} cb The callback function
*/
SQLConnector.prototype.destroyAll = function(model, where, options, cb) {
var self = this;
var stmt = this.buildDelete(model, where, options);
this.execute(stmt.sql, stmt.params, options, function(err, info) {
var affectedRows = self.getCountForAffectedRows(model, info);
if (cb) {
cb(err, {count: affectedRows});
}
});
this._executeAlteringQuery(model, stmt.sql, stmt.params, options, cb || NOOP);
};
// Alias to `destroyAll`. Juggler checks `destroyAll` only.
@ -582,14 +578,40 @@ Connector.defineAliases(SQLConnector.prototype, 'destroyAll', ['deleteAll']);
* @private
*/
SQLConnector.prototype.updateAttributes = function(model, id, data, options, cb) {
if (!isIdValuePresent(id, cb)) {
return;
}
if (!isIdValuePresent(id, cb)) return;
var where = this._buildWhereObjById(model, id, data);
this.updateAll(model, where, data, options, cb);
};
/**
* Replace attributes for a given model instance
* @param {String} model The model name
* @param {*} id The id value
* @param {Object} data The model data instance containing all properties to
* be replaced
* @param {Object} options Options object
* @param {Function} cb The callback function
* @private
*/
SQLConnector.prototype.replaceById = function(model, id, data, options, cb) {
if (!isIdValuePresent(id, cb)) return;
var where = this._buildWhereObjById(model, id, data);
this._replace(model, where, data, options, cb);
};
/*
* @param model The model name.
* @param id The instance ID.
* @param {Object} data The data Object.
* @returns {Object} where The where object for a spcific instance.
* @private
*/
SQLConnector.prototype._buildWhereObjById = function(model, id, data) {
var idName = this.idName(model);
delete data[idName];
var where = {};
where[idName] = id;
this.updateAll(model, where, data, options, cb);
return where;
};
/**
@ -603,6 +625,31 @@ SQLConnector.prototype.updateAttributes = function(model, id, data, options, cb)
*/
SQLConnector.prototype.buildUpdate = function(model, where, data, options) {
var fields = this.buildFieldsForUpdate(model, data);
return this._constructUpdateQuery(model, where, fields);
};
/**
* Build the UPDATE statement for replacing
* @param {String} model The model name
* @param {Object} where The where object
* @param {Object} data The data to be changed
* @param {Object} options The options object
* @param {Function} cb The callback function
* @returns {ParameterizedSQL} The UPDATE SQL statement for replacing fields
*/
SQLConnector.prototype.buildReplace = function(model, where, data, options) {
var fields = this.buildFieldsForReplace(model, data);
return this._constructUpdateQuery(model, where, fields);
};
/*
* @param model The model name.
* @param {} where The where object.
* @param {Object} field The parameterizedSQL fileds.
* @returns {Object} update query Constructed update query.
* @private
*/
SQLConnector.prototype._constructUpdateQuery = function(model, where, fields) {
var updateClause = new ParameterizedSQL('UPDATE ' + this.tableEscaped(model));
var whereClause = this.buildWhere(model, where);
updateClause.merge([fields, whereClause]);
@ -619,18 +666,35 @@ SQLConnector.prototype.buildUpdate = function(model, where, data, options) {
* @param {Function} cb The callback function
*/
SQLConnector.prototype.update = function(model, where, data, options, cb) {
var self = this;
var stmt = this.buildUpdate(model, where, data, options);
this.execute(stmt.sql, stmt.params, options, function(err, info) {
this._executeAlteringQuery(model, stmt.sql, stmt.params, options, cb || NOOP);
};
/**
* Replace all instances that match the where clause with the given data
* @param {String} model The model name
* @param {Object} where The where object
* @param {Object} data The property/value object representing changes
* to be made
* @param {Object} options The options object
* @param {Function} cb The callback function
*/
SQLConnector.prototype._replace = function(model, where, data, options, cb) {
var stmt = this.buildReplace(model, where, data, options);
this.execute(stmt.sql, stmt.params, options, cb);
};
SQLConnector.prototype._executeAlteringQuery = function(model, sql, params, options, cb) {
var self = this;
this.execute(sql, params, options, function(err, info) {
var affectedRows = self.getCountForAffectedRows(model, info);
if (cb) {
cb(err, {count: affectedRows});
}
cb(err, {count: affectedRows});
});
};
// Alias to `update`. Juggler checks `update` only.
// Alias to `update` and `replace`. Juggler checks `update` and `replace` only.
Connector.defineAliases(SQLConnector.prototype, 'update', ['updateAll']);
Connector.defineAliases(SQLConnector.prototype, 'replace', ['replaceAll']);
/**
* Build the SQL WHERE clause for the where object
@ -885,13 +949,37 @@ SQLConnector.prototype.buildOrderBy = function(model, order) {
* @returns {{names: Array, values: Array, properties: Array}}
*/
SQLConnector.prototype.buildFields = function(model, data, excludeIds) {
var keys = Object.keys(data);
return this._buildFieldsForKeys(model, data, keys, excludeIds);
};
/**
* Build an array of fields for the replace database operation
* @param {String} model Model name
* @param {Object} data Model data object
* @param {Boolean} excludeIds Exclude id properties or not, default to false
* @returns {{names: Array, values: Array, properties: Array}}
*/
SQLConnector.prototype.buildReplaceFields = function(model, data, excludeIds) {
var props = this.getModelDefinition(model).properties;
var keys = Object.keys(props);
return this._buildFieldsForKeys(model, data, keys, excludeIds);
};
/*
* @param {String} model The model name.
* @returns {Object} data The model data object.
* @returns {Array} keys The key fields for which need to be built.
* @param {Boolean} excludeIds Exclude id properties or not, default to false
* @private
*/
SQLConnector.prototype._buildFieldsForKeys = function(model, data, keys, excludeIds) {
var props = this.getModelDefinition(model).properties;
var fields = {
names: [], // field names
columnValues: [], // an array of ParameterizedSQL
properties: [] // model properties
};
var props = this.getModelDefinition(model).properties;
var keys = Object.keys(data);
};
for (var i = 0, n = keys.length; i < n; i++) {
var key = keys[i];
var p = props[key];
@ -900,10 +988,10 @@ SQLConnector.prototype.buildFields = function(model, data, excludeIds) {
debug('Unknown property %s is skipped for model %s', key, model);
continue;
}
if (excludeIds && p.id) {
continue;
}
var k = this.columnEscaped(model, key);
var v = this.toColumnValue(p, data[key]);
if (v !== undefined) {
@ -920,17 +1008,41 @@ SQLConnector.prototype.buildFields = function(model, data, excludeIds) {
};
/**
* Build the SET clause for database update
* @param {String} model Model na
* @param {Object} data The model data object
* @param {Boolean} excludeIds Exclude id properties or not, default to true
* @returns {string} The list of fields for update
* Build the SET clause for database update.
* @param {String} model Model name.
* @param {Object} data The model data object.
* @param {Boolean} excludeIds Exclude id properties or not, default to true.
* @returns {string} The list of fields for update query.
*/
SQLConnector.prototype.buildFieldsForUpdate = function(model, data, excludeIds) {
if (excludeIds === undefined) {
excludeIds = true;
}
var fields = this.buildFields(model, data, excludeIds);
return this._constructUpdateParameterizedSQL(fields);
};
/**
* Build the SET clause for database replace through update query.
* @param {String} model Model name.
* @param {Object} data The model data object.
* @param {Boolean} excludeIds Exclude id properties or not, default to true.
* @returns {string} The list of fields for update query.
*/
SQLConnector.prototype.buildFieldsForReplace = function(model, data, excludeIds) {
if (excludeIds === undefined) {
excludeIds = true;
}
var fields = this.buildReplaceFields(model, data, excludeIds);
return this._constructUpdateParameterizedSQL(fields);
};
/*
* @param {Object} field The fileds.
* @returns {Object} parameterizedSQL.
* @private
*/
SQLConnector.prototype._constructUpdateParameterizedSQL = function(fields) {
var columns = new ParameterizedSQL('');
for (var i = 0, n = fields.names.length; i < n; i++) {
var clause = ParameterizedSQL.append(fields.names[i],