diff options
Diffstat (limited to 'sqlr.go')
| -rw-r--r-- | sqlr.go | 51 |
1 files changed, 51 insertions, 0 deletions
@@ -0,0 +1,51 @@ +// 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...) +} |
