Skip to content

Commit

Permalink
Fix filters when two fields have the same name
Browse files Browse the repository at this point in the history
  • Loading branch information
verdie-g committed Oct 1, 2024
1 parent 5dda54e commit 5500d31
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 20 deletions.
59 changes: 45 additions & 14 deletions DotnetEventsViewer/Components/QueryBuilder.razor
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
protected override void OnInitialized()
{
_allFields = Field.StaticEventField
.Concat(EnumerateDynamicFieldSelectors(State.Trace!, State.Query!.Filters))
.Concat(EnumerateDynamicFields(State.Trace!, State.Query!.Filters))
.OrderBy(s => s.Name)
.ToArray();
Query = State.Query!;
Expand All @@ -158,18 +158,46 @@
_messageStore = new ValidationMessageStore(_editContext);
}

private IEnumerable<Field> EnumerateDynamicFieldSelectors(Trace trace, Filter[] filters)
private IEnumerable<Field> EnumerateDynamicFields(Trace trace, Filter[] filters)
{
return trace.EventMetadata
.SelectMany(m => m.FieldDefinitions.Select(d =>
// Some fields can have the same name. In that case, the field should be displayed once in the combobox,
// but it should work on all events that have that field. It's assumed in this method, that if two fields
// have the same name, they have a similar FieldDefinition.
Dictionary<string, List<EventMetadata>> eventMetadataByFieldName = [];
foreach (var metadata in trace.EventMetadata)
{
foreach (var fieldDefinition in metadata.FieldDefinitions)
{
// FluentCombobox.SelectedOption is expected to exist in FluentCombobox.Items but if the field is
// created dynamically, the reference comparison will fail and the filter will be set to null when
// changing page. The hack here, is to reuse existing fields before creating a new instance.
var filter = filters.FirstOrDefault(x => x.Field.Name == d.Name);
return filter?.Field ?? Field.FromPayloadFieldDefinition(d, m);
}))
.DistinctBy(s => s.Name);
if (!eventMetadataByFieldName.TryGetValue(fieldDefinition.Name, out var eventMetadataForFieldName))
{
eventMetadataForFieldName = [];
eventMetadataByFieldName[fieldDefinition.Name] = eventMetadataForFieldName;
}

eventMetadataForFieldName.Add(metadata);
}
}

List<Field> fields = new(eventMetadataByFieldName.Count);
foreach (var eventMetadataForFieldName in eventMetadataByFieldName)
{
// FluentCombobox.SelectedOption is expected to exist in FluentCombobox.Items but if the field is
// created dynamically, the reference comparison will fail and the filter will be set to null when
// changing page. The hack here, is to reuse existing fields before creating a new instance.
var filter = filters.FirstOrDefault(x => x.Field.Name == eventMetadataForFieldName.Key);
if (filter?.Field != null)
{
fields.Add(filter.Field);
continue;
}

var fieldDefinition = eventMetadataForFieldName.Value[0].FieldDefinitions.First(d => d.Name == eventMetadataForFieldName.Key);
var field = Field.FromNameAndType(eventMetadataForFieldName.Key, fieldDefinition.TypeCode, eventMetadataForFieldName.Value.ToArray());
fields.Add(field);
}


return fields;
}

private void OnAddFilter()
Expand Down Expand Up @@ -202,8 +230,11 @@
return _allFields;
}

return _allFields.Where(f => f.AssociatedEventMetadata == null
|| Query.EventKeys.Any(k => k.Matches(f.AssociatedEventMetadata))).ToArray();
return _allFields
.Where(f =>
f.AssociatedEventMetadata == null
|| Query.EventKeys.Any(k => f.AssociatedEventMetadata.Any(k.Matches)))
.ToArray();
}

private void OnColumnFieldSearch(OptionsSearchEventArgs<Field> e)
Expand All @@ -215,7 +246,7 @@
else
{
e.Items = _allFields.Where(f =>
(f.AssociatedEventMetadata == null || Query.EventKeys.Any(k => k.Matches(f.AssociatedEventMetadata)))
(f.AssociatedEventMetadata == null || Query.EventKeys.Any(k => f.AssociatedEventMetadata.Any(k.Matches)))
&& f.Name.Contains(e.Text, StringComparison.OrdinalIgnoreCase));
}
}
Expand Down
16 changes: 10 additions & 6 deletions DotnetEventsViewer/Querying/Field.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace DotnetEventsViewer.Querying;

public class Field(string name, TypeCode type, Func<Event, object?> selector, EventMetadata? associatedEventMetadata = null)
public class Field(string name, TypeCode type, Func<Event, object?> selector, EventMetadata[]? associatedEventMetadata = null)
{
public static readonly Field CaptureThreadIdField = new(nameof(Event.CaptureThreadId), TypeCode.Int64, e => e.CaptureThreadId);
public static readonly Field ThreadIdField = new(nameof(Event.ThreadId), TypeCode.Int64, e => e.ThreadId);
Expand All @@ -23,17 +23,21 @@ public class Field(string name, TypeCode type, Func<Event, object?> selector, Ev
EventNameField,
];

public static Field FromPayloadFieldDefinition(EventFieldDefinition fieldDefinition, EventMetadata eventMetadata)
public static Field FromNameAndType(string name, TypeCode typeCode, EventMetadata[] eventMetadata)
{
return new Field(
fieldDefinition.Name,
fieldDefinition.TypeCode,
e => e.Payload.GetValueOrDefault(fieldDefinition.Name),
name,
typeCode,
e => e.Payload.GetValueOrDefault(name),
eventMetadata);
}

public string Name { get; } = name;
public TypeCode Type { get; } = type;
public Func<Event, object?> Selector { get; } = selector;
public EventMetadata? AssociatedEventMetadata { get; } = associatedEventMetadata;

/// <summary>
/// The event the field is associated to. Can contain several events if the same name is used for different events.
/// </summary>
public EventMetadata[]? AssociatedEventMetadata { get; } = associatedEventMetadata;
}

0 comments on commit 5500d31

Please sign in to comment.