From ce22f77b32154f554e96845d3ebf2545704b3bb7 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:21:41 +0700 Subject: [PATCH] feat: added nested op --- .../src/controllers/searchController.ts | 25 +++++++----- Services/server/src/interfaces/search.ts | 39 +++++++++++++------ 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/Services/server/src/controllers/searchController.ts b/Services/server/src/controllers/searchController.ts index 158addc..37bd81a 100644 --- a/Services/server/src/controllers/searchController.ts +++ b/Services/server/src/controllers/searchController.ts @@ -1,8 +1,9 @@ import { Body, Controller, Post, Route, Security, SuccessResponse, Tags } from "tsoa"; import HttpStatusCode from "../interfaces/http-status"; import esClient from "../elasticsearch"; -import { Search } from "../interfaces/search"; +import { Search, SearchInfo, SearchOperator } from "../interfaces/search"; import { StorageFile } from "../interfaces/storage-fs"; +import { QueryDslQueryContainer } from "@elastic/elasticsearch/lib/api/types"; const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX; @@ -17,19 +18,23 @@ export class SearchController extends Controller { public async searchFile(@Body() search: Search): Promise { const type = ["match", "match_phrase"] as const; + const searchMapCallback = (v: SearchInfo | SearchOperator): QueryDslQueryContainer => { + if ("field" in v && "value" in v) { + return { [type[search.exact || v.exact ? 1 : 0]]: { [v.field]: v.value } }; + } + + return { + bool: { must: v.AND?.map(searchMapCallback), should: v.OR?.map(searchMapCallback) }, + }; + }; + const result = await esClient.search }>({ index: DEFAULT_INDEX, query: { bool: { - must: search.AND?.map((v) => ({ - [type[search.exact || v.exact ? 1 : 0]]: { [v.field]: v.value }, - })), - should: search.OR?.map((v) => ({ - [type[search.exact || v.exact ? 1 : 0]]: { [v.field]: v.value }, - })), - must_not: { - match: { hidden: true }, - }, + must: search.AND?.map(searchMapCallback), + should: search.OR?.map(searchMapCallback), + must_not: { match: { hidden: true } }, }, }, post_filter: { diff --git a/Services/server/src/interfaces/search.ts b/Services/server/src/interfaces/search.ts index 1ceedf3..c16fc63 100644 --- a/Services/server/src/interfaces/search.ts +++ b/Services/server/src/interfaces/search.ts @@ -1,15 +1,32 @@ -export interface Search { - AND?: { - field: string; - value: string; - exact?: boolean; - }[]; - OR?: { - field: string; - value: string; - exact?: boolean; - }[]; +import { QueryDslQueryContainer } from "@elastic/elasticsearch/lib/api/types"; + +export interface SearchInfo { + field: string; + value: string; exact?: boolean; +} + +export interface SearchOperator { + AND?: (SearchInfo | SearchOperator)[]; + OR?: (SearchInfo | SearchOperator)[]; +} + +export interface Search extends SearchOperator { recursive?: boolean; path?: string[]; + exact?: boolean; +} + +export function mapCallback(exact: boolean) { + const type = ["match", "match_phrase"] as const; + return (v: SearchInfo | SearchOperator): QueryDslQueryContainer => { + return "field" in v && "value" in v + ? { [type[exact || v.exact ? 1 : 0]]: { [v.field]: v.value } } + : { + bool: { + must: v.AND?.map(mapCallback(exact)), + should: v.OR?.map(mapCallback(exact)), + }, + }; + }; }