Skip to content

Commit

Permalink
[Data][Es Query] Use ES types in Kuery functions (#108367)
Browse files Browse the repository at this point in the history
* es-query types

* jest and lint

* cc

* options

* type

* types for kuery FUNCTIONS

* doc

* sec fixes

* typey type

* test typescript

* test

* fixes

* test

* cr

* cleanup a bit more

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
lizozom and kibanamachine authored Aug 17, 2021
1 parent e258f46 commit 9d1a8a8
Show file tree
Hide file tree
Showing 56 changed files with 298 additions and 250 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
esKuery: {
nodeTypes: import("@kbn/es-query/target_types/kuery/node_types").NodeTypes;
fromKueryExpression: (expression: string | import("@elastic/elasticsearch/api/types").QueryDslQueryContainer, parseOptions?: Partial<import("@kbn/es-query/target_types/kuery/types").KueryParseOptions> | undefined) => import("@kbn/es-query").KueryNode;
toElasticsearchQuery: (node: import("@kbn/es-query").KueryNode, indexPattern?: import("@kbn/es-query").IndexPatternBase | undefined, config?: Record<string, any> | undefined, context?: Record<string, any> | undefined) => import("@kbn/utility-types").JsonObject;
toElasticsearchQuery: (node: import("@kbn/es-query").KueryNode, indexPattern?: import("@kbn/es-query").IndexPatternBase | undefined, config?: import("@kbn/es-query").KueryQueryOptions | undefined, context?: Record<string, any> | undefined) => import("@elastic/elasticsearch/api/types").QueryDslQueryContainer;
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
esKuery: {
nodeTypes: import("@kbn/es-query/target_types/kuery/node_types").NodeTypes;
fromKueryExpression: (expression: string | import("@elastic/elasticsearch/api/types").QueryDslQueryContainer, parseOptions?: Partial<import("@kbn/es-query/target_types/kuery/types").KueryParseOptions> | undefined) => import("@kbn/es-query").KueryNode;
toElasticsearchQuery: (node: import("@kbn/es-query").KueryNode, indexPattern?: import("@kbn/es-query").IndexPatternBase | undefined, config?: Record<string, any> | undefined, context?: Record<string, any> | undefined) => import("@kbn/utility-types").JsonObject;
toElasticsearchQuery: (node: import("@kbn/es-query").KueryNode, indexPattern?: import("@kbn/es-query").IndexPatternBase | undefined, config?: import("@kbn/es-query").KueryQueryOptions | undefined, context?: Record<string, any> | undefined) => import("@elastic/elasticsearch/api/types").QueryDslQueryContainer;
}
```
2 changes: 1 addition & 1 deletion packages/kbn-es-query/src/es_query/from_kuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function buildQuery(
indexPattern: IndexPatternBase | undefined,
queryASTs: KueryNode[],
config: SerializableRecord = {}
) {
): BoolQuery {
const compoundQueryAST = nodeTypes.function.buildNode('and', queryASTs);
const kueryQuery = toElasticsearchQuery(compoundQueryAST, indexPattern, config);

Expand Down
7 changes: 4 additions & 3 deletions packages/kbn-es-query/src/kuery/ast/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { JsonObject } from '@kbn/utility-types';
import { estypes } from '@elastic/elasticsearch';
import { nodeTypes } from '../node_types/index';
import { KQLSyntaxError } from '../kuery_syntax_error';
import { KueryNode, KueryParseOptions } from '../types';
import { KueryNode, KueryParseOptions, KueryQueryOptions } from '../types';

import { parse as parseKuery } from '../grammar';
import { IndexPatternBase } from '../..';
Expand Down Expand Up @@ -62,18 +62,19 @@ export const fromKueryExpression = (
*
* 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 const toElasticsearchQuery = (
node: KueryNode,
indexPattern?: IndexPatternBase,
config?: Record<string, any>,
config: KueryQueryOptions = {},
context?: Record<string, any>
): JsonObject => {
if (!node || !node.type || !nodeTypes[node.type]) {
return toElasticsearchQuery(nodeTypes.function.buildNode('and', []), indexPattern);
}

// TODO: the return type of this function might be incorrect and it works only because of this casting
const nodeType = (nodeTypes[node.type] as unknown) as any;

return nodeType.toElasticsearchQuery(node, indexPattern, config, context);
};
9 changes: 5 additions & 4 deletions packages/kbn-es-query/src/kuery/functions/exists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
* Side Public License, v 1.
*/

import { IndexPatternFieldBase, IndexPatternBase, KueryNode } from '../..';
import { estypes } from '@elastic/elasticsearch';
import { IndexPatternFieldBase, IndexPatternBase, KueryNode, KueryQueryOptions } from '../..';
import * as literal from '../node_types/literal';

export function buildNodeParams(fieldName: string) {
Expand All @@ -18,17 +19,17 @@ export function buildNodeParams(fieldName: string) {
export function toElasticsearchQuery(
node: KueryNode,
indexPattern?: IndexPatternBase,
config: Record<string, any> = {},
config: KueryQueryOptions = {},
context: Record<string, any> = {}
) {
): estypes.QueryDslQueryContainer {
const {
arguments: [fieldNameArg],
} = node;
const fullFieldNameArg = {
...fieldNameArg,
value: context?.nested ? `${context.nested.path}.${fieldNameArg.value}` : fieldNameArg.value,
};
const fieldName = literal.toElasticsearchQuery(fullFieldNameArg);
const fieldName = literal.toElasticsearchQuery(fullFieldNameArg) as string;
const field = indexPattern?.fields?.find((fld: IndexPatternFieldBase) => fld.name === fieldName);

if (field?.scripted) {
Expand Down
25 changes: 19 additions & 6 deletions packages/kbn-es-query/src/kuery/functions/geo_bounding_box.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { fields } from '../../filters/stubs';
import { IndexPatternBase } from '../..';

import * as geoBoundingBox from './geo_bounding_box';
import { JsonObject } from '@kbn/utility-types';

jest.mock('../grammar');

Expand Down Expand Up @@ -78,24 +79,36 @@ describe('kuery functions', () => {
const result = geoBoundingBox.toElasticsearchQuery(node, indexPattern);

expect(result).toHaveProperty('geo_bounding_box');
expect(result.geo_bounding_box.geo).toHaveProperty('top_left', '73.12, -174.37');
expect(result.geo_bounding_box.geo).toHaveProperty('bottom_right', '50.73, -135.35');
expect((result.geo_bounding_box as JsonObject).geo).toHaveProperty(
'top_left',
'73.12, -174.37'
);
expect((result.geo_bounding_box as JsonObject).geo).toHaveProperty(
'bottom_right',
'50.73, -135.35'
);
});

test('should return an ES geo_bounding_box query without an index pattern', () => {
const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params);
const result = geoBoundingBox.toElasticsearchQuery(node);

expect(result).toHaveProperty('geo_bounding_box');
expect(result.geo_bounding_box.geo).toHaveProperty('top_left', '73.12, -174.37');
expect(result.geo_bounding_box.geo).toHaveProperty('bottom_right', '50.73, -135.35');
expect((result.geo_bounding_box as JsonObject).geo).toHaveProperty(
'top_left',
'73.12, -174.37'
);
expect((result.geo_bounding_box as JsonObject).geo).toHaveProperty(
'bottom_right',
'50.73, -135.35'
);
});

test('should use the ignore_unmapped parameter', () => {
const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params);
const result = geoBoundingBox.toElasticsearchQuery(node, indexPattern);

expect(result.geo_bounding_box.ignore_unmapped).toBe(true);
expect(result.geo_bounding_box!.ignore_unmapped).toBe(true);
});

test('should throw an error for scripted fields', () => {
Expand All @@ -116,7 +129,7 @@ describe('kuery functions', () => {
);

expect(result).toHaveProperty('geo_bounding_box');
expect(result.geo_bounding_box['nestedField.geo']).toBeDefined();
expect((result.geo_bounding_box as JsonObject)['nestedField.geo']).toBeDefined();
});
});
});
Expand Down
7 changes: 4 additions & 3 deletions packages/kbn-es-query/src/kuery/functions/geo_bounding_box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
*/

import _ from 'lodash';
import { estypes } from '@elastic/elasticsearch';
import { nodeTypes } from '../node_types';
import * as ast from '../ast';
import { IndexPatternBase, KueryNode, LatLon } from '../..';
import { IndexPatternBase, KueryNode, KueryQueryOptions, LatLon } from '../..';

export function buildNodeParams(fieldName: string, params: any) {
params = _.pick(params, 'topLeft', 'bottomRight');
Expand All @@ -27,9 +28,9 @@ export function buildNodeParams(fieldName: string, params: any) {
export function toElasticsearchQuery(
node: KueryNode,
indexPattern?: IndexPatternBase,
config: Record<string, any> = {},
config: KueryQueryOptions = {},
context: Record<string, any> = {}
) {
): estypes.QueryDslQueryContainer {
const [fieldNameArg, ...args] = node.arguments;
const fullFieldNameArg = {
...fieldNameArg,
Expand Down
12 changes: 6 additions & 6 deletions packages/kbn-es-query/src/kuery/functions/geo_polygon.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ describe('kuery functions', () => {
const result = geoPolygon.toElasticsearchQuery(node, indexPattern);

expect(result).toHaveProperty('geo_polygon');
expect(result.geo_polygon.geo).toHaveProperty('points');
expect((result.geo_polygon as any).geo).toHaveProperty('points');

(result.geo_polygon.geo as any).points.forEach((point: any, index: number) => {
(result.geo_polygon as any).geo.points.forEach((point: any, index: number) => {
const expectedLatLon = `${points[index].lat}, ${points[index].lon}`;

expect(point).toBe(expectedLatLon);
Expand All @@ -93,9 +93,9 @@ describe('kuery functions', () => {
const result = geoPolygon.toElasticsearchQuery(node);

expect(result).toHaveProperty('geo_polygon');
expect(result.geo_polygon.geo).toHaveProperty('points');
expect((result.geo_polygon as any).geo).toHaveProperty('points');

(result.geo_polygon.geo as any).points.forEach((point: any, index: number) => {
(result.geo_polygon as any).geo.points.forEach((point: any, index: number) => {
const expectedLatLon = `${points[index].lat}, ${points[index].lon}`;

expect(point).toBe(expectedLatLon);
Expand All @@ -106,7 +106,7 @@ describe('kuery functions', () => {
const node = nodeTypes.function.buildNode('geoPolygon', 'geo', points);
const result = geoPolygon.toElasticsearchQuery(node, indexPattern);

expect(result.geo_polygon.ignore_unmapped).toBe(true);
expect((result.geo_polygon as any).ignore_unmapped).toBe(true);
});

test('should throw an error for scripted fields', () => {
Expand All @@ -126,7 +126,7 @@ describe('kuery functions', () => {
);

expect(result).toHaveProperty('geo_polygon');
expect(result.geo_polygon['nestedField.geo']).toBeDefined();
expect((result.geo_polygon as any)['nestedField.geo']).toBeDefined();
});
});
});
Expand Down
7 changes: 4 additions & 3 deletions packages/kbn-es-query/src/kuery/functions/geo_polygon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
* Side Public License, v 1.
*/

import { estypes } from '@elastic/elasticsearch';
import { nodeTypes } from '../node_types';
import * as ast from '../ast';
import { IndexPatternBase, KueryNode, LatLon } from '../..';
import { IndexPatternBase, KueryNode, KueryQueryOptions, LatLon } from '../..';
import { LiteralTypeBuildNode } from '../node_types/types';

export function buildNodeParams(fieldName: string, points: LatLon[]) {
Expand All @@ -26,9 +27,9 @@ export function buildNodeParams(fieldName: string, points: LatLon[]) {
export function toElasticsearchQuery(
node: KueryNode,
indexPattern?: IndexPatternBase,
config: Record<string, any> = {},
config: KueryQueryOptions = {},
context: Record<string, any> = {}
) {
): estypes.QueryDslQueryContainer {
const [fieldNameArg, ...points] = node.arguments;
const fullFieldNameArg = {
...fieldNameArg,
Expand Down
9 changes: 7 additions & 2 deletions packages/kbn-es-query/src/kuery/functions/is.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { fields } from '../../filters/stubs';

import * as is from './is';
import { IndexPatternBase } from '../..';
import { estypes } from '@elastic/elasticsearch';

jest.mock('../grammar');

Expand Down Expand Up @@ -125,7 +126,9 @@ describe('kuery functions', () => {
const result = is.toElasticsearchQuery(node, indexPattern);

expect(result).toHaveProperty('bool');
expect(result.bool!.should!.length).toBe(indexPattern.fields.length);
expect((result.bool!.should! as estypes.QueryDslQueryContainer[]).length).toBe(
indexPattern.fields.length
);
});

test('should return an ES exists query when value is "*"', () => {
Expand Down Expand Up @@ -204,7 +207,9 @@ describe('kuery functions', () => {
const node = nodeTypes.function.buildNode('is', 'script string', 'foo');
const result = is.toElasticsearchQuery(node, indexPattern);

expect(result.bool!.should![0]).toHaveProperty('script');
expect((result.bool!.should as estypes.QueryDslQueryContainer[])[0]).toHaveProperty(
'script'
);
});

test('should support date fields without a dateFormat provided', () => {
Expand Down
9 changes: 5 additions & 4 deletions packages/kbn-es-query/src/kuery/functions/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
*/

import { get, isUndefined } from 'lodash';
import { estypes } from '@elastic/elasticsearch';
import { getPhraseScript } from '../../filters';
import { getFields } from './utils/get_fields';
import { getTimeZoneFromSettings } from '../../utils';
import { getFullFieldNameNode } from './utils/get_full_field_name_node';
import { IndexPatternBase, KueryNode, IndexPatternFieldBase } from '../..';
import { IndexPatternBase, KueryNode, IndexPatternFieldBase, KueryQueryOptions } from '../..';

import * as ast from '../ast';

Expand Down Expand Up @@ -40,9 +41,9 @@ export function buildNodeParams(fieldName: string, value: any, isPhrase: boolean
export function toElasticsearchQuery(
node: KueryNode,
indexPattern?: IndexPatternBase,
config: Record<string, any> = {},
config: KueryQueryOptions = {},
context: Record<string, any> = {}
) {
): estypes.QueryDslQueryContainer {
const {
arguments: [fieldNameArg, valueArg, isPhraseArg],
} = node;
Expand Down Expand Up @@ -75,7 +76,7 @@ export function toElasticsearchQuery(
return {
multi_match: {
type,
query: value,
query: (value as unknown) as string,
lenient: true,
},
};
Expand Down
6 changes: 3 additions & 3 deletions packages/kbn-es-query/src/kuery/functions/nested.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ describe('kuery functions', () => {
expect(result).toHaveProperty('nested');
expect(Object.keys(result).length).toBe(1);

expect(result.nested.path).toBe('nestedField');
expect(result.nested.score_mode).toBe('none');
expect(result.nested?.path).toBe('nestedField');
expect(result.nested?.score_mode).toBe('none');
});

test('should pass the nested path to subqueries so the full field name can be used', () => {
Expand All @@ -59,7 +59,7 @@ describe('kuery functions', () => {
nodeTypes.function.buildNode('is', 'nestedField.child', 'foo')
);

expect(result.nested.query).toEqual(expectedSubQuery);
expect(result.nested!.query).toEqual(expectedSubQuery);
});
});
});
Expand Down
11 changes: 6 additions & 5 deletions packages/kbn-es-query/src/kuery/functions/nested.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
* Side Public License, v 1.
*/

import { estypes } from '@elastic/elasticsearch';
import * as ast from '../ast';
import * as literal from '../node_types/literal';
import { IndexPatternBase, KueryNode } from '../..';
import { IndexPatternBase, KueryNode, KueryQueryOptions } from '../..';

export function buildNodeParams(path: any, child: any) {
const pathNode =
Expand All @@ -21,11 +22,11 @@ export function buildNodeParams(path: any, child: any) {
export function toElasticsearchQuery(
node: KueryNode,
indexPattern?: IndexPatternBase,
config: Record<string, any> = {},
config: KueryQueryOptions = {},
context: Record<string, any> = {}
) {
): estypes.QueryDslQueryContainer {
const [path, child] = node.arguments;
const stringPath = ast.toElasticsearchQuery(path);
const stringPath = (ast.toElasticsearchQuery(path) as unknown) as string;
const fullPath = context?.nested?.path ? `${context.nested.path}.${stringPath}` : stringPath;

return {
Expand All @@ -34,7 +35,7 @@ export function toElasticsearchQuery(
query: ast.toElasticsearchQuery(child, indexPattern, config, {
...context,
nested: { path: fullPath },
}),
}) as estypes.QueryDslQueryContainer,
score_mode: 'none',
},
};
Expand Down
4 changes: 2 additions & 2 deletions packages/kbn-es-query/src/kuery/functions/not.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ describe('kuery functions', () => {
expect(Object.keys(result).length).toBe(1);

expect(result.bool).toHaveProperty('must_not');
expect(Object.keys(result.bool).length).toBe(1);
expect(Object.keys(result.bool!).length).toBe(1);

expect(result.bool.must_not).toEqual(ast.toElasticsearchQuery(childNode, indexPattern));
expect(result.bool!.must_not).toEqual(ast.toElasticsearchQuery(childNode, indexPattern));
});
});
});
Expand Down
Loading

0 comments on commit 9d1a8a8

Please sign in to comment.