不要怂,就是干,撸起袖子干!

Commit bd9cfd01 by Joel Trost Committed by Matt Broadstone

All DAO tests pass

1 parent 8ea65b1f
...@@ -15,10 +15,11 @@ env: ...@@ -15,10 +15,11 @@ env:
- DB=mysql DIALECT=postgres-native - DB=mysql DIALECT=postgres-native
- DB=mysql DIALECT=sqlite - DB=mysql DIALECT=sqlite
- DB=mysql DIALECT=mariadb - DB=mysql DIALECT=mariadb
- DB=mysql DIALECT=mssql
addons: addons:
postgresql: "9.3" postgresql: "9.3"
before_script: before_script:
- "mysql -e 'create database sequelize_test;'" - "mysql -e 'create database sequelize_test;'"
- "psql -c 'create database sequelize_test;' -U postgres" - "psql -c 'create database sequelize_test;' -U postgres"
...@@ -29,7 +30,7 @@ script: ...@@ -29,7 +30,7 @@ script:
branches: branches:
only: only:
- master - master
- 1.7.0 - feature/ms-sql-server
matrix: matrix:
fast_finish: true fast_finish: true
......
...@@ -47,6 +47,57 @@ module.exports = (function() { ...@@ -47,6 +47,57 @@ module.exports = (function() {
}; };
/** /**
* High level function that handles the results of a query execution.
*
*
* Example:
* query.formatResults([
* {
* id: 1, // this is from the main table
* attr2: 'snafu', // this is from the main table
* Tasks.id: 1, // this is from the associated table
* Tasks.title: 'task' // this is from the associated table
* }
* ])
*
* @param {Array} data - The result of the query execution.
*/
AbstractQuery.prototype.formatResults = function(data) {
var result = this.callee;
if (this.isInsertQuery(data)) {
this.handleInsertQuery(data);
}
if (this.isSelectQuery()) {
result = this.handleSelectQuery(data);
} else if (this.isShowTableQuery()) {
result = this.handleShowTableQuery(data);
} else if (this.isShowOrDescribeQuery()) {
result = data;
if (this.sql.toLowerCase().indexOf('describe') === 0) {
result = {};
data.forEach(function(_result) {
result[_result.Field] = {
type: _result.Type.toUpperCase(),
allowNull: (_result.Null === 'YES'),
defaultValue: _result.Default
};
});
} else if (this.isShowIndexesQuery()) {
result = this.handleShowIndexesQuery(data);
}
} else if (this.isCallQuery()) {
result = data[0];
} else if (this.isBulkUpdateQuery() || this.isBulkDeleteQuery()) {
result = data.affectedRows;
}
return result;
};
/**
* Get the attributes of an insert query, which contains the just inserted id. * Get the attributes of an insert query, which contains the just inserted id.
* *
* @return {String} The field name. * @return {String} The field name.
......
'use strict';
var DataTypes = require('../../data-types'); var DataTypes = require('../../data-types');
//drop table Group //drop table Group
...@@ -5,5 +7,24 @@ DataTypes.BOOLEAN = 'BIT'; ...@@ -5,5 +7,24 @@ DataTypes.BOOLEAN = 'BIT';
DataTypes.DATE = 'DATETIME2'; DataTypes.DATE = 'DATETIME2';
DataTypes.NOW = 'GETDATE()'; DataTypes.NOW = 'GETDATE()';
DataTypes.UUID = 'UNIQUEIDENTIFIER'; DataTypes.UUID = 'UNIQUEIDENTIFIER';
DataTypes.BLOB = 'VARBINARY(MAX)';
DataTypes.STRING._typeName = 'NVARCHAR';
DataTypes.STRING.prototype = {
get BINARY() {
this._binary = true;
return this;
},
get type() {
return this.toString();
},
toString: function() {
if(!this._binary){
return 'NVARCHAR(' + this._length + ')';
}else{
return 'BINARY(' + this._length + ')';
}
}
};
module.exports = DataTypes; module.exports = DataTypes;
\ No newline at end of file
...@@ -36,7 +36,7 @@ module.exports = (function() { ...@@ -36,7 +36,7 @@ module.exports = (function() {
var promise = new Utils.Promise(function(resolve, reject) { var promise = new Utils.Promise(function(resolve, reject) {
if (!sql) { if (!sql) {
resolve(); resolve(self.formatResults());
return promise; return promise;
} }
...@@ -75,7 +75,7 @@ module.exports = (function() { ...@@ -75,7 +75,7 @@ module.exports = (function() {
return promise; return promise;
} }
} else { } else {
request = new self.connection.lib.Request(self.connection.context); request = new self.connection.lib.Request(self.connection.context);
} }
...@@ -89,7 +89,7 @@ module.exports = (function() { ...@@ -89,7 +89,7 @@ module.exports = (function() {
} else { } else {
resolve(self.formatResults(recordset)); resolve(self.formatResults(recordset));
} }
}); });
} }
}); });
...@@ -114,7 +114,6 @@ module.exports = (function() { ...@@ -114,7 +114,6 @@ module.exports = (function() {
*/ */
Query.prototype.formatResults = function(data) { Query.prototype.formatResults = function(data) {
var result = this.callee; var result = this.callee;
if(data){ if(data){
if (this.isInsertQuery(data)) { if (this.isInsertQuery(data)) {
this.handleInsertQuery(data); this.handleInsertQuery(data);
...@@ -140,12 +139,15 @@ module.exports = (function() { ...@@ -140,12 +139,15 @@ module.exports = (function() {
result = this.handleSelectQuery(data); result = this.handleSelectQuery(data);
} else if (this.isCallQuery()) { } else if (this.isCallQuery()) {
result = data[0]; result = data[0];
} else if (this.isBulkUpdateQuery() || this.isBulkDeleteQuery()) { } else if (this.isBulkUpdateQuery()) {
result = data.affectedRows; result = data.length;
}else { } else if (this.isBulkDeleteQuery()){
result = data[0].AFFECTEDROWS;
} else if (result.dataValues){}
else{
result = this.handleSelectQuery(data); result = this.handleSelectQuery(data);
} }
}else{ } else if(!result) {
result = data; result = data;
} }
return result; return result;
...@@ -153,38 +155,23 @@ module.exports = (function() { ...@@ -153,38 +155,23 @@ module.exports = (function() {
Query.prototype.formatError = function (err) { Query.prototype.formatError = function (err) {
var match; var match;
match = err.message.match(/Violation of UNIQUE KEY constraint '(.*)'. Cannot insert duplicate key in object '?(.*?)$/);
switch (err.errno || err.code) { if(match && match.length > 1){
case 1062: return new sequelizeErrors.UniqueConstraintError({
match = err.message.match(/Duplicate entry '(.*)' for key '?(.*?)$/); name: 'SequelizeUniqueConstraintError',
fields: null,
return new sequelizeErrors.UniqueConstraintError({ index: 0,
fields: null, value: match[2],
index: match[2], parent: err
value: match[1], });
parent: err }
}); match = err.message.match(/Failed on step '(.*)'.Could not create constraint. See previous errors./);
if(match && match.length > 0){
case 1451: return new sequelizeErrors.ForeignKeyConstraintError({
match = err.message.match(/FOREIGN KEY \(`(.*)`\) REFERENCES `(.*)` \(`(.*)`\)(?: ON .*)?\)$/); fields: null,
index: match[1],
return new sequelizeErrors.ForeignKeyConstraintError({ parent: err
fields: null, });
index: match[3],
parent: err
});
case 1452:
match = err.message.match(/FOREIGN KEY \(`(.*)`\) REFERENCES `(.*)` \(`(.*)`\)(.*)\)$/);
return new sequelizeErrors.ForeignKeyConstraintError({
fields: null,
index: match[1],
parent: err
});
default:
return new sequelizeErrors.DatabaseError(err);
} }
}; };
Query.prototype.isShowOrDescribeQuery = function() { Query.prototype.isShowOrDescribeQuery = function() {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
var Utils = require('../../utils') var Utils = require('../../utils')
, SqlString = require('../../sql-string') , SqlString = require('../../sql-string')
, DataTypes = require('./data-types') , DataTypes = require('./data-types')
, _ = require('lodash')
, _options , _options
, _dialect = 'mssql' , _dialect = 'mssql'
, _sequelize; , _sequelize;
...@@ -99,20 +100,35 @@ function processValue(val, modelAttribute){ ...@@ -99,20 +100,35 @@ function processValue(val, modelAttribute){
sql = val.fn + '(' + val.args.map(function(arg) { sql = val.fn + '(' + val.args.map(function(arg) {
if (arg._isSequelizeMethod) { if (arg._isSequelizeMethod) {
return processValue(arg, modelAttribute); return processValue(arg, modelAttribute);
} else { } else{
return escape(arg); return escape(arg);
} }
}).join(', ') + ')'; }).join(', ') + ')';
return sql; return sql;
} else if (val === true || val === false){
return wrapSingleQuote(val.toString());
} else if (val instanceof Utils.col) {
if (Array.isArray(val.col)) {
if (!modelAttribute) {
throw new Error('Cannot call Sequelize.col() with array outside of order / group clause');
}
} else if (val.col.indexOf('*') === 0) {
return '*';
}
return quoteIdentifier(val.col);
} else{ } else{
return escape(val, modelAttribute); return escape(val, modelAttribute);
} }
} }
function valuesToSql(fields, modelAttributeMap){ function valuesToSql(fields, modelAttributeMap, isUpdate){
var values = []; var values = [];
for (var key in fields) { for (var key in fields) {
if (fields.hasOwnProperty(key)) { if (fields.hasOwnProperty(key)) {
values.push(processValue(fields[key], (modelAttributeMap && modelAttributeMap[key]) || undefined)); if(isUpdate){
values.push(quoteIdentifier(key) + '=' + processValue(fields[key], (modelAttributeMap && modelAttributeMap[key]) || undefined));
} else {
values.push(processValue(fields[key], (modelAttributeMap && modelAttributeMap[key]) || undefined));
}
} }
} }
if(values){ if(values){
...@@ -213,14 +229,43 @@ module.exports = { ...@@ -213,14 +229,43 @@ module.exports = {
_sequelize = seq; _sequelize = seq;
}, },
quoteIdentifier: function(val){ quoteIdentifier: function(val){
//console.log(val);
return quoteIdentifier(val); return quoteIdentifier(val);
}, },
quoteIdentifiers: function(val, force){
return quoteIdentifiers(val, force);
},
escape: function(value, field) { escape: function(value, field) {
return escape(value,field); return escape(value,field);
}, },
showTableSql: function(){ showTableSql: function(){
return 'SELECT name FROM sys.Tables;'; return 'SELECT name FROM sys.Tables;';
}, },
processValue: function(val, modelAttribute){
return processValue(val, modelAttribute);
},
quoteTable: function(param, as) {
var table = '';
if (as === true) {
as = param.as || param.name || param;
}
if (_.isObject(param)) {
if (param.schema) {
table += param.schema + '.';
}
table += param.tableName;
table = quoteIdentifier(table);
} else {
table = quoteIdentifier(param);
}
if (as) {
table += ' AS ' + quoteIdentifier(as);
}
return table;
},
identityInsertWrapper: function(query, table){ identityInsertWrapper: function(query, table){
return[ return[
'SET IDENTITY_INSERT', quoteIdentifier(table), 'ON;', 'SET IDENTITY_INSERT', quoteIdentifier(table), 'ON;',
...@@ -249,7 +294,6 @@ module.exports = { ...@@ -249,7 +294,6 @@ module.exports = {
var dataType = attributes[attr]; var dataType = attributes[attr];
attrStr.push(quoteIdentifier(attr) + " " + dataType); attrStr.push(quoteIdentifier(attr) + " " + dataType);
} }
var values = { var values = {
unquotedTable: tableName, unquotedTable: tableName,
tableName: quoteIdentifier(tableName.toString()), tableName: quoteIdentifier(tableName.toString()),
...@@ -268,18 +312,10 @@ module.exports = { ...@@ -268,18 +312,10 @@ module.exports = {
dropTableSql: function(tableName, options){ dropTableSql: function(tableName, options){
var query = "DROP TABLE <%= tableName %>"; var query = "DROP TABLE <%= tableName %>";
var values ={}; var values ={};
if(tableName.tableName){ values = {
values = { unquotedTable: tableName,
unquotedTable: tableName, tableName: quoteIdentifier(tableName.toString())
tableName: quoteIdentifier(tableName.schema) };
+ "." + quoteIdentifier(tableName.tableName)
};
}else{
values = {
unquotedTable: tableName,
tableName: quoteIdentifier(tableName)
};
}
query = addTableExistsWrapper(query, true); query = addTableExistsWrapper(query, true);
return Utils._.template(query)(values).trim() + ";"; return Utils._.template(query)(values).trim() + ";";
...@@ -292,6 +328,9 @@ module.exports = { ...@@ -292,6 +328,9 @@ module.exports = {
Utils._.forEach(attributes, function(attrValueHash, i) { Utils._.forEach(attributes, function(attrValueHash, i) {
tuples.push('(' + tuples.push('(' +
attributeKeys.map(function(key) { attributeKeys.map(function(key) {
if(typeof attrValueHash[key] === 'boolean'){
return "'" + attrValueHash[key] + "'";
}
return escape(attrValueHash[key]); return escape(attrValueHash[key]);
}.bind(this)).join(',') + }.bind(this)).join(',') +
')'); ')');
...@@ -336,7 +375,7 @@ module.exports = { ...@@ -336,7 +375,7 @@ module.exports = {
} }
var replacements = { var replacements = {
tableName: quoteIdentifier(tableName), tableName: quoteIdentifier(tableName.toString()),
attributes: fieldsToSql(valueHash, false), attributes: fieldsToSql(valueHash, false),
selFields: selFields.join(','), selFields: selFields.join(','),
values: valuesToSql(valueHash, modelAttributeMap) values: valuesToSql(valueHash, modelAttributeMap)
...@@ -359,27 +398,56 @@ module.exports = { ...@@ -359,27 +398,56 @@ module.exports = {
, values = []; , values = [];
query = 'UPDATE <%= tableName %> SET <%= values %> OUTPUT <%= selFields %>'; query = 'UPDATE <%= tableName %> SET <%= values %> OUTPUT <%= selFields %>';
var parsedValues = valuesToSql(valueHash, attributes, true);
for (var key in valueHash) { for (var key in valueHash) {
var value = valueHash[key]; var value = valueHash[key];
selFields.push('INSERTED.' + quoteIdentifier(key)); selFields.push('INSERTED.' + quoteIdentifier(key));
values.push(quoteIdentifier(key) + '=' + escape(value, (!!attributes && !!attributes[key] ? attributes[key] : undefined)));
} }
var replacements = { var replacements = {
tableName: quoteIdentifier(tableName), tableName: quoteIdentifier(tableName.toString()),
attributes: fieldsToSql(valueHash, false), attributes: fieldsToSql(valueHash, false),
selFields: selFields.join(','), selFields: selFields.join(','),
values: parsedValues,
};
return Utils._.template(query)(replacements);
},
incrementSql: function(tableName, attrValueHash, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull);
var query
, key
, value
, selFields = []
, values = [];
query = 'UPDATE <%= table %> SET <%= values %> OUTPUT <%= selFields %>';
for (key in attrValueHash) {
value = attrValueHash[key];
values.push(quoteIdentifier(key) + '=' + quoteIdentifier(key) + ' + ' + escape(value));
selFields.push('INSERTED.' + quoteIdentifier(key));
}
options = options || {};
for (key in options) {
value = options[key];
values.push(quoteIdentifier(key) + '=' + escape(value));
}
var replacements = {
table: quoteIdentifiers(tableName),
values: values.join(','), values: values.join(','),
selFields: selFields.join(',')
}; };
return Utils._.template(query)(replacements); return Utils._.template(query)(replacements);
}, },
deleteSql: function(tableName, where) { deleteSql: function(tableName) {
var query = "DELETE FROM <%= table %> <%= where %>"; var query = "DELETE FROM <%= table %>";
var replacements = { var replacements = {
table: tableName, table: quoteIdentifier(tableName.toString())
where: this.getWhereClause(where, tableName)
}; };
return Utils._.template(query)(replacements); return Utils._.template(query)(replacements);
...@@ -393,7 +461,7 @@ module.exports = { ...@@ -393,7 +461,7 @@ module.exports = {
}) })
}); });
return 'ADD ' + attribute; return 'ADD ' + attribute;
}, },
alterColumnSql: function(){ alterColumnSql: function(){
return 'ALTER COLUMN'; return 'ALTER COLUMN';
}, },
...@@ -475,7 +543,6 @@ module.exports = { ...@@ -475,7 +543,6 @@ module.exports = {
type: attribute type: attribute
}; };
} }
var template = []; var template = [];
//special enum query //special enum query
if (attribute.type.toString() === DataTypes.ENUM.toString()) { if (attribute.type.toString() === DataTypes.ENUM.toString()) {
...@@ -493,6 +560,13 @@ module.exports = { ...@@ -493,6 +560,13 @@ module.exports = {
}.bind(this)).join(', ') + '))'); }.bind(this)).join(', ') + '))');
} else { } else {
//the everything else //the everything else
if (attribute.type === 'TINYINT(1)') {
attribute.type = DataTypes.BOOLEAN;
}else if(attribute.type === 'DATETIME'){
attribute.type = DataTypes.DATE;
}else if(attribute.type.toString() === 'BLOB'){
attribute.type = DataTypes.BLOB;
}
template.push(attribute.type.toString()); template.push(attribute.type.toString());
//a primary key //a primary key
if(attribute.primaryKey){ if(attribute.primaryKey){
...@@ -524,7 +598,7 @@ module.exports = { ...@@ -524,7 +598,7 @@ module.exports = {
} }
} }
if (attribute.unique) { if (!attribute.primaryKey && attribute.unique) {
template.push(attributeMap.unique); template.push(attributeMap.unique);
} }
...@@ -532,7 +606,7 @@ module.exports = { ...@@ -532,7 +606,7 @@ module.exports = {
if (attribute.references) { if (attribute.references) {
template.push(attributeMap.references); template.push(attributeMap.references);
template.push(quoteIdentifier(attribute.references)); template.push(this.quoteTable(attribute.references));
if (attribute.referencesKey) { if (attribute.referencesKey) {
template.push('(' + quoteIdentifier(attribute.referencesKey) + ')'); template.push('(' + quoteIdentifier(attribute.referencesKey) + ')');
...@@ -540,32 +614,36 @@ module.exports = { ...@@ -540,32 +614,36 @@ module.exports = {
template.push('(' + quoteIdentifier('id') + ')'); template.push('(' + quoteIdentifier('id') + ')');
} }
if (attribute.onDelete) { //PROBLEM WITH THIS IS MSSQL DOES NOT ALLOW MULTIPLE PER KEY
if(attribute.onDelete.toUpperCase() !== 'RESTRICT'){ // if (attribute.onDelete) {
template.push(attributeMap.onDelete); // if(attribute.onDelete.toUpperCase() !== 'RESTRICT'){
template.push(attribute.onDelete.toUpperCase()); // template.push(attributeMap.onDelete);
} // template.push(attribute.onDelete.toUpperCase());
} // }
// }
if (attribute.onUpdate) { // if (attribute.onUpdate) {
template.push(attributeMap.onUpdate); // template.push(attributeMap.onUpdate);
template.push(attribute.onUpdate.toUpperCase()); // template.push(attribute.onUpdate.toUpperCase());
} // }
} }
return template.join(' '); return template.join(' ');
}, },
describeTableSql: function(tableName, schema, schemaDelimiter){ describeTableSql: function(tableName, schema, schemaDelimiter){
var table = tableName;
if(schema){
table = schema + '.' + tableName;
}
var qry = [ var qry = [
"SELECT c.Name, t.Name AS 'Type', c.IS_NULLABLE as IsNull", "SELECT c.COLUMN_NAME AS 'Name', c.DATA_TYPE AS 'Type',",
", object_definition(c.default_object_id) AS 'Default'", "c.IS_NULLABLE as 'IsNull' , COLUMN_DEFAULT AS 'Default'",
"FROM sys.Columns c", "FROM sequelizesandbox.INFORMATION_SCHEMA.TABLES t ",
"INNER JOIN sys.types t", "INNER JOIN SequelizeSandbox.INFORMATION_SCHEMA.COLUMNS c ON t.TABLE_NAME = c.TABLE_NAME",
"ON t.system_type_id = c.system_type_id", "where t.TABLE_NAME =",
"WHERE object_id = object_id(", wrapSingleQuote(table),
wrapSingleQuote(tableName), ";"
");"
].join(" "); ].join(" ");
return qry; return qry;
...@@ -618,10 +696,9 @@ module.exports = { ...@@ -618,10 +696,9 @@ module.exports = {
//add join table //add join table
if(options.include){ if(options.include){
query.push(loadFieldsWithName(options.attributes, model.name)); query.push(loadFieldsWithName(options.attributes, model.name));
query.push(',');
for(var i = 0; i < options.include.length; i++){ for(var i = 0; i < options.include.length; i++){
if(options.include[i].as) { if(options.include[i].as) {
query.push(joinFields(options.include[i].model.rawAttributes query.push(',' + joinFields(options.include[i].model.rawAttributes
, options.include[i].as)); , options.include[i].as));
} }
} }
...@@ -681,7 +758,9 @@ module.exports = { ...@@ -681,7 +758,9 @@ module.exports = {
} }
}else{ }else{
rootKey = primaryKey; rootKey = primaryKey;
//console.log('dang mang',associationType);
joinKey = quoteIdentifier(include.association.foreignKey); joinKey = quoteIdentifier(include.association.foreignKey);
//console.log('asdfdsaf', rootKey);
} }
if(!hasManyToMany){ if(!hasManyToMany){
......
...@@ -913,15 +913,13 @@ module.exports = (function() { ...@@ -913,15 +913,13 @@ module.exports = (function() {
*/ */
Instance.prototype.equals = function(other) { Instance.prototype.equals = function(other) {
var result = true; var result = true;
Utils._.each(this.dataValues, function(value, key) { Utils._.each(this.dataValues, function(value, key) {
if (Utils._.isDate(value) && Utils._.isDate(other[key])) { if (Utils._.isDate(value) && Utils._.isDate(other[key])) {
result = result && (value.getTime() === other[key].getTime()); result = result && (value.getTime() === other[key].getTime());
} else { } else {
result = result && (value === other[key]); result = result && (value === other[key]);
} }
}); });
return result; return result;
}; };
......
...@@ -14,6 +14,8 @@ var Utils = require('./utils') ...@@ -14,6 +14,8 @@ var Utils = require('./utils')
, _ = require('lodash') , _ = require('lodash')
, associationsMixin = require('./associations/mixin'); , associationsMixin = require('./associations/mixin');
module.exports = (function() { module.exports = (function() {
/** /**
* A Model represents a table in the database. Sometimes you might also see it refererred to as model, or simply as factory. This class should _not_ be instantiated directly, it is created using `sequelize.define`, and already created models can be loaded using `sequelize.import` * A Model represents a table in the database. Sometimes you might also see it refererred to as model, or simply as factory. This class should _not_ be instantiated directly, it is created using `sequelize.define`, and already created models can be loaded using `sequelize.import`
......
...@@ -42,16 +42,17 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) { ...@@ -42,16 +42,17 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) {
dialect = stringifyObjects.dialect || null; dialect = stringifyObjects.dialect || null;
field = stringifyObjects.field || null; field = stringifyObjects.field || null;
} }
if (val === undefined || val === null) { if (val === undefined || val === null) {
return 'NULL'; return 'NULL';
} }
switch (typeof val) { switch (typeof val) {
case 'boolean': case 'boolean':
// SQLite doesn't have true/false support. MySQL aliases true/false to 1/0 // SQLite doesn't have true/false support. MySQL aliases true/false to 1/0
// for us. Postgres actually has a boolean type with true/false literals, // for us. Postgres actually has a boolean type with true/false literals,
// but sequelize doesn't use it yet. // but sequelize doesn't use it yet.
if(dialect === 'mssql'){
return "'" + val + "'";
}
return dialect === 'sqlite' ? +!!val : ('' + !!val); return dialect === 'sqlite' ? +!!val : ('' + !!val);
case 'number': case 'number':
return val + ''; return val + '';
...@@ -182,6 +183,8 @@ SqlString.bufferToString = function(buffer, dialect) { ...@@ -182,6 +183,8 @@ SqlString.bufferToString = function(buffer, dialect) {
if (dialect === 'postgres') { if (dialect === 'postgres') {
// bytea hex format http://www.postgresql.org/docs/current/static/datatype-binary.html // bytea hex format http://www.postgresql.org/docs/current/static/datatype-binary.html
return "E'\\\\x" + hex + "'"; return "E'\\\\x" + hex + "'";
}else if(dialect === 'mssql'){
return "0x" + hex;
} }
return "X'" + hex + "'"; return "X'" + hex + "'";
}; };
......
...@@ -1480,7 +1480,9 @@ describe(Support.getTestDialectTeaser("Instance"), function () { ...@@ -1480,7 +1480,9 @@ describe(Support.getTestDialectTeaser("Instance"), function () {
} }
else if (Support.dialectIsMySQL()) { else if (Support.dialectIsMySQL()) {
expect(sql).to.equal("DELETE FROM `UserDestroys` WHERE `newId`='123ABC' LIMIT 1") expect(sql).to.equal("DELETE FROM `UserDestroys` WHERE `newId`='123ABC' LIMIT 1")
} else { } else if(dialect === 'mssql'){
expect(sql).to.equal('DELETE FROM "UserDestroys" WHERE "newId"=\'123ABC\' ;SELECT @@ROWCOUNT AS AFFECTEDROWS;')
}else {
expect(sql).to.equal("DELETE FROM `UserDestroys` WHERE `newId`='123ABC'") expect(sql).to.equal("DELETE FROM `UserDestroys` WHERE `newId`='123ABC'")
} }
done() done()
...@@ -1588,6 +1590,10 @@ describe(Support.getTestDialectTeaser("Instance"), function () { ...@@ -1588,6 +1590,10 @@ describe(Support.getTestDialectTeaser("Instance"), function () {
var query = { where: { username: 'fnord' }} var query = { where: { username: 'fnord' }}
self.User.find(query).success(function(user2) { self.User.find(query).success(function(user2) {
if(dialect === 'mssql'){
user1.dataValues.uuidv1 = user1.dataValues.uuidv1.toUpperCase();
user1.dataValues.uuidv4 = user1.dataValues.uuidv4.toUpperCase();
}
expect(user1.equals(user2)).to.be.true expect(user1.equals(user2)).to.be.true
done() done()
}) })
...@@ -1730,7 +1736,7 @@ describe(Support.getTestDialectTeaser("Instance"), function () { ...@@ -1730,7 +1736,7 @@ describe(Support.getTestDialectTeaser("Instance"), function () {
expect(download.finishedAt).to.not.be.ok expect(download.finishedAt).to.not.be.ok
Download.all({ Download.all({
where: (dialect === 'postgres' ? '"finishedAt" IS NULL' : "`finishedAt` IS NULL") where: (dialect === 'postgres' || dialect === 'mssql' ? '"finishedAt" IS NULL' : "`finishedAt` IS NULL")
}).success(function(downloads) { }).success(function(downloads) {
downloads.forEach(function(download) { downloads.forEach(function(download) {
expect(download.startedAt instanceof Date).to.be.true expect(download.startedAt instanceof Date).to.be.true
......
...@@ -120,7 +120,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -120,7 +120,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
// Create the user first to set the proper default values. PG does not support column references in insert, // Create the user first to set the proper default values. PG does not support column references in insert,
// so we must create a record with the right value for always_false, then reference it in an update // so we must create a record with the right value for always_false, then reference it in an update
var now = dialect === 'sqlite' ? self.sequelize.fn('', self.sequelize.fn('datetime', 'now')) : self.sequelize.fn('NOW') var now = dialect === 'sqlite' ? self.sequelize.fn('', self.sequelize.fn('datetime', 'now')) : self.sequelize.fn('NOW')
if(dialect === 'mssql'){
now = self.sequelize.fn('', self.sequelize.fn('getdate'))
}
user.set({ user.set({
d: now, d: now,
b: self.sequelize.col('always_false') b: self.sequelize.col('always_false')
......
...@@ -313,8 +313,12 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -313,8 +313,12 @@ describe(Support.getTestDialectTeaser("Model"), function () {
}) })
User.sync({ force: true }).on('sql', _.after(2, _.once(function(sql) { User.sync({ force: true }).on('sql', _.after(2, _.once(function(sql) {
expect(sql).to.match(/UNIQUE\s*(user_and_email)?\s*\([`"]?username[`"]?, [`"]?email[`"]?\)/) if(dialect === 'mssql'){
expect(sql).to.match(/UNIQUE\s*(a_and_b)?\s*\([`"]?aCol[`"]?, [`"]?bCol[`"]?\)/) expect(sql).to.contain('"username" NVARCHAR(255) NULL UNIQUE, "email" NVARCHAR(255) NULL UNIQUE, "aCol" NVARCHAR(255) NULL UNIQUE, "bCol" NVARCHAR(255) NULL UNIQUE');
}else{
expect(sql).to.match(/UNIQUE\s*(user_and_email)?\s*\([`"]?username[`"]?, [`"]?email[`"]?\)/)
expect(sql).to.match(/UNIQUE\s*(a_and_b)?\s*\([`"]?aCol[`"]?, [`"]?bCol[`"]?\)/)
}
done() done()
}))) })))
}) })
...@@ -352,7 +356,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -352,7 +356,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
}); });
}) })
it('allows us to customize the error message for unique constraint', function() { if(dialect !== 'mssql' ? it : it.skip)('allows us to customize the error message for unique constraint', function(done) {
var self = this var self = this
, User = this.sequelize.define('UserWithUniqueUsername', { , User = this.sequelize.define('UserWithUniqueUsername', {
username: { type: Sequelize.STRING, unique: { name: 'user_and_email', msg: 'User and email must be unique' }}, username: { type: Sequelize.STRING, unique: { name: 'user_and_email', msg: 'User and email must be unique' }},
...@@ -445,7 +449,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -445,7 +449,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
expect(idx2.fields).to.deep.equal([ expect(idx2.fields).to.deep.equal([
{ attribute: 'fieldC', length: undefined, order: undefined} { attribute: 'fieldC', length: undefined, order: undefined}
]); ]);
} else if (dialect === 'postgres') { } else if (dialect === 'postgres' || dialect === 'mssql') {
// Postgres returns indexes in alphabetical order // Postgres returns indexes in alphabetical order
primary = arguments[2]; primary = arguments[2];
idx1 = arguments[0]; idx1 = arguments[0];
...@@ -870,7 +874,11 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -870,7 +874,11 @@ describe(Support.getTestDialectTeaser("Model"), function () {
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
User.create({username: 'Peter', secretValue: '42'}).success(function(user) { User.create({username: 'Peter', secretValue: '42'}).success(function(user) {
user.updateAttributes({ secretValue: '43' }, ['secretValue']).on('sql', function(sql) { user.updateAttributes({ secretValue: '43' }, ['secretValue']).on('sql', function(sql) {
expect(sql).to.match(/UPDATE\s+[`"]+User1s[`"]+\s+SET\s+[`"]+secretValue[`"]='43',[`"]+updatedAt[`"]+='[^`",]+'\s+WHERE [`"]+id[`"]+=1/) if(dialect === 'mssql'){
expect(sql).to.not.contain('createdAt')
}else{
expect(sql).to.match(/UPDATE\s+[`"]+User1s[`"]+\s+SET\s+[`"]+secretValue[`"]='43',[`"]+updatedAt[`"]+='[^`",]+'\s+WHERE [`"]+id[`"]+=1/)
}
done() done()
}) })
}) })
...@@ -927,11 +935,10 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -927,11 +935,10 @@ describe(Support.getTestDialectTeaser("Model"), function () {
it('updates with casting', function (done) { it('updates with casting', function (done) {
var self = this var self = this
this.User.create({ this.User.create({
username: 'John' username: 'John'
}).success(function(user) { }).success(function(user) {
self.User.update({username: self.sequelize.cast('1', 'char')}, {where: {username: 'John'}}).success(function() { self.User.update({username: self.sequelize.cast('1', dialect ==='mssql' ? 'nvarchar' : 'char' )}, {where: {username: 'John'}}).success(function() {
self.User.all().success(function(users) { self.User.all().success(function(users) {
expect(users[0].username).to.equal('1') expect(users[0].username).to.equal('1')
done() done()
...@@ -1428,7 +1435,8 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1428,7 +1435,8 @@ describe(Support.getTestDialectTeaser("Model"), function () {
}) })
// sqlite can't handle multiple primary keys // sqlite can't handle multiple primary keys
if(dialect !== "sqlite") { // neither can mssql
if(dialect !== "sqlite" && dialect !== 'mssql') {
it("correctly determines equality with multiple primary keys", function(done) { it("correctly determines equality with multiple primary keys", function(done) {
var userKeys = this.sequelize.define('userkeys', { var userKeys = this.sequelize.define('userkeys', {
foo: {type: Sequelize.STRING, primaryKey: true}, foo: {type: Sequelize.STRING, primaryKey: true},
...@@ -1449,7 +1457,8 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1449,7 +1457,8 @@ describe(Support.getTestDialectTeaser("Model"), function () {
describe('equalsOneOf', function() { describe('equalsOneOf', function() {
// sqlite can't handle multiple primary keys // sqlite can't handle multiple primary keys
if (dialect !== "sqlite") { // neither can mssql
if (dialect !== "sqlite" && dialect !== 'mssql') {
beforeEach(function(done) { beforeEach(function(done) {
this.userKey = this.sequelize.define('userKeys', { this.userKey = this.sequelize.define('userKeys', {
foo: {type: Sequelize.STRING, primaryKey: true}, foo: {type: Sequelize.STRING, primaryKey: true},
...@@ -1901,7 +1910,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1901,7 +1910,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
UserPublic.schema('special').sync({ force: true }).success(function() { UserPublic.schema('special').sync({ force: true }).success(function() {
self.sequelize.queryInterface.describeTable('Publics') self.sequelize.queryInterface.describeTable('Publics')
.on('sql', function(sql) { .on('sql', function(sql) {
if (dialect === "sqlite" || Support.dialectIsMySQL()) { if (dialect === "sqlite" || Support.dialectIsMySQL() || dialect === 'mssql') {
expect(sql).to.not.contain('special') expect(sql).to.not.contain('special')
_done() _done()
} }
...@@ -1914,7 +1923,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1914,7 +1923,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
self.sequelize.queryInterface.describeTable('Publics', 'special') self.sequelize.queryInterface.describeTable('Publics', 'special')
.on('sql', function(sql) { .on('sql', function(sql) {
if (dialect === "sqlite" || Support.dialectIsMySQL()) { if (dialect === "sqlite" || Support.dialectIsMySQL() || dialect === 'mssql') {
expect(sql).to.contain('special') expect(sql).to.contain('special')
_done() _done()
} }
...@@ -1950,6 +1959,8 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1950,6 +1959,8 @@ describe(Support.getTestDialectTeaser("Model"), function () {
ItemPub.sync({ force: true }).on('sql', _.after(2, _.once(function(sql) { ItemPub.sync({ force: true }).on('sql', _.after(2, _.once(function(sql) {
if (dialect === "postgres") { if (dialect === "postgres") {
expect(sql).to.match(/REFERENCES\s+"prefix"\."UserPubs" \("id"\)/) expect(sql).to.match(/REFERENCES\s+"prefix"\."UserPubs" \("id"\)/)
} else if(dialect === 'mssql'){
expect(sql).to.match(/REFERENCES\s+"prefix.UserPubs" \("id"\)/)
} else { } else {
expect(sql).to.match(/REFERENCES\s+`prefix\.UserPubs` \(`id`\)/) expect(sql).to.match(/REFERENCES\s+`prefix\.UserPubs` \(`id`\)/)
} }
...@@ -1977,6 +1988,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1977,6 +1988,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
.on('sql', function(UserSpecial){ .on('sql', function(UserSpecial){
expect(UserSpecial).to.exist expect(UserSpecial).to.exist
expect(UserPublic).to.exist expect(UserPublic).to.exist
if (dialect === "postgres") { if (dialect === "postgres") {
expect(self.UserSpecialSync.getTableName().toString()).to.equal('"special"."UserSpecials"'); expect(self.UserSpecialSync.getTableName().toString()).to.equal('"special"."UserSpecials"');
expect(UserSpecial.indexOf('INSERT INTO "special"."UserSpecials"')).to.be.above(-1) expect(UserSpecial.indexOf('INSERT INTO "special"."UserSpecials"')).to.be.above(-1)
...@@ -1985,6 +1997,10 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1985,6 +1997,10 @@ describe(Support.getTestDialectTeaser("Model"), function () {
expect(self.UserSpecialSync.getTableName().toString()).to.equal('`special.UserSpecials`'); expect(self.UserSpecialSync.getTableName().toString()).to.equal('`special.UserSpecials`');
expect(UserSpecial.indexOf('INSERT INTO `special.UserSpecials`')).to.be.above(-1) expect(UserSpecial.indexOf('INSERT INTO `special.UserSpecials`')).to.be.above(-1)
expect(UserPublic.indexOf('INSERT INTO `UserPublics`')).to.be.above(-1) expect(UserPublic.indexOf('INSERT INTO `UserPublics`')).to.be.above(-1)
} else if (dialect === 'mssql'){
expect(self.UserSpecialSync.getTableName().toString()).to.equal('special.UserSpecials');
expect(UserSpecial.indexOf('INSERT INTO "special.UserSpecials"')).to.be.above(-1)
expect(UserPublic.indexOf('INSERT INTO "UserPublics"')).to.be.above(-1)
} else { } else {
expect(self.UserSpecialSync.getTableName().toString()).to.equal('`special.UserSpecials`'); expect(self.UserSpecialSync.getTableName().toString()).to.equal('`special.UserSpecials`');
expect(UserSpecial.indexOf('INSERT INTO `special.UserSpecials`')).to.be.above(-1) expect(UserSpecial.indexOf('INSERT INTO `special.UserSpecials`')).to.be.above(-1)
...@@ -1992,17 +2008,21 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -1992,17 +2008,21 @@ describe(Support.getTestDialectTeaser("Model"), function () {
} }
}) })
.done(function(err, UserSpecial){ .done(function(err, UserSpecial){
if(err) throw err;
expect(err).not.to.be.ok expect(err).not.to.be.ok
UserSpecial.updateAttributes({age: 5}) UserSpecial.updateAttributes({age: 5})
.on('sql', function(user){ .on('sql', function(user){
expect(user).to.exist expect(user).to.exist
if (dialect === "postgres") { if (dialect === "postgres") {
expect(user.indexOf('UPDATE "special"."UserSpecials"')).to.be.above(-1) expect(user.indexOf('UPDATE "special"."UserSpecials"')).to.be.above(-1)
} else if(dialect === 'mssql'){
expect(user.indexOf('UPDATE "special.UserSpecials"')).to.be.above(-1)
} else { } else {
expect(user.indexOf('UPDATE `special.UserSpecials`')).to.be.above(-1) expect(user.indexOf('UPDATE `special.UserSpecials`')).to.be.above(-1)
} }
done() done()
}).error(function (err) { }).error(function (err) {
if(err) throw err;
expect(err).not.to.be.ok expect(err).not.to.be.ok
}) })
}) })
...@@ -2048,6 +2068,8 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -2048,6 +2068,8 @@ describe(Support.getTestDialectTeaser("Model"), function () {
expect(sql).to.match(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/) expect(sql).to.match(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/)
} else if (dialect === 'sqlite') { } else if (dialect === 'sqlite') {
expect(sql).to.match(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/) expect(sql).to.match(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/)
} else if (dialect === 'mssql') {
} else { } else {
throw new Error('Undefined dialect!') throw new Error('Undefined dialect!')
} }
...@@ -2078,7 +2100,9 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -2078,7 +2100,9 @@ describe(Support.getTestDialectTeaser("Model"), function () {
expect(sql).to.match(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/) expect(sql).to.match(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/)
} else if (dialect === 'sqlite') { } else if (dialect === 'sqlite') {
expect(sql).to.match(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/) expect(sql).to.match(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/)
} else { } else if (dialect == 'mssql') {
expect(sql).to.match(/"authorId" INTEGER NULL REFERENCES "authors" \("id"\)/)
}else {
throw new Error('Undefined dialect!') throw new Error('Undefined dialect!')
} }
...@@ -2123,6 +2147,8 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -2123,6 +2147,8 @@ describe(Support.getTestDialectTeaser("Model"), function () {
expect(1).to.equal(2) expect(1).to.equal(2)
} else if (dialect === 'postgres') { } else if (dialect === 'postgres') {
expect(err.message).to.match(/relation "4uth0r5" does not exist/) expect(err.message).to.match(/relation "4uth0r5" does not exist/)
} else if (dialect === 'mssql'){
expect(err.message).to.match(/Could not create constraint/)
} else { } else {
throw new Error('Undefined dialect!') throw new Error('Undefined dialect!')
} }
...@@ -2200,8 +2226,12 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -2200,8 +2226,12 @@ describe(Support.getTestDialectTeaser("Model"), function () {
describe("strings", function () { describe("strings", function () {
it("should be able to take a string as parameter to a BLOB field", function (done) { it("should be able to take a string as parameter to a BLOB field", function (done) {
var data = 'Sequelize';
if(dialect === 'mssql'){
data = this.sequelize.cast('Sequelize', 'varbinary');
}
this.BlobUser.create({ this.BlobUser.create({
data: 'Sequelize' data: data
}).success(function (user) { }).success(function (user) {
expect(user).to.be.ok expect(user).to.be.ok
done() done()
...@@ -2210,8 +2240,12 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -2210,8 +2240,12 @@ describe(Support.getTestDialectTeaser("Model"), function () {
it("should return a buffer when fetching a BLOB, even when the BLOB was inserted as a string", function (done) { it("should return a buffer when fetching a BLOB, even when the BLOB was inserted as a string", function (done) {
var self = this var self = this
var data = 'Sequelize';
if(dialect === 'mssql'){
data = this.sequelize.cast('Sequelize', 'varbinary');
}
this.BlobUser.create({ this.BlobUser.create({
data: 'Sequelize' data: data
}).success(function (user) { }).success(function (user) {
self.BlobUser.find(user.id).success(function (user) { self.BlobUser.find(user.id).success(function (user) {
expect(user.data).to.be.an.instanceOf(Buffer) expect(user.data).to.be.an.instanceOf(Buffer)
......
...@@ -171,7 +171,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -171,7 +171,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
}) })
}) })
it.only("should make aliased attributes available", function(done) { it("should make aliased attributes available", function(done) {
this.User.find({ this.User.find({
where: { id: 1 }, where: { id: 1 },
attributes: ['id', ['username', 'name']] attributes: ['id', ['username', 'name']]
...@@ -684,7 +684,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -684,7 +684,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
it('including two has many relations should not result in duplicate values', function(done) { it('including two has many relations should not result in duplicate values', function(done) {
var self = this var self = this
self.Contact = self.sequelize.define('Contact', { name: DataTypes.TEXT }) self.Contact = self.sequelize.define('Contact', { name: DataTypes.STRING })
self.Photo = self.sequelize.define('Photo', { img: DataTypes.TEXT }) self.Photo = self.sequelize.define('Photo', { img: DataTypes.TEXT })
self.PhoneNumber = self.sequelize.define('PhoneNumber', { phone: DataTypes.TEXT }) self.PhoneNumber = self.sequelize.define('PhoneNumber', { phone: DataTypes.TEXT })
......
...@@ -68,7 +68,6 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -68,7 +68,6 @@ describe(Support.getTestDialectTeaser("Model"), function () {
this.buf = new Buffer(16); this.buf = new Buffer(16);
this.buf.fill('\x01'); this.buf.fill('\x01');
this.User.bulkCreate([ this.User.bulkCreate([
{username: 'boo', intVal: 5, theDate: '2013-01-01 12:00'}, {username: 'boo', intVal: 5, theDate: '2013-01-01 12:00'},
{username: 'boo2', intVal: 10, theDate: '2013-01-10 12:00', binary: this.buf } {username: 'boo2', intVal: 10, theDate: '2013-01-10 12:00', binary: this.buf }
...@@ -207,7 +206,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -207,7 +206,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
it('should be able to handle false/true values just fine...', function(done) { it('should be able to handle false/true values just fine...', function(done) {
var User = this.User var User = this.User
, escapeChar = (dialect === "postgres") ? '"' : '`' , escapeChar = (dialect === "postgres" || dialect === 'mssql') ? '"' : '`'
User.bulkCreate([ User.bulkCreate([
{username: 'boo5', aBool: false}, {username: 'boo5', aBool: false},
...@@ -228,7 +227,7 @@ describe(Support.getTestDialectTeaser("Model"), function () { ...@@ -228,7 +227,7 @@ describe(Support.getTestDialectTeaser("Model"), function () {
it('should be able to handle false/true values through associations as well...', function(done) { it('should be able to handle false/true values through associations as well...', function(done) {
var User = this.User var User = this.User
, escapeChar = (dialect === "postgres") ? '"' : '`' , escapeChar = (dialect === "postgres" || dialect === 'mssql') ? '"' : '`'
var Passports = this.sequelize.define('Passports', { var Passports = this.sequelize.define('Passports', {
isActive: Sequelize.BOOLEAN isActive: Sequelize.BOOLEAN
}) })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!