Skip to content

Commit

Permalink
[Search Bar/Query/Default Syntax] Support for allowedFields in parse …
Browse files Browse the repository at this point in the history
…options
  • Loading branch information
tsullivan committed Aug 13, 2024
1 parent d4dc2f6 commit 7d7f01a
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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'
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
Expand Down Expand Up @@ -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()); }
Expand Down Expand Up @@ -257,6 +259,7 @@ interface ValueExpression {
export interface ParseOptions {
dateFormat?: any;
schema?: any;
recognizedFields?: string[];
escapeValue?: (value: any) => string;
}

Expand Down Expand Up @@ -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,
Expand All @@ -502,6 +506,7 @@ export const defaultSyntax: Syntax = Object.freeze({
resolveFieldValue,
validateFlag,
schema: { strict: false, flags: [], fields: {}, ...schema },
recognizedFields,
});
return AST.create(clauses);
},
Expand Down
15 changes: 12 additions & 3 deletions packages/eui/src/components/search_bar/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ export interface EuiSearchBarProps extends CommonProps {
// components can use e.g. a true value to mean "auto-derive a schema". See EuiInMemoryTable.
// Admittedly, this is a bit of a hack.
schema?: SchemaType | boolean;

// Controls which phrases will be parsed as field clauses
recognizedFields?: string[];
};

/**
Expand Down Expand Up @@ -123,11 +126,17 @@ const parseQuery = (
props: EuiSearchBarProps
): Query => {
let schema: SchemaType | undefined = undefined;
if (props.box && props.box.schema && typeof props.box.schema === 'object') {
schema = props.box.schema;
let recognizedFields: string[] | undefined;
if (props.box) {
if (props.box.schema && typeof props.box.schema === 'object') {
schema = props.box.schema;
}
if (props.box.recognizedFields) {
recognizedFields = props.box.recognizedFields;
}
}
const dateFormat = props.dateFormat;
const parseOptions = { schema, dateFormat };
const parseOptions = { schema, dateFormat, recognizedFields };
if (!query) {
return Query.parse('', parseOptions);
}
Expand Down

0 comments on commit 7d7f01a

Please sign in to comment.