mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[ES|QL] Sets the KQL/Lucene query on dataview to ES|QL transition (#206391)
## Summary Closes https://github.com/elastic/kibana/issues/203368 Transitions the KQL / Lucene query while transitioning from dataview to ES|QL mode  ### Checklist - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
10cc89182f
commit
098e8cb518
4 changed files with 120 additions and 6 deletions
|
@ -101,4 +101,79 @@ describe('getInitialESQLQuery', () => {
|
|||
'FROM logs* | WHERE @custom_timestamp >= ?_tstart AND @custom_timestamp <= ?_tend | LIMIT 10'
|
||||
);
|
||||
});
|
||||
|
||||
it('should append a where clause correctly if there is no @timestamp in the index fields and a query is given', () => {
|
||||
const fields = [
|
||||
{
|
||||
name: '@custom_timestamp',
|
||||
displayName: '@custom_timestamp',
|
||||
type: 'date',
|
||||
scripted: false,
|
||||
filterable: true,
|
||||
aggregatable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
displayName: 'message',
|
||||
type: 'string',
|
||||
scripted: false,
|
||||
filterable: false,
|
||||
},
|
||||
] as DataView['fields'];
|
||||
const dataView = getDataView('logs*', fields, '@custom_timestamp');
|
||||
expect(getInitialESQLQuery(dataView, { language: 'kuery', query: 'error' })).toBe(
|
||||
'FROM logs* | WHERE @custom_timestamp >= ?_tstart AND @custom_timestamp <= ?_tend AND KQL("""error""") | LIMIT 10'
|
||||
);
|
||||
});
|
||||
|
||||
it('should append a where clause correctly if there is @timestamp in the index fields and a query is given', () => {
|
||||
const fields = [
|
||||
{
|
||||
name: '@timestamp',
|
||||
displayName: '@timestamp',
|
||||
type: 'date',
|
||||
scripted: false,
|
||||
filterable: true,
|
||||
aggregatable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
displayName: 'message',
|
||||
type: 'string',
|
||||
scripted: false,
|
||||
filterable: false,
|
||||
},
|
||||
] as DataView['fields'];
|
||||
const dataView = getDataView('logs*', fields, 'timestamp');
|
||||
expect(getInitialESQLQuery(dataView, { language: 'lucene', query: 'error' })).toBe(
|
||||
'FROM logs* | WHERE QSTR("""error""") | LIMIT 10'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not append a where clause correctly if there is @timestamp in the index fields and no kql or lucene query is given', () => {
|
||||
const fields = [
|
||||
{
|
||||
name: '@timestamp',
|
||||
displayName: '@timestamp',
|
||||
type: 'date',
|
||||
scripted: false,
|
||||
filterable: true,
|
||||
aggregatable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
displayName: 'message',
|
||||
type: 'string',
|
||||
scripted: false,
|
||||
filterable: false,
|
||||
},
|
||||
] as DataView['fields'];
|
||||
const dataView = getDataView('logs*', fields, 'timestamp');
|
||||
expect(getInitialESQLQuery(dataView, { language: 'unknown', query: 'error' })).toBe(
|
||||
'FROM logs* | LIMIT 10'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,31 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { type Query, escapeQuotes } from '@kbn/es-query';
|
||||
|
||||
const getFilterBySearchText = (query?: Query) => {
|
||||
if (!query) {
|
||||
return '';
|
||||
}
|
||||
const searchTextFunc =
|
||||
query.language === 'kuery' ? 'KQL' : query.language === 'lucene' ? 'QSTR' : '';
|
||||
|
||||
if (searchTextFunc && query.query) {
|
||||
const escapedQuery =
|
||||
typeof query.query === 'string' && query.language === 'lucene'
|
||||
? escapeQuotes(query.query)
|
||||
: query.query;
|
||||
return `${searchTextFunc}("""${escapedQuery}""")`;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const getFinalWhereClause = (timeFilter?: string, queryFilter?: string) => {
|
||||
if (timeFilter && queryFilter) {
|
||||
return ` | WHERE ${timeFilter} AND ${queryFilter}`;
|
||||
}
|
||||
return timeFilter || queryFilter ? ` | WHERE ${timeFilter || queryFilter}` : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds an ES|QL query for the provided dataView
|
||||
|
@ -15,12 +40,16 @@ import type { DataView } from '@kbn/data-views-plugin/public';
|
|||
* If there is no @timestamp and there is a dataView timeFieldName, we add the WHERE clause with the timeFieldName
|
||||
* @param dataView
|
||||
*/
|
||||
export function getInitialESQLQuery(dataView: DataView): string {
|
||||
export function getInitialESQLQuery(dataView: DataView, query?: Query): string {
|
||||
const hasAtTimestampField = dataView?.fields?.getByName?.('@timestamp')?.type === 'date';
|
||||
const timeFieldName = dataView?.timeFieldName;
|
||||
const filterByTimeParams =
|
||||
!hasAtTimestampField && timeFieldName
|
||||
? ` | WHERE ${timeFieldName} >= ?_tstart AND ${timeFieldName} <= ?_tend`
|
||||
? `${timeFieldName} >= ?_tstart AND ${timeFieldName} <= ?_tend`
|
||||
: '';
|
||||
return `FROM ${dataView.getIndexPattern()}${filterByTimeParams} | LIMIT 10`;
|
||||
|
||||
const filterBySearchText = getFilterBySearchText(query);
|
||||
|
||||
const whereClause = getFinalWhereClause(filterByTimeParams, filterBySearchText);
|
||||
return `FROM ${dataView.getIndexPattern()}${whereClause} | LIMIT 10`;
|
||||
}
|
||||
|
|
|
@ -774,9 +774,10 @@ describe('Test discover state actions', () => {
|
|||
savedSearchWithQuery.searchSource.setField('filter', filters);
|
||||
const { state } = await getState('/', { savedSearch: savedSearchWithQuery });
|
||||
state.globalState?.set({ filters });
|
||||
state.appState.set({ query });
|
||||
await state.actions.transitionFromDataViewToESQL(dataViewMock);
|
||||
expect(state.appState.getState().query).toStrictEqual({
|
||||
esql: 'FROM the-data-view-title | LIMIT 10',
|
||||
esql: 'FROM the-data-view-title | WHERE KQL("""foo: \'bar\'""") | LIMIT 10',
|
||||
});
|
||||
expect(state.globalState?.get?.()?.filters).toStrictEqual([]);
|
||||
expect(state.appState.getState().filters).toStrictEqual([]);
|
||||
|
|
|
@ -25,7 +25,13 @@ import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
|||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { merge } from 'rxjs';
|
||||
import { getInitialESQLQuery } from '@kbn/esql-utils';
|
||||
import { AggregateQuery, isOfAggregateQueryType, Query, TimeRange } from '@kbn/es-query';
|
||||
import {
|
||||
AggregateQuery,
|
||||
isOfAggregateQueryType,
|
||||
isOfQueryType,
|
||||
Query,
|
||||
TimeRange,
|
||||
} from '@kbn/es-query';
|
||||
import { isFunction } from 'lodash';
|
||||
import { loadSavedSearch as loadSavedSearchFn } from './utils/load_saved_search';
|
||||
import { restoreStateFromSavedSearch } from '../../../services/saved_searches/restore_from_saved_search';
|
||||
|
@ -386,7 +392,10 @@ export function getDiscoverStateContainer({
|
|||
};
|
||||
|
||||
const transitionFromDataViewToESQL = (dataView: DataView) => {
|
||||
const queryString = getInitialESQLQuery(dataView);
|
||||
const appState = appStateContainer.get();
|
||||
const { query } = appState;
|
||||
const filterQuery = query && isOfQueryType(query) ? query : undefined;
|
||||
const queryString = getInitialESQLQuery(dataView, filterQuery);
|
||||
|
||||
appStateContainer.update({
|
||||
query: { esql: queryString },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue