import { InsightDatasetKind, InsightError, ResultTooLargeError } from "../controller/IInsightFacade";
import QueryValidatorWhere from "./QueryValidatorWhere";
import QueryValidatorOptions from "./QueryValidatorOptions";
import { ValidatorInfo } from "./QueryProcessor";
import QueryValidatorTransformations from "./QueryValidatorTransformations";
import QueryPersister from "./QueryPersister";
export default class QueryValidator {
constructor() {}
private static mfieldsSections: string[] = ["avg", "pass", "fail", "audit", "year"];
private static sfieldsSections: string[] = ["dept", "id", "instructor", "title", "uuid"];
private static mfieldsRooms: string[] = ["lat", "lon", "seats"];
private static sfieldsRooms: string[] = [
"fullname",
"shortname",
"number",
"address",
"name",
"type",
"furniture",
"href",
];
private static max = 3;
public static validateQuery(query: any, validateInfo: ValidatorInfo): boolean {
if (query === null || Array.isArray(query) || typeof query !== "object") {
throw new InsightError("Query is not an object!");
}
if ("WHERE" in query && "OPTIONS" in query && Object.keys(query).length === 2) {
QueryValidatorWhere.validateQueryWhere(query.WHERE, validateInfo);
QueryValidatorOptions.validateQueryOptions(query.OPTIONS, validateInfo);
return true;
} else if (
"TRANSFORMATIONS" in query &&
"WHERE" in query &&
"OPTIONS" in query &&
Object.keys(query).length === this.max
) {
QueryValidatorWhere.validateQueryWhere(query.WHERE, validateInfo);
QueryValidatorTransformations.validateTransformations(query.TRANSFORMATIONS, validateInfo);
QueryValidatorOptions.validateQueryOptions(query.OPTIONS, validateInfo);
return true;
}
throw new InsightError("Wrong object!");
}
public static validateMKey(mkey: any, validateInfo: ValidatorInfo): boolean {
if (typeof mkey === "string" && mkey.includes("_")) {
const index = mkey.indexOf("_");
const idstring = mkey.substring(0, index);
const key = mkey.substring(index + 1);
this.validateIdString(idstring, validateInfo);
if (validateInfo.type === "") {
if (this.mfieldsSections.includes(key)) {
validateInfo.type = "sections";
return true;
} else if (this.mfieldsRooms.includes(key)) {
validateInfo.type = "rooms";
return true;
}
} else {
if (validateInfo.type === "sections" && this.mfieldsSections.includes(key)) {
return true;
} else if (validateInfo.type === "rooms" && this.mfieldsRooms.includes(key)) {
return true;
}
}
}
throw new InsightError("Invalid mkey!");
}
public static validateSKey(skey: any, validateInfo: ValidatorInfo): boolean {
if (typeof skey === "string" && skey.includes("_")) {
const index = skey.indexOf("_");
const idstring = skey.substring(0, index);
const key = skey.substring(index + 1);
this.validateIdString(idstring, validateInfo);
if (validateInfo.type === "") {
if (this.sfieldsSections.includes(key)) {
validateInfo.type = "sections";
return true;
} else if (this.sfieldsRooms.includes(key)) {
validateInfo.type = "rooms";
return true;
}
} else {
if (validateInfo.type === "sections" && this.sfieldsSections.includes(key)) {
return true;
} else if (validateInfo.type === "rooms" && this.sfieldsRooms.includes(key)) {
return true;
}
}
}
throw new InsightError("Invalid skey!");
}
public static validateKey(key: any, validateInfo: ValidatorInfo): string {
if (typeof key === "string" && key.includes("_")) {
const index = key.indexOf("_");
const idstring = key.substring(0, index);
const akey = key.substring(index + 1);
this.validateIdString(idstring, validateInfo);
if (validateInfo.type === "") {
if (this.sfieldsSections.includes(akey) || this.mfieldsSections.includes(akey)) {
validateInfo.type = "sections";
return key;
} else if (this.sfieldsRooms.includes(akey) || this.mfieldsRooms.includes(akey)) {
validateInfo.type = "rooms";
return key;
}
} else {
if (
validateInfo.type === "sections" &&
(this.sfieldsSections.includes(akey) || this.mfieldsSections.includes(akey))
) {
return key;
} else if (
validateInfo.type === "rooms" &&
(this.sfieldsRooms.includes(akey) || this.mfieldsRooms.includes(akey))
) {
return key;
}
}
}
throw new InsightError("Invalid key!");
}
public static validateIdString(idstring: any, validateInfo: ValidatorInfo): boolean {
if (idstring.length > 0 && !idstring.includes("_")) {
if (validateInfo.id === "") {
validateInfo.id = idstring;
} else if (validateInfo.id !== idstring) {
throw new InsightError("Can only query one dataset!");
}
return true;
}
throw new InsightError("Invalid id string!");
}
public static validateAnykey(anykey: any, validateInfo: ValidatorInfo): string {
if (typeof anykey === "string") {
if (anykey.includes("_")) {
return this.validateKey(anykey, validateInfo);
} else if (anykey.length > 0) {
return anykey;
}
}
throw new InsightError("anykey is not string!");
}
public static validateSize(size: number): void {
const MAXSIZE = 5000;
if (size > MAXSIZE) {
throw new ResultTooLargeError(`InsightResult is over 5000, ${size}`);
}
}
public static async validateKind(id: string, kind: InsightDatasetKind): Promise<void> {
const insights = await new QueryPersister().persistQuery("data/_insightDatasets.json");
try {
const insight = insights.find((dataset: any) => dataset.id === id);
if (insight ? insight.kind === kind : false) {
return;
}
} catch (_e) {
throw new InsightError("validateKind! no id or wrong dataset kind");
}
}
}