aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--integration/bunjs-only-snippets/sqlite.test.js47
-rw-r--r--src/javascript/jsc/bindings/sqlite/JSSQLStatement.cpp11
-rw-r--r--src/javascript/jsc/bindings/sqlite/sqlite.exports.js15
3 files changed, 63 insertions, 10 deletions
diff --git a/integration/bunjs-only-snippets/sqlite.test.js b/integration/bunjs-only-snippets/sqlite.test.js
index 3f1e6c5db..2250f97f0 100644
--- a/integration/bunjs-only-snippets/sqlite.test.js
+++ b/integration/bunjs-only-snippets/sqlite.test.js
@@ -381,3 +381,50 @@ it("db.query()", () => {
db.close();
db.close();
});
+
+it("db.transaction()", () => {
+ const db = Database.open(":memory:");
+
+ db.exec(
+ "CREATE TABLE cats (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER)"
+ );
+
+ const insert = db.prepare(
+ "INSERT INTO cats (name, age) VALUES (@name, @age)"
+ );
+
+ expect(db.inTransaction).toBe(false);
+ const insertMany = db.transaction((cats) => {
+ expect(db.inTransaction).toBe(true);
+ try {
+ for (const cat of cats) insert.run(cat);
+ } catch (exception) {
+ throw exception;
+ }
+ });
+
+ try {
+ insertMany([
+ { "@name": "Joey", "@age": 2 },
+ { "@name": "Sally", "@age": 4 },
+ { "@name": "Junior", "@age": 1 },
+ { "@name": "Sally", "@age": 4 },
+ ]);
+ throw new Error("Should have thrown");
+ } catch (exception) {
+ expect(exception.message).toBe("constraint failed");
+ }
+
+ expect(db.inTransaction).toBe(false);
+ expect(db.query("SELECT * FROM cats").all().length).toBe(0);
+
+ expect(db.inTransaction).toBe(false);
+ insertMany([
+ { "@name": "Joey", "@age": 2 },
+ { "@name": "Sally", "@age": 4 },
+ { "@name": "Junior", "@age": 1 },
+ ]);
+ expect(db.inTransaction).toBe(false);
+ expect(db.query("SELECT * FROM cats").all().length).toBe(3);
+ expect(db.inTransaction).toBe(false);
+});
diff --git a/src/javascript/jsc/bindings/sqlite/JSSQLStatement.cpp b/src/javascript/jsc/bindings/sqlite/JSSQLStatement.cpp
index 2540e1dc0..d7cccd771 100644
--- a/src/javascript/jsc/bindings/sqlite/JSSQLStatement.cpp
+++ b/src/javascript/jsc/bindings/sqlite/JSSQLStatement.cpp
@@ -254,7 +254,7 @@ static JSC::JSValue rebindObject(JSC::JSGlobalObject* globalObject, JSC::JSValue
int index = sqlite3_bind_parameter_index(stmt, WTF::String(propertyName.string()).utf8().data());
if (index == 0) {
- throwException(globalObject, scope, createError(globalObject, "Unknown parameter name " + propertyName.string()));
+ throwException(globalObject, scope, createError(globalObject, "Unknown parameter \"" + propertyName.string() + "\""_s));
return JSValue();
}
@@ -646,7 +646,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementIsInTransactionFunction, (JSC::JSGlobalOb
return JSValue::encode(JSC::jsUndefined());
}
- RELEASE_AND_RETURN(scope, JSValue::encode(jsNumber(sqlite3_get_autocommit(db))));
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(!sqlite3_get_autocommit(db))));
}
JSC_DEFINE_HOST_FUNCTION(jsSQLStatementPrepareStatementFunction, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
@@ -1086,6 +1086,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionAll, (JSC::JSGlob
if (UNLIKELY(status != SQLITE_DONE)) {
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(sqlite3_errstr(status))));
+ sqlite3_reset(stmt);
return JSValue::encode(jsUndefined());
}
@@ -1098,6 +1099,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionAll, (JSC::JSGlob
RELEASE_AND_RETURN(scope, JSValue::encode(JSC::constructEmptyArray(lexicalGlobalObject, nullptr, 0)));
} else {
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(sqlite3_errstr(status))));
+ sqlite3_reset(stmt);
return JSValue::encode(jsUndefined());
}
}
@@ -1145,6 +1147,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionGet, (JSC::JSGlob
RELEASE_AND_RETURN(scope, JSValue::encode(JSC::jsNull()));
} else {
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(sqlite3_errstr(status))));
+ sqlite3_reset(stmt);
return JSValue::encode(jsUndefined());
}
}
@@ -1164,6 +1167,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionRows, (JSC::JSGlo
int statusCode = sqlite3_reset(stmt);
if (UNLIKELY(statusCode != SQLITE_OK)) {
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(sqlite3_errstr(statusCode))));
+ sqlite3_reset(stmt);
return JSValue::encode(jsUndefined());
}
@@ -1204,6 +1208,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionRows, (JSC::JSGlo
if (UNLIKELY(status != SQLITE_DONE)) {
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(sqlite3_errstr(status))));
+ sqlite3_reset(stmt);
return JSValue::encode(jsUndefined());
}
@@ -1217,6 +1222,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionRows, (JSC::JSGlo
RELEASE_AND_RETURN(scope, JSValue::encode(JSC::constructEmptyArray(lexicalGlobalObject, nullptr, 0)));
} else {
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(sqlite3_errstr(status))));
+ sqlite3_reset(stmt);
return JSValue::encode(jsUndefined());
}
}
@@ -1254,6 +1260,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionRun, (JSC::JSGlob
// sqlite3_reset(stmt);
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(jsUndefined()));
} else {
+ sqlite3_reset(stmt);
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, WTF::String::fromUTF8(sqlite3_errstr(status))));
return JSValue::encode(jsUndefined());
}
diff --git a/src/javascript/jsc/bindings/sqlite/sqlite.exports.js b/src/javascript/jsc/bindings/sqlite/sqlite.exports.js
index bf060c5b0..acd28164c 100644
--- a/src/javascript/jsc/bindings/sqlite/sqlite.exports.js
+++ b/src/javascript/jsc/bindings/sqlite/sqlite.exports.js
@@ -375,13 +375,13 @@ export class Database {
// Each version of the transaction function has these same properties
const properties = {
- default: { value: wrapTransaction(apply, fn, db, controller.default) },
- deferred: { value: wrapTransaction(apply, fn, db, controller.deferred) },
+ default: { value: wrapTransaction(fn, db, controller.default) },
+ deferred: { value: wrapTransaction(fn, db, controller.deferred) },
immediate: {
- value: wrapTransaction(apply, fn, db, controller.immediate),
+ value: wrapTransaction(fn, db, controller.immediate),
},
exclusive: {
- value: wrapTransaction(apply, fn, db, controller.exclusive),
+ value: wrapTransaction(fn, db, controller.exclusive),
},
database: { value: this, enumerable: true },
};
@@ -437,12 +437,11 @@ const getController = (db, self) => {
// Return a new transaction function by wrapping the given function
const wrapTransaction = (
- apply,
fn,
db,
{ begin, commit, rollback, savepoint, release, rollbackTo }
) =>
- function sqliteTransaction() {
+ function transaction(...args) {
let before, after, undo;
if (db.inTransaction) {
before = savepoint;
@@ -453,9 +452,9 @@ const wrapTransaction = (
after = commit;
undo = rollback;
}
- before.run();
try {
- const result = apply.call(fn, this, arguments);
+ before.run();
+ const result = fn.apply(this, args);
after.run();
return result;
} catch (ex) {