diff --git a/packages/elasticsearch-plugin/src/build-elastic-body.ts b/packages/elasticsearch-plugin/src/build-elastic-body.ts index 27f3e91cc5..2c7743491e 100644 --- a/packages/elasticsearch-plugin/src/build-elastic-body.ts +++ b/packages/elasticsearch-plugin/src/build-elastic-body.ts @@ -52,7 +52,7 @@ export function buildElasticBody( const operator = facetValueOperator === LogicalOperator.AND ? 'must' : 'should'; query.bool.filter = query.bool.filter.concat([ { - bool: { [operator]: facetValueIds.map(id => ({ term: { facetValueIds: id } })) }, + bool: { [operator]: facetValueIds.map((id) => ({ term: { facetValueIds: id } })) }, }, ]); } @@ -88,7 +88,9 @@ export function buildElasticBody( } } return { - query, + query: searchConfig.mapQuery + ? searchConfig.mapQuery(query, input, searchConfig, channelId, enabledOnly) + : query, sort: sortArray, from: skip || 0, size: take || 10, diff --git a/packages/elasticsearch-plugin/src/options.ts b/packages/elasticsearch-plugin/src/options.ts index 17b2a32662..764f44cb3d 100644 --- a/packages/elasticsearch-plugin/src/options.ts +++ b/packages/elasticsearch-plugin/src/options.ts @@ -1,7 +1,7 @@ -import { DeepRequired, Product, ProductVariant } from '@vendure/core'; +import { DeepRequired, ID, Product, ProductVariant } from '@vendure/core'; import deepmerge from 'deepmerge'; -import { CustomMapping } from './types'; +import { CustomMapping, ElasticSearchInput } from './types'; /** * @description @@ -188,6 +188,50 @@ export interface SearchConfig { * ``` */ priceRangeBucketInterval?: number; + /** + * @description + * This config option allows the the modification of the whole (already built) search query. This allows + * for e.g. wildcard / fuzzy searches on the index. + * + * @example + * ```TypeScript + * mapQuery: (query, input, searchConfig, channelId, enabledOnly){ + * if(query.bool.must){ + * delete query.bool.must; + * } + * query.bool.should = [ + * { + * query_string: { + * query: "*" + term + "*", + * fields: [ + * `productName^${searchConfig.boostFields.productName}`, + * `productVariantName^${searchConfig.boostFields.productVariantName}`, + * ] + * } + * }, + * { + * multi_match: { + * query: term, + * type: searchConfig.multiMatchType, + * fields: [ + * `description^${searchConfig.boostFields.description}`, + * `sku^${searchConfig.boostFields.sku}`, + * ], + * }, + * }, + * ]; + * + * return query; + * } + * ``` + */ + mapQuery?: ( + query: any, + input: ElasticSearchInput, + searchConfig: DeepRequired, + channelId: ID, + enabledOnly: boolean, + ) => any; } /** @@ -246,6 +290,7 @@ export const defaultOptions: DeepRequired = { sku: 1, }, priceRangeBucketInterval: 1000, + mapQuery: (query) => query, }, customProductMappings: {}, customProductVariantMappings: {},