huridocs/uwazi

View on GitHub
app/api/search.v2/queryHelpers.ts

Summary

Maintainability
A
25 mins
Test Coverage
A
100%
import { elastic } from 'api/search';
import { SearchQuery } from 'shared/types/SearchQueryType';
import templatesModel from 'api/templates/templates';
import propertiesHelper from 'shared/commonProperties';
import { PropertySchema } from 'shared/types/commonTypes';

export const cleanUp = (value: any) => value;

const searchStringMethod = async (searchString: string) => {
  const validationResult = await elastic.indices.validateQuery({
    body: { query: { query_string: { query: searchString } } },
  });
  return validationResult.body.valid ? 'query_string' : 'simple_query_string';
};

const FULLTEXTGROUP_MATCH_REGEX = /fullText:\(\s*[^,)]*\)/g;
const FULLTEXTGROUP_CAPTURE_REGEX = /fullText:\(\s*([^,)]*)\)/;

const extractFullTextGroups = (searchString: string) => {
  const fullTextGroups = searchString.match(FULLTEXTGROUP_MATCH_REGEX) || [];
  return fullTextGroups.map(s => s.match(FULLTEXTGROUP_CAPTURE_REGEX)).map(r => (r ? r[1] : ''));
};

// eslint-disable-next-line max-statements
async function extractSearchParams(query: SearchQuery) {
  const templates = await templatesModel.get();
  const uniqueProperties = (propertiesHelper.allUniqueProperties(templates) as PropertySchema[])
    .map(prop =>
      ['text', 'markdown', 'generatedid'].includes(prop.type)
        ? `metadata.${prop.name}.value`
        : `metadata.${prop.name}.label`
    )
    .concat(['title']);

  if (query.filter && query.filter.searchString) {
    const { searchString } = query.filter;
    const fullTextGroups = extractFullTextGroups(searchString);

    if (fullTextGroups.length) {
      const fullTextSearchString = fullTextGroups.join(' ');
      return {
        fullText: {
          string: fullTextSearchString,
          method: await searchStringMethod(fullTextSearchString),
        },
      };
    }

    const searchMethod = await searchStringMethod(searchString);
    return {
      search: {
        string: searchString,
        method: searchMethod,
        properties: uniqueProperties,
      },
      fullText: {
        string: searchString,
        method: searchMethod,
      },
    };
  }
  return {
    search: {
      string: query.filter?.searchString,
      method: 'query_string',
      properties: uniqueProperties,
    },
  };
}

function snippetsHighlight(query: SearchQuery, fields: { [key: string]: {} }[] | undefined) {
  const snippets = query.fields && query.fields.includes('snippets');
  return snippets
    ? {
        highlight: {
          order: 'score',
          pre_tags: ['<b>'],
          post_tags: ['</b>'],
          encoder: 'html',
          number_of_fragments: 9999,
          ...(fields?.[0].hasOwnProperty('fullText_*') ? { type: 'fvh' } : {}),
          fragment_size: 300,
          fragmenter: 'span',
          fields,
        },
      }
    : {};
}

export { extractSearchParams, snippetsHighlight };