import { UserType } from "../types/basicUser";
import IFilters from "../types/filters";
import { RequestContext } from "./requestContext";
/**
* Class for handling filters
*/
class Filters {
sortBy?: "hot" | "new" | "topRated" | "topViewed";
category?: string;
from?: Date;
author?: string;
skip?: number;
limit?: number;
query?: string;
clientID?: string;
private variables: string[] = [];
private queryParts: {
select: string[],
from: string[],
where: string[],
groupBy: string[],
orderBy: string[],
limit: (string|number)[]
} = {
select: ["animations.*"],
from: ["animations"],
where: [],
groupBy: [],
orderBy: [],
limit: []
};
/**
* Instantiates the class
* @param {IFilters} data
*/
constructor(data: IFilters, public ctx: RequestContext) {
this.sortBy = data.sortBy;
this.category = data.category;
this.from = data.from;
this.author = data.author;
this.query = data.query;
}
/**
* 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 anims";
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() {
switch(this.sortBy) {
case "topRated":
this.queryParts.select.push(
"SUM(ratings.stars) as num_stars", "COUNT(ratings.snowflake) as rating_count"
);
this.queryParts.from.push("ratings");
this.queryParts.where.push("ratings.animation = animations.snowflake");
this.queryParts.groupBy.push("animations.snowflake");
this.queryParts.orderBy.push(
"(SUM(ratings.stars) * COUNT(ratings.snowflake)) DESC"
);
break;
case "hot":
this.queryParts.select.push(
"SUM(ratings.stars) as num_stars", "COUNT(ratings.snowflake) as rating_count"
);
this.queryParts.from.push("ratings");
this.queryParts.where.push("ratings.animation = animations.snowflake");
this.queryParts.groupBy.push("animations.snowflake");
this.queryParts.orderBy.push(
"( (SUM(ratings.stars) * COUNT(ratings.snowflake)) / animations.snowflake) DESC"
);
break;
case "topViewed":
this.queryParts.orderBy.push("views DESC");
break;
case "new":
this.queryParts.orderBy.push("snowflake DESC");
break;
}
}
/**
* Builds the where part of queries
*/
private buildQueryWherePart() {
if(this.category) {
this.queryParts.where.push("category = ?");
this.variables.push(this.category);
}
if(this.from) {
var snowflake = BigInt(this.from.valueOf()) << BigInt(22);
this.queryParts.where.push("snowflake > ?");
this.variables.push(snowflake.toString());
}
if(this.author) {
this.queryParts.where.push("author = ?");
this.variables.push(this.author);
}
if(this.query) {
this.queryParts.where.push("MATCH (name, description) AGAINST (? IN BOOLEAN MODE)");
let query = this.query;
query = `(${query.split(" ")
.map((t) => t + "*").join(" ")}) ("${query.replace(/"/g, "")}")`;
this.variables.push(query);
}
if(this.ctx.user && this.ctx.user.type < UserType.MODERATOR) {
this.queryParts.where.push(
"(published IS NOT NULL OR author = ?)",
"category >= 0"
);
this.variables.push(this.ctx.user.id.toString());
} else if(!this.ctx.user) {
this.queryParts.where.push(
"published IS NOT NULL",
"category >= 0"
);
}
// blocked doesn't exist. User relations does - fix that later
// this.queryParts.where
// .push("NOT EXISTS (SELECT * FROM blocked WHERE blocked.blocked = animations.author)");
}
};
export default Filters;
Source