Skip to content

Commit

Permalink
Kuery/KQL: Support not passing an index pattern (elastic#28010)
Browse files Browse the repository at this point in the history
* Support not sending index pattern to Kuery functions

* fix match all inside is
  • Loading branch information
lukasolson authored and markov00 committed Jan 7, 2019
1 parent 90b202c commit f458405
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 7 deletions.
2 changes: 2 additions & 0 deletions packages/kbn-es-query/src/kuery/ast/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ function fromExpression(expression, parseOptions = {}, parse = parseKuery) {
return parse(expression, parseOptions);
}

// indexPattern isn't required, but if you pass one in, we can be more intelligent
// about how we craft the queries (e.g. scripted fields)
export function toElasticsearchQuery(node, indexPattern) {
if (!node || !node.type || !nodeTypes[node.type]) {
return toElasticsearchQuery(nodeTypes.function.buildNode('and', []));
Expand Down
11 changes: 10 additions & 1 deletion packages/kbn-es-query/src/kuery/functions/__tests__/exists.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,21 @@ describe('kuery functions', function () {
expect(_.isEqual(expected, result)).to.be(true);
});

it('should return an ES exists query without an index pattern', function () {
const expected = {
exists: { field: 'response' }
};

const existsNode = nodeTypes.function.buildNode('exists', 'response');
const result = exists.toElasticsearchQuery(existsNode);
expect(_.isEqual(expected, result)).to.be(true);
});

it('should throw an error for scripted fields', function () {
const existsNode = nodeTypes.function.buildNode('exists', 'script string');
expect(exists.toElasticsearchQuery)
.withArgs(existsNode, indexPattern).to.throwException(/Exists query does not support scripted fields/);
});

});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ describe('kuery functions', function () {
expect(result.geo_bounding_box.geo).to.have.property('bottom_right', '50.73, -135.35');
});

it('should return an ES geo_bounding_box query without an index pattern', function () {
const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params);
const result = geoBoundingBox.toElasticsearchQuery(node);
expect(result).to.have.property('geo_bounding_box');
expect(result.geo_bounding_box.geo).to.have.property('top_left', '73.12, -174.37');
expect(result.geo_bounding_box.geo).to.have.property('bottom_right', '50.73, -135.35');
});

it('should use the ignore_unmapped parameter', function () {
const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params);
const result = geoBoundingBox.toElasticsearchQuery(node, indexPattern);
Expand Down
11 changes: 11 additions & 0 deletions packages/kbn-es-query/src/kuery/functions/__tests__/geo_polygon.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ describe('kuery functions', function () {
});
});

it('should return an ES geo_polygon query without an index pattern', function () {
const node = nodeTypes.function.buildNode('geoPolygon', 'geo', points);
const result = geoPolygon.toElasticsearchQuery(node);
expect(result).to.have.property('geo_polygon');
expect(result.geo_polygon.geo).to.have.property('points');

result.geo_polygon.geo.points.forEach((point, index) => {
const expectedLatLon = `${points[index].lat}, ${points[index].lon}`;
expect(point).to.be(expectedLatLon);
});
});

it('should use the ignore_unmapped parameter', function () {
const node = nodeTypes.function.buildNode('geoPolygon', 'geo', points);
Expand Down
15 changes: 15 additions & 0 deletions packages/kbn-es-query/src/kuery/functions/__tests__/is.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,21 @@ describe('kuery functions', function () {
expect(result).to.eql(expected);
});

it('should return an ES match query when a concrete fieldName and value are provided without an index pattern', function () {
const expected = {
bool: {
should: [
{ match: { extension: 'jpg' } },
],
minimum_should_match: 1
}
};

const node = nodeTypes.function.buildNode('is', 'extension', 'jpg');
const result = is.toElasticsearchQuery(node);
expect(result).to.eql(expected);
});

it('should support creation of phrase queries', function () {
const expected = {
bool: {
Expand Down
22 changes: 22 additions & 0 deletions packages/kbn-es-query/src/kuery/functions/__tests__/range.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,28 @@ describe('kuery functions', function () {
expect(result).to.eql(expected);
});

it('should return an ES range query without an index pattern', function () {
const expected = {
bool: {
should: [
{
range: {
bytes: {
gt: 1000,
lt: 8000
}
}
}
],
minimum_should_match: 1
}
};

const node = nodeTypes.function.buildNode('range', 'bytes', { gt: 1000, lt: 8000 });
const result = range.toElasticsearchQuery(node);
expect(result).to.eql(expected);
});

it('should support wildcard field names', function () {
const expected = {
bool: {
Expand Down
3 changes: 2 additions & 1 deletion packages/kbn-es-query/src/kuery/functions/exists.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/

import { get } from 'lodash';
import * as literal from '../node_types/literal';

export function buildNodeParams(fieldName) {
Expand All @@ -28,7 +29,7 @@ export function buildNodeParams(fieldName) {
export function toElasticsearchQuery(node, indexPattern) {
const { arguments: [ fieldNameArg ] } = node;
const fieldName = literal.toElasticsearchQuery(fieldNameArg);
const field = indexPattern.fields.find(field => field.name === fieldName);
const field = get(indexPattern, 'fields', []).find(field => field.name === fieldName);

if (field && field.scripted) {
throw new Error(`Exists query does not support scripted fields`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function buildNodeParams(fieldName, params) {
export function toElasticsearchQuery(node, indexPattern) {
const [ fieldNameArg, ...args ] = node.arguments;
const fieldName = nodeTypes.literal.toElasticsearchQuery(fieldNameArg);
const field = indexPattern.fields.find(field => field.name === fieldName);
const field = _.get(indexPattern, 'fields', []).find(field => field.name === fieldName);
const queryParams = args.reduce((acc, arg) => {
const snakeArgName = _.snakeCase(arg.name);
return {
Expand Down
3 changes: 2 additions & 1 deletion packages/kbn-es-query/src/kuery/functions/geo_polygon.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/

import { get } from 'lodash';
import { nodeTypes } from '../node_types';
import * as ast from '../ast';

Expand All @@ -35,7 +36,7 @@ export function buildNodeParams(fieldName, points) {
export function toElasticsearchQuery(node, indexPattern) {
const [ fieldNameArg, ...points ] = node.arguments;
const fieldName = nodeTypes.literal.toElasticsearchQuery(fieldNameArg);
const field = indexPattern.fields.find(field => field.name === fieldName);
const field = get(indexPattern, 'fields', []).find(field => field.name === fieldName);
const queryParams = {
points: points.map(ast.toElasticsearchQuery)
};
Expand Down
8 changes: 6 additions & 2 deletions packages/kbn-es-query/src/kuery/functions/is.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function buildNodeParams(fieldName, value, isPhrase = false) {
export function toElasticsearchQuery(node, indexPattern) {
const { arguments: [ fieldNameArg, valueArg, isPhraseArg ] } = node;

const fieldName = ast.toElasticsearchQuery(fieldNameArg);
const value = !_.isUndefined(valueArg) ? ast.toElasticsearchQuery(valueArg) : valueArg;
const type = isPhraseArg.value ? 'phrase' : 'best_fields';

Expand All @@ -65,7 +66,7 @@ export function toElasticsearchQuery(node, indexPattern) {
};
}

const fields = getFields(fieldNameArg, indexPattern);
const fields = indexPattern ? getFields(fieldNameArg, indexPattern) : [];

// If no fields are found in the index pattern we send through the given field name as-is. We do this to preserve
// the behaviour of lucene on dashboards where there are panels based on different index patterns that have different
Expand All @@ -80,7 +81,10 @@ export function toElasticsearchQuery(node, indexPattern) {
}

const isExistsQuery = valueArg.type === 'wildcard' && value === '*';
const isMatchAllQuery = isExistsQuery && fields && fields.length === indexPattern.fields.length;
const isAllFieldsQuery =
(fieldNameArg.type === 'wildcard' && fieldName === '*')
|| (fields && indexPattern && fields.length === indexPattern.fields.length);
const isMatchAllQuery = isExistsQuery && isAllFieldsQuery;

if (isMatchAllQuery) {
return { match_all: {} };
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-es-query/src/kuery/functions/range.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function buildNodeParams(fieldName, params) {

export function toElasticsearchQuery(node, indexPattern) {
const [ fieldNameArg, ...args ] = node.arguments;
const fields = getFields(fieldNameArg, indexPattern);
const fields = indexPattern ? getFields(fieldNameArg, indexPattern) : [];
const namedArgs = extractArguments(args);
const queryParams = _.mapValues(namedArgs, ast.toElasticsearchQuery);

Expand Down

0 comments on commit f458405

Please sign in to comment.