Skip to content

Commit

Permalink
Allow EuiSearchBar group clauses to be negated (#2140)
Browse files Browse the repository at this point in the history
* Allow EuiSearchBar group clauses to be negated

* changelog
  • Loading branch information
chandlerprall authored Jul 18, 2019
1 parent 8ffeb53 commit eb9cce0
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- Added support for negated or clauses to `EuiSearchBar` ([#2140](https://github.com/elastic/eui/pull/2140))

**Bug fixes**

- Fixed `EuiComboBox`'s padding on the right ([#2135](https://github.com/elastic/eui/pull/2135))
Expand Down
3 changes: 3 additions & 0 deletions src/components/search_bar/query/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ const Group = Object.freeze({
must: value => {
return { type: Group.TYPE, value, match: Match.MUST };
},
mustNot: value => {
return { type: Group.TYPE, value, match: Match.MUST_NOT };
},
});

const Field = Object.freeze({
Expand Down
12 changes: 8 additions & 4 deletions src/components/search_bar/query/default_syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ Clauses
}
Clause
= IsClause
= GroupClause
/ IsClause
/ FieldClause
/ TermClause
/ GroupClause
GroupClause
SubGroupClause
= "(" head:Clause tail:(
space? orWord space? clause:Clause { return clause }
)* ")" {
return AST.Group.must([head, ...tail]);
return [head, ...tail];
}
GroupClause
= space? "-" group:SubGroupClause { return AST.Group.mustNot(group) }
/ space? group:SubGroupClause { return AST.Group.must(group) }
TermClause
= space? "-" value:termValue { return AST.Term.mustNot(value); }
/ space? value:termValue { return AST.Term.must(value); }
Expand Down
36 changes: 36 additions & 0 deletions src/components/search_bar/query/default_syntax.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,42 @@ describe('defaultSyntax', () => {
expect(nameClauseB.value).toBe('susan');
});

test('negated OR clause', () => {
const query = '-(name:john OR name:susan)';
const schema = {
strict: true,
fields: {
name: {
type: 'string',
},
},
};
const ast = defaultSyntax.parse(query, { schema });

expect(ast).toBeDefined();
expect(ast.clauses).toHaveLength(1);

const groupClauses = ast.getGroupClauses();
expect(groupClauses).toHaveLength(1);

const [groupClause] = groupClauses;
expect(groupClause).toBeDefined();
expect(AST.Group.isInstance(groupClause)).toBe(true);
expect(AST.Match.isMustClause(groupClause)).toBe(false);

const [nameClauseA, nameClauseB] = groupClause.value;

expect(AST.Field.isInstance(nameClauseA)).toBe(true);
expect(AST.Match.isMustClause(nameClauseA)).toBe(true);
expect(nameClauseA.field).toBe('name');
expect(nameClauseA.value).toBe('john');

expect(AST.Field.isInstance(nameClauseB)).toBe(true);
expect(AST.Match.isMustClause(nameClauseB)).toBe(true);
expect(nameClauseB.field).toBe('name');
expect(nameClauseB.value).toBe('susan');
});

test('or term parsing and printing', () => {
const query = '"or"';
const ast = defaultSyntax.parse(query);
Expand Down
2 changes: 1 addition & 1 deletion src/components/search_bar/query/execute_ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export const createFilter = (
}
throw new Error(`Unknown query clause type in group, [${clause.type}]`);
});
return matchesGroup;
return AST.Match.isMustClause(clause) ? matchesGroup : !matchesGroup;
});

return isGroupMatch;
Expand Down
21 changes: 21 additions & 0 deletions src/components/search_bar/query/execute_ast.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,27 @@ describe('execute ast', () => {
expect(names).toContain('foo bar');
});

test('negated OR clause', () => {
const items = [
{ name: 'john doe', age: 9 },
{ name: 'foo', age: 6 },
{ name: 'foo bar', age: 7 },
{ name: 'bar', age: 8 },
];
const result = executeAst(
AST.create([
AST.Group.mustNot([
AST.Field.must.eq('name', 'john doe'),
AST.Field.must.eq('name', 'foo'),
]),
]),
items
);
expect(result).toHaveLength(1);
const names = result.map(item => item.name);
expect(names).toContain('bar');
});

describe('array field values', () => {
describe('eq operator', () => {
test('full match', () => {
Expand Down

0 comments on commit eb9cce0

Please sign in to comment.