github.com/viant/toolbox@v0.34.5/decoder.go (about) 1 package toolbox 2 3 import ( 4 "bytes" 5 "encoding/csv" 6 "encoding/json" 7 "fmt" 8 "gopkg.in/yaml.v2" 9 "io" 10 "io/ioutil" 11 "strings" 12 ) 13 14 //Decoder represents a decoder. 15 type Decoder interface { 16 //Decode reads and decodes objects from an input stream. 17 Decode(v interface{}) error 18 } 19 20 //UnMarshaler represent an struct that can be converted to bytes 21 type UnMarshaler interface { 22 //Unmarshal converts a struct to bytes 23 Unmarshal(data []byte) error 24 } 25 26 //DecoderFactory create an decoder for passed in input stream 27 type DecoderFactory interface { 28 //Create a decoder for passed in io reader 29 Create(reader io.Reader) Decoder 30 } 31 32 type jsonDecoderFactory struct{ useNumber bool } 33 34 func (d jsonDecoderFactory) Create(reader io.Reader) Decoder { 35 decoder := json.NewDecoder(reader) 36 if d.useNumber { 37 decoder.UseNumber() 38 } 39 return decoder 40 } 41 42 //NewJSONDecoderFactory create a new JSONDecoderFactory 43 func NewJSONDecoderFactory() DecoderFactory { 44 return &jsonDecoderFactory{} 45 } 46 47 //NewJSONDecoderFactoryWithOption create a new JSONDecoderFactory, it takes useNumber decoder parameter 48 func NewJSONDecoderFactoryWithOption(useNumber bool) DecoderFactory { 49 return &jsonDecoderFactory{useNumber: useNumber} 50 } 51 52 type unMarshalerDecoderFactory struct { 53 } 54 55 func (f *unMarshalerDecoderFactory) Create(reader io.Reader) Decoder { 56 return &unMarshalerDecoder{ 57 reader: reader, 58 } 59 } 60 61 type unMarshalerDecoder struct { 62 reader io.Reader 63 provider func() UnMarshaler 64 } 65 66 func (d *unMarshalerDecoder) Decode(v interface{}) error { 67 bytes, err := ioutil.ReadAll(d.reader) 68 if err != nil { 69 return fmt.Errorf("failed to decode %v", err) 70 } 71 result, casted := v.(UnMarshaler) 72 if !casted { 73 return fmt.Errorf("failed to decode - unable cast %T to %s", v, result) 74 } 75 return result.Unmarshal(bytes) 76 } 77 78 //NewUnMarshalerDecoderFactory returns a decoder factory 79 func NewUnMarshalerDecoderFactory() DecoderFactory { 80 return &unMarshalerDecoderFactory{} 81 } 82 83 //DelimitedRecord represents a delimited record 84 type DelimitedRecord struct { 85 Columns []string 86 Delimiter string 87 Record map[string]interface{} 88 } 89 90 //IsEmpty returns true if all values are empty or null 91 func (r *DelimitedRecord) IsEmpty() bool { 92 var result = true 93 for _, value := range r.Record { 94 if value == nil { 95 continue 96 } 97 if AsString(value) == "" || AsString(value) == "<nil>" { 98 continue 99 } 100 return false 101 } 102 return result 103 } 104 105 type delimiterDecoder struct { 106 reader io.Reader 107 } 108 109 func (d *delimiterDecoder) Decode(target interface{}) error { 110 delimitedRecord, ok := target.(*DelimitedRecord) 111 if !ok { 112 return fmt.Errorf("invalid target type, expected %T but had %T", &DelimitedRecord{}, target) 113 } 114 if delimitedRecord.Record == nil { 115 delimitedRecord.Record = make(map[string]interface{}) 116 } 117 var delimiter = delimitedRecord.Delimiter 118 119 payload, err := ioutil.ReadAll(d.reader) 120 if err != nil { 121 return err 122 } 123 reader := csv.NewReader(bytes.NewReader(payload)) 124 reader.Comma = rune(delimiter[0]) 125 hasColumns := len(delimitedRecord.Columns) > 0 126 if !hasColumns { 127 delimitedRecord.Columns = make([]string, 0) 128 } 129 record, err := reader.Read() 130 if IsEOFError(err) { 131 return nil 132 } 133 if err != nil { 134 return err 135 } 136 if len(delimitedRecord.Columns) == 0 { 137 for _, field := range record { 138 delimitedRecord.Columns = append(delimitedRecord.Columns, strings.TrimSpace(field)) 139 } 140 } else { 141 for i, field := range record { 142 delimitedRecord.Record[delimitedRecord.Columns[i]] = field 143 } 144 } 145 return nil 146 } 147 148 type delimiterDecoderFactory struct{} 149 150 func (f *delimiterDecoderFactory) Create(reader io.Reader) Decoder { 151 return &delimiterDecoder{reader: reader} 152 } 153 154 //NewDelimiterDecoderFactory returns a new delimitered decoder factory. 155 func NewDelimiterDecoderFactory() DecoderFactory { 156 return &delimiterDecoderFactory{} 157 } 158 159 type yamlDecoderFactory struct{} 160 161 func (e yamlDecoderFactory) Create(reader io.Reader) Decoder { 162 return &yamlDecoder{reader} 163 } 164 165 type yamlDecoder struct { 166 io.Reader 167 } 168 169 func (d *yamlDecoder) Decode(target interface{}) error { 170 var data, err = ioutil.ReadAll(d.Reader) 171 if err != nil { 172 return fmt.Errorf("failed to read data: %T %v", d.Reader, err) 173 } 174 return yaml.Unmarshal(data, target) 175 } 176 177 //NewYamlDecoderFactory create a new yaml decoder factory 178 func NewYamlDecoderFactory() DecoderFactory { 179 return &yamlDecoderFactory{} 180 } 181 182 type flexYamlDecoderFactory struct{} 183 184 func (e flexYamlDecoderFactory) Create(reader io.Reader) Decoder { 185 return &flexYamlDecoder{reader} 186 } 187 188 type flexYamlDecoder struct { 189 io.Reader 190 } 191 192 //normalizeMap normalizes keyValuePairs from map or slice (map with preserved key order) 193 func (d *flexYamlDecoder) normalizeMap(keyValuePairs interface{}, deep bool) (map[string]interface{}, error) { 194 var result = make(map[string]interface{}) 195 if keyValuePairs == nil { 196 return result, nil 197 } 198 err := ProcessMap(keyValuePairs, func(k, value interface{}) bool { 199 var key = AsString(k) 200 201 //inline map key 202 result[key] = value 203 if deep { 204 if value == nil { 205 return true 206 } 207 if IsMap(value) { 208 if normalized, err := d.normalizeMap(value, deep); err == nil { 209 result[key] = normalized 210 } 211 } else if IsSlice(value) { //yaml style map conversion if applicable 212 aSlice := AsSlice(value) 213 if len(aSlice) == 0 { 214 return true 215 } 216 if IsMap(aSlice[0]) || IsStruct(aSlice[0]) { 217 normalized, err := d.normalizeMap(value, deep) 218 if err == nil { 219 result[key] = normalized 220 } 221 } else if IsSlice(aSlice[0]) { 222 for i, item := range aSlice { 223 itemMap, err := d.normalizeMap(item, deep) 224 if err != nil { 225 return true 226 } 227 aSlice[i] = itemMap 228 } 229 result[key] = aSlice 230 } 231 return true 232 } 233 } 234 return true 235 }) 236 return result, err 237 } 238 239 func (d *flexYamlDecoder) Decode(target interface{}) error { 240 var data, err = ioutil.ReadAll(d.Reader) 241 if err != nil { 242 return fmt.Errorf("failed to read data: %T %v", d.Reader, err) 243 } 244 aMap := map[string]interface{}{} 245 if err := yaml.Unmarshal(data, &aMap); err != nil { 246 return err 247 } 248 if normalized, err := d.normalizeMap(aMap, true); err == nil { 249 aMap = normalized 250 } 251 return DefaultConverter.AssignConverted(target, aMap) 252 } 253 254 //NewFlexYamlDecoderFactory create a new yaml decoder factory 255 func NewFlexYamlDecoderFactory() DecoderFactory { 256 return &flexYamlDecoderFactory{} 257 }