adonis-forge
Version:
Bundle utils for AdonisJS
121 lines (120 loc) • 3.55 kB
JavaScript
// src/crud/utils/query_handler.ts
var QueryHandler = class {
model;
qs;
constructor(model, qs) {
this.model = model;
this.qs = qs;
}
handle(query) {
this.handleSearch(query);
this.handleIncludes(query);
return query;
}
handleSearch(query) {
const modelKeys = Object.keys(this.model.$keys.columnsToSerialized.all());
const validKeys = Object.keys(this.qs).filter((key) => {
if (key === "keywords" && Array.isArray(this.qs[key])) {
query.where((q) => {
const keywords = this.qs[key];
for (const val of keywords) {
Object.entries(val).forEach(([k, value]) => {
q.orWhere(k, "like", `%${value}%`);
});
}
});
return false;
}
const match = key.match(/^\$(\w+)\$/);
if (match) {
this.handleMagicQuery(query, {
operator: match[1],
field: key.replace(match[0], ""),
value: this.qs[key]
});
return false;
}
if (!modelKeys.includes(key) || ["created_at", "updated_at"].includes(key)) {
return false;
}
return true;
});
for (const key of validKeys) {
query.where(key, this.qs[key]);
}
}
handleMagicQuery(query, options) {
switch (options.operator) {
case "gt":
query.where(options.field, ">", options.value);
break;
case "lt":
query.where(options.field, "<", options.value);
break;
case "like":
query.where(options.field, "like", `%${options.value}%`);
break;
case "in":
query.whereIn(
options.field,
options.value.split(",").map((e) => Number(e))
);
break;
case "notIn":
query.whereNotIn(
options.field,
options.value.split(",").map((e) => Number(e))
);
break;
case "between":
const [left, right] = options.value.split(",");
query.whereBetween(options.field, [Number(left), Number(right)]);
break;
default:
throw new Error(`invalid operator ${options.operator}`);
}
}
/**
* @example
* &includes=user,address
*/
handleIncludes(query) {
if (!this.qs["includes"]) return;
const includes = Array.isArray(this.qs["includes"]) ? this.qs["includes"] : this.qs["includes"].split(",").filter((item) => item !== "").map((item) => item.trim()) || [];
const arrayOptions = [];
for (const include of includes) {
const [firstRelation, secondRelation] = include.split(".");
if (!arrayOptions[firstRelation]) {
arrayOptions[firstRelation] = { firstRelation, subs: [] };
}
if (secondRelation) {
arrayOptions[firstRelation].subs.push({ secondRelation });
}
if (firstRelation && !secondRelation) {
this.hasInclude(includes);
}
if (arrayOptions) {
for (const relationOption of Object.keys(arrayOptions)) {
query.preload(`${arrayOptions[relationOption].firstRelation}`, () => {
});
}
}
}
}
hasInclude(includes) {
let includesNotAvailables = [];
for (const include of includes) {
const [first] = include.split(".");
if (!this.model.$hasRelation(first)) {
includesNotAvailables.push(include);
}
}
if (includesNotAvailables.length) {
throw new Error(`invalid relations includes ${includesNotAvailables.map((e) => e)}`);
}
}
};
export {
QueryHandler
};
//# sourceMappingURL=chunk-5AVUSAWG.js.map