fix(chat): migrate legacy cache to Elio conversation

This commit is contained in:
2026-07-17 19:04:41 +08:00
parent 5bfb71e2b8
commit a30e9937b8
7 changed files with 308 additions and 20 deletions
+51 -1
View File
@@ -9,12 +9,18 @@
* 构造时 `dbName` 可注入,便于测试时每个用例用独立 DB 互不污染。
*/
import Dexie, { type Table } from "dexie";
import Dexie, { type Table, type Transaction } from "dexie";
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
import type { ChatMediaKind } from "@/data/schemas/chat";
import type {
ChatImageData,
ChatLockDetailData,
} from "@/data/schemas/chat";
import {
buildChatConversationKey,
buildChatMediaCacheKey,
isLegacyChatCacheOwnerKey,
} from "@/lib/chat/chat_cache_keys";
export interface LocalMessageRow {
/** Dexie 自增主键(数据库内部使用,不暴露给 LocalMessage 类)。 */
@@ -71,5 +77,49 @@ export class LocalChatDB extends Dexie {
// so retaining it would expose one identity's history to another.
await transaction.table("messages").clear();
});
this.version(4)
.stores({
messages: "++dbId, sessionId",
media: "cacheKey, ownerKey, messageId, kind, remoteUrl, updatedAt, lastAccessedAt",
})
.upgrade(migrateLegacyChatCacheToElio);
}
}
async function migrateLegacyChatCacheToElio(
transaction: Transaction,
): Promise<void> {
const messages = transaction.table<LocalMessageRow, number>("messages");
await messages.toCollection().modify((message) => {
const conversationKey = getElioConversationKey(message.sessionId);
if (conversationKey) message.sessionId = conversationKey;
});
const media = transaction.table<LocalChatMediaRow, string>("media");
const rows = await media.toArray();
for (const row of rows) {
const conversationKey = getElioConversationKey(row.ownerKey);
if (!conversationKey) continue;
const cacheKey = buildChatMediaCacheKey({
ownerKey: conversationKey,
messageId: row.messageId,
kind: row.kind,
});
const existing = await media.get(cacheKey);
await media.delete(row.cacheKey);
if (existing) continue;
await media.put({
...row,
cacheKey,
ownerKey: conversationKey,
});
}
}
function getElioConversationKey(ownerKey: string): string | null {
return isLegacyChatCacheOwnerKey(ownerKey)
? buildChatConversationKey(ownerKey, DEFAULT_CHARACTER_ID)
: null;
}