diff --git a/src/eventlogdb.js b/src/eventlogdb.js index 49d12134f..0dc8e8bef 100644 --- a/src/eventlogdb.js +++ b/src/eventlogdb.js @@ -5,6 +5,7 @@ exports = module.exports = { getAllPaged: getAllPaged, getByCreationTime: getByCreationTime, add: add, + upsert: upsert, count: count, delByCreationTime: delByCreationTime, @@ -100,7 +101,33 @@ function add(id, action, source, data, callback) { if (error && error.code === 'ER_DUP_ENTRY') return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, error)); if (error || result.affectedRows !== 1) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - callback(null); + callback(null, id); + }); +} + +// id is only used if we didn't do an update but insert instead +function upsert(id, action, source, data, callback) { + assert.strictEqual(typeof id, 'string'); + assert.strictEqual(typeof action, 'string'); + assert.strictEqual(typeof source, 'object'); + assert.strictEqual(typeof data, 'object'); + assert.strictEqual(typeof callback, 'function'); + + // can't do a real sql upsert, for frequent eventlog entries we only have to do 2 queries once a day + var queries = [{ + query: 'UPDATE eventlog SET creationTime=NOW(), data="?" WHERE action = ? AND source LIKE ? AND DATE(creationTime)=CURDATE()', + args: [ data, action, JSON.stringify(source) ] + }, { + query: 'SELECT * FROM eventlog WHERE action = ? AND source LIKE ? AND DATE(creationTime)=CURDATE()', + args: [ action, JSON.stringify(source) ] + }]; + + database.transaction(queries, function (error, result) { + if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (result[0].affectedRows >= 1) return callback(null, result[1][0].id); + + // no existing eventlog found, create one + add(id, action, source, data, callback); }); } diff --git a/src/test/database-test.js b/src/test/database-test.js index d2f9fa507..8ea1c63a4 100644 --- a/src/test/database-test.js +++ b/src/test/database-test.js @@ -1675,8 +1675,9 @@ describe('database', function () { describe('eventlog', function () { it('add succeeds', function (done) { - eventlogdb.add('someid', 'some.event', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error) { + eventlogdb.add('someid', 'some.event', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error, result) { expect(error).to.be(null); + expect(result).to.equal('someid'); done(); }); }); @@ -1749,6 +1750,39 @@ describe('database', function () { }); }); + it('upsert with no existing entry succeeds', function (done) { + eventlogdb.upsert('logineventid', 'user.login', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error, result) { + expect(error).to.be(null); + expect(result).to.equal('logineventid'); + + done(); + }); + }); + + it('upsert with existing entry succeeds', function (done) { + eventlogdb.get('logineventid', function (error, result) { + expect(error).to.equal(null); + + var oldCreationTime = result.creationTime; + + // now wait 2sec + setTimeout(function () { + eventlogdb.upsert('logineventid_notused', 'user.login', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error, result) { + expect(error).to.be(null); + expect(result).to.equal('logineventid'); + + eventlogdb.get('logineventid', function (error, result) { + expect(error).to.equal(null); + // should have changed + expect(oldCreationTime).to.not.equal(result.creationTime); + + done(); + }); + }); + }, 2000); + }); + }); + it('delByCreationTime succeeds', function (done) { async.each([ 'persistent.event', 'transient.event', 'anothertransient.event', 'anotherpersistent.event' ], function (e, callback) { eventlogdb.add('someid' + Math.random(), e, { ip: '1.2.3.4' }, { appId: 'thatapp' }, callback);