github.com/hamba/avro@v1.8.0/reader_generic.go (about)

     1  package avro
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  )
     7  
     8  // ReadNext reads the next Avro element as a generic interface.
     9  func (r *Reader) ReadNext(schema Schema) interface{} {
    10  	var ls LogicalSchema
    11  	lts, ok := schema.(LogicalTypeSchema)
    12  	if ok {
    13  		ls = lts.Logical()
    14  	}
    15  
    16  	switch schema.Type() {
    17  	case Boolean:
    18  		return r.ReadBool()
    19  
    20  	case Int:
    21  		if ls != nil {
    22  			switch ls.Type() {
    23  			case Date:
    24  				i := r.ReadInt()
    25  				sec := int64(i) * int64(24*time.Hour/time.Second)
    26  				return time.Unix(sec, 0).UTC()
    27  
    28  			case TimeMillis:
    29  				return time.Duration(r.ReadInt()) * time.Millisecond
    30  			}
    31  		}
    32  		return int(r.ReadInt())
    33  
    34  	case Long:
    35  		if ls != nil {
    36  			switch ls.Type() {
    37  			case TimeMicros:
    38  				return time.Duration(r.ReadLong()) * time.Microsecond
    39  
    40  			case TimestampMillis:
    41  				i := r.ReadLong()
    42  				sec := i / 1e3
    43  				nsec := (i - sec*1e3) * 1e6
    44  				return time.Unix(sec, nsec).UTC()
    45  
    46  			case TimestampMicros:
    47  				i := r.ReadLong()
    48  				sec := i / 1e6
    49  				nsec := (i - sec*1e6) * 1e3
    50  				return time.Unix(sec, nsec).UTC()
    51  			}
    52  		}
    53  		return r.ReadLong()
    54  
    55  	case Float:
    56  		return r.ReadFloat()
    57  
    58  	case Double:
    59  		return r.ReadDouble()
    60  
    61  	case String:
    62  		return r.ReadString()
    63  
    64  	case Bytes:
    65  		if ls != nil && ls.Type() == Decimal {
    66  			dec := ls.(*DecimalLogicalSchema)
    67  			return ratFromBytes(r.ReadBytes(), dec.Scale())
    68  		}
    69  		return r.ReadBytes()
    70  
    71  	case Record:
    72  		fields := schema.(*RecordSchema).Fields()
    73  		obj := make(map[string]interface{}, len(fields))
    74  		for _, field := range fields {
    75  			obj[field.Name()] = r.ReadNext(field.Type())
    76  		}
    77  		return obj
    78  
    79  	case Ref:
    80  		return r.ReadNext(schema.(*RefSchema).Schema())
    81  
    82  	case Enum:
    83  		symbols := schema.(*EnumSchema).Symbols()
    84  		idx := int(r.ReadInt())
    85  		if idx < 0 || idx >= len(symbols) {
    86  			r.ReportError("Read", "unknown enum symbol")
    87  			return nil
    88  		}
    89  		return symbols[idx]
    90  
    91  	case Array:
    92  		arr := []interface{}{}
    93  		r.ReadArrayCB(func(r *Reader) bool {
    94  			elem := r.ReadNext(schema.(*ArraySchema).Items())
    95  			arr = append(arr, elem)
    96  			return true
    97  		})
    98  		return arr
    99  
   100  	case Map:
   101  		obj := map[string]interface{}{}
   102  		r.ReadMapCB(func(r *Reader, field string) bool {
   103  			elem := r.ReadNext(schema.(*MapSchema).Values())
   104  			obj[field] = elem
   105  			return true
   106  		})
   107  		return obj
   108  
   109  	case Union:
   110  		types := schema.(*UnionSchema).Types()
   111  		idx := int(r.ReadLong())
   112  		if idx < 0 || idx > len(types)-1 {
   113  			r.ReportError("Read", "unknown union type")
   114  			return nil
   115  		}
   116  		schema := types[idx]
   117  		if schema.Type() == Null {
   118  			return nil
   119  		}
   120  
   121  		key := schemaTypeName(schema)
   122  		obj := map[string]interface{}{}
   123  		obj[key] = r.ReadNext(types[idx])
   124  
   125  		return obj
   126  
   127  	case Fixed:
   128  		size := schema.(*FixedSchema).Size()
   129  		obj := make([]byte, size)
   130  		r.Read(obj)
   131  		if ls != nil && ls.Type() == Decimal {
   132  			dec := ls.(*DecimalLogicalSchema)
   133  			return ratFromBytes(obj, dec.Scale())
   134  		}
   135  		return obj
   136  
   137  	default:
   138  		r.ReportError("Read", fmt.Sprintf("unexpected schema type: %v", schema.Type()))
   139  		return nil
   140  	}
   141  }
   142  
   143  // ReadArrayCB reads an array with a callback per item.
   144  func (r *Reader) ReadArrayCB(callback func(*Reader) bool) {
   145  	for {
   146  		l, _ := r.ReadBlockHeader()
   147  		if l == 0 {
   148  			break
   149  		}
   150  
   151  		for i := 0; i < int(l); i++ {
   152  			callback(r)
   153  		}
   154  	}
   155  }
   156  
   157  // ReadMapCB reads an array with a callback per item.
   158  func (r *Reader) ReadMapCB(callback func(*Reader, string) bool) {
   159  	for {
   160  		l, _ := r.ReadBlockHeader()
   161  		if l == 0 {
   162  			break
   163  		}
   164  
   165  		for i := 0; i < int(l); i++ {
   166  			field := r.ReadString()
   167  			callback(r, field)
   168  		}
   169  	}
   170  }