2642844c27
We ran into issues when doing async operations inside of an IndexedDB `onupgradeneeded` handler. The errors were ‘The transaction is not active’ or ‘Transaction has finished’. The following documentation confirmed that transactions are committed/terminated when control returns to the event loop: Spec - https://www.w3.org/TR/IndexedDB/#transaction-lifetime-concept - https://www.w3.org/TR/IndexedDB/#upgrade-transaction-construct Stack Overflow - https://stackoverflow.com/a/11059085 - https://stackoverflow.com/a/27338944 Since the initial database migration is so critical, I decided to avoid `idb` with promise support for IndexedDB for now, but will reconsider using it for other tasks in the future to improve readability of IndexedDB code.
63 lines
2 KiB
JavaScript
63 lines
2 KiB
JavaScript
const Message = require('../../types/message');
|
|
|
|
|
|
exports.run = async (transaction) => {
|
|
const messagesStore = transaction.objectStore('messages');
|
|
|
|
console.log('Initialize messages schema version');
|
|
const numUpgradedMessages = await _initializeMessageSchemaVersion(messagesStore);
|
|
console.log('Complete messages schema version initialization', { numUpgradedMessages });
|
|
|
|
console.log('Create index from attachment schema version to attachment');
|
|
messagesStore.createIndex('schemaVersion', 'schemaVersion', { unique: false });
|
|
};
|
|
|
|
const _initializeMessageSchemaVersion = messagesStore =>
|
|
new Promise((resolve, reject) => {
|
|
const messagePutOperations = [];
|
|
|
|
const cursorRequest = messagesStore.openCursor();
|
|
cursorRequest.onsuccess = (event) => {
|
|
const cursor = event.target.result;
|
|
const hasMoreData = Boolean(cursor);
|
|
if (!hasMoreData) {
|
|
// eslint-disable-next-line more/no-then
|
|
return Promise.all(messagePutOperations)
|
|
.then(() => resolve(messagePutOperations.length));
|
|
}
|
|
|
|
const message = cursor.value;
|
|
const messageWithSchemaVersion = Message.initializeSchemaVersion(message);
|
|
messagePutOperations.push(new Promise((resolvePut) => {
|
|
console.log(
|
|
'Initialize schema version for message:',
|
|
messageWithSchemaVersion.id
|
|
);
|
|
|
|
resolvePut(putItem(
|
|
messagesStore,
|
|
messageWithSchemaVersion,
|
|
messageWithSchemaVersion.id
|
|
));
|
|
}));
|
|
|
|
return cursor.continue();
|
|
};
|
|
|
|
cursorRequest.onerror = event =>
|
|
reject(event.target.error);
|
|
});
|
|
|
|
// putItem :: IDBObjectStore -> Item -> Key -> Promise Item
|
|
const putItem = (store, item, key) =>
|
|
new Promise((resolve, reject) => {
|
|
try {
|
|
const request = store.put(item, key);
|
|
request.onsuccess = event =>
|
|
resolve(event.target.result);
|
|
request.onerror = event =>
|
|
reject(event.target.error);
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|