summaryrefslogtreecommitdiff
path: root/server/src/database/structures
diff options
context:
space:
mode:
author8cy <[email protected]>2020-07-23 23:24:17 -0700
committer8cy <[email protected]>2020-07-23 23:24:17 -0700
commitbb511abc03bb66848947e37a999502b813c77269 (patch)
tree612c010fc8317e1cdf11471a18aad0270819d33e /server/src/database/structures
parentfix: if clear amount equal or over 100, round down to 99 (diff)
downloaddep-core-bb511abc03bb66848947e37a999502b813c77269.tar.xz
dep-core-bb511abc03bb66848947e37a999502b813c77269.zip
goodbye old uwufier :cry:
Diffstat (limited to 'server/src/database/structures')
-rw-r--r--server/src/database/structures/SettingsProvider.ts212
1 files changed, 212 insertions, 0 deletions
diff --git a/server/src/database/structures/SettingsProvider.ts b/server/src/database/structures/SettingsProvider.ts
new file mode 100644
index 0000000..0a2325a
--- /dev/null
+++ b/server/src/database/structures/SettingsProvider.ts
@@ -0,0 +1,212 @@
+import { Collection } from 'discord.js';
+import { connect, Model, connection, Connection } from 'mongoose';
+import { Logger } from 'winston';
+import ReactionModel, { Reaction } from '../models/ReactionModel';
+import GuildModel, { Guild } from '../models/ReactionGuildModel';
+import { MONGO_EVENTS } from '../utils/Constants'
+import BotClient from '../../client/BotClient';
+import { mongoDBUri } from '../../Config';
+
+let i = 0;
+
+/**
+ * The key, model and cached collection of a database model.
+ * @interface
+ */
+interface Combo {
+ key: string;
+ model: Model<any>;
+ cache: Collection<string, any>;
+}
+
+/**
+ * The Settings Provider that handles all database reads and rights.
+ * @private
+ */
+export default class SettingsProvider {
+ protected readonly client: BotClient;
+
+ protected readonly guilds: Collection<string, Guild> = new Collection();
+ protected readonly reactions: Collection<string, Reaction> = new Collection();
+
+ protected readonly GuildModel = GuildModel;
+ protected readonly ReactionModel = ReactionModel;
+
+ /**
+ *
+ * @param {GiveawayClient} client - The extended Akairo Client
+ */
+ public constructor(client: BotClient) {
+ this.client = client;
+ }
+
+ /**
+ * Retuns all the collection caches.
+ * @returns {Object}
+ */
+ public get cache() {
+ return {
+ guilds: this.guilds,
+ reactions: this.reactions,
+ };
+ }
+
+ /**
+ * Returns the database combos
+ * @returns {Combo[]}
+ */
+ public get combos(): Combo[] {
+ return [
+ {
+ key: 'guild',
+ model: this.GuildModel,
+ cache: this.guilds,
+ },
+ {
+ key: 'reaction',
+ model: this.ReactionModel,
+ cache: this.reactions,
+ },
+ ];
+ }
+
+ /**
+ * Creates a new database document with the provided collection name and data.
+ * @param {string} type - The collection name
+ * @param {object} data - The data for the new document
+ * @returns {Docuement}
+ */
+ public async new(type: 'guild', data: Partial<Guild>): Promise<Guild>;
+ public async new(type: 'reaction', data: Partial<Reaction>): Promise<Reaction>;
+ public async new(type: string, data: object): Promise<object> {
+ const combo = this.combos.find(c => c.key === type);
+ if (combo) {
+ const document = new combo.model(data);
+ await document.save();
+ this.client.logger.data(`[DATABASE] Made new ${combo.model.modelName} document with ID of ${document._id}.`);
+ combo.cache.set(document.id, document);
+ return document;
+ }
+ throw Error(`"${type}" is not a valid model key.`);
+ }
+
+ /**
+ * Updates the a database document's data.
+ * @param {Types} type - The collection name
+ * @param {object} key - The search paramaters for the document
+ * @param {object} data - The data you wish to overwrite in the update
+ * @returns {Promise<Faction | Guild | null>}
+ */
+ public async set(type: 'guild', key: Partial<Guild>, data: Partial<Guild>): Promise<Guild | null>;
+ public async set(type: 'reaction', key: Partial<Reaction>, data: Partial<Reaction>): Promise<Reaction | null>;
+ public async set(type: string, key: object, data: object): Promise<object | null> {
+ const combo = this.combos.find(c => c.key === type);
+ if (combo) {
+ const document = await combo.model.findOneAndUpdate(key, { $set: data }, { new: true });
+ if (document) {
+ this.client.logger.verbose(`[DATABASE] Edited ${combo.model.modelName} document with ID of ${document._id}.`);
+ combo.cache.set(document.id, document);
+ return document;
+ }
+ return null;
+ }
+ throw Error(`"${type}" is not a valid model key.`);
+ }
+
+ /**
+ * Removes a database document.
+ * @param {Types} type - The collection name
+ * @param {object} data - The search paramaters for the document
+ * @returns {Promise<Faction | Guild | null>>} The document that was removed, if any.
+ */
+ public async remove(type: 'guild', data: Partial<Guild>): Promise<Guild | null>;
+ public async remove(type: 'user', data: Partial<Reaction>): Promise<Reaction | null>;
+ public async remove(type: string, data: object): Promise<object | null> {
+ const combo = this.combos.find(c => c.key === type);
+ if (combo) {
+ const document = await combo.model.findOneAndRemove(data);
+ if (document) {
+ this.client.logger.verbose(`[DATABASE] Edited ${combo.model.modelName} document with ID of ${document._id}.`);
+ combo.cache.delete(document.id);
+ return document;
+ }
+ return null;
+ }
+ throw Error(`"${type}" is not a valid model key.`);
+ }
+
+ /**
+ * Caching all database documents.
+ * @returns {number} The amount of documents cached total.
+ * @private
+ */
+ private async _cacheAll(): Promise<number> {
+ for (const combo of this.combos) await this._cache(combo);
+ return i;
+ }
+
+ /**
+ * Caching each collection's documents.
+ * @param {Combo} combo - The combo name
+ * @returns {number} The amount of documents cached from that collection.
+ * @private
+ */
+ private async _cache(combo: Combo): Promise<any> {
+ const items = await combo.model.find();
+ for (const i of items) combo.cache.set(i.id, i);
+ this.client.logger.verbose(
+ `[DATABASE]: Cached ${items.length.toLocaleString('en-US')} items from ${combo.model.modelName}.`,
+ );
+ return (i += items.length);
+ }
+
+ /**
+ * Connect to the database
+ * @param {string} url - the mongodb uri
+ * @returns {Promise<number | Logger>} Returns a
+ */
+ private async _connect(url: string | undefined): Promise<Logger | number> {
+ if (url) {
+ const start = Date.now();
+ try {
+ await connect(url, {
+ useCreateIndex: true,
+ useNewUrlParser: true,
+ useFindAndModify: false,
+ useUnifiedTopology: true,
+ });
+ } catch (err) {
+ this.client.logger.error(`[DATABASE] Error when connecting to MongoDB:\n${err.stack}`);
+ process.exit(1);
+ }
+ return this.client.logger.verbose(`[DATABASE] Connected to MongoDB in ${Date.now() - start}ms.`);
+ }
+ this.client.logger.error('[DATABASE] No MongoDB url provided!');
+ return process.exit(1);
+ }
+
+ /**
+ * Adds all the listeners to the mongo connection.
+ * @param connection - The mongoose connection
+ * @returns {void}
+ * @private
+ */
+ private _addListeners(connection: Connection): void {
+ for (const [event, msg] of Object.entries(MONGO_EVENTS)) {
+ connection.on(event, () => this.client.logger.data(`[DATABASE]: ${msg}`));
+ }
+ }
+
+ /**
+ * Starts the Settings Provider
+ * @returns {SettingsProvider}
+ */
+ public async init(): Promise<this> {
+ this._addListeners(connection);
+ await this._connect(mongoDBUri);
+ this.client.logger.verbose(`[DATABASE]: Now caching ${this.combos.length} schema documents.`);
+ await this._cacheAll();
+ this.client.logger.info(`[DATABASE] [LAUNCHED] Successfully connected and cached ${i} documents.`);
+ return this;
+ }
+}