Skip to content

Commit

Permalink
added Database#inTransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaWise committed Jun 12, 2017
1 parent 7e5a46f commit c23e359
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 2 deletions.
7 changes: 7 additions & 0 deletions src/objects/database.lzz
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ private:
NODE_SET_PROTOTYPE_METHOD(t, "close", JS_close);
NODE_SET_PROTOTYPE_METHOD(t, "defaultSafeIntegers", JS_defaultSafeIntegers);
NODE_SET_PROTOTYPE_GETTER(t, "open", JS_open);
NODE_SET_PROTOTYPE_GETTER(t, "inTransaction", JS_inTransaction);

UseContext;
exports->Set(ctx, StringFromUtf8(isolate, "Database", -1), t->GetFunction(ctx).ToLocalChecked()).FromJust();
Expand Down Expand Up @@ -240,6 +241,12 @@ private:
info.GetReturnValue().Set(Unwrap<Database>(info.This())->open);
}

NODE_GETTER(JS_inTransaction) {
info.GetReturnValue().Set(
!static_cast<bool>(sqlite3_get_autocommit(Unwrap<Database>(info.This())->db_handle))
);
}

void CloseHandles() {
if (open) {
open = false;
Expand Down
11 changes: 9 additions & 2 deletions src/objects/transaction.lzz
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ private:
sqlite3* db_handle = db->GetHandle();
double changes = 0;

auto rollback = [](sqlite3* db_handle, sqlite3_stmt* handle) {
if (!sqlite3_get_autocommit(db_handle)) {
sqlite3_step(handle);
sqlite3_reset(handle);
}
};

sqlite3_step(controller.begin);
if (sqlite3_reset(controller.begin) != SQLITE_OK) {
TRANSACTION_THROW(((void)0));
Expand All @@ -157,7 +164,7 @@ private:
int total_changes_before = sqlite3_total_changes(db_handle);
sqlite3_step(handle);
if (sqlite3_reset(handle) != SQLITE_OK) {
TRANSACTION_THROW(sqlite3_step(controller.rollback); sqlite3_reset(controller.rollback));
TRANSACTION_THROW(rollback(db_handle, controller.rollback));
}
if (sqlite3_total_changes(db_handle) != total_changes_before) {
changes += static_cast<double>(sqlite3_changes(db_handle));
Expand All @@ -166,7 +173,7 @@ private:

sqlite3_step(controller.commit);
if (sqlite3_reset(controller.commit) != SQLITE_OK) {
TRANSACTION_THROW(sqlite3_step(controller.rollback); sqlite3_reset(controller.rollback));
TRANSACTION_THROW(rollback(db_handle, controller.rollback));
}

UseIsolateAndContext;
Expand Down
4 changes: 4 additions & 0 deletions test/10.database.open.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ describe('new Database()', function () {
expect(db.memory).to.be.false;
expect(db.readonly).to.be.false;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
fs.accessSync(util.current());
});
it('should allow in-memory databases to be created', function () {
Expand All @@ -49,6 +50,7 @@ describe('new Database()', function () {
expect(db.memory).to.be.true;
expect(db.readonly).to.be.false;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
expect(function () {fs.accessSync(util.current());}).to.throw(Error);
});
it('should allow readonly database connections to be created', function () {
Expand All @@ -61,6 +63,7 @@ describe('new Database()', function () {
expect(db.memory).to.be.false;
expect(db.readonly).to.be.true;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
fs.accessSync(util.current());
});
it('should allow the "readonly" and "memory" options on the same connection', function () {
Expand All @@ -70,6 +73,7 @@ describe('new Database()', function () {
expect(db.memory).to.be.true;
expect(db.readonly).to.be.true;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
expect(function () {fs.accessSync(util.current());}).to.throw(Error);
});
it('should throw an Error if opening the database failed', function () {
Expand Down
4 changes: 4 additions & 0 deletions test/20.statement.run.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ describe('Statement#run()', function () {
expect(info.lastInsertROWID).to.equal(2);
});
it('should work with BEGIN and COMMIT', function () {
expect(db.inTransaction).to.equal(false);
expect(db.prepare("BEGIN TRANSACTION").run().changes).to.equal(0);
expect(db.inTransaction).to.equal(true);
var info = db.prepare("INSERT INTO entries VALUES ('foo', 25, 3.14, x'1133ddff')").run();
expect(info.changes).to.equal(1);
expect(info.lastInsertROWID).to.equal(3);
expect(db.inTransaction).to.equal(true);
expect(db.prepare("COMMIT TRANSACTION").run().changes).to.equal(0);
expect(db.inTransaction).to.equal(false);
});
it('should work with DROP TABLE', function () {
var stmt = db.prepare("DROP TABLE entries");
Expand Down
8 changes: 8 additions & 0 deletions test/30.transaction.run.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe('Transaction#run()', function () {
expect(trans.run().changes).to.equal(0);
});
it('should rollback and throw an exception for failed constraints', function () {
expect(db.inTransaction).to.equal(false);
db.transaction(['CREATE TABLE people (id INTEGER PRIMARY KEY, name TEXT)']).run();
db.transaction(['CREATE TABLE ages (age INTEGER, person INTEGER NOT NULL REFERENCES people ON DELETE CASCADE ON UPDATE CASCADE)']).run();
db.transaction([
Expand All @@ -62,19 +63,26 @@ describe('Transaction#run()', function () {
"INSERT INTO ages VALUES (40, 1)",
"INSERT INTO ages VALUES (30, 3)"
]);
expect(db.inTransaction).to.equal(false);
expect(function () {trans.run();}).to.throw(Database.SqliteError).with.property('code', 'SQLITE_CONSTRAINT_FOREIGNKEY');
expect(db.inTransaction).to.equal(false);
trans = db.transaction([
"INSERT INTO ages VALUES (40, 1)",
"INSERT INTO ages VALUES (30, NULL)"
]);
expect(db.inTransaction).to.equal(false);
expect(function () {trans.run();}).to.throw(Database.SqliteError).with.property('code', 'SQLITE_CONSTRAINT_NOTNULL');
expect(db.inTransaction).to.equal(false);
expect(db.prepare('SELECT * FROM ages WHERE age==35').get()).to.not.be.undefined;
expect(db.prepare('SELECT * FROM ages WHERE age==40').get()).to.be.undefined;
expect(db.inTransaction).to.equal(false);
db.transaction([
"INSERT INTO ages VALUES (40, 1)",
"INSERT INTO ages VALUES (30, 2)"
]).run();
expect(db.inTransaction).to.equal(false);
expect(db.prepare('SELECT * FROM ages WHERE age==40').get()).to.not.be.undefined;
expect(db.inTransaction).to.equal(false);
});
it('should not count changes from indirect mechanisms', function () {
var trans = db.transaction(["UPDATE people SET id=55 WHERE id=2"]);
Expand Down

0 comments on commit c23e359

Please sign in to comment.