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

Commit b63d4357 by Jan Aagaard Meier

Support for multiple savepoints

1 parent 209069e1
......@@ -1032,12 +1032,13 @@ module.exports = (function() {
/**
* Returns a query that starts a transaction.
*
* @param {Transaction} transaction
* @param {Object} options An object with options.
* @return {String} The generated sql query.
*/
startTransactionQuery: function(options) {
startTransactionQuery: function(transaction, options) {
if (options.parent) {
return 'SAVEPOINT ' + this.quoteIdentifier(options.parent.id) + ';';
return 'SAVEPOINT ' + this.quoteIdentifier(transaction.name) + ';';
}
return 'START TRANSACTION;';
......@@ -1060,12 +1061,13 @@ module.exports = (function() {
/**
* Returns a query that rollbacks a transaction.
*
* @param {Transaction} transaction
* @param {Object} options An object with options.
* @return {String} The generated sql query.
*/
rollbackTransactionQuery: function(options) {
rollbackTransactionQuery: function(transaction, options) {
if (options.parent) {
return 'ROLLBACK TO SAVEPOINT ' + this.quoteIdentifier(options.parent.id) + ';';
return 'ROLLBACK TO SAVEPOINT ' + this.quoteIdentifier(transaction.name) + ';';
}
return 'ROLLBACK;';
......
......@@ -374,9 +374,9 @@ module.exports = (function() {
});
},
startTransactionQuery: function(options) {
startTransactionQuery: function(transaction, options) {
if (options.parent) {
return 'SAVEPOINT ' + this.quoteIdentifier(options.parent.id) + ';';
return 'SAVEPOINT ' + this.quoteIdentifier(transaction.name) + ';';
}
return "BEGIN TRANSACTION;";
......
......@@ -286,7 +286,7 @@ module.exports = (function() {
}
var sql = this.QueryGenerator.describeTableQuery(tableName, schema, schemaDelimiter);
return this.sequelize.query(sql, null, { raw: true }).then(function(data) {
// If no data is returned from the query, then the table name may be wrong.
// Query generators that use information_schema for retrieving table info will just return an empty result set,
......@@ -729,7 +729,7 @@ module.exports = (function() {
parent: options.transaction
}, options || {});
var sql = this.QueryGenerator.startTransactionQuery(options);
var sql = this.QueryGenerator.startTransactionQuery(transaction, options);
return this.sequelize.query(sql, null, options);
};
......@@ -762,7 +762,7 @@ module.exports = (function() {
parent: options.transaction
}, options || {});
var sql = this.QueryGenerator.rollbackTransactionQuery(options);
var sql = this.QueryGenerator.rollbackTransactionQuery(transaction, options);
return this.sequelize.query(sql, null, options);
};
......
......@@ -505,7 +505,7 @@ module.exports = (function() {
*
* Note,that this is a schema in the [postgres sense of the word](http://www.postgresql.org/docs/9.1/static/ddl-schemas.html),
* not a database table. In mysql and sqlite, this command will do nothing.
*
*
* @see {Model#schema}
* @param {String} schema Name of the schema
* @return {Promise}
......@@ -516,7 +516,7 @@ module.exports = (function() {
/**
* Show all defined schemas
*
*
* Note,that this is a schema in the [postgres sense of the word](http://www.postgresql.org/docs/9.1/static/ddl-schemas.html),
* not a database table. In mysql and sqlite, this will show all tables.
* @return {Promise}
......@@ -771,9 +771,7 @@ module.exports = (function() {
var transaction = new Transaction(this, options);
return transaction.prepareEnvironment().then(function() {
return transaction;
});
return transaction.prepareEnvironment().return(transaction);
};
Sequelize.prototype.log = function() {
......
......@@ -11,11 +11,20 @@ var Utils = require('./utils')
*/
var Transaction = module.exports = function(sequelize, options) {
this.sequelize = sequelize;
this.savepoints = [];
this.options = Utils._.extend({
autocommit: true,
isolationLevel: Transaction.ISOLATION_LEVELS.REPEATABLE_READ
}, options || {});
this.id = this.options.transaction ? this.options.transaction.id : Utils.generateUUID();
if (this.options.transaction) {
this.id = this.options.transaction.id;
this.options.transaction.savepoints.push(this);
this.name = this.id + '-savepoint-' + this.options.transaction.savepoints.length;
} else {
this.id = this.name = Utils.generateUUID();
}
};
/**
......
......@@ -108,7 +108,7 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
}
done()
})
})
})
......@@ -929,6 +929,69 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
})
})
describe('supports rolling back to savepoints', function () {
beforeEach(function () {
this.User = this.sequelizeWithTransaction.define('user', {});
return this.sequelizeWithTransaction.sync({ force: true });
})
it('rolls back to the first savepoint, undoing everything', function () {
return this.sequelizeWithTransaction.transaction().bind(this).then(function(transaction) {
this.transaction = transaction;
return this.sequelizeWithTransaction.transaction({ transaction: transaction });
}).then(function (sp1) {
this.sp1 = sp1;
return this.User.create({}, { transaction: this.transaction });
}).then(function () {
return this.sequelizeWithTransaction.transaction({ transaction: this.transaction });
}).then(function (sp2) {
this.sp2 = sp2;
return this.User.create({}, { transaction: this.transaction });
}).then(function () {
return this.User.findAll({}, { transaction: this.transaction });
}).then(function (users) {
expect(users).to.have.length(2);
return this.sp1.rollback();
}).then(function () {
return this.User.findAll({}, { transaction: this.transaction });
}).then(function (users) {
expect(users).to.have.length(0);
return this.transaction.rollback();
});
});
it('rolls back to the most recent savepoint, only undoing recent changes', function () {
return this.sequelizeWithTransaction.transaction().bind(this).then(function(transaction) {
this.transaction = transaction;
return this.sequelizeWithTransaction.transaction({ transaction: transaction });
}).then(function (sp1) {
this.sp1 = sp1;
return this.User.create({}, { transaction: this.transaction });
}).then(function () {
return this.sequelizeWithTransaction.transaction({ transaction: this.transaction });
}).then(function (sp2) {
this.sp2 = sp2;
return this.User.create({}, { transaction: this.transaction });
}).then(function () {
return this.User.findAll({}, { transaction: this.transaction });
}).then(function (users) {
expect(users).to.have.length(2);
return this.sp2.rollback();
}).then(function () {
return this.User.findAll({}, { transaction: this.transaction });
}).then(function (users) {
expect(users).to.have.length(1);
return this.transaction.rollback();
});
});
});
it('supports rolling back a nested transaction', function(done) {
var self = this
var User = this.sequelize.define('Users', { username: DataTypes.STRING })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!