From b2072803010a1e3a1b6e4f208e2c7954abb8a17b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toomas=20S=C3=B5ukand?= Date: Wed, 25 Dec 2019 11:48:46 +0200 Subject: [PATCH] Added ability to receive updates from `sqlite3_update_hook` --- lib/sqlite3.js | 2 +- src/database.cc | 12 ++++++- test/update_hook.test.js | 75 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 test/update_hook.test.js diff --git a/lib/sqlite3.js b/lib/sqlite3.js index 313f5a316..430a2b88a 100644 --- a/lib/sqlite3.js +++ b/lib/sqlite3.js @@ -146,7 +146,7 @@ Statement.prototype.map = function() { let isVerbose = false; -const supportedEvents = [ 'trace', 'profile', 'insert', 'update', 'delete' ]; +const supportedEvents = [ 'trace', 'profile', 'change' ]; Database.prototype.addListener = Database.prototype.on = function(type) { const val = EventEmitter.prototype.addListener.apply(this, arguments); diff --git a/src/database.cc b/src/database.cc index 5ccbca74a..b16b1f768 100644 --- a/src/database.cc +++ b/src/database.cc @@ -387,6 +387,11 @@ Napi::Value Database::Configure(const Napi::CallbackInfo& info) { Baton* baton = new LimitBaton(db, handle, id, value); db->Schedule(SetLimit, baton); } + else if (info[0].StrictEquals(Napi::String::New(env, "change"))) { + Napi::Function handle; + Baton* baton = new Baton(db, handle); + db->Schedule(RegisterUpdateCallback, baton); + } else { Napi::TypeError::New(env, (StringConcat( #if V8_MAJOR_VERSION > 6 @@ -556,12 +561,13 @@ void Database::UpdateCallback(Database *db, UpdateInfo* i) { Napi::HandleScope scope(env); Napi::Value argv[] = { + Napi::String::New(env, "change"), Napi::String::New(env, sqlite_authorizer_string(info->type)), Napi::String::New(env, info->database.c_str()), Napi::String::New(env, info->table.c_str()), Napi::Number::New(env, info->rowid), }; - EMIT_EVENT(db->Value(), 4, argv); + EMIT_EVENT(db->Value(), 5, argv); } Napi::Value Database::Exec(const Napi::CallbackInfo& info) { @@ -762,4 +768,8 @@ void Database::RemoveCallbacks() { debug_profile->finish(); debug_profile = NULL; } + if (update_event) { + update_event->finish(); + update_event = NULL; + } } diff --git a/test/update_hook.test.js b/test/update_hook.test.js new file mode 100644 index 000000000..6507d2c83 --- /dev/null +++ b/test/update_hook.test.js @@ -0,0 +1,75 @@ +var sqlite3 = require('..'); +var assert = require('assert'); + +describe('update_hook', function() { + var db; + + beforeEach(function(done) { + db = new sqlite3.Database(':memory:', function(err) { + if (err) return done(err); + + db.run("CREATE TABLE update_hooks_test (id int PRIMARY KEY, value text)", done); + }); + }); + + it('emits insert event on inserting data to table', function(done) { + db.addListener('change', function(eventType, database, table, rowId) { + assert.equal(eventType, 'insert'); + assert.equal(database, 'main'); + assert.equal(table, 'update_hooks_test'); + assert.equal(rowId, 1); + + return done(); + }); + + db.run("INSERT INTO update_hooks_test VALUES (1, 'value')", function(err) { + if (err) return done(err); + }); + }); + + it('emits update event on row modification in table', function(done) { + db.run("INSERT INTO update_hooks_test VALUES (2, 'value'), (3, 'value4')", function(err) { + if (err) return done(err); + + db.addListener('change', function(eventType, database, table, rowId) { + assert.equal(eventType, 'update'); + assert.equal(database, 'main'); + assert.equal(table, 'update_hooks_test'); + assert.equal(rowId, 1); + + db.all("SELECT * FROM update_hooks_test WHERE rowid = ?", rowId, function(err, rows) { + assert.deepEqual(rows, [{ id: 2, value: 'new_val' }]); + + return done(err); + }); + }); + + db.run("UPDATE update_hooks_test SET value = 'new_val' WHERE id = 2", function(err) { + if (err) return done(err); + }); + }); + }); + + it('emits delete event on row was deleted from table', function(done) { + db.run("INSERT INTO update_hooks_test VALUES (2, 'value')", function(err) { + if (err) return done(err); + + db.addListener('change', function(eventType, database, table, rowId) { + assert.equal(eventType, 'delete'); + assert.equal(database, 'main'); + assert.equal(table, 'update_hooks_test'); + assert.equal(rowId, 1); + + return done(); + }); + + db.run("DELETE FROM update_hooks_test WHERE id = 2", function(err) { + if (err) return done(err); + }); + }); + }); + + afterEach(function(done) { + db.close(done); + }); +});