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 }