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

Commit 45c5c8fa by Jan Aagaard Meier

Change row locking option to be called lock, and added api doc

1 parent 2d480795
...@@ -956,11 +956,11 @@ module.exports = (function() { ...@@ -956,11 +956,11 @@ module.exports = (function() {
query = mainQueryItems.join('') query = mainQueryItems.join('')
} }
if (this._dialect.supports.rowLocking) { if (options.lock && this._dialect.supports.lock) {
if (options.forUpdate) { if (options.lock === 'SHARE') {
query += ' ' + this._dialect.supports.forUpdate
} else if (options.forShare) {
query += ' ' + this._dialect.supports.forShare query += ' ' + this._dialect.supports.forShare
} else {
query += ' FOR UPDATE'
} }
} }
......
...@@ -8,8 +8,7 @@ var MysqlDialect = function(sequelize) { ...@@ -8,8 +8,7 @@ var MysqlDialect = function(sequelize) {
MysqlDialect.prototype.supports = _.defaults({ MysqlDialect.prototype.supports = _.defaults({
'VALUES ()': true, 'VALUES ()': true,
'LIMIT ON UPDATE':true, 'LIMIT ON UPDATE':true,
rowLocking: true, lock: true,
forUpdate: 'FOR UPDATE',
forShare: 'LOCK IN SHARE MODE' forShare: 'LOCK IN SHARE MODE'
}, Abstract.prototype.supports) }, Abstract.prototype.supports)
......
...@@ -9,9 +9,8 @@ PostgresDialect.prototype.supports = _.defaults({ ...@@ -9,9 +9,8 @@ PostgresDialect.prototype.supports = _.defaults({
'RETURNING': true, 'RETURNING': true,
'DEFAULT VALUES': true, 'DEFAULT VALUES': true,
schemas: true, schemas: true,
rowLocking: true, lock: true,
forShare: 'FOR SHARE', forShare: 'FOR SHARE',
forUpdate: 'FOR UPDATE'
}, Abstract.prototype.supports) }, Abstract.prototype.supports)
module.exports = PostgresDialect module.exports = PostgresDialect
...@@ -643,6 +643,7 @@ module.exports = (function() { ...@@ -643,6 +643,7 @@ module.exports = (function() {
* @param {Number} [options.offset] * @param {Number} [options.offset]
* @param {Object} [queryOptions] Set the query options, e.g. raw, specifying that you want raw data instead of built Instances. See sequelize.query for options * @param {Object} [queryOptions] Set the query options, e.g. raw, specifying that you want raw data instead of built Instances. See sequelize.query for options
* @param {Transaction} [queryOptions.transaction] * @param {Transaction} [queryOptions.transaction]
* @param {String} [queryOptions.lock] Lock the selected rows in either share or update mode. Possible options are transaction.LOCK.UPDATE and transaction.LOCK.SHARE
* *
* @see {Sequelize#query} * @see {Sequelize#query}
* @return {Promise} * @return {Promise}
......
...@@ -552,6 +552,8 @@ module.exports = (function() { ...@@ -552,6 +552,8 @@ module.exports = (function() {
}) })
} }
options.lock = queryOptions.lock
var sql = this.QueryGenerator.selectQuery(tableName, options, factory) var sql = this.QueryGenerator.selectQuery(tableName, options, factory)
queryOptions = Utils._.extend({}, queryOptions, { queryOptions = Utils._.extend({}, queryOptions, {
include: options.include, include: options.include,
......
...@@ -40,6 +40,26 @@ Transaction.ISOLATION_LEVELS = { ...@@ -40,6 +40,26 @@ Transaction.ISOLATION_LEVELS = {
} }
/** /**
* Possible options for row locking. Used in conjuction with `find` calls:
*
* ```js
* t1 // is a transaction
* Model.findAll({
* where: ...
* }, {
* transaction: t1,
* lock: t1.LOCK.UPDATE,
* lock: t1.LOCK.SHARE
* })
* ```
* @property LOCK
*/
Transaction.LOCK = Transaction.prototype.LOCK = {
UPDATE: 'UPDATE',
SHARE: 'SHARE'
}
/**
* Commit the transaction * Commit the transaction
* *
* @return {this} * @return {this}
......
...@@ -94,9 +94,11 @@ describe(Support.getTestDialectTeaser("Transaction"), function () { ...@@ -94,9 +94,11 @@ describe(Support.getTestDialectTeaser("Transaction"), function () {
return User.find({ return User.find({
where: { where: {
username: 'jan' username: 'jan'
}, }
forUpdate: true }, {
}, { transaction: t1 }).then(function (t1Jan) { lock: t1.LOCK.UPDATE,
transaction: t1
}).then(function (t1Jan) {
self.sequelize.transaction({ self.sequelize.transaction({
isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED
}, function (t2) { }, function (t2) {
...@@ -104,8 +106,10 @@ describe(Support.getTestDialectTeaser("Transaction"), function () { ...@@ -104,8 +106,10 @@ describe(Support.getTestDialectTeaser("Transaction"), function () {
where: { where: {
username: 'jan' username: 'jan'
}, },
forUpdate: true }, {
}, { transaction: t2}).then(function () { lock: t2.LOCK.UPDATE,
transaction: t2
}).then(function () {
t2Spy() t2Spy()
t2.commit().then(function () { t2.commit().then(function () {
expect(t2Spy).to.have.been.calledAfter(t1Spy) // Find should not succeed before t1 has comitted expect(t2Spy).to.have.been.calledAfter(t1Spy) // Find should not succeed before t1 has comitted
...@@ -142,9 +146,11 @@ describe(Support.getTestDialectTeaser("Transaction"), function () { ...@@ -142,9 +146,11 @@ describe(Support.getTestDialectTeaser("Transaction"), function () {
return User.find({ return User.find({
where: { where: {
username: 'jan' username: 'jan'
}, }
forShare: true }, {
}, { transaction: t1 }).then(function (t1Jan) { lock: t1.LOCK.SHARE,
transaction: t1
}).then(function (t1Jan) {
self.sequelize.transaction({ self.sequelize.transaction({
isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED
}, function (t2) { }, function (t2) {
...@@ -157,7 +163,9 @@ describe(Support.getTestDialectTeaser("Transaction"), function () { ...@@ -157,7 +163,9 @@ describe(Support.getTestDialectTeaser("Transaction"), function () {
t2Jan.updateAttributes({ t2Jan.updateAttributes({
awesome: false awesome: false
}, { transaction: t2 }).then(function () { }, {
transaction: t2
}).then(function () {
t2UpdateSpy() t2UpdateSpy()
t2.commit().then(function () { t2.commit().then(function () {
expect(t2FindSpy).to.have.been.calledBefore(t1Spy) // The find call should have returned expect(t2FindSpy).to.have.been.calledBefore(t1Spy) // The find call should have returned
...@@ -169,7 +177,9 @@ describe(Support.getTestDialectTeaser("Transaction"), function () { ...@@ -169,7 +177,9 @@ describe(Support.getTestDialectTeaser("Transaction"), function () {
t1Jan.updateAttributes({ t1Jan.updateAttributes({
awesome: true awesome: true
}, { transaction: t1}).then(function () { }, {
transaction: t1
}).then(function () {
t1Spy() t1Spy()
setTimeout(t1.commit.bind(t1), 2000) setTimeout(t1.commit.bind(t1), 2000)
}) })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!