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

feat: add support for fetching multiple guilds #5472

Merged
merged 12 commits into from
May 29, 2021
2 changes: 2 additions & 0 deletions esm/discord.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const {
Base,
Activity,
APIMessage,
BaseGuild,
BaseGuildEmoji,
BaseGuildVoiceChannel,
CategoryChannel,
Expand Down Expand Up @@ -85,6 +86,7 @@ export const {
MessageMentions,
MessageReaction,
NewsChannel,
OAuth2Guild,
PermissionOverwrites,
Presence,
ClientPresence,
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ module.exports = {
Base: require('./structures/Base'),
Activity: require('./structures/Presence').Activity,
APIMessage: require('./structures/APIMessage'),
BaseGuild: require('./structures/BaseGuild'),
BaseGuildEmoji: require('./structures/BaseGuildEmoji'),
BaseGuildVoiceChannel: require('./structures/BaseGuildVoiceChannel'),
CategoryChannel: require('./structures/CategoryChannel'),
Expand Down Expand Up @@ -97,6 +98,7 @@ module.exports = {
MessageMentions: require('./structures/MessageMentions'),
MessageReaction: require('./structures/MessageReaction'),
NewsChannel: require('./structures/NewsChannel'),
OAuth2Guild: require('./structures/OAuth2Guild'),
PermissionOverwrites: require('./structures/PermissionOverwrites'),
Presence: require('./structures/Presence').Presence,
ClientPresence: require('./structures/ClientPresence'),
Expand Down
50 changes: 34 additions & 16 deletions src/managers/GuildManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const GuildChannel = require('../structures/GuildChannel');
const GuildEmoji = require('../structures/GuildEmoji');
const GuildMember = require('../structures/GuildMember');
const Invite = require('../structures/Invite');
const OAuth2Guild = require('../structures/OAuth2Guild');
const Role = require('../structures/Role');
const Collection = require('../util/Collection');
const {
ChannelTypes,
Events,
Expand Down Expand Up @@ -231,25 +233,41 @@ class GuildManager extends BaseManager {
}

/**
* Obtains a guild from Discord, or the guild cache if it's already available.
* @param {Snowflake} id ID of the guild
* @param {boolean} [cache=true] Whether to cache the new guild object if it isn't already
* @param {boolean} [force=false] Whether to skip the cache check and request the API
* @returns {Promise<Guild>}
* @example
* // Fetch a guild by its id
* client.guilds.fetch('222078108977594368')
* .then(guild => console.log(guild.name))
* .catch(console.error);
* Options used to fetch a single guild.
* @typedef {Object} FetchGuildOptions
* @property {GuildResolvable} guild The guild to fetch
* @property {boolean} [cache=true] Whether or not to cache the fetched guild
* @property {boolean} [force=false] Whether to skip the cache check and request the API
*/
async fetch(id, cache = true, force = false) {
if (!force) {
const existing = this.cache.get(id);
if (existing) return existing;

/**
* Options used to fetch multiple guilds.
* @typedef {Object} FetchGuildsOptions
* @property {Snowflake} [before] Get guilds before this guild ID
* @property {Snowflake} [after] Get guilds after this guild ID
* @property {number} [limit=100] Maximum number of guilds to request (1-100)
*/

/**
* Obtains one or multiple guilds from Discord, or the guild cache if it's already available.
* @param {GuildResolvable|FetchGuildOptions|FetchGuildsOptions} [options] ID of the guild or options
* @returns {Promise<Guild|Collection<Snowflake, OAuth2Guild>>}
*/
async fetch(options = {}) {
const id = this.resolveID(options) ?? this.resolveID(options.guild);

if (id) {
if (!options.force) {
const existing = this.cache.get(id);
if (existing) return existing;
}

const data = await this.client.api.guilds(id).get({ query: { with_counts: true } });
return this.add(data, options.cache);
}

const data = await this.client.api.guilds(id).get({ query: { with_counts: true } });
return this.add(data, cache);
const data = await this.client.api.users('@me').guilds.get({ query: options });
return data.reduce((coll, guild) => coll.set(guild.id, new OAuth2Guild(this.client, guild)), new Collection());
}
}

Expand Down
115 changes: 115 additions & 0 deletions src/structures/BaseGuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
'use strict';

const Base = require('./Base');
const SnowflakeUtil = require('../util/Snowflake');
iCrawl marked this conversation as resolved.
Show resolved Hide resolved

/**
* The base class for {@link Guild} and {@link OAuth2Guild}.
* @extends {Base}
*/
class BaseGuild extends Base {
constructor(client, data) {
super(client);

/**
* The ID of this guild
* @type {Snowflake}
*/
this.id = data.id;

/**
* The name of this guild
* @type {string}
*/
this.name = data.name;

/**
* The icon hash of this guild
* @type {?string}
*/
this.icon = data.icon;

/**
* An array of features available to this guild
* @type {Features[]}
*/
this.features = data.features;
}

/**
* The timestamp this guild was created at
* @type {number}
* @readonly
*/
get createdTimestamp() {
return SnowflakeUtil.deconstruct(this.id).timestamp;
}

/**
* The time this guild was created at
* @type {Date}
* @readonly
*/
get createdAt() {
return new Date(this.createdTimestamp);
}

/**
* The acronym that shows up in place of a guild icon
* @type {string}
* @readonly
*/
get nameAcronym() {
return this.name
.replace(/'s /g, ' ')
.replace(/\w+/g, e => e[0])
.replace(/\s/g, '');
}

/**
* Whether this guild is partnered
* @type {boolean}
* @readonly
*/
get partnered() {
return this.features.includes('PARTNERED');
}

/**
* Whether this guild is verified
* @type {boolean}
* @readonly
*/
get verified() {
return this.features.includes('VERIFIED');
}

/**
* The URL to this guild's icon.
* @param {ImageURLOptions} [options={}] Options for the Image URL
* @returns {?string}
*/
iconURL({ format, size, dynamic } = {}) {
if (!this.icon) return null;
return this.client.rest.cdn.Icon(this.id, this.icon, format, size, dynamic);
}

/**
* Fetches this guild.
* @returns {Promise<Guild>}
*/
async fetch() {
const data = await this.client.api.guilds(this.id).get({ query: { with_counts: true } });
return this.client.guilds.add(data);
}

/**
* When concatenated with a string, this automatically returns the guild's name instead of the Guild object.
* @returns {string}
*/
toString() {
return this.name;
}
}

module.exports = BaseGuild;
Loading