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 }