From 290938bf80fb8e7d30c66e33f019782178a4f791 Mon Sep 17 00:00:00 2001 From: Carter <45381083+Fyko@users.noreply.github.com> Date: Wed, 12 Aug 2020 13:23:04 -0600 Subject: [PATCH] feat: bypass cache check with forceFetch param (#4592) --- src/managers/ChannelManager.js | 9 ++++++--- src/managers/GuildMemberManager.js | 19 ++++++++++++++---- src/managers/MessageManager.js | 14 ++++++++----- src/managers/RoleManager.js | 5 +++-- src/managers/UserManager.js | 10 +++++++--- src/structures/Channel.js | 5 +++-- src/structures/DMChannel.js | 5 +++-- src/structures/GuildMember.js | 5 +++-- src/structures/Message.js | 5 +++-- src/structures/User.js | 20 ++++++++++++------- typings/index.d.ts | 32 ++++++++++++++++++------------ 11 files changed, 84 insertions(+), 45 deletions(-) diff --git a/src/managers/ChannelManager.js b/src/managers/ChannelManager.js index 99fde10f6..8d7d71e72 100644 --- a/src/managers/ChannelManager.js +++ b/src/managers/ChannelManager.js @@ -74,6 +74,7 @@ class ChannelManager extends BaseManager { * Obtains a channel from Discord, or the channel cache if it's already available. * @param {Snowflake} id ID of the channel * @param {boolean} [cache=true] Whether to cache the new channel object if it isn't already + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} * @example * // Fetch a channel by its id @@ -81,9 +82,11 @@ class ChannelManager extends BaseManager { * .then(channel => console.log(channel.name)) * .catch(console.error); */ - async fetch(id, cache = true) { - const existing = this.cache.get(id); - if (existing && !existing.partial) return existing; + async fetch(id, cache = true, force = false) { + if (!force) { + const existing = this.cache.get(id); + if (existing && !existing.partial) return existing; + } const data = await this.client.api.channels(id).get(); return this.add(data, null, cache); diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index f5027d65b..0d98d3360 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -67,6 +67,7 @@ class GuildMemberManager extends BaseManager { * @typedef {Object} FetchMemberOptions * @property {UserResolvable} user The user to fetch * @property {boolean} [cache=true] Whether or not to cache the fetched member + * @property {boolean} [force=false] Whether to skip the cache check and request the API */ /** @@ -78,6 +79,7 @@ class GuildMemberManager extends BaseManager { * @property {boolean} [withPresences=false] Whether or not to include the presences * @property {number} [time=120e3] Timeout for receipt of members * @property {?string} nonce Nonce for this request (32 characters max - default to base 16 now timestamp) + * @property {boolean} [force=false] Whether to skip the cache check and request the API */ /** @@ -97,6 +99,11 @@ class GuildMemberManager extends BaseManager { * .then(console.log) * .catch(console.error); * @example + * // Fetch a single member without checking cache + * guild.members.fetch({ user, force: true }) + * .then(console.log) + * .catch(console.error) + * @example * // Fetch a single member without caching * guild.members.fetch({ user, cache: false }) * .then(console.log) @@ -215,9 +222,12 @@ class GuildMemberManager extends BaseManager { .then(() => this.client.users.resolve(user)); } - _fetchSingle({ user, cache }) { - const existing = this.cache.get(user); - if (existing && !existing.partial) return Promise.resolve(existing); + _fetchSingle({ user, cache, force = false }) { + if (!force) { + const existing = this.cache.get(user); + if (existing && !existing.partial) return Promise.resolve(existing); + } + return this.client.api .guilds(this.guild.id) .members(user) @@ -232,9 +242,10 @@ class GuildMemberManager extends BaseManager { query, time = 120e3, nonce = Date.now().toString(16), + force = false, } = {}) { return new Promise((resolve, reject) => { - if (this.guild.memberCount === this.cache.size && !query && !limit && !presences && !user_ids) { + if (this.guild.memberCount === this.cache.size && !query && !limit && !presences && !user_ids && !force) { resolve(this.cache); return; } diff --git a/src/managers/MessageManager.js b/src/managers/MessageManager.js index 6d51bcf01..03834abe1 100644 --- a/src/managers/MessageManager.js +++ b/src/managers/MessageManager.js @@ -45,6 +45,7 @@ class MessageManager extends BaseManager { * 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) + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise|Promise>} * @example * // Get message @@ -62,8 +63,8 @@ class MessageManager extends BaseManager { * .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); + fetch(message, cache = true, force = false) { + return typeof message === 'string' ? this._fetchId(message, cache, force) : this._fetchMany(message, cache); } /** @@ -127,9 +128,12 @@ class MessageManager extends BaseManager { } } - async _fetchId(messageID, cache) { - const existing = this.cache.get(messageID); - if (existing && !existing.partial) return existing; + async _fetchId(messageID, cache, force) { + if (!force) { + 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); } diff --git a/src/managers/RoleManager.js b/src/managers/RoleManager.js index 7c5bf51ac..a1586b0f0 100644 --- a/src/managers/RoleManager.js +++ b/src/managers/RoleManager.js @@ -33,6 +33,7 @@ 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 + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} * @example * // Fetch all roles from the guild @@ -45,8 +46,8 @@ class RoleManager extends BaseManager { * .then(role => console.log(`The role color is: ${role.color}`)) * .catch(console.error); */ - async fetch(id, cache = true) { - if (id) { + async fetch(id, cache = true, force = false) { + if (id && !force) { const existing = this.cache.get(id); if (existing) return existing; } diff --git a/src/managers/UserManager.js b/src/managers/UserManager.js index ebd7fdf31..89287150e 100644 --- a/src/managers/UserManager.js +++ b/src/managers/UserManager.js @@ -55,11 +55,15 @@ class UserManager extends BaseManager { * Obtains a user from Discord, or the user cache if it's already available. * @param {Snowflake} id ID of the user * @param {boolean} [cache=true] Whether to cache the new user object if it isn't already + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} */ - async fetch(id, cache = true) { - const existing = this.cache.get(id); - if (existing && !existing.partial) return existing; + async fetch(id, cache = true, force = false) { + if (!force) { + const existing = this.cache.get(id); + if (existing && !existing.partial) return existing; + } + const data = await this.client.api.users(id).get(); return this.add(data, cache); } diff --git a/src/structures/Channel.js b/src/structures/Channel.js index 1dc7ee092..37913046f 100644 --- a/src/structures/Channel.js +++ b/src/structures/Channel.js @@ -90,10 +90,11 @@ class Channel extends Base { /** * Fetches this channel. + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} */ - fetch() { - return this.client.channels.fetch(this.id, true); + fetch(force = false) { + return this.client.channels.fetch(this.id, true, force); } static create(client, data, guild) { diff --git a/src/structures/DMChannel.js b/src/structures/DMChannel.js index e661bc44f..48075974a 100644 --- a/src/structures/DMChannel.js +++ b/src/structures/DMChannel.js @@ -61,10 +61,11 @@ class DMChannel extends Channel { /** * Fetch this DMChannel. + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} */ - fetch() { - return this.recipient.createDM(); + fetch(force = false) { + return this.recipient.createDM(force); } /** diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index f9757732e..61e56a62a 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -373,10 +373,11 @@ class GuildMember extends Base { /** * Fetches this GuildMember. + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} */ - fetch() { - return this.guild.members.fetch(this.id, true); + fetch(force = false) { + return this.guild.members.fetch({ user: this.id, cache: true, force }); } /** diff --git a/src/structures/Message.js b/src/structures/Message.js index 4610675d5..91c0212bc 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -547,10 +547,11 @@ class Message extends Base { /** * Fetch this message. + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} */ - fetch() { - return this.channel.messages.fetch(this.id, true); + fetch(force = false) { + return this.channel.messages.fetch(this.id, true, force); } /** diff --git a/src/structures/User.js b/src/structures/User.js index 034dc4bd1..93689606d 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -222,11 +222,15 @@ class User extends Base { /** * Creates a DM channel between the client and the user. + * @param {boolean} [force=false] Whether to skip the cache check and request the API * @returns {Promise} */ - async createDM() { - const { dmChannel } = this; - if (dmChannel && !dmChannel.partial) return dmChannel; + async createDM(force = false) { + if (!force) { + const { dmChannel } = this; + if (dmChannel && !dmChannel.partial) return dmChannel; + } + const data = await this.client.api.users(this.client.user.id).channels.post({ data: { recipient_id: this.id, @@ -265,10 +269,11 @@ class User extends Base { /** * Fetches this user's flags. + * @param {boolean} [force=false] Whether to skip the cache check and request the AP * @returns {Promise} */ - async fetchFlags() { - if (this.flags) return this.flags; + async fetchFlags(force = false) { + if (this.flags && !force) return this.flags; const data = await this.client.api.users(this.id).get(); this._patch(data); return this.flags; @@ -276,10 +281,11 @@ class User extends Base { /** * Fetches this user. + * @param {boolean} [force=false] Whether to skip the cache check and request the AP * @returns {Promise} */ - fetch() { - return this.client.users.fetch(this.id, true); + fetch(force = false) { + return this.client.users.fetch(this.id, true, force); } /** diff --git a/typings/index.d.ts b/typings/index.d.ts index e8db4c25f..c3e1cb4f7 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -159,7 +159,7 @@ declare module 'discord.js' { public id: Snowflake; public type: keyof typeof ChannelType; public delete(reason?: string): Promise; - public fetch(): Promise; + public fetch(force?: boolean): Promise; public toString(): string; } @@ -581,7 +581,7 @@ declare module 'discord.js' { public recipient: User; public readonly partial: false; public type: 'dm'; - public fetch(): Promise; + public fetch(force?: boolean): Promise; } export class Emoji extends Base { @@ -836,8 +836,8 @@ declare module 'discord.js' { public user: User; public readonly voice: VoiceState; public ban(options?: BanOptions): Promise; - public fetch(): Promise; - public createDM(): Promise; + public fetch(force?: boolean): Promise; + public createDM(force?: boolean): Promise; public deleteDM(): Promise; public edit(data: GuildMemberEditData, reason?: string): Promise; public hasPermission( @@ -985,7 +985,7 @@ declare module 'discord.js' { public edit(options: MessageEditOptions | MessageEmbed | APIMessage): Promise; public equals(message: Message, rawData: object): boolean; public fetchWebhook(): Promise; - public fetch(): Promise; + public fetch(force?: boolean): Promise; public pin(options?: { reason?: string }): Promise; public react(emoji: EmojiIdentifierResolvable): Promise; public reply( @@ -1520,8 +1520,8 @@ declare module 'discord.js' { public deleteDM(): Promise; public displayAvatarURL(options?: ImageURLOptions & { dynamic?: boolean }): string; public equals(user: User): boolean; - public fetch(): Promise; - public fetchFlags(): Promise; + public fetch(force?: boolean): Promise; + public fetchFlags(force?: boolean): Promise; public toString(): string; public typingDurationIn(channel: ChannelResolvable): number; public typingIn(channel: ChannelResolvable): boolean; @@ -1854,7 +1854,7 @@ declare module 'discord.js' { export class ChannelManager extends BaseManager { constructor(client: Client, iterable: Iterable); - public fetch(id: Snowflake, cache?: boolean): Promise; + public fetch(id: Snowflake, cache?: boolean, force?: boolean): Promise; } export abstract class BaseManager { @@ -1946,8 +1946,12 @@ declare module 'discord.js' { constructor(channel: TextChannel | DMChannel, iterable?: Iterable); public channel: TextBasedChannelFields; public cache: Collection; - public fetch(message: Snowflake, cache?: boolean): Promise; - public fetch(options?: ChannelLogsQueryOptions, cache?: boolean): Promise>; + public fetch(message: Snowflake, cache?: boolean, force?: boolean): Promise; + public fetch( + options?: ChannelLogsQueryOptions, + cache?: boolean, + force?: boolean, + ): Promise>; public fetchPinned(cache?: boolean): Promise>; public delete(message: MessageResolvable, reason?: string): Promise; } @@ -1986,13 +1990,13 @@ declare module 'discord.js' { 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; + public fetch(id: Snowflake, cache?: boolean, force?: boolean): Promise; + public fetch(id?: Snowflake, cache?: boolean, force?: boolean): Promise; } export class UserManager extends BaseManager { constructor(client: Client, iterable?: Iterable); - public fetch(id: Snowflake, cache?: boolean): Promise; + public fetch(id: Snowflake, cache?: boolean, force?: boolean): Promise; } export class VoiceStateManager extends BaseManager { @@ -2424,6 +2428,7 @@ declare module 'discord.js' { interface FetchMemberOptions { user: UserResolvable; cache?: boolean; + force?: boolean; } interface FetchMembersOptions { @@ -2433,6 +2438,7 @@ declare module 'discord.js' { withPresences?: boolean; time?: number; nonce?: string; + force?: boolean; } interface FileOptions {