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

Commit fd1ace03 by Jan Aagaard Meier

Changes to raw query handling

1 parent edb18238
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
- [FEATURE] Validations are now enabled by default for upsert. - [FEATURE] Validations are now enabled by default for upsert.
- [FEATURE] Preliminary support for `include.through.where` - [FEATURE] Preliminary support for `include.through.where`
- [SECURITY/BUG] Fixed injection issue in direction param for order - [SECURITY/BUG] Fixed injection issue in direction param for order
- [FEATURE/BUG] Raw queries always return all results (including affected rows etc).
# 2.0.0-rc7 # 2.0.0-rc7
- [FEATURE] Throw an error if no where clause is given to `Model.destroy()`. - [FEATURE] Throw an error if no where clause is given to `Model.destroy()`.
......
...@@ -83,6 +83,10 @@ module.exports = (function() { ...@@ -83,6 +83,10 @@ module.exports = (function() {
} }
}; };
AbstractQuery.prototype.isRawQuery = function () {
return this.options.type === QueryTypes.RAW;
};
AbstractQuery.prototype.isVersionQuery = function () { AbstractQuery.prototype.isVersionQuery = function () {
return this.options.type === QueryTypes.VERSION; return this.options.type === QueryTypes.VERSION;
}; };
...@@ -150,6 +154,10 @@ module.exports = (function() { ...@@ -150,6 +154,10 @@ module.exports = (function() {
}; };
AbstractQuery.prototype.isUpdateQuery = function() { AbstractQuery.prototype.isUpdateQuery = function() {
if (this.options.type === QueryTypes.UPDATE) {
return true;
}
return (this.sql.toLowerCase().indexOf('update') === 0); return (this.sql.toLowerCase().indexOf('update') === 0);
}; };
......
...@@ -98,6 +98,9 @@ module.exports = (function() { ...@@ -98,6 +98,9 @@ module.exports = (function() {
result = data.affectedRows; result = data.affectedRows;
} else if (this.isVersionQuery()) { } else if (this.isVersionQuery()) {
result = data[0].version; result = data[0].version;
} else if (this.isRawQuery()) {
// MySQL returns row data and metadata (affected rows etc) in a single object - let's standarize it, sorta
result = [data, data];
} }
return result; return result;
......
...@@ -243,6 +243,8 @@ module.exports = (function() { ...@@ -243,6 +243,8 @@ module.exports = (function() {
return self.callee || (rows && ((self.options.plain && rows[0]) || rows)) || undefined; return self.callee || (rows && ((self.options.plain && rows[0]) || rows)) || undefined;
} else if (self.isVersionQuery()) { } else if (self.isVersionQuery()) {
return results[0].version; return results[0].version;
} else if (self.isRawQuery()) {
return [rows, result];
} else { } else {
return results; return results;
} }
......
...@@ -139,6 +139,8 @@ module.exports = (function() { ...@@ -139,6 +139,8 @@ module.exports = (function() {
result = undefined; result = undefined;
} else if (self.options.type === QueryTypes.VERSION) { } else if (self.options.type === QueryTypes.VERSION) {
result = results[0].version; result = results[0].version;
} else if (self.options.type === QueryTypes.RAW) {
result = [results, metaData];
} }
resolve(result); resolve(result);
......
...@@ -831,7 +831,7 @@ module.exports = (function() { ...@@ -831,7 +831,7 @@ module.exports = (function() {
* @param {Integer} [options.by=1] The number to increment by * @param {Integer} [options.by=1] The number to increment by
* @param {Transaction} [options.transaction] * @param {Transaction} [options.transaction]
* *
* @return {Promise} * @return {Promise<this>}
*/ */
Instance.prototype.increment = function(fields, countOrOptions) { Instance.prototype.increment = function(fields, countOrOptions) {
Utils.validateParameter(countOrOptions, Object, { Utils.validateParameter(countOrOptions, Object, {
...@@ -895,7 +895,7 @@ module.exports = (function() { ...@@ -895,7 +895,7 @@ module.exports = (function() {
} }
}, this); }, this);
return this.QueryInterface.increment(this, this.Model.getTableName(countOrOptions), values, where, countOrOptions); return this.QueryInterface.increment(this, this.Model.getTableName(countOrOptions), values, where, countOrOptions).return(this);
}; };
/** /**
......
...@@ -725,7 +725,6 @@ module.exports = (function() { ...@@ -725,7 +725,6 @@ module.exports = (function() {
} }
}).then(function() { }).then(function() {
return this.QueryInterface.select(this, this.getTableName(options), options, Utils._.defaults({ return this.QueryInterface.select(this, this.getTableName(options), options, Utils._.defaults({
type: QueryTypes.SELECT,
hasJoin: hasJoin, hasJoin: hasJoin,
tableNames: Object.keys(tableNames) tableNames: Object.keys(tableNames)
}, queryOptions, { transaction: options.transaction })); }, queryOptions, { transaction: options.transaction }));
...@@ -743,9 +742,7 @@ module.exports = (function() { ...@@ -743,9 +742,7 @@ module.exports = (function() {
// whereCollection is used for non-primary key updates // whereCollection is used for non-primary key updates
this.options.whereCollection = options.where || null; this.options.whereCollection = options.where || null;
return this.QueryInterface.select(this, [[this.getTableName(options), this.name], joinTableName], options, Utils._.defaults({ return this.QueryInterface.select(this, [[this.getTableName(options), this.name], joinTableName], options, Utils._.defaults(queryOptions, { transaction: (options || {}).transaction }));
type: QueryTypes.SELECT
}, queryOptions, { transaction: (options || {}).transaction }));
}; };
/** /**
...@@ -1449,7 +1446,6 @@ module.exports = (function() { ...@@ -1449,7 +1446,6 @@ module.exports = (function() {
options.type = QueryTypes.BULKDELETE; options.type = QueryTypes.BULKDELETE;
mapFieldNames.call(this, options, this); mapFieldNames.call(this, options, this);
return Promise.try(function() { return Promise.try(function() {
......
...@@ -443,7 +443,7 @@ module.exports = (function() { ...@@ -443,7 +443,7 @@ module.exports = (function() {
} }
return Utils.Promise.map(tableNames, function(tableName) { return Utils.Promise.map(tableNames, function(tableName) {
return self.sequelize.query(self.QueryGenerator.getForeignKeysQuery(tableName, self.sequelize.config.database)); return self.sequelize.query(self.QueryGenerator.getForeignKeysQuery(tableName, self.sequelize.config.database)).get(0);
}).then(function(results) { }).then(function(results) {
var result = {}; var result = {};
...@@ -556,6 +556,9 @@ module.exports = (function() { ...@@ -556,6 +556,9 @@ module.exports = (function() {
, restrict = false , restrict = false
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier, options, dao.Model.rawAttributes); , sql = self.QueryGenerator.updateQuery(tableName, values, identifier, options, dao.Model.rawAttributes);
options = options || {};
options.type = QueryTypes.UPDATE;
// Check for a restrict field // Check for a restrict field
if (!!dao.Model && !!dao.Model.associations) { if (!!dao.Model && !!dao.Model.associations) {
var keys = Object.keys(dao.Model.associations) var keys = Object.keys(dao.Model.associations)
...@@ -689,13 +692,14 @@ module.exports = (function() { ...@@ -689,13 +692,14 @@ module.exports = (function() {
var sql = this.QueryGenerator.selectQuery(tableName, options, model); var sql = this.QueryGenerator.selectQuery(tableName, options, model);
queryOptions = Utils._.extend({}, queryOptions, { queryOptions = Utils._.extend({}, queryOptions, {
type: QueryTypes.SELECT,
include: options.include, include: options.include,
includeNames: options.includeNames, includeNames: options.includeNames,
includeMap: options.includeMap, includeMap: options.includeMap,
hasSingleAssociation: options.hasSingleAssociation, hasSingleAssociation: options.hasSingleAssociation,
hasMultiAssociation: options.hasMultiAssociation, hasMultiAssociation: options.hasMultiAssociation,
attributes: options.attributes, attributes: options.attributes,
originalAttributes: options.originalAttributes originalAttributes: options.originalAttributes,
}); });
return this.sequelize.query(sql, model, queryOptions); return this.sequelize.query(sql, model, queryOptions);
......
...@@ -3,10 +3,12 @@ ...@@ -3,10 +3,12 @@
module.exports = { module.exports = {
SELECT: 'SELECT', SELECT: 'SELECT',
INSERT: 'INSERT', INSERT: 'INSERT',
UPDATE: 'UPDATE',
BULKUPDATE: 'BULKUPDATE', BULKUPDATE: 'BULKUPDATE',
BULKDELETE: 'BULKDELETE', BULKDELETE: 'BULKDELETE',
UPSERT: 'UPSERT', UPSERT: 'UPSERT',
VERSION: 'VERSION', VERSION: 'VERSION',
SHOWTABLES: 'SHOWTABLES', SHOWTABLES: 'SHOWTABLES',
SHOWINDEXES: 'SHOWINDEXES' SHOWINDEXES: 'SHOWINDEXES',
RAW: 'RAW',
}; };
...@@ -660,7 +660,7 @@ module.exports = (function() { ...@@ -660,7 +660,7 @@ module.exports = (function() {
options = Utils._.extend(Utils._.clone(this.options.query), options); options = Utils._.extend(Utils._.clone(this.options.query), options);
options = Utils._.defaults(options, { options = Utils._.defaults(options, {
logging: this.options.hasOwnProperty('logging') ? this.options.logging : console.log, logging: this.options.hasOwnProperty('logging') ? this.options.logging : console.log,
type: (sql.toLowerCase().indexOf('select') === 0) ? QueryTypes.SELECT : false type: QueryTypes.RAW
}); });
if (options.transaction === undefined && Sequelize.cls) { if (options.transaction === undefined && Sequelize.cls) {
......
...@@ -18,7 +18,7 @@ chai.use(datetime); ...@@ -18,7 +18,7 @@ chai.use(datetime);
chai.config.includeStack = true; chai.config.includeStack = true;
describe(Support.getTestDialectTeaser('Model'), function() { describe(Support.getTestDialectTeaser('Model'), function() {
beforeEach(function(done) { beforeEach(function() {
this.User = this.sequelize.define('User', { this.User = this.sequelize.define('User', {
username: DataTypes.STRING, username: DataTypes.STRING,
secretValue: DataTypes.STRING, secretValue: DataTypes.STRING,
...@@ -28,25 +28,21 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -28,25 +28,21 @@ describe(Support.getTestDialectTeaser('Model'), function() {
aBool: DataTypes.BOOLEAN aBool: DataTypes.BOOLEAN
}); });
this.User.sync({ force: true }).success(function() { return this.User.sync({ force: true });
done();
});
}); });
describe('constructor', function() { describe('constructor', function() {
it('uses the passed dao name as tablename if freezeTableName', function(done) { it('uses the passed dao name as tablename if freezeTableName', function() {
var User = this.sequelize.define('FrozenUser', {}, { freezeTableName: true }); var User = this.sequelize.define('FrozenUser', {}, { freezeTableName: true });
expect(User.tableName).to.equal('FrozenUser'); expect(User.tableName).to.equal('FrozenUser');
done();
}); });
it('uses the pluralized dao name as tablename unless freezeTableName', function(done) { it('uses the pluralized dao name as tablename unless freezeTableName', function() {
var User = this.sequelize.define('SuperUser', {}, { freezeTableName: false }); var User = this.sequelize.define('SuperUser', {}, { freezeTableName: false });
expect(User.tableName).to.equal('SuperUsers'); expect(User.tableName).to.equal('SuperUsers');
done();
}); });
it('uses checks to make sure dao factory isnt leaking on multiple define', function(done) { it('uses checks to make sure dao factory isnt leaking on multiple define', function() {
this.sequelize.define('SuperUser', {}, { freezeTableName: false }); this.sequelize.define('SuperUser', {}, { freezeTableName: false });
var factorySize = this.sequelize.daoFactoryManager.all.length; var factorySize = this.sequelize.daoFactoryManager.all.length;
...@@ -54,10 +50,9 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -54,10 +50,9 @@ describe(Support.getTestDialectTeaser('Model'), function() {
var factorySize2 = this.sequelize.daoFactoryManager.all.length; var factorySize2 = this.sequelize.daoFactoryManager.all.length;
expect(factorySize).to.equal(factorySize2); expect(factorySize).to.equal(factorySize2);
done();
}); });
it('attaches class and instance methods', function(done) { it('attaches class and instance methods', function() {
var User = this.sequelize.define('UserWithClassAndInstanceMethods', {}, { var User = this.sequelize.define('UserWithClassAndInstanceMethods', {}, {
classMethods: { doSmth: function() { return 1; } }, classMethods: { doSmth: function() { return 1; } },
instanceMethods: { makeItSo: function() { return 2; } } instanceMethods: { makeItSo: function() { return 2; } }
...@@ -70,10 +65,9 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -70,10 +65,9 @@ describe(Support.getTestDialectTeaser('Model'), function() {
expect(User.build().doSmth).not.to.exist; expect(User.build().doSmth).not.to.exist;
expect(User.build().makeItSo).to.exist; expect(User.build().makeItSo).to.exist;
expect(User.build().makeItSo()).to.equal(2); expect(User.build().makeItSo()).to.equal(2);
done();
}); });
it('allows us us to predefine the ID column with our own specs', function(done) { it('allows us us to predefine the ID column with our own specs', function() {
var User = this.sequelize.define('UserCol', { var User = this.sequelize.define('UserCol', {
id: { id: {
type: Sequelize.STRING, type: Sequelize.STRING,
...@@ -82,15 +76,12 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -82,15 +76,12 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} }
}); });
User.sync({ force: true }).success(function() { return User.sync({ force: true }).then(function() {
User.create({id: 'My own ID!'}).success(function(user) { return expect(User.create({id: 'My own ID!'})).to.eventually.have.property('id', 'My own ID!');
expect(user.id).to.equal('My own ID!');
done();
});
}); });
}); });
it('throws an error if 2 autoIncrements are passed', function(done) { it('throws an error if 2 autoIncrements are passed', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.define('UserWithTwoAutoIncrements', { self.sequelize.define('UserWithTwoAutoIncrements', {
...@@ -98,10 +89,9 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -98,10 +89,9 @@ describe(Support.getTestDialectTeaser('Model'), function() {
userscore: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true } userscore: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }
}); });
}).to.throw(Error, 'Invalid Instance definition. Only one autoincrement field allowed.'); }).to.throw(Error, 'Invalid Instance definition. Only one autoincrement field allowed.');
done();
}); });
it('throws an error if a custom model-wide validation is not a function', function(done) { it('throws an error if a custom model-wide validation is not a function', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.define('Foo', { self.sequelize.define('Foo', {
...@@ -112,10 +102,9 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -112,10 +102,9 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} }
}); });
}).to.throw(Error, 'Members of the validate option must be functions. Model: Foo, error with validate member notFunction'); }).to.throw(Error, 'Members of the validate option must be functions. Model: Foo, error with validate member notFunction');
done();
}); });
it('throws an error if a custom model-wide validation has the same name as a field', function(done) { it('throws an error if a custom model-wide validation has the same name as a field', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.define('Foo', { self.sequelize.define('Foo', {
...@@ -126,7 +115,6 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -126,7 +115,6 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} }
}); });
}).to.throw(Error, 'A model validator function must not have the same name as a field. Model: Foo, field/validation name: field'); }).to.throw(Error, 'A model validator function must not have the same name as a field. Model: Foo, field/validation name: field');
done();
}); });
it('should allow me to set a default value for createdAt and updatedAt', function(done) { it('should allow me to set a default value for createdAt and updatedAt', function(done) {
...@@ -1239,8 +1227,9 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1239,8 +1227,9 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
it('sets deletedAt to the current timestamp if paranoid is true', function(done) { it('sets deletedAt to the current timestamp if paranoid is true', function() {
var self = this var self = this
, qi = this.sequelize.queryInterface.QueryGenerator.quoteIdentifier
, ParanoidUser = self.sequelize.define('ParanoidUser', { , ParanoidUser = self.sequelize.define('ParanoidUser', {
username: Sequelize.STRING, username: Sequelize.STRING,
secretValue: Sequelize.STRING, secretValue: Sequelize.STRING,
...@@ -1253,26 +1242,25 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1253,26 +1242,25 @@ describe(Support.getTestDialectTeaser('Model'), function() {
{ username: 'Paul', secretValue: '42' }, { username: 'Paul', secretValue: '42' },
{ username: 'Bob', secretValue: '43' }]; { username: 'Bob', secretValue: '43' }];
ParanoidUser.sync({ force: true }).success(function() { return ParanoidUser.sync({ force: true }).then(function() {
ParanoidUser.bulkCreate(data).success(function() { return ParanoidUser.bulkCreate(data);
}).bind({}).then(function() {
// since we save in UTC, let's format to UTC time // since we save in UTC, let's format to UTC time
var date = moment().utc().format('YYYY-MM-DD h:mm'); this.date = moment().utc().format('YYYY-MM-DD h:mm');
ParanoidUser.destroy({where: {secretValue: '42'}}).success(function() { return ParanoidUser.destroy({where: {secretValue: '42'}});
ParanoidUser.findAll({order: 'id'}).success(function(users) { }).then(function() {
return ParanoidUser.findAll({order: 'id'});
}).then(function(users) {
expect(users.length).to.equal(1); expect(users.length).to.equal(1);
expect(users[0].username).to.equal('Bob'); expect(users[0].username).to.equal('Bob');
self.sequelize.query('SELECT * FROM ' + self.sequelize.queryInterface.QueryGenerator.quoteIdentifier('ParanoidUsers') + ' WHERE ' + self.sequelize.queryInterface.QueryGenerator.quoteIdentifier('deletedAt') + ' IS NOT NULL ORDER BY ' + self.sequelize.queryInterface.QueryGenerator.quoteIdentifier('id'), null, {raw: true}).success(function(users) { return self.sequelize.query('SELECT * FROM ' + qi('ParanoidUsers') + ' WHERE ' + qi('deletedAt') + ' IS NOT NULL ORDER BY ' + qi('id'));
}).spread(function(users) {
expect(users[0].username).to.equal('Peter'); expect(users[0].username).to.equal('Peter');
expect(users[1].username).to.equal('Paul'); expect(users[1].username).to.equal('Paul');
expect(moment(new Date(users[0].deletedAt)).utc().format('YYYY-MM-DD h:mm')).to.equal(date); expect(moment(new Date(users[0].deletedAt)).utc().format('YYYY-MM-DD h:mm')).to.equal(this.date);
expect(moment(new Date(users[1].deletedAt)).utc().format('YYYY-MM-DD h:mm')).to.equal(date); expect(moment(new Date(users[1].deletedAt)).utc().format('YYYY-MM-DD h:mm')).to.equal(this.date);
done();
});
});
});
});
}); });
}); });
...@@ -1381,46 +1369,44 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1381,46 +1369,44 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
it('should delete a paranoid record if I set force to true', function(done) { it('should delete a paranoid record if I set force to true', function() {
var self = this; var self = this;
var User = this.sequelize.define('paranoiduser', { var User = this.sequelize.define('paranoiduser', {
username: Sequelize.STRING username: Sequelize.STRING
}, { paranoid: true }); }, { paranoid: true });
User.sync({ force: true }).success(function() { return User.sync({ force: true }).then(function() {
User.bulkCreate([ return User.bulkCreate([
{username: 'Bob'}, {username: 'Bob'},
{username: 'Tobi'}, {username: 'Tobi'},
{username: 'Max'}, {username: 'Max'},
{username: 'Tony'} {username: 'Tony'}
]).success(function() { ]);
User.find({where: {username: 'Bob'}}).success(function(user) { }).then(function() {
user.destroy({force: true}).success(function() { return User.find({where: {username: 'Bob'}});
User.find({where: {username: 'Bob'}}).success(function(user) { }).then(function(user) {
expect(user).to.be.null; return user.destroy({force: true});
User.find({where: {username: 'Tobi'}}).success(function(tobi) { }).then(function() {
tobi.destroy().success(function() { return expect(User.find({where: {username: 'Bob'}})).to.eventually.be.null;
self.sequelize.query('SELECT * FROM paranoidusers WHERE username=\'Tobi\'', null, {raw: true, plain: true}).success(function(result) { }).then(function(user) {
expect(result.username).to.equal('Tobi'); return User.find({where: {username: 'Tobi'}});
User.destroy({where: {username: 'Tony'}}).success(function() { }).then(function(tobi) {
self.sequelize.query('SELECT * FROM paranoidusers WHERE username=\'Tony\'', null, {raw: true, plain: true}).success(function(result) { return tobi.destroy();
expect(result.username).to.equal('Tony'); }).then(function() {
User.destroy({where: {username: ['Tony', 'Max']}, force: true}).success(function() { return self.sequelize.query('SELECT * FROM paranoidusers WHERE username=\'Tobi\'');
self.sequelize.query('SELECT * FROM paranoidusers', null, {raw: true}).success(function(users) { }).spread(function(result) {
expect(result[0].username).to.equal('Tobi');
return User.destroy({where: {username: 'Tony'}});
}).then(function() {
return self.sequelize.query('SELECT * FROM paranoidusers WHERE username=\'Tony\'');
}).spread(function(result) {
expect(result[0].username).to.equal('Tony');
return User.destroy({where: {username: ['Tony', 'Max']}, force: true});
}).spread(function() {
return self.sequelize.query('SELECT * FROM paranoidusers', null, {raw: true});
}).then(function(users) {
expect(users).to.have.length(1); expect(users).to.have.length(1);
expect(users[0].username).to.equal('Tobi'); expect(users[0].username).to.equal('Tobi');
done();
});
});
});
});
});
});
});
});
});
});
});
}); });
}); });
......
...@@ -1300,7 +1300,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1300,7 +1300,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
it('sorts the results via a date column', function(done) { it('sorts the results via a date column', function(done) {
var self = this; var self = this;
self.User.create({username: 'user3', data: 'bar', theDate: moment().add('hours', 2).toDate()}).success(function() { self.User.create({username: 'user3', data: 'bar', theDate: moment().add(2, 'hours').toDate()}).success(function() {
self.User.findAll({ order: [['theDate', 'DESC']] }).success(function(users) { self.User.findAll({ order: [['theDate', 'DESC']] }).success(function(users) {
expect(users[0].id).to.be.above(users[2].id); expect(users[0].id).to.be.above(users[2].id);
done(); done();
......
...@@ -246,61 +246,46 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -246,61 +246,46 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
}); });
}); });
it('executes select queries correctly', function(done) { it('executes select queries correctly', function() {
var self = this; var self = this;
self.sequelize.query(this.insertQuery).success(function() { return self.sequelize.query(this.insertQuery).then(function() {
self.sequelize return self.sequelize.query('select * from ' + qq(self.User.tableName) + '');
.query('select * from ' + qq(self.User.tableName) + '') }).spread(function(users) {
.complete(function(err, users) {
expect(err).to.be.null;
expect(users.map(function(u) { return u.username; })).to.include('john'); expect(users.map(function(u) { return u.username; })).to.include('john');
done();
});
}); });
}); });
it('executes select queries correctly when quoteIdentifiers is false', function(done) { it('executes select queries correctly when quoteIdentifiers is false', function() {
var self = this var self = this
, seq = Object.create(self.sequelize); , seq = Object.create(self.sequelize);
seq.options.quoteIdentifiers = false; seq.options.quoteIdentifiers = false;
seq.query(this.insertQuery).success(function() { return seq.query(this.insertQuery).then(function() {
seq.query('select * from ' + qq(self.User.tableName) + '') return seq.query('select * from ' + qq(self.User.tableName) + '');
.complete(function(err, users) { }).spread(function(users) {
expect(err).to.be.null;
expect(users.map(function(u) { return u.username; })).to.include('john'); expect(users.map(function(u) { return u.username; })).to.include('john');
done();
});
}); });
}); });
it('executes select query with dot notation results', function(done) { it('executes select query with dot notation results', function() {
var self = this; var self = this;
self.sequelize.query('DELETE FROM ' + qq(self.User.tableName)).complete(function() { return self.sequelize.query('DELETE FROM ' + qq(self.User.tableName)).then(function() {
self.sequelize.query(self.insertQuery).success(function() { return self.sequelize.query(self.insertQuery);
self.sequelize }).then(function() {
.query('select username as ' + qq('user.username') + ' from ' + qq(self.User.tableName) + '') return self.sequelize.query('select username as ' + qq('user.username') + ' from ' + qq(self.User.tableName) + '');
.complete(function(err, users) { }).spread(function( users) {
expect(err).to.be.null;
expect(users).to.deep.equal([{'user.username': 'john'}]); expect(users).to.deep.equal([{'user.username': 'john'}]);
done();
});
});
}); });
}); });
it('executes select query with dot notation results and nest it', function(done) { it('executes select query with dot notation results and nest it', function() {
var self = this; var self = this;
self.sequelize.query('DELETE FROM ' + qq(self.User.tableName)).complete(function() { return self.sequelize.query('DELETE FROM ' + qq(self.User.tableName)).then(function() {
self.sequelize.query(self.insertQuery).success(function() { return self.sequelize.query(self.insertQuery);
self.sequelize }).then(function() {
.query('select username as ' + qq('user.username') + ' from ' + qq(self.User.tableName) + '', null, { raw: true, nest: true }) return self.sequelize.query('select username as ' + qq('user.username') + ' from ' + qq(self.User.tableName) + '', null, { raw: true, nest: true });
.complete(function(err, users) { }).spread(function(users) {
expect(err).to.be.null;
expect(users.map(function(u) { return u.user; })).to.deep.equal([{'username': 'john'}]); expect(users.map(function(u) { return u.user; })).to.deep.equal([{'username': 'john'}]);
done();
});
});
}); });
}); });
...@@ -334,14 +319,11 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -334,14 +319,11 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
}); });
}); });
it('dot separated attributes when doing a raw query without nest', function(done) { it('dot separated attributes when doing a raw query without nest', function() {
var tickChar = (dialect === 'postgres' || dialect === 'mssql') ? '"' : '`' var tickChar = (dialect === 'postgres' || dialect === 'mssql') ? '"' : '`'
, sql = 'select 1 as ' + Sequelize.Utils.addTicks('foo.bar.baz', tickChar); , sql = 'select 1 as ' + Sequelize.Utils.addTicks('foo.bar.baz', tickChar);
this.sequelize.query(sql, null, { raw: true, nest: false }).success(function(result) { return expect(this.sequelize.query(sql, null, { raw: true, nest: false }).get(0)).to.eventually.deep.equal([{ 'foo.bar.baz': 1 }]);
expect(result).to.deep.equal([{ 'foo.bar.baz': 1 }]);
done();
});
}); });
it('destructs dot separated attributes when doing a raw query using nest', function(done) { it('destructs dot separated attributes when doing a raw query using nest', function(done) {
...@@ -361,72 +343,59 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -361,72 +343,59 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
}); });
}); });
it('replaces named parameters with the passed object', function(done) { it('replaces named parameters with the passed object', function() {
this.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, { one: 1, two: 2 }).success(function(result) { return expect(this.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, { one: 1, two: 2 }).get(0))
expect(result).to.deep.equal([{ foo: 1, bar: 2 }]); .to.eventually.deep.equal([{ foo: 1, bar: 2 }]);
done();
});
}); });
it('replaces named parameters with the passed object and ignore those which does not qualify', function(done) { it('replaces named parameters with the passed object and ignore those which does not qualify', function() {
this.sequelize.query('select :one as foo, :two as bar, \'00:00\' as baz', null, { raw: true }, { one: 1, two: 2 }).success(function(result) { return expect(this.sequelize.query('select :one as foo, :two as bar, \'00:00\' as baz', null, { raw: true }, { one: 1, two: 2 }).get(0))
expect(result).to.deep.equal([{ foo: 1, bar: 2, baz: '00:00' }]); .to.eventually.deep.equal([{ foo: 1, bar: 2, baz: '00:00' }]);
done();
});
}); });
it('replaces named parameters with the passed object using the same key twice', function(done) { it('replaces named parameters with the passed object using the same key twice', function() {
this.sequelize.query('select :one as foo, :two as bar, :one as baz', null, { raw: true }, { one: 1, two: 2 }).success(function(result) { return expect(this.sequelize.query('select :one as foo, :two as bar, :one as baz', null, { raw: true }, { one: 1, two: 2 }).get(0))
expect(result).to.deep.equal([{ foo: 1, bar: 2, baz: 1 }]); .to.eventually.deep.equal([{ foo: 1, bar: 2, baz: 1 }]);
done();
});
}); });
it('replaces named parameters with the passed object having a null property', function(done) { it('replaces named parameters with the passed object having a null property', function() {
this.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, { one: 1, two: null }).success(function(result) { return expect(this.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, { one: 1, two: null }).get(0))
expect(result).to.deep.equal([{ foo: 1, bar: null }]); .to.eventually.deep.equal([{ foo: 1, bar: null }]);
done();
});
}); });
it('throw an exception when key is missing in the passed object', function(done) { it('throw an exception when key is missing in the passed object', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.query('select :one as foo, :two as bar, :three as baz', null, { raw: true }, { one: 1, two: 2 }); self.sequelize.query('select :one as foo, :two as bar, :three as baz', null, { raw: true }, { one: 1, two: 2 });
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g); }).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g);
done();
}); });
it('throw an exception with the passed number', function(done) { it('throw an exception with the passed number', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, 2); self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, 2);
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g); }).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g);
done();
}); });
it('throw an exception with the passed empty object', function(done) { it('throw an exception with the passed empty object', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, {}); self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, {});
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g); }).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g);
done();
}); });
it('throw an exception with the passed string', function(done) { it('throw an exception with the passed string', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, 'foobar'); self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, 'foobar');
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g); }).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g);
done();
}); });
it('throw an exception with the passed date', function(done) { it('throw an exception with the passed date', function() {
var self = this; var self = this;
expect(function() { expect(function() {
self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, new Date()); self.sequelize.query('select :one as foo, :two as bar', null, { raw: true }, new Date());
}).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g); }).to.throw(Error, /Named parameter ":\w+" has no value in the given object\./g);
done();
}); });
it('handles AS in conjunction with functions just fine', function(done) { it('handles AS in conjunction with functions just fine', function(done) {
...@@ -435,28 +404,20 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -435,28 +404,20 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
datetime = 'GETDATE()'; datetime = 'GETDATE()';
} }
this.sequelize.query('SELECT ' + datetime + ' AS t').success(function(result) { return this.sequelize.query('SELECT ' + datetime + ' AS t').spread(function(result) {
expect(moment(result[0].t).isValid()).to.be.true; expect(moment(result[0].t).isValid()).to.be.true;
done();
}); });
}); });
if (Support.getTestDialect() === 'postgres') { if (Support.getTestDialect() === 'postgres') {
it('replaces named parameters with the passed object and ignores casts', function(done) { it('replaces named parameters with the passed object and ignores casts', function() {
this.sequelize.query('select :one as foo, :two as bar, \'1000\'::integer as baz', null, { raw: true }, { one: 1, two: 2 }).success(function(result) { return expect(this.sequelize.query('select :one as foo, :two as bar, \'1000\'::integer as baz', null, { raw: true }, { one: 1, two: 2 }).get(0))
expect(result).to.deep.equal([{ foo: 1, bar: 2, baz: 1000 }]); .to.eventually.deep.equal([{ foo: 1, bar: 2, baz: 1000 }]);
done();
});
}); });
it('supports WITH queries', function(done) { it('supports WITH queries', function() {
this return expect(this.sequelize.query('WITH RECURSIVE t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t WHERE n < 100) SELECT sum(n) FROM t').get(0))
.sequelize .to.eventually.deep.equal([{ 'sum': '5050' }]);
.query('WITH RECURSIVE t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t WHERE n < 100) SELECT sum(n) FROM t')
.success(function(results) {
expect(results).to.deep.equal([{ 'sum': '5050' }]);
done();
});
}); });
} }
}); });
...@@ -924,7 +885,7 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -924,7 +885,7 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
self self
.sequelizeWithTransaction .sequelizeWithTransaction
.query(sql, null, { plain: true, raw: true, transaction: transaction }) .query(sql, null, { plain: true, raw: true, transaction: transaction })
.success(function(result) { callback(result.cnt); }); .spread(function(result) { callback(result.cnt); });
}; };
TransactionTest.sync({ force: true }).success(function() { TransactionTest.sync({ force: true }).success(function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!