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  }