Rewrite migration 17 without idb
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.
This commit is contained in:
parent
db2941cbb0
commit
2642844c27
1 changed files with 48 additions and 24 deletions
|
@ -1,39 +1,63 @@
|
|||
const idb = require('idb');
|
||||
const Message = require('../../types/message');
|
||||
|
||||
|
||||
exports.run = async (transaction) => {
|
||||
const db = idb.upgradeDBFromTransaction(transaction);
|
||||
const tx = db.transaction;
|
||||
const messagesStore = tx.objectStore('messages');
|
||||
const messagesStore = transaction.objectStore('messages');
|
||||
|
||||
console.log('Initialize messages schema version');
|
||||
await exports._initializeMessageSchemaVersion(messagesStore);
|
||||
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 });
|
||||
|
||||
await db.transaction.complete;
|
||||
};
|
||||
|
||||
// NOTE: We disable `no-await-in-loop` because we want this migration to happen
|
||||
// in sequence and not in parallel:
|
||||
// https://eslint.org/docs/rules/no-await-in-loop#when-not-to-use-it
|
||||
exports._initializeMessageSchemaVersion = async (messagesStore) => {
|
||||
let cursor = await messagesStore.openCursor();
|
||||
while (cursor) {
|
||||
const message = cursor.value;
|
||||
console.log('Initialize schema version for message:', message.id);
|
||||
const _initializeMessageSchemaVersion = messagesStore =>
|
||||
new Promise((resolve, reject) => {
|
||||
const messagePutOperations = [];
|
||||
|
||||
const messageWithSchemaVersion = Message.initializeSchemaVersion(message);
|
||||
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 {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await messagesStore.put(messageWithSchemaVersion, message.id);
|
||||
const request = store.put(item, key);
|
||||
request.onsuccess = event =>
|
||||
resolve(event.target.result);
|
||||
request.onerror = event =>
|
||||
reject(event.target.error);
|
||||
} catch (error) {
|
||||
console.log('Failed to put message with initialized schema version:', message.id);
|
||||
reject(error);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
cursor = await cursor.continue();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue