🎨 better model code
This commit is contained in:
		
							parent
							
								
									eaf4bb4ad8
								
							
						
					
					
						commit
						9b24a1f645
					
				@ -2,8 +2,10 @@ package errcode
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ErrAnimalSqlFind = iota + ErrAnimal
 | 
			
		||||
	AnimalNoFind
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func AnimalMsgInit(m msg) {
 | 
			
		||||
	m[ErrAnimalSqlFind] = "Animals 表单查询失败"
 | 
			
		||||
	m[AnimalNoFind] = "Animals 没有查询到符合条件的目标"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,122 +3,56 @@ package web
 | 
			
		||||
import (
 | 
			
		||||
	"catface/app/global/consts"
 | 
			
		||||
	"catface/app/global/errcode"
 | 
			
		||||
	"catface/app/global/variable"
 | 
			
		||||
	"catface/app/model"
 | 
			
		||||
	"catface/app/utils/model_handler"
 | 
			
		||||
	"catface/app/utils/query_handler"
 | 
			
		||||
	"catface/app/service/animals/curd"
 | 
			
		||||
	"catface/app/utils/response"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Animals struct { // INFO 起到一个标记的作用,这样 web.xxx 的时候不同模块就不会命名冲突了。
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func buildSelectAttrs(db *gorm.DB, attrs string) *gorm.DB {
 | 
			
		||||
	if len(attrs) > 0 {
 | 
			
		||||
		// 1. 获取空 Field
 | 
			
		||||
		fieldMap := model_handler.GetModelField(model.Animal{})
 | 
			
		||||
 | 
			
		||||
		// 2. 开始检查请求字段
 | 
			
		||||
		attrsArray := query_handler.StringToStringArray(attrs)
 | 
			
		||||
		for _, attr := range attrsArray {
 | 
			
		||||
			if attr == "*" { // 不需要过滤,直接返回
 | 
			
		||||
				return db
 | 
			
		||||
			} else if attr == "avatar" {
 | 
			
		||||
				fieldMap["avatar_height"] = true
 | 
			
		||||
				fieldMap["avatar_width"] = true
 | 
			
		||||
			}
 | 
			
		||||
			// 过滤 无效 的请求字段
 | 
			
		||||
			if _, ok := fieldMap[attr]; ok {
 | 
			
		||||
				fieldMap[attr] = true
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 3. 装填字段,并 Select
 | 
			
		||||
		var validSelectedFields []string
 | 
			
		||||
		for key, value := range fieldMap {
 | 
			
		||||
			if value {
 | 
			
		||||
				validSelectedFields = append(validSelectedFields, key)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		db = db.Select(validSelectedFields)
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: 通过检查字段的方式构建 Where 函数。
 | 
			
		||||
 * @param {*gorm.DB} db
 | 
			
		||||
 * @param {map[string][]uint8} conditions
 | 
			
		||||
 * @return {*}
 | 
			
		||||
 */
 | 
			
		||||
func buildQuery(db *gorm.DB, conditions map[string][]uint8) *gorm.DB {
 | 
			
		||||
	for field, values := range conditions {
 | 
			
		||||
		if len(values) == 0 || len(values) == 1 && values[0] == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		db = db.Where(field+" in (?)", values)
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Animals) List(context *gin.Context) {
 | 
			
		||||
	// 1. Get Params
 | 
			
		||||
	attrs := context.GetString(consts.ValidatorPrefix + "attrs")
 | 
			
		||||
	gender := query_handler.StringToUint8Array(context.GetString(consts.ValidatorPrefix + "gender"))
 | 
			
		||||
	breed := query_handler.StringToUint8Array(context.GetString(consts.ValidatorPrefix + "breed"))
 | 
			
		||||
	sterilzation := query_handler.StringToUint8Array(context.GetString(consts.ValidatorPrefix + "sterilzation"))
 | 
			
		||||
	status := query_handler.StringToUint8Array(context.GetString(consts.ValidatorPrefix + "status"))
 | 
			
		||||
	gender := context.GetString(consts.ValidatorPrefix + "gender")
 | 
			
		||||
	breed := context.GetString(consts.ValidatorPrefix + "breed")
 | 
			
		||||
	sterilzation := context.GetString(consts.ValidatorPrefix + "sterilzation")
 | 
			
		||||
	status := context.GetString(consts.ValidatorPrefix + "status")
 | 
			
		||||
	num := context.GetFloat64(consts.ValidatorPrefix + "num")
 | 
			
		||||
	skip := context.GetFloat64(consts.ValidatorPrefix + "skip")
 | 
			
		||||
 | 
			
		||||
	// 创建条件映射
 | 
			
		||||
	conditions := map[string][]uint8{
 | 
			
		||||
		"gender":        gender,
 | 
			
		||||
		"breed":         breed,
 | 
			
		||||
		"sterilization": sterilzation,
 | 
			
		||||
		"status":        status,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 2. Select & Filter
 | 
			
		||||
	if num == 0 {
 | 
			
		||||
		num = 10
 | 
			
		||||
	}
 | 
			
		||||
	db := variable.GormDbMysql.Table("animals").Limit(int(num)).Offset(int(skip))
 | 
			
		||||
	db = buildSelectAttrs(db, attrs)
 | 
			
		||||
	db = buildQuery(db, conditions)
 | 
			
		||||
 | 
			
		||||
	// 3. Find
 | 
			
		||||
	var animals []model.Animal
 | 
			
		||||
	err := db.Find(&animals).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		response.Fail(context, errcode.ErrAnimalSqlFind, errcode.ErrMsg[errcode.ErrAnimalSqlFind], err) // UPDATE consts ?
 | 
			
		||||
	} else {
 | 
			
		||||
	animals := curd.CreateUserCurdFactory().List(attrs, gender, breed, sterilzation, status, int(num), int(skip))
 | 
			
		||||
	if animals != nil {
 | 
			
		||||
		response.Success(context, consts.CurdStatusOkMsg, animals)
 | 
			
		||||
	} else {
 | 
			
		||||
		response.Fail(context, errcode.AnimalNoFind, errcode.ErrMsg[errcode.AnimalNoFind], "")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// v1
 | 
			
		||||
// func (a *Animals) Detail(context *gin.Context) {
 | 
			
		||||
// 	// 1. Get Params
 | 
			
		||||
// 	anmId, err := strconv.Atoi(context.Param("anm_id"))
 | 
			
		||||
 | 
			
		||||
// 	// 2. Select & Filter
 | 
			
		||||
// 	var animal model.Animal
 | 
			
		||||
// 	err = variable.GormDbMysql.Table("animals").Model(&animal).Where("id = ?", anmId).Scan(&animal).Error // TIP GORM.First 采取默认的
 | 
			
		||||
// 	if err != nil {
 | 
			
		||||
// 		response.Fail(context, errcode.ErrAnimalSqlFind, errcode.ErrMsg[errcode.ErrAnimalSqlFind], err) // UPDATE consts ?
 | 
			
		||||
// 	} else {
 | 
			
		||||
// 		response.Success(context, consts.CurdStatusOkMsg, animal)
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
func (a *Animals) Detail(context *gin.Context) {
 | 
			
		||||
	// 1. Get Params
 | 
			
		||||
	anmId, err := strconv.Atoi(context.Param("anm_id"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		response.Fail(context, errcode.ErrAnimalSqlFind, errcode.ErrMsg[errcode.ErrAnimalSqlFind], err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("anmId:", anmId)
 | 
			
		||||
	anmId := context.Param("anm_id")
 | 
			
		||||
 | 
			
		||||
	// 2. Select & Filter
 | 
			
		||||
	var animal model.Animal
 | 
			
		||||
	err = variable.GormDbMysql.Table("animals").Model(&animal).Where("id = ?", anmId).Scan(&animal).Error // TIP GORM.First 采取默认的
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		response.Fail(context, errcode.ErrAnimalSqlFind, errcode.ErrMsg[errcode.ErrAnimalSqlFind], err) // UPDATE consts ?
 | 
			
		||||
	} else {
 | 
			
		||||
	animal := curd.CreateUserCurdFactory().Detail(anmId)
 | 
			
		||||
	if animal != nil {
 | 
			
		||||
		response.Success(context, consts.CurdStatusOkMsg, animal)
 | 
			
		||||
	} else {
 | 
			
		||||
		response.Fail(context, errcode.AnimalNoFind, errcode.ErrMsg[errcode.AnimalNoFind], "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,16 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"catface/app/global/variable"
 | 
			
		||||
	"catface/app/utils/gorm_v2"
 | 
			
		||||
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func CreateAnimalFactory(sqlType string) *Animal {
 | 
			
		||||
	return &Animal{BaseModel: BaseModel{DB: UseDbConn(sqlType)}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Animal struct {
 | 
			
		||||
	BaseModel              // 假设 BaseModel 中不需要添加 omitempty 标签
 | 
			
		||||
	Name           string  `gorm:"type:varchar(20)" json:"name,omitempty"`                            // 名称
 | 
			
		||||
@ -21,37 +32,35 @@ type Animal struct {
 | 
			
		||||
	Tags           string  `json:"tags,omitempty"` // 活动半径
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Breed struct {
 | 
			
		||||
	BriefModel
 | 
			
		||||
func (a *Animal) TableName() string {
 | 
			
		||||
	return "animals"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Sterilzation struct { // TEST How to use BriefModel, the dif between Common
 | 
			
		||||
	Id     int64  `json:"id"`
 | 
			
		||||
	NameZh string `json:"name_zh"`
 | 
			
		||||
	NameEn string `json:"name_en"`
 | 
			
		||||
func (a *Animal) Show(attrs []string, gender []uint8, breed []uint8, sterilzation []uint8, status []uint8, num int, skip int) (temp []Animal) {
 | 
			
		||||
	db := a.DB.Table(a.TableName()).Limit(int(num)).Offset(int(skip)).Select(attrs)
 | 
			
		||||
 | 
			
		||||
	// 创建条件映射
 | 
			
		||||
	conditions := map[string][]uint8{
 | 
			
		||||
		"gender":        gender,
 | 
			
		||||
		"breed":         breed,
 | 
			
		||||
		"sterilization": sterilzation,
 | 
			
		||||
		"status":        status,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	db = gorm_v2.BuildWhere(db, conditions)
 | 
			
		||||
 | 
			
		||||
	err := db.Find(&temp).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		variable.ZapLog.Error("Animal Show Error", zap.Error(err))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AnmStatus struct {
 | 
			
		||||
	BriefModel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AnmGender struct {
 | 
			
		||||
	BriefModel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: 保留 Top 3, 辅助 catface - breed 子模型判断; 单独建表,因为只会被 CatFace 模块使用。
 | 
			
		||||
 * @return {*}
 | 
			
		||||
 */
 | 
			
		||||
type AnmFaceBreed struct { // TODO 迁移 python 的时候再考虑一下细节
 | 
			
		||||
	BriefModel
 | 
			
		||||
	Top1  uint8
 | 
			
		||||
	Prob1 float64
 | 
			
		||||
	Top2  uint8
 | 
			
		||||
	Prob2 float64
 | 
			
		||||
	Top3  uint8
 | 
			
		||||
	Prob3 float64
 | 
			
		||||
 | 
			
		||||
	AnimalId int64 // INFO 外键设定?
 | 
			
		||||
	Animal   Animal
 | 
			
		||||
func (a *Animal) ShowByID(id int) *Animal {
 | 
			
		||||
	var temp Animal
 | 
			
		||||
	err := a.DB.Table(a.TableName()).Model(&temp).Where("id = ?", id).Scan(&temp).Error
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		variable.ZapLog.Error("Animal ShowByID Error", zap.Error(err))
 | 
			
		||||
	}
 | 
			
		||||
	return &temp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								app/model/animal_com.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/model/animal_com.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
// INFO 一些基础表单的整合
 | 
			
		||||
 | 
			
		||||
type Breed struct {
 | 
			
		||||
	BriefModel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Sterilzation struct { // TEST How to use BriefModel, the dif between Common
 | 
			
		||||
	Id     int64  `json:"id"`
 | 
			
		||||
	NameZh string `json:"name_zh"`
 | 
			
		||||
	NameEn string `json:"name_en"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AnmStatus struct {
 | 
			
		||||
	BriefModel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AnmGender struct {
 | 
			
		||||
	BriefModel
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								app/model/animal_face_breed.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/model/animal_face_breed.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: 保留 Top 3, 辅助 catface - breed 子模型判断; 单独建表,因为只会被 CatFace 模块使用。
 | 
			
		||||
 * @return {*}
 | 
			
		||||
 */
 | 
			
		||||
type AnmFaceBreed struct { // TODO 迁移 python 的时候再考虑一下细节
 | 
			
		||||
	BriefModel
 | 
			
		||||
	Top1  uint8
 | 
			
		||||
	Prob1 float64
 | 
			
		||||
	Top2  uint8
 | 
			
		||||
	Prob2 float64
 | 
			
		||||
	Top3  uint8
 | 
			
		||||
	Prob3 float64
 | 
			
		||||
 | 
			
		||||
	AnimalId int64 // INFO 外键设定?
 | 
			
		||||
	Animal   Animal
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								app/model/encounter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/model/encounter.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
type post struct { // Encounter 或者称为 post,指的就是 Human 单次的记录。
 | 
			
		||||
	BaseModel
 | 
			
		||||
	UserID int
 | 
			
		||||
}
 | 
			
		||||
@ -17,7 +17,7 @@ import (
 | 
			
		||||
// 参数说明: 传递空值,默认使用 配置文件选项:UseDbType(mysql)
 | 
			
		||||
 | 
			
		||||
func CreateUserFactory(sqlType string) *UsersModel {
 | 
			
		||||
	return &UsersModel{BaseModel: BaseModel{DB: UseDbConn(sqlType)}}
 | 
			
		||||
	return &UsersModel{BaseModel: BaseModel{DB: UseDbConn(sqlType)}} // INFO 这里补充 DB 的指针
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UsersModel struct {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										74
									
								
								app/service/animals/curd/animals_curd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								app/service/animals/curd/animals_curd.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
package curd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"catface/app/model"
 | 
			
		||||
	"catface/app/utils/model_handler"
 | 
			
		||||
	"catface/app/utils/query_handler"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func CreateUserCurdFactory() *AnimalsCurd {
 | 
			
		||||
	return &AnimalsCurd{model.CreateAnimalFactory("")}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AnimalsCurd struct {
 | 
			
		||||
	animals *model.Animal // INFO 难道数据就是存储到这里?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getSelectAttrs(attrs string) (validSelectedFields []string) {
 | 
			
		||||
	if len(attrs) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	// 1. 获取空 Field
 | 
			
		||||
	fieldMap := model_handler.GetModelField(model.Animal{})
 | 
			
		||||
 | 
			
		||||
	// 2. 开始检查请求字段
 | 
			
		||||
	attrsArray := query_handler.StringToStringArray(attrs)
 | 
			
		||||
	for _, attr := range attrsArray {
 | 
			
		||||
		if attr == "*" { // 不需要过滤,直接返回
 | 
			
		||||
			return nil
 | 
			
		||||
		} else if attr == "avatar" {
 | 
			
		||||
			fieldMap["avatar_height"] = true
 | 
			
		||||
			fieldMap["avatar_width"] = true
 | 
			
		||||
		}
 | 
			
		||||
		// 过滤 无效 的请求字段
 | 
			
		||||
		if _, ok := fieldMap[attr]; ok {
 | 
			
		||||
			fieldMap[attr] = true
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 3. 装填字段
 | 
			
		||||
	for key, value := range fieldMap {
 | 
			
		||||
		if value {
 | 
			
		||||
			validSelectedFields = append(validSelectedFields, key)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AnimalsCurd) List(attrs string, gender string, breed string, sterilzation string, status string, num int, skip int) []model.Animal {
 | 
			
		||||
	validSelectedFields := getSelectAttrs(attrs)
 | 
			
		||||
	genderArray := query_handler.StringToUint8Array(gender)
 | 
			
		||||
	breedArray := query_handler.StringToUint8Array(breed)
 | 
			
		||||
	sterilzationArray := query_handler.StringToUint8Array(sterilzation)
 | 
			
		||||
	statusArray := query_handler.StringToUint8Array(status)
 | 
			
		||||
 | 
			
		||||
	if num == 0 {
 | 
			
		||||
		num = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return model.CreateAnimalFactory("mysql").Show(validSelectedFields, genderArray, breedArray, sterilzationArray, statusArray, num, skip)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *AnimalsCurd) Detail(id string) *model.Animal {
 | 
			
		||||
	idInt, err := strconv.Atoi(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// TODO LOG
 | 
			
		||||
		fmt.Println("Detail id error:", err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return model.CreateAnimalFactory("mysql").ShowByID(idInt)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								app/utils/gorm_v2/utils.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/utils/gorm_v2/utils.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
package gorm_v2
 | 
			
		||||
 | 
			
		||||
import "gorm.io/gorm"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: 通过检查字段的方式构建 Where 函数。
 | 
			
		||||
 * @param {*gorm.DB} db
 | 
			
		||||
 * @param {map[string][]uint8} conditions
 | 
			
		||||
 * @return {*}
 | 
			
		||||
 */
 | 
			
		||||
func BuildWhere(db *gorm.DB, conditions map[string][]uint8) *gorm.DB {
 | 
			
		||||
	for field, values := range conditions {
 | 
			
		||||
		if len(values) == 0 || len(values) == 1 && values[0] == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		db = db.Where(field+" in (?)", values)
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
@ -30,7 +30,7 @@ func getProcessedJSONTag(field reflect.StructField) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetModelField(v interface{}) map[string]bool {
 | 
			
		||||
	t := reflect.TypeOf(v)
 | 
			
		||||
	t := reflect.TypeOf(v) // TODO 特化处理掉 BaseModel 这样的继承字段
 | 
			
		||||
 | 
			
		||||
	fieldMap := make(map[string]bool)
 | 
			
		||||
	for i := 0; i < t.NumField(); i++ {
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user