github.com/octohelm/storage@v0.0.0-20240516030302-1ac2cc1ea347/internal/sql/scanner/scan_test.go (about)

     1  package scanner
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/octohelm/storage/internal/testutil"
     8  	"github.com/octohelm/storage/pkg/dberr"
     9  
    10  	"github.com/DATA-DOG/go-sqlmock"
    11  )
    12  
    13  type T struct {
    14  	I int    `db:"f_i"`
    15  	S string `db:"f_s"`
    16  }
    17  
    18  type Any string
    19  
    20  type T2 T
    21  
    22  func (t *T2) ColumnReceivers() map[string]interface{} {
    23  	return map[string]interface{}{
    24  		"f_i": &t.I,
    25  		"f_s": &t.S,
    26  	}
    27  }
    28  
    29  type TDataList struct {
    30  	Data []T
    31  }
    32  
    33  func (*TDataList) New() interface{} {
    34  	return &T{}
    35  }
    36  
    37  func (l *TDataList) Next(v interface{}) error {
    38  	t := v.(*T)
    39  	l.Data = append(l.Data, *t)
    40  	return nil
    41  }
    42  
    43  func BenchmarkScan(b *testing.B) {
    44  	db, mock, _ := sqlmock.New()
    45  	defer db.Close()
    46  
    47  	b.Run("Scan to struct", func(b *testing.B) {
    48  		sql := "SELECT f_i,f_s from t"
    49  
    50  		mockRows := mock.NewRows([]string{"f_i", "f_s"})
    51  		mockRows.AddRow(2, "4")
    52  
    53  		_ = mock.ExpectQuery(sql).WillReturnRows(mockRows)
    54  
    55  		target := &T{}
    56  
    57  		for i := 0; i < b.N; i++ {
    58  			rows, _ := db.Query(sql)
    59  			_ = Scan(context.Background(), rows, target)
    60  		}
    61  
    62  		b.Log(target)
    63  	})
    64  
    65  	b.Run("Scan to struct with column receivers", func(b *testing.B) {
    66  		sql := "SELECT f_i,f_s from t"
    67  
    68  		mockRows := mock.NewRows([]string{"f_i", "f_s"})
    69  		mockRows.AddRow(2, "4")
    70  
    71  		_ = mock.ExpectQuery(sql).WillReturnRows(mockRows)
    72  
    73  		target := &T2{}
    74  
    75  		for i := 0; i < b.N; i++ {
    76  			rows, _ := db.Query(sql)
    77  			_ = Scan(context.Background(), rows, target)
    78  		}
    79  
    80  		b.Log(target)
    81  	})
    82  }
    83  
    84  func TestScan(t *testing.T) {
    85  	db, mock, _ := sqlmock.New()
    86  	defer db.Close()
    87  
    88  	t.Run("Scan to struct", func(t *testing.T) {
    89  		sql := "SELECT f_i,f_s from t"
    90  
    91  		mockRows := mock.NewRows([]string{"f_i", "f_s"})
    92  		mockRows.AddRow(2, "4")
    93  
    94  		_ = mock.ExpectQuery(sql).WillReturnRows(mockRows)
    95  
    96  		target := &T{}
    97  		rows, _ := db.Query(sql)
    98  		err := Scan(context.Background(), rows, target)
    99  		testutil.Expect(t, err, testutil.Be[error](nil))
   100  		testutil.Expect(t, target, testutil.Equal(&T{
   101  			I: 2,
   102  			S: "4",
   103  		}))
   104  	})
   105  
   106  	t.Run("Scan to struct with column receivers", func(t *testing.T) {
   107  		sql := "SELECT f_i,f_s from t"
   108  
   109  		mockRows := mock.NewRows([]string{"f_i", "f_s"})
   110  		mockRows.AddRow(2, "4")
   111  
   112  		_ = mock.ExpectQuery(sql).WillReturnRows(mockRows)
   113  
   114  		target := &T2{}
   115  		rows, _ := db.Query(sql)
   116  		err := Scan(context.Background(), rows, target)
   117  		testutil.Expect(t, err, testutil.Be[error](nil))
   118  		testutil.Expect(t, target, testutil.Equal(&T2{
   119  			I: 2,
   120  			S: "4",
   121  		}))
   122  	})
   123  
   124  	t.Run("Scan to struct without no record", func(t *testing.T) {
   125  		sql := "SELECT f_i,f_s from t"
   126  
   127  		mockRows := mock.NewRows([]string{"f_i", "f_s"})
   128  
   129  		_ = mock.ExpectQuery(sql).WillReturnRows(mockRows)
   130  
   131  		target := &T{}
   132  		rows, err := db.Query(sql)
   133  		testutil.Expect(t, err, testutil.Be[error](nil))
   134  
   135  		err = Scan(context.Background(), rows, target)
   136  		testutil.Expect(t, dberr.IsErrNotFound(err), testutil.Be(true))
   137  	})
   138  
   139  	t.Run("Scan to count", func(t *testing.T) {
   140  		mockRows := mock.NewRows([]string{"count(1)"})
   141  		mockRows.AddRow(10)
   142  
   143  		_ = mock.ExpectQuery("SELECT .+ from t").WillReturnRows(mockRows)
   144  
   145  		count := 0
   146  		rows, err := db.Query("SELECT count(1) from t")
   147  		testutil.Expect(t, err, testutil.Be[error](nil))
   148  
   149  		err = Scan(context.Background(), rows, &count)
   150  		testutil.Expect(t, err, testutil.Be[error](nil))
   151  		testutil.Expect(t, count, testutil.Equal(10))
   152  	})
   153  
   154  	t.Run("Scan to count failed when bad receiver", func(t *testing.T) {
   155  		mockRows := mock.NewRows([]string{"count(1)"})
   156  		mockRows.AddRow(10)
   157  
   158  		_ = mock.ExpectQuery("SELECT .+ from t").WillReturnRows(mockRows)
   159  
   160  		v := Any("")
   161  		rows, err := db.Query("SELECT count(1) from t")
   162  		testutil.Expect(t, err, testutil.Be[error](nil))
   163  
   164  		err = Scan(context.Background(), rows, &v)
   165  		testutil.Expect(t, err, testutil.Not(testutil.Be[error](nil)))
   166  	})
   167  
   168  	t.Run("Scan to slice", func(t *testing.T) {
   169  		mockRows := mock.NewRows([]string{"f_i", "f_s"})
   170  		mockRows.AddRow(2, "2")
   171  		mockRows.AddRow(3, "3")
   172  
   173  		_ = mock.ExpectQuery("SELECT .+ from t").WillReturnRows(mockRows)
   174  
   175  		list := make([]T, 0)
   176  		rows, err := db.Query("SELECT f_i,f_b from t")
   177  		testutil.Expect(t, err, testutil.Be[error](nil))
   178  
   179  		err = Scan(context.Background(), rows, &list)
   180  
   181  		testutil.Expect(t, err, testutil.Be[error](nil))
   182  		testutil.Expect(t, list, testutil.Equal([]T{
   183  			{
   184  				I: 2,
   185  				S: "2",
   186  			},
   187  			{
   188  				I: 3,
   189  				S: "3",
   190  			},
   191  		}))
   192  	})
   193  
   194  	t.Run("Scan to iterator", func(t *testing.T) {
   195  		mockRows := mock.NewRows([]string{"f_i", "f_s"})
   196  		mockRows.AddRow(2, "2")
   197  		mockRows.AddRow(3, "3")
   198  
   199  		_ = mock.ExpectQuery("SELECT .+ from t").WillReturnRows(mockRows)
   200  
   201  		rows, err := db.Query("SELECT f_i,f_b from t")
   202  		testutil.Expect(t, err, testutil.Be[error](nil))
   203  
   204  		list := TDataList{}
   205  
   206  		err = Scan(context.Background(), rows, &list)
   207  
   208  		testutil.Expect(t, err, testutil.Be[error](nil))
   209  		testutil.Expect(t, list.Data, testutil.Equal([]T{
   210  			{
   211  				I: 2,
   212  				S: "2",
   213  			},
   214  			{
   215  				I: 3,
   216  				S: "3",
   217  			},
   218  		}))
   219  	})
   220  }