Repository: grafana/grafana-plugin-sdk-go (go)

Issue:
Refactor dataframe UnMarshalArrow
Rename when doing this: s/ df.UnMarshalArrow /  df.UnmarshalArrow

This is a long sprawling function. Would probably be nice to break up like MarshalArrow with its decoders.

Good way to get some familiarity with the arrow code. 

Pull request description:
19 refactor un marshal arrow
This fix contains the following changes:
* Refactors `df.UnMarshalArrow`
* Renames `df.UnMarshalArrow` to `df.UnmarshalArrow`

Fixes #19 

Patch:
diff --git a/dataframe/arrow.go b/dataframe/arrow.go
index fdc2a02..b22c806 100644
--- a/dataframe/arrow.go
+++ b/dataframe/arrow.go
@@ -195,34 +195,15 @@ func fieldToArrow(f *Field) (arrow.DataType, bool, error) {
 	}
 }
 
-// UnMarshalArrow converts a byte representation of an arrow table to a Frame
-// TODO: Break up this function.
-func UnMarshalArrow(b []byte) (*Frame, error) {
-	fB := filebuffer.New(b)
-	fR, err := ipc.NewFileReader(fB)
-	if err != nil {
-		return nil, err
+func getMDKey(key string, metaData arrow.Metadata) (string, bool) {
+	idx := metaData.FindKey(key)
+	if idx < 0 {
+		return "", false
 	}
-	defer fR.Close()
+	return metaData.Values()[idx], true
+}
 
-	schema := fR.Schema()
-	metaData := schema.Metadata()
-	frame := &Frame{}
-	getMDKey := func(key string) (string, bool) {
-		idx := metaData.FindKey(key)
-		if idx < 0 {
-			return "", false
-		}
-		return metaData.Values()[idx], true
-	}
-	frame.Name, _ = getMDKey("name") // No need to check ok, zero value ("") is returned
-	frame.RefID, _ = getMDKey("refId")
-	if labelsAsString, ok := getMDKey("labels"); ok {
-		frame.Labels, err = LabelsFromString(labelsAsString)
-		if err != nil {
-			return nil, err
-		}
-	}
+func initializeFrameFields(schema *arrow.Schema, frame *Frame) ([]bool, error) {
 	nullable := make([]bool, len(schema.Fields()))
 	for idx, field := range schema.Fields() {
 		sdkField := &Field{
@@ -267,18 +248,21 @@ func UnMarshalArrow(b []byte) (*Frame, error) {
 			}
 			sdkField.Vector = newTimeVector(0)
 		default:
-			return nil, fmt.Errorf("unsupported conversion from arrow to sdk type for arrow type %v", field.Type.ID().String())
+			return nullable, fmt.Errorf("unsupported conversion from arrow to sdk type for arrow type %v", field.Type.ID().String())
 		}
 		frame.Fields = append(frame.Fields, sdkField)
 	}
+	return nullable, nil
+}
 
+func populateFrameFields(fR *ipc.FileReader, nullable []bool, frame *Frame) error {
 	for {
 		record, err := fR.Read()
 		if err == io.EOF {
 			break
 		}
 		if err != nil {
-			return nil, err
+			return err
 		}
 		for i := 0; i < len(frame.Fields); i++ {
 			col := record.Column(i)
@@ -374,10 +358,41 @@ func UnMarshalArrow(b []byte) (*Frame, error) {
 					frame.Fields[i].Vector.Append(t)
 				}
 			default:
-				return nil, fmt.Errorf("unsupported arrow type %s for conversion", col.DataType().ID())
+				return fmt.Errorf("unsupported arrow type %s for conversion", col.DataType().ID())
 			}
 		}
 	}
+	return nil
+}
 
+// UnmarshalArrow converts a byte representation of an arrow table to a Frame
+func UnmarshalArrow(b []byte) (*Frame, error) {
+	fB := filebuffer.New(b)
+	fR, err := ipc.NewFileReader(fB)
+	if err != nil {
+		return nil, err
+	}
+	defer fR.Close()
+
+	schema := fR.Schema()
+	metaData := schema.Metadata()
+	frame := &Frame{}
+	frame.Name, _ = getMDKey("name", metaData) // No need to check ok, zero value ("") is returned
+	frame.RefID, _ = getMDKey("refId", metaData)
+	if labelsAsString, ok := getMDKey("labels", metaData); ok {
+		frame.Labels, err = LabelsFromString(labelsAsString)
+		if err != nil {
+			return nil, err
+		}
+	}
+	nullable, err := initializeFrameFields(schema, frame)
+	if err != nil {
+		return nil, err
+	}
+
+	err = populateFrameFields(fR, nullable, frame)
+	if err != nil {
+		return nil, err
+	}
 	return frame, nil
 }
diff --git a/transform/transform.go b/transform/transform.go
index eb71cec..4d59950 100644
--- a/transform/transform.go
+++ b/transform/transform.go
@@ -152,7 +152,7 @@ func (w *grafanaAPIWrapper) QueryDatasource(ctx context.Context, orgID int64, da
 		// TODO Error property etc
 		dfs := make([]*dataframe.Frame, len(rawRes.Dataframes))
 		for dfIdx, b := range rawRes.Dataframes {
-			dfs[dfIdx], err = dataframe.UnMarshalArrow(b)
+			dfs[dfIdx], err = dataframe.UnmarshalArrow(b)
 			if err != nil {
 				return nil, err
 			}


Test patch:
diff --git a/dataframe/arrow_test.go b/dataframe/arrow_test.go
index f7f7d12..16836ed 100644
--- a/dataframe/arrow_test.go
+++ b/dataframe/arrow_test.go
@@ -115,7 +115,7 @@ func TestDecode(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	newDf, err := dataframe.UnMarshalArrow(b)
+	newDf, err := dataframe.UnmarshalArrow(b)
 	if err != nil {
 		t.Fatal(err)
 	}