diff options
Diffstat (limited to 'src/util')
38 files changed, 442 insertions, 124 deletions
diff --git a/src/util/cache/Cache.ts b/src/util/cache/Cache.ts new file mode 100644 index 00000000..fb66c2e3 --- /dev/null +++ b/src/util/cache/Cache.ts @@ -0,0 +1,85 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { EntityMetadata, FindOptionsWhere } from "typeorm"; +import { LocalCache } from "./LocalCache"; + +declare module "typeorm" { + interface BaseEntity { + metadata?: EntityMetadata; + cache: CacheManager; + } +} + +export type BaseEntityWithId = { id: string; [name: string]: any }; +export type Criteria = + | string + | string[] + | number + | number[] + | FindOptionsWhere<never>; + +export interface Cache { + get(id: string): BaseEntityWithId | undefined; + set(id: string, entity: BaseEntityWithId): this; + find(options: Record<string, never>): BaseEntityWithId | undefined; + filter(options: Record<string, never>): BaseEntityWithId[]; + delete(id: string): boolean; +} + +export class CacheManager { + // last access time to automatically remove old entities from cache after 5 minutes of inactivity (to prevent memory leaks) + cache: Cache; + + constructor() { + this.cache = new LocalCache(); + // TODO: Config.get().cache.redis; + } + + delete(id: string) { + return this.cache.delete(id); + } + + insert(entity: BaseEntityWithId) { + if (!entity.id) return; + + return this.cache.set(entity.id, entity); + } + + find(options?: Record<string, never>, select?: string[] | undefined) { + if (!options) return null; + const entity = this.cache.find(options); + if (!entity) return null; + if (!select) return entity; + + const result = {}; + for (const prop of select) { + // @ts-ignore + result[prop] = entity[prop]; + } + + // @ts-ignore + return entity.constructor.create(result); + } + + filter(options: Record<string, never>) { + return this.cache.filter(options); + } +} diff --git a/src/util/cache/EntityCache.ts b/src/util/cache/EntityCache.ts new file mode 100644 index 00000000..9135fef3 --- /dev/null +++ b/src/util/cache/EntityCache.ts @@ -0,0 +1,160 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +/* eslint-disable */ +import { + DataSource, + FindOneOptions, + EntityNotFoundError, + FindOptionsWhere, +} from "typeorm"; +import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"; +import { BaseClassWithId } from "../entities/BaseClass"; +import { Config, getDatabase } from "../util"; +import { CacheManager } from "./Cache"; + +function getObjectKeysAsArray(obj?: Record<string, any>) { + if (!obj) return []; + if (Array.isArray(obj)) return obj; + return Object.keys(obj); +} + +export type ThisType<T> = { + new (): T; +} & typeof BaseEntityCache; + +interface BaseEntityCache { + constructor: typeof BaseEntityCache; +} + +// @ts-ignore +class BaseEntityCache extends BaseClassWithId { + static cache: CacheManager; + static cacheEnabled: boolean; + + public get metadata() { + return getDatabase()?.getMetadata(this.constructor)!; + } + + static useDataSource(dataSource: DataSource | null) { + super.useDataSource(dataSource); + this.cacheEnabled = Config.get().cache.enabled ?? true; + if (Config.get().cache.redis) return; // TODO: Redis cache + if (!this.cacheEnabled) return; + this.cache = new CacheManager(); + } + + static async findOne<T extends BaseEntityCache>( + this: ThisType<T>, + options: FindOneOptions<T>, + ) { + // @ts-ignore + if (!this.cacheEnabled) return super.findOne(options); + let select = getObjectKeysAsArray(options.select); + + if (!select.length) { + // get all columns that are marked as select + getDatabase() + ?.getMetadata(this) + .columns.forEach((x) => { + if (!x.isSelect) return; + select.push(x.propertyName); + }); + } + if (options.relations) { + select.push(...getObjectKeysAsArray(options.relations)); + } + + const cacheResult = this.cache.find(options.where as never, select); + if (cacheResult) { + const hasAllProps = select.every((key) => { + if (key.includes(".")) return true; // @ts-ignore + return cacheResult[key] !== undefined; + }); + // console.log(`[Cache] get ${cacheResult.id} from ${cacheResult.constructor.name}`,); + if (hasAllProps) return cacheResult; + } + + // @ts-ignore + const result = await super.findOne<T>(options); + if (!result) return null; + + this.cache.insert(result as any); + + return result; + } + + static async findOneOrFail<T extends BaseEntityCache>( + this: ThisType<T>, + options: FindOneOptions<T>, + ) { + const result = await this.findOne<T>(options); + if (!result) throw new EntityNotFoundError(this, options); + return result; + } + + save() { + if (this.constructor.cacheEnabled) this.constructor.cache.insert(this); + return super.save(); + } + + remove() { + if (this.constructor.cacheEnabled) + this.constructor.cache.delete(this.id); + return super.remove(); + } + + static async update<T extends BaseEntityCache>( + this: ThisType<T>, + criteria: FindOptionsWhere<T>, + partialEntity: QueryDeepPartialEntity<T>, + ) { + // @ts-ignore + const result = super.update<T>(criteria, partialEntity); + if (!this.cacheEnabled) return result; + + const entities = this.cache.filter(criteria as never); + for (const entity of entities) { + // @ts-ignore + partialEntity.id = entity.id; + this.cache.insert(partialEntity as never); + } + + return result; + } + + static async delete<T extends BaseEntityCache>( + this: ThisType<T>, + criteria: FindOptionsWhere<T>, + ) { + // @ts-ignore + const result = super.delete<T>(criteria); + if (!this.cacheEnabled) return result; + + const entities = this.cache.filter(criteria as never); + for (const entity of entities) { + this.cache.delete(entity.id); + } + + return result; + } +} + +// needed, because typescript can't infer the type of the static methods with generics +const EntityCache = BaseEntityCache as unknown as typeof BaseClassWithId; + +export { EntityCache }; diff --git a/src/util/cache/LocalCache.ts b/src/util/cache/LocalCache.ts new file mode 100644 index 00000000..547899ac --- /dev/null +++ b/src/util/cache/LocalCache.ts @@ -0,0 +1,91 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { BaseEntityWithId, Cache } from "./Cache"; + +export const cacheTimeout = 1000 * 60 * 5; + +export class LocalCache extends Map<string, BaseEntityWithId> implements Cache { + last_access = new Map<string, number>(); + + constructor() { + super(); + + setInterval(() => { + const now = Date.now(); + for (const [key, value] of this.last_access) { + if (now - value > cacheTimeout) { + this.delete(key); + this.last_access.delete(key); + } + } + }, cacheTimeout); + } + + set(key: string, value: BaseEntityWithId): this { + this.last_access.set(key, Date.now()); + if (this.has(key)) this.update(key, value); + return super.set(key, value as never); + } + + get(key: string) { + const value = super.get(key); + if (value) this.last_access.set(key, Date.now()); + return value; + } + + update(id: string, entity: BaseEntityWithId) { + const oldEntity = this.get(id); + if (!oldEntity) return; + for (const key in entity) { + // @ts-ignore + if (entity[key] === undefined) continue; // @ts-ignore + oldEntity[key] = entity[key]; + } + } + + find(options: Record<string, never>): BaseEntityWithId | undefined { + if (options.id && Object.keys(options).length === 1) { + return this.get(options.id); + } + for (const entity of this.values()) { + if (objectFulfillsQuery(entity, options)) return entity; + } + } + + filter(options: Record<string, never>): BaseEntityWithId[] { + const result = []; + for (const entity of this.values()) { + if (objectFulfillsQuery(entity, options)) { + result.push(entity); + } + } + return result; + } +} + +function objectFulfillsQuery( + entity: BaseEntityWithId, + options: Record<string, never>, +) { + for (const key in options) { + // @ts-ignore + if (entity[key] !== options[key]) return false; + } + return true; +} diff --git a/src/util/cache/index.ts b/src/util/cache/index.ts new file mode 100644 index 00000000..43f0aa96 --- /dev/null +++ b/src/util/cache/index.ts @@ -0,0 +1,3 @@ +export * from "./EntityCache"; +export * from "./Cache"; +export * from "./LocalCache"; diff --git a/src/util/config/Config.ts b/src/util/config/Config.ts index f130e760..3cd18d3d 100644 --- a/src/util/config/Config.ts +++ b/src/util/config/Config.ts @@ -37,6 +37,7 @@ import { SecurityConfiguration, SentryConfiguration, TemplateConfiguration, + CacheConfiguration, } from "../config"; export class ConfigValue { @@ -61,4 +62,5 @@ export class ConfigValue { email: EmailConfiguration = new EmailConfiguration(); passwordReset: PasswordResetConfiguration = new PasswordResetConfiguration(); + cache: CacheConfiguration = new CacheConfiguration(); } diff --git a/src/util/config/types/CacheConfiguration.ts b/src/util/config/types/CacheConfiguration.ts new file mode 100644 index 00000000..4178090e --- /dev/null +++ b/src/util/config/types/CacheConfiguration.ts @@ -0,0 +1,22 @@ +/* + Fosscord: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Fosscord and Fosscord Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +export class CacheConfiguration { + enabled: boolean | null = true; + redis: string | null = null; +} diff --git a/src/util/config/types/index.ts b/src/util/config/types/index.ts index cd3335e0..03cc2e8b 100644 --- a/src/util/config/types/index.ts +++ b/src/util/config/types/index.ts @@ -17,6 +17,7 @@ */ export * from "./ApiConfiguration"; +export * from "./CacheConfiguration"; export * from "./CdnConfiguration"; export * from "./DefaultsConfiguration"; export * from "./EmailConfiguration"; diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index 94709320..5613109e 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Team } from "./Team"; import { User } from "./User"; @Entity("applications") -export class Application extends BaseClass { +export class Application extends EntityCache { @Column() name: string; diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts index fdc1b3f1..da879fad 100644 --- a/src/util/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts @@ -25,11 +25,11 @@ import { RelationId, } from "typeorm"; import { URL } from "url"; +import { EntityCache } from "../cache"; import { deleteFile } from "../util/cdn"; -import { BaseClass } from "./BaseClass"; @Entity("attachments") -export class Attachment extends BaseClass { +export class Attachment extends EntityCache { @Column() filename: string; // name of file attached diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts index 0cc2fc04..0c10c6f0 100644 --- a/src/util/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { ChannelPermissionOverwrite } from "./Channel"; import { User } from "./User"; @@ -112,7 +112,7 @@ export enum AuditLogEvents { } @Entity("audit_logs") -export class AuditLog extends BaseClass { +export class AuditLog extends EntityCache { @JoinColumn({ name: "target_id" }) @ManyToOne(() => User) target?: User; diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts index 467e1fe3..d6a38a63 100644 --- a/src/util/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; import crypto from "crypto"; @Entity("backup_codes") -export class BackupCode extends BaseClass { +export class BackupCode extends EntityCache { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) user: User; diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts index 4ed6e201..7accc153 100644 --- a/src/util/entities/Ban.ts +++ b/src/util/entities/Ban.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { User } from "./User"; @Entity("bans") -export class Ban extends BaseClass { +export class Ban extends EntityCache { @Column({ nullable: true }) @RelationId((ban: Ban) => ban.user) user_id: string; diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts index 445b3fc9..87b394c5 100644 --- a/src/util/entities/BaseClass.ts +++ b/src/util/entities/BaseClass.ts @@ -25,16 +25,12 @@ import { PrimaryColumn, } from "typeorm"; import { Snowflake } from "../util/Snowflake"; -import { getDatabase } from "../util/Database"; import { OrmUtils } from "../imports/OrmUtils"; +import { getDatabase } from "../util"; export class BaseClassWithoutId extends BaseEntity { - private get construct() { - return this.constructor; - } - - private get metadata() { - return getDatabase()?.getMetadata(this.construct); + public get metadata() { + return getDatabase()?.getMetadata(this.constructor); } assign(props: object) { @@ -61,8 +57,23 @@ export class BaseClassWithoutId extends BaseEntity { ), ); } +} + +export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") + ? ObjectIdColumn + : PrimaryColumn; + +export class BaseClassWithId extends BaseClassWithoutId { + @PrimaryIdColumn() + id: string = Snowflake.generate(); + + @BeforeUpdate() + @BeforeInsert() + _do_validate() { + if (!this.id) this.id = Snowflake.generate(); + } - static increment<T extends BaseClass>( + static increment<T extends BaseClassWithId>( conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string, @@ -71,7 +82,7 @@ export class BaseClassWithoutId extends BaseEntity { return repository.increment(conditions, propertyPath, value); } - static decrement<T extends BaseClass>( + static decrement<T extends BaseClassWithId>( conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string, @@ -80,18 +91,3 @@ export class BaseClassWithoutId extends BaseEntity { return repository.decrement(conditions, propertyPath, value); } } - -export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") - ? ObjectIdColumn - : PrimaryColumn; - -export class BaseClass extends BaseClassWithoutId { - @PrimaryIdColumn() - id: string = Snowflake.generate(); - - @BeforeUpdate() - @BeforeInsert() - _do_validate() { - if (!this.id) this.id = Snowflake.generate(); - } -} diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 1f128713..1cad928b 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -24,7 +24,7 @@ import { OneToMany, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { PublicUserProjection, User } from "./User"; import { HTTPError } from "lambert-server"; @@ -70,7 +70,7 @@ export enum ChannelType { } @Entity("channels") -export class Channel extends BaseClass { +export class Channel extends EntityCache { @Column() created_at: Date; diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts index 4b8150fd..57710194 100644 --- a/src/util/entities/ClientRelease.ts +++ b/src/util/entities/ClientRelease.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("client_release") -export class Release extends BaseClass { +export class Release extends EntityCache { @Column() name: string; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 9f0ce35e..dabdb944 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; export type PublicConnectedAccount = Pick< @@ -26,7 +26,7 @@ export type PublicConnectedAccount = Pick< >; @Entity("connected_accounts") -export class ConnectedAccount extends BaseClass { +export class ConnectedAccount extends EntityCache { @Column({ nullable: true }) @RelationId((account: ConnectedAccount) => account.user) user_id: string; diff --git a/src/util/entities/EmbedCache.ts b/src/util/entities/EmbedCache.ts index 800ee4e7..fd6db90e 100644 --- a/src/util/entities/EmbedCache.ts +++ b/src/util/entities/EmbedCache.ts @@ -16,12 +16,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Entity, Column } from "typeorm"; import { Embed } from "./Message"; @Entity("embed_cache") -export class EmbedCache extends BaseClass { +export class EmbedCache extends EntityCache { @Column() url: string; diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index 94ce3d54..c7678361 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -18,11 +18,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { User } from "."; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; @Entity("emojis") -export class Emoji extends BaseClass { +export class Emoji extends EntityCache { @Column() animated: boolean; diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts index 016b4331..19cb3987 100644 --- a/src/util/entities/Encryption.ts +++ b/src/util/entities/Encryption.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("security_settings") -export class SecuritySettings extends BaseClass { +export class SecuritySettings extends EntityCache { @Column({ nullable: true }) guild_id: string; diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index c835f5fc..b08e37d1 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -26,7 +26,7 @@ import { } from "typeorm"; import { Config, handleFile, Snowflake } from ".."; import { Ban } from "./Ban"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { Emoji } from "./Emoji"; import { Invite } from "./Invite"; @@ -67,7 +67,7 @@ export const PublicGuildRelations = [ ]; @Entity("guilds") -export class Guild extends BaseClass { +export class Guild extends EntityCache { @Column({ nullable: true }) @RelationId((guild: Guild) => guild.afk_channel) afk_channel_id?: string; diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index fc8c011c..feee84a7 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -34,7 +34,7 @@ import { OneToMany, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { Webhook } from "./Webhook"; import { Sticker } from "./Sticker"; @@ -70,7 +70,7 @@ export enum MessageType { @Entity("messages") @Index(["channel_id", "id"], { unique: true }) -export class Message extends BaseClass { +export class Message extends EntityCache { @Column({ nullable: true }) @RelationId((message: Message) => message.channel) @Index() diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts index 0f2a5ce3..9f13b257 100644 --- a/src/util/entities/Note.ts +++ b/src/util/entities/Note.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, Unique } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; @Entity("notes") @Unique(["owner", "target"]) -export class Note extends BaseClass { +export class Note extends EntityCache { @JoinColumn({ name: "owner_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) owner: User; diff --git a/src/util/entities/RateLimit.ts b/src/util/entities/RateLimit.ts index 79ebbb01..23f0952c 100644 --- a/src/util/entities/RateLimit.ts +++ b/src/util/entities/RateLimit.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("rate_limits") -export class RateLimit extends BaseClass { +export class RateLimit extends EntityCache { @Column() // no relation as it also executor_id: string; diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts index 825beb03..d39bfb4b 100644 --- a/src/util/entities/ReadState.ts +++ b/src/util/entities/ReadState.ts @@ -24,7 +24,7 @@ import { ManyToOne, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { User } from "./User"; @@ -34,7 +34,7 @@ import { User } from "./User"; @Entity("read_states") @Index(["channel_id", "user_id"], { unique: true }) -export class ReadState extends BaseClass { +export class ReadState extends EntityCache { @Column() @RelationId((read_state: ReadState) => read_state.channel) channel_id: string; diff --git a/src/util/entities/Recipient.ts b/src/util/entities/Recipient.ts index 1cf028dd..4c301827 100644 --- a/src/util/entities/Recipient.ts +++ b/src/util/entities/Recipient.ts @@ -17,10 +17,10 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("recipients") -export class Recipient extends BaseClass { +export class Recipient extends EntityCache { @Column() @RelationId((recipient: Recipient) => recipient.channel) channel_id: string; diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts index 1bf04c2c..48fbc81d 100644 --- a/src/util/entities/Relationship.ts +++ b/src/util/entities/Relationship.ts @@ -24,7 +24,7 @@ import { ManyToOne, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; export enum RelationshipType { @@ -36,7 +36,7 @@ export enum RelationshipType { @Entity("relationships") @Index(["from_id", "to_id"], { unique: true }) -export class Relationship extends BaseClass { +export class Relationship extends EntityCache { @Column({}) @RelationId((relationship: Relationship) => relationship.from) from_id: string; diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index d3275ede..c44fa2b1 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -18,11 +18,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; @Entity("roles") -export class Role extends BaseClass { +export class Role extends EntityCache { @Column({ nullable: true }) @RelationId((role: Role) => role.guild) guild_id: string; diff --git a/src/util/entities/SecurityKey.ts b/src/util/entities/SecurityKey.ts index 8f377d9d..86e5531e 100644 --- a/src/util/entities/SecurityKey.ts +++ b/src/util/entities/SecurityKey.ts @@ -17,11 +17,11 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; @Entity("security_keys") -export class SecurityKey extends BaseClass { +export class SecurityKey extends EntityCache { @Column({ nullable: true }) @RelationId((key: SecurityKey) => key.user) user_id: string; diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts index f416b9f5..f6e16916 100644 --- a/src/util/entities/Session.ts +++ b/src/util/entities/Session.ts @@ -17,7 +17,7 @@ */ import { User } from "./User"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Status } from "../interfaces/Status"; import { Activity } from "../interfaces/Activity"; @@ -25,7 +25,7 @@ import { Activity } from "../interfaces/Activity"; //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them @Entity("sessions") -export class Session extends BaseClass { +export class Session extends EntityCache { @Column({ nullable: true }) @RelationId((session: Session) => session.user) user_id: string; diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts index 513a4c9f..dd3d39dd 100644 --- a/src/util/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts @@ -18,7 +18,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { User } from "./User"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; export enum StickerType { @@ -34,7 +34,7 @@ export enum StickerFormatType { } @Entity("stickers") -export class Sticker extends BaseClass { +export class Sticker extends EntityCache { @Column() name: string; diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts index ce8d5e87..ad1a9c0f 100644 --- a/src/util/entities/StickerPack.ts +++ b/src/util/entities/StickerPack.ts @@ -25,10 +25,10 @@ import { RelationId, } from "typeorm"; import { Sticker } from "."; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; @Entity("sticker_packs") -export class StickerPack extends BaseClass { +export class StickerPack extends EntityCache { @Column() name: string; diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts index 82859409..5b86bfa6 100644 --- a/src/util/entities/Team.ts +++ b/src/util/entities/Team.ts @@ -24,12 +24,12 @@ import { OneToMany, RelationId, } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { TeamMember } from "./TeamMember"; import { User } from "./User"; @Entity("teams") -export class Team extends BaseClass { +export class Team extends EntityCache { @Column({ nullable: true }) icon?: string; diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts index df70050c..c8c07ea9 100644 --- a/src/util/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { User } from "./User"; export enum TeamMemberState { @@ -26,7 +26,7 @@ export enum TeamMemberState { } @Entity("team_members") -export class TeamMember extends BaseClass { +export class TeamMember extends EntityCache { @Column({ type: "int" }) membership_state: TeamMemberState; diff --git a/src/util/entities/Template.ts b/src/util/entities/Template.ts index 17f26e1c..7349367c 100644 --- a/src/util/entities/Template.ts +++ b/src/util/entities/Template.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Guild } from "./Guild"; import { User } from "./User"; @Entity("templates") -export class Template extends BaseClass { +export class Template extends EntityCache { @Column({ unique: true }) code: string; diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index f99a85e7..2b182c16 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -34,7 +34,7 @@ import { trimSpecial, } from ".."; import { BitField } from "../util/BitField"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { ConnectedAccount } from "./ConnectedAccount"; import { Member } from "./Member"; import { Relationship } from "./Relationship"; @@ -94,7 +94,7 @@ export interface UserPrivate extends Pick<User, PrivateUserKeys> { } @Entity("users") -export class User extends BaseClass { +export class User extends EntityCache { @Column() username: string; // username max length 32, min 2 (should be configurable) diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts index f790945f..32d94ed1 100644 --- a/src/util/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -25,7 +25,7 @@ import { Member } from "./Member"; //https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex @Entity("voice_states") -export class VoiceState extends BaseClass { +export class VoiceState extends EntityCache { @Column({ nullable: true }) @RelationId((voice_state: VoiceState) => voice_state.guild) guild_id: string; diff --git a/src/util/entities/Webhook.ts b/src/util/entities/Webhook.ts index 9be86c6d..3e845ddc 100644 --- a/src/util/entities/Webhook.ts +++ b/src/util/entities/Webhook.ts @@ -18,7 +18,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Application } from "./Application"; -import { BaseClass } from "./BaseClass"; +import { EntityCache } from "../cache"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -30,7 +30,7 @@ export enum WebhookType { } @Entity("webhooks") -export class Webhook extends BaseClass { +export class Webhook extends EntityCache { @Column({ type: "int" }) type: WebhookType; diff --git a/src/util/util/Cache.ts b/src/util/util/Cache.ts deleted file mode 100644 index 44839a65..00000000 --- a/src/util/util/Cache.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable */ -import { DataSource, QueryRunner } from "typeorm"; -import { QueryResultCache } from "typeorm/cache/QueryResultCache"; -import { QueryResultCacheOptions } from "typeorm/cache/QueryResultCacheOptions"; - -export class CustomQueryResultCache implements QueryResultCache { - constructor(private dataSource: DataSource) {} - connect(): Promise<void> { - throw new Error("Method not implemented."); - } - disconnect(): Promise<void> { - throw new Error("Method not implemented."); - } - synchronize(queryRunner?: QueryRunner | undefined): Promise<void> { - throw new Error("Method not implemented."); - } - getFromCache( - options: QueryResultCacheOptions, - queryRunner?: QueryRunner | undefined, - ): Promise<QueryResultCacheOptions | undefined> { - throw new Error("Method not implemented."); - } - storeInCache( - options: QueryResultCacheOptions, - savedCache: QueryResultCacheOptions | undefined, - queryRunner?: QueryRunner | undefined, - ): Promise<void> { - throw new Error("Method not implemented."); - } - isExpired(savedCache: QueryResultCacheOptions): boolean { - throw new Error("Method not implemented."); - } - clear(queryRunner?: QueryRunner | undefined): Promise<void> { - throw new Error("Method not implemented."); - } - remove( - identifiers: string[], - queryRunner?: QueryRunner | undefined, - ): Promise<void> { - throw new Error("Method not implemented."); - } -} |