diff --git a/executor_test.go b/executor_test.go index 3d17a14e9..5d7b9e952 100644 --- a/executor_test.go +++ b/executor_test.go @@ -16,6 +16,7 @@ package pilosa_test import ( "context" + "encoding/json" "flag" "fmt" "io/ioutil" @@ -2471,18 +2472,31 @@ func TestExecutor_ExecuteOptions(t *testing.T) { t.Run("columnAttrs", func(t *testing.T) { writeQuery := ` + Set(0, f=10) + SetColumnAttrs(0, foo="baz") Set(100, f=10) SetColumnAttrs(100, foo="bar")` readQueries := []string{`Options(Row(f=10), columnAttrs=true)`} responses := runCallTest(t, writeQuery, readQueries, nil) targetColAttrSets := []*pilosa.ColumnAttrSet{ + {ID: 0, Attrs: map[string]interface{}{"foo": "baz"}}, {ID: 100, Attrs: map[string]interface{}{"foo": "bar"}}, } - if bits := responses[0].Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(bits, []uint64{100}) { + targetJSON := `[{"id":0,"attrs":{"foo":"baz"}},{"id":100,"attrs":{"foo":"bar"}}]` + + if bits := responses[0].Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(bits, []uint64{0, 100}) { t.Fatalf("unexpected columns: %+v", bits) } else if attrs := responses[0].ColumnAttrSets; !reflect.DeepEqual(attrs, targetColAttrSets) { t.Fatalf("unexpected attrs: %s", spew.Sdump(attrs)) + } else { + // Ensure the JSON is marshaled correctly. + jres, err := json.Marshal(attrs) + if err != nil { + t.Fatal(err) + } else if string(jres) != targetJSON { + t.Fatalf("json marshal expected: %s, but got: %s", targetJSON, jres) + } } }) @@ -2499,10 +2513,20 @@ func TestExecutor_ExecuteOptions(t *testing.T) { {Key: "one-hundred", Attrs: map[string]interface{}{"foo": "bar"}}, } + targetJSON := `[{"key":"one-hundred","attrs":{"foo":"bar"}}]` + if keys := responses[0].Results[0].(*pilosa.Row).Keys; !reflect.DeepEqual(keys, []string{"one-hundred"}) { t.Fatalf("unexpected keys: %+v", keys) } else if attrs := responses[0].ColumnAttrSets; !reflect.DeepEqual(attrs, targetColAttrSets) { t.Fatalf("unexpected attrs: %s", spew.Sdump(attrs)) + } else { + // Ensure the JSON is marshaled correctly. + jres, err := json.Marshal(attrs) + if err != nil { + t.Fatal(err) + } else if string(jres) != targetJSON { + t.Fatalf("json marshal expected: %s, but got: %s", targetJSON, jres) + } } }) diff --git a/pilosa.go b/pilosa.go index 28d89e864..f8989e9b7 100644 --- a/pilosa.go +++ b/pilosa.go @@ -15,6 +15,7 @@ package pilosa import ( + "encoding/json" "errors" "regexp" ) @@ -121,11 +122,30 @@ var nameRegexp = regexp.MustCompile(`^[a-z][a-z0-9_-]{0,63}$`) // ColumnAttrSet represents a set of attributes for a vertical column in an index. // Can have a set of attributes attached to it. type ColumnAttrSet struct { - ID uint64 `json:"id,omitempty"` + ID uint64 `json:"id"` Key string `json:"key,omitempty"` Attrs map[string]interface{} `json:"attrs,omitempty"` } +func (cas ColumnAttrSet) MarshalJSON() ([]byte, error) { + if cas.Key != "" { + return json.Marshal(struct { + Key string `json:"key,omitempty"` + Attrs map[string]interface{} `json:"attrs,omitempty"` + }{ + Key: cas.Key, + Attrs: cas.Attrs, + }) + } + return json.Marshal(struct { + ID uint64 `json:"id"` + Attrs map[string]interface{} `json:"attrs,omitempty"` + }{ + ID: cas.ID, + Attrs: cas.Attrs, + }) +} + // TimeFormat is the go-style time format used to parse string dates. const TimeFormat = "2006-01-02T15:04"