package model import ( "database/sql" "fmt" "strings" "time" "git.i2edu.net/i2/go-zero/core/stores/cache" "git.i2edu.net/i2/go-zero/core/stores/sqlc" "git.i2edu.net/i2/go-zero/core/stores/sqlx" "git.i2edu.net/i2/go-zero/core/stringx" "git.i2edu.net/i2/go-zero/tools/goctl/model/sql/builderx" ) var ( userFieldNames = builderx.RawFieldNames(&User{}) userRows = strings.Join(userFieldNames, ",") userRowsExpectAutoSet = strings.Join(stringx.Remove(userFieldNames, "`id`", "`create_time`", "`update_time`"), ",") userRowsWithPlaceHolder = strings.Join(stringx.Remove(userFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?" cacheUserIdPrefix = "cache:user:id:" cacheUserUsernamePrefix = "cache:user:username:" cacheUserWeiXinOpenIdPrefix = "cache:user:weixin_openid:" ) type ( Cache interface { SetCache(key string, v interface{}) error GetCache(key string, v interface{}) error SetWithExpire(key string, v interface{}, expire time.Duration) error } UserModel interface { Insert(data User) (sql.Result, error) FindOne(id int64) (*User, error) FindOneByUsername(username string) (*User, error) FindOneByWeiXinOpenId(openid string) (*User, error) Update(data User) error Delete(id int64) error CacheStorage() Cache } defaultUserModel struct { sqlc.CachedConn table string } User struct { Mobile string `db:"mobile"` Avatar string `db:"avatar"` WeixinOpenid string `db:"weixin_openid"` Password string `db:"password"` Birthday int64 `db:"birthday"` RegisterTime int64 `db:"register_time"` LastLoginTime int64 `db:"last_login_time"` Nickname string `db:"nickname"` Id int64 `db:"id"` Username string `db:"username"` Gender int64 `db:"gender"` UserLevelId int64 `db:"user_level_id"` RegisterIp string `db:"register_ip"` LastLoginIp string `db:"last_login_ip"` } ) func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) UserModel { return &defaultUserModel{ CachedConn: sqlc.NewConn(conn, c), table: "`user`", } } func (m *defaultUserModel) Insert(data User) (sql.Result, error) { userUsernameKey := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, data.Username) ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet) return conn.Exec(query, data.Mobile, data.Avatar, data.WeixinOpenid, data.Password, data.Birthday, data.RegisterTime, data.LastLoginTime, data.Nickname, data.Username, data.Gender, data.UserLevelId, data.RegisterIp, data.LastLoginIp) }, userUsernameKey) return ret, err } func (m *defaultUserModel) FindOne(id int64) (*User, error) { userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id) var resp User err := m.QueryRow(&resp, userIdKey, func(conn sqlx.SqlConn, v interface{}) error { query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userRows, m.table) return conn.QueryRow(v, query, id) }) switch err { case nil: return &resp, nil case sqlc.ErrNotFound: return nil, ErrNotFound default: return nil, err } } func (m *defaultUserModel) FindOneByWeiXinOpenId(id string) (*User, error) { userIdKey := fmt.Sprintf("%s%v", cacheUserWeiXinOpenIdPrefix, id) var resp User err := m.QueryRow(&resp, userIdKey, func(conn sqlx.SqlConn, v interface{}) error { query := fmt.Sprintf("select %s from %s where `weixin_openid` = ? limit 1", userRows, m.table) return conn.QueryRow(v, query, id) }) switch err { case nil: return &resp, nil case sqlc.ErrNotFound: return nil, ErrNotFound default: return nil, err } } func (m *defaultUserModel) FindOneByUsername(username string) (*User, error) { userUsernameKey := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, username) var resp User err := m.QueryRowIndex(&resp, userUsernameKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { query := fmt.Sprintf("select %s from %s where `username` = ? limit 1", userRows, m.table) if err := conn.QueryRow(&resp, query, username); err != nil { return nil, err } return resp.Id, nil }, m.queryPrimary) switch err { case nil: return &resp, nil case sqlc.ErrNotFound: return nil, ErrNotFound default: return nil, err } } func (m *defaultUserModel) Update(data User) error { userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id) userUsernameKey := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, data.Username) _, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userRowsWithPlaceHolder) return conn.Exec(query, data.Mobile, data.Avatar, data.WeixinOpenid, data.Password, data.Birthday, data.RegisterTime, data.LastLoginTime, data.Nickname, data.Username, data.Gender, data.UserLevelId, data.RegisterIp, data.LastLoginIp, data.Id) }, userIdKey, userUsernameKey) return err } func (m *defaultUserModel) Delete(id int64) error { data, err := m.FindOne(id) if err != nil { return err } userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id) userUsernameKey := fmt.Sprintf("%s%v", cacheUserUsernamePrefix, data.Username) _, err = m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("delete from %s where `id` = ?", m.table) return conn.Exec(query, id) }, userUsernameKey, userIdKey) return err } func (m *defaultUserModel) formatPrimary(primary interface{}) string { return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary) } func (m *defaultUserModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error { query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userRows, m.table) return conn.QueryRow(v, query, primary) } func (m *defaultUserModel) SetCache(key string, v interface{}) error { return m.CachedConn.SetCache(key, v) } func (m *defaultUserModel) GetCache(key string, v interface{}) error { return m.CachedConn.GetCache(key, v) } func (m *defaultUserModel) SetWithExpire(key string, v interface{}, expire time.Duration) error { return m.CachedConn.SetWithExpire(key, v, expire) } func (m *defaultUserModel) CacheStorage() Cache { return m }