Skip to content

Commit

Permalink
feat(connection): make transaction() reset versionKey if transactio…
Browse files Browse the repository at this point in the history
…n fails

Re: #8380
  • Loading branch information
vkarpov15 committed Jun 15, 2020
1 parent 78f5dbb commit 688d19d
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 8 deletions.
11 changes: 8 additions & 3 deletions lib/connection.js
Expand Up @@ -452,7 +452,7 @@ Connection.prototype.startSession = _wrapConnHelper(function startSession(option

Connection.prototype.transaction = function transaction(fn) {
return this.startSession().then(session => {
session[sessionNewDocuments] = [];
session[sessionNewDocuments] = new Map();
return session.withTransaction(() => fn(session)).
then(res => {
delete session[sessionNewDocuments];
Expand All @@ -461,8 +461,13 @@ Connection.prototype.transaction = function transaction(fn) {
catch(err => {
// If transaction was aborted, we need to reset newly
// inserted documents' `isNew`.
for (const doc of session[sessionNewDocuments]) {
doc.isNew = true;
for (const [doc, state] of session[sessionNewDocuments].entries()) {
if (state.hasOwnProperty('isNew')) {
doc.isNew = state.isNew;
}
if (state.hasOwnProperty('versionKey')) {
doc.set(doc.schema.options.versionKey, state.versionKey);
}
}
delete session[sessionNewDocuments];
throw err;
Expand Down
17 changes: 12 additions & 5 deletions lib/plugins/trackTransaction.js
Expand Up @@ -4,17 +4,24 @@ const sessionNewDocuments = require('../helpers/symbols').sessionNewDocuments;

module.exports = function trackTransaction(schema) {
schema.pre('save', function() {
if (!this.isNew) {
return;
}

const session = this.$session();
if (session == null) {
return;
}
if (session.transaction == null || session[sessionNewDocuments] == null) {
return;
}
session[sessionNewDocuments].push(this);

if (!session[sessionNewDocuments].has(this)) {
const initialState = {};
if (this.isNew) {
initialState.isNew = true;
}
if (this.schema.options.versionKey) {
initialState.versionKey = this.get(this.schema.options.versionKey);
}

session[sessionNewDocuments].set(this, initialState);
}
});
};
22 changes: 22 additions & 0 deletions test/docs/transactions.test.js
Expand Up @@ -10,6 +10,7 @@ const Schema = mongoose.Schema;
describe('transactions', function() {
let db;
let _skipped = false;
this.timeout(10000);

before(function() {
if (!process.env.REPLICA_SET) {
Expand Down Expand Up @@ -382,4 +383,25 @@ describe('transactions', function() {
assert.ok(doc.isNew);
});
});

it('can save document after aborted transaction (gh-8380)', function() {
return co(function*() {
const schema = Schema({ name: String, arr: [String] });

const Test = db.model('gh8380', schema);

yield Test.createCollection();
yield Test.create({ name: 'foo', arr: ['bar'] });
const doc = yield Test.findOne();
yield db.
transaction(session => co(function*() {
doc.arr.pop();
yield doc.save({ session });
throw new Error('Oops');
})).
catch(err => assert.equal(err.message, 'Oops'));
doc.set('arr.0', 'qux');
yield doc.save();
});
});
});

0 comments on commit 688d19d

Please sign in to comment.