From 455c249f3d2b52d3e206a18e1f5442c224139b1b Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Mon, 25 Sep 2023 13:45:03 +0200 Subject: [PATCH] [mastodon-client] Improve note query performance --- .../src/server/api/mastodon/helpers/note.ts | 5 +-- .../server/api/mastodon/helpers/timeline.ts | 44 +++---------------- .../src/server/api/mastodon/helpers/user.ts | 11 +---- 3 files changed, 9 insertions(+), 51 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/helpers/note.ts b/packages/backend/src/server/api/mastodon/helpers/note.ts index 126f5e944..0108e90e9 100644 --- a/packages/backend/src/server/api/mastodon/helpers/note.ts +++ b/packages/backend/src/server/api/mastodon/helpers/note.ts @@ -16,10 +16,7 @@ export class NoteHelpers { .andWhere( "note.id IN (SELECT id FROM note_replies(:noteId, :depth, :limit))", {noteId, depth, limit}, - ) - .innerJoinAndSelect("note.user", "user") - .leftJoinAndSelect("user.avatar", "avatar") - .leftJoinAndSelect("user.banner", "banner"); + ); generateVisibilityQuery(query, user); if (user) { diff --git a/packages/backend/src/server/api/mastodon/helpers/timeline.ts b/packages/backend/src/server/api/mastodon/helpers/timeline.ts index 85411e0a5..c867e2ecd 100644 --- a/packages/backend/src/server/api/mastodon/helpers/timeline.ts +++ b/packages/backend/src/server/api/mastodon/helpers/timeline.ts @@ -1,8 +1,7 @@ import { Note } from "@/models/entities/note.js"; import { ILocalUser } from "@/models/entities/user.js"; import { Followings, Notes } from "@/models/index.js"; -import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; -import { Brackets, SelectQueryBuilder } from "typeorm"; +import { Brackets } from "typeorm"; import { generateChannelQuery } from "@/server/api/common/generate-channel-query.js"; import { generateRepliesQuery } from "@/server/api/common/generate-replies-query.js"; import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js"; @@ -13,24 +12,15 @@ import { generateMutedUserRenotesQueryForNotes } from "@/server/api/common/gener import { fetchMeta } from "@/misc/fetch-meta.js"; import { ApiError } from "@/server/api/error.js"; import { meta } from "@/server/api/endpoints/notes/global-timeline.js"; -import { NoteHelpers } from "@/server/api/mastodon/helpers/note.js"; import { PaginationHelpers } from "@/server/api/mastodon/helpers/pagination.js"; export class TimelineHelpers { public static async getHomeTimeline(user: ILocalUser, maxId: string | undefined, sinceId: string | undefined, minId: string | undefined, limit: number = 20): Promise { if (limit > 40) limit = 40; - const hasFollowing = - (await Followings.count({ - where: { - followerId: user.id, - }, - take: 1, - })) !== 0; - - const followingQuery = Followings.createQueryBuilder("following") - .select("following.followeeId") - .where("following.followerId = :followerId", {followerId: user.id}); + const followingIds = await Followings.findBy({ + followerId: user.id + }).then(res => res.map(p => p.followeeId)); const query = PaginationHelpers.makePaginationQuery( Notes.createQueryBuilder("note"), @@ -41,22 +31,11 @@ export class TimelineHelpers { .andWhere( new Brackets((qb) => { qb.where("note.userId = :meId", {meId: user.id}); - if (hasFollowing) - qb.orWhere(`note.userId IN (${followingQuery.getQuery()})`); + qb.orWhere(`note.userId IN (:...followingIds)`, {followingIds: followingIds}); }), ) - .innerJoinAndSelect("note.user", "user") - .leftJoinAndSelect("user.avatar", "avatar") - .leftJoinAndSelect("user.banner", "banner") .leftJoinAndSelect("note.reply", "reply") - .leftJoinAndSelect("note.renote", "renote") - .leftJoinAndSelect("reply.user", "replyUser") - .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") - .leftJoinAndSelect("replyUser.banner", "replyUserBanner") - .leftJoinAndSelect("renote.user", "renoteUser") - .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") - .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner") - .setParameters(followingQuery.getParameters()); + .leftJoinAndSelect("note.renote", "renote"); generateChannelQuery(query, user); generateRepliesQuery(query, true, user); @@ -98,17 +77,8 @@ export class TimelineHelpers { if (!local) query.andWhere("note.channelId IS NULL"); query - .innerJoinAndSelect("note.user", "user") - .leftJoinAndSelect("user.avatar", "avatar") - .leftJoinAndSelect("user.banner", "banner") .leftJoinAndSelect("note.reply", "reply") - .leftJoinAndSelect("note.renote", "renote") - .leftJoinAndSelect("reply.user", "replyUser") - .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") - .leftJoinAndSelect("replyUser.banner", "replyUserBanner") - .leftJoinAndSelect("renote.user", "renoteUser") - .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") - .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); + .leftJoinAndSelect("note.renote", "renote"); generateRepliesQuery(query, true, user); if (user) { diff --git a/packages/backend/src/server/api/mastodon/helpers/user.ts b/packages/backend/src/server/api/mastodon/helpers/user.ts index 7da05130d..ff85541d3 100644 --- a/packages/backend/src/server/api/mastodon/helpers/user.ts +++ b/packages/backend/src/server/api/mastodon/helpers/user.ts @@ -51,17 +51,8 @@ export class UserHelpers { if (excludeReblogs) query.andWhere("(note.renoteId IS NOT NULL) OR (note.text IS NOT NULL)"); query - .innerJoinAndSelect("note.user", "user") - .leftJoinAndSelect("user.avatar", "avatar") - .leftJoinAndSelect("user.banner", "banner") .leftJoinAndSelect("note.reply", "reply") - .leftJoinAndSelect("note.renote", "renote") - .leftJoinAndSelect("reply.user", "replyUser") - .leftJoinAndSelect("replyUser.avatar", "replyUserAvatar") - .leftJoinAndSelect("replyUser.banner", "replyUserBanner") - .leftJoinAndSelect("renote.user", "renoteUser") - .leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar") - .leftJoinAndSelect("renoteUser.banner", "renoteUserBanner"); + .leftJoinAndSelect("note.renote", "renote"); //FIXME this doesn't exclude replies to your own reply to someone else's post generateRepliesQuery(query, !excludeReplies, localUser);