es query rule - get time field from data view instead of rule (#182883)

## Summary

Previously it was possible to create a rule with a data view and change
the data view but the previous time field would still be referenced. Now
the time field is always pulled from the current data view.


Closes https://github.com/elastic/kibana/issues/182879

#### Release note

Fixed issue where an ES query rule could be created with a data view,
then the data view is changed but there's still a reference to the
previous data view's timestamp field. Now the timestamp field is always
taken from the currently configured data view.

---------

Co-authored-by: Davis McPhee <davis.mcphee@elastic.co>
This commit is contained in:
Matthew Kime 2024-05-08 17:00:24 -05:00 committed by GitHub
parent d770d21312
commit bc103c7016
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 12 additions and 10 deletions

View file

@ -59,7 +59,8 @@ const defaultParams: OnlySearchSourceRuleParams = {
excludeHitsFromPreviousRun: true,
aggType: 'count',
groupBy: 'all',
timeField: 'time',
// this should be ignored when using a data view
timeField: 'timeFieldNotFromDataView',
};
describe('fetchSearchSourceQuery', () => {

View file

@ -112,18 +112,17 @@ export function updateSearchSource(
alertLimit?: number
): { searchSource: ISearchSource; filterToExcludeHitsFromPreviousRun: Filter | null } {
const isGroupAgg = isGroupAggregation(params.termField);
const timeFieldName = params.timeField || index.timeFieldName;
const timeField = index.getTimeField();
if (!timeFieldName) {
throw new Error('Invalid data view without timeFieldName.');
if (!timeField) {
throw new Error(`Data view with ID ${index.id} no longer contains a time field.`);
}
searchSource.setField('size', isGroupAgg ? 0 : params.size);
const field = index.fields.find((f) => f.name === timeFieldName);
const filters = [
buildRangeFilter(
field!,
timeField,
{ lte: dateEnd, gte: dateStart, format: 'strict_date_optional_time' },
index
),
@ -135,7 +134,7 @@ export function updateSearchSource(
// add additional filter for documents with a timestamp greater than
// the timestamp of the previous run, so that those documents are not counted twice
filterToExcludeHitsFromPreviousRun = buildRangeFilter(
field!,
timeField,
{ gt: latestTimestamp, format: 'strict_date_optional_time' },
index
);
@ -150,7 +149,7 @@ export function updateSearchSource(
searchSourceChild.setField('filter', filters as Filter[]);
searchSourceChild.setField('sort', [
{
[timeFieldName]: {
[timeField.name]: {
order: SortDirection.desc,
format: 'strict_date_optional_time||epoch_millis',
},

View file

@ -633,6 +633,7 @@ describe('ruleType', () => {
toSpec: () => {
return { id: 'test-id', title: 'test-title', timeFieldName: 'timestamp', fields: [] };
},
getTimeField: () => dataViewMock.fields[1],
};
const defaultParams: OnlySearchSourceRuleParams = {
size: 100,
@ -701,12 +702,12 @@ describe('ruleType', () => {
(searchSourceInstanceMock.getField as jest.Mock).mockImplementationOnce((name: string) => {
if (name === 'index') {
return { dataViewMock, timeFieldName: undefined };
return { dataViewMock, getTimeField: () => undefined, id: 1234 };
}
});
await expect(invokeExecutor({ params, ruleServices })).rejects.toThrow(
'Invalid data view without timeFieldName.'
'Data view with ID 1234 no longer contains a time field.'
);
});
@ -717,6 +718,7 @@ describe('ruleType', () => {
(ruleServices.dataViews.create as jest.Mock).mockResolvedValueOnce({
...dataViewMock.toSpec(),
toSpec: () => dataViewMock.toSpec(),
getTimeField: () => dataViewMock.fields[1],
toMinimalSpec: () => dataViewMock.toSpec(),
});
(searchSourceInstanceMock.getField as jest.Mock).mockImplementation((name: string) => {