From 7378e11210084a963c30548c672cf99fe18095a9 Mon Sep 17 00:00:00 2001 From: samsamson33 Date: Thu, 27 Feb 2020 10:10:12 -0500 Subject: [PATCH] Revert "feat: remove datastores and implement Managers (#3696)" This reverts commit 7e8197cfb02298ee081c92909ead1a5210a5eddd. --- docs/examples/greeting.js | 2 +- src/client/Client.js | 34 ++-- src/client/actions/Action.js | 6 +- src/client/actions/ChannelCreate.js | 2 +- src/client/actions/ChannelDelete.js | 4 +- src/client/actions/ChannelUpdate.js | 6 +- src/client/actions/GuildBanRemove.js | 2 +- .../actions/GuildChannelsPositionUpdate.js | 4 +- src/client/actions/GuildDelete.js | 8 +- src/client/actions/GuildEmojiDelete.js | 2 +- src/client/actions/GuildEmojisUpdate.js | 6 +- src/client/actions/GuildIntegrationsUpdate.js | 2 +- src/client/actions/GuildMemberRemove.js | 6 +- src/client/actions/GuildRoleCreate.js | 4 +- src/client/actions/GuildRoleDelete.js | 6 +- src/client/actions/GuildRoleUpdate.js | 4 +- .../actions/GuildRolesPositionUpdate.js | 4 +- src/client/actions/GuildUpdate.js | 2 +- src/client/actions/InviteCreate.js | 4 +- src/client/actions/InviteDelete.js | 4 +- src/client/actions/MessageCreate.js | 4 +- src/client/actions/MessageDelete.js | 2 +- src/client/actions/MessageDeleteBulk.js | 4 +- .../actions/MessageReactionRemoveAll.js | 2 +- .../actions/MessageReactionRemoveEmoji.js | 2 +- src/client/actions/PresenceUpdate.js | 8 +- src/client/actions/UserUpdate.js | 2 +- src/client/actions/VoiceStateUpdate.js | 8 +- src/client/actions/WebhooksUpdate.js | 2 +- src/client/voice/ClientVoiceManager.js | 2 +- src/client/voice/VoiceConnection.js | 2 +- src/client/websocket/WebSocketManager.js | 2 +- .../websocket/handlers/CHANNEL_PINS_UPDATE.js | 2 +- .../websocket/handlers/GUILD_BAN_ADD.js | 2 +- src/client/websocket/handlers/GUILD_CREATE.js | 2 +- .../websocket/handlers/GUILD_MEMBERS_CHUNK.js | 2 +- .../websocket/handlers/GUILD_MEMBER_ADD.js | 2 +- .../websocket/handlers/GUILD_MEMBER_UPDATE.js | 4 +- src/client/websocket/handlers/READY.js | 2 +- src/client/websocket/handlers/TYPING_START.js | 4 +- src/index.js | 29 ++-- src/managers/MessageManager.js | 141 ---------------- src/managers/VoiceStateManager.js | 37 ----- src/sharding/ShardClientUtil.js | 4 +- src/sharding/ShardingManager.js | 2 +- .../ChannelStore.js} | 73 ++++++--- .../BaseManager.js => stores/DataStore.js} | 59 +++---- .../GuildChannelStore.js} | 30 ++-- .../GuildEmojiRoleStore.js} | 57 +++---- .../GuildEmojiStore.js} | 21 +-- .../GuildMemberRoleStore.js} | 62 +++---- .../GuildMemberStore.js} | 33 ++-- .../GuildManager.js => stores/GuildStore.js} | 23 +-- src/stores/MessageStore.js | 135 ++++++++++++++++ .../PresenceStore.js} | 21 +-- .../ReactionStore.js} | 32 ++-- .../ReactionUserStore.js} | 25 +-- .../RoleManager.js => stores/RoleStore.js} | 39 ++--- .../UserManager.js => stores/UserStore.js} | 19 +-- src/stores/VoiceStateStore.js | 26 +++ src/structures/CategoryChannel.js | 2 +- src/structures/Channel.js | 4 +- src/structures/DMChannel.js | 8 +- src/structures/Emoji.js | 2 +- src/structures/Guild.js | 85 +++++----- src/structures/GuildAuditLogs.js | 16 +- src/structures/GuildChannel.js | 8 +- src/structures/GuildEmoji.js | 16 +- src/structures/GuildMember.js | 20 +-- src/structures/Integration.js | 2 +- src/structures/Invite.js | 2 +- src/structures/Message.js | 12 +- src/structures/MessageMentions.js | 6 +- src/structures/MessageReaction.js | 18 +-- src/structures/Presence.js | 4 +- src/structures/ReactionCollector.js | 2 +- src/structures/Role.js | 2 +- src/structures/TextChannel.js | 8 +- src/structures/User.js | 10 +- src/structures/VoiceChannel.js | 2 +- src/structures/VoiceState.js | 4 +- src/structures/Webhook.js | 4 +- src/structures/interfaces/TextBasedChannel.js | 10 +- src/util/LimitedCollection.js | 29 ---- src/util/Structures.js | 2 +- src/util/Util.js | 38 ++++- typings/index.d.ts | 153 +++++++++--------- 87 files changed, 705 insertions(+), 804 deletions(-) delete mode 100644 src/managers/MessageManager.js delete mode 100644 src/managers/VoiceStateManager.js rename src/{managers/ChannelManager.js => stores/ChannelStore.js} (52%) rename src/{managers/BaseManager.js => stores/DataStore.js} (50%) rename src/{managers/GuildChannelManager.js => stores/GuildChannelStore.js} (85%) rename src/{managers/GuildEmojiRoleManager.js => stores/GuildEmojiRoleStore.js} (73%) rename src/{managers/GuildEmojiManager.js => stores/GuildEmojiStore.js} (89%) rename src/{managers/GuildMemberRoleManager.js => stores/GuildMemberRoleStore.js} (77%) rename src/{managers/GuildMemberManager.js => stores/GuildMemberStore.js} (91%) rename src/{managers/GuildManager.js => stores/GuildStore.js} (85%) create mode 100644 src/stores/MessageStore.js rename src/{managers/PresenceManager.js => stores/PresenceStore.js} (73%) rename src/{managers/ReactionManager.js => stores/ReactionStore.js} (74%) rename src/{managers/ReactionUserManager.js => stores/ReactionUserStore.js} (77%) rename src/{managers/RoleManager.js => stores/RoleStore.js} (78%) rename src/{managers/UserManager.js => stores/UserStore.js} (80%) create mode 100644 src/stores/VoiceStateStore.js delete mode 100644 src/util/LimitedCollection.js diff --git a/docs/examples/greeting.js b/docs/examples/greeting.js index 314a7598659be..8fc1dfada9002 100644 --- a/docs/examples/greeting.js +++ b/docs/examples/greeting.js @@ -19,7 +19,7 @@ client.on('ready', () => { // Create an event listener for new guild members client.on('guildMemberAdd', member => { // Send the message to a designated channel on a server: - const channel = member.guild.channels.cache.find(ch => ch.name === 'member-log'); + const channel = member.guild.channels.find(ch => ch.name === 'member-log'); // Do nothing if the channel wasn't found on this server if (!channel) return; // Send the message, mentioning the member diff --git a/src/client/Client.js b/src/client/Client.js index ae7bbf8b3c66b..a1ab6672eae12 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -11,10 +11,10 @@ const Webhook = require('../structures/Webhook'); const Invite = require('../structures/Invite'); const ClientApplication = require('../structures/ClientApplication'); const ShardClientUtil = require('../sharding/ShardClientUtil'); -const UserManager = require('../managers/UserManager'); -const ChannelManager = require('../managers/ChannelManager'); -const GuildManager = require('../managers/GuildManager'); -const GuildEmojiManager = require('../managers/GuildEmojiManager'); +const UserStore = require('../stores/UserStore'); +const ChannelStore = require('../stores/ChannelStore'); +const GuildStore = require('../stores/GuildStore'); +const GuildEmojiStore = require('../stores/GuildEmojiStore'); const { Events, browser, DefaultOptions } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); const Structures = require('../util/Structures'); @@ -99,25 +99,25 @@ class Client extends BaseClient { /** * All of the {@link User} objects that have been cached at any point, mapped by their IDs - * @type {UserManager} + * @type {UserStore} */ - this.users = new UserManager(this); + this.users = new UserStore(this); /** * All of the guilds the client is currently handling, mapped by their IDs - * as long as sharding isn't being used, this will be *every* guild the bot is a member of - * @type {GuildManager} + * @type {GuildStore} */ - this.guilds = new GuildManager(this); + this.guilds = new GuildStore(this); /** * All of the {@link Channel}s that the client is currently handling, mapped by their IDs - * as long as sharding isn't being used, this will be *every* channel in *every* guild the bot * is a member of. Note that DM channels will not be initially cached, and thus not be present - * in the Manager without their explicit fetching or use. - * @type {ChannelManager} + * in the store without their explicit fetching or use. + * @type {ChannelStore} */ - this.channels = new ChannelManager(this); + this.channels = new ChannelStore(this); const ClientPresence = Structures.get('ClientPresence'); /** @@ -159,13 +159,13 @@ class Client extends BaseClient { /** * All custom emojis that the client has access to, mapped by their IDs - * @type {GuildEmojiManager} + * @type {GuildEmojiStore} * @readonly */ get emojis() { - const emojis = new GuildEmojiManager({ client: this }); - for (const guild of this.guilds.cache.values()) { - if (guild.available) for (const emoji of guild.emojis.cache.values()) emojis.cache.set(emoji.id, emoji); + const emojis = new GuildEmojiStore({ client: this }); + for (const guild of this.guilds.values()) { + if (guild.available) for (const emoji of guild.emojis.values()) emojis.set(emoji.id, emoji); } return emojis; } @@ -298,11 +298,11 @@ class Client extends BaseClient { let channels = 0; let messages = 0; - for (const channel of this.channels.cache.values()) { + for (const channel of this.channels.values()) { if (!channel.messages) continue; channels++; - messages += channel.messages.cache.sweep( + messages += channel.messages.sweep( message => now - (message.editedTimestamp || message.createdTimestamp) > lifetimeMs ); } diff --git a/src/client/actions/Action.js b/src/client/actions/Action.js index 2a0bc861c1452..ce4fd6db2221d 100644 --- a/src/client/actions/Action.js +++ b/src/client/actions/Action.js @@ -23,10 +23,10 @@ class GenericAction { return data; } - getPayload(data, manager, id, partialType, cache) { - const existing = manager.cache.get(id); + getPayload(data, store, id, partialType, cache) { + const existing = store.get(id); if (!existing && this.client.options.partials.includes(partialType)) { - return manager.add(data, cache); + return store.add(data, cache); } return existing; } diff --git a/src/client/actions/ChannelCreate.js b/src/client/actions/ChannelCreate.js index fa60a0b395080..6830f2ab5549f 100644 --- a/src/client/actions/ChannelCreate.js +++ b/src/client/actions/ChannelCreate.js @@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants'); class ChannelCreateAction extends Action { handle(data) { const client = this.client; - const existing = client.channels.cache.has(data.id); + const existing = client.channels.has(data.id); const channel = client.channels.add(data); if (!existing && channel) { /** diff --git a/src/client/actions/ChannelDelete.js b/src/client/actions/ChannelDelete.js index 66fad20dbd025..fdfc3870922dc 100644 --- a/src/client/actions/ChannelDelete.js +++ b/src/client/actions/ChannelDelete.js @@ -12,13 +12,13 @@ class ChannelDeleteAction extends Action { handle(data) { const client = this.client; - let channel = client.channels.cache.get(data.id); + let channel = client.channels.get(data.id); if (channel) { client.channels.remove(channel.id); channel.deleted = true; if (channel.messages && !(channel instanceof DMChannel)) { - for (const message of channel.messages.cache.values()) { + for (const message of channel.messages.values()) { message.deleted = true; } } diff --git a/src/client/actions/ChannelUpdate.js b/src/client/actions/ChannelUpdate.js index 06bb71b853546..7b716de0707d9 100644 --- a/src/client/actions/ChannelUpdate.js +++ b/src/client/actions/ChannelUpdate.js @@ -8,16 +8,16 @@ class ChannelUpdateAction extends Action { handle(data) { const client = this.client; - let channel = client.channels.cache.get(data.id); + let channel = client.channels.get(data.id); if (channel) { const old = channel._update(data); if (ChannelTypes[channel.type.toUpperCase()] !== data.type) { const newChannel = Channel.create(this.client, data, channel.guild); - for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message); + for (const [id, message] of channel.messages) newChannel.messages.set(id, message); newChannel._typing = new Map(channel._typing); channel = newChannel; - this.client.channels.cache.set(channel.id, channel); + this.client.channels.set(channel.id, channel); } return { diff --git a/src/client/actions/GuildBanRemove.js b/src/client/actions/GuildBanRemove.js index fc28e113f66b7..5a4c0a90258a2 100644 --- a/src/client/actions/GuildBanRemove.js +++ b/src/client/actions/GuildBanRemove.js @@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants'); class GuildBanRemove extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); const user = client.users.add(data.user); /** * Emitted whenever a member is unbanned from a guild. diff --git a/src/client/actions/GuildChannelsPositionUpdate.js b/src/client/actions/GuildChannelsPositionUpdate.js index a393167e6ec09..b21115947e895 100644 --- a/src/client/actions/GuildChannelsPositionUpdate.js +++ b/src/client/actions/GuildChannelsPositionUpdate.js @@ -6,10 +6,10 @@ class GuildChannelsPositionUpdate extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); if (guild) { for (const partialChannel of data.channels) { - const channel = guild.channels.cache.get(partialChannel.id); + const channel = guild.channels.get(partialChannel.id); if (channel) channel.rawPosition = partialChannel.position; } } diff --git a/src/client/actions/GuildDelete.js b/src/client/actions/GuildDelete.js index 69cd9143886c2..193abc47cad3a 100644 --- a/src/client/actions/GuildDelete.js +++ b/src/client/actions/GuildDelete.js @@ -12,9 +12,9 @@ class GuildDeleteAction extends Action { handle(data) { const client = this.client; - let guild = client.guilds.cache.get(data.id); + let guild = client.guilds.get(data.id); if (guild) { - for (const channel of guild.channels.cache.values()) { + for (const channel of guild.channels.values()) { if (channel.type === 'text') channel.stopTyping(true); } @@ -36,11 +36,11 @@ class GuildDeleteAction extends Action { }; } - for (const channel of guild.channels.cache.values()) this.client.channels.remove(channel.id); + for (const channel of guild.channels.values()) this.client.channels.remove(channel.id); if (guild.voice && guild.voice.connection) guild.voice.connection.disconnect(); // Delete guild - client.guilds.cache.delete(guild.id); + client.guilds.remove(guild.id); guild.deleted = true; /** diff --git a/src/client/actions/GuildEmojiDelete.js b/src/client/actions/GuildEmojiDelete.js index 42af70c12ee55..d5c973afaf340 100644 --- a/src/client/actions/GuildEmojiDelete.js +++ b/src/client/actions/GuildEmojiDelete.js @@ -5,7 +5,7 @@ const { Events } = require('../../util/Constants'); class GuildEmojiDeleteAction extends Action { handle(emoji) { - emoji.guild.emojis.cache.delete(emoji.id); + emoji.guild.emojis.remove(emoji.id); emoji.deleted = true; /** * Emitted whenever a custom emoji is deleted in a guild. diff --git a/src/client/actions/GuildEmojisUpdate.js b/src/client/actions/GuildEmojisUpdate.js index 77119333d80c0..d6902d5353dd7 100644 --- a/src/client/actions/GuildEmojisUpdate.js +++ b/src/client/actions/GuildEmojisUpdate.js @@ -4,14 +4,14 @@ const Action = require('./Action'); class GuildEmojisUpdateAction extends Action { handle(data) { - const guild = this.client.guilds.cache.get(data.guild_id); + const guild = this.client.guilds.get(data.guild_id); if (!guild || !guild.emojis) return; - const deletions = new Map(guild.emojis.cache); + const deletions = new Map(guild.emojis); for (const emoji of data.emojis) { // Determine type of emoji event - const cachedEmoji = guild.emojis.cache.get(emoji.id); + const cachedEmoji = guild.emojis.get(emoji.id); if (cachedEmoji) { deletions.delete(emoji.id); if (!cachedEmoji.equals(emoji)) { diff --git a/src/client/actions/GuildIntegrationsUpdate.js b/src/client/actions/GuildIntegrationsUpdate.js index 4129be6ad2f39..a8e910774194f 100644 --- a/src/client/actions/GuildIntegrationsUpdate.js +++ b/src/client/actions/GuildIntegrationsUpdate.js @@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants'); class GuildIntegrationsUpdate extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); /** * Emitted whenever a guild integration is updated * @event Client#guildIntegrationsUpdate diff --git a/src/client/actions/GuildMemberRemove.js b/src/client/actions/GuildMemberRemove.js index ed6c0d14452e5..28aa50386377f 100644 --- a/src/client/actions/GuildMemberRemove.js +++ b/src/client/actions/GuildMemberRemove.js @@ -6,14 +6,14 @@ const { Events, Status } = require('../../util/Constants'); class GuildMemberRemoveAction extends Action { handle(data, shard) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); let member = null; if (guild) { member = this.getMember(data, guild); guild.memberCount--; if (member) { member.deleted = true; - guild.members.cache.delete(member.id); + guild.members.remove(member.id); /** * Emitted whenever a member leaves a guild, or is kicked. * @event Client#guildMemberRemove @@ -21,7 +21,7 @@ class GuildMemberRemoveAction extends Action { */ if (shard.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member); } - guild.voiceStates.cache.delete(data.user.id); + guild.voiceStates.delete(data.user.id); } return { guild, member }; } diff --git a/src/client/actions/GuildRoleCreate.js b/src/client/actions/GuildRoleCreate.js index 65c64f36ab38e..36111f064ca0e 100644 --- a/src/client/actions/GuildRoleCreate.js +++ b/src/client/actions/GuildRoleCreate.js @@ -6,10 +6,10 @@ const { Events } = require('../../util/Constants'); class GuildRoleCreate extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); let role; if (guild) { - const already = guild.roles.cache.has(data.role.id); + const already = guild.roles.has(data.role.id); role = guild.roles.add(data.role); /** * Emitted whenever a role is created. diff --git a/src/client/actions/GuildRoleDelete.js b/src/client/actions/GuildRoleDelete.js index ec9df82337bf6..31b13b81255fe 100644 --- a/src/client/actions/GuildRoleDelete.js +++ b/src/client/actions/GuildRoleDelete.js @@ -6,13 +6,13 @@ const { Events } = require('../../util/Constants'); class GuildRoleDeleteAction extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); let role; if (guild) { - role = guild.roles.cache.get(data.role_id); + role = guild.roles.get(data.role_id); if (role) { - guild.roles.cache.delete(data.role_id); + guild.roles.remove(data.role_id); role.deleted = true; /** * Emitted whenever a guild role is deleted. diff --git a/src/client/actions/GuildRoleUpdate.js b/src/client/actions/GuildRoleUpdate.js index 631746d2a662a..bf61c7878f945 100644 --- a/src/client/actions/GuildRoleUpdate.js +++ b/src/client/actions/GuildRoleUpdate.js @@ -6,12 +6,12 @@ const { Events } = require('../../util/Constants'); class GuildRoleUpdateAction extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); if (guild) { let old = null; - const role = guild.roles.cache.get(data.role.id); + const role = guild.roles.get(data.role.id); if (role) { old = role._update(data.role); /** diff --git a/src/client/actions/GuildRolesPositionUpdate.js b/src/client/actions/GuildRolesPositionUpdate.js index d7abca97b5a37..f09f11436a897 100644 --- a/src/client/actions/GuildRolesPositionUpdate.js +++ b/src/client/actions/GuildRolesPositionUpdate.js @@ -6,10 +6,10 @@ class GuildRolesPositionUpdate extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); if (guild) { for (const partialRole of data.roles) { - const role = guild.roles.cache.get(partialRole.id); + const role = guild.roles.get(partialRole.id); if (role) role.rawPosition = partialRole.position; } } diff --git a/src/client/actions/GuildUpdate.js b/src/client/actions/GuildUpdate.js index c40fc0cde71b4..6d7cf9b4e283c 100644 --- a/src/client/actions/GuildUpdate.js +++ b/src/client/actions/GuildUpdate.js @@ -7,7 +7,7 @@ class GuildUpdateAction extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.id); + const guild = client.guilds.get(data.id); if (guild) { const old = guild._update(data); /** diff --git a/src/client/actions/InviteCreate.js b/src/client/actions/InviteCreate.js index 6381331546135..5552ea2f03805 100644 --- a/src/client/actions/InviteCreate.js +++ b/src/client/actions/InviteCreate.js @@ -7,8 +7,8 @@ const { Events } = require('../../util/Constants'); class InviteCreateAction extends Action { handle(data) { const client = this.client; - const channel = client.channels.cache.get(data.channel_id); - const guild = client.guilds.cache.get(data.guild_id); + const channel = client.channels.get(data.channel_id); + const guild = client.guilds.get(data.guild_id); if (!channel && !guild) return false; const inviteData = Object.assign(data, { channel, guild }); diff --git a/src/client/actions/InviteDelete.js b/src/client/actions/InviteDelete.js index 92692c3e2bb4b..83933d34fe5c5 100644 --- a/src/client/actions/InviteDelete.js +++ b/src/client/actions/InviteDelete.js @@ -7,8 +7,8 @@ const { Events } = require('../../util/Constants'); class InviteDeleteAction extends Action { handle(data) { const client = this.client; - const channel = client.channels.cache.get(data.channel_id); - const guild = client.guilds.cache.get(data.guild_id); + const channel = client.channels.get(data.channel_id); + const guild = client.guilds.get(data.guild_id); if (!channel && !guild) return false; const inviteData = Object.assign(data, { channel, guild }); diff --git a/src/client/actions/MessageCreate.js b/src/client/actions/MessageCreate.js index ddb56ea97a2f6..3772c4a10d0bd 100644 --- a/src/client/actions/MessageCreate.js +++ b/src/client/actions/MessageCreate.js @@ -6,9 +6,9 @@ const { Events } = require('../../util/Constants'); class MessageCreateAction extends Action { handle(data) { const client = this.client; - const channel = client.channels.cache.get(data.channel_id); + const channel = client.channels.get(data.channel_id); if (channel) { - const existing = channel.messages.cache.get(data.id); + const existing = channel.messages.get(data.id); if (existing) return { message: existing }; const message = channel.messages.add(data); const user = message.author; diff --git a/src/client/actions/MessageDelete.js b/src/client/actions/MessageDelete.js index 7869365c94f5e..feb118c1082a2 100644 --- a/src/client/actions/MessageDelete.js +++ b/src/client/actions/MessageDelete.js @@ -11,7 +11,7 @@ class MessageDeleteAction extends Action { if (channel) { message = this.getMessage(data, channel); if (message) { - channel.messages.cache.delete(message.id); + channel.messages.delete(message.id); message.deleted = true; /** * Emitted whenever a message is deleted. diff --git a/src/client/actions/MessageDeleteBulk.js b/src/client/actions/MessageDeleteBulk.js index 00fd54b51d19c..f80bc7c4db969 100644 --- a/src/client/actions/MessageDeleteBulk.js +++ b/src/client/actions/MessageDeleteBulk.js @@ -7,7 +7,7 @@ const { Events } = require('../../util/Constants'); class MessageDeleteBulkAction extends Action { handle(data) { const client = this.client; - const channel = client.channels.cache.get(data.channel_id); + const channel = client.channels.get(data.channel_id); if (channel) { const ids = data.ids; @@ -20,7 +20,7 @@ class MessageDeleteBulkAction extends Action { if (message) { message.deleted = true; messages.set(message.id, message); - channel.messages.cache.delete(id); + channel.messages.delete(id); } } diff --git a/src/client/actions/MessageReactionRemoveAll.js b/src/client/actions/MessageReactionRemoveAll.js index 14b79bf089e4b..0921ce50ef0f7 100644 --- a/src/client/actions/MessageReactionRemoveAll.js +++ b/src/client/actions/MessageReactionRemoveAll.js @@ -13,7 +13,7 @@ class MessageReactionRemoveAll extends Action { const message = this.getMessage(data, channel); if (!message) return false; - message.reactions.cache.clear(); + message.reactions.clear(); this.client.emit(Events.MESSAGE_REACTION_REMOVE_ALL, message); return { message }; diff --git a/src/client/actions/MessageReactionRemoveEmoji.js b/src/client/actions/MessageReactionRemoveEmoji.js index 143702c008f78..ab0eaa7708ea6 100644 --- a/src/client/actions/MessageReactionRemoveEmoji.js +++ b/src/client/actions/MessageReactionRemoveEmoji.js @@ -13,7 +13,7 @@ class MessageReactionRemoveEmoji extends Action { const reaction = this.getReaction(data, message); if (!reaction) return false; - if (!message.partial) message.reactions.cache.delete(reaction.emoji.id || reaction.emoji.name); + if (!message.partial) message.reactions.delete(reaction.emoji.id || reaction.emoji.name); /** * Emitted when a bot removes an emoji reaction from a cached message. diff --git a/src/client/actions/PresenceUpdate.js b/src/client/actions/PresenceUpdate.js index f74fbeb5d3e5e..538789e251195 100644 --- a/src/client/actions/PresenceUpdate.js +++ b/src/client/actions/PresenceUpdate.js @@ -5,7 +5,7 @@ const { Events } = require('../../util/Constants'); class PresenceUpdateAction extends Action { handle(data) { - let user = this.client.users.cache.get(data.user.id); + let user = this.client.users.get(data.user.id); if (!user && data.user.username) user = this.client.users.add(data.user); if (!user) return; @@ -13,12 +13,12 @@ class PresenceUpdateAction extends Action { if (!user.equals(data.user)) this.client.actions.UserUpdate.handle(data.user); } - const guild = this.client.guilds.cache.get(data.guild_id); + const guild = this.client.guilds.get(data.guild_id); if (!guild) return; - let oldPresence = guild.presences.cache.get(user.id); + let oldPresence = guild.presences.get(user.id); if (oldPresence) oldPresence = oldPresence._clone(); - let member = guild.members.cache.get(user.id); + let member = guild.members.get(user.id); if (!member && data.status !== 'offline') { member = guild.members.add({ user, diff --git a/src/client/actions/UserUpdate.js b/src/client/actions/UserUpdate.js index 7279ca7dd5cf9..a762511f45cde 100644 --- a/src/client/actions/UserUpdate.js +++ b/src/client/actions/UserUpdate.js @@ -7,7 +7,7 @@ class UserUpdateAction extends Action { handle(data) { const client = this.client; - const newUser = client.users.cache.get(data.id); + const newUser = client.users.get(data.id); const oldUser = newUser._update(data); if (!oldUser.equals(newUser)) { diff --git a/src/client/actions/VoiceStateUpdate.js b/src/client/actions/VoiceStateUpdate.js index b2a4b11bd92b5..386bf77834742 100644 --- a/src/client/actions/VoiceStateUpdate.js +++ b/src/client/actions/VoiceStateUpdate.js @@ -7,17 +7,17 @@ const VoiceState = require('../../structures/VoiceState'); class VoiceStateUpdate extends Action { handle(data) { const client = this.client; - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); if (guild) { // Update the state - const oldState = guild.voiceStates.cache.has(data.user_id) ? - guild.voiceStates.cache.get(data.user_id)._clone() : + const oldState = guild.voiceStates.has(data.user_id) ? + guild.voiceStates.get(data.user_id)._clone() : new VoiceState(guild, { user_id: data.user_id }); const newState = guild.voiceStates.add(data); // Get the member - let member = guild.members.cache.get(data.user_id); + let member = guild.members.get(data.user_id); if (member && data.member) { member._patch(data.member); } else if (data.member && data.member.user && data.member.joined_at) { diff --git a/src/client/actions/WebhooksUpdate.js b/src/client/actions/WebhooksUpdate.js index f6a515b2c75e3..69e28aecb58a5 100644 --- a/src/client/actions/WebhooksUpdate.js +++ b/src/client/actions/WebhooksUpdate.js @@ -6,7 +6,7 @@ const { Events } = require('../../util/Constants'); class WebhooksUpdate extends Action { handle(data) { const client = this.client; - const channel = client.channels.cache.get(data.channel_id); + const channel = client.channels.get(data.channel_id); /** * Emitted whenever a guild text channel has its webhooks changed. * @event Client#webhookUpdate diff --git a/src/client/voice/ClientVoiceManager.js b/src/client/voice/ClientVoiceManager.js index fbf5d1ba12451..cf752662393de 100644 --- a/src/client/voice/ClientVoiceManager.js +++ b/src/client/voice/ClientVoiceManager.js @@ -56,7 +56,7 @@ class ClientVoiceManager { this.connections.delete(guild_id); return; } - connection.channel = this.client.channels.cache.get(channel_id); + connection.channel = this.client.channels.get(channel_id); connection.setSessionID(session_id); } diff --git a/src/client/voice/VoiceConnection.js b/src/client/voice/VoiceConnection.js index 050775b602ca9..b4b1e9da18152 100644 --- a/src/client/voice/VoiceConnection.js +++ b/src/client/voice/VoiceConnection.js @@ -483,7 +483,7 @@ class VoiceConnection extends EventEmitter { onSpeaking({ user_id, speaking }) { speaking = new Speaking(speaking).freeze(); const guild = this.channel.guild; - const user = this.client.users.cache.get(user_id); + const user = this.client.users.get(user_id); const old = this._speaking.get(user_id); this._speaking.set(user_id, speaking); /** diff --git a/src/client/websocket/WebSocketManager.js b/src/client/websocket/WebSocketManager.js index 02139f484adf8..3e299c58d16d5 100644 --- a/src/client/websocket/WebSocketManager.js +++ b/src/client/websocket/WebSocketManager.js @@ -408,7 +408,7 @@ class WebSocketManager extends EventEmitter { if (this.client.options.fetchAllMembers) { try { - const promises = this.client.guilds.cache.map(guild => { + const promises = this.client.guilds.map(guild => { if (guild.available) return guild.members.fetch(); // Return empty promise if guild is unavailable return Promise.resolve(); diff --git a/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js b/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js index 13e6f0faf0c26..6da643ff3f291 100644 --- a/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js +++ b/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js @@ -3,7 +3,7 @@ const { Events } = require('../../../util/Constants'); module.exports = (client, { d: data }) => { - const channel = client.channels.cache.get(data.channel_id); + const channel = client.channels.get(data.channel_id); const time = new Date(data.last_pin_timestamp); if (channel && !Number.isNaN(time.getTime())) { diff --git a/src/client/websocket/handlers/GUILD_BAN_ADD.js b/src/client/websocket/handlers/GUILD_BAN_ADD.js index 5d4a0965c7b58..cbb60e13c82dc 100644 --- a/src/client/websocket/handlers/GUILD_BAN_ADD.js +++ b/src/client/websocket/handlers/GUILD_BAN_ADD.js @@ -3,7 +3,7 @@ const { Events } = require('../../../util/Constants'); module.exports = (client, { d: data }) => { - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); const user = client.users.add(data.user); /** diff --git a/src/client/websocket/handlers/GUILD_CREATE.js b/src/client/websocket/handlers/GUILD_CREATE.js index eb897443556c9..33cc0c239fca7 100644 --- a/src/client/websocket/handlers/GUILD_CREATE.js +++ b/src/client/websocket/handlers/GUILD_CREATE.js @@ -3,7 +3,7 @@ const { Events, Status } = require('../../../util/Constants'); module.exports = async (client, { d: data }, shard) => { - let guild = client.guilds.cache.get(data.id); + let guild = client.guilds.get(data.id); if (guild) { if (!guild.available && !data.unavailable) { // A newly available guild diff --git a/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js b/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js index 9a0a880a7b97f..0738eaa672416 100644 --- a/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +++ b/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js @@ -4,7 +4,7 @@ const { Events } = require('../../../util/Constants'); const Collection = require('../../../util/Collection'); module.exports = (client, { d: data }) => { - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); if (!guild) return; const members = new Collection(); diff --git a/src/client/websocket/handlers/GUILD_MEMBER_ADD.js b/src/client/websocket/handlers/GUILD_MEMBER_ADD.js index 964e3da26051c..796b6c376b2ec 100644 --- a/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +++ b/src/client/websocket/handlers/GUILD_MEMBER_ADD.js @@ -3,7 +3,7 @@ const { Events, Status } = require('../../../util/Constants'); module.exports = (client, { d: data }, shard) => { - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); if (guild) { guild.memberCount++; const member = guild.members.add(data); diff --git a/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js b/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js index 92c9da6c5fd9b..9341329a39689 100644 --- a/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js +++ b/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js @@ -3,9 +3,9 @@ const { Status, Events } = require('../../../util/Constants'); module.exports = (client, { d: data }, shard) => { - const guild = client.guilds.cache.get(data.guild_id); + const guild = client.guilds.get(data.guild_id); if (guild) { - const member = guild.members.cache.get(data.user.id); + const member = guild.members.get(data.user.id); if (member) { const old = member._update(data); if (shard.status === Status.READY) { diff --git a/src/client/websocket/handlers/READY.js b/src/client/websocket/handlers/READY.js index c38b681c4ba66..00257502398af 100644 --- a/src/client/websocket/handlers/READY.js +++ b/src/client/websocket/handlers/READY.js @@ -9,7 +9,7 @@ module.exports = (client, { d: data }, shard) => { if (!ClientUser) ClientUser = require('../../../structures/ClientUser'); const clientUser = new ClientUser(client, data.user); client.user = clientUser; - client.users.cache.set(clientUser.id, clientUser); + client.users.set(clientUser.id, clientUser); } for (const guild of data.guilds) { diff --git a/src/client/websocket/handlers/TYPING_START.js b/src/client/websocket/handlers/TYPING_START.js index 92e0125f2b2f8..9df76dc75af38 100644 --- a/src/client/websocket/handlers/TYPING_START.js +++ b/src/client/websocket/handlers/TYPING_START.js @@ -3,8 +3,8 @@ const { Events } = require('../../../util/Constants'); module.exports = (client, { d: data }) => { - const channel = client.channels.cache.get(data.channel_id); - const user = client.users.cache.get(data.user_id); + const channel = client.channels.get(data.channel_id); + const user = client.users.get(data.user_id); if (channel && user) { /** diff --git a/src/index.js b/src/index.js index 155d2f539ffc1..896919c40e5eb 100644 --- a/src/index.js +++ b/src/index.js @@ -17,8 +17,7 @@ module.exports = { Collection: require('./util/Collection'), Constants: require('./util/Constants'), DataResolver: require('./util/DataResolver'), - LimitedCollection: require('./util/LimitedCollection'), - BaseManager: require('./managers/BaseManager'), + DataStore: require('./stores/DataStore'), DiscordAPIError: require('./rest/DiscordAPIError'), HTTPError: require('./rest/HTTPError'), MessageFlags: require('./util/MessageFlags'), @@ -31,19 +30,19 @@ module.exports = { Util: Util, version: require('../package.json').version, - // Managers - ChannelManager: require('./managers/ChannelManager'), - GuildChannelManager: require('./managers/GuildChannelManager'), - GuildEmojiManager: require('./managers/GuildEmojiManager'), - GuildEmojiRoleManager: require('./managers/GuildEmojiRoleManager'), - GuildMemberManager: require('./managers/GuildMemberManager'), - GuildMemberRoleManager: require('./managers/GuildMemberRoleManager'), - GuildManager: require('./managers/GuildManager'), - ReactionUserManager: require('./managers/ReactionUserManager'), - MessageManager: require('./managers/MessageManager'), - PresenceManager: require('./managers/PresenceManager'), - RoleManager: require('./managers/RoleManager'), - UserManager: require('./managers/UserManager'), + // Stores + ChannelStore: require('./stores/ChannelStore'), + GuildChannelStore: require('./stores/GuildChannelStore'), + GuildEmojiStore: require('./stores/GuildEmojiStore'), + GuildEmojiRoleStore: require('./stores/GuildEmojiRoleStore'), + GuildMemberStore: require('./stores/GuildMemberStore'), + GuildMemberRoleStore: require('./stores/GuildMemberRoleStore'), + GuildStore: require('./stores/GuildStore'), + ReactionUserStore: require('./stores/ReactionUserStore'), + MessageStore: require('./stores/MessageStore'), + PresenceStore: require('./stores/PresenceStore'), + RoleStore: require('./stores/RoleStore'), + UserStore: require('./stores/UserStore'), // Shortcuts to Util methods discordSort: Util.discordSort, diff --git a/src/managers/MessageManager.js b/src/managers/MessageManager.js deleted file mode 100644 index 19eb82b8c5508..0000000000000 --- a/src/managers/MessageManager.js +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -const BaseManager = require('./BaseManager'); -const Message = require('../structures/Message'); -const LimitedCollection = require('../util/LimitedCollection'); -const Collection = require('../util/Collection'); - -/** -* Manages API methods for Messages and holds their cache. -* @extends {BaseManager} -*/ -class MessageManager extends BaseManager { - constructor(channel, iterable) { - super(channel.client, iterable, Message, LimitedCollection, channel.client.options.messageCacheMaxSize); - /** - * The channel that the messages belong to - * @type {TextBasedChannel} - */ - this.channel = channel; - } - - /** - * The cache of Messages - * @property {LimitedCollection} cache - * @memberof MessageManager - * @instance - */ - - add(data, cache) { - return super.add(data, cache, { extras: [this.channel] }); - } - - /** - * The parameters to pass in when requesting previous messages from a channel. `around`, `before` and - * `after` are mutually exclusive. All the parameters are optional. - * @typedef {Object} ChannelLogsQueryOptions - * @property {number} [limit=50] Number of messages to acquire - * @property {Snowflake} [before] ID of a message to get the messages that were posted before it - * @property {Snowflake} [after] ID of a message to get the messages that were posted after it - * @property {Snowflake} [around] ID of a message to get the messages that were posted around it - */ - - /** - * Gets a message, or messages, from this channel. - * The returned Collection does not contain reaction users of the messages if they were not cached. - * Those need to be fetched separately in such a case. - * @param {Snowflake|ChannelLogsQueryOptions} [message] The ID of the message to fetch, or query parameters. - * @param {boolean} [cache=true] Whether to cache the message(s) - * @returns {Promise|Promise>} - * @example - * // Get message - * channel.messages.fetch('99539446449315840') - * .then(message => console.log(message.content)) - * .catch(console.error); - * @example - * // Get messages - * channel.messages.fetch({ limit: 10 }) - * .then(messages => console.log(`Received ${messages.size} messages`)) - * .catch(console.error); - * @example - * // Get messages and filter by user ID - * channel.messages.fetch() - * .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`)) - * .catch(console.error); - */ - fetch(message, cache = true) { - return typeof message === 'string' ? this._fetchId(message, cache) : this._fetchMany(message, cache); - } - - /** - * Fetches the pinned messages of this channel and returns a collection of them. - * The returned Collection does not contain any reaction data of the messages. - * Those need to be fetched separately. - * @param {boolean} [cache=true] Whether to cache the message(s) - * @returns {Promise>} - * @example - * // Get pinned messages - * channel.fetchPinned() - * .then(messages => console.log(`Received ${messages.size} messages`)) - * .catch(console.error); - */ - fetchPinned(cache = true) { - return this.client.api.channels[this.channel.id].pins.get().then(data => { - const messages = new Collection(); - for (const message of data) messages.set(message.id, this.add(message, cache)); - return messages; - }); - } - - /** - * Data that can be resolved to a Message object. This can be: - * * A Message - * * A Snowflake - * @typedef {Message|Snowflake} MessageResolvable - */ - - /** - * Resolves a MessageResolvable to a Message object. - * @method resolve - * @memberof MessageManager - * @instance - * @param {MessageResolvable} message The message resolvable to resolve - * @returns {?Message} - */ - - /** - * Resolves a MessageResolvable to a Message ID string. - * @method resolveID - * @memberof MessageManager - * @instance - * @param {MessageResolvable} message The message resolvable to resolve - * @returns {?Snowflake} - */ - - - /** - * Deletes a message, even if it's not cached. - * @param {MessageResolvable} message The message to delete - * @param {string} [reason] Reason for deleting this message, if it does not belong to the client user - */ - async delete(message, reason) { - message = this.resolveID(message); - if (message) await this.client.api.channels(this.channel.id).messages(message).delete({ reason }); - } - - async _fetchId(messageID, cache) { - const existing = this.cache.get(messageID); - if (existing && !existing.partial) return existing; - const data = await this.client.api.channels[this.channel.id].messages[messageID].get(); - return this.add(data, cache); - } - - async _fetchMany(options = {}, cache) { - const data = await this.client.api.channels[this.channel.id].messages.get({ query: options }); - const messages = new Collection(); - for (const message of data) messages.set(message.id, this.add(message, cache)); - return messages; - } -} - -module.exports = MessageManager; diff --git a/src/managers/VoiceStateManager.js b/src/managers/VoiceStateManager.js deleted file mode 100644 index 755392b2d28b0..0000000000000 --- a/src/managers/VoiceStateManager.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const BaseManager = require('./BaseManager'); -const VoiceState = require('../structures/VoiceState'); - -/** - * Manages API methods for VoiceStates and stores their cache. - * @extends {BaseManager} - */ -class VoiceStateManager extends BaseManager { - constructor(guild, iterable) { - super(guild.client, iterable, VoiceState); - /** - * The guild this manager belongs to - * @type {Guild} - */ - this.guild = guild; - } - - /** - * The cache of this manager - * @property {Collection} cache - * @memberof VoiceStateManager - * @instance - */ - - add(data, cache = true) { - const existing = this.cache.get(data.user_id); - if (existing) return existing._patch(data); - - const entry = new VoiceState(this.guild, data); - if (cache) this.cache.set(data.user_id, entry); - return entry; - } -} - -module.exports = VoiceStateManager; diff --git a/src/sharding/ShardClientUtil.js b/src/sharding/ShardClientUtil.js index 8b76efd6ffced..8ed1b9787e7a4 100644 --- a/src/sharding/ShardClientUtil.js +++ b/src/sharding/ShardClientUtil.js @@ -86,7 +86,7 @@ class ShardClientUtil { * @param {string} prop Name of the client property to get, using periods for nesting * @returns {Promise>} * @example - * client.shard.fetchClientValues('guilds.cache.size') + * client.shard.fetchClientValues('guilds.size') * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`)) * .catch(console.error); * @see {@link ShardingManager#fetchClientValues} @@ -114,7 +114,7 @@ class ShardClientUtil { * @param {string|Function} script JavaScript to run on each shard * @returns {Promise>} Results of the script execution * @example - * client.shard.broadcastEval('this.guilds.cache.size') + * client.shard.broadcastEval('this.guilds.size') * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`)) * .catch(console.error); * @see {@link ShardingManager#broadcastEval} diff --git a/src/sharding/ShardingManager.js b/src/sharding/ShardingManager.js index b6818d3066358..7126148d0266b 100644 --- a/src/sharding/ShardingManager.js +++ b/src/sharding/ShardingManager.js @@ -229,7 +229,7 @@ class ShardingManager extends EventEmitter { * @param {string} prop Name of the client property to get, using periods for nesting * @returns {Promise>} * @example - * manager.fetchClientValues('guilds.cache.size') + * manager.fetchClientValues('guilds.size') * .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`)) * .catch(console.error); */ diff --git a/src/managers/ChannelManager.js b/src/stores/ChannelStore.js similarity index 52% rename from src/managers/ChannelManager.js rename to src/stores/ChannelStore.js index dcb098c139bb5..762f0e193eefa 100644 --- a/src/managers/ChannelManager.js +++ b/src/stores/ChannelStore.js @@ -1,26 +1,59 @@ 'use strict'; +const DataStore = require('./DataStore'); const Channel = require('../structures/Channel'); -const BaseManager = require('./BaseManager'); const { Events } = require('../util/Constants'); +const kLru = Symbol('LRU'); +const lruable = ['dm']; + /** - * A manager of channels belonging to a client + * Stores channels. + * @extends {DataStore} */ -class ChannelManager extends BaseManager { - constructor(client, iterable) { - super(client, iterable, Channel); +class ChannelStore extends DataStore { + constructor(client, iterableOrOptions = {}, options) { + if (!options && typeof iterableOrOptions[Symbol.iterator] !== 'function') { + options = iterableOrOptions; + iterableOrOptions = undefined; + } + super(client, iterableOrOptions, Channel); + + if (options.lru) { + const lru = this[kLru] = []; + lru.add = item => { + lru.remove(item); + lru.unshift(item); + while (lru.length > options.lru) this.remove(lru[lru.length - 1]); + }; + lru.remove = item => { + const index = lru.indexOf(item); + if (index > -1) lru.splice(index, 1); + }; + } } - /** - * The cache of Channels - * @property {Collection} cache - * @memberof ChannelManager - * @instance - */ + get(key, peek = false) { + const item = super.get(key); + if (!item || !lruable.includes(item.type)) return item; + if (!peek && this[kLru]) this[kLru].add(key); + return item; + } + + set(key, val) { + if (this[kLru] && lruable.includes(val.type)) this[kLru].add(key); + return super.set(key, val); + } + + delete(key) { + const item = this.get(key, true); + if (!item) return false; + if (this[kLru] && lruable.includes(item.type)) this[kLru].remove(key); + return super.delete(key); + } add(data, guild, cache = true) { - const existing = this.cache.get(data.id); + const existing = this.get(data.id); if (existing) { if (existing._patch && cache) existing._patch(data); if (guild) guild.channels.add(existing); @@ -34,15 +67,15 @@ class ChannelManager extends BaseManager { return null; } - if (cache) this.cache.set(channel.id, channel); + if (cache) this.set(channel.id, channel); return channel; } remove(id) { - const channel = this.cache.get(id); - if (channel.guild) channel.guild.channels.cache.delete(id); - this.cache.delete(id); + const channel = this.get(id); + if (channel.guild) channel.guild.channels.remove(id); + super.remove(id); } /** @@ -55,7 +88,7 @@ class ChannelManager extends BaseManager { /** * Resolves a ChannelResolvable to a Channel object. * @method resolve - * @memberof ChannelManager + * @memberof ChannelStore * @instance * @param {ChannelResolvable} channel The channel resolvable to resolve * @returns {?Channel} @@ -64,7 +97,7 @@ class ChannelManager extends BaseManager { /** * Resolves a ChannelResolvable to a channel ID string. * @method resolveID - * @memberof ChannelManager + * @memberof ChannelStore * @instance * @param {ChannelResolvable} channel The channel resolvable to resolve * @returns {?Snowflake} @@ -82,7 +115,7 @@ class ChannelManager extends BaseManager { * .catch(console.error); */ async fetch(id, cache = true) { - const existing = this.cache.get(id); + const existing = this.get(id); if (existing && !existing.partial) return existing; const data = await this.client.api.channels(id).get(); @@ -90,4 +123,4 @@ class ChannelManager extends BaseManager { } } -module.exports = ChannelManager; +module.exports = ChannelStore; diff --git a/src/managers/BaseManager.js b/src/stores/DataStore.js similarity index 50% rename from src/managers/BaseManager.js rename to src/stores/DataStore.js index b9d0be938469f..be1e93d79007a 100644 --- a/src/managers/BaseManager.js +++ b/src/stores/DataStore.js @@ -4,67 +4,44 @@ const Collection = require('../util/Collection'); let Structures; /** - * Manages the API methods of a data model and holds its cache. - * @abstract + * Manages the creation, retrieval and deletion of a specific data model. + * @extends {Collection} */ -class BaseManager { - constructor(client, iterable, holds, cacheType = Collection, ...cacheOptions) { +class DataStore extends Collection { + constructor(client, iterable, holds) { + super(); if (!Structures) Structures = require('../util/Structures'); - /** - * The data structure belonging to this manager - * @name BaseManager#holds - * @type {Function} - * @private - * @readonly - */ - Object.defineProperty(this, 'holds', { value: Structures.get(holds.name) || holds }); - - /** - * The client that instantiated this Manager - * @name BaseManager#client - * @type {Client} - * @readonly - */ Object.defineProperty(this, 'client', { value: client }); - - /** - * The type of Collection of the Manager - * @type {Collection} - */ - this.cacheType = cacheType; - - /** - * Holds the cache for the data model - * @type {?Collection} - */ - this.cache = new cacheType(...cacheOptions); - if (iterable) for (const i of iterable) this.add(i); + Object.defineProperty(this, 'holds', { value: Structures.get(holds.name) || holds }); + if (iterable) for (const item of iterable) this.add(item); } add(data, cache = true, { id, extras = [] } = {}) { - const existing = this.cache.get(id || data.id); + const existing = this.get(id || data.id); if (existing && existing._patch && cache) existing._patch(data); if (existing) return existing; const entry = this.holds ? new this.holds(this.client, data, ...extras) : data; - if (cache) this.cache.set(id || entry.id, entry); + if (cache) this.set(id || entry.id, entry); return entry; } + remove(key) { return this.delete(key); } + /** * Resolves a data entry to a data Object. - * @param {string|Object} idOrInstance The id or instance of something in this Manager - * @returns {?Object} An instance from this Manager + * @param {string|Object} idOrInstance The id or instance of something in this DataStore + * @returns {?Object} An instance from this DataStore */ resolve(idOrInstance) { if (idOrInstance instanceof this.holds) return idOrInstance; - if (typeof idOrInstance === 'string') return this.cache.get(idOrInstance) || null; + if (typeof idOrInstance === 'string') return this.get(idOrInstance) || null; return null; } /** * Resolves a data entry to a instance ID. - * @param {string|Instance} idOrInstance The id or instance of something in this Manager + * @param {string|Instance} idOrInstance The id or instance of something in this DataStore * @returns {?Snowflake} */ resolveID(idOrInstance) { @@ -72,6 +49,10 @@ class BaseManager { if (typeof idOrInstance === 'string') return idOrInstance; return null; } + + static get [Symbol.species]() { + return Collection; + } } -module.exports = BaseManager; +module.exports = DataStore; diff --git a/src/managers/GuildChannelManager.js b/src/stores/GuildChannelStore.js similarity index 85% rename from src/managers/GuildChannelManager.js rename to src/stores/GuildChannelStore.js index 147a0b207b23c..552b40f005b4b 100644 --- a/src/managers/GuildChannelManager.js +++ b/src/stores/GuildChannelStore.js @@ -1,36 +1,24 @@ 'use strict'; const { ChannelTypes } = require('../util/Constants'); -const BaseManager = require('./BaseManager'); +const DataStore = require('./DataStore'); const GuildChannel = require('../structures/GuildChannel'); const PermissionOverwrites = require('../structures/PermissionOverwrites'); /** - * Manages API methods for GuildChannels and stores their cache. - * @extends {BaseManager} + * Stores guild channels. + * @extends {DataStore} */ -class GuildChannelManager extends BaseManager { +class GuildChannelStore extends DataStore { constructor(guild, iterable) { super(guild.client, iterable, GuildChannel); - - /** - * The guild this Manager belongs to - * @type {Guild} - */ this.guild = guild; } - /** - * The cache of this Manager - * @property {Collection} cache - * @memberof GuildChannelManager - * @instance - */ - add(channel) { - const existing = this.cache.get(channel.id); + const existing = this.get(channel.id); if (existing) return existing; - this.cache.set(channel.id, channel); + this.set(channel.id, channel); return channel; } @@ -44,7 +32,7 @@ class GuildChannelManager extends BaseManager { /** * Resolves a GuildChannelResolvable to a Channel object. * @method resolve - * @memberof GuildChannelManager + * @memberof GuildChannelStore * @instance * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve * @returns {?Channel} @@ -53,7 +41,7 @@ class GuildChannelManager extends BaseManager { /** * Resolves a GuildChannelResolvable to a channel ID string. * @method resolveID - * @memberof GuildChannelManager + * @memberof GuildChannelStore * @instance * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve * @returns {?Snowflake} @@ -129,4 +117,4 @@ class GuildChannelManager extends BaseManager { } } -module.exports = GuildChannelManager; +module.exports = GuildChannelStore; diff --git a/src/managers/GuildEmojiRoleManager.js b/src/stores/GuildEmojiRoleStore.js similarity index 73% rename from src/managers/GuildEmojiRoleManager.js rename to src/stores/GuildEmojiRoleStore.js index 5775955883e12..6db2003ed14a2 100644 --- a/src/managers/GuildEmojiRoleManager.js +++ b/src/stores/GuildEmojiRoleStore.js @@ -1,28 +1,18 @@ 'use strict'; const Collection = require('../util/Collection'); +const Util = require('../util/Util'); const { TypeError } = require('../errors'); /** - * Manages API methods for roles belonging to emojis and stores their cache. + * Stores emoji roles + * @extends {Collection} */ -class GuildEmojiRoleManager { +class GuildEmojiRoleStore extends Collection { constructor(emoji) { - /** - * The emoji belonging to this manager - * @type {GuildEmoji} - */ + super(); this.emoji = emoji; - /** - * The guild belonging to this manager - * @type {Guild} - */ this.guild = emoji.guild; - /** - * The client belonging to this manager - * @type {Client} - * @readonly - */ Object.defineProperty(this, 'client', { value: emoji.client }); } @@ -32,17 +22,8 @@ class GuildEmojiRoleManager { * @private * @readonly */ - get _roles() { - return this.guild.roles.cache.filter(role => this.emoji._roles.includes(role.id)); - } - - /** - * The cache of roles belonging to this emoji - * @type {Collection} - * @readonly - */ - get cache() { - return this._roles; + get _filtered() { + return this.guild.roles.filter(role => this.emoji._roles.includes(role.id)); } /** @@ -60,7 +41,7 @@ class GuildEmojiRoleManager { 'Array or Collection of Roles or Snowflakes', true)); } - const newRoles = [...new Set(roleOrRoles.concat(...this._roles.values()))]; + const newRoles = [...new Set(roleOrRoles.concat(...this.values()))]; return this.set(newRoles); } @@ -79,7 +60,7 @@ class GuildEmojiRoleManager { 'Array or Collection of Roles or Snowflakes', true)); } - const newRoles = this._roles.keyArray().filter(role => !roleOrRoles.includes(role)); + const newRoles = this.keyArray().filter(role => !roleOrRoles.includes(role)); return this.set(newRoles); } @@ -104,18 +85,32 @@ class GuildEmojiRoleManager { clone() { const clone = new this.constructor(this.emoji); - clone._patch(this._roles.keyArray().slice()); + clone._patch(this.keyArray().slice()); return clone; } /** - * Patches the roles for this manager's cache + * Patches the roles for this store * @param {Snowflake[]} roles The new roles * @private */ _patch(roles) { this.emoji._roles = roles; } + + *[Symbol.iterator]() { + yield* this._filtered.entries(); + } + + valueOf() { + return this._filtered; + } + + static get [Symbol.species]() { + return Collection; + } } -module.exports = GuildEmojiRoleManager; +Util.mixin(GuildEmojiRoleStore, ['set']); + +module.exports = GuildEmojiRoleStore; diff --git a/src/managers/GuildEmojiManager.js b/src/stores/GuildEmojiStore.js similarity index 89% rename from src/managers/GuildEmojiManager.js rename to src/stores/GuildEmojiStore.js index 27ac363ca9aab..b992a68c92ed3 100644 --- a/src/managers/GuildEmojiManager.js +++ b/src/stores/GuildEmojiStore.js @@ -1,33 +1,22 @@ 'use strict'; const Collection = require('../util/Collection'); -const BaseManager = require('./BaseManager'); +const DataStore = require('./DataStore'); const GuildEmoji = require('../structures/GuildEmoji'); const ReactionEmoji = require('../structures/ReactionEmoji'); const DataResolver = require('../util/DataResolver'); const { TypeError } = require('../errors'); /** - * Manages API methods for GuildEmojis and stores their cache. - * @extends {BaseManager} + * Stores guild emojis. + * @extends {DataStore} */ -class GuildEmojiManager extends BaseManager { +class GuildEmojiStore extends DataStore { constructor(guild, iterable) { super(guild.client, iterable, GuildEmoji); - /** - * The guild this manager belongs to - * @type {Guild} - */ this.guild = guild; } - /** - * The cache of GuildEmojis - * @property {Collection} cache - * @memberof GuildEmojiManager - * @instance - */ - add(data, cache) { return super.add(data, cache, { extras: [this.guild] }); } @@ -125,4 +114,4 @@ class GuildEmojiManager extends BaseManager { } } -module.exports = GuildEmojiManager; +module.exports = GuildEmojiStore; diff --git a/src/managers/GuildMemberRoleManager.js b/src/stores/GuildMemberRoleStore.js similarity index 77% rename from src/managers/GuildMemberRoleManager.js rename to src/stores/GuildMemberRoleStore.js index d9186f90e21fd..047b8086ae32f 100644 --- a/src/managers/GuildMemberRoleManager.js +++ b/src/stores/GuildMemberRoleStore.js @@ -1,22 +1,17 @@ 'use strict'; const Collection = require('../util/Collection'); +const Util = require('../util/Util'); const { TypeError } = require('../errors'); /** - * Manages API methods for roles of a GuildMember and stores their cache. + * Stores member roles + * @extends {Collection} */ -class GuildMemberRoleManager { +class GuildMemberRoleStore extends Collection { constructor(member) { - /** - * The GuildMember this manager belongs to - * @type {GuildMember} - */ + super(); this.member = member; - /** - * The Guild this manager belongs to - * @type {Guild} - */ this.guild = member.guild; Object.defineProperty(this, 'client', { value: member.client }); } @@ -27,18 +22,9 @@ class GuildMemberRoleManager { * @private * @readonly */ - get _roles() { + get _filtered() { const everyone = this.guild.roles.everyone; - return this.guild.roles.cache.filter(role => this.member._roles.includes(role.id)).set(everyone.id, everyone); - } - - /** - * The roles of this member - * @type {Collection} - * @readonly - */ - get cache() { - return this._roles; + return this.guild.roles.filter(role => this.member._roles.includes(role.id)).set(everyone.id, everyone); } /** @@ -47,7 +33,7 @@ class GuildMemberRoleManager { * @readonly */ get hoist() { - const hoistedRoles = this._roles.filter(role => role.hoist); + const hoistedRoles = this._filtered.filter(role => role.hoist); if (!hoistedRoles.size) return null; return hoistedRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev); } @@ -58,7 +44,7 @@ class GuildMemberRoleManager { * @readonly */ get color() { - const coloredRoles = this._roles.filter(role => role.color); + const coloredRoles = this._filtered.filter(role => role.color); if (!coloredRoles.size) return null; return coloredRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev); } @@ -69,7 +55,7 @@ class GuildMemberRoleManager { * @readonly */ get highest() { - return this._roles.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this._roles.first()); + return this._filtered.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this.first()); } /** @@ -86,7 +72,7 @@ class GuildMemberRoleManager { 'Array or Collection of Roles or Snowflakes', true); } - const newRoles = [...new Set(roleOrRoles.concat(...this._roles.values()))]; + const newRoles = [...new Set(roleOrRoles.concat(...this.values()))]; return this.set(newRoles, reason); } else { roleOrRoles = this.guild.roles.resolve(roleOrRoles); @@ -98,7 +84,7 @@ class GuildMemberRoleManager { await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].put({ reason }); const clone = this.member._clone(); - clone._roles = [...this._roles.keys(), roleOrRoles.id]; + clone._roles = [...this.keys(), roleOrRoles.id]; return clone; } } @@ -117,7 +103,7 @@ class GuildMemberRoleManager { 'Array or Collection of Roles or Snowflakes', true); } - const newRoles = this._roles.filter(role => !roleOrRoles.includes(role)); + const newRoles = this.filter(role => !roleOrRoles.includes(role)); return this.set(newRoles, reason); } else { roleOrRoles = this.guild.roles.resolve(roleOrRoles); @@ -129,7 +115,7 @@ class GuildMemberRoleManager { await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].delete({ reason }); const clone = this.member._clone(); - const newRoles = this._roles.filter(role => role.id !== roleOrRoles.id); + const newRoles = this.filter(role => role.id !== roleOrRoles.id); clone._roles = [...newRoles.keys()]; return clone; } @@ -148,7 +134,7 @@ class GuildMemberRoleManager { * @example * // Remove all the roles from a member * guildMember.roles.set([]) - * .then(member => console.log(`Member roles is now of ${member.roles.cache.size} size`)) + * .then(member => console.log(`Member roles is now of ${member.roles.size} size`)) * .catch(console.error); */ set(roles, reason) { @@ -157,9 +143,23 @@ class GuildMemberRoleManager { clone() { const clone = new this.constructor(this.member); - clone.member._roles = [...this._roles.keyArray()]; + clone.member._roles = [...this.keyArray()]; return clone; } + + *[Symbol.iterator]() { + yield* this._filtered.entries(); + } + + valueOf() { + return this._filtered; + } + + static get [Symbol.species]() { + return Collection; + } } -module.exports = GuildMemberRoleManager; +Util.mixin(GuildMemberRoleStore, ['set']); + +module.exports = GuildMemberRoleStore; diff --git a/src/managers/GuildMemberManager.js b/src/stores/GuildMemberStore.js similarity index 91% rename from src/managers/GuildMemberManager.js rename to src/stores/GuildMemberStore.js index b7d49f5c345b9..7abc81cafc304 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/stores/GuildMemberStore.js @@ -1,32 +1,21 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const DataStore = require('./DataStore'); const GuildMember = require('../structures/GuildMember'); const { Events, OPCodes } = require('../util/Constants'); const Collection = require('../util/Collection'); const { Error, TypeError } = require('../errors'); /** - * Manages API methods for GuildMembers and stores their cache. - * @extends {BaseManager} + * Stores guild members. + * @extends {DataStore} */ -class GuildMemberManager extends BaseManager { +class GuildMemberStore extends DataStore { constructor(guild, iterable) { super(guild.client, iterable, GuildMember); - /** - * The guild this manager belongs to - * @type {Guild} - */ this.guild = guild; } - /** - * The cache of this Manager - * @property {Collection} cache - * @memberof GuildMemberManager - * @instance - */ - add(data, cache = true) { return super.add(data, cache, { id: data.user.id, extras: [this.guild] }); } @@ -60,7 +49,7 @@ class GuildMemberManager extends BaseManager { const memberResolvable = super.resolveID(member); if (memberResolvable) return memberResolvable; const userResolvable = this.client.users.resolveID(member); - return this.cache.has(userResolvable) ? userResolvable : null; + return this.has(userResolvable) ? userResolvable : null; } /** @@ -195,7 +184,7 @@ class GuildMemberManager extends BaseManager { _fetchSingle({ user, cache }) { - const existing = this.cache.get(user); + const existing = this.get(user); if (existing && !existing.partial) return Promise.resolve(existing); return this.client.api.guilds(this.guild.id).members(user).get() .then(data => this.add(data, cache)); @@ -203,8 +192,8 @@ class GuildMemberManager extends BaseManager { _fetchMany({ query = '', limit = 0 } = {}) { return new Promise((resolve, reject) => { - if (this.guild.memberCount === this.cache.size && !query && !limit) { - resolve(this.cache); + if (this.guild.memberCount === this.size && !query && !limit) { + resolve(this); return; } this.guild.shard.send({ @@ -222,11 +211,11 @@ class GuildMemberManager extends BaseManager { for (const member of members.values()) { if (query || limit) fetchedMembers.set(member.id, member); } - if (this.guild.memberCount <= this.cache.size || + if (this.guild.memberCount <= this.size || ((query || limit) && members.size < 1000) || (limit && fetchedMembers.size >= limit)) { this.guild.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler); - resolve(query || limit ? fetchedMembers : this.cache); + resolve(query || limit ? fetchedMembers : this); } }; const timeout = this.guild.client.setTimeout(() => { @@ -238,4 +227,4 @@ class GuildMemberManager extends BaseManager { } } -module.exports = GuildMemberManager; +module.exports = GuildMemberStore; diff --git a/src/managers/GuildManager.js b/src/stores/GuildStore.js similarity index 85% rename from src/managers/GuildManager.js rename to src/stores/GuildStore.js index 5666156b588da..eb7090b63c74d 100644 --- a/src/managers/GuildManager.js +++ b/src/stores/GuildStore.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const DataStore = require('./DataStore'); const DataResolver = require('../util/DataResolver'); const { Events } = require('../util/Constants'); const Guild = require('../structures/Guild'); @@ -9,21 +9,14 @@ const GuildMember = require('../structures/GuildMember'); const Role = require('../structures/Role'); /** - * Manages API methods for Guilds and stores their cache. - * @extends {BaseManager} + * Stores guilds. + * @extends {DataStore} */ -class GuildManager extends BaseManager { +class GuildStore extends DataStore { constructor(client, iterable) { super(client, iterable, Guild); } - /** - * The cache of this Manager - * @property {Collection} cache - * @memberof GuildManager - * @instance - */ - /** * Data that resolves to give a Guild object. This can be: * * A Guild object @@ -36,7 +29,7 @@ class GuildManager extends BaseManager { /** * Resolves a GuildResolvable to a Guild object. * @method resolve - * @memberof GuildManager + * @memberof GuildStore * @instance * @param {GuildResolvable} guild The guild resolvable to identify * @returns {?Guild} @@ -51,7 +44,7 @@ class GuildManager extends BaseManager { /** * Resolves a GuildResolvable to a Guild ID string. * @method resolveID - * @memberof GuildManager + * @memberof GuildStore * @instance * @param {GuildResolvable} guild The guild resolvable to identify * @returns {?Snowflake} @@ -77,7 +70,7 @@ class GuildManager extends BaseManager { return new Promise((resolve, reject) => this.client.api.guilds.post({ data: { name, region, icon } }) .then(data => { - if (this.client.guilds.cache.has(data.id)) return resolve(this.client.guilds.cache.get(data.id)); + if (this.client.guilds.has(data.id)) return resolve(this.client.guilds.get(data.id)); const handleGuild = guild => { if (guild.id === data.id) { @@ -102,4 +95,4 @@ class GuildManager extends BaseManager { } } -module.exports = GuildManager; +module.exports = GuildStore; diff --git a/src/stores/MessageStore.js b/src/stores/MessageStore.js new file mode 100644 index 0000000000000..59b224f720c0f --- /dev/null +++ b/src/stores/MessageStore.js @@ -0,0 +1,135 @@ +'use strict'; + +const DataStore = require('./DataStore'); +const Collection = require('../util/Collection'); +const Message = require('../structures/Message'); + +/** + * Stores messages for text-based channels. + * @extends {DataStore} + */ +class MessageStore extends DataStore { + constructor(channel, iterable) { + super(channel.client, iterable, Message); + this.channel = channel; + } + + add(data, cache) { + return super.add(data, cache, { extras: [this.channel] }); + } + + set(key, value) { + const maxSize = this.client.options.messageCacheMaxSize; + if (maxSize === 0) return; + if (this.size >= maxSize && maxSize > 0) this.delete(this.firstKey()); + super.set(key, value); + } + + /** + * The parameters to pass in when requesting previous messages from a channel. `around`, `before` and + * `after` are mutually exclusive. All the parameters are optional. + * @typedef {Object} ChannelLogsQueryOptions + * @property {number} [limit=50] Number of messages to acquire + * @property {Snowflake} [before] ID of a message to get the messages that were posted before it + * @property {Snowflake} [after] ID of a message to get the messages that were posted after it + * @property {Snowflake} [around] ID of a message to get the messages that were posted around it + */ + + /** + * Gets a message, or messages, from this channel. + * The returned Collection does not contain reaction users of the messages if they were not cached. + * Those need to be fetched separately in such a case. + * @param {Snowflake|ChannelLogsQueryOptions} [message] The ID of the message to fetch, or query parameters. + * @param {boolean} [cache=true] Whether to cache the message(s) + * @returns {Promise|Promise>} + * @example + * // Get message + * channel.messages.fetch('99539446449315840') + * .then(message => console.log(message.content)) + * .catch(console.error); + * @example + * // Get messages + * channel.messages.fetch({ limit: 10 }) + * .then(messages => console.log(`Received ${messages.size} messages`)) + * .catch(console.error); + * @example + * // Get messages and filter by user ID + * channel.messages.fetch() + * .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`)) + * .catch(console.error); + */ + fetch(message, cache = true) { + return typeof message === 'string' ? this._fetchId(message, cache) : this._fetchMany(message, cache); + } + + /** + * Fetches the pinned messages of this channel and returns a collection of them. + * The returned Collection does not contain any reaction data of the messages. + * Those need to be fetched separately. + * @param {boolean} [cache=true] Whether to cache the message(s) + * @returns {Promise>} + * @example + * // Get pinned messages + * channel.fetchPinned() + * .then(messages => console.log(`Received ${messages.size} messages`)) + * .catch(console.error); + */ + fetchPinned(cache = true) { + return this.client.api.channels[this.channel.id].pins.get().then(data => { + const messages = new Collection(); + for (const message of data) messages.set(message.id, this.add(message, cache)); + return messages; + }); + } + + /** + * Data that can be resolved to a Message object. This can be: + * * A Message + * * A Snowflake + * @typedef {Message|Snowflake} MessageResolvable + */ + + /** + * Resolves a MessageResolvable to a Message object. + * @method resolve + * @memberof MessageStore + * @instance + * @param {MessageResolvable} message The message resolvable to resolve + * @returns {?Message} + */ + + /** + * Resolves a MessageResolvable to a Message ID string. + * @method resolveID + * @memberof MessageStore + * @instance + * @param {MessageResolvable} message The message resolvable to resolve + * @returns {?Snowflake} + */ + + /** + * Deletes a message, even if it's not cached. + * @param {MessageResolvable} message The message to delete + * @param {string} [reason] Reason for deleting this message, if it does not belong to the client user + */ + async remove(message, reason) { + message = this.resolveID(message); + if (message) await this.client.api.channels(this.channel.id).messages(message).delete({ reason }); + } + + async _fetchId(messageID, cache) { + const existing = this.get(messageID); + if (existing && !existing.partial) return existing; + const data = await this.client.api.channels[this.channel.id].messages[messageID].get(); + return this.add(data, cache); + } + + async _fetchMany(options = {}, cache) { + const data = await this.client.api.channels[this.channel.id].messages.get({ query: options }); + const messages = new Collection(); + for (const message of data) messages.set(message.id, this.add(message, cache)); + return messages; + } +} + +module.exports = MessageStore; diff --git a/src/managers/PresenceManager.js b/src/stores/PresenceStore.js similarity index 73% rename from src/managers/PresenceManager.js rename to src/stores/PresenceStore.js index 0a38fd8746c85..061d3f1e933bb 100644 --- a/src/managers/PresenceManager.js +++ b/src/stores/PresenceStore.js @@ -1,26 +1,19 @@ 'use strict'; +const DataStore = require('./DataStore'); const { Presence } = require('../structures/Presence'); -const BaseManager = require('./BaseManager'); /** - * Manages API methods for Presences and holds their cache. - * @extends {BaseManager} + * Stores presences. + * @extends {DataStore} */ -class PresenceManager extends BaseManager { +class PresenceStore extends DataStore { constructor(client, iterable) { super(client, iterable, Presence); } - /** - * The cache of Presences - * @property {Collection} cache - * @memberof PresenceManager - * @instance - */ - add(data, cache) { - const existing = this.cache.get(data.user.id); + const existing = this.get(data.user.id); return existing ? existing.patch(data) : super.add(data, cache, { id: data.user.id }); } @@ -53,8 +46,8 @@ class PresenceManager extends BaseManager { const presenceResolvable = super.resolveID(presence); if (presenceResolvable) return presenceResolvable; const userResolvable = this.client.users.resolveID(presence); - return this.cache.has(userResolvable) ? userResolvable : null; + return this.has(userResolvable) ? userResolvable : null; } } -module.exports = PresenceManager; +module.exports = PresenceStore; diff --git a/src/managers/ReactionManager.js b/src/stores/ReactionStore.js similarity index 74% rename from src/managers/ReactionManager.js rename to src/stores/ReactionStore.js index 7350aebdabf52..1b1fb60304e3c 100644 --- a/src/managers/ReactionManager.js +++ b/src/stores/ReactionStore.js @@ -1,20 +1,15 @@ 'use strict'; +const DataStore = require('./DataStore'); const MessageReaction = require('../structures/MessageReaction'); -const BaseManager = require('./BaseManager'); /** - * Manages API methods for reactions and holds their cache. - * @extends {BaseManager} + * Stores reactions. + * @extends {DataStore} */ -class ReactionManager extends BaseManager { +class ReactionStore extends DataStore { constructor(message, iterable) { super(message.client, iterable, MessageReaction); - - /** - * The message that this manager belongs to - * @type {Message} - */ this.message = message; } @@ -22,13 +17,6 @@ class ReactionManager extends BaseManager { return super.add(data, cache, { id: data.emoji.id || data.emoji.name, extras: [this.message] }); } - /** - * The reaction cache of this manager - * @property {Collection} cache - * @memberof ReactionManager - * @instance - */ - /** * Data that can be resolved to a MessageReaction object. This can be: * * A MessageReaction @@ -39,7 +27,7 @@ class ReactionManager extends BaseManager { /** * Resolves a MessageReactionResolvable to a MessageReaction object. * @method resolve - * @memberof ReactionManager + * @memberof ReactionStore * @instance * @param {MessageReactionResolvable} reaction The MessageReaction to resolve * @returns {?MessageReaction} @@ -48,7 +36,7 @@ class ReactionManager extends BaseManager { /** * Resolves a MessageReactionResolvable to a MessageReaction ID string. * @method resolveID - * @memberof ReactionManager + * @memberof ReactionStore * @instance * @param {MessageReactionResolvable} reaction The MessageReaction to resolve * @returns {?Snowflake} @@ -65,18 +53,18 @@ class ReactionManager extends BaseManager { _partial(emoji) { const id = emoji.id || emoji.name; - const existing = this.cache.get(id); + const existing = this.get(id); return !existing || existing.partial; } async _fetchReaction(reactionEmoji, cache) { const id = reactionEmoji.id || reactionEmoji.name; - const existing = this.cache.get(id); + const existing = this.get(id); if (!this._partial(reactionEmoji)) return existing; const data = await this.client.api.channels(this.message.channel.id).messages(this.message.id).get(); if (!data.reactions || !data.reactions.some(r => (r.emoji.id || r.emoji.name) === id)) { reactionEmoji.reaction._patch({ count: 0 }); - this.message.reactions.cache.delete(id); + this.message.reactions.remove(id); return existing; } for (const reaction of data.reactions) { @@ -86,4 +74,4 @@ class ReactionManager extends BaseManager { } } -module.exports = ReactionManager; +module.exports = ReactionStore; diff --git a/src/managers/ReactionUserManager.js b/src/stores/ReactionUserStore.js similarity index 77% rename from src/managers/ReactionUserManager.js rename to src/stores/ReactionUserStore.js index c82b119d1c32a..dc250a9fbd3fd 100644 --- a/src/managers/ReactionUserManager.js +++ b/src/stores/ReactionUserStore.js @@ -1,30 +1,19 @@ 'use strict'; const Collection = require('../util/Collection'); -const BaseManager = require('./BaseManager'); +const DataStore = require('./DataStore'); const { Error } = require('../errors'); /** - * Manages API methods for users who reacted to a reaction and stores their cache. - * @extends {BaseManager} + * A data store to store User models who reacted to a MessageReaction. + * @extends {DataStore} */ -class ReactionUserManager extends BaseManager { +class ReactionUserStore extends DataStore { constructor(client, iterable, reaction) { - super(client, iterable, { name: 'User' }); - /** - * The reaction that this manager belongs to - * @type {MessageReaction} - */ + super(client, iterable, require('../structures/User')); this.reaction = reaction; } - /** - * The cache of this manager - * @property {Collection} cache - * @memberof GuildManager - * @instance - */ - /** * Fetches all the users that gave this reaction. Resolves with a collection of users, mapped by their IDs. * @param {Object} [options] Options for fetching the users @@ -41,7 +30,7 @@ class ReactionUserManager extends BaseManager { const users = new Collection(); for (const rawUser of data) { const user = this.client.users.add(rawUser); - this.cache.set(user.id, user); + this.set(user.id, user); users.set(user.id, user); } return users; @@ -63,4 +52,4 @@ class ReactionUserManager extends BaseManager { } } -module.exports = ReactionUserManager; +module.exports = ReactionUserStore; diff --git a/src/managers/RoleManager.js b/src/stores/RoleStore.js similarity index 78% rename from src/managers/RoleManager.js rename to src/stores/RoleStore.js index 9eb03cf2cd11b..649048be2f527 100644 --- a/src/managers/RoleManager.js +++ b/src/stores/RoleStore.js @@ -1,31 +1,20 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const DataStore = require('./DataStore'); const Role = require('../structures/Role'); const { resolveColor } = require('../util/Util'); const Permissions = require('../util/Permissions'); /** - * Manages API methods for roles and stores their cache. - * @extends {BaseManager} + * Stores roles. + * @extends {DataStore} */ -class RoleManager extends BaseManager { +class RoleStore extends DataStore { constructor(guild, iterable) { super(guild.client, iterable, Role); - /** - * The guild belonging to this manager - * @type {Guild} - */ this.guild = guild; } - /** - * The role cache of this manager - * @property {Collection} cache - * @memberof RoleManager - * @instance - */ - add(data, cache) { return super.add(data, cache, { extras: [this.guild] }); } @@ -34,11 +23,11 @@ class RoleManager extends BaseManager { * Obtains one or more roles from Discord, or the role cache if they're already available. * @param {Snowflake} [id] ID or IDs of the role(s) * @param {boolean} [cache=true] Whether to cache the new roles objects if it weren't already - * @returns {Promise} + * @returns {Promise} * @example * // Fetch all roles from the guild * message.guild.roles.fetch() - * .then(roles => console.log(`There are ${roles.cache.size} roles.`)) + * .then(roles => console.log(`There are ${roles.size} roles.`)) * .catch(console.error); * @example * // Fetch a single role @@ -48,14 +37,14 @@ class RoleManager extends BaseManager { */ async fetch(id, cache = true) { if (id) { - const existing = this.cache.get(id); + const existing = this.get(id); if (existing) return existing; } // We cannot fetch a single role, as of this commit's date, Discord API throws with 405 const roles = await this.client.api.guilds(this.guild.id).roles.get(); for (const role of roles) this.add(role, cache); - return id ? this.cache.get(id) || null : this; + return id ? this.get(id) || null : this; } /** @@ -68,7 +57,7 @@ class RoleManager extends BaseManager { /** * Resolves a RoleResolvable to a Role object. * @method resolve - * @memberof RoleManager + * @memberof RoleStore * @instance * @param {RoleResolvable} role The role resolvable to resolve * @returns {?Role} @@ -77,7 +66,7 @@ class RoleManager extends BaseManager { /** * Resolves a RoleResolvable to a role ID string. * @method resolveID - * @memberof RoleManager + * @memberof RoleStore * @instance * @param {RoleResolvable} role The role resolvable to resolve * @returns {?Snowflake} @@ -127,17 +116,17 @@ class RoleManager extends BaseManager { * @readonly */ get everyone() { - return this.cache.get(this.guild.id) || null; + return this.get(this.guild.id) || null; } /** - * The role with the highest position in the cache + * The role with the highest position in the store * @type {Role} * @readonly */ get highest() { - return this.cache.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this.cache.first()); + return this.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this.first()); } } -module.exports = RoleManager; +module.exports = RoleStore; diff --git a/src/managers/UserManager.js b/src/stores/UserStore.js similarity index 80% rename from src/managers/UserManager.js rename to src/stores/UserStore.js index 8818206aa17a3..20c25d05bb843 100644 --- a/src/managers/UserManager.js +++ b/src/stores/UserStore.js @@ -1,26 +1,19 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const DataStore = require('./DataStore'); const User = require('../structures/User'); const GuildMember = require('../structures/GuildMember'); const Message = require('../structures/Message'); /** - * Manages API methods for users and stores their cache. - * @extends {BaseManager} + * A data store to store User models. + * @extends {DataStore} */ -class UserManager extends BaseManager { +class UserStore extends DataStore { constructor(client, iterable) { super(client, iterable, User); } - /** - * The cache of this manager - * @property {Collection} cache - * @memberof UserManager - * @instance - */ - /** * Data that resolves to give a User object. This can be: * * A User object @@ -59,11 +52,11 @@ class UserManager extends BaseManager { * @returns {Promise} */ async fetch(id, cache = true) { - const existing = this.cache.get(id); + const existing = this.get(id); if (existing && !existing.partial) return existing; const data = await this.client.api.users(id).get(); return this.add(data, cache); } } -module.exports = UserManager; +module.exports = UserStore; diff --git a/src/stores/VoiceStateStore.js b/src/stores/VoiceStateStore.js new file mode 100644 index 0000000000000..a5eaac2dcef06 --- /dev/null +++ b/src/stores/VoiceStateStore.js @@ -0,0 +1,26 @@ +'use strict'; + +const DataStore = require('./DataStore'); +const VoiceState = require('../structures/VoiceState'); + +/** + * Stores voice states. + * @extends {DataStore} + */ +class VoiceStateStore extends DataStore { + constructor(guild, iterable) { + super(guild.client, iterable, VoiceState); + this.guild = guild; + } + + add(data, cache = true) { + const existing = this.get(data.user_id); + if (existing) return existing._patch(data); + + const entry = new VoiceState(this.guild, data); + if (cache) this.set(data.user_id, entry); + return entry; + } +} + +module.exports = VoiceStateStore; diff --git a/src/structures/CategoryChannel.js b/src/structures/CategoryChannel.js index 4ac9fbbb268c6..60be408c62749 100644 --- a/src/structures/CategoryChannel.js +++ b/src/structures/CategoryChannel.js @@ -13,7 +13,7 @@ class CategoryChannel extends GuildChannel { * @readonly */ get children() { - return this.guild.channels.cache.filter(c => c.parentID === this.id); + return this.guild.channels.filter(c => c.parentID === this.id); } /** diff --git a/src/structures/Channel.js b/src/structures/Channel.js index d5949c3cdfddb..9eade660025b7 100644 --- a/src/structures/Channel.js +++ b/src/structures/Channel.js @@ -100,7 +100,7 @@ class Channel extends Base { const DMChannel = Structures.get('DMChannel'); channel = new DMChannel(client, data); } else { - guild = guild || client.guilds.cache.get(data.guild_id); + guild = guild || client.guilds.get(data.guild_id); if (guild) { switch (data.type) { case ChannelTypes.TEXT: { @@ -129,7 +129,7 @@ class Channel extends Base { break; } } - if (channel) guild.channels.cache.set(channel.id, channel); + if (channel) guild.channels.set(channel.id, channel); } } return channel; diff --git a/src/structures/DMChannel.js b/src/structures/DMChannel.js index 9042519a9ef28..006a9fab22663 100644 --- a/src/structures/DMChannel.js +++ b/src/structures/DMChannel.js @@ -2,7 +2,7 @@ const Channel = require('./Channel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); -const MessageManager = require('../managers/MessageManager'); +const MessageStore = require('../stores/MessageStore'); /** * Represents a direct message channel between two users. @@ -19,10 +19,10 @@ class DMChannel extends Channel { // Override the channel type so partials have a known type this.type = 'dm'; /** - * A manager of the messages belonging to this channel - * @type {MessageManager} + * A collection containing the messages sent to this channel + * @type {MessageStore} */ - this.messages = new MessageManager(this); + this.messages = new MessageStore(this); this._typing = new Map(); } diff --git a/src/structures/Emoji.js b/src/structures/Emoji.js index 5cbf913d5c298..803fc5002c006 100644 --- a/src/structures/Emoji.js +++ b/src/structures/Emoji.js @@ -82,7 +82,7 @@ class Emoji extends Base { * @returns {string} * @example * // Send a custom emoji from a guild: - * const emoji = guild.emojis.cache.first(); + * const emoji = guild.emojis.first(); * msg.reply(`Hello! ${emoji}`); * @example * // Send the emoji used in a reaction to the channel the reaction is part of diff --git a/src/structures/Guild.js b/src/structures/Guild.js index d9bad7cefbe7d..04d091b0c8f87 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -11,12 +11,12 @@ const Util = require('../util/Util'); const DataResolver = require('../util/DataResolver'); const Snowflake = require('../util/Snowflake'); const SystemChannelFlags = require('../util/SystemChannelFlags'); -const GuildMemberManager = require('../managers/GuildMemberManager'); -const RoleManager = require('../managers/RoleManager'); -const GuildEmojiManager = require('../managers/GuildEmojiManager'); -const GuildChannelManager = require('../managers/GuildChannelManager'); -const PresenceManager = require('../managers/PresenceManager'); -const VoiceStateManager = require('../managers/VoiceStateManager'); +const GuildMemberStore = require('../stores/GuildMemberStore'); +const RoleStore = require('../stores/RoleStore'); +const GuildEmojiStore = require('../stores/GuildEmojiStore'); +const GuildChannelStore = require('../stores/GuildChannelStore'); +const PresenceStore = require('../stores/PresenceStore'); +const VoiceStateStore = require('../stores/VoiceStateStore'); const Base = require('./Base'); const { Error, TypeError } = require('../errors'); @@ -35,34 +35,34 @@ class Guild extends Base { super(client); /** - * A manager of the members belonging to this guild - * @type {GuildMemberManager} + * A collection of members that are in this guild. The key is the member's ID, the value is the member + * @type {GuildMemberStore} */ - this.members = new GuildMemberManager(this); + this.members = new GuildMemberStore(this); /** - * A manager of the members belonging to this guild - * @type {GuildChannelManager} + * A collection of channels that are in this guild. The key is the channel's ID, the value is the channel + * @type {GuildChannelStore} */ - this.channels = new GuildChannelManager(this); + this.channels = new GuildChannelStore(this); /** - * A manager of the roles belonging to this guild - * @type {RoleManager} + * A collection of roles that are in this guild. The key is the role's ID, the value is the role + * @type {RoleStore} */ - this.roles = new RoleManager(this); + this.roles = new RoleStore(this); /** - * A manager of the presences belonging to this guild - * @type {PresenceManager} + * A collection of presences in this guild + * @type {PresenceStore} */ - this.presences = new PresenceManager(this.client); + this.presences = new PresenceStore(this.client); /** - * A manager of the voice states of this guild - * @type {VoiceStateManager} + * A collection of voice states in this guild + * @type {VoiceStateStore} */ - this.voiceStates = new VoiceStateManager(this); + this.voiceStates = new VoiceStateStore(this); /** * Whether the bot has been removed from the guild @@ -321,19 +321,19 @@ class Guild extends Base { this.features = data.features || this.features || []; if (data.channels) { - this.channels.cache.clear(); + this.channels.clear(); for (const rawChannel of data.channels) { this.client.channels.add(rawChannel, this); } } if (data.roles) { - this.roles.cache.clear(); + this.roles.clear(); for (const role of data.roles) this.roles.add(role); } if (data.members) { - this.members.cache.clear(); + this.members.clear(); for (const guildUser of data.members) this.members.add(guildUser); } @@ -352,7 +352,7 @@ class Guild extends Base { } if (data.voice_states) { - this.voiceStates.cache.clear(); + this.voiceStates.clear(); for (const voiceState of data.voice_states) { this.voiceStates.add(voiceState); } @@ -360,10 +360,10 @@ class Guild extends Base { if (!this.emojis) { /** - * A manager of the emojis belonging to this guild - * @type {GuildEmojiManager} + * A collection of emojis that are in this guild. The key is the emoji's ID, the value is the emoji. + * @type {GuildEmojiStore} */ - this.emojis = new GuildEmojiManager(this); + this.emojis = new GuildEmojiStore(this); if (data.emojis) for (const emoji of data.emojis) this.emojis.add(emoji); } else if (data.emojis) { this.client.actions.GuildEmojisUpdate.handle({ @@ -463,7 +463,7 @@ class Guild extends Base { * @readonly */ get owner() { - return this.members.cache.get(this.ownerID) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ? + return this.members.get(this.ownerID) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ? this.members.add({ user: { id: this.ownerID } }, true) : null); } @@ -474,7 +474,7 @@ class Guild extends Base { * @readonly */ get afkChannel() { - return this.client.channels.cache.get(this.afkChannelID) || null; + return this.client.channels.get(this.afkChannelID) || null; } /** @@ -483,7 +483,7 @@ class Guild extends Base { * @readonly */ get systemChannel() { - return this.client.channels.cache.get(this.systemChannelID) || null; + return this.client.channels.get(this.systemChannelID) || null; } /** @@ -492,7 +492,7 @@ class Guild extends Base { * @readonly */ get widgetChannel() { - return this.client.channels.cache.get(this.widgetChannelID) || null; + return this.client.channels.get(this.widgetChannelID) || null; } /** @@ -501,7 +501,7 @@ class Guild extends Base { * @readonly */ get embedChannel() { - return this.client.channels.cache.get(this.embedChannelID) || null; + return this.client.channels.get(this.embedChannelID) || null; } /** @@ -510,10 +510,9 @@ class Guild extends Base { * @readonly */ get me() { - return this.members.cache.get(this.client.user.id) || - (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ? - this.members.add({ user: { id: this.client.user.id } }, true) : - null); + return this.members.get(this.client.user.id) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ? + this.members.add({ user: { id: this.client.user.id } }, true) : + null); } /** @@ -522,7 +521,7 @@ class Guild extends Base { * @readonly */ get voice() { - return this.voiceStates.cache.get(this.client.user.id); + return this.voiceStates.get(this.client.user.id); } /** @@ -717,7 +716,7 @@ class Guild extends Base { fetchEmbed() { return this.client.api.guilds(this.id).embed.get().then(data => ({ enabled: data.enabled, - channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null, + channel: data.channel_id ? this.channels.get(data.channel_id) : null, })); } @@ -764,7 +763,7 @@ class Guild extends Base { addMember(user, options) { user = this.client.users.resolveID(user); if (!user) return Promise.reject(new TypeError('INVALID_TYPE', 'user', 'UserResolvable')); - if (this.members.cache.has(user)) return Promise.resolve(this.members.cache.get(user)); + if (this.members.has(user)) return Promise.resolve(this.members.get(user)); options.access_token = options.accessToken; if (options.roles) { const roles = []; @@ -989,7 +988,7 @@ class Guild extends Base { * @returns {Promise} * @example * // Edit the guild owner - * guild.setOwner(guild.members.cache.first()) + * guild.setOwner(guild.members.first()) * .then(updated => console.log(`Updated the guild owner to ${updated.owner.displayName}`)) * .catch(console.error); */ @@ -1204,7 +1203,7 @@ class Guild extends Base { * @private */ _sortedRoles() { - return Util.discordSort(this.roles.cache); + return Util.discordSort(this.roles); } /** @@ -1215,7 +1214,7 @@ class Guild extends Base { */ _sortedChannels(channel) { const category = channel.type === ChannelTypes.CATEGORY; - return Util.discordSort(this.channels.cache.filter(c => + return Util.discordSort(this.channels.filter(c => c.type === channel.type && (category || c.parent === channel.parent) )); } diff --git a/src/structures/GuildAuditLogs.js b/src/structures/GuildAuditLogs.js index a6327f35c1907..d1185bdd91c19 100644 --- a/src/structures/GuildAuditLogs.js +++ b/src/structures/GuildAuditLogs.js @@ -285,7 +285,7 @@ class GuildAuditLogsEntry { */ this.executor = guild.client.options.partials.includes(PartialTypes.USER) ? guild.client.users.add({ id: data.user_id }) : - guild.client.users.cache.get(data.user_id); + guild.client.users.get(data.user_id); /** * An entry in the audit log representing a specific change. @@ -321,7 +321,7 @@ class GuildAuditLogsEntry { } else if (data.action_type === Actions.MESSAGE_DELETE) { this.extra = { count: data.options.count, - channel: guild.channels.cache.get(data.options.channel_id), + channel: guild.channels.get(data.options.channel_id), }; } else if (data.action_type === Actions.MESSAGE_BULK_DELETE) { this.extra = { @@ -330,11 +330,11 @@ class GuildAuditLogsEntry { } else { switch (data.options.type) { case 'member': - this.extra = guild.members.cache.get(data.options.id); + this.extra = guild.members.get(data.options.id); if (!this.extra) this.extra = { id: data.options.id }; break; case 'role': - this.extra = guild.roles.cache.get(data.options.id); + this.extra = guild.roles.get(data.options.id); if (!this.extra) this.extra = { id: data.options.id, name: data.options.role_name }; break; default: @@ -357,9 +357,9 @@ class GuildAuditLogsEntry { } else if (targetType === Targets.USER) { this.target = guild.client.options.partials.includes(PartialTypes.USER) ? guild.client.users.add({ id: data.target_id }) : - guild.client.users.cache.get(data.target_id); + guild.client.users.get(data.target_id); } else if (targetType === Targets.GUILD) { - this.target = guild.client.guilds.cache.get(data.target_id); + this.target = guild.client.guilds.get(data.target_id); } else if (targetType === Targets.WEBHOOK) { this.target = logs.webhooks.get(data.target_id) || new Webhook(guild.client, @@ -386,9 +386,9 @@ class GuildAuditLogsEntry { } }); } else if (targetType === Targets.MESSAGE) { - this.target = guild.client.users.cache.get(data.target_id); + this.target = guild.client.users.get(data.target_id); } else { - this.target = guild[`${targetType.toLowerCase()}s`].cache.get(data.target_id) || { id: data.target_id }; + this.target = guild[`${targetType.toLowerCase()}s`].get(data.target_id) || { id: data.target_id }; } } diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 649e5b2222d3a..fa1f84d43e87f 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -72,7 +72,7 @@ class GuildChannel extends Channel { * @readonly */ get parent() { - return this.guild.channels.cache.get(this.parentID) || null; + return this.guild.channels.get(this.parentID) || null; } /** @@ -118,7 +118,7 @@ class GuildChannel extends Channel { if (!verified) member = this.guild.members.resolve(member); if (!member) return []; - roles = roles || member.roles.cache; + roles = roles || member.roles; const roleOverwrites = []; let memberOverwrites; let everyoneOverwrites; @@ -149,7 +149,7 @@ class GuildChannel extends Channel { memberPermissions(member) { if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze(); - const roles = member.roles.cache; + const roles = member.roles; const permissions = new Permissions(roles.map(role => role.permissions)); if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze(); @@ -274,7 +274,7 @@ class GuildChannel extends Channel { */ get members() { const members = new Collection(); - for (const member of this.guild.members.cache.values()) { + for (const member of this.guild.members.values()) { if (this.permissionsFor(member).has('VIEW_CHANNEL', false)) { members.set(member.id, member); } diff --git a/src/structures/GuildEmoji.js b/src/structures/GuildEmoji.js index 64138b86b8877..a7620911d5838 100644 --- a/src/structures/GuildEmoji.js +++ b/src/structures/GuildEmoji.js @@ -1,6 +1,6 @@ 'use strict'; -const GuildEmojiRoleManager = require('../managers/GuildEmojiRoleManager'); +const GuildEmojiRoleStore = require('../stores/GuildEmojiRoleStore'); const Permissions = require('../util/Permissions'); const { Error } = require('../errors'); const Emoji = require('./Emoji'); @@ -79,12 +79,12 @@ class GuildEmoji extends Emoji { } /** - * A manager for roles this emoji is active for. - * @type {GuildEmojiRoleManager} + * A collection of roles this emoji is active for (empty if all), mapped by role ID + * @type {GuildEmojiRoleStore} * @readonly */ get roles() { - return new GuildEmojiRoleManager(this); + return new GuildEmojiRoleStore(this); } /** @@ -168,15 +168,15 @@ class GuildEmoji extends Emoji { other.name === this.name && other.managed === this.managed && other.requiresColons === this.requiresColons && - other.roles.cache.size === this.roles.cache.size && - other.roles.cache.every(role => this.roles.cache.has(role.id)) + other.roles.size === this.roles.size && + other.roles.every(role => this.roles.has(role.id)) ); } else { return ( other.id === this.id && other.name === this.name && - other.roles.length === this.roles.cache.size && - other.roles.every(role => this.roles.cache.has(role)) + other.roles.length === this.roles.size && + other.roles.every(role => this.roles.has(role)) ); } } diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index b832f959393b5..8a8b8bb6a4e5b 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -3,7 +3,7 @@ const TextBasedChannel = require('./interfaces/TextBasedChannel'); const Role = require('./Role'); const Permissions = require('../util/Permissions'); -const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager'); +const GuildMemberRoleStore = require('../stores/GuildMemberRoleStore'); const Base = require('./Base'); const VoiceState = require('./VoiceState'); const { Presence } = require('./Presence'); @@ -101,12 +101,12 @@ class GuildMember extends Base { } /** - * A manager for the roles belonging to this member - * @type {GuildMemberRoleManager} + * A collection of roles that are applied to this member, mapped by the role ID + * @type {GuildMemberRoleStore} * @readonly */ get roles() { - return new GuildMemberRoleManager(this); + return new GuildMemberRoleStore(this); } /** @@ -115,8 +115,8 @@ class GuildMember extends Base { * @readonly */ get lastMessage() { - const channel = this.guild.channels.cache.get(this.lastMessageChannelID); - return (channel && channel.messages.cache.get(this.lastMessageID)) || null; + const channel = this.guild.channels.get(this.lastMessageChannelID); + return (channel && channel.messages.get(this.lastMessageID)) || null; } /** @@ -125,7 +125,7 @@ class GuildMember extends Base { * @readonly */ get voice() { - return this.guild.voiceStates.cache.get(this.id) || new VoiceState(this.guild, { user_id: this.id }); + return this.guild.voiceStates.get(this.id) || new VoiceState(this.guild, { user_id: this.id }); } /** @@ -152,7 +152,7 @@ class GuildMember extends Base { * @readonly */ get presence() { - return this.guild.presences.cache.get(this.id) || new Presence(this.client, { + return this.guild.presences.get(this.id) || new Presence(this.client, { user: { id: this.id, }, @@ -205,7 +205,7 @@ class GuildMember extends Base { */ get permissions() { if (this.user.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze(); - return new Permissions(this.roles.cache.map(role => role.permissions)).freeze(); + return new Permissions(this.roles.map(role => role.permissions)).freeze(); } /** @@ -261,7 +261,7 @@ class GuildMember extends Base { */ hasPermission(permission, { checkAdmin = true, checkOwner = true } = {}) { if (checkOwner && this.user.id === this.guild.ownerID) return true; - return this.roles.cache.some(r => r.permissions.has(permission, checkAdmin)); + return this.roles.some(r => r.permissions.has(permission, checkAdmin)); } /** diff --git a/src/structures/Integration.js b/src/structures/Integration.js index 8fef7aa2247be..5ff760dc7c078 100644 --- a/src/structures/Integration.js +++ b/src/structures/Integration.js @@ -56,7 +56,7 @@ class Integration extends Base { * The role that this integration uses for subscribers * @type {Role} */ - this.role = this.guild.roles.cache.get(data.role_id); + this.role = this.guild.roles.get(data.role_id); /** * The user for this integration diff --git a/src/structures/Invite.js b/src/structures/Invite.js index 88b62b4a956e8..4d048b3f1ff35 100644 --- a/src/structures/Invite.js +++ b/src/structures/Invite.js @@ -117,7 +117,7 @@ class Invite extends Base { */ get deletable() { const guild = this.guild; - if (!guild || !this.client.guilds.cache.has(guild.id)) return false; + if (!guild || !this.client.guilds.has(guild.id)) return false; if (!guild.me) throw new Error('GUILD_UNCACHED_ME'); return this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS, false) || guild.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD); diff --git a/src/structures/Message.js b/src/structures/Message.js index adc4ec834504f..b09f1d3480738 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -7,7 +7,7 @@ const ReactionCollector = require('./ReactionCollector'); const ClientApplication = require('./ClientApplication'); const Util = require('../util/Util'); const Collection = require('../util/Collection'); -const ReactionManager = require('../managers/ReactionManager'); +const ReactionStore = require('../stores/ReactionStore'); const { MessageTypes } = require('../util/Constants'); const Permissions = require('../util/Permissions'); const Base = require('./Base'); @@ -126,10 +126,10 @@ class Message extends Base { this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null; /** - * A manager of the reactions belonging to this message - * @type {ReactionManager} + * A collection of reactions to this message, mapped by the reaction ID + * @type {ReactionStore} */ - this.reactions = new ReactionManager(this); + this.reactions = new ReactionStore(this); if (data.reactions && data.reactions.length > 0) { for (const reaction of data.reactions) { this.reactions.add(reaction); @@ -452,7 +452,7 @@ class Message extends Base { * .catch(console.error); * @example * // React to a message with a custom emoji - * message.react(message.guild.emojis.cache.get('123456789012345678')) + * message.react(message.guild.emojis.get('123456789012345678')) * .then(console.log) * .catch(console.error); */ @@ -484,7 +484,7 @@ class Message extends Base { */ delete({ timeout = 0, reason } = {}) { if (timeout <= 0) { - return this.channel.messages.delete(this.id, reason).then(() => this); + return this.channel.messages.remove(this.id, reason).then(() => this); } else { return new Promise(resolve => { this.client.setTimeout(() => { diff --git a/src/structures/MessageMentions.js b/src/structures/MessageMentions.js index 6079dc23b0320..ab2d5c81b880a 100644 --- a/src/structures/MessageMentions.js +++ b/src/structures/MessageMentions.js @@ -71,7 +71,7 @@ class MessageMentions { } else { this.roles = new Collection(); for (const mention of roles) { - const role = message.channel.guild.roles.cache.get(mention); + const role = message.channel.guild.roles.get(mention); if (role) this.roles.set(role.id, role); } } @@ -156,7 +156,7 @@ class MessageMentions { this._channels = new Collection(); let matches; while ((matches = this.constructor.CHANNELS_PATTERN.exec(this._content)) !== null) { - const chan = this.client.channels.cache.get(matches[1]); + const chan = this.client.channels.get(matches[1]); if (chan) this._channels.set(chan.id, chan); } return this._channels; @@ -175,7 +175,7 @@ class MessageMentions { has(data, { ignoreDirect = false, ignoreRoles = false, ignoreEveryone = false } = {}) { if (!ignoreEveryone && this.everyone) return true; if (!ignoreRoles && data instanceof GuildMember) { - for (const role of this.roles.values()) if (data.roles.cache.has(role.id)) return true; + for (const role of this.roles.values()) if (data.roles.has(role.id)) return true; } if (!ignoreDirect) { diff --git a/src/structures/MessageReaction.js b/src/structures/MessageReaction.js index 150288a55a21e..5cb9210fb77ee 100644 --- a/src/structures/MessageReaction.js +++ b/src/structures/MessageReaction.js @@ -3,7 +3,7 @@ const GuildEmoji = require('./GuildEmoji'); const Util = require('../util/Util'); const ReactionEmoji = require('./ReactionEmoji'); -const ReactionUserManager = require('../managers/ReactionUserManager'); +const ReactionUserStore = require('../stores/ReactionUserStore'); /** * Represents a reaction to a message. @@ -35,10 +35,10 @@ class MessageReaction { this.me = data.me; /** - * A manager of the users that have given this reaction - * @type {ReactionUserManager} + * The users that have given this reaction, mapped by their ID + * @type {ReactionUserStore} */ - this.users = new ReactionUserManager(client, undefined, this); + this.users = new ReactionUserStore(client, undefined, this); this._emoji = new ReactionEmoji(this, data.emoji); @@ -75,7 +75,7 @@ class MessageReaction { if (this._emoji instanceof GuildEmoji) return this._emoji; // Check to see if the emoji has become known to the client if (this._emoji.id) { - const emojis = this.message.client.emojis.cache; + const emojis = this.message.client.emojis; if (emojis.has(this._emoji.id)) { const emoji = emojis.get(this._emoji.id); this._emoji = emoji; @@ -108,18 +108,18 @@ class MessageReaction { _add(user) { if (this.partial) return; - this.users.cache.set(user.id, user); + this.users.set(user.id, user); if (!this.me || user.id !== this.message.client.user.id || this.count === 0) this.count++; if (!this.me) this.me = user.id === this.message.client.user.id; } _remove(user) { if (this.partial) return; - this.users.cache.delete(user.id); + this.users.delete(user.id); if (!this.me || user.id !== this.message.client.user.id) this.count--; if (user.id === this.message.client.user.id) this.me = false; - if (this.count <= 0 && this.users.cache.size === 0) { - this.message.reactions.cache.delete(this.emoji.id || this.emoji.name); + if (this.count <= 0 && this.users.size === 0) { + this.message.reactions.remove(this.emoji.id || this.emoji.name); } } } diff --git a/src/structures/Presence.js b/src/structures/Presence.js index fdc038a5c3f8a..12888f1c6d008 100644 --- a/src/structures/Presence.js +++ b/src/structures/Presence.js @@ -66,7 +66,7 @@ class Presence { * @readonly */ get user() { - return this.client.users.cache.get(this.userID) || null; + return this.client.users.get(this.userID) || null; } /** @@ -75,7 +75,7 @@ class Presence { * @readonly */ get member() { - return this.guild.members.cache.get(this.userID) || null; + return this.guild.members.get(this.userID) || null; } patch(data) { diff --git a/src/structures/ReactionCollector.js b/src/structures/ReactionCollector.js index 65b604cdf2938..e7d5aeb164d0c 100644 --- a/src/structures/ReactionCollector.js +++ b/src/structures/ReactionCollector.js @@ -74,7 +74,7 @@ class ReactionCollector extends Collector { this.on('remove', (reaction, user) => { this.total--; - if (!this.collected.some(r => r.users.cache.has(user.id))) this.users.delete(user.id); + if (!this.collected.some(r => r.users.has(user.id))) this.users.delete(user.id); }); } diff --git a/src/structures/Role.js b/src/structures/Role.js index cedaa545660ba..9c7ebd494066a 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -117,7 +117,7 @@ class Role extends Base { * @readonly */ get members() { - return this.guild.members.cache.filter(m => m.roles.cache.has(this.id)); + return this.guild.members.filter(m => m.roles.has(this.id)); } /** diff --git a/src/structures/TextChannel.js b/src/structures/TextChannel.js index 10b5d7cb39a19..66212e70a118e 100644 --- a/src/structures/TextChannel.js +++ b/src/structures/TextChannel.js @@ -5,7 +5,7 @@ const Webhook = require('./Webhook'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); const Collection = require('../util/Collection'); const DataResolver = require('../util/DataResolver'); -const MessageManager = require('../managers/MessageManager'); +const MessageStore = require('../stores/MessageStore'); /** * Represents a guild text channel on Discord. @@ -20,10 +20,10 @@ class TextChannel extends GuildChannel { constructor(guild, data) { super(guild, data); /** - * A manager of the messages sent to this channel - * @type {MessageManager} + * A collection containing the messages sent to this channel + * @type {MessageStore} */ - this.messages = new MessageManager(this); + this.messages = new MessageStore(this); this._typing = new Map(); } diff --git a/src/structures/User.js b/src/structures/User.js index ae301705291eb..7ae67451bee36 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -119,8 +119,8 @@ class User extends Base { * @readonly */ get lastMessage() { - const channel = this.client.channels.cache.get(this.lastMessageChannelID); - return (channel && channel.messages.cache.get(this.lastMessageID)) || null; + const channel = this.client.channels.get(this.lastMessageChannelID); + return (channel && channel.messages.get(this.lastMessageID)) || null; } /** @@ -129,8 +129,8 @@ class User extends Base { * @readonly */ get presence() { - for (const guild of this.client.guilds.cache.values()) { - if (guild.presences.cache.has(this.id)) return guild.presences.cache.get(this.id); + for (const guild of this.client.guilds.values()) { + if (guild.presences.has(this.id)) return guild.presences.get(this.id); } return new Presence(this.client, { user: { id: this.id } }); } @@ -209,7 +209,7 @@ class User extends Base { * @readonly */ get dmChannel() { - return this.client.channels.cache.find(c => c.type === 'dm' && c.recipient.id === this.id) || null; + return this.client.channels.find(c => c.type === 'dm' && c.recipient.id === this.id) || null; } /** diff --git a/src/structures/VoiceChannel.js b/src/structures/VoiceChannel.js index 6b3850dfbff6d..15f2e496f08af 100644 --- a/src/structures/VoiceChannel.js +++ b/src/structures/VoiceChannel.js @@ -34,7 +34,7 @@ class VoiceChannel extends GuildChannel { */ get members() { const coll = new Collection(); - for (const state of this.guild.voiceStates.cache.values()) { + for (const state of this.guild.voiceStates.values()) { if (state.channelID === this.id && state.member) { coll.set(state.id, state.member); } diff --git a/src/structures/VoiceState.js b/src/structures/VoiceState.js index 3ad02dea198e1..c60f6ac657af6 100644 --- a/src/structures/VoiceState.js +++ b/src/structures/VoiceState.js @@ -72,7 +72,7 @@ class VoiceState extends Base { * @readonly */ get member() { - return this.guild.members.cache.get(this.id) || null; + return this.guild.members.get(this.id) || null; } /** @@ -81,7 +81,7 @@ class VoiceState extends Base { * @readonly */ get channel() { - return this.guild.channels.cache.get(this.channelID) || null; + return this.guild.channels.get(this.channelID) || null; } /** diff --git a/src/structures/Webhook.js b/src/structures/Webhook.js index b29607040898a..9b6b43c8f4c23 100644 --- a/src/structures/Webhook.js +++ b/src/structures/Webhook.js @@ -70,7 +70,7 @@ class Webhook { * The owner of the webhook * @type {?User|Object} */ - this.owner = this.client.users ? this.client.users.cache.get(data.user.id) : data.user; + this.owner = this.client.users ? this.client.users.get(data.user.id) : data.user; } else { this.owner = null; } @@ -154,7 +154,7 @@ class Webhook { query: { wait: true }, auth: false, }).then(d => { - const channel = this.client.channels ? this.client.channels.cache.get(d.channel_id) : undefined; + const channel = this.client.channels ? this.client.channels.get(d.channel_id) : undefined; if (!channel) return d; return channel.messages.add(d, false); }); diff --git a/src/structures/interfaces/TextBasedChannel.js b/src/structures/interfaces/TextBasedChannel.js index 4106e00df2a7d..a6b1837533499 100644 --- a/src/structures/interfaces/TextBasedChannel.js +++ b/src/structures/interfaces/TextBasedChannel.js @@ -13,10 +13,10 @@ const APIMessage = require('../APIMessage'); class TextBasedChannel { constructor() { /** - * A manager of the messages sent to this channel - * @type {MessageManager} + * A collection containing the messages sent to this channel + * @type {MessageStore} */ - this.messages = new MessageManager(this); + this.messages = new MessageStore(this); /** * The ID of the last message in the channel, if one was sent @@ -37,7 +37,7 @@ class TextBasedChannel { * @readonly */ get lastMessage() { - return this.messages.cache.get(this.lastMessageID) || null; + return this.messages.get(this.lastMessageID) || null; } /** @@ -350,4 +350,4 @@ class TextBasedChannel { module.exports = TextBasedChannel; // Fixes Circular -const MessageManager = require('../../managers/MessageManager'); +const MessageStore = require('../../stores/MessageStore'); diff --git a/src/util/LimitedCollection.js b/src/util/LimitedCollection.js deleted file mode 100644 index 5719a9fa61f91..0000000000000 --- a/src/util/LimitedCollection.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -const Collection = require('./Collection.js'); - -/** - * A Collection which holds a max amount of entries. The first key is deleted if the Collection has - * reached max size. - * @extends {Collection} - * @param {number} [maxSize=0] The maximum size of the Collection - * @param {Iterable} [iterable=null] Optional entries passed to the Map constructor. - */ -class LimitedCollection extends Collection { - constructor(maxSize = 0, iterable = null) { - super(iterable); - /** - * The max size of the Collection. - * @type {number} - */ - this.maxSize = maxSize; - } - - set(key, value) { - if (this.maxSize === 0) return this; - if (this.size >= this.maxSize && !this.has(key)) this.delete(this.firstKey()); - return super.set(key, value); - } -} - -module.exports = LimitedCollection; diff --git a/src/util/Structures.js b/src/util/Structures.js index c4061f62cd1b8..02529d26dd589 100644 --- a/src/util/Structures.js +++ b/src/util/Structures.js @@ -1,7 +1,7 @@ 'use strict'; /** - * Allows for the extension of built-in Discord.js structures that are instantiated by {@link BaseManager Managers}. + * Allows for the extension of built-in Discord.js structures that are instantiated by {@link DataStore DataStores}. */ class Structures { constructor() { diff --git a/src/util/Util.js b/src/util/Util.js index da4bff4491a45..6087f3c244ede 100644 --- a/src/util/Util.js +++ b/src/util/Util.js @@ -528,25 +528,25 @@ class Util { .replace(/<@!?[0-9]+>/g, input => { const id = input.replace(/<|!|>|@/g, ''); if (message.channel.type === 'dm') { - const user = message.client.users.cache.get(id); + const user = message.client.users.get(id); return user ? `@${user.username}` : input; } - const member = message.channel.guild.members.cache.get(id); + const member = message.channel.guild.members.get(id); if (member) { return `@${member.displayName}`; } else { - const user = message.client.users.cache.get(id); + const user = message.client.users.get(id); return user ? `@${user.username}` : input; } }) .replace(/<#[0-9]+>/g, input => { - const channel = message.client.channels.cache.get(input.replace(/<|#|>/g, '')); + const channel = message.client.channels.get(input.replace(/<|#|>/g, '')); return channel ? `#${channel.name}` : input; }) .replace(/<@&[0-9]+>/g, input => { if (message.channel.type === 'dm') return input; - const role = message.guild.roles.cache.get(input.replace(/<|@|>|&/g, '')); + const role = message.guild.roles.get(input.replace(/<|@|>|&/g, '')); return role ? `@${role.name}` : input; }); } @@ -571,6 +571,34 @@ class Util { setTimeout(resolve, ms); }); } + + /** + * Adds methods from collections and maps onto the provided store + * @param {DataStore} store The store to mixin + * @param {string[]} ignored The properties to ignore + * @private + */ + /* eslint-disable func-names */ + static mixin(store, ignored) { + const Collection = require('./Collection'); + Object.getOwnPropertyNames(Collection.prototype) + .concat(Object.getOwnPropertyNames(Map.prototype)).forEach(prop => { + if (ignored.includes(prop)) return; + if (prop === 'size') { + Object.defineProperty(store.prototype, prop, { + get: function() { + return this._filtered[prop]; + }, + }); + return; + } + const func = Collection.prototype[prop]; + if (prop === 'constructor' || typeof func !== 'function') return; + store.prototype[prop] = function(...args) { + return func.apply(this._filtered, args); + }; + }); + } } module.exports = Util; diff --git a/typings/index.d.ts b/typings/index.d.ts index a0f40ce979727..07f725bce6c66 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -151,16 +151,16 @@ declare module 'discord.js' { private _eval(script: string): any; private _validateOptions(options?: ClientOptions): void; - public channels: ChannelManager; - public readonly emojis: GuildEmojiManager; - public guilds: GuildManager; + public channels: ChannelStore; + public readonly emojis: GuildEmojiStore; + public guilds: GuildStore; public readyAt: Date | null; public readonly readyTimestamp: number | null; public shard: ShardClientUtil | null; public token: string | null; public readonly uptime: number | null; public user: ClientUser | null; - public users: UserManager; + public users: UserStore; public voice: ClientVoiceManager | null; public ws: WebSocketManager; public destroy(): void; @@ -328,6 +328,16 @@ declare module 'discord.js' { public setUsername(username: string): Promise; } + export class Collection extends BaseCollection { + public flatMap(fn: (value: V, key: K, collection: this) => Collection): Collection; + public flatMap(fn: (this: This, value: V, key: K, collection: this) => Collection, thisArg: This): Collection; + public flatMap(fn: (value: V, key: K, collection: this) => Collection, thisArg?: unknown): Collection; + public mapValues(fn: (value: V, key: K, collection: this) => T): Collection; + public mapValues(fn: (this: This, value: V, key: K, collection: this) => T, thisArg: This): Collection; + public mapValues(fn: (value: V, key: K, collection: this) => T, thisArg?: unknown): Collection; + public toJSON(): object; + } + export abstract class Collector extends EventEmitter { constructor(client: Client, filter: CollectorFilter, options?: CollectorOptions); private _timeout: NodeJS.Timer | null; @@ -638,7 +648,7 @@ declare module 'discord.js' { export class DMChannel extends TextBasedChannel(Channel) { constructor(client: Client, data?: object); - public messages: MessageManager; + public messages: MessageStore; public recipient: User; public readonly partial: false; public fetch(): Promise; @@ -670,7 +680,7 @@ declare module 'discord.js' { public applicationID: Snowflake; public available: boolean; public banner: string | null; - public channels: GuildChannelManager; + public channels: GuildChannelStore; public readonly createdAt: Date; public readonly createdTimestamp: number; public defaultMessageNotifications: DefaultMessageNotifications | number; @@ -679,7 +689,7 @@ declare module 'discord.js' { public embedChannel: GuildChannel | null; public embedChannelID: Snowflake | null; public embedEnabled: boolean; - public emojis: GuildEmojiManager; + public emojis: GuildEmojiStore; public explicitContentFilter: number; public features: GuildFeatures[]; public icon: string | null; @@ -691,7 +701,7 @@ declare module 'discord.js' { public maximumPresences: number | null; public readonly me: GuildMember | null; public memberCount: number; - public members: GuildMemberManager; + public members: GuildMemberStore; public mfaLevel: number; public name: string; public readonly nameAcronym: string; @@ -700,9 +710,9 @@ declare module 'discord.js' { public readonly partnered: boolean; public premiumSubscriptionCount: number | null; public premiumTier: PremiumTier; - public presences: PresenceManager; + public presences: PresenceStore; public region: string; - public roles: RoleManager; + public roles: RoleStore; public readonly shard: WebSocketShard; public shardID: number; public splash: string | null; @@ -713,7 +723,7 @@ declare module 'discord.js' { public verificationLevel: number; public readonly verified: boolean; public readonly voice: VoiceState | null; - public readonly voiceStates: VoiceStateManager; + public readonly voiceStates: VoiceStateStore; public readonly widgetChannel: TextChannel | null; public widgetChannelID: Snowflake | null; public widgetEnabled: boolean | null; @@ -837,7 +847,7 @@ declare module 'discord.js' { public id: Snowflake; public managed: boolean; public requiresColons: boolean; - public roles: GuildEmojiRoleManager; + public roles: GuildEmojiRoleStore; public readonly url: string; public delete(reason?: string): Promise; public edit(data: GuildEmojiEditData, reason?: string): Promise; @@ -865,7 +875,7 @@ declare module 'discord.js' { public readonly premiumSince: Date | null; public premiumSinceTimestamp: number | null; public readonly presence: Presence; - public roles: GuildMemberRoleManager; + public roles: GuildMemberRoleStore; public user: User; public readonly voice: VoiceState; public ban(options?: BanOptions): Promise; @@ -968,7 +978,7 @@ declare module 'discord.js' { public readonly partial: false; public readonly pinnable: boolean; public pinned: boolean; - public reactions: ReactionManager; + public reactions: ReactionStore; public system: boolean; public tts: boolean; public type: MessageType; @@ -1103,7 +1113,7 @@ declare module 'discord.js' { public me: boolean; public message: Message; public readonly partial: boolean; - public users: ReactionUserManager; + public users: ReactionUserStore; public remove(): Promise; public fetch(): Promise; public toJSON(): object; @@ -1387,7 +1397,7 @@ declare module 'discord.js' { export class TextChannel extends TextBasedChannel(GuildChannel) { constructor(guild: Guild, data?: object); - public messages: MessageManager; + public messages: MessageStore; public nsfw: boolean; public rateLimitPerUser: number; public topic: string | null; @@ -1399,7 +1409,7 @@ declare module 'discord.js' { export class NewsChannel extends TextBasedChannel(GuildChannel) { constructor(guild: Guild, data?: object); - public messages: MessageManager; + public messages: MessageStore; public nsfw: boolean; public topic: string | null; public createWebhook(name: string, options?: { avatar?: BufferResolvable | Base64Resolvable, reason?: string }): Promise; @@ -1739,64 +1749,64 @@ declare module 'discord.js' { //#endregion -//#region Collections +//#region Stores - export class Collection extends BaseCollection { + export class ChannelStore extends DataStore { + constructor(client: Client, iterable: Iterable, options?: { lru: boolean }); + constructor(client: Client, options?: { lru: boolean }); + public fetch(id: Snowflake, cache?: boolean): Promise; + } + + export class DataStore, R = any> extends Collection { + constructor(client: Client, iterable: Iterable, holds: VConstructor); + public client: Client; + public holds: VConstructor; + public add(data: any, cache?: boolean, { id, extras }?: { id: K, extras: any[] }): V; + public remove(key: K): void; + public resolve(resolvable: R): V | null; + public resolveID(resolvable: R): K | null; + // Don't worry about those bunch of ts-ignores here, this is intended https://github.com/microsoft/TypeScript/issues/1213 + // @ts-ignore + public filter(fn: (value: V, key: K, collection: this) => boolean): Collection; + // @ts-ignore + public filter(fn: (this: T, value: V, key: K, collection: this) => boolean, thisArg: T): Collection; + // @ts-ignore + public filter(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): Collection; + // @ts-ignore + public partition(fn: (value: V, key: K, collection: this) => boolean): [Collection, Collection]; + // @ts-ignore + public partition(fn: (this: T, value: V, key: K, collection: this) => boolean, thisArg: T): [Collection, Collection]; + // @ts-ignore + public partition(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): [Collection, Collection]; public flatMap(fn: (value: V, key: K, collection: this) => Collection): Collection; public flatMap(fn: (this: This, value: V, key: K, collection: this) => Collection, thisArg: This): Collection; public flatMap(fn: (value: V, key: K, collection: this) => Collection, thisArg?: unknown): Collection; public mapValues(fn: (value: V, key: K, collection: this) => T): Collection; public mapValues(fn: (this: This, value: V, key: K, collection: this) => T, thisArg: This): Collection; public mapValues(fn: (value: V, key: K, collection: this) => T, thisArg?: unknown): Collection; - public toJSON(): object; - } - - export class LimitedCollection extends Collection { - public constructor(maxSize: number, iterable: Iterable); - public maxSize: number; + // @ts-ignore + public clone(): Collection; + // @ts-ignore + public concat(...collections: Collection[]): Collection; + // @ts-ignore + public sorted(compareFunction: (firstValue: V, secondValue: V, firstKey: K, secondKey: K) => number): Collection; } -//#endregion - -//#region Managers - - export class ChannelManager extends BaseManager { - constructor(client: Client, iterable: Iterable); - public fetch(id: Snowflake, cache?: boolean): Promise; - } - - export abstract class BaseManager { - constructor(client: Client, iterable: Iterable, holds: Constructable, cacheType: Collection); - public holds: Constructable; - public cache: Collection; - public cacheType: Collection; - public readonly client: Client; - public add(data: any, cache?: boolean, { id, extras }?: { id: K, extras: any[] }): Holds; - public remove(key: K): void; - public resolve(resolvable: R): Holds | null; - public resolveID(resolvable: R): K | null; - } - - export class GuildEmojiRoleManager { + export class GuildEmojiRoleStore extends OverridableDataStore { constructor(emoji: GuildEmoji); - public emoji: GuildEmoji; - public guild: Guild; - public cache: Collection; public add(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection): Promise; public set(roles: RoleResolvable[] | Collection): Promise; public remove(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection): Promise; } - export class GuildEmojiManager extends BaseManager { + export class GuildEmojiStore extends DataStore { constructor(guild: Guild, iterable?: Iterable); - public guild: Guild; public create(attachment: BufferResolvable | Base64Resolvable, name: string, options?: GuildEmojiCreateOptions): Promise; public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null; } - export class GuildChannelManager extends BaseManager { + export class GuildChannelStore extends DataStore { constructor(guild: Guild, iterable?: Iterable); - public guild: Guild; public create(name: string, options: GuildCreateChannelOptions & { type: 'voice' }): Promise; public create(name: string, options: GuildCreateChannelOptions & { type: 'category' }): Promise; public create(name: string, options?: GuildCreateChannelOptions & { type?: 'text' }): Promise; @@ -1804,87 +1814,78 @@ declare module 'discord.js' { } // Hacky workaround because changing the signature of an overridden method errors - class OverridableManager extends BaseManager { + class OverridableDataStore, R = any> extends DataStore { public add(data: any, cache: any): any; public set(key: any): any; } - export class GuildMemberRoleManager extends OverridableManager { + export class GuildMemberRoleStore extends OverridableDataStore { constructor(member: GuildMember); public readonly hoist: Role | null; public readonly color: Role | null; public readonly highest: Role; - public member: GuildMember; - public guild: Guild; public add(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection, reason?: string): Promise; public set(roles: RoleResolvable[] | Collection, reason?: string): Promise; public remove(roleOrRoles: RoleResolvable | RoleResolvable[] | Collection, reason?: string): Promise; } - export class GuildMemberManager extends BaseManager { + export class GuildMemberStore extends DataStore { constructor(guild: Guild, iterable?: Iterable); - public guild: Guild; public ban(user: UserResolvable, options?: BanOptions): Promise; public fetch(options: UserResolvable | FetchMemberOptions): Promise; - public fetch(): Promise; + public fetch(): Promise; public fetch(options: FetchMembersOptions): Promise>; public prune(options: GuildPruneMembersOptions & { dry?: false, count: false }): Promise; public prune(options?: GuildPruneMembersOptions): Promise; public unban(user: UserResolvable, reason?: string): Promise; } - export class GuildManager extends BaseManager { + export class GuildStore extends DataStore { constructor(client: Client, iterable?: Iterable); public create(name: string, options?: { region?: string, icon: BufferResolvable | Base64Resolvable | null }): Promise; } - export class MessageManager extends BaseManager { + export class MessageStore extends DataStore { constructor(channel: TextChannel | DMChannel, iterable?: Iterable); - public channel: TextBasedChannelFields; - public cache: LimitedCollection; public fetch(message: Snowflake, cache?: boolean): Promise; public fetch(options?: ChannelLogsQueryOptions, cache?: boolean): Promise>; public fetchPinned(cache?: boolean): Promise>; - public delete(message: MessageResolvable, reason?: string): Promise; + public remove(message: MessageResolvable, reason?: string): Promise; } - export class PresenceManager extends BaseManager { + export class PresenceStore extends DataStore { constructor(client: Client, iterable?: Iterable); } - export class ReactionManager extends BaseManager { + export class ReactionStore extends DataStore { constructor(message: Message, iterable?: Iterable); - public message: Message; public removeAll(): Promise; } - export class ReactionUserManager extends BaseManager { + export class ReactionUserStore extends DataStore { constructor(client: Client, iterable: Iterable | undefined, reaction: MessageReaction); - public reaction: MessageReaction; public fetch(options?: { limit?: number, after?: Snowflake, before?: Snowflake }): Promise>; public remove(user?: UserResolvable): Promise; } - export class RoleManager extends BaseManager { + export class RoleStore extends DataStore { constructor(guild: Guild, iterable?: Iterable); public readonly everyone: Role | null; public readonly highest: Role; - public guild: Guild; public create(options?: { data?: RoleData, reason?: string }): Promise; public fetch(id: Snowflake, cache?: boolean): Promise; public fetch(id?: Snowflake, cache?: boolean): Promise; } - export class UserManager extends BaseManager { + export class UserStore extends DataStore { constructor(client: Client, iterable?: Iterable); public fetch(id: Snowflake, cache?: boolean): Promise; } - export class VoiceStateManager extends BaseManager { + export class VoiceStateStore extends DataStore { constructor(guild: Guild, iterable?: Iterable); - public guild: Guild; } //#endregion