github.com/RevenueMonster/sqlike@v1.0.6/sqlike/result.go (about) 1 package sqlike 2 3 import ( 4 "database/sql" 5 "io" 6 "reflect" 7 8 "errors" 9 10 "github.com/RevenueMonster/sqlike/reflext" 11 "github.com/RevenueMonster/sqlike/sql/codec" 12 ) 13 14 // Resulter : 15 type Resulter interface { 16 Scan(dests ...interface{}) error 17 Columns() []string 18 Next() bool 19 NextResultSet() bool 20 Close() error 21 } 22 23 // ErrNoRows : is an alias for no record found 24 var ErrNoRows = sql.ErrNoRows 25 26 // EOF : is an alias for end of file 27 var EOF = io.EOF 28 29 // Result : 30 type Result struct { 31 close bool 32 rows *sql.Rows 33 codec codec.Codecer 34 cache reflext.StructMapper 35 columns []string 36 columnTypes []*sql.ColumnType 37 err error 38 } 39 40 var _ Resulter = (*Result)(nil) 41 42 // Columns : 43 func (r *Result) Columns() []string { 44 return r.columns 45 } 46 47 // ColumnTypes : 48 func (r *Result) ColumnTypes() ([]*sql.ColumnType, error) { 49 return r.columnTypes, nil 50 } 51 52 func (r *Result) nextValues() ([]interface{}, error) { 53 if !r.Next() { 54 return nil, EOF 55 } 56 return r.values() 57 } 58 59 func (r *Result) values() ([]interface{}, error) { 60 length := len(r.columns) 61 values := make([]interface{}, length) 62 for j := 0; j < length; j++ { 63 values[j] = &values[j] 64 } 65 if err := r.rows.Scan(values...); err != nil { 66 return nil, err 67 } 68 return values, nil 69 } 70 71 // Scan : will behave as similar as sql.Scan. 72 func (r *Result) Scan(dests ...interface{}) error { 73 defer r.Close() 74 if r.err != nil { 75 return r.err 76 } 77 if len(dests) == 0 { 78 return errors.New("sqlike: empty destination to scan") 79 } 80 values, err := r.values() 81 if err != nil { 82 return err 83 } 84 max := len(dests) 85 for i, v := range values { 86 if i >= max { 87 break 88 } 89 fv := reflext.ValueOf(dests[i]) 90 if fv.Kind() != reflect.Ptr { 91 return ErrUnaddressableEntity 92 } 93 fv = reflext.IndirectInit(fv) 94 decoder, err := r.codec.LookupDecoder(fv.Type()) 95 if err != nil { 96 return err 97 } 98 if err := decoder(v, fv); err != nil { 99 return err 100 } 101 } 102 return r.Close() 103 } 104 105 // Decode will decode the current document into val, this will only accepting pointer of struct as an input. 106 func (r *Result) Decode(dst interface{}) error { 107 if r.close { 108 defer r.Close() 109 } 110 if r.err != nil { 111 return r.err 112 } 113 114 v := reflext.ValueOf(dst) 115 if !v.IsValid() { 116 return ErrInvalidInput 117 } 118 119 t := v.Type() 120 if !reflext.IsKind(t, reflect.Ptr) { 121 return ErrUnaddressableEntity 122 } 123 124 t = reflext.Deref(t) 125 if !reflext.IsKind(t, reflect.Struct) { 126 return errors.New("sqlike: it must be a struct to decode") 127 } 128 129 idxs := r.cache.TraversalsByName(t, r.columns) 130 values, err := r.values() 131 if err != nil { 132 return err 133 } 134 vv := reflext.Zero(t) 135 for j, idx := range idxs { 136 if idx == nil { 137 continue 138 } 139 fv := r.cache.FieldByIndexes(vv, idx) 140 decoder, err := r.codec.LookupDecoder(fv.Type()) 141 if err != nil { 142 return err 143 } 144 if err := decoder(values[j], fv); err != nil { 145 return err 146 } 147 } 148 reflext.IndirectInit(v).Set(reflext.Indirect(vv)) 149 if r.close { 150 return r.Close() 151 } 152 return nil 153 } 154 155 // ScanSlice : 156 func (r *Result) ScanSlice(results interface{}) error { 157 defer r.Close() 158 if r.err != nil { 159 return r.err 160 } 161 162 v := reflext.ValueOf(results) 163 if !v.IsValid() { 164 return ErrInvalidInput 165 } 166 167 if !reflext.IsKind(v.Type(), reflect.Ptr) { 168 return ErrUnaddressableEntity 169 } 170 171 v = reflext.Indirect(v) 172 t := v.Type() 173 if !reflext.IsKind(t, reflect.Slice) { 174 return errors.New("sqlike: it must be a slice of entity") 175 } 176 177 slice := reflect.MakeSlice(t, 0, 0) 178 t = t.Elem() 179 180 for i := 0; r.rows.Next(); i++ { 181 values, err := r.values() 182 if err != nil { 183 return err 184 } 185 slice = reflect.Append(slice, reflext.Zero(t)) 186 fv := slice.Index(i) 187 decoder, err := r.codec.LookupDecoder(fv.Type()) 188 if err != nil { 189 return err 190 } 191 if err := decoder(values[0], fv); err != nil { 192 return err 193 } 194 } 195 v.Set(slice) 196 return r.rows.Close() 197 } 198 199 // All : this will map all the records from sql to a slice of struct. 200 func (r *Result) All(results interface{}) error { 201 defer r.Close() 202 if r.err != nil { 203 return r.err 204 } 205 206 v := reflext.ValueOf(results) 207 if !v.IsValid() { 208 return ErrInvalidInput 209 } 210 211 if !reflext.IsKind(v.Type(), reflect.Ptr) { 212 return ErrUnaddressableEntity 213 } 214 215 v = reflext.Indirect(v) 216 t := v.Type() 217 if !reflext.IsKind(t, reflect.Slice) { 218 return errors.New("sqlike: it must be a slice of entity") 219 } 220 221 length := len(r.columns) 222 slice := reflect.MakeSlice(t, 0, 0) 223 t = t.Elem() 224 idxs := r.cache.TraversalsByName(t, r.columns) 225 decoders := make([]codec.ValueDecoder, length) 226 for i := 0; r.rows.Next(); i++ { 227 values, err := r.values() 228 if err != nil { 229 return err 230 } 231 vv := reflext.Zero(t) 232 for j, idx := range idxs { 233 if idx == nil { 234 continue 235 } 236 fv := r.cache.FieldByIndexes(vv, idx) 237 if i < 1 { 238 decoder, err := r.codec.LookupDecoder(fv.Type()) 239 if err != nil { 240 return err 241 } 242 decoders[j] = decoder 243 } 244 if err := decoders[j](values[j], fv); err != nil { 245 return err 246 } 247 } 248 slice = reflect.Append(slice, vv) 249 } 250 v.Set(slice) 251 return r.rows.Close() 252 } 253 254 // Error : 255 func (r *Result) Error() error { 256 if r.rows != nil { 257 defer r.rows.Close() 258 } 259 return r.err 260 } 261 262 // Next : 263 func (r *Result) Next() bool { 264 return r.rows.Next() 265 } 266 267 // NextResultSet : 268 func (r *Result) NextResultSet() bool { 269 return r.rows.NextResultSet() 270 } 271 272 // Close : 273 func (r *Result) Close() error { 274 if r.rows != nil { 275 return r.rows.Close() 276 } 277 return nil 278 }