dexie / Dexie.js

A Minimalistic Wrapper for IndexedDB
https://dexie.org
Apache License 2.0
11.49k stars 642 forks source link

InvalidStateError when Attempting to Update Message Read Status in Dexie 3.2.4 #1889

Open asuradoll opened 8 months ago

asuradoll commented 8 months ago

Issue Description

I'm encountering an InvalidStateError with Dexie version 3.2.4 when trying to update the read status of a message in my application's database. The error message suggests an attempt to execute an operation on an objectStore of an IDBTransaction that has already finished. This occurs in a seemingly straightforward operation where I first check if a message exists and then attempt to update its readed status.

Steps to Reproduce

Initialize the database with tables for messages, contacts, and entities. Ensure messages have a unique index on msgId. Attempt to update a message's readed status by first retrieving the message by its ID and then calling the update method on the tgMessages table. The error occurs upon executing the update operation, despite the message existing in the database. Expected Behavior The message's readed status should be updated without any errors, and the operation should complete successfully within the context of an active transaction.

Actual Behavior

The operation fails with the following error: InvalidStateError: Failed to execute 'objectStore' on 'IDBTransaction': The transaction has finished.

export class ChatMessageDatabase extends Dexie {
    tgMessages: Dexie.Table<TgMessage, number> = null as any;
    constructor(userId: number) {
        super(`ChatMessageDatabase_userId_${userId}`);

        this.version(1).stores({
            tgMessages: '++id,&msgId,contactId,senderId,receiverId',
        });
        this.tgMessages = this.table('tgMessages');

async updateMessageReaded(message: TgMessage) {
    try {
        await this.transaction('rw', this.tgMessages, async () => {
            const msg = await this.tgMessages.get(message.id);
            if (msg) {
                await this.tgMessages.update(message.id, { readed: true });
                console.log('Successfully updated message read status', message);
            } else {
                console.log('Message not found');
            }
        });
    } catch (err) {
        console.error('Failed to update message read status', err);
    }
}

Additional Context

Dexie version: 3.2.4 Browser: [Include browser name and version] The issue occurs consistently when attempting to update any message's readed status. The database initialization and update operation are part of an application managing chat messages. I have tried several approaches to ensure the operation executes within an active transaction context, including wrapping the operation in a this.transaction call, but the error persists.

I use the following code which works fine:

async updateMessageReadedDirectly(message: TgMessage) {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(this.name); 
            request.onerror = function (event) {
                reject('Database open error');
            };
            request.onsuccess = function (event) {
                //@ts-ignore
                const db = event.target.result;
                const transaction = db.transaction(['tgMessages'], 'readwrite');
                const store = transaction.objectStore('tgMessages');
                const getRequest = store.get(message.id);

                getRequest.onsuccess = function () {
                    const data = getRequest.result;
                    data.readed = message.readed;
                    const updateRequest = store.put(data);
                    updateRequest.onsuccess = function () {
                        resolve('Update success');
                    };
                    updateRequest.onerror = function (event: any) {
                        reject('Update failed');
                    };
                };

                getRequest.onerror = function (event: any) {
                    reject('Get failed');
                };
            };
        });
    }

Any insights or suggestions on how to resolve this error would be greatly appreciated.

dfahlander commented 8 months ago

Is the error happening on a real browser or in a unit test? What browser engine and version are you using? Reason I ask is because unit tests usually use fakeIndexedDB or indexedDBShim which cannot survive transactions between awaits, just like browsers had problem with for a while ago.

dfahlander commented 8 months ago

If the case is an old browser, fakeIndexedDB or indexedDBShim, one solution is to transpile the code to ES2016 (before await was introduced).