From 65e7204ec94cccb53a66f681efa9c057bb9580a9 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 19 Mar 2021 10:53:09 +0900 Subject: [PATCH] =?UTF-8?q?perf:=20myReaction=20=E3=81=AE=E5=8F=96?= =?UTF-8?q?=E5=BE=97=E3=82=92=E3=81=BE=E3=81=A8=E3=82=81=E3=81=A6=E8=A1=8C?= =?UTF-8?q?=E3=81=86=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related #6813 --- src/models/repositories/note.ts | 47 +++++++++++++++++++++++++--- src/services/note/reaction/create.ts | 1 + 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/models/repositories/note.ts b/src/models/repositories/note.ts index 32552db2f..43caaf94b 100644 --- a/src/models/repositories/note.ts +++ b/src/models/repositories/note.ts @@ -9,6 +9,7 @@ import { toString } from '../../mfm/to-string'; import { parse } from '../../mfm/parse'; import { Emoji } from '../entities/emoji'; import { concat } from '../../prelude/array'; +import { NoteReaction } from '../entities/note-reaction'; export type PackedNote = SchemaType; @@ -83,6 +84,9 @@ export class NoteRepository extends Repository { options?: { detail?: boolean; skipHide?: boolean; + _hint_?: { + myReactions: Map; + }; } ): Promise { const opts = Object.assign({ @@ -188,6 +192,16 @@ export class NoteRepository extends Repository { } async function populateMyReaction() { + if (options?._hint_?.myReactions) { + const reaction = options._hint_.myReactions.get(note.id); + if (reaction) { + return convertLegacyReaction(reaction.reaction); + } else if (reaction === null) { + return undefined; + } + // 実装上抜けがあるだけかもしれないので、「ヒントに含まれてなかったら(=undefinedなら)return」のようにはしない + } + const reaction = await NoteReactions.findOne({ userId: meId!, noteId: note.id, @@ -245,11 +259,13 @@ export class NoteRepository extends Repository { ...(opts.detail ? { reply: note.replyId ? this.pack(note.replyId, meId, { - detail: false + detail: false, + _hint_: options?._hint_ }) : undefined, renote: note.renoteId ? this.pack(note.renoteId, meId, { - detail: true + detail: true, + _hint_: options?._hint_ }) : undefined, poll: note.hasPoll ? populatePoll() : undefined, @@ -272,7 +288,7 @@ export class NoteRepository extends Repository { return packed; } - public packMany( + public async packMany( notes: (Note['id'] | Note)[], me?: User['id'] | User | null | undefined, options?: { @@ -280,7 +296,30 @@ export class NoteRepository extends Repository { skipHide?: boolean; } ) { - return Promise.all(notes.map(n => this.pack(n, me, options))); + if (notes.length === 0) return []; + + const meId = me ? typeof me === 'string' ? me : me.id : null; + const noteIds = notes.map(n => typeof n === 'object' ? n.id : n); + const myReactionsMap = new Map(); + if (meId) { + const renoteIds = notes.filter(n => (typeof n === 'object') && (n.renoteId != null)).map(n => (n as Note).renoteId!); + const targets = [...noteIds, ...renoteIds]; + const myReactions = await NoteReactions.find({ + userId: meId, + noteId: In(targets), + }); + + for (const target of targets) { + myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) || null); + } + } + + return await Promise.all(notes.map(n => this.pack(n, me, { + ...options, + _hint_: { + myReactions: myReactionsMap + } + }))); } } diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index 30a17ad3e..6c0a852f3 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -15,6 +15,7 @@ import { isDuplicateKeyValueError } from '../../../misc/is-duplicate-key-value-e import { NoteReaction } from '../../../models/entities/note-reaction'; export default async (user: User, note: Note, reaction?: string) => { + // TODO: cache reaction = await toDbReaction(reaction, user.host); let record: NoteReaction;