diff --git a/src/lib/caching/stores/GuildMemberStore.ts b/src/lib/caching/stores/GuildMemberStore.ts index c24e9f519..970ed9281 100644 --- a/src/lib/caching/stores/GuildMemberStore.ts +++ b/src/lib/caching/stores/GuildMemberStore.ts @@ -1,8 +1,10 @@ /* eslint-disable no-dupe-class-members */ -import { Cache } from '@klasa/cache'; +import { ProxyCache } from '@klasa/cache'; import { DataStore } from './base/DataStore'; import { extender } from '../../util/Extender'; import { Routes, RequestOptions } from '@klasa/rest'; +import { RequestGuildMembers, OpCodes, GuildMembersChunkDispatch } from '@klasa/ws'; +import { EventIterator } from '@klasa/event-iterator'; import type { APIUserData, APIGuildMemberData } from '@klasa/dapi-types'; import type { Client } from '../../client/Client'; @@ -67,11 +69,11 @@ export class GuildMemberStore extends DataStore { /** * Returns up to 1000 {@link GuildMember members}. * @since 0.0.1 - * @param userID The {@link User user} ID to fetch. - * @see https://discord.com/developers/docs/resources/guild#list-guild-members + * @param options The {@link GuildMemberStoreFetchOptions options} used to fetch. + * @see https://discord.com/developers/docs/topics/gateway#request-guild-members */ - public fetch(options?: GuildMemberStoreFetchOptions): Promise>; - public async fetch(idOrOptions?: string | GuildMemberStoreFetchOptions): Promise> { + public fetch(options?: GuildMemberStoreFetchOptions): Promise>; + public async fetch(idOrOptions?: string | GuildMemberStoreFetchOptions): Promise> { if (typeof idOrOptions === 'string') { const previous = this.get(idOrOptions); if (previous) return previous; @@ -80,13 +82,75 @@ export class GuildMemberStore extends DataStore { return this._add(member); } - const entries = await this.client.api.get(Routes.guildMembers(this.guild.id), { data: idOrOptions }) as APIGuildMemberData[]; + if (typeof idOrOptions === 'undefined') idOrOptions = {}; + + const { query = '', userIDs, presences, limit = 0, nonce = Date.now().toString(16) } = idOrOptions; + + /* eslint-disable id-length */ + const options: RequestGuildMembers = { + op: OpCodes.REQUEST_GUILD_MEMBERS, + d: { + /* eslint-disable camelcase */ + guild_id: this.guild.id, + user_ids: userIDs, + /* eslint-enable camelcase */ + query, + presences, + limit, + nonce + } + }; + + this.guild.shard.send(options); + + let i = 0; + // const cache = new Cache(); + const cache = new ProxyCache(this); + for await (const [{ d }] of new EventIterator<[GuildMembersChunkDispatch]>(this.client.ws, 'GUILD_MEMBERS_CHUNK', { + filter: ([{ d: data }]): boolean => data.nonce === nonce && data.guild_id === this.guild.id + })) { + if (i === d.chunk_count) break; + i++; + for (const rawMember of d.members) { + const member = this._add(rawMember); + cache.set(member.id); + } + } + /* eslint-enable id-length */ - const cache = new Cache(); + return cache; + } + + /** + * TBD + * @param options + */ + public async search(data: GuildMemberStoreSearchOptions): Promise> { + const members = await this.client.api.get(Routes.guildMembersSearch(this.guild.id), { data }) as APIGuildMemberData[]; + const cache = new ProxyCache(this); + for (const rawMember of members) { + const member = this._add(rawMember); + cache.set(member.id); + } + + return cache; + } + + /** + * Returns up to 1000 {@link GuildMember members}. + * @since 0.0.3 + * @param options The {@link GuildMemberStoreListOptions options} used to fetch. + * @see https://discord.com/developers/docs/resources/guild#list-guild-members + */ + public async list(options: GuildMemberStoreListOptions): Promise> { + const entries = await this.client.api.get(Routes.guildMembers(this.guild.id), { data: options }) as APIGuildMemberData[]; + + const cache = new ProxyCache(this); for (const entry of entries) { const member = this._add(entry); - cache.set(member.id, member); + cache.set(member.id); } + return cache; } @@ -170,11 +234,11 @@ export interface GuildMemberStoreAddData { } /** - * The options for {@link GuildMemberStore#fetch}. + * The options for {@link GuildMemberStore#list}. * @since 0.0.1 * @see https://discord.com/developers/docs/resources/guild#list-guild-members-query-string-params */ -export interface GuildMemberStoreFetchOptions { +export interface GuildMemberStoreListOptions { /** * Max number of members to return (1-1000). * @since 0.0.1 @@ -188,4 +252,54 @@ export interface GuildMemberStoreFetchOptions { after?: string; } +/** + * The options for {@link GuildMemberStore#fetch} when fetching many. + * @since 0.0.3 + * @see https://discord.com/developers/docs/topics/gateway#request-guild-members + */ +export interface GuildMemberStoreFetchOptions { + /** + * The query to fetch members with, will be used to search via nicknames. + * @since 0.0.3 + */ + query?: string; + /** + * The number of members to fetch. + * @since 0.0.3 + */ + limit?: number; + /** + * Whether to include presences with the request. + * @since 0.0.3 + */ + presences?: boolean; + /** + * The user ID(s) to search for. + * @since 0.0.3 + */ + userIDs?: string | string[]; + /** + * The unique nonce to look for, this is mainly used internally. + * @since 0.0.3 + * @internal + */ + nonce?: string; +} + +/** + * The options for {@link GuildMemberStore#search}. + * @since 0.0.3 + */ +export interface GuildMemberStoreSearchOptions { + /** + * The query to search for. + * @since 0.0.3 + */ + query: string; + /** + * The limit for fetching members. + */ + limit?: number; +} + /* eslint-enable camelcase */