func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) { t = reflectx.Deref(t) if t.Kind() != expected { return nil, fmt.Errorf("expected %s but got %s", expected, t.Kind()) } return t, nil }
func (r *Row) scanAny(dest interface{}, structOnly bool) error { if r.err != nil { return r.err } defer r.rows.Close() v := reflect.ValueOf(dest) if v.Kind() != reflect.Ptr { return errors.New("must pass a pointer, not a value, to StructScan destination") } if v.IsNil() { return errors.New("nil pointer passed to StructScan destination") } base := reflectx.Deref(v.Type()) scannable := isScannable(base) if structOnly && scannable { return structOnlyError(base) } columns, err := r.Columns() if err != nil { return err } if scannable && len(columns) > 1 { return fmt.Errorf("scannable dest type %s with >1 columns (%d) in result", base.Kind(), len(columns)) } if scannable { return r.Scan(dest) } m := r.Mapper fields := m.TraversalsByName(v.Type(), columns) // if we are not unsafe and are missing fields, return an error if f, err := missingFields(fields); err != nil && !r.unsafe { return fmt.Errorf("missing destination name %s", columns[f]) } values := make([]interface{}, len(columns)) err = fieldsByTraversal(v, fields, values, true) if err != nil { return err } // scan into the struct field pointers and append to our results return r.Scan(values...) }
// In expands slice values in args, returning the modified query string // and a new arg list that can be executed by a database. The `query` should // use the `?` bindVar. The return value uses the `?` bindVar. func In(query string, args ...interface{}) (string, []interface{}, error) { // argMeta stores reflect.Value and length for slices and // the value itself for non-slice arguments type argMeta struct { v reflect.Value i interface{} length int } var flatArgsCount int var anySlices bool meta := make([]argMeta, len(args)) for i, arg := range args { v := reflect.ValueOf(arg) t := reflectx.Deref(v.Type()) if t.Kind() == reflect.Slice { meta[i].length = v.Len() meta[i].v = v anySlices = true flatArgsCount += meta[i].length if meta[i].length == 0 { return "", nil, errors.New("empty slice passed to 'in' query") } } else { meta[i].i = arg flatArgsCount++ } } // don't do any parsing if there aren't any slices; note that this means // some errors that we might have caught below will not be returned. if !anySlices { return query, args, nil } newArgs := make([]interface{}, 0, flatArgsCount) var arg, offset int var buf bytes.Buffer for i := strings.IndexByte(query[offset:], '?'); i != -1; i = strings.IndexByte(query[offset:], '?') { if arg >= len(meta) { // if an argument wasn't passed, lets return an error; this is // not actually how database/sql Exec/Query works, but since we are // creating an argument list programmatically, we want to be able // to catch these programmer errors earlier. return "", nil, errors.New("number of bindVars exceeds arguments") } argMeta := meta[arg] arg++ // not a slice, continue. // our questionmark will either be written before the next expansion // of a slice or after the loop when writing the rest of the query if argMeta.length == 0 { offset = offset + i + 1 newArgs = append(newArgs, argMeta.i) continue } // write everything up to and including our ? character buf.WriteString(query[:offset+i+1]) newArgs = append(newArgs, argMeta.v.Index(0).Interface()) for si := 1; si < argMeta.length; si++ { buf.WriteString(", ?") newArgs = append(newArgs, argMeta.v.Index(si).Interface()) } // slice the query and reset the offset. this avoids some bookkeeping for // the write after the loop query = query[offset+i+1:] offset = 0 } buf.WriteString(query) if arg < len(meta) { return "", nil, errors.New("number of bindVars less than number arguments") } return buf.String(), newArgs, nil }
// scanAll scans all rows into a destination, which must be a slice of any // type. If the destination slice type is a Struct, then StructScan will be // used on each row. If the destination is some other kind of base type, then // each row must only have one column which can scan into that type. This // allows you to do something like: // // rows, _ := db.Query("select id from people;") // var ids []int // scanAll(rows, &ids, false) // // and ids will be a list of the id results. I realize that this is a desirable // interface to expose to users, but for now it will only be exposed via changes // to `Get` and `Select`. The reason that this has been implemented like this is // this is the only way to not duplicate reflect work in the new API while // maintaining backwards compatibility. func scanAll(rows rowsi, dest interface{}, structOnly bool) error { var v, vp reflect.Value value := reflect.ValueOf(dest) // json.Unmarshal returns errors for these if value.Kind() != reflect.Ptr { return errors.New("must pass a pointer, not a value, to StructScan destination") } if value.IsNil() { return errors.New("nil pointer passed to StructScan destination") } direct := reflect.Indirect(value) slice, err := baseType(value.Type(), reflect.Slice) if err != nil { return err } isPtr := slice.Elem().Kind() == reflect.Ptr base := reflectx.Deref(slice.Elem()) scannable := isScannable(base) if structOnly && scannable { return structOnlyError(base) } columns, err := rows.Columns() if err != nil { return err } // if it's a base type make sure it only has 1 column; if not return an error if scannable && len(columns) > 1 { return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(columns)) } if !scannable { var values []interface{} var m *reflectx.Mapper switch rows.(type) { case *Rows: m = rows.(*Rows).Mapper default: m = mapper() } fields := m.TraversalsByName(base, columns) // if we are not unsafe and are missing fields, return an error if f, err := missingFields(fields); err != nil && !isUnsafe(rows) { return fmt.Errorf("missing destination name %s", columns[f]) } values = make([]interface{}, len(columns)) for rows.Next() { // create a new struct type (which returns PtrTo) and indirect it vp = reflect.New(base) v = reflect.Indirect(vp) err = fieldsByTraversal(v, fields, values, true) // scan into the struct field pointers and append to our results err = rows.Scan(values...) if err != nil { return err } if isPtr { direct.Set(reflect.Append(direct, vp)) } else { direct.Set(reflect.Append(direct, v)) } } } else { for rows.Next() { vp = reflect.New(base) err = rows.Scan(vp.Interface()) // append if isPtr { direct.Set(reflect.Append(direct, vp)) } else { direct.Set(reflect.Append(direct, reflect.Indirect(vp))) } } } return rows.Err() }