diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index b86b955eb3..b0ed3f41ce 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -3,10 +3,11 @@ import {Notes} from "@/models/index.js"; import define from "../../define.js"; import {ApiError} from "../../error.js"; import {getUser} from "../../common/getters.js"; -import {makePaginationQuery} from "../../common/make-pagination-query.js"; import {generateVisibilityQuery} from "../../common/generate-visibility-query.js"; import {generateMutedUserQuery} from "../../common/generate-muted-user-query.js"; import {generateBlockedUserQuery} from "../../common/generate-block-query.js"; +import {makePaginationQuery} from "@/server/api/common/make-pagination-query.js"; +import {Note} from "@/models/entities/note.js"; export const meta = { tags: ["users", "notes"], @@ -66,7 +67,32 @@ export default define(meta, paramDef, async (ps, me) => { throw e; }); - //#region Construct query + const cte = + Notes.createQueryBuilder("n") + .select(`"n"."id"`, "id") + .andWhere("n.userId = :userId", { userId: user.id }); + + if (ps.withFiles || ps.fileType != null) { + cte.andWhere("n.fileIds != '{}'"); + } + if (!ps.includeReplies) { + cte.andWhere("n.replyId IS NULL"); + } + + if (ps.includeMyRenotes === false) { + cte.andWhere( + new Brackets((qb) => { + qb.orWhere("n.userId != :userId", { userId: user.id }); + qb.orWhere("n.renoteId IS NULL"); + qb.orWhere("n.text IS NOT NULL"); + qb.orWhere("n.fileIds != '{}'"); + qb.orWhere( + '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = n.id)', + ); + }), + ); + } + const query = makePaginationQuery( Notes.createQueryBuilder("note"), ps.sinceId, @@ -74,21 +100,14 @@ export default define(meta, paramDef, async (ps, me) => { ps.sinceDate, ps.untilDate, ) - .andWhere("note.userId = :userId", { userId: user.id }) - .innerJoinAndSelect("note.user", "user"); + .addCommonTableExpression(cte, "noteCte"); - generateVisibilityQuery(query, me); - if (me) { - generateMutedUserQuery(query, me, user); - generateBlockedUserQuery(query, me); - } - - if (ps.withFiles) { - query.andWhere("note.fileIds != '{}'"); - } + query.andWhere(`"note"."id" IN` + query.subQuery() + .select(`"noteCte"."id"`) + .from("noteCte", "noteCte") + .getQuery()); if (ps.fileType != null) { - query.andWhere("note.fileIds != '{}'"); query.andWhere( new Brackets((qb) => { for (const type of ps.fileType!) { @@ -108,22 +127,10 @@ export default define(meta, paramDef, async (ps, me) => { } } - if (!ps.includeReplies) { - query.andWhere("note.replyId IS NULL"); - } - - if (ps.includeMyRenotes === false) { - query.andWhere( - new Brackets((qb) => { - qb.orWhere("note.userId != :userId", { userId: user.id }); - qb.orWhere("note.renoteId IS NULL"); - qb.orWhere("note.text IS NOT NULL"); - qb.orWhere("note.fileIds != '{}'"); - qb.orWhere( - '0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)', - ); - }), - ); + generateVisibilityQuery(query, me); + if (me) { + generateMutedUserQuery(query, me, user); + generateBlockedUserQuery(query, me); } //#endregion