From ffe4a4672678e08b5d533cbd25fff3d1618d5432 Mon Sep 17 00:00:00 2001 From: hzmi Date: Sat, 24 Feb 2024 18:41:14 +0700 Subject: [PATCH] feat: delete intellegently (#386) --- packages/core/src/Structures/Client.ts | 23 +++++++-- .../Caches/Channels/ChannelUpdateListener.ts | 50 ++++++++++++------- .../GuildMembers/GuildMemberUpdateListener.ts | 22 ++++++-- 3 files changed, 72 insertions(+), 23 deletions(-) diff --git a/packages/core/src/Structures/Client.ts b/packages/core/src/Structures/Client.ts index de72c775..c1ed5d21 100644 --- a/packages/core/src/Structures/Client.ts +++ b/packages/core/src/Structures/Client.ts @@ -15,7 +15,7 @@ import type { ChannelWrapper } from "amqp-connection-manager"; import type { Channel } from "amqplib"; import type { APIChannel, APIGuild, APIGuildMember, APIMessage, APIUser, RESTPostAPIChannelMessageJSONBody } from "discord-api-types/v10"; import { ChannelType, Routes } from "discord-api-types/v10"; -import { and, eq, sql } from "drizzle-orm"; +import { and, eq, inArray, not, sql } from "drizzle-orm"; import type { NodePgDatabase } from "drizzle-orm/node-postgres"; import { drizzle } from "drizzle-orm/node-postgres"; import pg from "pg"; @@ -408,8 +408,25 @@ export class Client extends EventEmitter { }); if ("permission_overwrites" in channel && channel.permission_overwrites !== undefined) { - // TODO [2024-03-01]: Avoid delete all, intelligently delete only the ones that are not in the new payload - await this.store.delete(schema.channelsOverwrite).where(eq(schema.channelsOverwrite.channelId, channel.id)); + const toBeDeleted = await this.store + .select({ id: schema.channelsOverwrite.channelId }) + .from(schema.channelsOverwrite) + .where( + and( + eq(schema.channelsOverwrite.channelId, channel.id), + not(inArray(schema.channelsOverwrite.userOrRole, channel.permission_overwrites.map(x => x.id))) + ) + ); + + if (toBeDeleted.length > 0) { + await this.store.delete(schema.channelsOverwrite).where( + and( + eq(schema.channelsOverwrite.channelId, channel.id), + inArray(schema.channelsOverwrite.userOrRole, toBeDeleted.map(x => x.id) as string[]) + ) + ); + } + for (const overwrite of channel.permission_overwrites) { // @ts-expect-error Intended to avoid .map overwrite.channelId = channel.id; diff --git a/services/kanao-cache/src/Listeners/Caches/Channels/ChannelUpdateListener.ts b/services/kanao-cache/src/Listeners/Caches/Channels/ChannelUpdateListener.ts index 4370f6d0..a67e843e 100644 --- a/services/kanao-cache/src/Listeners/Caches/Channels/ChannelUpdateListener.ts +++ b/services/kanao-cache/src/Listeners/Caches/Channels/ChannelUpdateListener.ts @@ -1,7 +1,7 @@ import { channels, channelsOverwrite } from "@nezuchan/kanao-schema"; import type { GatewayChannelUpdateDispatch } from "discord-api-types/v10"; import { GatewayDispatchEvents } from "discord-api-types/v10"; -import { eq, sql } from "drizzle-orm"; +import { and, eq, inArray, not, sql } from "drizzle-orm"; import type { ListenerContext } from "../../../Stores/Listener.js"; import { Listener } from "../../../Stores/Listener.js"; import { stateChannels } from "../../../config.js"; @@ -35,27 +35,43 @@ export class ChannelUpdateListener extends Listener { nsfw: sql`EXCLUDED.nsfw`, lastMessageId: sql`EXCLUDED.last_message_id` } - }) - .returning({ id: channels.id }) - .then(c => c[0]); + }); - // TODO [2024-03-01]: Avoid delete all, intelligently delete only the ones that are not in the new payload - await this.container.client.drizzle.delete(channelsOverwrite).where(eq(channelsOverwrite.channelId, payload.data.d.id)); + if ("permission_overwrites" in payload.data.d && payload.data.d.permission_overwrites !== undefined) { + const toBeDeleted = await this.container.client.drizzle + .select({ id: channelsOverwrite.channelId }) + .from(channelsOverwrite) + .where( + and( + eq(channelsOverwrite.channelId, payload.data.d.id), + not(inArray(channelsOverwrite.userOrRole, payload.data.d.permission_overwrites.map(x => x.id))) + ) + ); - if ("permission_overwrites" in payload.data.d && payload.data.d.permission_overwrites !== undefined && payload.data.d.permission_overwrites.length > 0) { - for (const overwrite of payload.data.d.permission_overwrites) { - // @ts-expect-error Intended to avoid .map - overwrite.channelId = payload.data.d.id; + if (toBeDeleted.length > 0) { + await this.container.client.drizzle.delete(channelsOverwrite).where( + and( + eq(channelsOverwrite.channelId, payload.data.d.id), + inArray(channelsOverwrite.userOrRole, toBeDeleted.map(x => x.id) as string[]) + ) + ); + } + if (payload.data.d.permission_overwrites.length > 0) { + for (const overwrite of payload.data.d.permission_overwrites) { // @ts-expect-error Intended to avoid .map - overwrite.userOrRole = overwrite.id; - } + overwrite.channelId = payload.data.d.id; + + // @ts-expect-error Intended to avoid .map + overwrite.userOrRole = overwrite.id; + } - await this.container.client.drizzle.insert(channelsOverwrite) - .values(payload.data.d.permission_overwrites) - .onConflictDoNothing({ - target: [channelsOverwrite.userOrRole, channelsOverwrite.channelId] - }); + await this.container.client.drizzle.insert(channelsOverwrite) + .values(payload.data.d.permission_overwrites) + .onConflictDoNothing({ + target: [channelsOverwrite.userOrRole, channelsOverwrite.channelId] + }); + } } await DispatchListener.dispatch(payload); diff --git a/services/kanao-cache/src/Listeners/Caches/GuildMembers/GuildMemberUpdateListener.ts b/services/kanao-cache/src/Listeners/Caches/GuildMembers/GuildMemberUpdateListener.ts index cc65d718..8386d5e7 100644 --- a/services/kanao-cache/src/Listeners/Caches/GuildMembers/GuildMemberUpdateListener.ts +++ b/services/kanao-cache/src/Listeners/Caches/GuildMembers/GuildMemberUpdateListener.ts @@ -1,7 +1,7 @@ import { memberRoles, members, users } from "@nezuchan/kanao-schema"; import type { GatewayGuildMemberUpdateDispatch } from "discord-api-types/v10"; import { GatewayDispatchEvents } from "discord-api-types/v10"; -import { and, eq, sql } from "drizzle-orm"; +import { and, eq, inArray, not, sql } from "drizzle-orm"; import type { ListenerContext } from "../../../Stores/Listener.js"; import { Listener } from "../../../Stores/Listener.js"; import { stateMembers, stateUsers } from "../../../config.js"; @@ -68,8 +68,24 @@ export class GuildMemberUpdateListener extends Listener { } }); - // TODO [2024-03-01]: Avoid delete all, intelligently delete only the ones that are not in the new payload - await this.container.client.drizzle.delete(memberRoles).where(and(eq(memberRoles.memberId, payload.data.d.user.id), eq(memberRoles.guildId, payload.data.d.guild_id))); + const toBeDeleted = await this.container.client.drizzle + .select({ id: memberRoles.roleId }) + .from(memberRoles) + .where( + and( + eq(memberRoles.memberId, payload.data.d.user.id), + not(inArray(memberRoles.roleId, payload.data.d.roles)) + ) + ); + + if (toBeDeleted.length > 0) { + await this.container.client.drizzle.delete(memberRoles).where( + and( + eq(memberRoles.memberId, payload.data.d.user.id), + inArray(memberRoles.roleId, toBeDeleted.map(x => x.id) as string[]) + ) + ); + } if (payload.data.d.roles.length > 0) { await this.container.client.drizzle.insert(memberRoles).values(payload.data.d.roles.map(role => ({