Skip to content

Commit 7e0106c

Browse files
authored
Merge pull request #101 from tursodatabase/tx-modes
Add support for transaction modes
2 parents e43fedb + 489dc21 commit 7e0106c

File tree

4 files changed

+86
-22
lines changed

4 files changed

+86
-22
lines changed

index.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -121,18 +121,32 @@ class Database {
121121
if (typeof fn !== "function")
122122
throw new TypeError("Expected first argument to be a function");
123123

124-
return (...bindParameters) => {
125-
// TODO: Use libsql transaction API.
126-
this.exec("BEGIN");
127-
try {
128-
const result = fn(...bindParameters);
129-
this.exec("COMMIT");
130-
return result;
131-
} catch (err) {
132-
this.exec("ROLLBACK");
133-
throw err;
134-
}
124+
const db = this;
125+
const wrapTxn = (mode) => {
126+
return (...bindParameters) => {
127+
db.exec("BEGIN " + mode);
128+
try {
129+
const result = fn(...bindParameters);
130+
db.exec("COMMIT");
131+
return result;
132+
} catch (err) {
133+
db.exec("ROLLBACK");
134+
throw err;
135+
}
136+
};
137+
};
138+
const properties = {
139+
default: { value: wrapTxn("") },
140+
deferred: { value: wrapTxn("DEFERRED") },
141+
immediate: { value: wrapTxn("IMMEDIATE") },
142+
exclusive: { value: wrapTxn("EXCLUSIVE") },
143+
database: { value: this, enumerable: true },
135144
};
145+
Object.defineProperties(properties.default.value, properties);
146+
Object.defineProperties(properties.deferred.value, properties);
147+
Object.defineProperties(properties.immediate.value, properties);
148+
Object.defineProperties(properties.exclusive.value, properties);
149+
return properties.default.value;
136150
}
137151

138152
pragma(source, options) {

integration-tests/tests/async.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,24 @@ test.serial("Database.transaction()", async (t) => {
236236
t.is(stmt.get(5).name, "Junior");
237237
});
238238

239+
test.serial("Database.transaction().immediate()", async (t) => {
240+
const db = t.context.db;
241+
const insert = await db.prepare(
242+
"INSERT INTO users(name, email) VALUES (:name, :email)"
243+
);
244+
const insertMany = db.transaction((users) => {
245+
t.is(db.inTransaction, true);
246+
for (const user of users) insert.run(user);
247+
});
248+
t.is(db.inTransaction, false);
249+
await insertMany.immediate([
250+
{ name: "Joey", email: "joey@example.org" },
251+
{ name: "Sally", email: "sally@example.org" },
252+
{ name: "Junior", email: "junior@example.org" },
253+
]);
254+
t.is(db.inTransaction, false);
255+
});
256+
239257
test.serial("Database.pragma()", async (t) => {
240258
const db = t.context.db;
241259
await db.pragma("cache_size = 2000");

integration-tests/tests/sync.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,24 @@ test.serial("Database.transaction()", async (t) => {
240240
t.is(stmt.get(5).name, "Junior");
241241
});
242242

243+
test.serial("Database.transaction().immediate()", async (t) => {
244+
const db = t.context.db;
245+
const insert = db.prepare(
246+
"INSERT INTO users(name, email) VALUES (:name, :email)"
247+
);
248+
const insertMany = db.transaction((users) => {
249+
t.is(db.inTransaction, true);
250+
for (const user of users) insert.run(user);
251+
});
252+
t.is(db.inTransaction, false);
253+
insertMany.immediate([
254+
{ name: "Joey", email: "joey@example.org" },
255+
{ name: "Sally", email: "sally@example.org" },
256+
{ name: "Junior", email: "junior@example.org" },
257+
]);
258+
t.is(db.inTransaction, false);
259+
});
260+
243261
test.serial("values", async (t) => {
244262
const db = t.context.db;
245263

promise.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,32 @@ class Database {
124124
if (typeof fn !== "function")
125125
throw new TypeError("Expected first argument to be a function");
126126

127-
return async (...bindParameters) => {
128-
// TODO: Use libsql transaction API.
129-
await this.exec("BEGIN");
130-
try {
131-
const result = fn(...bindParameters);
132-
await this.exec("COMMIT");
133-
return result;
134-
} catch (err) {
135-
await this.exec("ROLLBACK");
136-
throw err;
137-
}
127+
const db = this;
128+
const wrapTxn = (mode) => {
129+
return async (...bindParameters) => {
130+
await db.exec("BEGIN " + mode);
131+
try {
132+
const result = fn(...bindParameters);
133+
await db.exec("COMMIT");
134+
return result;
135+
} catch (err) {
136+
await db.exec("ROLLBACK");
137+
throw err;
138+
}
139+
};
140+
};
141+
const properties = {
142+
default: { value: wrapTxn("") },
143+
deferred: { value: wrapTxn("DEFERRED") },
144+
immediate: { value: wrapTxn("IMMEDIATE") },
145+
exclusive: { value: wrapTxn("EXCLUSIVE") },
146+
database: { value: this, enumerable: true },
138147
};
148+
Object.defineProperties(properties.default.value, properties);
149+
Object.defineProperties(properties.deferred.value, properties);
150+
Object.defineProperties(properties.immediate.value, properties);
151+
Object.defineProperties(properties.exclusive.value, properties);
152+
return properties.default.value;
139153
}
140154

141155
pragma(source, options) {

0 commit comments

Comments
 (0)