@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
54 lines (52 loc) • 2.86 kB
JavaScript
import { getCases } from "../../../../permissions/modules/process-ast/lib/get-cases.js";
import { isValidUuid } from "../../../../utils/is-valid-uuid.js";
import { parseNumericString } from "../../../../utils/parse-numeric-string.js";
import { applyFilter } from "./filter/index.js";
import { getHelpers } from "../../../helpers/index.js";
import { isIn } from "@directus/utils";
import { NUMERIC_TYPES } from "@directus/constants";
//#region src/database/run-ast/lib/apply-query/search.ts
function applySearch(knex, schema, dbQuery, searchQuery, collection, aliasMap, permissions) {
const { number: numberHelper } = getHelpers(knex);
const allowedFields = new Set(permissions.filter((p) => p.collection === collection).flatMap((p) => p.fields ?? []));
let fields = Object.entries(schema.collections[collection].fields);
fields = fields.filter(([_name, field]) => field.searchable !== false && field.special.includes("conceal") !== true);
const { cases, caseMap } = getCases(collection, permissions, []);
if (cases.length !== 0 && !allowedFields.has("*")) fields = fields.filter((field) => allowedFields.has(field[0]));
dbQuery.andWhere(function(queryBuilder) {
let needsFallbackCondition = true;
fields.forEach(([name, field]) => {
const whenCases = allowedFields.has("*") ? [] : (caseMap[name] ?? []).map((caseIndex) => cases[caseIndex]);
const fieldType = getFieldType(field);
if (fieldType !== null) needsFallbackCondition = false;
else return;
if (cases.length !== 0 && whenCases?.length !== 0) queryBuilder.orWhere((subQuery) => {
addSearchCondition(subQuery, name, fieldType, "and");
applyFilter(knex, schema, subQuery, { _or: whenCases }, collection, aliasMap, cases, permissions);
});
else addSearchCondition(queryBuilder, name, fieldType, "or");
});
if (needsFallbackCondition) queryBuilder.orWhereRaw("1 = 0");
});
function addSearchCondition(queryBuilder, name, fieldType, logical) {
if (fieldType === null) return;
if (fieldType === "string") queryBuilder[logical].whereRaw(`LOWER(??) LIKE ?`, [`${collection}.${name}`, `%${searchQuery.toLowerCase()}%`]);
else if (fieldType === "numeric") numberHelper.addSearchCondition(queryBuilder, collection, name, parseNumericString(searchQuery), logical);
else if (fieldType === "uuid") queryBuilder[logical].where({ [`${collection}.${name}`]: searchQuery });
}
function getFieldType(field) {
if (["text", "string"].includes(field.type)) return "string";
if (isNumericField(field)) {
const number = parseNumericString(searchQuery);
if (number === null) return null;
if (numberHelper.isNumberValid(number, field)) return "numeric";
}
if (field.type === "uuid" && isValidUuid(searchQuery)) return "uuid";
return null;
}
}
function isNumericField(field) {
return isIn(field.type, NUMERIC_TYPES);
}
//#endregion
export { applySearch };