diff --git a/data/framestruct/converter.go b/data/framestruct/converter.go index 55d805990..ebfca8b37 100644 --- a/data/framestruct/converter.go +++ b/data/framestruct/converter.go @@ -129,6 +129,7 @@ func (c *converter) convertStruct(field reflect.Value, fieldName string) error { func (c *converter) convertSlice(s reflect.Value, prefix string) error { for i := 0; i < s.Len(); i++ { + c.maxLen++ v := s.Index(i) switch v.Kind() { case reflect.Map: @@ -259,9 +260,6 @@ func (c *converter) convertField(v reflect.Value, fieldName string) (interface{} func (c *converter) appendToField(name string, value interface{}) { c.fields[name].Append(value) - if c.fields[name].Len() > c.maxLen { - c.maxLen++ - } } func (c *converter) createFrame(name string) *data.Frame { diff --git a/data/framestruct/converter_test.go b/data/framestruct/converter_test.go index ad2cdcf11..3c34928b7 100644 --- a/data/framestruct/converter_test.go +++ b/data/framestruct/converter_test.go @@ -312,6 +312,71 @@ func TestSlices(t *testing.T) { require.Equal(t, "baz1", fromPointer(frame.Fields[2].At(1))) }) + t.Run("it flattens a slice of maps that are different sizes even if col0 is not fully-defined", func(t *testing.T) { + maps := []map[string]interface{}{ + { + "Thing2": int32(36), + }, + { + "Thing1": "foo1", + "Thing3": "baz1", + }, + } + + // result + // | Thing1 | Thing2 | Thing3 | + // |--------+--------+--------| + // | nil | 36 | nil | + // | foo1 | nil | baz1 | + + frame, err := framestruct.ToDataFrame("results", maps) + require.Nil(t, err) + + require.Len(t, frame.Fields, 3) + require.Equal(t, 2, frame.Fields[0].Len()) + require.Equal(t, 2, frame.Fields[1].Len()) + require.Equal(t, 2, frame.Fields[2].Len()) + + require.Nil(t, frame.Fields[0].At(0)) + require.Equal(t, "foo1", fromPointer(frame.Fields[0].At(1))) + + require.Equal(t, int32(36), fromPointer(frame.Fields[1].At(0))) + require.Nil(t, frame.Fields[1].At(1)) + + require.Nil(t, frame.Fields[2].At(0)) + require.Equal(t, "baz1", fromPointer(frame.Fields[2].At(1))) + }) + + t.Run("it flattens a slice of maps that are different sizes even if col0 is not fully-defined (minimal)s", func(t *testing.T) { + maps := []map[string]interface{}{ + { + "b": true, + }, + { + "a": true, + }, + } + + // result + // | a | b | + // |------+------| + // | nil | true | + // | true | nil | + + frame, err := framestruct.ToDataFrame("results", maps) + require.Nil(t, err) + + require.Len(t, frame.Fields, 2) + require.Equal(t, 2, frame.Fields[0].Len()) + require.Equal(t, 2, frame.Fields[1].Len()) + + require.Nil(t, frame.Fields[0].At(0)) + require.Equal(t, true, fromPointer(frame.Fields[0].At(1))) + + require.Equal(t, true, fromPointer(frame.Fields[1].At(0))) + require.Nil(t, frame.Fields[1].At(1)) + }) + t.Run("it flattens a slice of maps that contains nil values", func(t *testing.T) { // like the testcase above, just with "nil" instead of non-defined map keys. maps := []map[string]interface{}{