UNPKG

@meilisearch/instant-meilisearch

Version:
127 lines 4.73 kB
const filterEscapeRegExp = /([\\"])/g; function getValueWithEscapedBackslashesAndQuotes(value) { return value.replace(filterEscapeRegExp, '\\$1'); } /** * Transform InstantSearch [facet * filter](https://www.algolia.com/doc/api-reference/api-parameters/facetFilters/) * to Meilisearch compatible filter format. Change sign from `:` to `=` * "facet:facetValue" becomes "facet=facetValue" * * Wrap both the facet and its facet value between quotes. This avoids * formatting issues on facets containing multiple words. Escape backslash \ and * quote " characters. * * 'My facet:My facet value' becomes '"My facet":"My facet value"' * * @param {string} filter * @returns {string} */ function transformFacetFilter(filter) { const escapedFilter = getValueWithEscapedBackslashesAndQuotes(filter); const colonIndex = escapedFilter.indexOf(':'); const attribute = escapedFilter.slice(0, colonIndex); const value = escapedFilter.slice(colonIndex + 1); return `"${attribute}"="${value}"`; } /** * Transform InstantSearch [numeric * filter](https://www.algolia.com/doc/api-reference/api-parameters/numericFilters/) * to Meilisearch compatible filter format. * * 'price:5.99 TO 100' becomes '"price" 5.99 TO 100' * * 'price = 5.99' becomes '"price"=5.99' * * Wrap the attribute between quotes. Escape backslash \ and quote " characters. * * @param {string} filter * @returns {string} */ function transformNumericFilter(filter) { const splitNumericFilter = () => { const attributeMatch = filter.match(/^([^<!>:=]*)([<!>:=]+)(.*)$/); if (attributeMatch) { const [attribute, dirtyOperator, valueEnd] = attributeMatch.slice(1); const operatorMatch = dirtyOperator.match(/^([<!>]?=|<|>|:){1}(.*)/) || [ '', '', ]; const [operator, valueStart] = operatorMatch.slice(1); const cleanedValue = valueStart + valueEnd; return [attribute, operator, cleanedValue]; } return [filter, '', '']; }; const [attribute, operator, value] = splitNumericFilter(); const escapedAttribute = getValueWithEscapedBackslashesAndQuotes(attribute); return `"${escapedAttribute.trim()}"${operator === ':' ? ' ' : operator}${value.trim()}`; } /** * Iterate over all filters. Return the filters in a Meilisearch compatible * format. * * @param {(filter: string) => string} transformCallback * @param {SearchContext['facetFilters']} filters * @returns {Filter} */ function transformFilters(transformCallback, filters) { return typeof filters === 'string' ? transformCallback(filters) : filters.map((filter) => typeof filter === 'string' ? transformCallback(filter) : filter.map((nestedFilter) => transformCallback(nestedFilter))); } /** * Return the filter in an array if it is a string If filter is array, return * without change. * * @param {Filter} [filter] * @returns {Array | undefined} */ function filterToArray(filter) { return typeof filter === 'string' ? [filter] : filter; } /** * Merge filters, transformedNumericFilters and transformedFacetFilters * together. * * @param {string} filters * @param {Filter} transformedNumericFilters * @param {Filter} transformedFacetFilters * @returns {Filter} */ function mergeFilters(filters, transformedNumericFilters, transformedFacetFilters) { const adaptedNumericFilters = filterToArray(transformedNumericFilters); const adaptedFacetFilters = filterToArray(transformedFacetFilters); const adaptedFilters = []; if (filters !== undefined) { adaptedFilters.push(filters); } if (adaptedNumericFilters !== undefined) { adaptedFilters.push(...adaptedNumericFilters); } if (adaptedFacetFilters !== undefined) { adaptedFilters.push(...adaptedFacetFilters); } return adaptedFilters; } /** * Adapt instantsearch.js filters to Meilisearch filters by combining and * transforming all provided filters. * * @param {string | undefined} filters * @param {SearchContext['numericFilters']} numericFilters * @param {SearchContext['facetFilters']} facetFilters * @returns {Filter} */ export function adaptFilters(filters, numericFilters, facetFilters) { const transformedNumericFilters = numericFilters !== undefined ? transformFilters(transformNumericFilter, numericFilters) : numericFilters; const transformedFacetFilters = facetFilters !== undefined ? transformFilters(transformFacetFilter, facetFilters) : facetFilters; return mergeFilters(filters, transformedNumericFilters, transformedFacetFilters); } //# sourceMappingURL=filter-adapter.js.map