1// Copyright 2013 Matthew Baird 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// http://www.apache.org/licenses/LICENSE-2.0 6// Unless required by applicable law or agreed to in writing, software 7// distributed under the License is distributed on an "AS IS" BASIS, 8// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9// See the License for the specific language governing permissions and 10// limitations under the License. 11 12package elastigo 13 14import ( 15 "encoding/json" 16 "fmt" 17 "reflect" 18 "strings" 19) 20 21type Mapping map[string]MappingOptions 22 23type MappingOptions struct { 24 Id IdOptions `json:"_id"` 25 Timestamp TimestampOptions `json:"_timestamp"` 26 Analyzer *AnalyzerOptions `json:"_analyzer,omitempty"` 27 Parent *ParentOptions `json:"_parent,omitempty"` 28 Routing *RoutingOptions `json:"_routing,omitempty"` 29 Size *SizeOptions `json:"_size,omitempty"` 30 Source *SourceOptions `json:"_source,omitempty"` 31 TTL *TTLOptions `json:"_ttl,omitempty"` 32 Type *TypeOptions `json:"_type,omitempty"` 33 Properties map[string]interface{} `json:"properties"` 34 DynamicTemplates []map[string]interface{} `json:"dynamic_templates,omitempty"` 35} 36 37type TimestampOptions struct { 38 Enabled bool `json:"enabled"` 39} 40 41type AnalyzerOptions struct { 42 Path string `json:"path,omitempty"` 43 Index string `json:"index,omitempty"` 44} 45 46type ParentOptions struct { 47 Type string `json:"type"` 48} 49 50type RoutingOptions struct { 51 Required bool `json:"required,omitempty"` 52 Path string `json:"path,omitempty"` 53} 54 55type SizeOptions struct { 56 Enabled bool `json:"enabled,omitempty"` 57 Store bool `json:"store,omitempty"` 58} 59 60type SourceOptions struct { 61 Enabled bool `json:"enabled,omitempty"` 62 Includes []string `json:"includes,omitempty"` 63 Excludes []string `json:"excludes,omitempty"` 64} 65 66type TypeOptions struct { 67 Store bool `json:"store,omitempty"` 68 Index string `json:"index,omitempty"` 69} 70 71type TTLOptions struct { 72 Enabled bool `json:"enabled"` 73 Default string `json:"default,omitempty"` 74} 75 76type IdOptions struct { 77 Index string `json:"index,omitempty"` 78 Path string `json:"path,omitempty"` 79} 80 81func (m_ Mapping) Options() MappingOptions { 82 m := map[string]MappingOptions(m_) 83 for _, v := range m { 84 return v 85 } 86 panic(fmt.Errorf("Malformed input: %v", m_)) 87} 88 89func MappingForType(typeName string, opts MappingOptions) Mapping { 90 return map[string]MappingOptions{typeName: opts} 91} 92 93func (c *Conn) PutMapping(index string, typeName string, instance interface{}, opt MappingOptions) error { 94 instanceType := reflect.TypeOf(instance) 95 if instanceType.Kind() != reflect.Struct { 96 return fmt.Errorf("instance kind was not struct") 97 } 98 99 if opt.Properties == nil { 100 opt.Properties = make(map[string]interface{}) 101 } 102 getProperties(instanceType, opt.Properties) 103 body, err := json.Marshal(MappingForType(typeName, opt)) 104 if err != nil { 105 return err 106 } 107 _, err = c.DoCommand("PUT", fmt.Sprintf("/%s/%s/_mapping", index, typeName), nil, string(body)) 108 if err != nil { 109 return err 110 } 111 112 return nil 113} 114 115//Same as PutMapping, but takes a []byte for mapping and provides no check of structure 116func (c *Conn) PutMappingFromJSON(index string, typeName string, mapping []byte) error { 117 _, err := c.DoCommand("PUT", fmt.Sprintf("/%s/%s/_mapping", index, typeName), nil, string(mapping)) 118 return err 119} 120 121func getProperties(t reflect.Type, prop map[string]interface{}) { 122 n := t.NumField() 123 for i := 0; i < n; i++ { 124 field := t.Field(i) 125 126 name := strings.Split(field.Tag.Get("json"), ",")[0] 127 if name == "-" { 128 continue 129 } else if name == "" { 130 name = field.Name 131 } 132 133 attrMap := make(map[string]interface{}) 134 attrs := splitTag(field.Tag.Get("elastic")) 135 for _, attr := range attrs { 136 keyvalue := strings.Split(attr, ":") 137 attrMap[keyvalue[0]] = keyvalue[1] 138 } 139 140 if len(attrMap) == 0 || attrMap["type"] == "nested" { 141 142 // We are looking for tags on any inner struct, independently of 143 // whether the field is a struct, a pointer to struct, or a slice of structs 144 targetType := field.Type 145 if targetType.Kind() == reflect.Ptr || 146 targetType.Kind() == reflect.Slice { 147 targetType = field.Type.Elem() 148 } 149 if targetType.Kind() == reflect.Struct { 150 if field.Anonymous { 151 getProperties(targetType, prop) 152 } else { 153 innerStructProp := make(map[string]interface{}) 154 getProperties(targetType, innerStructProp) 155 attrMap["properties"] = innerStructProp 156 } 157 } 158 } 159 if len(attrMap) != 0 { 160 prop[name] = attrMap 161 } 162 } 163} 164 165func splitTag(tag string) []string { 166 tag = strings.Trim(tag, " ") 167 if tag == "" { 168 return []string{} 169 } else { 170 return strings.Split(tag, ",") 171 } 172} 173