github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/sqlx/database_test.go (about) 1 package sqlx_test 2 3 import ( 4 "context" 5 "database/sql" 6 "fmt" 7 "os" 8 "testing" 9 "time" 10 11 _ "github.com/go-sql-driver/mysql" 12 "github.com/google/uuid" 13 "github.com/sirupsen/logrus" 14 "github.com/stretchr/testify/assert" 15 16 "github.com/johnnyeven/libtools/runner" 17 "github.com/johnnyeven/libtools/sqlx" 18 "github.com/johnnyeven/libtools/sqlx/builder" 19 "github.com/johnnyeven/libtools/timelib" 20 ) 21 22 var db *sqlx.DB 23 24 func init() { 25 logrus.SetLevel(logrus.DebugLevel) 26 db, _ = sqlx.Open("logger:mysql", "root:root@tcp(localhost:3306)/?charset=utf8&parseTime=true&interpolateParams=true&autocommit=true&loc=Local") 27 } 28 29 type TableOperateTime struct { 30 CreatedAt timelib.MySQLDatetime `db:"F_created_at" sql:"datetime(6) NOT NULL DEFAULT '0' ON UPDATE CURRENT_TIMESTAMP(6)" ` 31 UpdatedAt int64 `db:"F_updated_at" sql:"bigint(64) NOT NULL DEFAULT '0'"` 32 } 33 34 func (t *TableOperateTime) BeforeUpdate() { 35 time.Now() 36 t.UpdatedAt = time.Now().UnixNano() 37 } 38 39 func (t *TableOperateTime) BeforeInsert() { 40 t.CreatedAt = timelib.MySQLDatetime(time.Now()) 41 t.UpdatedAt = t.CreatedAt.Unix() 42 } 43 44 type Gender int 45 46 const ( 47 GenderMale Gender = iota + 1 48 GenderFemale 49 ) 50 51 func (Gender) EnumType() string { 52 return "Gender" 53 } 54 55 func (Gender) Enums() map[int][]string { 56 return map[int][]string{ 57 int(GenderMale): {"male", "男"}, 58 int(GenderFemale): {"female", "女"}, 59 } 60 } 61 62 func (g Gender) String() string { 63 switch g { 64 case GenderMale: 65 return "male" 66 case GenderFemale: 67 return "female" 68 } 69 return "" 70 } 71 72 // @def primary ID 73 // @def index I_nickname Nickname Name 74 // @def unique_index I_name Name 75 type User struct { 76 ID uint64 `db:"F_id" sql:"bigint(64) unsigned NOT NULL AUTO_INCREMENT"` 77 Name string `db:"F_name" sql:"varchar(255) binary NOT NULL DEFAULT ''"` 78 Username string `db:"F_username" sql:"varchar(255)"` 79 Nickname string `db:"F_nickname" sql:"varchar(255) CHARACTER SET latin1 binary NOT NULL DEFAULT ''"` 80 Gender Gender `db:"F_gender" sql:"int(32) NOT NULL DEFAULT '0'"` 81 82 TableOperateTime 83 } 84 85 func (user *User) Comments() map[string]string { 86 return map[string]string{ 87 "Name": "姓名", 88 } 89 } 90 91 func (user *User) AfterInsert(result sql.Result) error { 92 lastInsertID, err := result.LastInsertId() 93 if err != nil { 94 return err 95 } 96 user.ID = uint64(lastInsertID) 97 return nil 98 } 99 100 func (user *User) TableName() string { 101 return "t_user" 102 } 103 104 func (user *User) PrimaryKey() sqlx.FieldNames { 105 return []string{"ID"} 106 } 107 108 func (user *User) Indexes() sqlx.Indexes { 109 return sqlx.Indexes{ 110 "I_nickname": {"Nickname", "Name"}, 111 } 112 } 113 114 func (user *User) UniqueIndexes() sqlx.Indexes { 115 return sqlx.Indexes{ 116 "I_name": {"Name"}, 117 } 118 } 119 120 type User2 struct { 121 User 122 Age int32 `db:"F_age" sql:"int(32) NOT NULL DEFAULT '0'"` 123 } 124 125 func (user2 *User2) Indexes() sqlx.Indexes { 126 return sqlx.Indexes{} 127 } 128 129 func TestMigrate(t *testing.T) { 130 tt := assert.New(t) 131 132 os.Setenv("PROJECT_FEATURE", "test") 133 dbTest := sqlx.NewFeatureDatabase("test_for_migrate") 134 defer func() { 135 err := db.Do(dbTest.Drop()).Err() 136 tt.Nil(err) 137 }() 138 139 { 140 dbTest.Register(&User{}) 141 err := dbTest.MigrateTo(db, false) 142 tt.NoError(err) 143 } 144 { 145 dbTest.Register(&User{}) 146 err := dbTest.MigrateTo(db, false) 147 tt.NoError(err) 148 } 149 { 150 dbTest.Register(&User2{}) 151 err := dbTest.MigrateTo(db, false) 152 tt.NoError(err) 153 } 154 155 { 156 dbTest.Register(&User{}) 157 err := dbTest.MigrateTo(db, false) 158 tt.NoError(err) 159 } 160 } 161 162 func TestCRUD(t *testing.T) { 163 tt := assert.New(t) 164 165 dbTest := sqlx.NewDatabase("test") 166 defer func() { 167 err := db.Do(dbTest.Drop()).Err() 168 tt.Nil(err) 169 }() 170 171 userTable := dbTest.Register(&User{}) 172 err := dbTest.MigrateTo(db, false) 173 tt.Nil(err) 174 175 { 176 user := User{ 177 Name: uuid.New().String(), 178 Gender: GenderMale, 179 } 180 user.BeforeInsert() 181 dbRet := db.Do(dbTest.Insert(&user).Comment("InsertUser")) 182 err := dbRet.Err() 183 tt.Nil(err) 184 user.AfterInsert(dbRet.Result) 185 tt.NotEmpty(user.ID) 186 187 { 188 user.Gender = GenderFemale 189 user.BeforeUpdate() 190 err := db.Do( 191 dbTest.Update(&user). 192 Where( 193 userTable.F("Name").Eq(user.Name), 194 ). 195 Comment("UpdateUser"), 196 ). 197 Err() 198 tt.Nil(err) 199 } 200 201 { 202 userForSelect := User{} 203 err := db.Do( 204 userTable.Select().Where(userTable.F("Name").Eq(user.Name)).Comment("FindUser"), 205 ). 206 Scan(&userForSelect). 207 Err() 208 tt.Nil(err) 209 tt.Equal(userForSelect.Name, user.Name) 210 tt.Equal(userForSelect.CreatedAt.Unix(), user.CreatedAt.Unix()) 211 } 212 213 { 214 user.BeforeInsert() 215 err := db.Do(dbTest.Insert(&user).Comment("Insert Conflict")).Err() 216 t.Log(err) 217 tt.True(sqlx.DBErr(err).IsConflict()) 218 219 { 220 err := db.Do( 221 dbTest.Insert(&user). 222 OnDuplicateKeyUpdate( 223 userTable.AssignsByFieldValues(builder.FieldValues{ 224 "Gender": GenderMale, 225 })..., 226 ).Comment("InsertUserOnDuplicate"), 227 ).Err() 228 tt.Nil(err) 229 } 230 } 231 } 232 233 } 234 235 func TestSelect(t *testing.T) { 236 tt := assert.New(t) 237 238 dbTest := sqlx.NewDatabase("test2") 239 defer func() { 240 err := db.Do(dbTest.Drop()).Err() 241 tt.Nil(err) 242 }() 243 244 table := dbTest.Register(&User{}) 245 err := dbTest.MigrateTo(db, false) 246 tt.Nil(err) 247 248 ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) 249 defer cancel() 250 251 r := runner.NewRunner(ctx, "create data", 30) 252 253 for i := 0; i < 10; i++ { 254 r.Add(func(ctx context.Context) error { 255 user := User{ 256 Name: uuid.New().String(), 257 Gender: GenderMale, 258 } 259 user.BeforeInsert() 260 return db.Do(dbTest.Insert(&user).Comment("InsertUser")).Scan(&user).Err() 261 }, fmt.Sprintf("%d", i)) 262 } 263 264 tt.NoError(r.Commit()) 265 266 { 267 users := make([]User, 0) 268 err := db.Do(table.Select().Where(table.F("Gender").Eq(GenderMale))).Scan(&users).Err() 269 tt.NoError(err) 270 tt.Len(users, 10) 271 } 272 { 273 user := User{} 274 err := db.Do(table.Select().Where(table.F("ID").Eq(11))).Scan(&user).Err() 275 tt.True(sqlx.DBErr(err).IsNotFound()) 276 } 277 { 278 count := 0 279 err := db.Do( 280 table.Select().For(builder.Count(builder.Star())), 281 ).Scan(&count).Err() 282 tt.NoError(err) 283 tt.Equal(10, count) 284 } 285 { 286 user := &User{} 287 err := db.Do(table.Select().Where(table.F("Gender").Eq(GenderMale))).Scan(user).Err() 288 tt.Error(err) 289 } 290 }