diff --git a/mapping/document.go b/mapping/document.go index 9bdb8596..6b903889 100644 --- a/mapping/document.go +++ b/mapping/document.go @@ -15,6 +15,7 @@ package mapping import ( + "encoding" "encoding/json" "fmt" "reflect" @@ -481,6 +482,17 @@ func (dm *DocumentMapping) processProperty(property interface{}, path []string, fieldMapping := newDateTimeFieldMappingDynamic(context.im) fieldMapping.processTime(property, pathString, path, indexes, context) } + case encoding.TextMarshaler: + txt, err := property.MarshalText() + if err == nil && subDocMapping != nil { + // index by explicit mapping + for _, fieldMapping := range subDocMapping.Fields { + if fieldMapping.Type == "text" { + fieldMapping.processString(string(txt), pathString, path, indexes, context) + } + } + } + dm.walkDocument(property, path, indexes, context) default: if subDocMapping != nil { for _, fieldMapping := range subDocMapping.Fields { @@ -500,6 +512,23 @@ func (dm *DocumentMapping) processProperty(property interface{}, path []string, } } dm.walkDocument(property, path, indexes, context) + case reflect.Ptr: + switch property := property.(type) { + case encoding.TextMarshaler: + txt, err := property.MarshalText() + if err == nil && subDocMapping != nil { + // index by explicit mapping + for _, fieldMapping := range subDocMapping.Fields { + if fieldMapping.Type == "text" { + fieldMapping.processString(string(txt), pathString, path, indexes, context) + } + } + } else { + dm.walkDocument(property, path, indexes, context) + } + default: + dm.walkDocument(property, path, indexes, context) + } default: dm.walkDocument(property, path, indexes, context) } diff --git a/mapping/mapping_test.go b/mapping/mapping_test.go index 309c0e1d..e16052b1 100644 --- a/mapping/mapping_test.go +++ b/mapping/mapping_test.go @@ -900,3 +900,69 @@ func TestMappingForGeo(t *testing.T) { t.Errorf("expected to find geo point, did not") } } + +type textMarshalable struct { + body string + Extra string +} + +func (t *textMarshalable) MarshalText() ([]byte, error) { + return []byte(t.body), nil +} + +func TestMappingForTextMarshaler(t *testing.T) { + tm := struct { + Marshalable *textMarshalable + }{ + Marshalable: &textMarshalable{ + body: "text", + Extra: "stuff", + }, + } + + // first verify that when using a mapping that doesn't explicity + // map the stuct field as text, then we traverse inside the struct + // and do our best + m := NewIndexMapping() + doc := document.NewDocument("x") + err := m.MapDocument(doc, tm) + if err != nil { + t.Fatal(err) + } + + if len(doc.Fields) != 1 { + t.Fatalf("expected 1 field, got: %d", len(doc.Fields)) + } + if doc.Fields[0].Name() != "Marshalable.Extra" { + t.Errorf("expected field to be named 'Marshalable.Extra', got: '%s'", doc.Fields[0].Name()) + } + if string(doc.Fields[0].Value()) != tm.Marshalable.Extra { + t.Errorf("expected field value to be '%s', got: '%s'", tm.Marshalable.Extra, string(doc.Fields[0].Value())) + } + + // now verify that when a mapping explicity + m = NewIndexMapping() + txt := NewTextFieldMapping() + m.DefaultMapping.AddFieldMappingsAt("Marshalable", txt) + doc = document.NewDocument("x") + err = m.MapDocument(doc, tm) + if err != nil { + t.Fatal(err) + } + + if len(doc.Fields) != 1 { + t.Fatalf("expected 1 field, got: %d", len(doc.Fields)) + + } + if doc.Fields[0].Name() != "Marshalable" { + t.Errorf("expected field to be named 'Marshalable', got: '%s'", doc.Fields[0].Name()) + } + want, err := tm.Marshalable.MarshalText() + if err != nil { + t.Fatal(err) + } + if string(doc.Fields[0].Value()) != string(want) { + t.Errorf("expected field value to be '%s', got: '%s'", string(want), string(doc.Fields[0].Value())) + } + +}