Source

classes/rating.ts

import Snowflake from "./snowflake";
import User from "./user";
import Animation, { BasicAnimation } from "./animation";
import { SnowflakeResolvable, SnowflakeString } from "../types/snowflake";
import UserClient from "./userClient";
import { UserResolvable } from "../types/user";
import { AnimationResolvable } from "../types/animation";
import { RequestContext } from "./requestContext";
import {
    DBRating,
    DBRatingFull,
    DBRatingWithAnimation,
    DBRatingWithAuthor,
    prisma
} from "../../prisma";

/**
 * Holds data about animation rating
 */
class Rating {
    id: Snowflake;
    ctx: RequestContext;
    client?: UserClient;

    user: User;
    animation: BasicAnimation;
    stars: number;

    /**
     * Creates animation rating data holder
     * @param {object} data
     */
    constructor({
        id,
        ctx,
        user,
        animation,
        stars
    }: {
        id: Snowflake;
        ctx: RequestContext;
        user: User;
        animation: BasicAnimation;
        stars: number;
    }) {
        this.id = id;
        this.ctx = ctx;
        this.client = ctx.client;
        this.user = user;
        this.animation = animation;
        this.stars = stars;
    }

    /**
     * @param {DBRating | DBRatingWithAnimation | DBRatingWithAuthor | DBRatingFull} data
     * @param {RequestContext} ctx
     */
    static async fromDatabase(
        data: DBRating | DBRatingWithAnimation | DBRatingWithAuthor | DBRatingFull,
        ctx: RequestContext
    ) {
        return new Rating({
            id: new Snowflake(data.snowflake),
            ctx,
            user:
                "author" in data ?
                    await User.fromDatabase(data.author, ctx) :
                    await User.getUser(data.authorId, ctx),
            animation:
                "animation" in data ?
                    await Animation.fromDatabase(data.animation, ctx) :
                    await Animation.getAnimation(data.animationId, ctx),
            stars: data.stars
        });
    }

    /**
     * Updates the rating
     * @return {Promise<void>}
     */
    async update(): Promise<void> {
        await prisma.rating.update({
            where: {
                snowflake: this.id.toBigInt()
            },
            data: {
                stars: this.stars
            }
        });
    }

    /**
     * Deletes the rating
     * @return {Promise<void>}
     */
    async delete(): Promise<void> {
        await prisma.rating.delete({
            where: {
                snowflake: this.id.toBigInt()
            }
        });
    }

    /**
     * Fetches a rating from given user and animation
     * @param {UserResolvable} user
     * @param {AnimationResolvable} animation
     * @param {RequestContext} ctx
     * @return {Promise}
     */
    static async getUserRating(
        user: UserResolvable,
        animation: AnimationResolvable,
        ctx: RequestContext
    ): Promise<Rating | null> {
        const res = await prisma.rating.findUnique({
            where: {
                authorId_animationId: {
                    authorId: BigInt(User.resolveUserID(user)),
                    animationId: BigInt(Animation.resolveAnimationID(animation))
                }
            }
        });
        if(!res) return null;
        return Rating.fromDatabase(res, ctx);
    }

    /**
     * Returns rating with specified id
     * @param {SnowflakeResolvable} id
     * @param {RequestContext} ctx
     * @return {Promise<Rating>}
     */
    static async getRating(
        id: SnowflakeResolvable,
        ctx: RequestContext
    ): Promise<Rating> {
        const res = await prisma.rating.findUniqueOrThrow({
            where: {
                snowflake: new Snowflake(id).toBigInt()
            }
        });
        return Rating.fromDatabase(res, ctx);
    }

    /**
     * Creates a JSON-compatible object
     * @return {Object}
     */
    toJSON() {
        return {
            id: this.id.getSnowflake(),
            user: this.user.toJSON(),
            animation: this.animation.toJSON(),
            stars: this.stars,
            time: this.id.time
        };
    }
}

export default Rating;