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

Commit 7378a16b by Mick Hansen

Merge pull request #4990 from MichaelKearnsSoftwire/mssql_can_remove_column_with_default

Mssql can remove column with default
2 parents ecffc5f5 e3ab3456
...@@ -22,7 +22,7 @@ endif ...@@ -22,7 +22,7 @@ endif
# Unit tests # Unit tests
test-unit: test-unit:
$(MOCHA) --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 15000 --reporter $(REPORTER) ./test/unit/*.js ./test/unit/**/*.js $(MOCHA) --globals setImmediate,clearImmediate --ui tdd --check-leaks --colors -t 15000 --reporter $(REPORTER) ./test/unit/*.js "./test/unit/**/*.js"
test-unit-all: test-unit-sqlite test-unit-mysql test-unit-postgres test-unit-postgres-native test-unit-mariadb test-unit-mssql test-unit-all: test-unit-sqlite test-unit-mysql test-unit-postgres test-unit-postgres-native test-unit-mariadb test-unit-mssql
......
...@@ -24,7 +24,7 @@ var QueryGenerator = { ...@@ -24,7 +24,7 @@ var QueryGenerator = {
tableName = tableName || {}; tableName = tableName || {};
return { return {
schema: tableName.schema || options.schema || 'public', schema: tableName.schema || options.schema || 'public',
tableName: _.isPlainObject(tableName) ? tableName.table : tableName, tableName: _.isPlainObject(tableName) ? tableName.tableName : tableName,
delimiter: tableName.delimiter || options.delimiter || '.' delimiter: tableName.delimiter || options.delimiter || '.'
}; };
}, },
......
...@@ -532,6 +532,25 @@ var QueryGenerator = { ...@@ -532,6 +532,25 @@ var QueryGenerator = {
}); });
}, },
getDefaultConstraintQuery: function (tableName, attributeName) {
var sql = "SELECT name FROM SYS.DEFAULT_CONSTRAINTS " +
"WHERE PARENT_OBJECT_ID = OBJECT_ID('<%= table %>', 'U') " +
"AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns WHERE NAME = ('<%= column %>') " +
"AND object_id = OBJECT_ID('<%= table %>', 'U'));";
return Utils._.template(sql)({
table: this.quoteTable(tableName),
column: attributeName
});
},
dropConstraintQuery: function (tableName, constraintName) {
var sql = 'ALTER TABLE <%= table %> DROP CONSTRAINT <%= constraint %>;';
return Utils._.template(sql)({
table: this.quoteTable(tableName),
constraint: this.quoteIdentifier(constraintName)
});
},
setAutocommitQuery: function(value) { setAutocommitQuery: function(value) {
return ''; return '';
// return 'SET IMPLICIT_TRANSACTIONS ' + (!!value ? 'OFF' : 'ON') + ';'; // return 'SET IMPLICIT_TRANSACTIONS ' + (!!value ? 'OFF' : 'ON') + ';';
......
'use strict';
/**
Returns an object that treats MSSQL's inabilities to do certain queries.
@class QueryInterface
@static
*/
/**
A wrapper that fixes MSSQL's inability to cleanly remove columns from existing tables if they have a default constraint.
@method removeColumn
@for QueryInterface
@param {String} tableName The name of the table.
@param {String} attributeName The name of the attribute that we want to remove.
@param {Object} options
@param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries
*/
var removeColumn = function (tableName, attributeName, options) {
var self = this;
options = options || {};
var findConstraintSql = self.QueryGenerator.getDefaultConstraintQuery(tableName, attributeName);
return self.sequelize.query(findConstraintSql, { raw: true, logging: options.logging})
.spread(function (results) {
if (!results.length) {
// No default constraint found -- we can cleanly remove the column
return;
}
var dropConstraintSql = self.QueryGenerator.dropConstraintQuery(tableName, results[0].name);
return self.sequelize.query(dropConstraintSql, { raw: true, logging: options.logging});
})
.then(function () {
var removeSql = self.QueryGenerator.removeColumnQuery(tableName, attributeName);
return self.sequelize.query(removeSql, { raw: true, logging: options.logging});
});
};
module.exports = {
removeColumn: removeColumn
};
...@@ -193,7 +193,7 @@ var QueryGenerator = { ...@@ -193,7 +193,7 @@ var QueryGenerator = {
}); });
return Utils._.template(query)({ return Utils._.template(query)({
table: this.quoteTable(table), table: this.quoteTable(this.extractTableDetails(table)),
attribute: attribute attribute: attribute
}); });
}, },
...@@ -201,7 +201,7 @@ var QueryGenerator = { ...@@ -201,7 +201,7 @@ var QueryGenerator = {
removeColumnQuery: function(tableName, attributeName) { removeColumnQuery: function(tableName, attributeName) {
var query = 'ALTER TABLE <%= tableName %> DROP COLUMN <%= attributeName %>;'; var query = 'ALTER TABLE <%= tableName %> DROP COLUMN <%= attributeName %>;';
return Utils._.template(query)({ return Utils._.template(query)({
tableName: this.quoteTable(tableName), tableName: this.quoteTable(this.extractTableDetails(tableName)),
attributeName: this.quoteIdentifier(attributeName) attributeName: this.quoteIdentifier(attributeName)
}); });
}, },
......
...@@ -22,8 +22,6 @@ var Utils = require('../../utils') ...@@ -22,8 +22,6 @@ var Utils = require('../../utils')
@param {String} attributeName The name of the attribute that we want to remove. @param {String} attributeName The name of the attribute that we want to remove.
@param {Object} options @param {Object} options
@param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries @param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries
@param {CustomEventEmitter} emitter The EventEmitter from outside.
@param {Function} queryAndEmit The function from outside that triggers some events to get triggered.
@since 1.6.0 @since 1.6.0
*/ */
...@@ -55,8 +53,6 @@ var removeColumn = function(tableName, attributeName, options) { ...@@ -55,8 +53,6 @@ var removeColumn = function(tableName, attributeName, options) {
@param {Object} attributes An object with the attribute's name as key and it's options as value object. @param {Object} attributes An object with the attribute's name as key and it's options as value object.
@param {Object} options @param {Object} options
@param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries @param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries
@param {CustomEventEmitter} emitter The EventEmitter from outside.
@param {Function} queryAndEmit The function from outside that triggers some events to get triggered.
@since 1.6.0 @since 1.6.0
*/ */
...@@ -90,8 +86,6 @@ var changeColumn = function(tableName, attributes, options) { ...@@ -90,8 +86,6 @@ var changeColumn = function(tableName, attributes, options) {
@param {String} attrNameAfter The name of the attribute after it was renamed. @param {String} attrNameAfter The name of the attribute after it was renamed.
@param {Object} options @param {Object} options
@param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries @param {Boolean|Function} [options.logging] A function that logs the sql queries, or false for explicitly not logging these queries
@param {CustomEventEmitter} emitter The EventEmitter from outside.
@param {Function} queryAndEmit The function from outside that triggers some events to get triggered.
@since 1.6.0 @since 1.6.0
*/ */
......
...@@ -4,6 +4,7 @@ var Utils = require('./utils') ...@@ -4,6 +4,7 @@ var Utils = require('./utils')
, _ = require('lodash') , _ = require('lodash')
, DataTypes = require('./data-types') , DataTypes = require('./data-types')
, SQLiteQueryInterface = require('./dialects/sqlite/query-interface') , SQLiteQueryInterface = require('./dialects/sqlite/query-interface')
, MSSSQLQueryInterface = require('./dialects/mssql/query-interface')
, Transaction = require('./transaction') , Transaction = require('./transaction')
, Promise = require('./promise') , Promise = require('./promise')
, QueryTypes = require('./query-types'); , QueryTypes = require('./query-types');
...@@ -354,12 +355,16 @@ QueryInterface.prototype.addColumn = function(table, key, attribute, options) { ...@@ -354,12 +355,16 @@ QueryInterface.prototype.addColumn = function(table, key, attribute, options) {
QueryInterface.prototype.removeColumn = function(tableName, attributeName, options) { QueryInterface.prototype.removeColumn = function(tableName, attributeName, options) {
options = options || {}; options = options || {};
if (this.sequelize.options.dialect === 'sqlite') { switch (this.sequelize.options.dialect) {
// sqlite needs some special treatment as it cannot drop a column case 'sqlite':
return SQLiteQueryInterface.removeColumn.call(this, tableName, attributeName, options); // sqlite needs some special treatment as it cannot drop a column
} else { return SQLiteQueryInterface.removeColumn.call(this, tableName, attributeName, options);
var sql = this.QueryGenerator.removeColumnQuery(tableName, attributeName); case 'mssql':
return this.sequelize.query(sql, options); // mssql needs special treatment as it cannot drop a column with a default constraint
return MSSSQLQueryInterface.removeColumn.call(this, tableName, attributeName, options);
default:
var sql = this.QueryGenerator.removeColumnQuery(tableName, attributeName);
return this.sequelize.query(sql, options);
} }
}; };
......
...@@ -21,26 +21,20 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -21,26 +21,20 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
this.queryInterface = this.sequelize.getQueryInterface(); this.queryInterface = this.sequelize.getQueryInterface();
}); });
afterEach(function() {
return this.sequelize.dropAllSchemas();
});
describe('dropAllTables', function() { describe('dropAllTables', function() {
it('should drop all tables', function() { it('should drop all tables', function() {
var self = this; var self = this;
return this.queryInterface.dropAllTables().then(function() { return this.queryInterface.dropAllTables().then(function() {
return self.queryInterface.showAllTables({logging: log}).then(function(tableNames) { return self.queryInterface.showAllTables().then(function(tableNames) {
expect(count).to.be.equal(1);
count = 0;
expect(tableNames).to.be.empty; expect(tableNames).to.be.empty;
return self.queryInterface.createTable('table', { name: DataTypes.STRING }, { return self.queryInterface.createTable('table', { name: DataTypes.STRING }).then(function() {
logging: log return self.queryInterface.showAllTables().then(function(tableNames) {
}).then(function() {
expect(count).to.be.equal(1);
count = 0;
return self.queryInterface.showAllTables({logging: log}).then(function(tableNames) {
expect(count).to.be.equal(1);
count = 0;
expect(tableNames).to.have.length(1); expect(tableNames).to.have.length(1);
return self.queryInterface.dropAllTables({logging: log}).then(function() { return self.queryInterface.dropAllTables().then(function() {
expect(count).to.be.at.least(1);
count = 0;
return self.queryInterface.showAllTables().then(function(tableNames) { return self.queryInterface.showAllTables().then(function(tableNames) {
expect(tableNames).to.be.empty; expect(tableNames).to.be.empty;
}); });
...@@ -71,9 +65,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -71,9 +65,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
describe('indexes', function() { describe('indexes', function() {
beforeEach(function() { beforeEach(function() {
var self = this; var self = this;
return this.queryInterface.dropTable('Group', {logging: log}).then(function() { return this.queryInterface.dropTable('Group').then(function() {
expect(count).to.be.at.least(1);
count = 0;
return self.queryInterface.createTable('Group', { return self.queryInterface.createTable('Group', {
username: DataTypes.STRING, username: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN, isAdmin: DataTypes.BOOLEAN,
...@@ -84,20 +76,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -84,20 +76,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
it('adds, reads and removes an index to the table', function() { it('adds, reads and removes an index to the table', function() {
var self = this; var self = this;
return this.queryInterface.addIndex('Group', ['username', 'isAdmin'], { return this.queryInterface.addIndex('Group', ['username', 'isAdmin']).then(function() {
logging: log return self.queryInterface.showIndex('Group').then(function(indexes) {
}).then(function() {
expect(count).to.be.equal(1);
count = 0;
return self.queryInterface.showIndex('Group', {logging: log}).then(function(indexes) {
expect(count).to.be.equal(1);
count = 0;
var indexColumns = _.uniq(indexes.map(function(index) { return index.name; })); var indexColumns = _.uniq(indexes.map(function(index) { return index.name; }));
expect(indexColumns).to.include('group_username_is_admin'); expect(indexColumns).to.include('group_username_is_admin');
return self.queryInterface.removeIndex('Group', ['username', 'isAdmin'], {logging: log}).then(function() { return self.queryInterface.removeIndex('Group', ['username', 'isAdmin']).then(function() {
expect(count).to.be.equal(1);
count = 0;
return self.queryInterface.showIndex('Group').then(function(indexes) { return self.queryInterface.showIndex('Group').then(function(indexes) {
indexColumns = _.uniq(indexes.map(function(index) { return index.name; })); indexColumns = _.uniq(indexes.map(function(index) { return index.name; }));
expect(indexColumns).to.be.empty; expect(indexColumns).to.be.empty;
...@@ -109,9 +92,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -109,9 +92,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
it('works with schemas', function() { it('works with schemas', function() {
var self = this; var self = this;
return self.sequelize.dropAllSchemas({logging: log}).then(function() { return self.sequelize.createSchema('schema').then(function() {
return self.sequelize.createSchema('schema', {logging: log});
}).then(function() {
return self.queryInterface.createTable('table', { return self.queryInterface.createTable('table', {
name: { name: {
type: DataTypes.STRING type: DataTypes.STRING
...@@ -126,19 +107,16 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -126,19 +107,16 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
return self.queryInterface.addIndex({ return self.queryInterface.addIndex({
schema: 'schema', schema: 'schema',
tableName: 'table' tableName: 'table'
}, ['name', 'isAdmin'], { }, ['name', 'isAdmin'], null, 'schema_table').then(function() {
logging: log return self.queryInterface.showIndex({
}, 'schema_table').then(function() { schema: 'schema',
return self.queryInterface.showIndex({ tableName: 'table'
schema: 'schema', }).then(function(indexes) {
tableName: 'table' expect(indexes.length).to.eq(1);
}, {logging: log}).then(function(indexes) { });
expect(indexes.length).to.eq(1);
count = 0;
}); });
}); });
}); });
});
it('does not fail on reserved keywords', function() { it('does not fail on reserved keywords', function() {
return this.queryInterface.addIndex('Group', ['from']); return this.queryInterface.addIndex('Group', ['from']);
...@@ -159,10 +137,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -159,10 +137,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
}, { freezeTableName: true }); }, { freezeTableName: true });
return Users.sync({ force: true }).then(function() { return Users.sync({ force: true }).then(function() {
return self.queryInterface.describeTable('_Users', {logging: log}).then(function(metadata) { return self.queryInterface.describeTable('_Users').then(function(metadata) {
expect(count).to.be.at.least(1);
count = 0;
var id = metadata.id; var id = metadata.id;
var username = metadata.username; var username = metadata.username;
var city = metadata.city; var city = metadata.city;
...@@ -225,6 +200,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -225,6 +200,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
}); });
}); });
// FIXME: These tests should make assertions against the created table using describeTable
describe('createTable', function() { describe('createTable', function() {
it('should create a auto increment primary key', function() { it('should create a auto increment primary key', function() {
return this.queryInterface.createTable('TableWithPK', { return this.queryInterface.createTable('TableWithPK', {
...@@ -267,16 +243,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -267,16 +243,7 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
it('should work with schemas', function() { it('should work with schemas', function() {
var self = this; var self = this;
return self.sequelize.dropAllSchemas({logging: log}).then(function() { return self.sequelize.createSchema('hero').then(function() {
// TODO: FIXME: somehow these do not fire the logging function
if (dialect !== 'mysql' && dialect !== 'sqlite' && dialect !== 'mariadb') {
expect(count).to.be.above(0);
}
count = 0;
return self.sequelize.createSchema('hero', {logging: log});
}).then(function() {
expect(count).to.be.equal(1);
count = 0;
return self.queryInterface.createTable('User', { return self.queryInterface.createTable('User', {
name: { name: {
type: DataTypes.STRING type: DataTypes.STRING
...@@ -284,14 +251,6 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -284,14 +251,6 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
}, { }, {
schema: 'hero' schema: 'hero'
}); });
}).then(function() {
return self.queryInterface.rawSelect('User', {
schema: 'hero',
logging: log
}, 'name');
}).then(function() {
expect(count).to.be.equal(1);
count = 0;
}); });
}); });
}); });
...@@ -304,33 +263,38 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -304,33 +263,38 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
}, { freezeTableName: true }); }, { freezeTableName: true });
return Users.sync({ force: true }).then(function() { return Users.sync({ force: true }).then(function() {
return self.queryInterface.renameColumn('_Users', 'username', 'pseudo', {logging: log}).then(function() { return self.queryInterface.renameColumn('_Users', 'username', 'pseudo');
if (dialect === 'sqlite') }).bind(this).then(function() {
count++; return this.queryInterface.describeTable('_Users');
expect(count).to.be.equal(2); }).then(function (table) {
count = 0; expect(table).to.have.property('pseudo');
}); expect(table).to.not.have.property('username');
}); });
}); });
it('works with schemas', function() { it('works with schemas', function() {
var self = this; var self = this;
var Users = self.sequelize.define('User', { return self.sequelize.createSchema('archive').then(function() {
username: DataTypes.STRING var Users = self.sequelize.define('User', {
}, { username: DataTypes.STRING
tableName: 'Users', }, {
schema: 'archive' tableName: 'Users',
}); schema: 'archive'
});
return self.sequelize.dropAllSchemas().then(function() {
return self.sequelize.createSchema('archive');
}).then(function() {
return Users.sync({ force: true }).then(function() { return Users.sync({ force: true }).then(function() {
return self.queryInterface.renameColumn({ return self.queryInterface.renameColumn({
schema: 'archive', schema: 'archive',
tableName: 'Users' tableName: 'Users'
}, 'username', 'pseudo'); }, 'username', 'pseudo');
}); });
}).bind(this).then(function() {
return this.queryInterface.describeTable({
schema: 'archive',
tableName: 'Users'
});
}).then(function (table) {
expect(table).to.have.property('pseudo');
expect(table).to.not.have.property('username');
}); });
}); });
...@@ -345,6 +309,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -345,6 +309,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
return Users.sync({ force: true }).then(function() { return Users.sync({ force: true }).then(function() {
return self.queryInterface.renameColumn('_Users', 'username', 'pseudo'); return self.queryInterface.renameColumn('_Users', 'username', 'pseudo');
}).bind(this).then(function() {
return this.queryInterface.describeTable('_Users');
}).then(function (table) {
expect(table).to.have.property('pseudo');
expect(table).to.not.have.property('username');
}); });
}); });
...@@ -360,6 +329,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -360,6 +329,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
return Users.sync({ force: true }).then(function() { return Users.sync({ force: true }).then(function() {
return self.queryInterface.renameColumn('_Users', 'active', 'enabled'); return self.queryInterface.renameColumn('_Users', 'active', 'enabled');
}).bind(this).then(function() {
return this.queryInterface.describeTable('_Users');
}).then(function (table) {
expect(table).to.have.property('enabled');
expect(table).to.not.have.property('active');
}); });
}); });
...@@ -376,15 +350,18 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -376,15 +350,18 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
return Fruits.sync({ force: true }).then(function() { return Fruits.sync({ force: true }).then(function() {
return self.queryInterface.renameColumn('Fruit', 'fruitId', 'fruit_id'); return self.queryInterface.renameColumn('Fruit', 'fruitId', 'fruit_id');
}).bind(this).then(function() {
return this.queryInterface.describeTable('Fruit');
}).then(function (table) {
expect(table).to.have.property('fruit_id');
expect(table).to.not.have.property('fruitId');
}); });
}); });
}); });
describe('changeColumn', function() { describe('changeColumn', function() {
it('should support schemas', function() { it('should support schemas', function() {
return this.sequelize.dropAllSchemas().bind(this).then(function() { return this.sequelize.createSchema('archive').bind(this).then(function() {
return this.sequelize.createSchema('archive');
}).then(function() {
return this.queryInterface.createTable({ return this.queryInterface.createTable({
tableName: 'users', tableName: 'users',
schema: 'archive' schema: 'archive'
...@@ -401,19 +378,25 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -401,19 +378,25 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
schema: 'archive' schema: 'archive'
}, 'currency', { }, 'currency', {
type: DataTypes.FLOAT type: DataTypes.FLOAT
}, {
logging: log
}).then(function() {
expect(count).to.be.equal(1);
count = 0;
}); });
}).then(function() {
return this.queryInterface.describeTable({
tableName: 'users',
schema: 'archive'
});
}).then(function (table) {
if (dialect === 'postgres' || dialect === 'postgres-native') {
expect(table.currency.type).to.equal('DOUBLE PRECISION');
} else {
expect(table.currency.type).to.equal('FLOAT');
}
}); });
}); });
}); });
it('should change columns', function() { it('should change columns', function() {
return this.queryInterface.createTable({ return this.queryInterface.createTable({
tableName: 'users', tableName: 'users'
}, { }, {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
...@@ -425,13 +408,19 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -425,13 +408,19 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
return this.queryInterface.changeColumn('users', 'currency', { return this.queryInterface.changeColumn('users', 'currency', {
type: DataTypes.FLOAT, type: DataTypes.FLOAT,
allowNull: true allowNull: true
}, {
logging: log
}).then(function() {
expect(count).to.be.equal(1);
count = 0;
}); });
}).then(function() {
return this.queryInterface.describeTable({
tableName: 'users'
});
}).then(function (table) {
if (dialect === 'postgres' || dialect === 'postgres-native') {
expect(table.currency.type).to.equal('DOUBLE PRECISION');
} else {
expect(table.currency.type).to.equal('FLOAT');
}
}); });
});
}); });
//SQlite navitely doesnt support ALTER Foreign key //SQlite navitely doesnt support ALTER Foreign key
...@@ -477,16 +466,17 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -477,16 +466,17 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
}); });
} }
});
describe('addColumn', function() { describe('addColumn', function() {
beforeEach(function() { beforeEach(function() {
return this.queryInterface.createTable('users', { return this.sequelize.createSchema('archive').bind(this).then(function() {
id: { return this.queryInterface.createTable('users', {
type: DataTypes.INTEGER, id: {
primaryKey: true, type: DataTypes.INTEGER,
autoIncrement: true primaryKey: true,
} autoIncrement: true
}
});
}); });
}); });
...@@ -506,10 +496,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -506,10 +496,11 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
}, },
onUpdate: 'cascade', onUpdate: 'cascade',
onDelete: 'set null' onDelete: 'set null'
}, {logging: log}); });
}).then(function() { }).then(function() {
expect(count).to.be.equal(1); return this.queryInterface.describeTable('users');
count = 0; }).then(function (table) {
expect(table).to.have.property('level_id');
}); });
}); });
...@@ -529,6 +520,13 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -529,6 +520,13 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
schema: 'archive' schema: 'archive'
}, 'level_id', { }, 'level_id', {
type: DataTypes.INTEGER type: DataTypes.INTEGER
}).bind(this).then(function() {
return this.queryInterface.describeTable({
tableName: 'users',
schema: 'archive'
});
}).then(function (table) {
expect(table).to.have.property('level_id');
}); });
}); });
}); });
...@@ -545,6 +543,97 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -545,6 +543,97 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
}); });
}); });
describe('removeColumn', function() {
describe('(without a schema)', function() {
beforeEach(function() {
return this.queryInterface.createTable('users', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstName: {
type: DataTypes.STRING,
defaultValue: 'Someone'
},
lastName: {
type: DataTypes.STRING
}
});
});
it('should be able to remove a column with a default value', function() {
return this.queryInterface.removeColumn('users', 'firstName').bind(this).then(function() {
return this.queryInterface.describeTable('users');
}).then(function(table) {
expect(table).to.not.have.property('firstName');
});
});
it('should be able to remove a column without default value', function() {
return this.queryInterface.removeColumn('users', 'lastName').bind(this).then(function() {
return this.queryInterface.describeTable('users');
}).then(function(table) {
expect(table).to.not.have.property('lastName');
});
});
});
describe('(with a schema)', function() {
beforeEach(function() {
return this.sequelize.createSchema('archive').bind(this).then(function() {
return this.queryInterface.createTable({
tableName: 'users',
schema: 'archive'
}, {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstName: {
type: DataTypes.STRING,
defaultValue: 'Someone'
},
lastName: {
type: DataTypes.STRING
}
});
});
});
it('should be able to remove a column with a default value', function() {
return this.queryInterface.removeColumn({
tableName: 'users',
schema: 'archive'
}, 'firstName'
).bind(this).then(function() {
return this.queryInterface.describeTable({
tableName: 'users',
schema: 'archive'
});
}).then(function(table) {
expect(table).to.not.have.property('firstName');
});
});
it('should be able to remove a column without default value', function() {
return this.queryInterface.removeColumn({
tableName: 'users',
schema: 'archive'
}, 'lastName'
).bind(this).then(function() {
return this.queryInterface.describeTable({
tableName: 'users',
schema: 'archive'
});
}).then(function(table) {
expect(table).to.not.have.property('lastName');
});
});
});
});
describe('describeForeignKeys', function() { describe('describeForeignKeys', function() {
beforeEach(function() { beforeEach(function() {
return this.queryInterface.createTable('users', { return this.queryInterface.createTable('users', {
...@@ -591,10 +680,8 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() { ...@@ -591,10 +680,8 @@ describe(Support.getTestDialectTeaser('QueryInterface'), function() {
it('should get a list of foreign keys for the table', function() { it('should get a list of foreign keys for the table', function() {
var sql = this.queryInterface.QueryGenerator.getForeignKeysQuery('hosts', this.sequelize.config.database); var sql = this.queryInterface.QueryGenerator.getForeignKeysQuery('hosts', this.sequelize.config.database);
return this.sequelize.query(sql, {type: this.sequelize.QueryTypes.FOREIGNKEYS, logging: log}).then(function(fks) { return this.sequelize.query(sql, {type: this.sequelize.QueryTypes.FOREIGNKEYS}).then(function(fks) {
expect(count).to.be.equal(1);
expect(fks).to.have.length(3); expect(fks).to.have.length(3);
count = 0;
var keys = Object.keys(fks[0]), var keys = Object.keys(fks[0]),
keys2 = Object.keys(fks[1]), keys2 = Object.keys(fks[1]),
keys3 = Object.keys(fks[2]); keys3 = Object.keys(fks[2]);
......
'use strict';
/* jshint -W110 */
var Support = require(__dirname + '/../../support')
, expectsql = Support.expectsql
, current = Support.sequelize
, QueryGenerator = require('../../../../lib/dialects/mssql/query-generator');
if (current.dialect.name === 'mssql') {
suite('[MSSQL Specific] QueryGenerator', function () {
// Dialect would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
QueryGenerator._dialect = current.dialect;
test('getDefaultConstraintQuery', function () {
expectsql(QueryGenerator.getDefaultConstraintQuery({tableName: 'myTable', schema: 'mySchema'}, 'myColumn'), {
mssql: "SELECT name FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('[mySchema].[myTable]', 'U') AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns WHERE NAME = ('myColumn') AND object_id = OBJECT_ID('[mySchema].[myTable]', 'U'));"
});
});
test('dropConstraintQuery', function () {
expectsql(QueryGenerator.dropConstraintQuery({tableName: 'myTable', schema: 'mySchema'}, 'myConstraint'), {
mssql: "ALTER TABLE [mySchema].[myTable] DROP CONSTRAINT [myConstraint];"
});
});
});
}
...@@ -13,17 +13,6 @@ var chai = require('chai') ...@@ -13,17 +13,6 @@ var chai = require('chai')
if (dialect.match(/^postgres/)) { if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] QueryGenerator', function() { describe('[POSTGRES Specific] QueryGenerator', function() {
beforeEach(function() {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
email: { type: DataTypes.ARRAY(DataTypes.TEXT) },
numbers: { type: DataTypes.ARRAY(DataTypes.FLOAT) },
document: { type: DataTypes.HSTORE, defaultValue: { default: '"value"' } }
});
return this.User.sync({ force: true });
});
var suites = { var suites = {
attributesToSQL: [ attributesToSQL: [
{ {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!