UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

54 lines (52 loc) 2.86 kB
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 };