this repo has no description
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

introduce ScanWith to supply custom scanner funcs

Signed-off-by: oppiliappan <me@oppi.li>

+84 -7
+21 -7
scanner.go
··· 7 7 ) 8 8 9 9 type Scanner[T any] struct { 10 - rows *sql.Rows 11 - onError func(err error) 10 + rows *sql.Rows 11 + scanFunc func(*T) []any 12 + onError func(err error) 12 13 } 13 14 14 15 func NewScanner[T any](rows *sql.Rows) Scanner[T] { ··· 17 18 } 18 19 } 19 20 20 - func (s *Scanner[T]) Scan() iter.Seq2[T, error] { 21 - return func(yield func(T, error) bool) { 22 - for s.rows.Next() { 23 - var data T 24 - elem := reflect.ValueOf(&data).Elem() 21 + func (s Scanner[T]) ScanWith(fn func(*T) []any) iter.Seq2[T, error] { 22 + s.scanFunc = fn 23 + return s.Scan() 24 + } 25 + 26 + func (s Scanner[T]) Scan() iter.Seq2[T, error] { 27 + // If no custom scan function provided, use reflection-based default 28 + if s.scanFunc == nil { 29 + s.scanFunc = func(dest *T) []any { 30 + elem := reflect.ValueOf(dest).Elem() 25 31 numCols := elem.NumField() 26 32 columns := make([]any, numCols) 27 33 ··· 30 36 columns[i] = field.Addr().Interface() 31 37 } 32 38 39 + return columns 40 + } 41 + } 42 + 43 + return func(yield func(T, error) bool) { 44 + for s.rows.Next() { 45 + var data T 46 + columns := s.scanFunc(&data) 33 47 err := s.rows.Scan(columns...) 34 48 35 49 if !yield(data, err) {
+63
scanner_test.go
··· 291 291 t.Errorf("user data incorrect: %+v", u) 292 292 } 293 293 } 294 + 295 + func TestScannerWithCustomMapping(t *testing.T) { 296 + db := setupTestDB(t) 297 + defer db.Close() 298 + 299 + rows, err := db.Query("SELECT email, name, id FROM users ORDER BY id") 300 + if err != nil { 301 + t.Fatalf("Failed to query users: %v", err) 302 + } 303 + 304 + scanner := NewScanner[UserBasic](rows) 305 + defer scanner.Close() 306 + 307 + var users []UserBasic 308 + for user, err := range scanner.ScanWith(func(dest *UserBasic) []any { 309 + return []any{&dest.Email, &dest.Name, &dest.ID} 310 + }) { 311 + if err != nil { 312 + t.Fatalf("Failed to scan user: %v", err) 313 + } 314 + users = append(users, user) 315 + } 316 + 317 + if len(users) != 6 { 318 + t.Errorf("Expected 6 users, got %d", len(users)) 319 + } 320 + 321 + if users[0].ID != 1 || users[0].Name != "John Doe" || users[0].Email != "john@example.com" { 322 + t.Errorf("Expected first user to be John Doe, got %+v", users[0]) 323 + } 324 + } 325 + 326 + func TestScannerWithSkipColumn(t *testing.T) { 327 + db := setupTestDB(t) 328 + defer db.Close() 329 + 330 + rows, err := db.Query("SELECT id, email, age, name FROM users ORDER BY id LIMIT 1") 331 + if err != nil { 332 + t.Fatalf("Failed to query users: %v", err) 333 + } 334 + 335 + scanner := NewScanner[UserBasic](rows) 336 + defer scanner.Close() 337 + 338 + var users []UserBasic 339 + for user, err := range scanner.ScanWith(func(dest *UserBasic) []any { 340 + var discard any 341 + return []any{&dest.ID, &dest.Email, &discard, &dest.Name} 342 + }) { 343 + if err != nil { 344 + t.Fatalf("Failed to scan user: %v", err) 345 + } 346 + users = append(users, user) 347 + } 348 + 349 + if len(users) != 1 { 350 + t.Errorf("Expected 1 user, got %d", len(users)) 351 + } 352 + 353 + if users[0].ID != 1 || users[0].Name != "John Doe" || users[0].Email != "john@example.com" { 354 + t.Errorf("User data incorrect: %+v", users[0]) 355 + } 356 + }