github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/s3select/simdj/record.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package simdj 19 20 import ( 21 "fmt" 22 "io" 23 24 "github.com/bcicen/jstream" 25 csv "github.com/minio/csvparser" 26 "github.com/minio/minio/internal/s3select/json" 27 "github.com/minio/minio/internal/s3select/sql" 28 "github.com/minio/simdjson-go" 29 ) 30 31 // Record - is JSON record. 32 type Record struct { 33 // object 34 object simdjson.Object 35 } 36 37 // Get - gets the value for a column name. 38 func (r *Record) Get(name string) (*sql.Value, error) { 39 elem := r.object.FindKey(name, nil) 40 if elem == nil { 41 return nil, nil 42 } 43 return iterToValue(elem.Iter) 44 } 45 46 func iterToValue(iter simdjson.Iter) (*sql.Value, error) { 47 switch iter.Type() { 48 case simdjson.TypeString: 49 v, err := iter.String() 50 if err != nil { 51 return nil, err 52 } 53 return sql.FromString(v), nil 54 case simdjson.TypeFloat: 55 v, err := iter.Float() 56 if err != nil { 57 return nil, err 58 } 59 return sql.FromFloat(v), nil 60 case simdjson.TypeInt: 61 v, err := iter.Int() 62 if err != nil { 63 return nil, err 64 } 65 return sql.FromInt(v), nil 66 case simdjson.TypeUint: 67 v, err := iter.Int() 68 if err != nil { 69 // Can't fit into int, convert to float. 70 v, err := iter.Float() 71 return sql.FromFloat(v), err 72 } 73 return sql.FromInt(v), nil 74 case simdjson.TypeBool: 75 v, err := iter.Bool() 76 if err != nil { 77 return nil, err 78 } 79 return sql.FromBool(v), nil 80 case simdjson.TypeNull: 81 return sql.FromNull(), nil 82 case simdjson.TypeObject, simdjson.TypeArray: 83 b, err := iter.MarshalJSON() 84 return sql.FromBytes(b), err 85 } 86 return nil, fmt.Errorf("iterToValue: unknown JSON type: %s", iter.Type().String()) 87 } 88 89 // Reset the record. 90 func (r *Record) Reset() { 91 r.object = simdjson.Object{} 92 } 93 94 // Clone the record and if possible use the destination provided. 95 func (r *Record) Clone(dst sql.Record) sql.Record { 96 other, ok := dst.(*Record) 97 if !ok { 98 other = &Record{} 99 } 100 other.object = r.object 101 return other 102 } 103 104 // CloneTo clones the record to a json Record. 105 // Values are only unmashaled on object level. 106 func (r *Record) CloneTo(dst *json.Record) (sql.Record, error) { 107 if dst == nil { 108 dst = &json.Record{SelectFormat: sql.SelectFmtJSON} 109 } 110 dst.Reset() 111 elems, err := r.object.Parse(nil) 112 if err != nil { 113 return nil, err 114 } 115 if cap(dst.KVS) < len(elems.Elements) { 116 dst.KVS = make(jstream.KVS, 0, len(elems.Elements)) 117 } 118 for _, elem := range elems.Elements { 119 v, err := sql.IterToValue(elem.Iter) 120 if err != nil { 121 v, err = elem.Iter.Interface() 122 if err != nil { 123 panic(err) 124 } 125 } 126 dst.KVS = append(dst.KVS, jstream.KV{ 127 Key: elem.Name, 128 Value: v, 129 }) 130 } 131 return dst, nil 132 } 133 134 // Set - sets the value for a column name. 135 func (r *Record) Set(name string, value *sql.Value) (sql.Record, error) { 136 dst, err := r.CloneTo(nil) 137 if err != nil { 138 return nil, err 139 } 140 return dst.Set(name, value) 141 } 142 143 // WriteCSV - encodes to CSV data. 144 func (r *Record) WriteCSV(writer io.Writer, opts sql.WriteCSVOpts) error { 145 csvRecord := make([]string, 0, 10) 146 var tmp simdjson.Iter 147 obj := r.object 148 allElems: 149 for { 150 _, typ, err := obj.NextElement(&tmp) 151 if err != nil { 152 return err 153 } 154 var columnValue string 155 switch typ { 156 case simdjson.TypeNull, simdjson.TypeFloat, simdjson.TypeUint, simdjson.TypeInt, simdjson.TypeBool, simdjson.TypeString: 157 val, err := tmp.StringCvt() 158 if err != nil { 159 return err 160 } 161 columnValue = val 162 case simdjson.TypeObject, simdjson.TypeArray: 163 b, err := tmp.MarshalJSON() 164 if err != nil { 165 return err 166 } 167 columnValue = string(b) 168 case simdjson.TypeNone: 169 break allElems 170 default: 171 return fmt.Errorf("cannot marshal unhandled type: %s", typ.String()) 172 } 173 csvRecord = append(csvRecord, columnValue) 174 } 175 w := csv.NewWriter(writer) 176 w.Comma = opts.FieldDelimiter 177 w.Quote = opts.Quote 178 w.QuoteEscape = opts.QuoteEscape 179 w.AlwaysQuote = opts.AlwaysQuote 180 if err := w.Write(csvRecord); err != nil { 181 return err 182 } 183 w.Flush() 184 return w.Error() 185 } 186 187 // Raw - returns the underlying representation. 188 func (r *Record) Raw() (sql.SelectObjectFormat, interface{}) { 189 return sql.SelectFmtSIMDJSON, r.object 190 } 191 192 // WriteJSON - encodes to JSON data. 193 func (r *Record) WriteJSON(writer io.Writer) error { 194 o := r.object 195 elems, err := o.Parse(nil) 196 if err != nil { 197 return err 198 } 199 b, err := elems.MarshalJSON() 200 if err != nil { 201 return err 202 } 203 n, err := writer.Write(b) 204 if err != nil { 205 return err 206 } 207 if n != len(b) { 208 return io.ErrShortWrite 209 } 210 return nil 211 } 212 213 // Replace the underlying buffer of json data. 214 func (r *Record) Replace(k interface{}) error { 215 v, ok := k.(simdjson.Object) 216 if !ok { 217 return fmt.Errorf("cannot replace internal data in simd json record with type %T", k) 218 } 219 r.object = v 220 return nil 221 } 222 223 // NewRecord - creates new empty JSON record. 224 func NewRecord(f sql.SelectObjectFormat, obj simdjson.Object) *Record { 225 return &Record{ 226 object: obj, 227 } 228 }