diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.test.ts new file mode 100644 index 0000000000000..83271d492718b --- /dev/null +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.test.ts @@ -0,0 +1,439 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { query } from './query'; + +import type { + AnnotationsRequestProcessorsFunction, + AnnotationsRequestProcessorsParams, +} from './types'; +import { DefaultSearchCapabilities } from '../../../search_strategies/capabilities/default_search_capabilities'; + +describe('query', () => { + let req: AnnotationsRequestProcessorsParams['req']; + let panel: AnnotationsRequestProcessorsParams['panel']; + let annotation: AnnotationsRequestProcessorsParams['annotation']; + let esQueryConfig: AnnotationsRequestProcessorsParams['esQueryConfig']; + let annotationIndex: AnnotationsRequestProcessorsParams['annotationIndex']; + let capabilities: AnnotationsRequestProcessorsParams['capabilities']; + let uiSettings: AnnotationsRequestProcessorsParams['uiSettings']; + + const next = jest.fn((x) => x) as unknown as ReturnType< + ReturnType + >; + + beforeEach(() => { + req = { + body: { + timerange: { + timezone: 'Europe/Minsk', + min: '2022-01-29T22:03:02.317Z', + max: '2022-02-07T09:00:00.000Z', + }, + }, + } as AnnotationsRequestProcessorsParams['req']; + panel = {} as AnnotationsRequestProcessorsParams['panel']; + annotation = { + time_field: 'fooField', + } as AnnotationsRequestProcessorsParams['annotation']; + annotationIndex = { + indexPattern: undefined, + indexPatternString: 'foo*', + }; + capabilities = { + getValidTimeInterval: jest.fn((x) => x), + } as unknown as DefaultSearchCapabilities; + uiSettings = { + get: jest.fn().mockResolvedValue(100), + } as unknown as AnnotationsRequestProcessorsParams['uiSettings']; + }); + + test('should set "size" to 0', async () => { + const doc = await query({ + req, + panel, + annotation, + esQueryConfig, + annotationIndex, + capabilities, + uiSettings, + } as AnnotationsRequestProcessorsParams)(next)({}); + + expect(doc.size).toBe(0); + }); + + test('should apply global query (Lucene)', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'lucene', + }, + ]; + + annotation.ignore_global_filters = 0; + + const doc = await query({ + req, + panel, + annotation, + esQueryConfig, + annotationIndex, + capabilities, + uiSettings, + } as AnnotationsRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [], + "must": Array [ + Object { + "query_string": Object { + "query": "hour_of_day : 1", + }, + }, + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T08:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should apply global query (KQL)', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'kuery', + }, + ]; + + annotation.ignore_global_filters = 0; + + const doc = await query({ + req, + panel, + annotation, + esQueryConfig, + annotationIndex, + capabilities, + uiSettings, + } as AnnotationsRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "hour_of_day": "1", + }, + }, + ], + }, + }, + ], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T08:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should apply global filters', async () => { + req.body.filters = [ + { + meta: { + index: '90943e30-9a47-11e8-b64d-95841ca0b247', + alias: null, + negate: false, + disabled: false, + type: 'exists', + key: 'referer', + value: 'exists', + }, + query: { + exists: { + field: 'referer', + }, + }, + }, + ]; + + annotation.ignore_global_filters = 0; + + const doc = await query({ + req, + panel, + annotation, + esQueryConfig, + annotationIndex, + capabilities, + uiSettings, + } as AnnotationsRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "referer", + }, + }, + ], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T08:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should add panel filters and merge it with global one', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'kuery', + }, + ]; + + panel.filter = { + query: 'agent : 2', + language: 'kuery', + }; + + annotation.ignore_global_filters = 0; + annotation.ignore_panel_filters = 0; + + const doc = await query({ + req, + panel, + annotation, + esQueryConfig, + annotationIndex, + capabilities, + uiSettings, + } as AnnotationsRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "hour_of_day": "1", + }, + }, + ], + }, + }, + ], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T08:00:00.000Z", + }, + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "agent": "2", + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should ignore global and panel filters/queries ', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'kuery', + }, + ]; + + req.body.filters = [ + { + meta: { + index: '90943e30-9a47-11e8-b64d-95841ca0b247', + alias: null, + negate: false, + disabled: false, + type: 'exists', + key: 'referer', + value: 'exists', + }, + query: { + exists: { + field: 'referer', + }, + }, + }, + ]; + + panel.filter = { + query: 'agent : 2', + language: 'kuery', + }; + + annotation.ignore_global_filters = 1; + annotation.ignore_panel_filters = 1; + + const doc = await query({ + req, + panel, + annotation, + esQueryConfig, + annotationIndex, + capabilities, + uiSettings, + } as AnnotationsRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T08:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should add annotation query ', async () => { + annotation.query_string = { + query: 'hour_of_day : 1', + language: 'kuery', + }; + + const doc = await query({ + req, + panel, + annotation, + esQueryConfig, + annotationIndex, + capabilities, + uiSettings, + } as AnnotationsRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T08:00:00.000Z", + }, + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "hour_of_day": "1", + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); +}); diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.ts index 1400702a47fd5..eaf2c5ae2e7bf 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/annotations/query.ts @@ -34,14 +34,12 @@ export const query: AnnotationsRequestProcessorsFunction = ({ const { bucketSize } = getBucketSize(req, 'auto', capabilities, barTargetUiSettings); const { from, to } = getTimerange(req); - doc.size = 0; const queries = !annotation.ignore_global_filters ? req.body.query : []; const filters = !annotation.ignore_global_filters ? req.body.filters : []; + const esQuery = buildEsQuery(indexPattern, queries, filters, esQueryConfig); - doc.query = buildEsQuery(indexPattern, queries, filters, esQueryConfig); - - const boolFilters: unknown[] = [ - { + if (timeField) { + esQuery.bool.must.push({ range: { [timeField]: { gte: from.toISOString(), @@ -49,25 +47,28 @@ export const query: AnnotationsRequestProcessorsFunction = ({ format: 'strict_date_optional_time', }, }, - }, - ]; + }); + } if (annotation.query_string) { - boolFilters.push(buildEsQuery(indexPattern, [annotation.query_string], [], esQueryConfig)); + esQuery.bool.must.push( + buildEsQuery(indexPattern, [annotation.query_string], [], esQueryConfig) + ); } if (!annotation.ignore_panel_filters && panel.filter) { - boolFilters.push(buildEsQuery(indexPattern, [panel.filter], [], esQueryConfig)); + esQuery.bool.must.push(buildEsQuery(indexPattern, [panel.filter], [], esQueryConfig)); } if (annotation.fields) { const fields = annotation.fields.split(/[,\s]+/) || []; fields.forEach((field) => { - boolFilters.push({ exists: { field } }); + esQuery.bool.must.push({ exists: { field } }); }); } - overwrite(doc, 'query.bool.must', boolFilters); + overwrite(doc, 'size', 0); + overwrite(doc, 'query', esQuery); return next(doc); }; diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.test.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.test.ts new file mode 100644 index 0000000000000..013a5f0314d2d --- /dev/null +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.test.ts @@ -0,0 +1,340 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { query } from './query'; + +import type { TableRequestProcessorsFunction, TableRequestProcessorsParams } from './types'; + +describe('query', () => { + let req: TableRequestProcessorsParams['req']; + let panel: TableRequestProcessorsParams['panel']; + let seriesIndex: TableRequestProcessorsParams['seriesIndex']; + let buildSeriesMetaParams: TableRequestProcessorsParams['buildSeriesMetaParams']; + + const next = jest.fn((x) => x) as unknown as ReturnType< + ReturnType + >; + + beforeEach(() => { + req = { + body: { + timerange: { + timezone: 'Europe/Minsk', + min: '2022-01-29T22:03:02.317Z', + max: '2022-02-07T09:00:00.000Z', + }, + }, + } as TableRequestProcessorsParams['req']; + panel = {} as TableRequestProcessorsParams['panel']; + seriesIndex = { + indexPattern: undefined, + indexPatternString: 'foo*', + }; + buildSeriesMetaParams = jest.fn().mockResolvedValue({ timeField: 'fooField' }); + }); + + test('should set "size" to 0', async () => { + const doc = await query({ + req, + panel, + seriesIndex, + buildSeriesMetaParams, + } as TableRequestProcessorsParams)(next)({}); + + expect(doc.size).toBe(0); + }); + + test('should apply global query (Lucene)', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'lucene', + }, + ]; + + panel.ignore_global_filter = 0; + + const doc = await query({ + req, + panel, + seriesIndex, + buildSeriesMetaParams, + } as TableRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [], + "must": Array [ + Object { + "query_string": Object { + "query": "hour_of_day : 1", + }, + }, + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T09:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should apply global query (KQL)', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'kuery', + }, + ]; + + panel.ignore_global_filter = 0; + + const doc = await query({ + req, + panel, + seriesIndex, + buildSeriesMetaParams, + } as TableRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "hour_of_day": "1", + }, + }, + ], + }, + }, + ], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T09:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should apply global filters', async () => { + req.body.filters = [ + { + meta: { + index: '90943e30-9a47-11e8-b64d-95841ca0b247', + alias: null, + negate: false, + disabled: false, + type: 'exists', + key: 'referer', + value: 'exists', + }, + query: { + exists: { + field: 'referer', + }, + }, + }, + ]; + + panel.ignore_global_filter = 0; + + const doc = await query({ + req, + panel, + seriesIndex, + buildSeriesMetaParams, + } as TableRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "referer", + }, + }, + ], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T09:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should add panel filters and merge it with global one', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'kuery', + }, + ]; + + panel.filter = { + query: 'agent : 2', + language: 'kuery', + }; + + panel.ignore_global_filter = 0; + + const doc = await query({ + req, + panel, + seriesIndex, + buildSeriesMetaParams, + } as TableRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "hour_of_day": "1", + }, + }, + ], + }, + }, + ], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T09:00:00.000Z", + }, + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "agent": "2", + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); + + test('should ignore global filters/queries in case is panel.ignore_global_filter = 1 ', async () => { + req.body.query = [ + { + query: 'hour_of_day : 1', + language: 'kuery', + }, + ]; + + req.body.filters = [ + { + meta: { + index: '90943e30-9a47-11e8-b64d-95841ca0b247', + alias: null, + negate: false, + disabled: false, + type: 'exists', + key: 'referer', + value: 'exists', + }, + query: { + exists: { + field: 'referer', + }, + }, + }, + ]; + + panel.ignore_global_filter = 1; + + const doc = await query({ + req, + panel, + seriesIndex, + buildSeriesMetaParams, + } as TableRequestProcessorsParams)(next)({}); + + expect(doc.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [], + "must": Array [ + Object { + "range": Object { + "fooField": Object { + "format": "strict_date_optional_time", + "gte": "2022-01-29T22:03:02.317Z", + "lte": "2022-02-07T09:00:00.000Z", + }, + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + } + `); + }); +}); diff --git a/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.ts b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.ts index d92aa1317b971..1036a4f8a105c 100644 --- a/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.ts +++ b/src/plugins/vis_types/timeseries/server/lib/vis_data/request_processors/table/query.ts @@ -17,14 +17,10 @@ export const query: TableRequestProcessorsFunction = const { timeField } = await buildSeriesMetaParams(); const { from, to } = getTimerange(req); const indexPattern = seriesIndex.indexPattern || undefined; - - doc.size = 0; - const queries = !panel.ignore_global_filter ? req.body.query : []; const filters = !panel.ignore_global_filter ? req.body.filters : []; - doc.query = buildEsQuery(indexPattern, queries, filters, esQueryConfig); - const boolFilters: unknown[] = []; + const esQuery = buildEsQuery(indexPattern, queries, filters, esQueryConfig); if (timeField) { const timerange = { @@ -37,13 +33,14 @@ export const query: TableRequestProcessorsFunction = }, }; - boolFilters.push(timerange); + esQuery.bool.must.push(timerange); } if (panel.filter) { - boolFilters.push(buildEsQuery(indexPattern, [panel.filter], [], esQueryConfig)); + esQuery.bool.must.push(buildEsQuery(indexPattern, [panel.filter], [], esQueryConfig)); } - overwrite(doc, 'query.bool.must', boolFilters); + overwrite(doc, 'size', 0); + overwrite(doc, 'query', esQuery); return next(doc); };