perf: server navigation
This commit is contained in:
@@ -66,31 +66,32 @@ export class BrowserDatabaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve messages for a room, sorted oldest-first.
|
||||
* Retrieve the latest messages for a room, sorted oldest-first for display.
|
||||
* @param roomId - Target room.
|
||||
* @param limit - Maximum number of messages to return.
|
||||
* @param offset - Number of messages to skip (for pagination).
|
||||
* @param offset - Number of newer messages to skip (for pagination).
|
||||
*/
|
||||
async getMessages(roomId: string, limit = 100, offset = 0): Promise<Message[]> {
|
||||
const allRoomMessages = await this.getAllFromIndex<Message>(
|
||||
STORE_MESSAGES, 'roomId', roomId
|
||||
);
|
||||
const sortedMessages = allRoomMessages.sort((first, second) => first.timestamp - second.timestamp);
|
||||
const endIndex = Math.max(sortedMessages.length - offset, 0);
|
||||
const startIndex = Math.max(endIndex - limit, 0);
|
||||
const messages = sortedMessages.slice(startIndex, endIndex);
|
||||
|
||||
return allRoomMessages
|
||||
.sort((first, second) => first.timestamp - second.timestamp)
|
||||
.slice(offset, offset + limit)
|
||||
.map((message) => this.normaliseMessage(message));
|
||||
return this.hydrateMessages(messages);
|
||||
}
|
||||
|
||||
async getMessagesSince(roomId: string, sinceTimestamp: number): Promise<Message[]> {
|
||||
const allRoomMessages = await this.getAllFromIndex<Message>(
|
||||
STORE_MESSAGES, 'roomId', roomId
|
||||
);
|
||||
|
||||
return allRoomMessages
|
||||
const messages = allRoomMessages
|
||||
.filter((message) => message.timestamp > sinceTimestamp)
|
||||
.sort((first, second) => first.timestamp - second.timestamp)
|
||||
.map((message) => this.normaliseMessage(message));
|
||||
.sort((first, second) => first.timestamp - second.timestamp);
|
||||
|
||||
return this.hydrateMessages(messages);
|
||||
}
|
||||
|
||||
/** Delete a message by its ID. */
|
||||
@@ -112,7 +113,11 @@ export class BrowserDatabaseService {
|
||||
async getMessageById(messageId: string): Promise<Message | null> {
|
||||
const message = await this.get<Message>(STORE_MESSAGES, messageId);
|
||||
|
||||
return message ? this.normaliseMessage(message) : null;
|
||||
if (!message) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (await this.hydrateMessages([message]))[0] ?? null;
|
||||
}
|
||||
|
||||
/** Remove every message belonging to a room. */
|
||||
@@ -520,6 +525,47 @@ export class BrowserDatabaseService {
|
||||
await this.awaitTransaction(transaction);
|
||||
}
|
||||
|
||||
private async hydrateMessages(messages: Message[]): Promise<Message[]> {
|
||||
if (messages.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const reactionsByMessageId = await this.loadReactionsForMessages(messages.map((message) => message.id));
|
||||
|
||||
return messages.map((message) => this.normaliseMessage({
|
||||
...message,
|
||||
reactions: reactionsByMessageId.get(message.id) ?? message.reactions ?? []
|
||||
}));
|
||||
}
|
||||
|
||||
private async loadReactionsForMessages(messageIds: readonly string[]): Promise<Map<string, Reaction[]>> {
|
||||
const messageIdSet = new Set(messageIds.filter((messageId) => messageId.trim().length > 0));
|
||||
const reactionsByMessageId = new Map<string, Reaction[]>();
|
||||
|
||||
if (messageIdSet.size === 0) {
|
||||
return reactionsByMessageId;
|
||||
}
|
||||
|
||||
const allReactions = await this.getAll<Reaction>(STORE_REACTIONS);
|
||||
|
||||
for (const reaction of allReactions) {
|
||||
if (!messageIdSet.has(reaction.messageId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const reactions = reactionsByMessageId.get(reaction.messageId) ?? [];
|
||||
|
||||
reactions.push(reaction);
|
||||
reactionsByMessageId.set(reaction.messageId, reactions);
|
||||
}
|
||||
|
||||
for (const reactions of reactionsByMessageId.values()) {
|
||||
reactions.sort((first, second) => first.timestamp - second.timestamp);
|
||||
}
|
||||
|
||||
return reactionsByMessageId;
|
||||
}
|
||||
|
||||
private normaliseMessage(message: Message): Message {
|
||||
if (message.content === DELETED_MESSAGE_CONTENT) {
|
||||
return { ...message,
|
||||
|
||||
Reference in New Issue
Block a user