From 16f7d51187be932527d4e1142b35f0fee9d79c24 Mon Sep 17 00:00:00 2001 From: socram03 Date: Mon, 11 Jul 2022 13:13:28 -0400 Subject: [PATCH] feat(cache): utility functions --- packages/cache/mod.ts | 186 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 166 insertions(+), 20 deletions(-) diff --git a/packages/cache/mod.ts b/packages/cache/mod.ts index 06f4c84..7347c70 100644 --- a/packages/cache/mod.ts +++ b/packages/cache/mod.ts @@ -1,27 +1,27 @@ import type { ChannelTypes, - SymCache, + DiscordChannel, + DiscordEmoji, + DiscordGuild, + DiscordMemberWithUser, + DiscordUser, Session, Snowflake, - DiscordGuild, - DiscordEmoji, - DiscordUser, - DiscordChannel, - DiscordMemberWithUser, + SymCache, } from "./deps.ts"; import { ChannelFactory, - Guild, - User, DMChannel, + Guild, GuildEmoji, GuildTextChannel, Member, Message, - VoiceChannel, - ThreadChannel, NewsChannel, + ThreadChannel, + User, + VoiceChannel, } from "./deps.ts"; export const cache_sym = Symbol("@cache"); @@ -57,7 +57,7 @@ export interface CachedGuildChannel extends Omit { } export interface CachedGuildChannel extends Omit { - type: ChannelTypes + type: ChannelTypes; messages: Map; } @@ -66,7 +66,7 @@ export interface SessionCache extends SymCache { users: StructCache; dms: StructCache; emojis: StructCache; - session: Session, + session: Session; } export default function (session: Session): SessionCache { @@ -80,13 +80,156 @@ export default function (session: Session): SessionCache { }; } -export class StructCache extends Map { - constructor(session: Session, entries?: Iterable) { +export class StructCache extends Map { + constructor(session: Session, entries?: Iterable) { super(entries); this.session = session; } - readonly session: Session; + + get(key: Snowflake): V | undefined { + return super.get(key); + } + + set(key: Snowflake, value: V): this { + return super.set(key, value); + } + + has(key: Snowflake): boolean { + return super.has(key); + } + + clear(): void { + return super.clear(); + } + + random(): V | undefined; + random(amount: number): V[]; + random(amount?: number): V | V[] | undefined { + const arr = [...this.values()]; + if (typeof amount === "undefined") return arr[Math.floor(Math.random() * arr.length)]; + if (!arr.length) return []; + if (amount && amount > arr.length) amount = arr.length; + return Array.from( + { length: Math.min(amount, arr.length) }, + (): V => arr.splice(Math.floor(Math.random() * arr.length), 1)[0], + ); + } + + find(fn: (value: V, key: Snowflake, structCache: this) => boolean): V | undefined { + for (const [key, value] of this.entries()) { + if (fn(value, key, this)) return value; + } + return undefined; + } + + filter(fn: (value: V, key: Snowflake, structCache: this) => boolean): StructCache { + const result = new StructCache(this.session); + for (const [key, value] of this.entries()) { + if (fn(value, key, this)) result.set(key, value); + } + return result; + } + + forEach(fn: (value: V, key: Snowflake, structCache: this) => T): void { + super.forEach((v: V, k: Snowflake) => { + fn(v, k, this); + }); + } + + clone(): StructCache { + return new StructCache(this.session, this.entries()); + } + + concat(structures: StructCache[]): StructCache { + const conc = this.clone(); + + for (const structure of structures) { + if (!structure || !(structure instanceof StructCache)) continue; + for (const [key, value] of structure.entries()) { + conc.set(key, value); + } + } + return conc; + } + + some(fn: (value: V, key: Snowflake, structCache: this) => boolean): boolean { + for (const [key, value] of this.entries()) { + if (fn(value, key, this)) { + return true; + } + } + return false; + } + + every(fn: (value: V, key: Snowflake, structCache: this) => boolean): boolean { + for (const [key, value] of this.entries()) { + if (!fn(value, key, this)) { + return false; + } + } + return true; + } + + first(): V | undefined; + first(amount: number): V[]; + first(amount?: number): V | V[] | undefined { + if (!amount || amount <= 1) { + return this.values().next().value; + } + const values = [...this.values()]; + amount = Math.min(values.length, amount); + return values.slice(0, amount); + } + + last(): V | undefined; + last(amount: number): V[]; + last(amount?: number): V | V[] | undefined { + const values = [...this.values()]; + if (!amount || amount <= 1) { + return values[values.length - 1]; + } + amount = Math.min(values.length, amount); + return values.slice(-amount); + } + + reverse(): this { + const entries = [...this.entries()].reverse(); + this.clear(); + for (const [key, value] of entries) this.set(key, value); + return this; + } + + map(fn: (value: V, key: Snowflake, collection: this) => T): T[] { + const result: T[] = []; + for (const [key, value] of this.entries()) { + result.push(fn(value, key, this)); + } + return result; + } + + reduce(fn: (acc: T, value: V, key: Snowflake, structCache: this) => T, initV?: T): T { + const entries = this.entries(); + const first = entries.next().value; + let result = initV; + if (result !== undefined) { + result = fn(result, first[1], first[0], this); + } else { + result = first; + } + for (const [key, value] of entries) { + result = fn(result!, value, key, this); + } + return result!; + } + + get size(): number { + return super.size; + } + + get empty(): boolean { + return this.size === 0; + } } export function userBootstrapper(cache: SessionCache, user: DiscordUser) { @@ -108,7 +251,7 @@ export function guildBootstrapper(guild: DiscordGuild, cache: SessionCache) { userId: data.user!.id, get user(): User | undefined { return cache.users.get(this.userId); - } + }, }); return [data.user!.id, obj as CachedMember]; @@ -122,8 +265,11 @@ export function guildBootstrapper(guild: DiscordGuild, cache: SessionCache) { return [data.id, obj as CachedGuildChannel]; })); - cache.guilds.set(guild.id, Object.assign( - new Guild(cache.session, guild), - { members, channels }, - )); + cache.guilds.set( + guild.id, + Object.assign( + new Guild(cache.session, guild), + { members, channels }, + ), + ); }