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  }