Source

classes/userFilters.ts

import { UserType } from "../types/basicUser";
import IUserFilters from "../types/userFilters";
import { RequestContext } from "./requestContext";

/**
 * Class for handling filters
 */
class UserFilters {
    // sortBy?: "mostFollowers" | "mostContent" |
    // "mostAnimations" | "mostViews" | "mostComments" | "mostPopular";
    skip?: number;
    limit?: number;
    query?: string;

    private variables: string[] = [];
    private queryParts: {
        select: string[],
        from: string[],
        where: string[],
        groupBy: string[],
        orderBy: string[],
        limit: (string|number)[]
    } = {
        select: ["users.*"],
        from: ["users"],
        where: [],
        groupBy: [],
        orderBy: [],
        limit: []
    };

    /**
     * Instantiates the class
     * @param {IUserFilters} data
     */
    constructor(data: IUserFilters, public ctx: RequestContext) {
        // this.sortBy = data.sortBy;
        this.query = data.query;
    }

    /**
     * Clones the class
     * Building query modifies internal state, so we need to clone it sometimes
     * @return {UserFilters}
     */
    clone() {
        return new UserFilters({
            // sortBy: this.sortBy,
            skip: this.skip,
            limit: this.limit,
            query: this.query
        }, this.ctx);
    }

    /**
     * Builds the query to get the count
     * @return {{ query: string, variables: string[]}}
     */
    buildCountQuery(): { query: string, variables: string[] } {
        this.variables = [];
        // this.prepareQueryOrderByPart();

        this.buildQueryWherePart();
        this.buildQueryLimitPart();

        var query =
        "SELECT COUNT(*) as count FROM (SELECT " + this.queryParts.select.join(", ") +
        " FROM " + this.queryParts.from.join(", ") +
        (this.queryParts.where.length ? " WHERE " + this.queryParts.where.join(" AND ") : "") +
        (this.queryParts.groupBy.length ? " GROUP BY " + this.queryParts.groupBy.join(", ") : "") +
        ") as users";

        return {
            query,
            variables: this.variables
        };
    }

    /**
     * Builds the query
     * @return {{ query: string, variables: string[] }}
     */
    buildQuery(): { query: string, variables: string[] } {
        this.variables = [];
        this.prepareQueryOrderByPart();

        this.buildQueryWherePart();
        this.buildQueryLimitPart();

        var query =
        `SELECT ${this.queryParts.select.join(", ")} FROM ${this.queryParts.from.join(", ")}` +
        (this.queryParts.where.length ? " WHERE " + this.queryParts.where.join(" AND ") : "") +
        (this.queryParts.groupBy.length ? " GROUP BY " + this.queryParts.groupBy.join(", ") : "") +
        (this.queryParts.orderBy.length ? " ORDER BY " + this.queryParts.orderBy.join(", ") : "") +
        (this.queryParts.limit.length ? " LIMIT " + this.queryParts.limit.join(",") : "");

        return {
            query,
            variables: this.variables
        };
    }

    /**
     * Builds the limit part
     */
    private buildQueryLimitPart() {
        if(this.skip) this.queryParts.limit.push(this.skip.toString());
        if(this.limit) this.queryParts.limit.push(this.limit.toString());
    }

    /**
     * Prepares the orderBy part
     */
    private prepareQueryOrderByPart() {
        this.queryParts.orderBy.push("users.snowflake DESC");
    }

    /**
     * Builds the where part of queries
     */
    private buildQueryWherePart() {
        if(this.query) {
            this.queryParts.where.push("MATCH (name, description) AGAINST (? IN BOOLEAN MODE)");
            this.queryParts.select
                .push("MATCH (name, description) AGAINST (? IN BOOLEAN MODE) as score");
            let q = this.query;
            q = `(${q.split(" ").map((t) => t + "*").join(" ")}) ("${q.replace(/"/g, "")}")`;
            this.variables.push(q);
            this.variables.push(q);
            this.queryParts.orderBy.unshift("score DESC");
        }
        if((this.ctx.user && this.ctx.user.type < UserType.MODERATOR) || !this.ctx.user) {
            this.queryParts.where.push(
                "type >= 0"
            );
        }
        // TODO: blocked doesn't exist. User relations does - fix that later
        // this.queryParts.where
        // .push("NOT EXISTS (SELECT * FROM blocked WHERE blocked.blocked = user.id)");
    }
};

export default UserFilters;