Copyright 2019 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package database

import (
	
	
	
	
	
	
	
	

	
)
StructScanner takes a struct and returns a function that, when called on a struct pointer of that type, returns a slice of arguments suitable for Row.Scan or Rows.Scan. The call to either Scan will populate the exported fields of the struct in the order they appear in the type definition. StructScanner panics if p is not a struct or a pointer to a struct. The function it returns will panic if its argument is not a pointer to a struct. Example: type Player struct { Name string; Score int } playerScanArgs := database.StructScanner(Player{}) err := db.RunQuery(ctx, "SELECT name, score FROM players", func(rows *sql.Rows) error { var p Player if err := rows.Scan(playerScanArgs(&p)...); err != nil { return err } // use p return nil })
func ( interface{}) func( interface{}) []interface{} {
	 := reflect.ValueOf()
	if .Kind() == reflect.Ptr {
		 = .Elem()
	}
	return structScannerForType(.Type())
}

type fieldInfo struct {
	num  int // to pass to v.Field
	kind reflect.Kind
}

func ( reflect.Type) func( interface{}) []interface{} {
	if .Kind() != reflect.Struct {
		panic(fmt.Sprintf("%s is not a struct", ))
	}
Collect the numbers of the exported fields.
	var  []fieldInfo
	for  := 0;  < .NumField(); ++ {
		,  := utf8.DecodeRuneInString(.Field().Name)
		if unicode.IsUpper() {
			 = append(, fieldInfo{, .Field().Type.Kind()})
		}
Return a function that gets pointers to the exported fields.
	return func( interface{}) []interface{} {
		 := reflect.ValueOf().Elem()
		var  []interface{}
		for ,  := range  {
			 := .Field(.num).Addr().Interface()
			switch .kind {
			case reflect.Slice:
				if ,  := .(*[]byte); ! {
					 = pq.Array()
				}
			case reflect.Ptr:
				 = NullPtr()
			default:
			}
			 = append(, )
		}
		return 
	}
}
NullPtr is for scanning nullable database columns into pointer variables or fields. When given a pointer to to a pointer to some type T, it returns a value that can be passed to a Scan function. If the corresponding column is nil, the variable will be set to nil. Otherwise, it will be set to a newly allocated pointer to the column value.
func ( interface{}) nullPtr {
	 := reflect.ValueOf()
	if .Kind() != reflect.Ptr || .Elem().Kind() != reflect.Ptr {
		panic("NullPtr arg must be pointer to pointer")
	}
	return nullPtr{}
}

ptr is a pointer to a pointer to something: **T
n.ptr is like a variable v of type **T
	 := .ptr.Elem().Type() // T
	if  == nil {
		.ptr.Elem().Set(reflect.Zero()) // *v = nil
	} else {
		 := reflect.New(.Elem())       // p := new(T)
		.Elem().Set(reflect.ValueOf()) // *p = value
		.ptr.Elem().Set()                  // *v = p
	}
	return nil
}

func ( nullPtr) () (driver.Value, error) {
	if .ptr.Elem().IsNil() {
		return nil, nil
	}
	return .ptr.Elem().Elem().Interface(), nil
}
CollectStructs scans the the rows from the query into structs and appends them to pslice, which must be a pointer to a slice of structs. Example: type Player struct { Name string; Score int } var players []Player err := db.CollectStructs(ctx, &players, "SELECT name, score FROM players")
func ( *DB) ( context.Context,  interface{},  string,  ...interface{}) error {
	 := reflect.ValueOf()
	if .Kind() != reflect.Ptr {
		return errors.New("collectStructs: arg is not a pointer")
	}
	 := .Elem()
	if .Kind() != reflect.Slice {
		return errors.New("collectStructs: arg is not a pointer to a slice")
	}
	 := false
	 := .Type().Elem() // slice element type
	if .Kind() == reflect.Ptr {
		 = true
		 = .Elem()
	}
	if .Kind() != reflect.Struct {
		return fmt.Errorf("slice element type is neither struct nor struct pointer: %s", .Type().Elem())
	}

	 := structScannerForType()
	 := .RunQuery(, , func( *sql.Rows) error {
		 := reflect.New()
		if  := .Scan((.Interface())...);  != nil {
			return 
		}
		if ! {
			 = .Elem()
		}
		 = reflect.Append(, )
		return nil
	}, ...)
	if  != nil {
		return 
	}
	.Elem().Set()
	return nil