package norm import ( "database/sql" "iter" "reflect" ) type Scanner[T any] struct { rows *sql.Rows scanFunc func(*T) []any onError func(err error) } func NewScanner[T any](rows *sql.Rows) Scanner[T] { return Scanner[T]{ rows: rows, } } func (s Scanner[T]) ScanWith(fn func(*T) []any) iter.Seq2[T, error] { s.scanFunc = fn return s.Scan() } func (s Scanner[T]) Scan() iter.Seq2[T, error] { // If no custom scan function provided, use reflection-based default if s.scanFunc == nil { s.scanFunc = func(dest *T) []any { elem := reflect.ValueOf(dest).Elem() numCols := elem.NumField() columns := make([]any, numCols) for i := range numCols { field := elem.Field(i) columns[i] = field.Addr().Interface() } return columns } } return func(yield func(T, error) bool) { for s.rows.Next() { var data T columns := s.scanFunc(&data) err := s.rows.Scan(columns...) if !yield(data, err) { return } } } } func (s *Scanner[T]) Close() error { return s.rows.Close() } func ScanAll[T any](rows *sql.Rows, dest *[]T) error { scanner := NewScanner[T](rows) defer scanner.Close() for elem, err := range scanner.Scan() { if err != nil { return err } *dest = append(*dest, elem) } return nil } func Scan[T any](row *sql.Row, dest *T) error { elem := reflect.ValueOf(dest).Elem() numCols := elem.NumField() columns := make([]any, numCols) for i := range numCols { field := elem.Field(i) columns[i] = field.Addr().Interface() } return row.Scan(columns...) }