Source

classes/category.ts

import Snowflake from "./snowflake";
import UserClient from "./userClient";
import { SnowflakeString } from "../types/snowflake";
import { UserType } from "../types/basicUser";
import Collection from "@discordjs/collection";
import { RequestContext } from "./requestContext";
import { DBCategory, prisma } from "../../prisma";

const cache = new Collection<SnowflakeString, Category>();
let lengthCache = -1;

/**
 * Holds data about given category
 */
class Category {
    id: Snowflake;
    ctx: RequestContext;
    client?: UserClient;

    name: string;
    description: string;

    /**
     * @param {object} data
     */
    constructor({
        id,
        ctx,
        name,
        description
    }: {
        id: Snowflake,
        ctx: RequestContext,
        name: string,
        description: string
    }) {
        this.id = id;
        this.ctx = ctx;
        this.client = ctx.client;
        this.name = name;
        this.description = description;
    }

    /**
     * @param {DBCategory} data
     * @param {RequestContext} ctx
     * @return {Category}
     */
    static fromDatabase(data: DBCategory, ctx: RequestContext): Category {
        if(cache.has(data.snowflake.toString())) {
            return cache.get(data.snowflake.toString()) as Category;
        }

        const cat = new Category({
            id: new Snowflake(data.snowflake),
            ctx,
            name: data.name,
            description: data.description
        });

        cache.set(data.snowflake.toString(), cat);

        return cat;
    }

    /**
     * Fetches category by id
     * @param {bigint | Snowflake | SnowflakeString} id
     * @param {requestContext} ctx
     * @param {UserClient | undefined} client
     * @return {Promise<Category>}
     */
    static async getCategory(id: bigint | Snowflake | SnowflakeString, ctx: RequestContext):
        Promise<Category> {
        let b: bigint;
        if(typeof id === "bigint") b = id;
        else if(id instanceof Snowflake) b = id.toBigInt();
        else b = BigInt(id);

        if(cache.has(id.toString())) return cache.get(id.toString()) as Category;

        const data = await prisma.category.findUniqueOrThrow({
            where: {
                snowflake: b
            }
        });

        return Category.fromDatabase(data, ctx);
    }

    /**
     * Gets total number of categories
     * @param {RequestContext} ctx
     * @return {Promise<number>}
     */
    static async getCategoryCount(ctx: RequestContext): Promise<number> {
        if(lengthCache !== -1) return lengthCache;
        const length = await prisma.category.count();
        lengthCache = length;
        return length;
    }

    /**
     * Gets categories
     * @param {RequestContext} ctx
     * @param {number} max
     * @param {number} page
     * @param {UserClient?} client
     * @return {Promise<Collection<SnowflakeString, Category>>}
     */
    static async getCategories(ctx: RequestContext, max: number, page: number):
        Promise<Collection<SnowflakeString, Category>> {
        if(lengthCache < max && cache.size === lengthCache && page === 0) return cache;

        const categories = await prisma.category.findMany({
            skip: page*max,
            take: max
        });

        const col = new Collection<SnowflakeString, Category>();

        for(const category of categories) {
            col.set(category.snowflake.toString(), Category.fromDatabase(category, ctx));
        }

        return col;
    }

    /**
     * Updates the given category
     * @return {Promise<void>}
     */
    async update(): Promise<void> {
        if(!this.client) throw new Error("unauthorized");
        if(!this.client.user.comparePosition(UserType.MODERATOR)) {
            throw new Error("unauthorized");
        }
        await prisma.category.update({
            where: {
                snowflake: this.id.toBigInt()
            },
            data: {
                name: this.name,
                description: this.description
            }
        });
    }

    /**
     * Creates a JSON-compatible object
     * @return {Object}
     */
    toJSON() {
        return {
            id: this.id.getSnowflake(),
            name: this.name,
            description: this.description
        };
    }
}

export default Category;