server: rewrite user status queries in SQL

This commit is contained in:
Johann150 2022-12-30 13:45:19 +01:00 committed by Gitea
parent cd26e3a35c
commit 4fe288f17c

View file

@ -5,7 +5,6 @@ import config from '@/config/index.js';
import { Packed } from '@/misc/schema.js'; import { Packed } from '@/misc/schema.js';
import { awaitAll, Promiseable } from '@/prelude/await-all.js'; import { awaitAll, Promiseable } from '@/prelude/await-all.js';
import { populateEmojis } from '@/misc/populate-emojis.js'; import { populateEmojis } from '@/misc/populate-emojis.js';
import { getAntennas } from '@/misc/antenna-cache.js';
import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD, HOUR } from '@/const.js'; import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD, HOUR } from '@/const.js';
import { Cache } from '@/misc/cache.js'; import { Cache } from '@/misc/cache.js';
import { db } from '@/db/postgre.js'; import { db } from '@/db/postgre.js';
@ -126,92 +125,71 @@ export const UserRepository = db.getRepository(User).extend({
}, },
async getHasUnreadMessagingMessage(userId: User['id']): Promise<boolean> { async getHasUnreadMessagingMessage(userId: User['id']): Promise<boolean> {
const mute = await Mutings.findBy({ return await db.query(
muterId: userId, `SELECT EXISTS (
}); SELECT 1
FROM "messaging_message"
WHERE
"recipientId" = $1
AND
NOT "isRead"
AND
"userId" NOT IN (
SELECT "muteeId"
FROM "muting"
WHERE "muterId" = $1
)
const joinings = await UserGroupJoinings.findBy({ userId }); UNION
const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message') SELECT 1
.where('message.groupId = :groupId', { groupId: j.userGroupId }) FROM "messaging_message"
.andWhere('message.userId != :userId', { userId }) JOIN "user_group_joining"
.andWhere('NOT (:userId = ANY(message.reads))', { userId }) ON "messaging_message"."groupId" = "user_group_joining"."userGroupId"
.andWhere('message.createdAt > :joinedAt', { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない WHERE
.getOne().then(x => x != null))); "messaging_message"."userId" != $1
AND
const [withUser, withGroups] = await Promise.all([ NOT $1 = ANY("messaging_message"."reads")
MessagingMessages.count({ AND
where: { "messaging_message"."createdAt" > "user_group_joining"."createdAt"
recipientId: userId, ) AS exists`,
isRead: false, [userId]
...(mute.length > 0 ? { userId: Not(In(mute.map(x => x.muteeId))) } : {}), ).then(res => res[0].exists);
},
take: 1,
}).then(count => count > 0),
groupQs,
]);
return withUser || withGroups.some(x => x);
}, },
async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> { async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> {
const reads = await AnnouncementReads.findBy({ return await db.query(
userId, `SELECT EXISTS (SELECT 1 FROM "announcement" WHERE "id" NOT IN (SELECT "announcementId" FROM "announcement_read" WHERE "userId" = $1)) AS exists`,
}); [userId]
).then(res => res[0].exists);
const count = await Announcements.countBy(reads.length > 0 ? {
id: Not(In(reads.map(read => read.announcementId))),
} : {});
return count > 0;
}, },
async getHasUnreadAntenna(userId: User['id']): Promise<boolean> { async getHasUnreadAntenna(userId: User['id']): Promise<boolean> {
const myAntennas = (await getAntennas()).filter(a => a.userId === userId); return await db.query(
`SELECT EXISTS (SELECT 1 FROM "antenna_note" WHERE NOT "read" AND "antennaId" IN (SELECT "id" FROM "antenna" WHERE "userId" = $1)) AS exists`,
const unread = myAntennas.length > 0 ? await AntennaNotes.findOneBy({ [userId]
antennaId: In(myAntennas.map(x => x.id)), ).then(res => res[0].exists);
read: false,
}) : null;
return unread != null;
}, },
async getHasUnreadChannel(userId: User['id']): Promise<boolean> { async getHasUnreadChannel(userId: User['id']): Promise<boolean> {
const channels = await ChannelFollowings.findBy({ followerId: userId }); return await db.query(
`SELECT EXISTS (SELECT 1 FROM "note_unread" WHERE "noteChannelId" IN (SELECT "followeeId" FROM "channel_following" WHERE "followerId" = $1)) AS exists`,
const unread = channels.length > 0 ? await NoteUnreads.findOneBy({ [userId]
userId, ).then(res => res[0].exists);
noteChannelId: In(channels.map(x => x.followeeId)),
}) : null;
return unread != null;
}, },
async getHasUnreadNotification(userId: User['id']): Promise<boolean> { async getHasUnreadNotification(userId: User['id']): Promise<boolean> {
const mute = await Mutings.findBy({ return await db.query(
muterId: userId, `SELECT EXISTS (SELECT 1 FROM "notification" WHERE NOT "isRead" AND "notifieeId" = $1 AND "notifierId" NOT IN (SELECT "muteeId" FROM "muting" WHERE "muterId" = $1)) AS exists`,
}); [userId]
const mutedUserIds = mute.map(m => m.muteeId); ).then(res => res[0].exists);
const count = await Notifications.count({
where: {
notifieeId: userId,
...(mutedUserIds.length > 0 ? { notifierId: Not(In(mutedUserIds)) } : {}),
isRead: false,
},
take: 1,
});
return count > 0;
}, },
async getHasPendingReceivedFollowRequest(userId: User['id']): Promise<boolean> { async getHasPendingReceivedFollowRequest(userId: User['id']): Promise<boolean> {
const count = await FollowRequests.countBy({ return await db.query(
followeeId: userId, `SELECT EXISTS (SELECT 1 FROM "follow_request" WHERE "followeeId" = $1) AS exists`,
}); [userId]
).then(res => res[0].exists);
return count > 0;
}, },
getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' { getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' {