mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
cache preview version alpha
This commit is contained in:
parent
04b856818c
commit
0daec51769
@ -16,6 +16,8 @@ ignorePatterns:
|
|||||||
- 'coverage'
|
- 'coverage'
|
||||||
- '**/*.js'
|
- '**/*.js'
|
||||||
- '**/*.d.ts'
|
- '**/*.d.ts'
|
||||||
|
- '__tests__'
|
||||||
|
- '__test__'
|
||||||
|
|
||||||
parser: '@typescript-eslint/parser'
|
parser: '@typescript-eslint/parser'
|
||||||
|
|
||||||
|
34
packages/cache/README.md
vendored
34
packages/cache/README.md
vendored
@ -1,13 +1,39 @@
|
|||||||
# @biscuitland/cache
|
# @biscuitland/cache
|
||||||
|
|
||||||
In progress.
|
## Most importantly, biscuit's cache is:
|
||||||
|
|
||||||
|
A resource control cache layer, based on carriers and resource-intensive policies
|
||||||
|
|
||||||
[<img src="https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white">](https://github.com/oasisjs/biscuit)
|
[<img src="https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white">](https://github.com/oasisjs/biscuit)
|
||||||
[<img src="https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white">](https://discord.gg/XNw2RZFzaP)
|
[<img src="https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white">](https://discord.gg/XNw2RZFzaP)
|
||||||
|
|
||||||
|
<img align="right" src="https://raw.githubusercontent.com/oasisjs/biscuit/main/assets/icon.svg" alt="biscuit"/>
|
||||||
|
|
||||||
|
## Install (for [node18](https://nodejs.org/en/download/))
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
npm install @biscuitland/cache
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example (Basic)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Cache, MemoryCacheAdapter } from '@biscuitland/cache';
|
||||||
|
|
||||||
|
const bootstrap = async () => {
|
||||||
|
const cache = new Cache({
|
||||||
|
adapter: new MemoryCacheAdapter(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// You can listen to the raw biscuit event
|
||||||
|
|
||||||
|
cache.start(<payloads>);
|
||||||
|
};
|
||||||
|
|
||||||
|
bootstrap();
|
||||||
|
```
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- [Website](https://biscuitjs.com/)
|
|
||||||
- [Documentation](https://docs.biscuitjs.com/)
|
- [Documentation](https://docs.biscuitjs.com/)
|
||||||
- [Discord](https://discord.gg/XNw2RZFzaP)
|
- [Website](https://biscuitjs.com/)
|
||||||
- [core](https://www.npmjs.com/package/@biscuitland/core) | [api-types](https://www.npmjs.com/package/@biscuitland/api-types) | [rest](https://www.npmjs.com/package/@biscuitland/rest) | [ws](https://www.npmjs.com/package/@biscuitland/ws) | [helpers](https://www.npmjs.com/package/@biscuitland/helpers)
|
|
||||||
|
50
packages/cache/src/adapters/cache-adapter.ts
vendored
50
packages/cache/src/adapters/cache-adapter.ts
vendored
@ -1,50 +0,0 @@
|
|||||||
export interface CacheAdapter {
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
get(id: string): any | Promise<any>;
|
|
||||||
get(id: string, guild?: string): string | Promise<string>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
set(id: string, data: any, expire?: number): void | Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
count(to: string): number | Promise<number>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
remove(id: string): void | Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
contains(to: string, id: string): boolean | Promise<boolean>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
getToRelationship(to: string): string[] | Promise<string[]>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
addToRelationship(to: string, id: string): void | Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
removeToRelationship(to: string, id: string): void | Promise<void>;
|
|
||||||
}
|
|
121
packages/cache/src/adapters/redis-cache-adapter.ts
vendored
121
packages/cache/src/adapters/redis-cache-adapter.ts
vendored
@ -1,121 +0,0 @@
|
|||||||
import type { CacheAdapter } from './cache-adapter';
|
|
||||||
|
|
||||||
import type { RedisOptions } from 'ioredis';
|
|
||||||
import type Redis from 'ioredis';
|
|
||||||
import IORedis from 'ioredis';
|
|
||||||
|
|
||||||
interface BaseOptions {
|
|
||||||
namespace: string;
|
|
||||||
expire?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BuildOptions extends BaseOptions, RedisOptions { }
|
|
||||||
|
|
||||||
interface ClientOptions extends BaseOptions {
|
|
||||||
client: Redis;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Options = BuildOptions | ClientOptions;
|
|
||||||
|
|
||||||
export class RedisCacheAdapter implements CacheAdapter {
|
|
||||||
private static readonly DEFAULTS = {
|
|
||||||
namespace: 'biscuitland'
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly client: Redis;
|
|
||||||
|
|
||||||
readonly options: Options;
|
|
||||||
|
|
||||||
constructor(options?: Options) {
|
|
||||||
this.options = Object.assign(RedisCacheAdapter.DEFAULTS, options);
|
|
||||||
|
|
||||||
if ((this.options as ClientOptions).client) {
|
|
||||||
this.client = (this.options as ClientOptions).client;
|
|
||||||
} else {
|
|
||||||
const { ...redisOpt } = this.options as BuildOptions;
|
|
||||||
this.client = new IORedis(redisOpt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async get(id: string): Promise<any> {
|
|
||||||
const data = await this.client.get(this.composite(id));
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.parse(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async set(id: string, data: unknown, expire = this.options.expire): Promise<void> {
|
|
||||||
if (expire) {
|
|
||||||
await this.client.set(this.composite(id), JSON.stringify(data), 'EX', expire);
|
|
||||||
} else {
|
|
||||||
await this.client.set(this.composite(id), JSON.stringify(data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async count(_to: string): Promise<number> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
|
||||||
await this.client.del(this.composite(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async contains(_to: string, _id: string): Promise<boolean> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async getToRelationship(_to: string): Promise<string[]> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async addToRelationship(_to: string, _id: string): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async removeToRelationship(_to: string, _id: string): Promise<void> {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
composite(id: string): string {
|
|
||||||
return `${this.options.namespace}:${id}`;
|
|
||||||
}
|
|
||||||
}
|
|
184
packages/cache/src/cache.ts
vendored
184
packages/cache/src/cache.ts
vendored
@ -1,6 +1,8 @@
|
|||||||
/* eslint-disable no-case-declarations */
|
/* eslint-disable no-case-declarations */
|
||||||
import { MemoryCacheAdapter } from './adapters/memory-cache-adapter';
|
import type { CacheOptions, CO } from './types';
|
||||||
// import { RedisCacheAdapter } from './adapters/redis-cache-adapter';
|
|
||||||
|
import type { CacheAdapter } from './scheme/adapters/cache-adapter';
|
||||||
|
import { MemoryCacheAdapter } from './scheme/adapters/memory-cache-adapter';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChannelResource,
|
ChannelResource,
|
||||||
@ -9,26 +11,23 @@ import {
|
|||||||
GuildResource,
|
GuildResource,
|
||||||
GuildRoleResource,
|
GuildRoleResource,
|
||||||
GuildStickerResource,
|
GuildStickerResource,
|
||||||
|
GuildVoiceResource,
|
||||||
|
PresenceResource,
|
||||||
UserResource,
|
UserResource,
|
||||||
VoiceResource
|
|
||||||
} from './resources';
|
} from './resources';
|
||||||
|
|
||||||
/**
|
import { Options } from './utils/options';
|
||||||
* add options and adaptor passable by options
|
|
||||||
* @default MemoryCacheAdapter
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add more adapters and options
|
|
||||||
* Allow passing customizable resources and deleting resources
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add presence system (disabled by default)
|
|
||||||
* Add TTL option (default 7 days)
|
|
||||||
* Add permissions resource (accessible as a subResource)
|
|
||||||
*/
|
|
||||||
export class Cache {
|
export class Cache {
|
||||||
|
static readonly DEFAULTS = {
|
||||||
|
adapter: new MemoryCacheAdapter(),
|
||||||
|
};
|
||||||
|
|
||||||
|
readonly options: CO;
|
||||||
|
#adapter: CacheAdapter;
|
||||||
|
|
||||||
|
// move to resources assigned
|
||||||
|
|
||||||
readonly channels: ChannelResource;
|
readonly channels: ChannelResource;
|
||||||
|
|
||||||
readonly emojis: GuildEmojiResource;
|
readonly emojis: GuildEmojiResource;
|
||||||
@ -36,61 +35,64 @@ export class Cache {
|
|||||||
readonly guilds: GuildResource;
|
readonly guilds: GuildResource;
|
||||||
readonly roles: GuildRoleResource;
|
readonly roles: GuildRoleResource;
|
||||||
readonly stickers: GuildStickerResource;
|
readonly stickers: GuildStickerResource;
|
||||||
|
readonly voices: GuildVoiceResource;
|
||||||
|
|
||||||
|
readonly presences: PresenceResource;
|
||||||
readonly users: UserResource;
|
readonly users: UserResource;
|
||||||
readonly voices: VoiceResource;
|
|
||||||
|
|
||||||
ready: boolean;
|
constructor(options: CacheOptions) {
|
||||||
|
this.options = Options({}, Cache.DEFAULTS, options);
|
||||||
|
this.#adapter = this.options.adapter;
|
||||||
|
|
||||||
constructor() {
|
this.channels = new ChannelResource(this.#adapter);
|
||||||
this.ready = false;
|
|
||||||
|
|
||||||
/** this change to memory */
|
this.emojis = new GuildEmojiResource(this.#adapter);
|
||||||
const adapter = new MemoryCacheAdapter();
|
this.members = new GuildMemberResource(this.#adapter);
|
||||||
|
|
||||||
this.channels = new ChannelResource(adapter);
|
this.guilds = new GuildResource(this.#adapter);
|
||||||
|
this.roles = new GuildRoleResource(this.#adapter);
|
||||||
|
|
||||||
this.emojis = new GuildEmojiResource(adapter);
|
this.stickers = new GuildStickerResource(this.#adapter);
|
||||||
this.members = new GuildMemberResource(adapter);
|
this.voices = new GuildVoiceResource(this.#adapter);
|
||||||
|
|
||||||
this.guilds = new GuildResource(adapter);
|
this.presences = new PresenceResource(this.#adapter);
|
||||||
this.roles = new GuildRoleResource(adapter);
|
this.users = new UserResource(this.#adapter);
|
||||||
this.stickers = new GuildStickerResource(adapter);
|
|
||||||
|
|
||||||
this.users = new UserResource(adapter);
|
|
||||||
this.voices = new VoiceResource(adapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async start(event: { t: string; d: any }) {
|
async start(event: any) {
|
||||||
|
let resources: any[] = [];
|
||||||
|
|
||||||
|
let contents: any[] = [];
|
||||||
|
|
||||||
switch (event.t) {
|
switch (event.t) {
|
||||||
case 'READY':
|
case 'READY':
|
||||||
|
resources = [];
|
||||||
|
|
||||||
await this.users.set(event.d.user.id, event.d.user);
|
await this.users.set(event.d.user.id, event.d.user);
|
||||||
|
|
||||||
const guilds: (Promise<any> | undefined)[] = [];
|
|
||||||
|
|
||||||
for (const guild of event.d.guilds) {
|
for (const guild of event.d.guilds) {
|
||||||
guilds.push(this.guilds.set(guild.id, guild));
|
resources.push(this.guilds.set(guild.id, guild));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(guilds);
|
await Promise.all(resources);
|
||||||
|
|
||||||
this.ready = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'USER_UPDATE':
|
case 'USER_UPDATE':
|
||||||
await this.users.set(event.d.id, event.d);
|
await this.users.set(event.d.id, event.d);
|
||||||
break;
|
break;
|
||||||
|
case 'PRESENCE_UPDATE':
|
||||||
|
await this.presences.set(event.d.user?.id, event.d);
|
||||||
|
|
||||||
case 'GUILD_CREATE':
|
|
||||||
await this.guilds.set(event.d.id, event.d);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'GUILD_CREATE':
|
||||||
case 'GUILD_UPDATE':
|
case 'GUILD_UPDATE':
|
||||||
this.guilds.set(event.d.id, event.d);
|
await this.guilds.set(event.d.id, event.d);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'GUILD_DELETE':
|
case 'GUILD_DELETE':
|
||||||
@ -102,10 +104,6 @@ export class Cache {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'CHANNEL_CREATE':
|
case 'CHANNEL_CREATE':
|
||||||
// modify [Add elimination system]
|
|
||||||
await this.channels.set(event.d.id, event.d);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'CHANNEL_UPDATE':
|
case 'CHANNEL_UPDATE':
|
||||||
// modify [Add elimination system]
|
// modify [Add elimination system]
|
||||||
await this.channels.set(event.d.id, event.d);
|
await this.channels.set(event.d.id, event.d);
|
||||||
@ -116,14 +114,18 @@ export class Cache {
|
|||||||
await this.channels.remove(event.d.id);
|
await this.channels.remove(event.d.id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'GUILD_ROLE_CREATE':
|
case 'MESSAGE_CREATE':
|
||||||
await this.roles.set(
|
if (event.d.webhook_id) {
|
||||||
event.d.role.id,
|
return;
|
||||||
event.d.guild_id,
|
}
|
||||||
event.d.role
|
|
||||||
);
|
if (event.d.author) {
|
||||||
|
await this.users.set(event.d.author.id, event.d.author);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'GUILD_ROLE_CREATE':
|
||||||
case 'GUILD_ROLE_UPDATE':
|
case 'GUILD_ROLE_UPDATE':
|
||||||
await this.roles.set(
|
await this.roles.set(
|
||||||
event.d.role.id,
|
event.d.role.id,
|
||||||
@ -137,27 +139,62 @@ export class Cache {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'GUILD_EMOJIS_UPDATE':
|
case 'GUILD_EMOJIS_UPDATE':
|
||||||
// modify [Add elimination system]
|
contents = [];
|
||||||
for (const v of event.d.emojis) {
|
contents = await this.emojis.items(event.d.guild_id);
|
||||||
await this.emojis?.set(v.id, event.d.guild_id, v);
|
|
||||||
|
for (const emoji of event.d.emojis) {
|
||||||
|
const emote = contents.find(o => o?.id === emoji.id);
|
||||||
|
|
||||||
|
if (!emote || emote !== emoji) {
|
||||||
|
await this.emojis.set(
|
||||||
|
emoji.id,
|
||||||
|
event.d.guild_id,
|
||||||
|
emoji
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const emoji of contents) {
|
||||||
|
const emote = event.d.emojis.find(
|
||||||
|
(o: any) => o.id === emoji?.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!emote) {
|
||||||
|
await this.emojis.remove(emote.id, event.d.guild_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'GUILD_STICKERS_UPDATE':
|
case 'GUILD_STICKERS_UPDATE':
|
||||||
// modify [Add elimination system]
|
contents = [];
|
||||||
for (const v of event.d.stickers) {
|
contents = await this.stickers.items(event.d.guild_id);
|
||||||
await this.stickers?.set(v.id, event.d.guild_id, v);
|
|
||||||
|
for (const sticker of event.d.stickers) {
|
||||||
|
const stick = contents.find(o => o?.id === sticker.id);
|
||||||
|
|
||||||
|
if (!stick || stick !== sticker) {
|
||||||
|
await this.stickers.set(
|
||||||
|
sticker.id,
|
||||||
|
event.d.guild_id,
|
||||||
|
sticker
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const sticker of contents) {
|
||||||
|
const stick = event.d.stickers.find(
|
||||||
|
(o: any) => o.id === sticker?.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!stick) {
|
||||||
|
await this.stickers.remove(stick.id, event.d.guild_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'GUILD_MEMBER_ADD':
|
case 'GUILD_MEMBER_ADD':
|
||||||
await this.members.set(
|
|
||||||
event.d.user.id,
|
|
||||||
event.d.guild_id,
|
|
||||||
event.d
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'GUILD_MEMBER_UPDATE':
|
case 'GUILD_MEMBER_UPDATE':
|
||||||
await this.members.set(
|
await this.members.set(
|
||||||
event.d.user.id,
|
event.d.user.id,
|
||||||
@ -171,10 +208,10 @@ export class Cache {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'GUILD_MEMBERS_CHUNK':
|
case 'GUILD_MEMBERS_CHUNK':
|
||||||
const members: (Promise<any> | undefined)[] = [];
|
resources = [];
|
||||||
|
|
||||||
for (const member of event.d.members) {
|
for (const member of event.d.members) {
|
||||||
members.push(
|
resources.push(
|
||||||
this.members.set(
|
this.members.set(
|
||||||
member.user.id,
|
member.user.id,
|
||||||
event.d.guild_id,
|
event.d.guild_id,
|
||||||
@ -183,7 +220,7 @@ export class Cache {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(members);
|
await Promise.all(resources);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -192,16 +229,15 @@ export class Cache {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.d.user_id && event.d.member) {
|
if (event.d.guild_id && event.d.member && event.d.user_id) {
|
||||||
await this.members.set(
|
await this.members.set(event.d.user_id, event.d.guild_id, {
|
||||||
event.d.user_id,
|
guild_id: event.d.guild_id,
|
||||||
event.d.guild_id,
|
...event.d.member,
|
||||||
event.d.member
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.d.channel_id != null) {
|
if (event.d.channel_id != null) {
|
||||||
await this.voices.set(
|
await this.members.set(
|
||||||
event.d.user_id,
|
event.d.user_id,
|
||||||
event.d.guild_id,
|
event.d.guild_id,
|
||||||
event.d
|
event.d
|
||||||
|
7
packages/cache/src/index.ts
vendored
7
packages/cache/src/index.ts
vendored
@ -1,6 +1,7 @@
|
|||||||
export { CacheAdapter } from './adapters/cache-adapter';
|
export { MemoryCacheAdapter } from './scheme/adapters/memory-cache-adapter';
|
||||||
|
export { RedisCacheAdapter } from './scheme/adapters/redis-cache-adapter';
|
||||||
|
|
||||||
export { MemoryCacheAdapter } from './adapters/memory-cache-adapter';
|
export { CacheAdapter } from './scheme/adapters/cache-adapter';
|
||||||
export { RedisCacheAdapter } from './adapters/redis-cache-adapter';
|
|
||||||
|
|
||||||
|
export { RedisOptions, MemoryOptions, CacheOptions } from './types';
|
||||||
export { Cache } from './cache';
|
export { Cache } from './cache';
|
||||||
|
112
packages/cache/src/resources/base-resource.ts
vendored
112
packages/cache/src/resources/base-resource.ts
vendored
@ -1,63 +1,117 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
|
|
||||||
export class BaseResource {
|
/**
|
||||||
namespace = 'base';
|
* Base class for all resources
|
||||||
|
* All Methods from BaseResource are also available on every class extends
|
||||||
|
*/
|
||||||
|
|
||||||
adapter!: CacheAdapter; // replace
|
class Base<T> {
|
||||||
|
/**
|
||||||
|
* Resource name
|
||||||
|
*/
|
||||||
|
|
||||||
|
#namespace = 'base';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* Adapter for storage processes and operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
#adapter: CacheAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guild linked and assigned to the current entity (resource)
|
||||||
|
*/
|
||||||
|
|
||||||
|
parent?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
constructor(namespace: string, adapter: CacheAdapter) {
|
||||||
|
this.#namespace = namespace;
|
||||||
|
this.#adapter = adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity linked
|
||||||
|
*/
|
||||||
|
|
||||||
|
setEntity(entity: T): void {
|
||||||
|
Object.assign(this, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent linked
|
||||||
|
*/
|
||||||
|
|
||||||
|
setParent(parent: string): void {
|
||||||
|
// rename
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count how many resources there are in the relationships
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async count(to: string): Promise<number> {
|
async count(to: string): Promise<number> {
|
||||||
return await this.adapter.count(this.hashId(to));
|
return await this.#adapter.count(this.hashId(to));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* Check if the resource is in the relationships
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async contains(to: string, id: string): Promise<boolean> {
|
async contains(
|
||||||
return await this.adapter.contains(this.hashId(to), id);
|
id: string,
|
||||||
|
guild: string = this.parent as string
|
||||||
|
): Promise<boolean> {
|
||||||
|
return await this.#adapter.contains(this.hashId(guild), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* Gets the resource relationships
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async getToRelationship(to: string): Promise<string[]> {
|
async getToRelationship(
|
||||||
return await this.adapter.getToRelationship(this.hashId(to));
|
id: string = this.parent as string
|
||||||
|
): Promise<string[]> {
|
||||||
|
return await this.#adapter.getToRelationship(this.hashId(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* Adds the resource to relationships
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async addToRelationship(to: string, id: string): Promise<void> {
|
async addToRelationship(
|
||||||
await this.adapter.addToRelationship(this.hashId(to), id);
|
id: string,
|
||||||
|
guild: string = this.parent as string
|
||||||
|
): Promise<void> {
|
||||||
|
await this.#adapter.addToRelationship(this.hashId(guild), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc // to-do replace
|
* Removes the relationship resource
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async removeToRelationship(to: string, id: string): Promise<void> {
|
async removeToRelationship(
|
||||||
await this.adapter.removeToRelationship(this.hashId(to), id);
|
id: string,
|
||||||
|
guild: string = this.parent as string
|
||||||
|
): Promise<void> {
|
||||||
|
await this.#adapter.removeToRelationship(this.hashId(guild), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* Construct an id consisting of namespace.id
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hashId(id: string): string {
|
protected hashId(id: string): string {
|
||||||
return `${this.namespace}.${id}`;
|
return `${this.#namespace}.${id}`;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
hashGuildId(id: string, guild: string): string {
|
|
||||||
return `${this.namespace}.${guild}.${id}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const BaseResource = Base as new <T>(
|
||||||
|
data: string,
|
||||||
|
adapter: CacheAdapter
|
||||||
|
) => Base<T> & T;
|
||||||
|
94
packages/cache/src/resources/channel-resource.ts
vendored
94
packages/cache/src/resources/channel-resource.ts
vendored
@ -1,42 +1,92 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
/**
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
import type { DiscordChannel } from '@biscuitland/api-types';
|
import type { DiscordChannel } from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { BaseResource } from './base-resource';
|
import { BaseResource } from './base-resource';
|
||||||
|
import { UserResource } from './user-resource';
|
||||||
|
|
||||||
export class ChannelResource extends BaseResource {
|
/**
|
||||||
namespace = 'channel' as const;
|
* Resource represented by an channel of discord
|
||||||
|
*/
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
export class ChannelResource extends BaseResource<DiscordChannel> {
|
||||||
|
#namespace = 'channel';
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
#adapter: CacheAdapter;
|
||||||
super();
|
|
||||||
|
|
||||||
this.adapter = adapter;
|
#users: UserResource;
|
||||||
|
|
||||||
|
constructor(adapter: CacheAdapter, entity?: DiscordChannel | null) {
|
||||||
|
super('channel', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
this.#users = new UserResource(adapter);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async get(id: string): Promise<DiscordChannel | null> {
|
async get(id: string): Promise<ChannelResource | null> {
|
||||||
const kv = await this.adapter.get(this.hashId(id));
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashId(id));
|
||||||
|
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv;
|
return new ChannelResource(this.#adapter, kv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc // to-do rework
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async set(id: string, data: any, expire?: number): Promise<void> {
|
async set(id: string, data: any): Promise<void> {
|
||||||
|
if (data.recipients) {
|
||||||
|
const recipients = [];
|
||||||
|
|
||||||
|
for (const recipient of data.recipients) {
|
||||||
|
recipients.push(this.#users.set(recipient.id, recipient));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(recipients);
|
||||||
|
}
|
||||||
|
|
||||||
delete data.recipients;
|
delete data.recipients;
|
||||||
|
delete data.permission_overwrites;
|
||||||
|
|
||||||
await this.addToRelationship(id);
|
await this.addToRelationship(id);
|
||||||
await this.adapter.set(this.hashId(id), data, expire);
|
await this.#adapter.set(this.hashId(id), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async items(): Promise<ChannelResource[]> {
|
||||||
|
const data = await this.#adapter.items(this.#namespace);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => {
|
||||||
|
const resource = new ChannelResource(this.#adapter, dt);
|
||||||
|
resource.setParent(resource.id);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +94,7 @@ export class ChannelResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async count(): Promise<number> {
|
async count(): Promise<number> {
|
||||||
return await this.adapter.count(this.namespace);
|
return await this.#adapter.count(this.#namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,7 +102,7 @@ export class ChannelResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
await this.adapter.remove(this.hashId(id));
|
await this.#adapter.remove(this.hashId(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,7 +110,7 @@ export class ChannelResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async contains(id: string): Promise<boolean> {
|
async contains(id: string): Promise<boolean> {
|
||||||
return await this.adapter.contains(this.namespace, id);
|
return await this.#adapter.contains(this.#namespace, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +118,7 @@ export class ChannelResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async getToRelationship(): Promise<string[]> {
|
async getToRelationship(): Promise<string[]> {
|
||||||
return await this.adapter.getToRelationship(this.namespace);
|
return await this.#adapter.getToRelationship(this.#namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,6 +126,14 @@ export class ChannelResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async addToRelationship(id: string): Promise<void> {
|
async addToRelationship(id: string): Promise<void> {
|
||||||
await this.adapter.addToRelationship(this.namespace, id);
|
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async removeToRelationship(id: string): Promise<void> {
|
||||||
|
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
109
packages/cache/src/resources/guild-emoji-resource.ts
vendored
109
packages/cache/src/resources/guild-emoji-resource.ts
vendored
@ -1,28 +1,55 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
import type { DiscordEmoji } from '@biscuitland/api-types';
|
import type { DiscordEmoji } from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { BaseResource } from './base-resource';
|
import { BaseResource } from './base-resource';
|
||||||
|
import { UserResource } from './user-resource';
|
||||||
|
|
||||||
export class GuildEmojiResource extends BaseResource {
|
/**
|
||||||
namespace = 'emoji' as const;
|
* Resource represented by an emoji of discord
|
||||||
|
*/
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
export class GuildEmojiResource extends BaseResource<DiscordEmoji> {
|
||||||
|
#namespace = 'emoji' as const;
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
#adapter: CacheAdapter;
|
||||||
super();
|
|
||||||
|
|
||||||
this.adapter = adapter;
|
#users: UserResource;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
adapter: CacheAdapter,
|
||||||
|
entity?: DiscordEmoji | null,
|
||||||
|
parent?: string
|
||||||
|
) {
|
||||||
|
super('emoji', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
this.#users = new UserResource(adapter);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
this.setParent(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async get(id: string, guild: string): Promise<DiscordEmoji | null> {
|
async get(
|
||||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<GuildEmojiResource | null> {
|
||||||
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||||
|
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv;
|
return new GuildEmojiResource(this.#adapter, kv, guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -34,18 +61,68 @@ export class GuildEmojiResource extends BaseResource {
|
|||||||
|
|
||||||
async set(
|
async set(
|
||||||
id: string,
|
id: string,
|
||||||
guild: string,
|
guild: string | undefined = this.parent,
|
||||||
data: any,
|
data: any
|
||||||
expire?: number
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
if (data.user) {
|
||||||
|
await this.#users.set(data.user.id, data.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete data.user;
|
||||||
|
delete data.roles;
|
||||||
|
|
||||||
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.addToRelationship(id, guild);
|
||||||
|
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async remove(id: string, guild: string): Promise<void> {
|
async items(to: string): Promise<GuildEmojiResource[]> {
|
||||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
if (!to && this.parent) {
|
||||||
|
to = this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.#adapter.items(this.hashId(to));
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => {
|
||||||
|
const resource = new GuildEmojiResource(this.#adapter, dt);
|
||||||
|
resource.setParent(to);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async remove(
|
||||||
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<void> {
|
||||||
|
await this.removeToRelationship(id, guild);
|
||||||
|
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected hashGuildId(id: string, guild?: string): string {
|
||||||
|
if (!guild) {
|
||||||
|
return this.hashId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.#namespace}.${guild}.${id}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,37 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
import type { DiscordMember } from '@biscuitland/api-types';
|
import type { DiscordMember } from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { BaseResource } from './base-resource';
|
import { BaseResource } from './base-resource';
|
||||||
import { UserResource } from './user-resource';
|
import { UserResource } from './user-resource';
|
||||||
|
|
||||||
export class GuildMemberResource extends BaseResource {
|
/**
|
||||||
namespace = 'member' as const;
|
* Resource represented by an member of discord
|
||||||
|
*/
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
export class GuildMemberResource extends BaseResource<DiscordMember> {
|
||||||
users: UserResource;
|
#namespace = 'member' as const;
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
#adapter: CacheAdapter;
|
||||||
super();
|
|
||||||
|
|
||||||
this.adapter = adapter;
|
#users: UserResource;
|
||||||
this.users = new UserResource(adapter);
|
|
||||||
|
constructor(
|
||||||
|
adapter: CacheAdapter,
|
||||||
|
entity?: DiscordMember | null,
|
||||||
|
parent?: string
|
||||||
|
) {
|
||||||
|
super('member', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
this.#users = new UserResource(adapter);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
this.setParent(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,12 +40,16 @@ export class GuildMemberResource extends BaseResource {
|
|||||||
|
|
||||||
async get(
|
async get(
|
||||||
id: string,
|
id: string,
|
||||||
guild: string
|
guild: string | undefined = this.parent
|
||||||
): Promise<(DiscordMember & { id: string }) | null> {
|
): Promise<GuildMemberResource | null> {
|
||||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||||
|
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv;
|
return new GuildMemberResource(this.#adapter, kv, guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -40,33 +61,68 @@ export class GuildMemberResource extends BaseResource {
|
|||||||
|
|
||||||
async set(
|
async set(
|
||||||
id: string,
|
id: string,
|
||||||
guild: string,
|
guild: string | undefined = this.parent,
|
||||||
data: any,
|
data: any
|
||||||
expire?: number
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!data.id) {
|
|
||||||
data.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.user) {
|
if (data.user) {
|
||||||
await this.users.set(data.user.id, data.user);
|
await this.#users.set(data.user.id, data.user);
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.guild_id) {
|
|
||||||
data.guild_id = guild;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete data.user;
|
delete data.user;
|
||||||
|
delete data.roles;
|
||||||
|
|
||||||
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
|
}
|
||||||
|
|
||||||
await this.addToRelationship(id, guild);
|
await this.addToRelationship(id, guild);
|
||||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async remove(id: string, guild: string): Promise<void> {
|
async items(to: string): Promise<GuildMemberResource[]> {
|
||||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
if (!to && this.parent) {
|
||||||
|
to = this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.#adapter.items(this.hashId(to));
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => {
|
||||||
|
const resource = new GuildMemberResource(this.#adapter, dt);
|
||||||
|
resource.setParent(to);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async remove(
|
||||||
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<void> {
|
||||||
|
await this.removeToRelationship(id, guild);
|
||||||
|
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected hashGuildId(id: string, guild?: string): string {
|
||||||
|
if (!guild) {
|
||||||
|
return this.hashId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.#namespace}.${guild}.${id}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
275
packages/cache/src/resources/guild-resource.ts
vendored
275
packages/cache/src/resources/guild-resource.ts
vendored
@ -1,4 +1,8 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
/**
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
import type { DiscordGuild } from '@biscuitland/api-types';
|
import type { DiscordGuild } from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { ChannelResource } from './channel-resource';
|
import { ChannelResource } from './channel-resource';
|
||||||
@ -6,44 +10,90 @@ import { GuildEmojiResource } from './guild-emoji-resource';
|
|||||||
import { GuildMemberResource } from './guild-member-resource';
|
import { GuildMemberResource } from './guild-member-resource';
|
||||||
import { GuildRoleResource } from './guild-role-resource';
|
import { GuildRoleResource } from './guild-role-resource';
|
||||||
import { GuildStickerResource } from './guild-sticker-resource';
|
import { GuildStickerResource } from './guild-sticker-resource';
|
||||||
import { VoiceResource } from './voice-resource';
|
import { GuildVoiceResource } from './guild-voice-resource';
|
||||||
|
|
||||||
|
import { PresenceResource } from './presence-resource';
|
||||||
import { BaseResource } from './base-resource';
|
import { BaseResource } from './base-resource';
|
||||||
|
|
||||||
export class GuildResource extends BaseResource {
|
/**
|
||||||
namespace = 'guild' as const;
|
* Resource represented by an guild of discord
|
||||||
|
*/
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
export class GuildResource extends BaseResource<DiscordGuild> {
|
||||||
|
#namespace = 'guild' as const;
|
||||||
|
|
||||||
private channels: ChannelResource;
|
#adapter: CacheAdapter;
|
||||||
private emojis: GuildEmojiResource;
|
|
||||||
private members: GuildMemberResource;
|
|
||||||
private roles: GuildRoleResource;
|
|
||||||
private stickers: GuildStickerResource;
|
|
||||||
private voices: VoiceResource;
|
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
#channels: ChannelResource;
|
||||||
super();
|
#emojis: GuildEmojiResource;
|
||||||
|
#members: GuildMemberResource;
|
||||||
|
#roles: GuildRoleResource;
|
||||||
|
#stickers: GuildStickerResource;
|
||||||
|
#voices: GuildVoiceResource;
|
||||||
|
|
||||||
this.adapter = adapter;
|
#presences: PresenceResource;
|
||||||
|
|
||||||
this.channels = new ChannelResource(adapter);
|
constructor(
|
||||||
this.emojis = new GuildEmojiResource(adapter);
|
adapter: CacheAdapter,
|
||||||
this.members = new GuildMemberResource(adapter);
|
entity?: DiscordGuild | null,
|
||||||
this.roles = new GuildRoleResource(adapter);
|
parent?: string,
|
||||||
this.stickers = new GuildStickerResource(adapter);
|
channels?: ChannelResource,
|
||||||
this.voices = new VoiceResource(adapter);
|
emojis?: GuildEmojiResource,
|
||||||
|
members?: GuildMemberResource,
|
||||||
|
roles?: GuildRoleResource,
|
||||||
|
stickers?: GuildStickerResource,
|
||||||
|
voices?: GuildVoiceResource,
|
||||||
|
presences?: PresenceResource
|
||||||
|
) {
|
||||||
|
super('guild', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
|
||||||
|
this.#channels = channels ?? new ChannelResource(adapter);
|
||||||
|
|
||||||
|
this.#emojis = emojis ?? new GuildEmojiResource(adapter);
|
||||||
|
this.#members = members ?? new GuildMemberResource(adapter);
|
||||||
|
|
||||||
|
this.#roles = roles ?? new GuildRoleResource(adapter);
|
||||||
|
|
||||||
|
this.#stickers = stickers ?? new GuildStickerResource(adapter);
|
||||||
|
|
||||||
|
this.#voices = voices ?? new GuildVoiceResource(adapter);
|
||||||
|
this.#presences = presences ?? new PresenceResource(adapter);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
this.setParent(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async get(id: string): Promise<DiscordGuild | null> {
|
async get(id: string): Promise<GuildResource | null> {
|
||||||
const kv = await this.adapter.get(this.hashId(id));
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashId(id));
|
||||||
|
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv;
|
return new GuildResource(
|
||||||
|
this.#adapter,
|
||||||
|
kv,
|
||||||
|
id,
|
||||||
|
new ChannelResource(this.#adapter),
|
||||||
|
new GuildEmojiResource(this.#adapter, null, id),
|
||||||
|
new GuildMemberResource(this.#adapter, null, id),
|
||||||
|
new GuildRoleResource(this.#adapter, null, id),
|
||||||
|
new GuildStickerResource(this.#adapter, null, id),
|
||||||
|
new GuildVoiceResource(this.#adapter, null, id),
|
||||||
|
new PresenceResource(this.#adapter)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -53,83 +103,125 @@ export class GuildResource extends BaseResource {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async set(id: string, data: any, expire?: number): Promise<void> {
|
async set(id: string, data: any): Promise<void> {
|
||||||
if (data.channels) {
|
if (data.channels) {
|
||||||
const channels: (Promise<any> | undefined)[] = [];
|
const channels: unknown[] = [];
|
||||||
|
|
||||||
for (const channel of data.channels) {
|
for (const channel of data.channels) {
|
||||||
await this.channels.set(channel.id, channel);
|
channel.guild_id = id;
|
||||||
|
|
||||||
|
await this.#channels.set(channel.id, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(channels);
|
await Promise.all(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.emojis) {
|
||||||
|
const emojis: unknown[] = [];
|
||||||
|
|
||||||
|
for (const emoji of data.emojis) {
|
||||||
|
emoji.guild_id = id;
|
||||||
|
|
||||||
|
await this.#emojis.set(emoji.id, id, emoji);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(emojis);
|
||||||
|
}
|
||||||
|
|
||||||
if (data.members) {
|
if (data.members) {
|
||||||
const members: (Promise<any> | undefined)[] = [];
|
const members: unknown[] = [];
|
||||||
|
|
||||||
for (const member of data.members) {
|
for (const member of data.members) {
|
||||||
await this.members.set(member.user.id, id, member);
|
member.guild_id = id;
|
||||||
|
|
||||||
|
await this.#members.set(member.user.id, id, member);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(members);
|
await Promise.all(members);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.roles) {
|
if (data.roles) {
|
||||||
const roles: (Promise<any> | undefined)[] = [];
|
const roles: unknown[] = [];
|
||||||
|
|
||||||
for (const role of data.roles) {
|
for (const role of data.roles) {
|
||||||
await this.roles.set(role.id, id, role);
|
role.guild_id = id;
|
||||||
|
|
||||||
|
await this.#roles.set(role.id, id, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(roles);
|
await Promise.all(roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.stickers) {
|
if (data.stickers) {
|
||||||
const stickers: (Promise<any> | undefined)[] = [];
|
const stickers: unknown[] = [];
|
||||||
|
|
||||||
for (const sticker of data.stickers) {
|
for (const sticker of data.stickers) {
|
||||||
await this.stickers.set(sticker.id, id, sticker);
|
sticker.guild_id = id;
|
||||||
|
|
||||||
|
await this.#stickers.set(sticker.id, id, sticker);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(stickers);
|
await Promise.all(stickers);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.emojis) {
|
|
||||||
const emojis: (Promise<any> | undefined)[] = [];
|
|
||||||
|
|
||||||
for (const emoji of data.emojis) {
|
|
||||||
await this.emojis.set(emoji.id, id, emoji);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(emojis);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.voice_states) {
|
if (data.voice_states) {
|
||||||
const voices: Promise<any>[] = [];
|
const voices: unknown[] = [];
|
||||||
|
|
||||||
for (const voice of data.voice_states) {
|
for (const voice of data.voice_states) {
|
||||||
if (!voice.guild_id) {
|
voice.guild_id = id;
|
||||||
voice.guild_id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
voices.push(this.voices.set(voice.user_id, id, voice));
|
voices.push(this.#voices.set(voice.user_id, id, voice));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(voices);
|
await Promise.all(voices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.presences) {
|
||||||
|
const presences: unknown[] = [];
|
||||||
|
|
||||||
|
for (const presence of data.presences) {
|
||||||
|
await this.#presences.set(presence.user.id, presence);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(presences);
|
||||||
|
}
|
||||||
|
|
||||||
delete data.channels;
|
delete data.channels;
|
||||||
|
delete data.emojis;
|
||||||
delete data.members;
|
delete data.members;
|
||||||
delete data.roles;
|
delete data.roles;
|
||||||
delete data.stickers;
|
delete data.stickers;
|
||||||
delete data.emojis;
|
|
||||||
|
delete data.voice_states;
|
||||||
|
delete data.guild_hashes;
|
||||||
|
|
||||||
delete data.presences;
|
delete data.presences;
|
||||||
|
|
||||||
delete data.voice_states;
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
|
}
|
||||||
|
|
||||||
await this.addToRelationship(id);
|
await this.addToRelationship(id);
|
||||||
await this.adapter.set(this.hashId(id), data, expire);
|
await this.#adapter.set(this.hashId(id), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async items(): Promise<GuildResource[]> {
|
||||||
|
const data = await this.#adapter.items(this.#namespace);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => {
|
||||||
|
const resource = new GuildResource(this.#adapter, dt);
|
||||||
|
resource.setParent(resource.id);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +229,7 @@ export class GuildResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async count(): Promise<number> {
|
async count(): Promise<number> {
|
||||||
return await this.adapter.count(this.namespace);
|
return await this.#adapter.count(this.#namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,7 +237,32 @@ export class GuildResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
await this.adapter.remove(this.hashId(id));
|
const members = await this.#members.getToRelationship(id);
|
||||||
|
|
||||||
|
for (const member of members) {
|
||||||
|
await this.#members.remove(member, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const roles = await this.#roles.getToRelationship(id);
|
||||||
|
|
||||||
|
for (const role of roles) {
|
||||||
|
await this.#roles.remove(role, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emojis = await this.#emojis.getToRelationship(id);
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
await this.#emojis.remove(emoji, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stickers = await this.#stickers.getToRelationship(id);
|
||||||
|
|
||||||
|
for (const sticker of stickers) {
|
||||||
|
await this.#stickers.remove(sticker, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.removeToRelationship(id);
|
||||||
|
await this.#adapter.remove(this.hashId(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,7 +270,7 @@ export class GuildResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async contains(id: string): Promise<boolean> {
|
async contains(id: string): Promise<boolean> {
|
||||||
return await this.adapter.contains(this.namespace, id);
|
return await this.#adapter.contains(this.#namespace, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,7 +278,7 @@ export class GuildResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async getToRelationship(): Promise<string[]> {
|
async getToRelationship(): Promise<string[]> {
|
||||||
return await this.adapter.getToRelationship(this.namespace);
|
return await this.#adapter.getToRelationship(this.#namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,6 +286,54 @@ export class GuildResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async addToRelationship(id: string): Promise<void> {
|
async addToRelationship(id: string): Promise<void> {
|
||||||
await this.adapter.addToRelationship(this.namespace, id);
|
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async removeToRelationship(id: string): Promise<void> {
|
||||||
|
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getEmojis(): Promise<GuildEmojiResource[]> {
|
||||||
|
return await this.#emojis.items(this.parent as string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getMembers(): Promise<GuildMemberResource[]> {
|
||||||
|
return await this.#members.items(this.parent as string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getRoles(): Promise<GuildRoleResource[]> {
|
||||||
|
return await this.#roles.items(this.parent as string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getStickers(): Promise<GuildStickerResource[]> {
|
||||||
|
return await this.#stickers.items(this.parent as string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getVoiceStates(): Promise<GuildVoiceResource[]> {
|
||||||
|
return await this.#voices.items(this.parent as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
106
packages/cache/src/resources/guild-role-resource.ts
vendored
106
packages/cache/src/resources/guild-role-resource.ts
vendored
@ -1,28 +1,51 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
import type { DiscordRole } from '@biscuitland/api-types';
|
import type { DiscordRole } from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { BaseResource } from './base-resource';
|
import { BaseResource } from './base-resource';
|
||||||
|
|
||||||
export class GuildRoleResource extends BaseResource {
|
/**
|
||||||
namespace = 'role' as const;
|
* Resource represented by an role of discord
|
||||||
|
*/
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
export class GuildRoleResource extends BaseResource<DiscordRole> {
|
||||||
|
#namespace = 'role' as const;
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
#adapter: CacheAdapter;
|
||||||
super();
|
|
||||||
|
|
||||||
this.adapter = adapter;
|
constructor(
|
||||||
|
adapter: CacheAdapter,
|
||||||
|
entity?: DiscordRole | null,
|
||||||
|
parent?: string
|
||||||
|
) {
|
||||||
|
super('role', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
this.setParent(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async get(id: string, guild: string): Promise<DiscordRole | null> {
|
async get(
|
||||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<GuildRoleResource | null> {
|
||||||
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||||
|
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv;
|
return new GuildRoleResource(this.#adapter, kv, guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -34,9 +57,8 @@ export class GuildRoleResource extends BaseResource {
|
|||||||
|
|
||||||
async set(
|
async set(
|
||||||
id: string,
|
id: string,
|
||||||
guild: string,
|
guild: string | undefined = this.parent,
|
||||||
data: any,
|
data: any
|
||||||
expire?: number
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
data.id = id;
|
data.id = id;
|
||||||
@ -46,14 +68,66 @@ export class GuildRoleResource extends BaseResource {
|
|||||||
data.guild_id = guild;
|
data.guild_id = guild;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.addToRelationship(id, guild);
|
||||||
|
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async remove(id: string, guild: string): Promise<void> {
|
async count(): Promise<number> {
|
||||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
return await this.#adapter.count(this.#namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async items(to: string): Promise<GuildRoleResource[]> {
|
||||||
|
if (!to && this.parent) {
|
||||||
|
to = this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.#adapter.items(this.hashId(to));
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => {
|
||||||
|
const resource = new GuildRoleResource(this.#adapter, dt);
|
||||||
|
resource.setParent(to);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async remove(
|
||||||
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<void> {
|
||||||
|
await this.removeToRelationship(id, guild);
|
||||||
|
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected hashGuildId(id: string, guild?: string): string {
|
||||||
|
if (!guild) {
|
||||||
|
return this.hashId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.#namespace}.${guild}.${id}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,52 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
import type { DiscordSticker } from '@biscuitland/api-types';
|
import type { DiscordSticker } from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { BaseResource } from './base-resource';
|
import { BaseResource } from './base-resource';
|
||||||
|
import { UserResource } from './user-resource';
|
||||||
|
|
||||||
export class GuildStickerResource extends BaseResource {
|
/**
|
||||||
namespace = 'sticker' as const;
|
* Resource represented by an sticker of discord
|
||||||
|
*/
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
export class GuildStickerResource extends BaseResource<DiscordSticker> {
|
||||||
|
#namespace = 'sticker' as const;
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
#adapter: CacheAdapter;
|
||||||
super();
|
|
||||||
|
|
||||||
this.adapter = adapter;
|
#users: UserResource;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
adapter: CacheAdapter,
|
||||||
|
entity?: DiscordSticker | null,
|
||||||
|
parent?: string
|
||||||
|
) {
|
||||||
|
super('sticker', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
this.#users = new UserResource(adapter);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
this.setParent(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async get(id: string, guild: string): Promise<DiscordSticker | null> {
|
async get(id: string, guild: string): Promise<GuildStickerResource | null> {
|
||||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||||
|
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv;
|
return new GuildStickerResource(this.#adapter, kv, guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -34,26 +58,67 @@ export class GuildStickerResource extends BaseResource {
|
|||||||
|
|
||||||
async set(
|
async set(
|
||||||
id: string,
|
id: string,
|
||||||
guild: string,
|
guild: string | undefined = this.parent,
|
||||||
data: any,
|
data: any
|
||||||
expire?: number
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!data.id) {
|
if (data.user) {
|
||||||
data.id = id;
|
await this.#users.set(data.user.id, data.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.guild_id) {
|
delete data.user;
|
||||||
data.guild_id = guild;
|
|
||||||
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
await this.addToRelationship(id, guild);
|
||||||
|
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async remove(id: string, guild: string): Promise<void> {
|
async items(to: string): Promise<GuildStickerResource[]> {
|
||||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
if (!to && this.parent) {
|
||||||
|
to = this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.#adapter.items(this.hashId(to));
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => {
|
||||||
|
const resource = new GuildStickerResource(this.#adapter, dt);
|
||||||
|
resource.setParent(to);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async remove(
|
||||||
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<void> {
|
||||||
|
await this.removeToRelationship(id, guild);
|
||||||
|
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected hashGuildId(id: string, guild?: string): string {
|
||||||
|
if (!guild) {
|
||||||
|
return this.hashId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.#namespace}.${guild}.${id}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
127
packages/cache/src/resources/guild-voice-resource.ts
vendored
Normal file
127
packages/cache/src/resources/guild-voice-resource.ts
vendored
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
|
import type { DiscordVoiceState } from '@biscuitland/api-types';
|
||||||
|
|
||||||
|
import { BaseResource } from './base-resource';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource represented by an voice state of discord
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class GuildVoiceResource extends BaseResource<DiscordVoiceState> {
|
||||||
|
#namespace = 'voice' as const;
|
||||||
|
|
||||||
|
#adapter: CacheAdapter;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
adapter: CacheAdapter,
|
||||||
|
entity?: DiscordVoiceState | null,
|
||||||
|
parent?: string
|
||||||
|
) {
|
||||||
|
super('voice', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
this.setParent(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async get(
|
||||||
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<GuildVoiceResource | null> {
|
||||||
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||||
|
|
||||||
|
if (kv) {
|
||||||
|
return new GuildVoiceResource(this.#adapter, kv, guild);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async set(
|
||||||
|
id: string,
|
||||||
|
guild: string | undefined = this.parent,
|
||||||
|
data: any
|
||||||
|
): Promise<void> {
|
||||||
|
if (!data.guild_id) {
|
||||||
|
data.guild_id = guild;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete data.member;
|
||||||
|
|
||||||
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.addToRelationship(id, guild);
|
||||||
|
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async items(to: string): Promise<GuildVoiceResource[]> {
|
||||||
|
if (!to && this.parent) {
|
||||||
|
to = this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.#adapter.items(this.hashId(to));
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => {
|
||||||
|
const resource = new GuildVoiceResource(this.#adapter, dt);
|
||||||
|
resource.setParent(to);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async remove(
|
||||||
|
id: string,
|
||||||
|
guild: string | undefined = this.parent
|
||||||
|
): Promise<void> {
|
||||||
|
await this.removeToRelationship(id, guild);
|
||||||
|
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected hashGuildId(id: string, guild?: string): string {
|
||||||
|
if (!guild) {
|
||||||
|
return this.hashId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.#namespace}.${guild}.${id}`;
|
||||||
|
}
|
||||||
|
}
|
6
packages/cache/src/resources/index.ts
vendored
6
packages/cache/src/resources/index.ts
vendored
@ -7,7 +7,9 @@ export { GuildMemberResource } from './guild-member-resource';
|
|||||||
export { GuildResource } from './guild-resource';
|
export { GuildResource } from './guild-resource';
|
||||||
|
|
||||||
export { GuildRoleResource } from './guild-role-resource';
|
export { GuildRoleResource } from './guild-role-resource';
|
||||||
export { GuildStickerResource } from './guild-sticker-resource';
|
|
||||||
|
|
||||||
|
export { GuildStickerResource } from './guild-sticker-resource';
|
||||||
|
export { GuildVoiceResource } from './guild-voice-resource';
|
||||||
|
|
||||||
|
export { PresenceResource } from './presence-resource';
|
||||||
export { UserResource } from './user-resource';
|
export { UserResource } from './user-resource';
|
||||||
export { VoiceResource } from './voice-resource';
|
|
||||||
|
135
packages/cache/src/resources/presence-resource.ts
vendored
Normal file
135
packages/cache/src/resources/presence-resource.ts
vendored
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/**
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
|
import type { DiscordPresenceUpdate } from '@biscuitland/api-types';
|
||||||
|
|
||||||
|
import { BaseResource } from './base-resource';
|
||||||
|
import { UserResource } from './user-resource';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource represented by an presence of discord
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class PresenceResource extends BaseResource<DiscordPresenceUpdate> {
|
||||||
|
#namespace = 'presence' as const;
|
||||||
|
|
||||||
|
#adapter: CacheAdapter;
|
||||||
|
|
||||||
|
#users: UserResource;
|
||||||
|
|
||||||
|
constructor(adapter: CacheAdapter, entity?: DiscordPresenceUpdate | null) {
|
||||||
|
super('presence', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
this.#users = new UserResource(this.#adapter);
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async get(id: string): Promise<PresenceResource | null> {
|
||||||
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashId(id));
|
||||||
|
|
||||||
|
if (kv) {
|
||||||
|
return new PresenceResource(this.#adapter, kv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async set(id: string, data: any): Promise<void> {
|
||||||
|
if (data.user) {
|
||||||
|
await this.#users.set(data.user.id, data.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete data.user;
|
||||||
|
delete data.roles;
|
||||||
|
|
||||||
|
delete data.guild_id;
|
||||||
|
|
||||||
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.addToRelationship(id);
|
||||||
|
await this.#adapter.set(this.hashId(id), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async items(): Promise<PresenceResource[]> {
|
||||||
|
const data = await this.#adapter.items(this.#namespace);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => new PresenceResource(this.#adapter, dt));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async count(): Promise<number> {
|
||||||
|
return await this.#adapter.count(this.#namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async remove(id: string): Promise<void> {
|
||||||
|
await this.removeToRelationship(id);
|
||||||
|
await this.#adapter.remove(this.hashId(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async contains(id: string): Promise<boolean> {
|
||||||
|
return await this.#adapter.contains(this.#namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getToRelationship(): Promise<string[]> {
|
||||||
|
return await this.#adapter.getToRelationship(this.#namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async addToRelationship(id: string): Promise<void> {
|
||||||
|
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async removeToRelationship(id: string): Promise<void> {
|
||||||
|
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||||
|
}
|
||||||
|
}
|
102
packages/cache/src/resources/user-resource.ts
vendored
102
packages/cache/src/resources/user-resource.ts
vendored
@ -1,28 +1,44 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
/**
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||||
import type { DiscordUser } from '@biscuitland/api-types';
|
import type { DiscordUser } from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { BaseResource } from './base-resource';
|
import { BaseResource } from './base-resource';
|
||||||
|
|
||||||
export class UserResource extends BaseResource {
|
/**
|
||||||
namespace = 'user' as const;
|
* Resource represented by an user of discord
|
||||||
|
*/
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
export class UserResource extends BaseResource<DiscordUser> {
|
||||||
|
#namespace = 'user' as const;
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
#adapter: CacheAdapter;
|
||||||
super();
|
|
||||||
|
|
||||||
this.adapter = adapter;
|
constructor(adapter: CacheAdapter, entity?: DiscordUser | null) {
|
||||||
|
super('user', adapter);
|
||||||
|
|
||||||
|
this.#adapter = adapter;
|
||||||
|
|
||||||
|
if (entity) {
|
||||||
|
this.setEntity(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async get(id: string): Promise<DiscordUser | null> {
|
async get(id: string): Promise<UserResource | null> {
|
||||||
const kv = await this.adapter.get(this.hashId(id));
|
if (this.parent) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kv = await this.#adapter.get(this.hashId(id));
|
||||||
|
|
||||||
if (kv) {
|
if (kv) {
|
||||||
return kv;
|
return new UserResource(this.#adapter, kv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -32,8 +48,35 @@ export class UserResource extends BaseResource {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async set(id: string, data: any, expire?: number): Promise<void> {
|
async set(id: string, data: any): Promise<void> {
|
||||||
await this.adapter.set(this.hashId(id), data, expire);
|
if (this.parent) {
|
||||||
|
this.setEntity(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.addToRelationship(id);
|
||||||
|
await this.#adapter.set(this.hashId(id), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async items(): Promise<UserResource[]> {
|
||||||
|
const data = await this.#adapter.items(this.#namespace);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.map(dt => new UserResource(this.#adapter, dt));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async count(): Promise<number> {
|
||||||
|
return await this.#adapter.count(this.#namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,6 +84,39 @@ export class UserResource extends BaseResource {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
await this.adapter.remove(this.hashId(id));
|
await this.removeToRelationship(id);
|
||||||
|
await this.#adapter.remove(this.hashId(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async contains(id: string): Promise<boolean> {
|
||||||
|
return await this.#adapter.contains(this.#namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getToRelationship(): Promise<string[]> {
|
||||||
|
return await this.#adapter.getToRelationship(this.#namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async addToRelationship(id: string): Promise<void> {
|
||||||
|
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async removeToRelationship(id: string): Promise<void> {
|
||||||
|
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
packages/cache/src/resources/voice-resource.ts
vendored
57
packages/cache/src/resources/voice-resource.ts
vendored
@ -1,57 +0,0 @@
|
|||||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
|
||||||
import type { DiscordVoiceState } from '@biscuitland/api-types';
|
|
||||||
|
|
||||||
import { BaseResource } from './base-resource';
|
|
||||||
|
|
||||||
export class VoiceResource extends BaseResource {
|
|
||||||
namespace = 'voice' as const;
|
|
||||||
|
|
||||||
adapter: CacheAdapter;
|
|
||||||
|
|
||||||
constructor(adapter: CacheAdapter) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.adapter = adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async get(id: string, guild: string): Promise<DiscordVoiceState | null> {
|
|
||||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
|
||||||
|
|
||||||
if (kv) {
|
|
||||||
return kv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async set(
|
|
||||||
id: string,
|
|
||||||
guild: string,
|
|
||||||
data: any,
|
|
||||||
expire?: number
|
|
||||||
): Promise<void> {
|
|
||||||
if (!data.guild_id) {
|
|
||||||
data.guild_id = guild;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete data.member;
|
|
||||||
|
|
||||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async remove(id: string, guild: string): Promise<void> {
|
|
||||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
|
||||||
}
|
|
||||||
}
|
|
63
packages/cache/src/scheme/adapters/cache-adapter.ts
vendored
Normal file
63
packages/cache/src/scheme/adapters/cache-adapter.ts
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* Base class for all adapters
|
||||||
|
* All Methods from CacheAdapter are also available on every class extends
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface CacheAdapter {
|
||||||
|
/**
|
||||||
|
* Gets the resource to adapter
|
||||||
|
*/
|
||||||
|
|
||||||
|
get(id: string): any | Promise<any>;
|
||||||
|
get(id: string, guild: string): string | Promise<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the resource to adapter
|
||||||
|
*/
|
||||||
|
|
||||||
|
set(id: string, data: any): void | Promise<void>;
|
||||||
|
set(id: string, guild: string, data: any): void | Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the items of a relationship
|
||||||
|
*/
|
||||||
|
|
||||||
|
items(to?: string): any[] | Promise<any[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count how many resources there are in the relationships
|
||||||
|
*/
|
||||||
|
|
||||||
|
count(to: string): number | Promise<number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the adapter resource
|
||||||
|
*/
|
||||||
|
|
||||||
|
remove(id: string): void | Promise<void>;
|
||||||
|
remove(id: string, guild: string): void | Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the resource is in the relationships
|
||||||
|
*/
|
||||||
|
|
||||||
|
contains(to: string, id: string): boolean | Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the resource relationships
|
||||||
|
*/
|
||||||
|
|
||||||
|
getToRelationship(to: string): string[] | Promise<string[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the resource to relationships
|
||||||
|
*/
|
||||||
|
|
||||||
|
addToRelationship(to: string, id: string): void | Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the relationship resource
|
||||||
|
*/
|
||||||
|
|
||||||
|
removeToRelationship(to: string, id: string): void | Promise<void>;
|
||||||
|
}
|
@ -1,20 +1,24 @@
|
|||||||
import type { CacheAdapter } from './cache-adapter';
|
/**
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
interface Options {
|
import type { CacheAdapter } from './cache-adapter';
|
||||||
expire?: number;
|
import type { MemoryOptions, MO } from '../../types';
|
||||||
}
|
|
||||||
|
import { Options } from '../../utils/options';
|
||||||
|
|
||||||
export class MemoryCacheAdapter implements CacheAdapter {
|
export class MemoryCacheAdapter implements CacheAdapter {
|
||||||
private static readonly DEFAULTS = {
|
static readonly DEFAULTS = {
|
||||||
|
expire: 3600000,
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly relationships = new Map<string, string[]>();
|
readonly relationships = new Map<string, string[]>();
|
||||||
private readonly storage = new Map<string, { data: any; expire?: number }>();
|
readonly storage = new Map<string, { data: any; expire?: number }>();
|
||||||
|
|
||||||
readonly options: Options;
|
readonly options: MO;
|
||||||
|
|
||||||
constructor(options?: Options) {
|
constructor(options?: MemoryOptions) {
|
||||||
this.options = Object.assign(MemoryCacheAdapter.DEFAULTS, options);
|
this.options = Options({}, MemoryCacheAdapter.DEFAULTS, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,14 +43,40 @@ export class MemoryCacheAdapter implements CacheAdapter {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
set(id: string, data: any, expire = this.options.expire): void {
|
set(id: string, data: any): void {
|
||||||
|
const expire = this.options.expire;
|
||||||
|
|
||||||
if (expire) {
|
if (expire) {
|
||||||
this.storage.set(id, { data: JSON.stringify(data), expire: Date.now() + expire });
|
this.storage.set(id, {
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
expire: Date.now() + expire,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.storage.set(id, { data: JSON.stringify(data) });
|
this.storage.set(id, { data: JSON.stringify(data) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
items(to: string): any[] {
|
||||||
|
const array: unknown[] = [];
|
||||||
|
let data = this.getToRelationship(to);
|
||||||
|
|
||||||
|
data = data.map(id => `${to}.${id}`);
|
||||||
|
|
||||||
|
for (const key of data) {
|
||||||
|
const content = this.get(key);
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
array.push(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
195
packages/cache/src/scheme/adapters/redis-cache-adapter.ts
vendored
Normal file
195
packages/cache/src/scheme/adapters/redis-cache-adapter.ts
vendored
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/**
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { CacheAdapter } from './cache-adapter';
|
||||||
|
|
||||||
|
import type { RedisOptions } from 'ioredis';
|
||||||
|
import type Redis from 'ioredis';
|
||||||
|
import IORedis from 'ioredis';
|
||||||
|
|
||||||
|
interface BaseOptions {
|
||||||
|
namespace: string;
|
||||||
|
expire?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BuildOptions extends BaseOptions, RedisOptions {}
|
||||||
|
|
||||||
|
interface ClientOptions extends BaseOptions {
|
||||||
|
client: Redis;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options = BuildOptions | ClientOptions;
|
||||||
|
|
||||||
|
export class RedisCacheAdapter implements CacheAdapter {
|
||||||
|
static readonly DEFAULTS = {
|
||||||
|
namespace: 'biscuitland',
|
||||||
|
};
|
||||||
|
|
||||||
|
readonly options: Options;
|
||||||
|
|
||||||
|
readonly client: Redis;
|
||||||
|
|
||||||
|
constructor(options?: Options) {
|
||||||
|
this.options = Object.assign(RedisCacheAdapter.DEFAULTS, options);
|
||||||
|
|
||||||
|
if ((this.options as ClientOptions).client) {
|
||||||
|
this.client = (this.options as ClientOptions).client;
|
||||||
|
} else {
|
||||||
|
const { ...redisOpt } = this.options as BuildOptions;
|
||||||
|
this.client = new IORedis(redisOpt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async get(id: string): Promise<any> {
|
||||||
|
const data = await this.client.get(this.build(id));
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async set(id: string, data: unknown): Promise<void> {
|
||||||
|
const expire = this.options.expire;
|
||||||
|
|
||||||
|
if (expire) {
|
||||||
|
await this.client.set(
|
||||||
|
this.build(id),
|
||||||
|
JSON.stringify(data),
|
||||||
|
'EX',
|
||||||
|
expire
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await this.client.set(this.build(id), JSON.stringify(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async items(to: string): Promise<any[]> {
|
||||||
|
const array: unknown[] = [];
|
||||||
|
|
||||||
|
let data = await this.getToRelationship(to);
|
||||||
|
data = data.map(id => this.build(`${to}.${id}`));
|
||||||
|
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
const items = await this.client.mget(data);
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (item) {
|
||||||
|
array.push(JSON.parse(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async count(to: string): Promise<number> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.client.scard(this.build(to), (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(result || 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async remove(id: string): Promise<void> {
|
||||||
|
await this.client.del(this.build(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async contains(to: string, id: string): Promise<boolean> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.client.sismember(this.build(to), id, (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(result === 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getToRelationship(to: string): Promise<string[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.client.smembers(this.build(to), (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(result || []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async addToRelationship(to: string, id: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.client.sadd(this.build(to), id, err => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
async removeToRelationship(to: string, id: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.client.srem(this.build(to), id, err => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected build(id: string): string {
|
||||||
|
return `${this.options.namespace}:${id}`;
|
||||||
|
}
|
||||||
|
}
|
7
packages/cache/src/scheme/transporters/base-transporter.ts
vendored
Normal file
7
packages/cache/src/scheme/transporters/base-transporter.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* future update
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface BaseTransporter {
|
||||||
|
//
|
||||||
|
}
|
3
packages/cache/src/scheme/transporters/redis-transporter.ts
vendored
Normal file
3
packages/cache/src/scheme/transporters/redis-transporter.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import type { BaseTransporter } from './base-transporter';
|
||||||
|
|
||||||
|
export class RedisTransporter implements BaseTransporter {}
|
3
packages/cache/src/scheme/transporters/tcp-transporter.ts
vendored
Normal file
3
packages/cache/src/scheme/transporters/tcp-transporter.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import type { BaseTransporter } from './base-transporter';
|
||||||
|
|
||||||
|
export class TcpTransporter implements BaseTransporter {}
|
55
packages/cache/src/types.ts
vendored
Normal file
55
packages/cache/src/types.ts
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import type { Cache } from './cache';
|
||||||
|
import type { CacheAdapter } from './scheme/adapters/cache-adapter';
|
||||||
|
|
||||||
|
import type { MemoryCacheAdapter } from './scheme/adapters/memory-cache-adapter';
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
export type CacheOptions = Pick<
|
||||||
|
CO,
|
||||||
|
Exclude<keyof CO, keyof typeof Cache.DEFAULTS>
|
||||||
|
> &
|
||||||
|
Partial<CO>;
|
||||||
|
|
||||||
|
export interface CO {
|
||||||
|
/**
|
||||||
|
* Adapter to be used for storing resources
|
||||||
|
* @default MemoryCacheAdapter
|
||||||
|
*/
|
||||||
|
|
||||||
|
adapter: CacheAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
export type MemoryOptions = Pick<
|
||||||
|
MO,
|
||||||
|
Exclude<keyof MO, keyof typeof MemoryCacheAdapter.DEFAULTS>
|
||||||
|
> &
|
||||||
|
Partial<MO>;
|
||||||
|
|
||||||
|
export interface MO {
|
||||||
|
/**
|
||||||
|
* Time the resource will be stored
|
||||||
|
* @default 3600000
|
||||||
|
*/
|
||||||
|
|
||||||
|
expire: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
export type RedisOptions = Pick<
|
||||||
|
RO,
|
||||||
|
Exclude<keyof RO, keyof typeof MemoryCacheAdapter.DEFAULTS>
|
||||||
|
> &
|
||||||
|
Partial<RO>;
|
||||||
|
|
||||||
|
export interface RO {
|
||||||
|
/**
|
||||||
|
* Time the resource will be stored
|
||||||
|
* @default 300
|
||||||
|
*/
|
||||||
|
|
||||||
|
expire: number;
|
||||||
|
}
|
48
packages/cache/src/utils/options.ts
vendored
Normal file
48
packages/cache/src/utils/options.ts
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Needs to be moved to a common location
|
||||||
|
* refactor
|
||||||
|
*/
|
||||||
|
|
||||||
|
const isPlainObject = (value: any) => {
|
||||||
|
return (
|
||||||
|
(value !== null &&
|
||||||
|
typeof value === 'object' &&
|
||||||
|
typeof value.constructor === 'function' &&
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
(value.constructor.prototype.hasOwnProperty('isPrototypeOf') ||
|
||||||
|
Object.getPrototypeOf(value.constructor.prototype) === null)) ||
|
||||||
|
(value && Object.getPrototypeOf(value) === null)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isObject = (o: any) => {
|
||||||
|
return !!o && typeof o === 'object' && !Array.isArray(o);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Options = (defaults: any, ...options: any[]): any => {
|
||||||
|
if (!options.length) {
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = options.shift();
|
||||||
|
|
||||||
|
if (isObject(defaults) && isPlainObject(source)) {
|
||||||
|
Object.entries(source).forEach(([key, value]) => {
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlainObject(value)) {
|
||||||
|
if (!(key in defaults)) {
|
||||||
|
Object.assign(defaults, { [key]: {} });
|
||||||
|
}
|
||||||
|
|
||||||
|
Options(defaults[key], value);
|
||||||
|
} else {
|
||||||
|
Object.assign(defaults, { [key]: value });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Options(defaults, ...options);
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user