從golang-gin-realworld-example-app項目學寫httpapi (二)

https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/users/models.gogit

模型定義

users/models.gogithub

package users

import (
    "errors"
    "github.com/jinzhu/gorm"
    "github.com/wangzitian0/golang-gin-starter-kit/common"
    "golang.org/x/crypto/bcrypt"
)

// UserModel對象,對應用戶表
// gorm結構體標記,經常使用的column, type, size, primary_key, unique, index, unique_index, not null, -(忽略此字段)
type UserModel struct {
    ID           uint    `gorm:"primary_key"`
    Username     string  `gorm:"column:username"`
    Email        string  `gorm:"column:email;unique_index"`
    Bio          string  `gorm:"column:bio;size:1024"`
    Image        *string `gorm:"column:image"`
    PasswordHash string  `gorm:"column:password;not null"`
}

// FollowModel對象,對應關注表
// gorm.Model 是一個包含了基本字段的結構(struct), 其中包括字段: ID、CreatedAt、UpdatedAt、DeletedAt(邏輯刪除字段)
type FollowModel struct {
    gorm.Model
    Following    UserModel
    FollowingID  uint
    FollowedBy   UserModel
    FollowedByID uint
}

// 函數 用於建立表結構
// 若是不特別指定表名,以對象名大寫單詞拆分,用下劃線鏈接,未尾加s 指定表名,如UserModel -> user_models
func AutoMigrate() {
    // 獲取數據庫鏈接
    db := common.GetDB()

    // 整合表結構,會建立新增的字段,不會改變原有字段內容,能夠選擇db.CreateTable代替
    db.AutoMigrate(&UserModel{})
    db.AutoMigrate(&FollowModel{})
    //db.CreateTable(&UserModel{})
    //db.CreateTable(&FollowModel{})
}

// UserModel對象的內置方法 用於設置密碼, 使用 if err := user.setPassword("password0"); err !=nil { ... }
func (u *UserModel) setPassword(password string) error {
    if len(password) == 0 {
        return errors.New("password should not be empty!")
    }

    bytePassword := []byte(password)
    
    // `bcrypt generator cost` 取值 [4, 32] 間
    passwordHash, _ := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
    u.PasswordHash = string(passwordHash)
    return nil
}

// UserModel對象的內置方法 用於校驗密碼,使用 if err := user.checkPassword("password0"); err != nil { ... }
func (u *UserModel) checkPassword(password string) error {
    bytePassword := []byte(password)
    byteHashedPassword := []byte(u.PasswordHash)
        
    return bcrypt.CompareHashAndPassword(byteHashedPassword, bytePassword)
}

// UserModel對象相關的函數 用於查找符合條件的第一條記錄,使用 user, err := FindOneUser(&UserModel{Username: "username0"})
func FindOneUser(condition interface{}) (UserModel, error) {
    db := common.GetDB()
    var model UserModel
    // condition使用Struct 或者 Map
    err := db.Where(condition).First(&model).Error
    return model, err
}

// UserModel對象相關的函數 用於插入記錄,使用 if err := SaveOne(&userModel); err != nil { ... }
func SaveOne(data interface{}) error {
    db := common.GetDB()
    err := db.Save(data).Error
    //err := db.Create(data).Error
    return err
}

// UserModel對象的內置方法 用於更新記錄,使用 if err := user.Update(UserModel{Username: "wangzitian0"}); err !=nil { ... }
func (model *UserModel) Update(data interface{}) error {
    db := common.GetDB()
    err := db.Model(model).Update(data).Error
    return err
}

// UserModel對象的內置方法 創建用戶間關注(user1 -> user2),使用 if err := user1.following(user2); err != nil { ... }
func (u UserModel) following(v UserModel) error {
    db := common.GetDB()

    var follow FollowModel
    // 查詢是否創建關注,若是沒有則創建
    err := db.FirstOrCreate(&follow, &FollowModel{
        FollowingID:  v.ID,
        FollowedByID: u.ID,
    }).Error
    
    return err
}

// UserModel對象的內置方法 查詢用戶間是否關注(user1 -> user2),使用 if  ok := user1.isFollowing(user2); if ok { ... }
func (u UserModel) isFollowing(v UserModel) bool {
    db := common.GetDB()

    var follow FollowModel
    db.Where(FollowModel{
        FollowingID:  v.ID,
        FollowedByID: u.ID,
    }).First(&follow)

    // 查詢是否關注,若是有關注,返回True(用戶ID非0值),沒有關注(用戶ID爲0值)
    return follow.ID != 0
}

// UserModel對象的內置方法 取消用戶間關注,使用 if err := user1.unFollowing(user2); err != nil { ... }
func (u UserModel) unFollowing(v UserModel) error {
    db := common.GetDB()

    err := db.Where(FollowModel{
        FollowingID:  v.ID,
        FollowedByID: u.ID,
    }).Delete(FollowModel{}).Error
    
    //由於FollowModel包含DeletedAt字段,此處爲邏輯刪除,實際執行的是 UPDATE follow_models SET deleted_at="2013-10-29 10:23" WHERE ...;
    return err
}

// UserModel對象的內置方法 查詢指定用戶的全部關注,使用 followings := user1.GetFollowings()
func (u UserModel) GetFollowings() []UserModel {
    db := common.GetDB()

    // 事務處理開始
    tx := db.Begin()
    var follows []FollowModel
    var followings []UserModel

    // 獲取關注表裏全部相關的關聯記錄
    tx.Where(FollowModel{
        FollowedByID: u.ID,
    }).Find(&follows)

    // 循環每條關聯記錄 
    for _, follow := range follows {
        var userModel UserModel
        // 第2參數Following爲外鍵名
        tx.Model(&follow).Related(&userModel, "Following")
        followings = append(followings, userModel)
    }

    // 事務處理結束   
    tx.Commit()
    return followings
}
相關文章
相關標籤/搜索