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

Commit bd9cfd01 by Joel Trost Committed by Matt Broadstone

All DAO tests pass

1 parent 8ea65b1f
...@@ -15,6 +15,7 @@ env: ...@@ -15,6 +15,7 @@ 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"
...@@ -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
...@@ -52,6 +52,9 @@ module.exports = (function() { ...@@ -52,6 +52,9 @@ module.exports = (function() {
createSchema: function(schema){ createSchema: function(schema){
return SqlGenerator.getCreateSchemaSql(schema); return SqlGenerator.getCreateSchemaSql(schema);
}, },
showSchemasQuery: function(){
return 'SELECT name FROM sys.Tables;';
},
/* /*
Returns a query for creating a table. Returns a query for creating a table.
Parameters: Parameters:
...@@ -65,7 +68,8 @@ module.exports = (function() { ...@@ -65,7 +68,8 @@ module.exports = (function() {
*/ */
/* istanbul ignore next */ /* istanbul ignore next */
createTableQuery: function(tableName, attributes, options) { createTableQuery: function(tableName, attributes, options) {
return SqlGenerator.getCreateTableSql(tableName, attributes, options); var query = SqlGenerator.getCreateTableSql(tableName, attributes, options);
return query;
}, },
...@@ -199,12 +203,27 @@ module.exports = (function() { ...@@ -199,12 +203,27 @@ module.exports = (function() {
// throw new Error(); // throw new Error();
// } // }
//console.log('here', where); //console.log('here', where);
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, false, options);
for(var key in attributes){
//console.log(key);
//console.log('some more action', attributes.deletedAtThisTime);
if(attributes[key].primaryKey && attrValueHash[key]){
delete attrValueHash[key];
}
if(attrValueHash[key] && attrValueHash[key].fn){
}
}
if(!Object.keys(attrValueHash).length){
return '';
//return ['SELECT * FROM ', tableName, 'WHERE', this.getWhereConditions(where) + ';'].join(' ');
}
var query = [ var query = [
SqlGenerator.updateSql(tableName, attrValueHash, attributes), SqlGenerator.updateSql(tableName, attrValueHash, attributes),
'WHERE', 'WHERE',
this.getWhereConditions(where) this.getWhereConditions(where)
].join(' ') + ';'; ].join(' ') + ';';
console.log(query);
return query; return query;
}, },
/* /*
...@@ -225,8 +244,11 @@ module.exports = (function() { ...@@ -225,8 +244,11 @@ module.exports = (function() {
*/ */
/* istanbul ignore next */ /* istanbul ignore next */
deleteQuery: function(tableName, where, options) { deleteQuery: function(tableName, where, options) {
var query = [
var query = SqlGenerator.deleteSql(tableName, where); SqlGenerator.deleteSql(tableName),
"WHERE",
this.getWhereConditions(where),
";SELECT @@ROWCOUNT AS AFFECTEDROWS;"].join(' ');
return query; return query;
}, },
...@@ -241,8 +263,32 @@ module.exports = (function() { ...@@ -241,8 +263,32 @@ module.exports = (function() {
OR a string with conditions (e.g. 'name="foo"'). OR a string with conditions (e.g. 'name="foo"').
If you use a string, you have to escape it on your own. If you use a string, you have to escape it on your own.
*/ */
incrementQuery: function(tableName, attrValueHash, where, options) { incrementQuery: function(tableName, attrValueHash, where, options, attributes) {
throwMethodUndefined('incrementQuery'); attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, false, options);
for(var key in attributes){
//console.log(key);
//console.log('some more action', attributes.deletedAtThisTime);
if(attributes[key].primaryKey && attrValueHash[key]){
delete attrValueHash[key];
}
attrValueHash[key] += 1;
}
for(key in options){
if(key === 'allowNull'){
delete options[key];
}
}
if(!Object.keys(attrValueHash).length){
return '';
//return ['SELECT * FROM ', tableName, 'WHERE', this.getWhereConditions(where) + ';'].join(' ');
}
var query = [
SqlGenerator.incrementSql(tableName, attrValueHash, options),
'WHERE',
this.getWhereConditions(where)
].join(' ') + ';';
return query;
}, },
nameIndexes: function (indexes, rawTablename) { nameIndexes: function (indexes, rawTablename) {
...@@ -304,11 +350,66 @@ module.exports = (function() { ...@@ -304,11 +350,66 @@ module.exports = (function() {
return fields; return fields;
}, },
quoteTable: function(param, as) { quoteTable: function(param, as) {
throwMethodUndefined('quoteTable'); return SqlGenerator.quoteTable(param, as);
}, },
quote: function(obj, parent, force) { quote: function(obj, parent, force) {
throwMethodUndefined('quote'); if (Utils._.isString(obj)) {
return SqlGenerator.quoteIdentifiers(obj, force);
} else if (Array.isArray(obj)) {
// loop through array, adding table names of models to quoted
// (checking associations to see if names should be singularised or not)
var tableNames = []
, parentAssociation
, len = obj.length;
for (var i = 0; i < len - 1; i++) {
var item = obj[i];
if (item._modelAttribute || Utils._.isString(item) || item._isSequelizeMethod || 'raw' in item) {
break;
}
var model, as;
if (item instanceof Model) {
model = item;
} else {
model = item.model;
as = item.as;
}
// check if model provided is through table
var association;
if (!as && parentAssociation && parentAssociation.through.model === model) {
association = {as: Utils.singularize(model.tableName, model.options.language)};
} else {
// find applicable association for linking parent to this model
association = parent.getAssociation(model, as);
}
if (association) {
tableNames[i] = association.as;
parent = model;
parentAssociation = association;
} else {
tableNames[i] = model.tableName;
throw new Error('\'' + tableNames.join('.') + '\' in order / group clause is not valid association');
}
}
// add 1st string as quoted, 2nd as unquoted raw
var sql = (i > 0 ? SqlGenerator.quoteIdentifier(tableNames.join('.')) + '.' : '') + this.quote(obj[i], parent, force);
if (i < len - 1) {
sql += ' ' + obj[i + 1];
}
return sql;
} else if (obj._modelAttribute) {
return SqlGenerator.quoteIdentifer(obj.Model.name) + '.' + obj.fieldName;
} else if (obj._isSequelizeMethod) {
return this.handleSequelizeMethod(obj);
} else if (Utils._.isObject(obj) && 'raw' in obj) {
return obj.raw;
} else {
throw new Error('Unknown structure passed to order / group: ' + JSON.stringify(obj));
}
}, },
...@@ -371,7 +472,7 @@ module.exports = (function() { ...@@ -371,7 +472,7 @@ module.exports = (function() {
*/ */
/* istanbul ignore next */ /* istanbul ignore next */
quoteIdentifier: function(identifier, force) { quoteIdentifier: function(identifier, force) {
throwMethodUndefined('quoteIdentifier'); return SqlGenerator.quoteIdentifier(identifier, force);
}, },
/* /*
...@@ -392,8 +493,7 @@ module.exports = (function() { ...@@ -392,8 +493,7 @@ module.exports = (function() {
Escape a value (e.g. a string, number or date) Escape a value (e.g. a string, number or date)
*/ */
escape: function(value, field) { escape: function(value, field) {
return SqlGenerator.escape(value,field);
throwMethodUndefined('escape');
}, },
/** /**
...@@ -435,26 +535,451 @@ module.exports = (function() { ...@@ -435,26 +535,451 @@ module.exports = (function() {
selectQuery: function(tableName, options, model) { selectQuery: function(tableName, options, model) {
// Enter and change at your own peril -- Mick Hansen // Enter and change at your own peril -- Mick Hansen
// options = options || {};
// var query =[];
// if(options.attributes[0][0].fn === 'COUNT'){
// query.push(SqlGenerator.getCountClause('COUNT', options.attributes[0][0].args[0].col));
// }else{
// query.push(SqlGenerator.getSelectorClause(model,options));
// }
// query.push(SqlGenerator.getFromClause(model.tableName, model.name));
// if(options.include){
// for(var i = 0; i < options.include.length; i ++){
// query.push(SqlGenerator.getJoinClause(model, options.include[i]));
// }
// }
// if(options.hasOwnProperty('where')){
// query.push('WHERE');
// query.push(this.getWhereConditions(options.where, model.name, model, options));
// }
// //console.log(query.join(' ') + ';');
// return query.join(' ') + ';';
// Enter and change at your own peril -- Mick Hansen
options = options || {}; options = options || {};
var query =[];
if(options.attributes[0][0].fn === 'COUNT'){ var table = null
query.push(SqlGenerator.getCountClause('COUNT', options.attributes[0][0].args[0].col)); , self = this
}else{ , query
query.push(SqlGenerator.getSelectorClause(model,options)); , limit = options.limit
, mainQueryItems = []
, mainAttributes = options.attributes && options.attributes.slice(0)
, mainJoinQueries = []
// We'll use a subquery if we have hasMany associations and a limit and a filtered/required association
, subQuery = limit && (options.hasIncludeWhere || options.hasIncludeRequired || options.hasMultiAssociation) && options.subQuery !== false
, subQueryItems = []
, subQueryAttributes = null
, subJoinQueries = []
, mainTableAs = null;
if (!Array.isArray(tableName) && model) {
options.tableAs = mainTableAs = SqlGenerator.quoteIdentifier(model.name);
}
options.table = table = !Array.isArray(tableName) ? SqlGenerator.quoteTable(tableName) : tableName.map(function(t) {
if (Array.isArray(t)) {
return SqlGenerator.quoteTable(t[0], t[1]);
}
return SqlGenerator.quoteTable(t, true);
}.bind(this)).join(', ');
if (subQuery && mainAttributes) {
model.primaryKeyAttributes.forEach(function(keyAtt) {
// Check if mainAttributes contain the primary key of the model either as a field or an aliased field
if (!_.find(mainAttributes, function (attr) {
return keyAtt === attr || keyAtt === attr[0] || keyAtt === attr[1];
})) {
mainAttributes.push(model.rawAttributes[keyAtt].field ? [keyAtt, model.rawAttributes[keyAtt].field] : keyAtt);
}
});
}
// Escape attributes
mainAttributes = mainAttributes && mainAttributes.map(function(attr) {
var addTable = true;
if (attr._isSequelizeMethod) {
return self.handleSequelizeMethod(attr);
}
if (Array.isArray(attr) && attr.length === 2) {
if (attr[0]._isSequelizeMethod) {
attr[0] = self.handleSequelizeMethod(attr[0]);
addTable = false;
} else {
if (attr[0].indexOf('(') === -1 && attr[0].indexOf(')') === -1) {
attr[0] = SqlGenerator.quoteIdentifier(attr[0]);
}
}
attr = [attr[0], SqlGenerator.quoteIdentifier(attr[1])].join(' AS ');
} else {
attr = attr.indexOf(Utils.TICK_CHAR) < 0 && attr.indexOf('"') < 0 ? self.quoteIdentifiers(attr) : attr;
}
if (options.include && attr.indexOf('.') === -1 && addTable) {
attr = mainTableAs + '.' + attr;
}
return attr;
});
// If no attributes specified, use *
mainAttributes = mainAttributes || (options.include ? [mainTableAs + '.*'] : ['*']);
// If subquery, we ad the mainAttributes to the subQuery and set the mainAttributes to select * from subquery
if (subQuery) {
// We need primary keys
subQueryAttributes = mainAttributes;
mainAttributes = [mainTableAs + '.*'];
}
var topSql = this.getTop(options, query);
if (options.include) {
var generateJoinQueries = function(include, parentTable) {
var table = include.model.getTableName()
, as = include.as
, joinQueryItem = ''
, joinQueries = {
mainQuery: [],
subQuery: []
}
, attributes
, association = include.association
, through = include.through
, joinType = include.required ? ' INNER JOIN ' : ' LEFT OUTER JOIN '
, includeWhere = {}
, whereOptions = Utils._.clone(options);
whereOptions.keysEscaped = true;
if (tableName !== parentTable && mainTableAs !== parentTable) {
as = parentTable + '.' + include.as;
} }
query.push(SqlGenerator.getFromClause(model.tableName, model.name));
if(options.include){ // includeIgnoreAttributes is used by aggregate functions
for(var i = 0; i < options.include.length; i ++){ if (options.includeIgnoreAttributes !== false) {
query.push(SqlGenerator.getJoinClause(model, options.include[i]));
attributes = include.attributes.map(function(attr) {
var attrAs = attr,
verbatim = false;
if (Array.isArray(attr) && attr.length === 2) {
if (attr[0]._isSequelizeMethod) {
if (attr[0] instanceof Utils.literal ||
attr[0] instanceof Utils.cast ||
attr[0] instanceof Utils.fn
) {
verbatim = true;
} }
} }
if(options.hasOwnProperty('where')){
query.push('WHERE'); attr = attr.map(function($attr) {
query.push(this.getWhereConditions(options.where, model.name, model, options)); return $attr._isSequelizeMethod ? self.handleSequelizeMethod($attr) : $attr;
});
attrAs = attr[1];
attr = attr[0];
} else if (attr instanceof Utils.literal) {
return attr.val; // We trust the user to rename the field correctly
} else if (attr instanceof Utils.cast ||
attr instanceof Utils.fn
) {
throw new Error("Tried to select attributes using Sequelize.cast or Sequelize.fn without specifying an alias for the result, during eager loading. " +
"This means the attribute will not be added to the returned instance");
} }
//console.log(query.join(' ') + ';');
return query.join(' ') + ';'; var prefix;
if (verbatim === true) {
prefix = attr;
} else {
prefix = SqlGenerator.quoteIdentifier(as) + '.' + SqlGenerator.quoteIdentifier(attr);
}
return prefix + ' AS ' + SqlGenerator.quoteIdentifier(as + '.' + attrAs);
});
if (include.subQuery && subQuery) {
subQueryAttributes = subQueryAttributes.concat(attributes);
} else {
mainAttributes = mainAttributes.concat(attributes);
}
}
if (through) {
var throughTable = through.model.getTableName()
, throughAs = as + '.' + through.as
, throughAttributes = through.attributes.map(function(attr) {
return SqlGenerator.quoteIdentifier(throughAs) + '.' + SqlGenerator.quoteIdentifier(Array.isArray(attr) ? attr[0] : attr) +
' AS ' +
SqlGenerator.quoteIdentifier(throughAs + '.' + (Array.isArray(attr) ? attr[1] : attr));
})
, primaryKeysSource = association.source.primaryKeyAttributes
, tableSource = parentTable
, identSource = association.identifierField
, attrSource = association.source.rawAttributes[primaryKeysSource[0]].field || primaryKeysSource[0]
, where
, primaryKeysTarget = association.target.primaryKeyAttributes
, tableTarget = as
, identTarget = association.foreignIdentifierField
, attrTarget = association.target.rawAttributes[primaryKeysTarget[0]].field || primaryKeysTarget[0]
, sourceJoinOn
, targetJoinOn
, targetWhere;
if (options.includeIgnoreAttributes !== false) {
// Through includes are always hasMany, so we need to add the attributes to the mainAttributes no matter what (Real join will never be executed in subquery)
mainAttributes = mainAttributes.concat(throughAttributes);
}
// Filter statement for left side of through
// Used by both join and subquery where
sourceJoinOn = SqlGenerator.quoteIdentifier(tableSource) + '.' + SqlGenerator.quoteIdentifier(attrSource) + ' = ';
sourceJoinOn += SqlGenerator.quoteIdentifier(throughAs) + '.' + SqlGenerator.quoteIdentifier(identSource);
// Filter statement for right side of through
// Used by both join and subquery where
targetJoinOn = SqlGenerator.quoteIdentifier(tableTarget) + '.' + SqlGenerator.quoteIdentifier(attrTarget) + ' = ';
targetJoinOn += SqlGenerator.quoteIdentifier(throughAs) + '.' + SqlGenerator.quoteIdentifier(identTarget);
if (self._dialect.supports.joinTableDependent) {
// Generate a wrapped join so that the through table join can be dependent on the target join
joinQueryItem += joinType + '(';
joinQueryItem += SqlGenerator.quoteTable(throughTable, throughAs);
joinQueryItem += joinType + SqlGenerator.quoteTable(table, as) + ' ON ';
joinQueryItem += targetJoinOn;
joinQueryItem += ') ON '+sourceJoinOn;
} else {
// Generate join SQL for left side of through
joinQueryItem += joinType + SqlGenerator.quoteTable(throughTable, throughAs) + ' ON ';
joinQueryItem += sourceJoinOn;
// Generate join SQL for right side of through
joinQueryItem += joinType + SqlGenerator.quoteTable(table, as) + ' ON ';
joinQueryItem += targetJoinOn;
}
if (include.where) {
targetWhere = self.getWhereConditions(include.where, self.sequelize.literal(SqlGenerator.quoteIdentifier(as)), include.model, whereOptions);
joinQueryItem += ' AND ' + targetWhere;
if (subQuery && include.required) {
if (!options.where) options.where = {};
// Creating the as-is where for the subQuery, checks that the required association exists
options.where['__' + throughAs] = self.sequelize.asIs(['(',
'SELECT TOP(1)' + SqlGenerator.quoteIdentifier(throughAs) + '.' + SqlGenerator.quoteIdentifier(identSource) + ' FROM ' + SqlGenerator.quoteTable(throughTable, throughAs),
! include.required && joinType + SqlGenerator.quoteTable(association.source.tableName, tableSource) + ' ON ' + sourceJoinOn || '',
joinType + SqlGenerator.quoteTable(table, as) + ' ON ' + targetJoinOn,
'WHERE ' + (! include.required && targetWhere || sourceJoinOn + ' AND ' + targetWhere),
')', 'IS NOT NULL'].join(' '));
}
}
} else {
var left = association.associationType === 'BelongsTo' ? association.target : association.source
, primaryKeysLeft = left.primaryKeyAttributes
, tableLeft = association.associationType === 'BelongsTo' ? as : parentTable
, attrLeft = primaryKeysLeft[0]
, tableRight = association.associationType === 'BelongsTo' ? parentTable : as
, attrRight = association.identifierField || association.identifier
, joinOn;
// Alias the left attribute if the left attribute is not from a subqueried main table
// When doing a query like SELECT aliasedKey FROM (SELECT primaryKey FROM primaryTable) only aliasedKey is available to the join, this is not the case when doing a regular select where you can't used the aliased attribute
if (!subQuery || parentTable !== mainTableAs || tableLeft !== parentTable) {
if (left.rawAttributes[attrLeft].field) {
attrLeft = left.rawAttributes[attrLeft].field;
}
}
// Filter statement
// Used by both join and subquery where
joinOn =
// Left side
(
(subQuery && !include.subQuery && include.parent.subQuery && !(include.hasParentRequired && include.hasParentWhere)) && SqlGenerator.quoteIdentifier(tableLeft + '.' + attrLeft) ||
SqlGenerator.quoteIdentifier(tableLeft) + '.' + SqlGenerator.quoteIdentifier(attrLeft)
)
+ ' = ' +
// Right side
(
(subQuery && !include.subQuery && include.parent.subQuery && (include.hasParentRequired && include.hasParentWhere)) && SqlGenerator.quoteIdentifier(tableRight + '.' + attrRight) ||
SqlGenerator.quoteIdentifier(tableRight) + '.' + SqlGenerator.quoteIdentifier(attrRight)
);
if (include.where) {
joinOn += ' AND ' + self.getWhereConditions(include.where, self.sequelize.literal(SqlGenerator.quoteIdentifier(as)), include.model, whereOptions);
// If its a multi association we need to add a where query to the main where (executed in the subquery)
if (subQuery && association.isMultiAssociation && include.required) {
if (!options.where) options.where = {};
// Creating the as-is where for the subQuery, checks that the required association exists
options.where['__' + as] = self.sequelize.asIs(['(',
'SELECT TOP(1)' + SqlGenerator.quoteIdentifier(attrRight),
'FROM ' + SqlGenerator.quoteTable(table, as),
'WHERE ' + joinOn,
')', 'IS NOT NULL'].join(' '));
}
}
// Generate join SQL
joinQueryItem += joinType + SqlGenerator.quoteTable(table,as) + ' ON ' + joinOn;
}
if (include.subQuery && subQuery) {
joinQueries.subQuery.push(joinQueryItem);
} else {
joinQueries.mainQuery.push(joinQueryItem);
}
if (include.include) {
include.include.forEach(function(childInclude) {
if (childInclude._pseudo) return;
var childJoinQueries = generateJoinQueries(childInclude, as);
if (childInclude.subQuery && subQuery) {
joinQueries.subQuery = joinQueries.subQuery.concat(childJoinQueries.subQuery);
}
if (childJoinQueries.mainQuery) {
joinQueries.mainQuery = joinQueries.mainQuery.concat(childJoinQueries.mainQuery);
}
}.bind(this));
}
return joinQueries;
};
// Loop through includes and generate subqueries
options.include.forEach(function(include) {
var joinQueries = generateJoinQueries(include, options.tableAs);
subJoinQueries = subJoinQueries.concat(joinQueries.subQuery);
mainJoinQueries = mainJoinQueries.concat(joinQueries.mainQuery);
}.bind(this));
}
// If using subQuery select defined subQuery attributes and join subJoinQueries
if (subQuery) {
subQueryItems.push('SELECT ' + topSql + subQueryAttributes.join(', ') + ' FROM ' + options.table);
if (mainTableAs) {
subQueryItems.push(' AS ' + mainTableAs);
}
subQueryItems.push(subJoinQueries.join(''));
// Else do it the reguar way
} else {
mainQueryItems.push('SELECT ' + topSql + mainAttributes.join(', ') + ' FROM ' + options.table);
if (mainTableAs) {
mainQueryItems.push(' AS ' + mainTableAs);
}
mainQueryItems.push(mainJoinQueries.join(''));
}
// Add WHERE to sub or main query
if (options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, mainTableAs || tableName, model, options);
if (options.where) {
if (subQuery) {
subQueryItems.push(' WHERE ' + options.where);
} else {
mainQueryItems.push(' WHERE ' + options.where);
}
}
}
// Add GROUP BY to sub or main query
if (options.group) {
options.group = Array.isArray(options.group) ? options.group.map(function(t) { return this.quote(t, model); }.bind(this)).join(', ') : options.group;
if (subQuery) {
subQueryItems.push(' GROUP BY ' + options.group);
} else {
mainQueryItems.push(' GROUP BY ' + options.group);
}
}
// Add HAVING to sub or main query
if (options.hasOwnProperty('having')) {
options.having = this.getWhereConditions(options.having, tableName, model, options, false);
if (subQuery) {
subQueryItems.push(' HAVING ' + options.having);
} else {
mainQueryItems.push(' HAVING ' + options.having);
}
}
// Add ORDER to sub or main query
if (options.order) {
var mainQueryOrder = [];
var subQueryOrder = [];
if (Array.isArray(options.order)) {
options.order.forEach(function(t) {
if (subQuery && !(t[0] instanceof Model) && !(t[0].model instanceof Model)) {
subQueryOrder.push(this.quote(t, model));
}
mainQueryOrder.push(this.quote(t, model));
}.bind(this));
} else {
mainQueryOrder.push(options.order);
}
if (mainQueryOrder.length) {
mainQueryItems.push(' ORDER BY ' + mainQueryOrder.join(', '));
}
if (subQueryOrder.length) {
subQueryItems.push(' ORDER BY ' + subQueryOrder.join(', '));
}
}
//var limitOrder = this.addLimitAndOffset(options, query);
// Add LIMIT, OFFSET to sub or main query
//console.log(mainQueryItems);
if (options.offset) {
//needs an order column for this to work
//default to id
var limitOrder = this.getLimitAndOffset(options,query);
if (subQuery) {
if(!options.order){
subQueryItems.push(' ORDER BY ' + SqlGenerator.quoteIdentifier(model.primaryKeyAttribute));
}
subQueryItems.push(limitOrder);
} else {
if(!options.order){
mainQueryItems.push(' ORDER BY ' + SqlGenerator.quoteIdentifier(model.primaryKeyAttribute));
}
mainQueryItems.push(limitOrder);
}
}
// If using subQuery, select attributes from wrapped subQuery and join out join tables
if (subQuery) {
query = 'SELECT ' + mainAttributes.join(', ') + ' FROM (';
query += subQueryItems.join('');
query += ') AS ' + options.tableAs;
query += mainJoinQueries.join('');
query += mainQueryItems.join('');
} else {
query = mainQueryItems.join('');
}
if (options.lock && this._dialect.supports.lock) {
if (options.lock === 'SHARE') {
query += ' ' + this._dialect.supports.forShare;
} else {
query += ' FOR UPDATE';
}
}
query += ';';
//console.log(query);
return query;
}, },
/** /**
* Returns a query that starts a transaction. * Returns a query that starts a transaction.
...@@ -519,24 +1044,29 @@ module.exports = (function() { ...@@ -519,24 +1044,29 @@ module.exports = (function() {
*/ */
rollbackTransactionQuery: function(transaction, options) { rollbackTransactionQuery: function(transaction, options) {
if (options.parent) { if (options.parent) {
return 'ROLLBACK TRANSACTION ' + this.quoteIdentifier(transaction.name) + ';'; return 'ROLLBACK TRANSACTION ' + SqlGenerator.quoteIdentifier(transaction.name) + ';';
} }
return 'ROLLBACK TRANSACTION;'; return 'ROLLBACK TRANSACTION;';
// return ''; // return '';
}, },
getTop: function(options){
addLimitAndOffset: function(options, query) { var query = '';
if(options.limit && !options.offset){
query += ' TOP(' + options.limit + ') ';
}
return query;
},
getLimitAndOffset: function(options, query) {
query = query || ''; query = query || '';
if (options.offset && !options.limit) { if(options.limit){
query += ' LIMIT ' + options.offset + ', ' + 10000000000000; if(options.offset){
} else if (options.limit) { query += ' OFFSET ' + options.offset + ' ROWS'
if (options.offset) { + ' FETCH NEXT ' + options.limit + ' ROWS ONLY';
query += ' LIMIT ' + options.offset + ', ' + options.limit;
} else {
query += ' LIMIT ' + options.limit;
} }
}else if(options.offset){
query += ' OFFSET ' + options.offset + ' ROWS';
} }
return query; return query;
}, },
...@@ -594,7 +1124,7 @@ module.exports = (function() { ...@@ -594,7 +1124,7 @@ module.exports = (function() {
} else if (typeof smth === 'string') { } else if (typeof smth === 'string') {
result = smth; result = smth;
} else if (Buffer.isBuffer(smth)) { } else if (Buffer.isBuffer(smth)) {
result = this.escape(smth); result = SqlGenerator.escape(smth);
} else if (Array.isArray(smth)) { } else if (Array.isArray(smth)) {
if (Utils.canTreatArrayAsAnd(smth)) { if (Utils.canTreatArrayAsAnd(smth)) {
var _smth = self.sequelize.and.apply(null, smth); var _smth = self.sequelize.and.apply(null, smth);
...@@ -603,23 +1133,10 @@ module.exports = (function() { ...@@ -603,23 +1133,10 @@ module.exports = (function() {
result = Utils.format(smth, this.dialect); result = Utils.format(smth, this.dialect);
} }
} else if (smth === null) { } else if (smth === null) {
result = '1=1'; result = "1=1";
} }
return result ? result : '1=1'; return result ? result : '1=1';
}, },
// getWhereConditions: function(where, tableName, model, options, prepend) {
// //console.log('where:', model);
// console.log('logic', where);
// //console.log('options', options);
// if(where){
// return SqlGenerator.getWhereClause(where, tableName);
// }else{
// return '';
// }
// },
handleSequelizeMethod: function (smth, tableName, factory, options, prepend) { handleSequelizeMethod: function (smth, tableName, factory, options, prepend) {
var self = this var self = this
...@@ -645,7 +1162,7 @@ module.exports = (function() { ...@@ -645,7 +1162,7 @@ module.exports = (function() {
if (smth.attribute._isSequelizeMethod) { if (smth.attribute._isSequelizeMethod) {
key = this.getWhereConditions(smth.attribute, tableName, factory, options, prepend); key = this.getWhereConditions(smth.attribute, tableName, factory, options, prepend);
} else { } else {
key = this.quoteTable(smth.attribute.Model.name) + '.' + this.quoteIdentifier(smth.attribute.fieldName); key = SqlGenerator.quoteIdentifier(smth.attribute.Model.name) + '.' + SqlGenerator.quoteIdentifier(smth.attribute.fieldName);
} }
if (value._isSequelizeMethod) { if (value._isSequelizeMethod) {
...@@ -658,7 +1175,7 @@ module.exports = (function() { ...@@ -658,7 +1175,7 @@ module.exports = (function() {
result = [key, value.join].join('='); result = [key, value.join].join('=');
} else { } else {
for (logic in value) { for (logic in value) {
_result.push([key, this.escape(value[logic])].join(' ' + Utils.getWhereLogic(logic, value[logic]) + ' ')); _result.push([key, SqlGenerator.escape(value[logic])].join(' ' + Utils.getWhereLogic(logic, value[logic]) + ' '));
} }
result = _result.join(' AND '); result = _result.join(' AND ');
...@@ -667,7 +1184,7 @@ module.exports = (function() { ...@@ -667,7 +1184,7 @@ module.exports = (function() {
if (typeof value === 'boolean') { if (typeof value === 'boolean') {
value = this.booleanValue(value); value = this.booleanValue(value);
} else { } else {
value = this.escape(value); value = SqlGenerator.escape(value);
} }
result = (value === 'NULL') ? key + ' IS NULL' : [key, value].join(' ' + smth.comparator + ' '); result = (value === 'NULL') ? key + ' IS NULL' : [key, value].join(' ' + smth.comparator + ' ');
...@@ -678,7 +1195,7 @@ module.exports = (function() { ...@@ -678,7 +1195,7 @@ module.exports = (function() {
if (smth.val._isSequelizeMethod) { if (smth.val._isSequelizeMethod) {
result = this.handleSequelizeMethod(smth.val, tableName, factory, options, prepend); result = this.handleSequelizeMethod(smth.val, tableName, factory, options, prepend);
} else { } else {
result = this.escape(smth.val); result = SqlGenerator.escape(smth.val);
} }
result = 'CAST(' + result + ' AS ' + smth.type.toUpperCase() + ')'; result = 'CAST(' + result + ' AS ' + smth.type.toUpperCase() + ')';
...@@ -687,7 +1204,7 @@ module.exports = (function() { ...@@ -687,7 +1204,7 @@ module.exports = (function() {
if (arg._isSequelizeMethod) { if (arg._isSequelizeMethod) {
return self.handleSequelizeMethod(arg, tableName, factory, options, prepend); return self.handleSequelizeMethod(arg, tableName, factory, options, prepend);
} else { } else {
return self.escape(arg); return SqlGenerator.escape(arg);
} }
}).join(', ') + ')'; }).join(', ') + ')';
} else if (smth instanceof Utils.col) { } else if (smth instanceof Utils.col) {
...@@ -718,7 +1235,7 @@ module.exports = (function() { ...@@ -718,7 +1235,7 @@ module.exports = (function() {
_hash[SqlGenerator.quoteIdentifier(tableName) + '.' + SqlGenerator.quoteIdentifier(key)] = hash[key]; _hash[SqlGenerator.quoteIdentifier(tableName) + '.' + SqlGenerator.quoteIdentifier(key)] = hash[key];
} }
} else { } else {
_hash[this.quoteIdentifiers(key)] = hash[key]; _hash[SqlGenerator.quoteIdentifiers(key)] = hash[key];
} }
} }
...@@ -765,7 +1282,11 @@ module.exports = (function() { ...@@ -765,7 +1282,11 @@ module.exports = (function() {
}, },
arrayValue: function(value, key, _key, factory, logicResult) { arrayValue: function(value, key, _key, factory, logicResult) {
throwMethodUndefined('arrayValue'); var _value = null;
if (value.length === 0) { value = [null]; }
_value = '(' + value.map(function(v) { return SqlGenerator.escape(v); }.bind(this)).join(',') + ')';
return [_key, _value].join(' ' + logicResult + ' ');
}, },
/* /*
...@@ -793,7 +1314,7 @@ module.exports = (function() { ...@@ -793,7 +1314,7 @@ module.exports = (function() {
if (this.isAssociationFilter(key, dao, options)) { if (this.isAssociationFilter(key, dao, options)) {
_key = key = this.getAssociationFilterColumn(key, dao, options); _key = key = this.getAssociationFilterColumn(key, dao, options);
} else { } else {
_key = this.quoteIdentifiers(key); _key = SqlGenerator.quoteIdentifiers(key);
} }
} }
...@@ -802,7 +1323,7 @@ module.exports = (function() { ...@@ -802,7 +1323,7 @@ module.exports = (function() {
} else if ((value) && (typeof value === 'object') && !(value instanceof Date) && !Buffer.isBuffer(value)) { } else if ((value) && (typeof value === 'object') && !(value instanceof Date) && !Buffer.isBuffer(value)) {
if (!!value.join) { if (!!value.join) {
//using as sentinel for join column => value //using as sentinel for join column => value
_value = this.quoteIdentifiers(value.join); _value = SqlGenerator.quoteIdentifiers(value.join);
result.push([_key, _value].join('=')); result.push([_key, _value].join('='));
} else { } else {
for (var logic in value) { for (var logic in value) {
...@@ -832,7 +1353,6 @@ module.exports = (function() { ...@@ -832,7 +1353,6 @@ module.exports = (function() {
result.push((_value === 'NULL') ? _key + ' IS NULL' : [_key, _value].join('=')); result.push((_value === 'NULL') ? _key + ' IS NULL' : [_key, _value].join('='));
} }
}.bind(this)); }.bind(this));
return result.join(' AND '); return result.join(' AND ');
}, },
......
...@@ -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;
} }
...@@ -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:
match = err.message.match(/Duplicate entry '(.*)' for key '?(.*?)$/);
return new sequelizeErrors.UniqueConstraintError({ return new sequelizeErrors.UniqueConstraintError({
name: 'SequelizeUniqueConstraintError',
fields: null, fields: null,
index: match[2], index: 0,
value: match[1], value: match[2],
parent: err parent: err
}); });
}
case 1451: match = err.message.match(/Failed on step '(.*)'.Could not create constraint. See previous errors./);
match = err.message.match(/FOREIGN KEY \(`(.*)`\) REFERENCES `(.*)` \(`(.*)`\)(?: ON .*)?\)$/); if(match && match.length > 0){
return new sequelizeErrors.ForeignKeyConstraintError({
fields: null,
index: match[3],
parent: err
});
case 1452:
match = err.message.match(/FOREIGN KEY \(`(.*)`\) REFERENCES `(.*)` \(`(.*)`\)(.*)\)$/);
return new sequelizeErrors.ForeignKeyConstraintError({ return new sequelizeErrors.ForeignKeyConstraintError({
fields: null, fields: null,
index: match[1], index: match[1],
parent: err 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,22 +100,37 @@ function processValue(val, modelAttribute){ ...@@ -99,22 +100,37 @@ 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)) {
if(isUpdate){
values.push(quoteIdentifier(key) + '=' + processValue(fields[key], (modelAttributeMap && modelAttributeMap[key]) || undefined));
} else {
values.push(processValue(fields[key], (modelAttributeMap && modelAttributeMap[key]) || undefined)); values.push(processValue(fields[key], (modelAttributeMap && modelAttributeMap[key]) || undefined));
} }
} }
}
if(values){ if(values){
if(values.length > 0){ if(values.length > 0){
return values.join(','); return values.join(',');
...@@ -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 = {
unquotedTable: tableName,
tableName: quoteIdentifier(tableName.schema)
+ "." + quoteIdentifier(tableName.tableName)
};
}else{
values = { values = {
unquotedTable: tableName, unquotedTable: tableName,
tableName: quoteIdentifier(tableName) tableName: quoteIdentifier(tableName.toString())
}; };
}
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)
...@@ -360,26 +399,55 @@ module.exports = { ...@@ -360,26 +399,55 @@ module.exports = {
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);
...@@ -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,7 +913,6 @@ module.exports = (function() { ...@@ -913,7 +913,6 @@ 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());
...@@ -921,7 +920,6 @@ module.exports = (function() { ...@@ -921,7 +920,6 @@ module.exports = (function() {
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) {
if(dialect === 'mssql'){
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*(user_and_email)?\s*\([`"]?username[`"]?, [`"]?email[`"]?\)/)
expect(sql).to.match(/UNIQUE\s*(a_and_b)?\s*\([`"]?aCol[`"]?, [`"]?bCol[`"]?\)/) 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) {
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/) 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!