diff --git a/packages/eui/src/components/search_bar/query/default_syntax.test.ts b/packages/eui/src/components/search_bar/query/default_syntax.test.ts index 1303b93a6e27..cb12d5027565 100644 --- a/packages/eui/src/components/search_bar/query/default_syntax.test.ts +++ b/packages/eui/src/components/search_bar/query/default_syntax.test.ts @@ -1240,4 +1240,70 @@ describe('defaultSyntax', () => { const printedQuery = defaultSyntax.print(ast); expect(printedQuery).toBe(query); }); + + describe('recognizedFields', () => { + test('parse field clauses from a query only for recognized fields', () => { + const query = 'remote:test type:dataview happiness'; + const ast = defaultSyntax.parse(query, { + recognizedFields: ['tag', 'type'], + }); + expect(ast).toBeDefined(); + expect(ast.clauses).toHaveLength(3); + expect(ast.getFieldClauses()).toMatchObject([ + { field: 'type', match: 'must', value: 'dataview' }, + ]); + expect(ast.getTermClauses()).toEqual([ + { match: 'must', type: 'term', value: 'remote:test' }, + { match: 'must', type: 'term', value: 'happiness' }, + ]); + + const printedQuery = defaultSyntax.print(ast); + expect(printedQuery).toBe('remote\\:test type:dataview happiness'); + }); + + test('combined with "is" clause', () => { + const query = 'remote:test is:pending'; + const ast = defaultSyntax.parse(query, { + recognizedFields: ['tag', 'type'], + }); + expect(ast).toBeDefined(); + expect(ast.clauses).toHaveLength(2); + expect(ast.getFieldClauses()).toHaveLength(0); + expect(ast.getIsClauses()).toEqual([ + { flag: 'pending', match: 'must', type: 'is' }, + ]); + expect(ast.getTermClauses()).toEqual([ + { match: 'must', type: 'term', value: 'remote:test' }, + ]); + + const printedQuery = defaultSyntax.print(ast); + expect(printedQuery).toBe('remote\\:test is:pending'); + }); + + test('parse complex terms from a query', () => { + const query = + 'my-remote-cluster:my-remote-index type:data-view tag:really-nice-content'; + const ast = defaultSyntax.parse(query, { + recognizedFields: ['tag', 'type'], + }); + expect(ast).toBeDefined(); + expect(ast.clauses).toHaveLength(3); + expect(ast.getFieldClauses()).toMatchObject([ + { field: 'type', match: 'must', value: 'data-view' }, + { field: 'tag', match: 'must', value: 'really-nice-content' }, + ]); + expect(ast.getTermClauses()).toEqual([ + { + match: 'must', + type: 'term', + value: 'my-remote-cluster:my-remote-index', + }, + ]); + + const printedQuery = defaultSyntax.print(ast); + expect(printedQuery).toBe( + 'my\\-remote\\-cluster\\:my\\-remote\\-index type:data-view tag:really-nice-content' + ); + }); + }); }); diff --git a/packages/eui/src/components/search_bar/query/default_syntax.ts b/packages/eui/src/components/search_bar/query/default_syntax.ts index fb1abda17fb4..9692811bbd22 100644 --- a/packages/eui/src/components/search_bar/query/default_syntax.ts +++ b/packages/eui/src/components/search_bar/query/default_syntax.ts @@ -15,7 +15,8 @@ import peg from 'pegjs-inline-precompile'; // eslint-disable-line import/no-unre const parser = peg` { - const { AST, Exp, unescapeValue, unescapePhraseValue, resolveFieldValue } = options; + const { AST, Exp, unescapeValue, unescapePhraseValue, resolveFieldValue, recognizedFields } = options; + const hasRecognizedFields = recognizedFields && recognizedFields.length > 0; const ctx = Object.assign({ error }, options ); } @@ -108,8 +109,9 @@ FieldLTEValue flagName "flag name" = identifier +// If recognizedFields was given in options, the identifier must match an allowed field fieldName "field name" - = identifier + = id:identifier &{ return !hasRecognizedFields || recognizedFields.includes(id); } { return id; } identifier = identifierChar+ { return unescapeValue(text()); } @@ -257,6 +259,7 @@ interface ValueExpression { export interface ParseOptions { dateFormat?: any; schema?: any; + recognizedFields?: string[]; escapeValue?: (value: any) => string; } @@ -493,6 +496,7 @@ export const defaultSyntax: Syntax = Object.freeze({ const dateFormat = options.dateFormat || defaultDateFormat; const parseDate = dateValueParser(dateFormat); const schema = options.schema || {}; + const recognizedFields = options.recognizedFields; const clauses = parser.parse(query, { AST, Exp, @@ -502,6 +506,7 @@ export const defaultSyntax: Syntax = Object.freeze({ resolveFieldValue, validateFlag, schema: { strict: false, flags: [], fields: {}, ...schema }, + recognizedFields, }); return AST.create(clauses); },