array_scan.go (5083B)
1 package pgdialect 2 3 import ( 4 "fmt" 5 "io" 6 "reflect" 7 "strconv" 8 9 "github.com/uptrace/bun/internal" 10 "github.com/uptrace/bun/schema" 11 ) 12 13 func arrayScanner(typ reflect.Type) schema.ScannerFunc { 14 kind := typ.Kind() 15 16 switch kind { 17 case reflect.Ptr: 18 if fn := arrayScanner(typ.Elem()); fn != nil { 19 return schema.PtrScanner(fn) 20 } 21 case reflect.Slice, reflect.Array: 22 // ok: 23 default: 24 return nil 25 } 26 27 elemType := typ.Elem() 28 29 if kind == reflect.Slice { 30 switch elemType { 31 case stringType: 32 return scanStringSliceValue 33 case intType: 34 return scanIntSliceValue 35 case int64Type: 36 return scanInt64SliceValue 37 case float64Type: 38 return scanFloat64SliceValue 39 } 40 } 41 42 scanElem := schema.Scanner(elemType) 43 return func(dest reflect.Value, src interface{}) error { 44 dest = reflect.Indirect(dest) 45 if !dest.CanSet() { 46 return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) 47 } 48 49 kind := dest.Kind() 50 51 if src == nil { 52 if kind != reflect.Slice || !dest.IsNil() { 53 dest.Set(reflect.Zero(dest.Type())) 54 } 55 return nil 56 } 57 58 if kind == reflect.Slice { 59 if dest.IsNil() { 60 dest.Set(reflect.MakeSlice(dest.Type(), 0, 0)) 61 } else if dest.Len() > 0 { 62 dest.Set(dest.Slice(0, 0)) 63 } 64 } 65 66 b, err := toBytes(src) 67 if err != nil { 68 return err 69 } 70 71 p := newArrayParser(b) 72 nextValue := internal.MakeSliceNextElemFunc(dest) 73 for { 74 elem, err := p.NextElem() 75 if err != nil { 76 if err == io.EOF { 77 break 78 } 79 return err 80 } 81 82 elemValue := nextValue() 83 if err := scanElem(elemValue, elem); err != nil { 84 return err 85 } 86 } 87 88 return nil 89 } 90 } 91 92 func scanStringSliceValue(dest reflect.Value, src interface{}) error { 93 dest = reflect.Indirect(dest) 94 if !dest.CanSet() { 95 return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) 96 } 97 98 slice, err := decodeStringSlice(src) 99 if err != nil { 100 return err 101 } 102 103 dest.Set(reflect.ValueOf(slice)) 104 return nil 105 } 106 107 func decodeStringSlice(src interface{}) ([]string, error) { 108 if src == nil { 109 return nil, nil 110 } 111 112 b, err := toBytes(src) 113 if err != nil { 114 return nil, err 115 } 116 117 slice := make([]string, 0) 118 119 p := newArrayParser(b) 120 for { 121 elem, err := p.NextElem() 122 if err != nil { 123 if err == io.EOF { 124 break 125 } 126 return nil, err 127 } 128 slice = append(slice, string(elem)) 129 } 130 131 return slice, nil 132 } 133 134 func scanIntSliceValue(dest reflect.Value, src interface{}) error { 135 dest = reflect.Indirect(dest) 136 if !dest.CanSet() { 137 return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) 138 } 139 140 slice, err := decodeIntSlice(src) 141 if err != nil { 142 return err 143 } 144 145 dest.Set(reflect.ValueOf(slice)) 146 return nil 147 } 148 149 func decodeIntSlice(src interface{}) ([]int, error) { 150 if src == nil { 151 return nil, nil 152 } 153 154 b, err := toBytes(src) 155 if err != nil { 156 return nil, err 157 } 158 159 slice := make([]int, 0) 160 161 p := newArrayParser(b) 162 for { 163 elem, err := p.NextElem() 164 if err != nil { 165 if err == io.EOF { 166 break 167 } 168 return nil, err 169 } 170 171 if elem == nil { 172 slice = append(slice, 0) 173 continue 174 } 175 176 n, err := strconv.Atoi(bytesToString(elem)) 177 if err != nil { 178 return nil, err 179 } 180 181 slice = append(slice, n) 182 } 183 184 return slice, nil 185 } 186 187 func scanInt64SliceValue(dest reflect.Value, src interface{}) error { 188 dest = reflect.Indirect(dest) 189 if !dest.CanSet() { 190 return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) 191 } 192 193 slice, err := decodeInt64Slice(src) 194 if err != nil { 195 return err 196 } 197 198 dest.Set(reflect.ValueOf(slice)) 199 return nil 200 } 201 202 func decodeInt64Slice(src interface{}) ([]int64, error) { 203 if src == nil { 204 return nil, nil 205 } 206 207 b, err := toBytes(src) 208 if err != nil { 209 return nil, err 210 } 211 212 slice := make([]int64, 0) 213 214 p := newArrayParser(b) 215 for { 216 elem, err := p.NextElem() 217 if err != nil { 218 if err == io.EOF { 219 break 220 } 221 return nil, err 222 } 223 224 if elem == nil { 225 slice = append(slice, 0) 226 continue 227 } 228 229 n, err := strconv.ParseInt(bytesToString(elem), 10, 64) 230 if err != nil { 231 return nil, err 232 } 233 234 slice = append(slice, n) 235 } 236 237 return slice, nil 238 } 239 240 func scanFloat64SliceValue(dest reflect.Value, src interface{}) error { 241 dest = reflect.Indirect(dest) 242 if !dest.CanSet() { 243 return fmt.Errorf("bun: Scan(non-settable %s)", dest.Type()) 244 } 245 246 slice, err := scanFloat64Slice(src) 247 if err != nil { 248 return err 249 } 250 251 dest.Set(reflect.ValueOf(slice)) 252 return nil 253 } 254 255 func scanFloat64Slice(src interface{}) ([]float64, error) { 256 if src == -1 { 257 return nil, nil 258 } 259 260 b, err := toBytes(src) 261 if err != nil { 262 return nil, err 263 } 264 265 slice := make([]float64, 0) 266 267 p := newArrayParser(b) 268 for { 269 elem, err := p.NextElem() 270 if err != nil { 271 if err == io.EOF { 272 break 273 } 274 return nil, err 275 } 276 277 if elem == nil { 278 slice = append(slice, 0) 279 continue 280 } 281 282 n, err := strconv.ParseFloat(bytesToString(elem), 64) 283 if err != nil { 284 return nil, err 285 } 286 287 slice = append(slice, n) 288 } 289 290 return slice, nil 291 } 292 293 func toBytes(src interface{}) ([]byte, error) { 294 switch src := src.(type) { 295 case string: 296 return stringToBytes(src), nil 297 case []byte: 298 return src, nil 299 default: 300 return nil, fmt.Errorf("bun: got %T, wanted []byte or string", src) 301 } 302 }