// eslint-disable-next-line security/detect-non-literal-fs-filename
const stat = fs.statSync(fPath);
if (!stat.isFile()
- || fExt.toLowerCase() !== '.sql') {
+ || fExt.toLowerCase() !== '.sql') {
continue;
}
// eslint-disable-next-line security/detect-non-literal-fs-filename
}
this.statement._optimize = this.db.prepare('SELECT * FROM pragma_optimize(0xffff)');
+ // this.db.transaction fails when fn is async, so we need to wrangle our own
+ this.statement._beginImmediate = this.db.prepare('BEGIN IMMEDIATE');
+ this.statement._commit = this.db.prepare('COMMIT');
+ this.statement._rollback = this.db.prepare('ROLLBACK');
+
this.logger.debug(_scope, 'statements initialized', { statements: Object.keys(this.statement).length });
}
async transaction(dbCtx, fn) {
dbCtx = dbCtx || this.db;
- return dbCtx.transaction(fn).immediate();
+
+ try {
+ this.statement._beginImmediate.run();
+ const result = await fn(dbCtx);
+ this.statement._commit.run();
+ return result;
+ } finally {
+ if (this.db.inTransaction) {
+ this.statement._rollback.run();
+ }
+ }
}
});
});
+ step('covers transaction rollback', async function () {
+ const expected = events;
+ const event = 'event3';
+ const date = new Date('May 14 2025 12:02 PDT');
+ await db.context(async (dbCtx) => {
+ try {
+ await db.transaction(dbCtx, async (txCtx) => {
+ await db.almanacUpsert(dbCtx, event, date);
+ throw new Error('we interrupt this transaction');
+ });
+ } catch (e) {
+ // expected
+ }
+ const allEvents = await db.almanacGetAll(dbCtx);
+ assert.deepStrictEqual(allEvents, expected);
+ });
+ });
+
}); // Almanac
}); // specific implementation
}); // context
describe('transaction', function () {
- it('covers', function () {
- db.transaction(db.db, nop);
- });
- it('covers no context', function () {
- db.transaction(undefined, nop);
+ let fn;
+ beforeEach(function () {
+ fn = sinon.stub().resolves();
+ sinon.spy(db.statement._beginImmediate, 'run');
+ sinon.spy(db.statement._commit, 'run');
+ sinon.spy(db.statement._rollback, 'run');
+ });
+ it('covers', async function () {
+ await db.transaction(db.db, fn);
+ assert(db.statement._beginImmediate.run.called);
+ assert(fn.called);
+ assert(db.statement._commit.run.called);
+ });
+ it('covers no context', async function () {
+ await db.transaction(undefined, fn);
+ assert(db.statement._beginImmediate.run.called);
+ assert(fn.called);
+ assert(db.statement._commit.run.called);
+ });
+ it('covers rollback', async function () {
+ fn.rejects();
+ await assert.rejects(async () => db.transaction(db.db, fn));
+ assert(db.statement._beginImmediate.run.called);
+ assert(fn.called);
+ assert(db.statement._rollback.run.called);
});
}); // transaction