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

Commit 08782303 by Mick Hansen

Merge pull request #3667 from BridgeAR/fix-transactions

Fix build and regression
2 parents 92a7377b 6700695d
...@@ -3,7 +3,8 @@ language: node_js ...@@ -3,7 +3,8 @@ language: node_js
node_js: node_js:
- "0.10" - "0.10"
- "0.12" - "0.12"
- "iojs" - "iojs-v1.8"
# - "iojs" # iojs 2.0 is failing because of pg-native and nan
sudo: false sudo: false
......
# next
- [BUG] Fix regression introduced in 2.1.2: updatedAt not set anymore [3667](https://github.com/sequelize/sequelize/pull/3667)
- [BUG] Fix managed transactions not rolling back if no thenable was provided in the transaction block [3667](https://github.com/sequelize/sequelize/pull/3667)
# 2.1.2 # 2.1.2
- [BUG] `Model.create()/update()` no longer attempts to save undefined fields. - [BUG] `Model.create()/update()` no longer attempts to save undefined fields.
# 2.1.1 # 2.1.1
- [BUG] .get() now passes along options correctly when using a custom getter - [BUG] .get() now passes along options correctly when using a custom getter
- [BUG] Fix managed transactions not rolling back if an error occured the transaction block [3661](https://github.com/sequelize/sequelize/pull/3661)
- [BUG] Fix a node-webkit issue [3650](https://github.com/sequelize/sequelize/pull/3650)
- [FEATURE] Lock modes in Postgres now support `OF table` - [FEATURE] Lock modes in Postgres now support `OF table`
- [FEATURE] New transaction lock modes `FOR KEY SHARE` and `NO KEY UPDATE` for Postgres 9.3+ - [FEATURE] New transaction lock modes `FOR KEY SHARE` and `NO KEY UPDATE` for Postgres 9.3+
- [FEATURE/REFACTOR] Rewritten scopes with complete support for includes and scopes across associations - [FEATURE/REFACTOR] Rewritten scopes with complete support for includes and scopes across associations
......
...@@ -1630,7 +1630,11 @@ module.exports = (function() { ...@@ -1630,7 +1630,11 @@ module.exports = (function() {
} }
}); });
} else { } else {
var updatedAtAttr = this._timestampAttributes.updatedAt;
options.fields = _.intersection(Object.keys(values), Object.keys(this.tableAttributes)); options.fields = _.intersection(Object.keys(values), Object.keys(this.tableAttributes));
if (updatedAtAttr && options.fields.indexOf(updatedAtAttr) === -1) {
options.fields.push(updatedAtAttr);
}
} }
if (this._timestampAttributes.updatedAt) { if (this._timestampAttributes.updatedAt) {
......
...@@ -1140,7 +1140,7 @@ module.exports = (function() { ...@@ -1140,7 +1140,7 @@ module.exports = (function() {
} }
var result = autoCallback(transaction); var result = autoCallback(transaction);
if (!result || !result.then) return reject(new Error('You need to return a promise chain/thenable to the sequelize.transaction() callback')); if (!result || !result.then) throw new Error('You need to return a promise chain/thenable to the sequelize.transaction() callback');
return result.then(function (result) { return result.then(function (result) {
return transaction.commit().then(function () { return transaction.commit().then(function () {
...@@ -1148,9 +1148,7 @@ module.exports = (function() { ...@@ -1148,9 +1148,7 @@ module.exports = (function() {
}); });
}); });
}).catch(function(err) { }).catch(function(err) {
transaction.rollback().then(function () { transaction.rollback().finally(function () {
reject(err);
}, function () {
reject(err); reject(err);
}); });
}); });
......
...@@ -164,7 +164,6 @@ var Utils = module.exports = { ...@@ -164,7 +164,6 @@ var Utils = module.exports = {
fields.forEach(function(attr) { fields.forEach(function(attr) {
if (dataValues[attr] !== undefined && !Model._isVirtualAttribute(attr)) { if (dataValues[attr] !== undefined && !Model._isVirtualAttribute(attr)) {
values[attr] = dataValues[attr]; values[attr] = dataValues[attr];
// Field name mapping // Field name mapping
if (Model.rawAttributes[attr] && Model.rawAttributes[attr].field && Model.rawAttributes[attr].field !== attr) { if (Model.rawAttributes[attr] && Model.rawAttributes[attr].field && Model.rawAttributes[attr].field !== attr) {
......
...@@ -1881,15 +1881,14 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), function() { ...@@ -1881,15 +1881,14 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), function() {
describe('allows the user to provide an attribute definition object as foreignKey', function() { describe('allows the user to provide an attribute definition object as foreignKey', function() {
it('works when taking a column directly from the object', function() { it('works when taking a column directly from the object', function() {
var Project = this.sequelize.define('project', {}) var Project = this.sequelize.define('project', {})
, User = this.sequelize.define('user', { , User = this.sequelize.define('user', {
uid: { uid: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
primaryKey: true primaryKey: true
} }
}); });
var UserProjects = User.belongsToMany(Project, { foreignKey: { name: 'user_id', defaultValue: 42 }}); var UserProjects = User.belongsToMany(Project, { foreignKey: { name: 'user_id', defaultValue: 42 }, through: 'UserProjects' });
expect(UserProjects.through.model.rawAttributes.user_id).to.be.ok; expect(UserProjects.through.model.rawAttributes.user_id).to.be.ok;
expect(UserProjects.through.model.rawAttributes.user_id.references).to.equal(User.getTableName()); expect(UserProjects.through.model.rawAttributes.user_id.references).to.equal(User.getTableName());
expect(UserProjects.through.model.rawAttributes.user_id.referencesKey).to.equal('uid'); expect(UserProjects.through.model.rawAttributes.user_id.referencesKey).to.equal('uid');
...@@ -1902,7 +1901,7 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), function() { ...@@ -1902,7 +1901,7 @@ describe(Support.getTestDialectTeaser('BelongsToMany'), function() {
user: Sequelize.INTEGER user: Sequelize.INTEGER
}); });
expect(User.belongsToMany.bind(User, User, { as: 'user' })).to expect(User.belongsToMany.bind(User, User, { as: 'user', through: 'UserUser' })).to
.throw ('Naming collision between attribute \'user\' and association \'user\' on model user. To remedy this, change either foreignKey or as in your association definition'); .throw ('Naming collision between attribute \'user\' and association \'user\' on model user. To remedy this, change either foreignKey or as in your association definition');
}); });
}); });
......
...@@ -1817,8 +1817,8 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1817,8 +1817,8 @@ describe(Support.getTestDialectTeaser('Include'), function() {
, Group = this.sequelize.define('Group', {}); , Group = this.sequelize.define('Group', {});
User.belongsTo(Company); User.belongsTo(Company);
User.belongsToMany(Group); User.belongsToMany(Group, { through: 'UsersGroups' });
Group.belongsToMany(User); Group.belongsToMany(User, { through: 'UsersGroups' });
return this.sequelize.sync({force: true}).then(function () { return this.sequelize.sync({force: true}).then(function () {
return User.findAll({ return User.findAll({
......
...@@ -25,7 +25,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -25,7 +25,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
(['or', 'and']).forEach(function(method) { (['or', 'and']).forEach(function(method) {
var word = method.toUpperCase(); var word = method.toUpperCase();
describe.skip('Sequelize.' + method, function() { describe('Sequelize.' + method, function() {
it('can handle plain strings', function() { it('can handle plain strings', function() {
return this.User.find({ return this.User.find({
where: Sequelize[method]('1=1', '2=2') where: Sequelize[method]('1=1', '2=2')
...@@ -33,38 +33,38 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -33,38 +33,38 @@ describe(Support.getTestDialectTeaser('Model'), function() {
logging: function(sql) { logging: function(sql) {
if (dialect === 'mssql') { if (dialect === 'mssql') {
expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2)'); expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2)');
}else { } else {
expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2) LIMIT 1'); expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2) LIMIT 1');
} }
} }
}); });
}); });
it('can handle arrays', function() { it.skip('can handle arrays', function() {
return this.User.find({ return this.User.find({
where: Sequelize[method](['1=?', 1], ['2=?', 2]) where: Sequelize[method](['1=?', 1], ['2=?', 2])
}, { }, {
logging: function(sql) { logging: function(sql) {
if (dialect === 'mssql') { if (dialect === 'mssql') {
expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2)'); expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2)');
}else { } else {
expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2) LIMIT 1'); expect(sql).to.contain('WHERE (1=1 ' + word + ' 2=2) LIMIT 1');
} }
} }
}); });
}); });
it('can handle objects', function() { it.skip('can handle objects', function() {
return this.User.find({ return this.User.find({
where: Sequelize[method]({ username: 'foo', intVal: 2 }, { secretValue: 'bar' }) where: Sequelize[method]({ username: 'foo', intVal: 2 }, { secretValue: 'bar' })
}, { }, {
logging: function(sql) { logging: function(sql) {
var expectation = ({ var expectation = ({
mysql: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')", mysql: "WHERE (`User`.`username` = 'foo' AND `User`.`intVal` = 2 " + word + " `User`.`secretValue` = 'bar')",
mssql: 'WHERE ([User].[username]=\'foo\' AND [User].[intVal]=2 ' + word + ' [User].[secretValue]=\'bar\')', mssql: 'WHERE ([User].[username] = \'foo\' AND [User].[intVal] = 2 ' + word + ' [User].[secretValue] = \'bar\')',
sqlite: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')", sqlite: "WHERE (`User`.`username` = 'foo' AND `User`.`intVal` = 2 " + word + " `User`.`secretValue` = 'bar')",
postgres: 'WHERE ("User"."username"=\'foo\' AND "User"."intVal"=2 ' + word + ' "User"."secretValue"=\'bar\')', postgres: 'WHERE ("User"."username" = \'foo\' AND "User"."intVal" = 2 ' + word + ' "User"."secretValue" = \'bar\')',
mariadb: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')" mariadb: "WHERE (`User`.`username` = 'foo' AND `User`.`intVal` = 2 " + word + " `User`.`secretValue` = 'bar')"
})[Support.getTestDialect()]; })[Support.getTestDialect()];
if (!expectation) { if (!expectation) {
...@@ -81,11 +81,11 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -81,11 +81,11 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}, { }, {
logging: function(sql) { logging: function(sql) {
var expectation = ({ var expectation = ({
mysql: 'WHERE (`User`.`id`=1 ' + word + ' `User`.`id`=2)', mysql: 'WHERE (`User`.`id` = 1 ' + word + ' `User`.`id` = 2)',
sqlite: 'WHERE (`User`.`id`=1 ' + word + ' `User`.`id`=2)', sqlite: 'WHERE (`User`.`id` = 1 ' + word + ' `User`.`id` = 2)',
postgres: 'WHERE ("User"."id"=1 ' + word + ' "User"."id"=2)', postgres: 'WHERE ("User"."id" = 1 ' + word + ' "User"."id" = 2)',
mssql: 'WHERE ([User].[id]=1 ' + word + ' [User].[id]=2)', mssql: 'WHERE ([User].[id] = 1 ' + word + ' [User].[id] = 2)',
mariadb: 'WHERE (`User`.`id`=1 ' + word + ' `User`.`id`=2)' mariadb: 'WHERE (`User`.`id` = 1 ' + word + ' `User`.`id` = 2)'
})[Support.getTestDialect()]; })[Support.getTestDialect()];
if (!expectation) { if (!expectation) {
...@@ -98,7 +98,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -98,7 +98,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
}); });
describe.skip('Combinations of Sequelize.and and Sequelize.or', function() { describe('Combinations of Sequelize.and and Sequelize.or', function() {
it('allows nesting of Sequelize.or', function() { it('allows nesting of Sequelize.or', function() {
return this.User.find({ return this.User.find({
where: Sequelize.and(Sequelize.or('1=1', '2=2'), Sequelize.or('3=3', '4=4')) where: Sequelize.and(Sequelize.or('1=1', '2=2'), Sequelize.or('3=3', '4=4'))
...@@ -115,8 +115,8 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -115,8 +115,8 @@ describe(Support.getTestDialectTeaser('Model'), function() {
it('allows nesting of Sequelize.or using object notation', function() { it('allows nesting of Sequelize.or using object notation', function() {
return this.User.find({ return this.User.find({
where: Sequelize.and(Sequelize.or({username: {eq: 'foo'}}, {username: {eq: 'bar'}}), where: Sequelize.and(Sequelize.or({username: {$eq: 'foo'}}, {username: {$eq: 'bar'}}),
Sequelize.or({id: {eq: 1}}, {id: {eq: 4}})) Sequelize.or({id: {$eq: 1}}, {id: {$eq: 4}}))
}, { }, {
logging: function(sql) { logging: function(sql) {
var expectation = ({ var expectation = ({
...@@ -152,8 +152,8 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -152,8 +152,8 @@ describe(Support.getTestDialectTeaser('Model'), function() {
it('allows nesting of Sequelize.and using object notation', function() { it('allows nesting of Sequelize.and using object notation', function() {
return this.User.find({ return this.User.find({
where: Sequelize.or(Sequelize.and({username: {eq: 'foo'}}, {username: {eq: 'bar'}}), where: Sequelize.or(Sequelize.and({username: {$eq: 'foo'}}, {username: {$eq: 'bar'}}),
Sequelize.and({id: {eq: 1}}, {id: {eq: 4}})) Sequelize.and({id: {$eq: 1}}, {id: {$eq: 4}}))
}, { }, {
logging: function(sql) { logging: function(sql) {
var expectation = ({ var expectation = ({
...@@ -174,6 +174,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -174,6 +174,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
if (dialect !== 'postgres') { if (dialect !== 'postgres') {
// TODO: Fix this. There's a weird output produced by SqlString.arrayToList
it('still allows simple arrays lookups', function() { it('still allows simple arrays lookups', function() {
return this.User.find({ return this.User.find({
where: ['id IN (?) OR id IN (?)', [1, 2], [3, 4]] where: ['id IN (?) OR id IN (?)', [1, 2], [3, 4]]
...@@ -206,16 +207,16 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -206,16 +207,16 @@ describe(Support.getTestDialectTeaser('Model'), function() {
if (dialect === 'postgres') { if (dialect === 'postgres') {
expect(sql).to.contain( expect(sql).to.contain(
'WHERE (' + [ 'WHERE (' + [
'"User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\' AND ', '"User"."id" = 42 AND 2=2 AND (1=1) AND "User"."username" = \'foo\' AND ',
'(', '(',
'"User"."id"=42 OR 2=2 OR 1=1 OR "User"."username"=\'foo\' OR ', '"User"."id" = 42 OR 2=2 OR (1=1) OR "User"."username" = \'foo\' OR ',
'("User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\') OR ', '("User"."id" = 42 AND 2=2 AND (1=1) AND "User"."username" = \'foo\') OR ',
'("User"."id"=42 OR 2=2 OR 1=1 OR "User"."username"=\'foo\')', '("User"."id" = 42 OR 2=2 OR (1=1) OR "User"."username" = \'foo\')',
') AND ', ') AND ',
'(', '(',
'"User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\' AND ', '"User"."id" = 42 AND 2=2 AND (1=1) AND "User"."username" = \'foo\' AND ',
'("User"."id"=42 OR 2=2 OR 1=1 OR "User"."username"=\'foo\') AND ', '("User"."id" = 42 OR 2=2 OR (1=1) OR "User"."username" = \'foo\') AND ',
'("User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\')', '("User"."id" = 42 AND 2=2 AND (1=1) AND "User"."username" = \'foo\')',
')' ')'
].join('') + ].join('') +
')' ')'
...@@ -223,16 +224,16 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -223,16 +224,16 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} else if (dialect === 'mssql') { } else if (dialect === 'mssql') {
expect(sql).to.contain( expect(sql).to.contain(
'WHERE (' + [ 'WHERE (' + [
'[User].[id]=42 AND 2=2 AND 1=1 AND [User].[username]=\'foo\' AND ', '[User].[id] = 42 AND 2=2 AND (1=1) AND [User].[username] = \'foo\' AND ',
'(', '(',
'[User].[id]=42 OR 2=2 OR 1=1 OR [User].[username]=\'foo\' OR ', '[User].[id] = 42 OR 2=2 OR (1=1) OR [User].[username] = \'foo\' OR ',
'([User].[id]=42 AND 2=2 AND 1=1 AND [User].[username]=\'foo\') OR ', '([User].[id] = 42 AND 2=2 AND (1=1) AND [User].[username] = \'foo\') OR ',
'([User].[id]=42 OR 2=2 OR 1=1 OR [User].[username]=\'foo\')', '([User].[id] = 42 OR 2=2 OR (1=1) OR [User].[username] = \'foo\')',
') AND ', ') AND ',
'(', '(',
'[User].[id]=42 AND 2=2 AND 1=1 AND [User].[username]=\'foo\' AND ', '[User].[id] = 42 AND 2=2 AND (1=1) AND [User].[username] = \'foo\' AND ',
'([User].[id]=42 OR 2=2 OR 1=1 OR [User].[username]=\'foo\') AND ', '([User].[id] = 42 OR 2=2 OR (1=1) OR [User].[username] = \'foo\') AND ',
'([User].[id]=42 AND 2=2 AND 1=1 AND [User].[username]=\'foo\')', '([User].[id] = 42 AND 2=2 AND (1=1) AND [User].[username] = \'foo\')',
')' ')'
].join('') + ].join('') +
')' ')'
...@@ -240,16 +241,16 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -240,16 +241,16 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} else { } else {
expect(sql).to.contain( expect(sql).to.contain(
'WHERE (' + [ 'WHERE (' + [
"`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo' AND ", "`User`.`id` = 42 AND 2=2 AND (1=1) AND `User`.`username` = 'foo' AND ",
'(', '(',
"`User`.`id`=42 OR 2=2 OR 1=1 OR `User`.`username`='foo' OR ", "`User`.`id` = 42 OR 2=2 OR (1=1) OR `User`.`username` = 'foo' OR ",
"(`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo') OR ", "(`User`.`id` = 42 AND 2=2 AND (1=1) AND `User`.`username` = 'foo') OR ",
"(`User`.`id`=42 OR 2=2 OR 1=1 OR `User`.`username`='foo')", "(`User`.`id` = 42 OR 2=2 OR (1=1) OR `User`.`username` = 'foo')",
') AND ', ') AND ',
'(', '(',
"`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo' AND ", "`User`.`id` = 42 AND 2=2 AND (1=1) AND `User`.`username` = 'foo' AND ",
"(`User`.`id`=42 OR 2=2 OR 1=1 OR `User`.`username`='foo') AND ", "(`User`.`id` = 42 OR 2=2 OR (1=1) OR `User`.`username` = 'foo') AND ",
"(`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo')", "(`User`.`id` = 42 AND 2=2 AND (1=1) AND `User`.`username` = 'foo')",
')' ')'
].join('') + ].join('') +
')' ')'
......
...@@ -18,7 +18,7 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -18,7 +18,7 @@ describe(Support.getTestDialectTeaser('Model'), function() {
} }
}); });
return Account.sync({force: true, logging: console.log}).then(function () { return Account.sync({force: true}).then(function () {
return Account.create({ return Account.create({
ownerId: 2 ownerId: 2
}).then(function (account) { }).then(function (account) {
......
...@@ -44,6 +44,7 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -44,6 +44,7 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
return Promise.resolve(); return Promise.resolve();
}); });
}); });
it('supports automatically rolling back with a thrown error', function() { it('supports automatically rolling back with a thrown error', function() {
var t; var t;
return (expect(this.sequelize.transaction(function(transaction) { return (expect(this.sequelize.transaction(function(transaction) {
...@@ -53,15 +54,24 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -53,15 +54,24 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
expect(t.finished).to.be.equal('rollback'); expect(t.finished).to.be.equal('rollback');
}); });
}); });
it('supports automatically rolling back with a rejection', function() { it('supports automatically rolling back with a rejection', function() {
return expect(this.sequelize.transaction(function() { var t;
return (expect(this.sequelize.transaction(function(transaction) {
t = transaction;
return Promise.reject('Swag'); return Promise.reject('Swag');
})).to.eventually.be.rejected; })).to.eventually.be.rejected).then(function() {
expect(t.finished).to.be.equal('rollback');
});
}); });
it('errors when no promise chain is returned', function() {
return expect(this.sequelize.transaction(function() {
})).to.eventually.be.rejected; it('errors when no promise chain is returned', function() {
var t;
return (expect(this.sequelize.transaction(function(transaction) {
t = transaction;
})).to.eventually.be.rejected).then(function() {
expect(t.finished).to.be.equal('rollback');
});
}); });
}); });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!