Skip to content

Commit

Permalink
Merge pull request loopbackio#27 from strongloop/feature/fix-custom-c…
Browse files Browse the repository at this point in the history
…olumn

Add support for custom column mapping
  • Loading branch information
raymondfeng committed Feb 21, 2015
2 parents d5090cb + 30e5ee1 commit efd3644
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 58 deletions.
115 changes: 64 additions & 51 deletions lib/mssql.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ MsSQL.prototype.create = function (model, data, callback) {

var columns = fieldsAndData.fields ? " (" + fieldsAndData.fields + ")" : "";
var sql = "INSERT INTO " + tblName + columns + MsSQL.newline;
sql += "OUTPUT INSERTED." + modelPKID + " AS insertId" + MsSQL.newline;
sql += "OUTPUT INSERTED." + this.columnEscaped(model, modelPKID)
+ " AS insertId" + MsSQL.newline;
sql += (fieldsAndData.paramPlaceholders ?
"VALUES (" + fieldsAndData.paramPlaceholders + ");" :
"DEFAULT VALUES;");
Expand All @@ -183,14 +184,33 @@ MsSQL.prototype.updateOrCreate = function (model, data, callback) {
var fieldValues = [];
var fieldValuesPlaceholders = [];
var combined = [];

var doQuery = function (sql, fieldValues) {
self.query(sql, fieldValues, function (err, results) {
if (err) {
return callback(err);
}
//msnodesql will execute the callback for each statement that get's
// executed, we're only interested in the one that returns with the pkid
if (results.length > 0 && results[0].pkid) {
data[modelPKID] = results[0].pkid;
//#jdb id compatibility#
data.id = results[0].pkid; //set the id property also, to play nice
// with the jugglingdb abstract class implementation.
callback(err, data);
}
});
};

Object.keys(data).forEach(function (key) {
if (props[key]) {
//check for the "id" key also, for backwards compatibility with the jugglingdb hardcoded id system
if (key !== "id" && key !== modelPKID) {
fieldNames.push("[" + key + "]");
var columnName = self.columnEscaped(model, key);
fieldNames.push(columnName);
fieldValues.push(self.toDatabase(props[key], data[key], true));
fieldValuesPlaceholders.push("(?)");
combined.push(key + "=(?)");
combined.push(columnName + "=(?)");
}
}
});
Expand All @@ -204,18 +224,18 @@ MsSQL.prototype.updateOrCreate = function (model, data, callback) {
//update
sql = "UPDATE " + tblName + MsSQL.newline;
sql += "SET " + combined.join() + MsSQL.newline;
sql += "WHERE [" + modelPKID + "] = (?);" + MsSQL.newline;
sql += "SELECT " + id + " AS pkid;";
sql += "WHERE " + self.columnEscaped(model, modelPKID) + " = (?);" + MsSQL.newline;
sql += "SELECT " + escape(id) + " AS pkid;";
fieldValues.push(id);
} else {
//insert with identity_insert
sql = "SET IDENTITY_INSERT " + tblName + " ON;" + MsSQL.newline;
var columns = fieldNames.length ? "," + fieldNames.join() + ")" : ")";
sql += "INSERT INTO " + tblName + " ([" + modelPKID + "]"
sql += "INSERT INTO " + tblName + " (" + self.columnEscaped(model, modelPKID)
+ columns + MsSQL.newline;
sql += "VALUES (" + id + "," + fieldValuesPlaceholders.join() + ");" + MsSQL.newline;
sql += "VALUES (" + escape(id) + "," + fieldValuesPlaceholders.join() + ");" + MsSQL.newline;
sql += "SET IDENTITY_INSERT " + tblName + " OFF;" + MsSQL.newline;
sql += "SELECT " + id + " AS pkid;";
sql += "SELECT " + escape(id) + " AS pkid;";
}
doQuery(sql, fieldValues);
});
Expand All @@ -230,23 +250,6 @@ MsSQL.prototype.updateOrCreate = function (model, data, callback) {
sql += "SELECT IDENT_CURRENT('" + tblName + "') AS pkid;";
doQuery(sql, fieldValues);
}

var doQuery = function (sql, fieldValues) {
self.query(sql, fieldValues, function (err, results) {
if (err) {
return callback(err);
}
//msnodesql will execute the callback for each statement that get's
// executed, we're only interested in the one that returns with the pkid
if (results.length > 0 && results[0].pkid) {
data[modelPKID] = results[0].pkid;
//#jdb id compatibility#
data.id = results[0].pkid; //set the id property also, to play nice
// with the jugglingdb abstract class implementation.
callback(err, data);
}
});
};
};

//redundant, same functionality as "updateOrCreate" right now. Maybe in the
Expand Down Expand Up @@ -349,7 +352,7 @@ MsSQL.prototype.update = MsSQL.prototype.updateAll = function (model, where, dat
if (props[key]) {
//check for the "id" key also, for backwards compatibility with the jugglingdb hardcoded id system
if (key !== "id" && key !== modelPKID) {
fieldNames.push("[" + key + "]");
fieldNames.push(self.columnEscaped(model, key));
fieldValues.push(self.toDatabase(props[key], data[key], true));
fieldValuesPlaceholders.push("(?)");
combined.push(key + "=(?)");
Expand Down Expand Up @@ -396,7 +399,7 @@ MsSQL.prototype.buildInsert = function (model, data) {
delete data.id;
Object.keys(data).forEach(function (key) {
if (props[key]) {
insertIntoFields.push("[" + key + "]");
insertIntoFields.push(self.columnEscaped(model, key));
paramPlaceholders.push("(?)");
params.push(self.toDatabase(props[key], data[key], true));
}
Expand Down Expand Up @@ -560,28 +563,33 @@ MsSQL.prototype.toDatabase = function (prop, val, wrap) {
};

MsSQL.prototype.fromDatabase = function (model, data) {
var self = this;
if (!data) {
return null;
}
// create an "id" property in the data for backwards compatibility with juggling-db
// data.id = data[this.idName(model)];
var props = this._models[model].properties;
var result = {};
//look for date values in the data, convert them from the database to a javascript date object
Object.keys(data).forEach(function (key) {
Object.keys(props).forEach(function (p) {
var key = self.column(model, p);
var val = data[key];
if (props[key]) {
if (props[key].type.name === 'Boolean' && val !== null) {
if (val !== undefined) {
if (props[p].type.name === 'Boolean' && val !== null) {
val = (true && val); //convert to a boolean type from number
}
if (props[key].type.name === 'Date' && val !== null) {
if (props[p].type.name === 'Date' && val !== null) {
if(!(val instanceof Date)) {
val = new Date(val.toString());
}
}
}
data[key] = val;
if (val !== undefined) {
result[p] = val;
}
});
return data;
return result;
};

MsSQL.prototype.escapeName = function (name) {
Expand Down Expand Up @@ -710,15 +718,17 @@ MsSQL.prototype.all = function (model, filter, callback) {
if (err) return callback(err);

//convert database types to js types
data = self.fromDatabase(model, data);
data = data.map(function (obj) {
return self.fromDatabase(model, obj);
});

//check for eager loading relationships
if (filter && filter.include) {
this._models[model].model.include(data, filter.include, callback);
self._models[model].model.include(data, filter.include, callback);
} else {
callback(null, data);
}
}.bind(this));
});

return sql;
};
Expand Down Expand Up @@ -997,7 +1007,8 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
if (found) {
actualize(propName, found);
} else {
columnsToAdd.push('[' + propName + '] ' + self.propertySettingsSQL(model, propName));
columnsToAdd.push(self.columnEscaped(model, propName) +
' ' + self.propertySettingsSQL(model, propName));
}
});

Expand All @@ -1006,7 +1017,7 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
var notFound = !~propNames.indexOf(f.Field);
if (f.Field === idName) return;
if (notFound || !m.properties[f.Field]) {
columnsToDrop.push('[' + f.Field + ']');
columnsToDrop.push(self.columnEscaped(model, f.Field));
}
});

Expand All @@ -1017,7 +1028,7 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
}
if (indexNames.indexOf(indexName) === -1 && !m.properties[indexName]
|| m.properties[indexName] && !m.properties[indexName].index) {
sql.push('DROP INDEX [' + indexName + ']');
sql.push('DROP INDEX ' + self.columnEscaped(model, indexName));
} else {
// first: check single (only type and kind)
if (m.properties[indexName] && !m.properties[indexName].index) {
Expand All @@ -1034,7 +1045,7 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
});
}
if (!orderMatched) {
sql.push('DROP INDEX [' + indexName + ']');
sql.push('DROP INDEX [' + self.columnEscaped(model, indexName) + ']');
delete ai[indexName];
}
}
Expand All @@ -1047,6 +1058,7 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
return;
}
var found = ai[propName] && ai[propName].info;
var columnName = self.columnEscaped(model, propName);
if (!found) {
var type = '';
var kind = '';
Expand All @@ -1057,8 +1069,8 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
// kind = i.kind;
}
if (kind && type) {
sql.push('ADD ' + kind + ' INDEX [' + propName
+ '] ([' + propName + ']) ' + type);
sql.push('ADD ' + kind + ' INDEX ' + columnName
+ ' (' + columnName + ') ' + type);
} else {
sql.push('ADD ' + kind + ' INDEX [' + propName + '] '
+ type + ' ([' + propName + ']) ');
Expand All @@ -1083,8 +1095,8 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
sql.push('ADD ' + kind + ' INDEX [' + indexName + '] ('
+ i.columns + ') ' + type);
} else {
sql.push('ADD ' + kind + ' INDEX ' + type + ' [' + indexName
+ '] (' + i.columns + ')');
sql.push('ADD ' + kind + ' INDEX [' + indexName + '] ('
+ i.columns + ') ');
}
}
});
Expand Down Expand Up @@ -1121,7 +1133,7 @@ MsSQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
function actualize(propName, oldSettings) {
var newSettings = m.properties[propName];
if (newSettings && changed(newSettings, oldSettings)) {
columnsToAlter.push('[' + propName + '] '
columnsToAlter.push(self.columnEscaped(model, propName) + ' '
+ self.propertySettingsSQL(model, propName));
}
}
Expand Down Expand Up @@ -1155,24 +1167,25 @@ MsSQL.prototype.propertiesSQL = function(model) {
if (prop === modelPKID) {
var idProp = objModel.properties[modelPKID];
if (idProp.type === Number) {
sql.push("[" + modelPKID + "] [int] IDENTITY(1,1) NOT NULL");
sql.push(self.columnEscaped(model, modelPKID) +
" [int] IDENTITY(1,1) NOT NULL");
continue;
} else if (idProp.type === String) {
if(idProp.generated) {
sql.push("[" + modelPKID
+ "] [uniqueidentifier] DEFAULT newid() NOT NULL");
sql.push(self.columnEscaped(model, modelPKID) +
" [uniqueidentifier] DEFAULT newid() NOT NULL");
} else {
sql.push("[" + modelPKID + "] " +
sql.push(self.columnEscaped(model, modelPKID) + " " +
self.propertySettingsSQL(model, prop) + " DEFAULT newid()");
}
continue;
}
}
sql.push("[" + prop + "] " + self.propertySettingsSQL(model, prop));
sql.push(self.columnEscaped(model, prop) + " " + self.propertySettingsSQL(model, prop));
}
var joinedSql = sql.join("," + MsSQL.newline + " ");
var cmd = "PRIMARY KEY CLUSTERED" + MsSQL.newline + "(" + MsSQL.newline;
cmd += " [" + modelPKID + "] ASC" + MsSQL.newline;
cmd += " " + self.columnEscaped(model, modelPKID) + " ASC" + MsSQL.newline;
cmd += ") WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, " +
"IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)"

Expand Down
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@
],
"main": "index.js",
"dependencies": {
"async": "~0.9.0",
"debug": "^2.0.0",
"async": "^0.9.0",
"debug": "^2.1.1",
"loopback-connector": "1.x",
"mssql": "^1.2.0"
"mssql": "^2.1.0"
},
"devDependencies": {
"bluebird": "^2.9.12",
"loopback-datasource-juggler": "2.x",
"mocha": "~1.20.1",
"should": "~1.2.2",
"rc": "~0.4.0"
"mocha": "^2.1.0",
"rc": "^0.6.0",
"should": "^5.0.0"
},
"scripts": {
"test": "./node_modules/.bin/mocha --timeout 5000 -R spec"
Expand All @@ -36,6 +37,6 @@
"url": "https://github.com/strongloop/loopback-connector-mssql/blob/master/LICENSE"
},
"optionalDependencies": {
"sl-blip": "http://blip.strongloop.com/loopback-connector-mssql@1.4.0"
"sl-blip": "http://blip.strongloop.com/loopback-connector-mssql@1.0.0"
}
}
Loading

0 comments on commit efd3644

Please sign in to comment.