sql_scan.go 1.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. package repository
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. )
  7. type sqlQueryer interface {
  8. QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
  9. }
  10. // scanSingleRow 执行查询并扫描第一行到 dest。
  11. // 若无结果,可通过 errors.Is(err, sql.ErrNoRows) 判断。
  12. // 如果 Close 失败,会与原始错误合并返回。
  13. // 设计目的:仅依赖 QueryContext,避免 QueryRowContext 对 *sql.Tx 的强绑定,
  14. // 让 ent.Tx 也能作为 sqlExecutor/Queryer 使用。
  15. func scanSingleRow(ctx context.Context, q sqlQueryer, query string, args []any, dest ...any) (err error) {
  16. rows, err := q.QueryContext(ctx, query, args...)
  17. if err != nil {
  18. return err
  19. }
  20. defer func() {
  21. if closeErr := rows.Close(); closeErr != nil {
  22. err = errors.Join(err, closeErr)
  23. }
  24. }()
  25. if !rows.Next() {
  26. if err = rows.Err(); err != nil {
  27. return err
  28. }
  29. return sql.ErrNoRows
  30. }
  31. if err = rows.Scan(dest...); err != nil {
  32. return err
  33. }
  34. if err = rows.Err(); err != nil {
  35. return err
  36. }
  37. return nil
  38. }