-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[data.search.aggs] Move agg-specific field formats to search service #69586
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
6f2dc58
Add format to serialized agg config.
lukeelmers fd1d89f
Add AggConfig.toSerializedFieldFormat.
lukeelmers af1ee76
Remove serializeFieldFormat and replace with AggConfig.toSerializedFi…
lukeelmers 2fa1191
Fix agg config unit tests.
lukeelmers 78f26ec
Add unit tests.
lukeelmers c3efb24
Ensure toSerializedFormat is set for pipeline aggs.
lukeelmers 08f4e2f
Fix issue where range agg formatting params were not properly structu…
lukeelmers 0548a74
Update docs.
lukeelmers c0c8053
Fix build pipeline unit tests.
lukeelmers 70103ea
Revert added 'format' property on serialized agg config.
lukeelmers 0721506
Merge branch 'master' into feat/aggs-formatters
elasticmachine 5b1a6bc
Merge branch 'master' into feat/aggs-formatters
elasticmachine ec77286
Merge branch 'master' into feat/aggs-formatters
elasticmachine c6325c0
Move custom agg formatter logic into aggs.
lukeelmers 14c2b9f
Add unit tests for getFormatWithAggs.
lukeelmers 0cf41e5
Merge branch 'master' into fix/aggs-formats
elasticmachine 501ba77
Merge branch 'master' into fix/aggs-formats
elasticmachine File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
src/plugins/data/public/search/aggs/utils/get_format_with_aggs.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* Licensed to Elasticsearch B.V. under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch B.V. licenses this file to you under | ||
* the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
import { identity } from 'lodash'; | ||
|
||
import { SerializedFieldFormat } from '../../../../../expressions/common/types'; | ||
import { FieldFormat } from '../../../../common'; | ||
import { IFieldFormat } from '../../../../public'; | ||
|
||
import { getFormatWithAggs } from './get_format_with_aggs'; | ||
|
||
describe('getFormatWithAggs', () => { | ||
let getFormat: jest.MockedFunction<(mapping: SerializedFieldFormat) => IFieldFormat>; | ||
|
||
beforeEach(() => { | ||
getFormat = jest.fn().mockImplementation(() => { | ||
const DefaultFieldFormat = FieldFormat.from(identity); | ||
return new DefaultFieldFormat(); | ||
}); | ||
}); | ||
|
||
test('calls provided getFormat if no matching aggs exist', () => { | ||
const mapping = { id: 'foo', params: {} }; | ||
const getFieldFormat = getFormatWithAggs(getFormat); | ||
getFieldFormat(mapping); | ||
|
||
expect(getFormat).toHaveBeenCalledTimes(1); | ||
expect(getFormat).toHaveBeenCalledWith(mapping); | ||
}); | ||
|
||
test('creates custom format for date_range', () => { | ||
const mapping = { id: 'date_range', params: {} }; | ||
const getFieldFormat = getFormatWithAggs(getFormat); | ||
const format = getFieldFormat(mapping); | ||
|
||
expect(format.convert({ from: '2020-05-01', to: '2020-06-01' })).toBe( | ||
'2020-05-01 to 2020-06-01' | ||
); | ||
expect(format.convert({ to: '2020-06-01' })).toBe('Before 2020-06-01'); | ||
expect(format.convert({ from: '2020-06-01' })).toBe('After 2020-06-01'); | ||
expect(getFormat).toHaveBeenCalledTimes(3); | ||
}); | ||
|
||
test('creates custom format for ip_range', () => { | ||
const mapping = { id: 'ip_range', params: {} }; | ||
const getFieldFormat = getFormatWithAggs(getFormat); | ||
const format = getFieldFormat(mapping); | ||
|
||
expect(format.convert({ type: 'range', from: '10.0.0.1', to: '10.0.0.10' })).toBe( | ||
'10.0.0.1 to 10.0.0.10' | ||
); | ||
expect(format.convert({ type: 'range', to: '10.0.0.10' })).toBe('-Infinity to 10.0.0.10'); | ||
expect(format.convert({ type: 'range', from: '10.0.0.10' })).toBe('10.0.0.10 to Infinity'); | ||
format.convert({ type: 'mask', mask: '10.0.0.1/24' }); | ||
expect(getFormat).toHaveBeenCalledTimes(4); | ||
}); | ||
|
||
test('creates custom format for range', () => { | ||
const mapping = { id: 'range', params: {} }; | ||
const getFieldFormat = getFormatWithAggs(getFormat); | ||
const format = getFieldFormat(mapping); | ||
|
||
expect(format.convert({ gte: 1, lt: 20 })).toBe('≥ 1 and < 20'); | ||
expect(getFormat).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
test('creates custom format for terms', () => { | ||
const mapping = { | ||
id: 'terms', | ||
params: { | ||
otherBucketLabel: 'other bucket', | ||
missingBucketLabel: 'missing bucket', | ||
}, | ||
}; | ||
const getFieldFormat = getFormatWithAggs(getFormat); | ||
const format = getFieldFormat(mapping); | ||
|
||
expect(format.convert('machine.os.keyword')).toBe('machine.os.keyword'); | ||
expect(format.convert('__other__')).toBe(mapping.params.otherBucketLabel); | ||
expect(format.convert('__missing__')).toBe(mapping.params.missingBucketLabel); | ||
expect(getFormat).toHaveBeenCalledTimes(3); | ||
}); | ||
}); |
116 changes: 116 additions & 0 deletions
116
src/plugins/data/public/search/aggs/utils/get_format_with_aggs.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* Licensed to Elasticsearch B.V. under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch B.V. licenses this file to you under | ||
* the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
import { i18n } from '@kbn/i18n'; | ||
|
||
import { SerializedFieldFormat } from '../../../../../expressions/common/types'; | ||
import { FieldFormat } from '../../../../common'; | ||
import { FieldFormatsContentType, IFieldFormat } from '../../../../public'; | ||
import { convertDateRangeToString, DateRangeKey } from '../buckets/lib/date_range'; | ||
import { convertIPRangeToString, IpRangeKey } from '../buckets/lib/ip_range'; | ||
|
||
type GetFieldFormat = (mapping: SerializedFieldFormat) => IFieldFormat; | ||
|
||
/** | ||
* Certain aggs have custom field formats that are not part of the field formats | ||
* registry. This function will take the `getFormat` function which is used inside | ||
* `deserializeFieldFormat` and decorate it with the additional custom formats | ||
* that the field formats service doesn't know anything about. | ||
* | ||
* This function is internal to the data plugin, and only exists for use inside | ||
* the field formats service. | ||
* | ||
* @internal | ||
*/ | ||
export function getFormatWithAggs(getFieldFormat: GetFieldFormat): GetFieldFormat { | ||
return (mapping) => { | ||
const { id, params = {} } = mapping; | ||
|
||
const customFormats: Record<string, () => IFieldFormat> = { | ||
range: () => { | ||
const RangeFormat = FieldFormat.from((range: any) => { | ||
const nestedFormatter = params as SerializedFieldFormat; | ||
const format = getFieldFormat({ | ||
id: nestedFormatter.id, | ||
params: nestedFormatter.params, | ||
}); | ||
const gte = '\u2265'; | ||
const lt = '\u003c'; | ||
return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessage', { | ||
defaultMessage: '{gte} {from} and {lt} {to}', | ||
values: { | ||
gte, | ||
from: format.convert(range.gte), | ||
lt, | ||
to: format.convert(range.lt), | ||
}, | ||
}); | ||
}); | ||
return new RangeFormat(); | ||
}, | ||
date_range: () => { | ||
const nestedFormatter = params as SerializedFieldFormat; | ||
const DateRangeFormat = FieldFormat.from((range: DateRangeKey) => { | ||
const format = getFieldFormat({ | ||
id: nestedFormatter.id, | ||
params: nestedFormatter.params, | ||
}); | ||
return convertDateRangeToString(range, format.convert.bind(format)); | ||
}); | ||
return new DateRangeFormat(); | ||
}, | ||
ip_range: () => { | ||
const nestedFormatter = params as SerializedFieldFormat; | ||
const IpRangeFormat = FieldFormat.from((range: IpRangeKey) => { | ||
const format = getFieldFormat({ | ||
id: nestedFormatter.id, | ||
params: nestedFormatter.params, | ||
}); | ||
return convertIPRangeToString(range, format.convert.bind(format)); | ||
}); | ||
return new IpRangeFormat(); | ||
}, | ||
terms: () => { | ||
const convert = (val: string, type: FieldFormatsContentType) => { | ||
const format = getFieldFormat({ id: params.id, params }); | ||
|
||
if (val === '__other__') { | ||
return params.otherBucketLabel; | ||
} | ||
if (val === '__missing__') { | ||
return params.missingBucketLabel; | ||
} | ||
|
||
return format.convert(val, type); | ||
}; | ||
|
||
return { | ||
convert, | ||
getConverterFor: (type: FieldFormatsContentType) => (val: string) => convert(val, type), | ||
} as IFieldFormat; | ||
}, | ||
}; | ||
|
||
if (!id || !(id in customFormats)) { | ||
return getFieldFormat(mapping); | ||
} | ||
|
||
return customFormats[id](); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TS needed an index signature, so I converted this default to
Record<string, any>