Skip to content

Commit 2365a0d

Browse files
Merge custom and core multi_fields arrays (#982)
1 parent 043d144 commit 2365a0d

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

CHANGELOG.next.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Thanks, you're awesome :-) -->
6767
* Added support for marking fields, field sets, or field reuse as beta in the documentation. #1051
6868
* Added support for `constant_keyword`'s optional parameter `value`. #1112
6969
* Added component templates for ECS field sets. #1156, #1186, #1191
70+
* Added functionality for merging custom and core multi-fields. #982
7071

7172
#### Improvements
7273

scripts/schema/loader.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,28 @@ def nest_fields(field_array):
186186
return schema_root
187187

188188

189+
def array_of_maps_to_map(array_vals):
190+
ret_map = {}
191+
for map_val in array_vals:
192+
name = map_val['name']
193+
# if multiple name fields exist in the same custom definition this will take the last one
194+
ret_map[name] = map_val
195+
return ret_map
196+
197+
198+
def map_of_maps_to_array(map_vals):
199+
ret_list = []
200+
for key in map_vals:
201+
ret_list.append(map_vals[key])
202+
return sorted(ret_list, key=lambda k: k['name'])
203+
204+
205+
def dedup_and_merge_lists(list_a, list_b):
206+
list_a_map = array_of_maps_to_map(list_a)
207+
list_a_map.update(array_of_maps_to_map(list_b))
208+
return map_of_maps_to_array(list_a_map)
209+
210+
189211
def merge_fields(a, b):
190212
"""Merge ECS field sets with custom field sets."""
191213
a = copy.deepcopy(a)
@@ -199,6 +221,14 @@ def merge_fields(a, b):
199221
a[key].setdefault('field_details', {})
200222
a[key]['field_details'].setdefault('normalize', [])
201223
a[key]['field_details']['normalize'].extend(b[key]['field_details'].pop('normalize'))
224+
if 'multi_fields' in b[key]['field_details']:
225+
a[key].setdefault('field_details', {})
226+
a[key]['field_details'].setdefault('multi_fields', [])
227+
a[key]['field_details']['multi_fields'] = dedup_and_merge_lists(
228+
a[key]['field_details']['multi_fields'], b[key]['field_details']['multi_fields'])
229+
# if we don't do this then the update call below will overwrite a's field_details, with the original
230+
# contents of b, which undoes our merging the multi_fields
231+
del b[key]['field_details']['multi_fields']
202232
a[key]['field_details'].update(b[key]['field_details'])
203233
# merge schema details
204234
if 'schema_details' in b[key]:

scripts/tests/unit/test_schema_loader.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,81 @@ def test_merge_non_array_attributes(self):
646646
}
647647
self.assertEqual(merged_fields, expected_fields)
648648

649+
def test_merge_and_overwrite_multi_fields(self):
650+
originalSchema = {
651+
'overwrite_field': {
652+
'field_details': {
653+
'multi_fields': [
654+
{
655+
'type': 'text',
656+
'name': 'text',
657+
'norms': True
658+
}
659+
]
660+
},
661+
'fields': {
662+
'message': {
663+
'field_details': {
664+
'multi_fields': [
665+
{
666+
'type': 'text',
667+
'name': 'text'
668+
}
669+
]
670+
}
671+
}
672+
}
673+
}
674+
}
675+
676+
customSchema = {
677+
'overwrite_field': {
678+
'field_details': {
679+
'multi_fields': [
680+
# this entry will completely overwrite the originalSchema's name text entry
681+
{
682+
'type': 'text',
683+
'name': 'text'
684+
}
685+
]
686+
},
687+
'fields': {
688+
'message': {
689+
'field_details': {
690+
'multi_fields': [
691+
# this entry will be merged with the originalSchema's multi_fields entries
692+
{
693+
'type': 'keyword',
694+
'name': 'a_field'
695+
}
696+
]
697+
}
698+
}
699+
}
700+
}
701+
}
702+
merged_fields = loader.merge_fields(originalSchema, customSchema)
703+
expected_overwrite_field_mf = [
704+
{
705+
'type': 'text',
706+
'name': 'text'
707+
}
708+
]
709+
710+
expected_message_mf = [
711+
{
712+
'type': 'keyword',
713+
'name': 'a_field'
714+
},
715+
{
716+
'type': 'text',
717+
'name': 'text'
718+
}
719+
]
720+
self.assertEqual(merged_fields['overwrite_field']['field_details']['multi_fields'], expected_overwrite_field_mf)
721+
self.assertEqual(merged_fields['overwrite_field']['fields']['message']['field_details']
722+
['multi_fields'], expected_message_mf)
723+
649724

650725
if __name__ == '__main__':
651726
unittest.main()

0 commit comments

Comments
 (0)