diff --git a/javascript/indexdb.js b/javascript/indexdb.js index ace3d5843..17d79b93b 100644 --- a/javascript/indexdb.js +++ b/javascript/indexdb.js @@ -36,6 +36,37 @@ async function initIndexDB() { if (!db) await createDB(); } +/** + * Reusable setup for handling IDB transactions. + * @param {Object} resources - Required resources for implementation + * @param {IDBTransaction} resources.transaction + * @param {AbortSignal} resources.signal + * @param {Function} resources.resolve + * @param {Function} resources.reject + * @param {*} resolveValue - Value to resolve the outer Promise with + * @returns {() => void} - Function for manually aborting the transaction + */ +function configureTransactionAbort({ transaction, signal, resolve, reject }, resolveValue) { + function abortTransaction() { + signal.removeEventListener('abort', abortTransaction); + transaction.abort(); + } + signal.addEventListener('abort', abortTransaction); + transaction.onabort = () => { + signal.removeEventListener('abort', abortTransaction); + reject(new DOMException(`Aborting database transaction. ${signal.reason}`, 'AbortError')); + }; + transaction.onerror = (e) => { + signal.removeEventListener('abort', abortTransaction); + reject(new Error('Database transaction error.', e)); + }; + transaction.oncomplete = () => { + signal.removeEventListener('abort', abortTransaction); + resolve(resolveValue); + }; + return abortTransaction; +} + async function add(record) { if (!db) return null; return new Promise((resolve, reject) => { @@ -161,24 +192,8 @@ async function idbFolderCleanup(keepSet, folder, signal) { } return new Promise((resolve, reject) => { const transaction = db.transaction('thumbs', 'readwrite'); - function abortTransaction() { - signal.removeEventListener('abort', abortTransaction); - transaction.abort(); - } - signal.addEventListener('abort', abortTransaction); - transaction.onabort = () => { - signal.removeEventListener('abort', abortTransaction); - reject(`Aborting. ${signal.reason}`); // eslint-disable-line prefer-promise-reject-errors - }; - transaction.onerror = () => { - signal.removeEventListener('abort', abortTransaction); - reject(new Error('Database transaction error')); - }; - transaction.oncomplete = async () => { - signal.removeEventListener('abort', abortTransaction); - resolve(totalRemovals); - }; - + const props = { transaction, signal, resolve, reject }; + const abortTransaction = configureTransactionAbort(props, totalRemovals); try { const store = transaction.objectStore('thumbs'); removals.forEach((entry) => { store.delete(entry); });