// Package sqlr ("squealer") provides some convenience wrappers around // database/sql in the spirit of encoding/json. package sqlr import ( "database/sql" "fmt" "reflect" ) // Scan calls rows.Scan to unpack a single row into the fields of v. func Scan(rows *sql.Rows, v any) error { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Pointer || rv.Elem().Kind() != reflect.Struct { return fmt.Errorf("Scan needs a pointer to a struct") } inner := rv.Elem() innerType := inner.Type() fields := make(map[string]reflect.StructField) inner.FieldByNameFunc(func(fieldName string) bool { field, ok := innerType.FieldByName(fieldName) if !ok { return false } tag, ok := field.Tag.Lookup("sql") if !ok { fields[fieldName] = field return false } if tag != "-" { fields[tag] = field } return false }) cols, err := rows.Columns() if err != nil { return err } dest := make([]any, len(cols)) for i, c := range cols { field, ok := fields[c] if !ok { return fmt.Errorf("no field with tag %q", c) } dest[i] = inner.FieldByIndex(field.Index).Addr().Interface() } return rows.Scan(dest...) }