Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(CachedManager): allow overriding constructor for makeCache #9763

Merged
merged 4 commits into from
Aug 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/discord.js/src/managers/CachedManager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const DataManager = require('./DataManager');
const { MakeCacheOverrideSymbol } = require('../util/Symbols');

/**
* Manages the API methods of a data model with a mutable cache of instances.
Expand All @@ -18,7 +19,13 @@ class CachedManager extends DataManager {
* @readonly
* @name CachedManager#_cache
*/
Object.defineProperty(this, '_cache', { value: this.client.options.makeCache(this.constructor, this.holds) });
Object.defineProperty(this, '_cache', {
value: this.client.options.makeCache(
this.constructor[MakeCacheOverrideSymbol] ?? this.constructor,
this.holds,
this.constructor,
),
});

if (iterable) {
for (const item of iterable) {
Expand Down
3 changes: 3 additions & 0 deletions packages/discord.js/src/managers/MessageManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const CachedManager = require('./CachedManager');
const { DiscordjsTypeError, ErrorCodes } = require('../errors');
const { Message } = require('../structures/Message');
const MessagePayload = require('../structures/MessagePayload');
const { MakeCacheOverrideSymbol } = require('../util/Symbols');
const { resolvePartialEmoji } = require('../util/Util');

/**
Expand All @@ -15,6 +16,8 @@ const { resolvePartialEmoji } = require('../util/Util');
* @abstract
*/
class MessageManager extends CachedManager {
static [MakeCacheOverrideSymbol] = MessageManager;

constructor(channel, iterable) {
super(channel.client, Message, iterable);

Expand Down
3 changes: 3 additions & 0 deletions packages/discord.js/src/managers/ThreadManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ const { Routes } = require('discord-api-types/v10');
const CachedManager = require('./CachedManager');
const { DiscordjsTypeError, ErrorCodes } = require('../errors');
const ThreadChannel = require('../structures/ThreadChannel');
const { MakeCacheOverrideSymbol } = require('../util/Symbols');

/**
* Manages API methods for thread-based channels and stores their cache.
* @extends {CachedManager}
*/
class ThreadManager extends CachedManager {
static [MakeCacheOverrideSymbol] = ThreadManager;

constructor(channel, iterable) {
super(channel.client, ThreadChannel, iterable);

Expand Down
8 changes: 5 additions & 3 deletions packages/discord.js/src/util/Options.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ const { DefaultRestOptions, DefaultUserAgentAppendix } = require('@discordjs/res
const { toSnakeCase } = require('./Transformers');
const { version } = require('../../package.json');

// TODO(ckohen): switch order of params so full manager is first and "type" is optional
/**
* @typedef {Function} CacheFactory
* @param {Function} manager The manager class the cache is being requested from.
* @param {Function} managerType The base manager class the cache is being requested from.
* @param {Function} holds The class that the cache will hold.
* @param {Function} manager The fully extended manager class the cache is being requested from.
* @returns {Collection} A Collection used to store the cache of the manager.
*/

Expand Down Expand Up @@ -150,8 +152,8 @@ class Options extends null {
const { Collection } = require('@discordjs/collection');
const LimitedCollection = require('./LimitedCollection');

return manager => {
const setting = settings[manager.name];
return (managerType, _, manager) => {
const setting = settings[manager.name] ?? settings[managerType.name];
/* eslint-disable-next-line eqeqeq */
if (setting == null) {
return new Collection();
Expand Down
3 changes: 3 additions & 0 deletions packages/discord.js/src/util/Symbols.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

exports.MakeCacheOverrideSymbol = Symbol('djs.managers.makeCacheOverride');
15 changes: 12 additions & 3 deletions packages/discord.js/typings/index.d.ts
ckohen marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4720,17 +4720,19 @@ export interface Caches {
AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule];
ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand];
BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji];
DMMessageManager: [manager: typeof MessageManager, holds: typeof Message<false>];
GuildEmojiManager: [manager: typeof GuildEmojiManager, holds: typeof GuildEmoji];
// TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel];
// TODO: GuildChannelManager: [manager: typeof GuildChannelManager, holds: typeof GuildChannel];
// TODO: GuildManager: [manager: typeof GuildManager, holds: typeof Guild];
GuildMemberManager: [manager: typeof GuildMemberManager, holds: typeof GuildMember];
GuildBanManager: [manager: typeof GuildBanManager, holds: typeof GuildBan];
GuildForumThreadManager: [manager: typeof GuildForumThreadManager, holds: typeof ThreadChannel];
GuildForumThreadManager: [manager: typeof GuildForumThreadManager, holds: typeof ThreadChannel<true>];
GuildInviteManager: [manager: typeof GuildInviteManager, holds: typeof Invite];
GuildMessageManager: [manager: typeof GuildMessageManager, holds: typeof Message<true>];
GuildScheduledEventManager: [manager: typeof GuildScheduledEventManager, holds: typeof GuildScheduledEvent];
GuildStickerManager: [manager: typeof GuildStickerManager, holds: typeof Sticker];
GuildTextThreadManager: [manager: typeof GuildTextThreadManager, holds: typeof ThreadChannel];
GuildTextThreadManager: [manager: typeof GuildTextThreadManager, holds: typeof ThreadChannel<false>];
MessageManager: [manager: typeof MessageManager, holds: typeof Message];
// TODO: PermissionOverwriteManager: [manager: typeof PermissionOverwriteManager, holds: typeof PermissionOverwrites];
PresenceManager: [manager: typeof PresenceManager, holds: typeof Presence];
Expand All @@ -4748,11 +4750,18 @@ export type CacheConstructors = {
[K in keyof Caches]: Caches[K][0] & { name: K };
};

type OverriddenCaches =
| 'DMMessageManager'
| 'GuildForumThreadManager'
| 'GuildMessageManager'
| 'GuildTextThreadManager';

// This doesn't actually work the way it looks 😢.
// Narrowing the type of `manager.name` doesn't propagate type information to `holds` and the return type.
export type CacheFactory = (
manager: CacheConstructors[keyof Caches],
managerType: CacheConstructors[Exclude<keyof Caches, OverriddenCaches>],
holds: Caches[(typeof manager)['name']][1],
manager: CacheConstructors[keyof Caches],
) => (typeof manager)['prototype'] extends DataManager<infer K, infer V, any> ? Collection<K, V> : never;

export type CacheWithLimitsOptions = {
Expand Down