uniugm/admin/apps/user/domain/repo/comm_resource.go
2025-05-16 15:17:10 +08:00

236 lines
8.3 KiB
Go

package repo
import (
"admin/apps/user/domain/entity"
"admin/apps/user/model"
"admin/internal/errcode"
"admin/internal/model/dto"
"admin/lib/passlib"
"admin/lib/xlog"
"errors"
"fmt"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"reflect"
"strings"
"time"
)
type ICommonResourceRepo interface {
List(params *dto.CommonListReq) (int, []*dto.CommonDtoFieldDesc, []*entity.CommonResource, error)
GetById(id int) ([]*dto.CommonDtoFieldDesc, *entity.CommonResource, bool, error)
Create(et dto.CommonDtoValues) (*entity.CommonResource, error)
Edit(et dto.CommonDtoValues) error
Delete(id int) (*entity.CommonResource, bool, error)
}
func NewCommonResourceRepo(db *gorm.DB, poTemplate model.IModel) ICommonResourceRepo {
return newCommonResourceRepoImpl(db, poTemplate)
}
type commonResourceRepoImpl struct {
db *gorm.DB
poTemplate model.IModel
fieldsDescInfoFun func() []*dto.CommonDtoFieldDesc
}
func newCommonResourceRepoImpl(db *gorm.DB, poTemplate model.IModel) *commonResourceRepoImpl {
fieldsInfo := (&entity.CommonResource{}).FromPo(poTemplate).GetDtoFieldsDescInfo
return &commonResourceRepoImpl{db: db, poTemplate: poTemplate, fieldsDescInfoFun: fieldsInfo}
}
func (repo *commonResourceRepoImpl) List(params *dto.CommonListReq) (int, []*dto.CommonDtoFieldDesc, []*entity.CommonResource, error) {
pageNo := params.PageNo
pageLen := params.PageLen
whereConditions := params.ParsedWhereConditions.Conditions
if pageNo <= 0 || pageLen <= 0 {
return 0, nil, nil, errcode.New(errcode.ParamsInvalid, "page no or page len invalid:%v,%v", pageNo, pageLen)
}
limitStart := (pageNo - 1) * pageLen
limitLen := pageLen
listType := reflect.New(reflect.SliceOf(reflect.TypeOf(repo.poTemplate)))
var totalCount int64
var txCount, txFind *gorm.DB
var err error
if len(whereConditions) <= 0 {
txCount = repo.db.Model(repo.poTemplate)
txFind = repo.db.Offset(limitStart).Limit(limitLen).Order("created_at desc")
} else {
whereSql, whereArgs := repo.parseWhereConditions2Sql(whereConditions)
xlog.Debugf("list resource %v where sql:%v, args:%+v",
repo.poTemplate.TableName(), whereSql, whereArgs)
txCount = repo.db.Model(repo.poTemplate).Where(whereSql, whereArgs...)
txFind = repo.db.Where(whereSql, whereArgs...).Offset(limitStart).Limit(limitLen).Order("created_at desc")
}
err = txCount.Count(&totalCount).Error
if err != nil {
return 0, nil, nil, errcode.New(errcode.DBError, "count resource %v error:%v", repo.poTemplate.TableName(), err)
}
err = txFind.Find(listType.Interface()).Error
if err != nil {
return 0, nil, nil, errcode.New(errcode.DBError, "list resource %v error:%v", repo.poTemplate.TableName(), err)
}
listType1 := listType.Elem()
listLen := listType1.Len()
entityList := make([]*entity.CommonResource, 0, listLen)
for i := 0; i < listType1.Len(); i++ {
po := listType1.Index(i).Interface().(model.IModel)
et := &entity.CommonResource{}
et.FromPo(po)
entityList = append(entityList, et)
}
return int(totalCount), repo.fieldsDescInfoFun(), entityList, nil
}
func (repo *commonResourceRepoImpl) GetById(id int) ([]*dto.CommonDtoFieldDesc, *entity.CommonResource, bool, error) {
po := repo.newEmptyPo()
err := repo.db.Where("id = ?", id).First(po).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return repo.fieldsDescInfoFun(), (&entity.CommonResource{}).FromPo(repo.newEmptyPo()), false, nil
}
return nil, nil, false, errcode.New(errcode.DBError, "get resource:%v by id:%v error:%v", repo.poTemplate.TableName(), id, err)
}
return repo.fieldsDescInfoFun(), (&entity.CommonResource{}).FromPo(po), true, nil
}
func (repo *commonResourceRepoImpl) Create(dtoObj dto.CommonDtoValues) (*entity.CommonResource, error) {
if pass, find := dtoObj["UserPass"]; find {
dtoObj["UserPass"] = passlib.EncryptPassword(pass.(string))
xlog.Tracef("create user %v pwd %v, encrypted pwd %v", dtoObj["UserName"], pass, dtoObj["UserPass"])
}
et := (&entity.CommonResource{}).FromPo(repo.newEmptyPo()).FromDto(dtoObj)
err := repo.db.Create(et.Po).Error
if err != nil {
return et, errcode.New(errcode.DBError, "create resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err)
}
return et, nil
}
func (repo *commonResourceRepoImpl) Edit(dtoObj dto.CommonDtoValues) error {
xlog.Infof("update obj:%+v", dtoObj)
if pass, find := dtoObj["UserPass"]; find {
if pass.(string) == "***" {
// 没有改密码
delete(dtoObj, "UserPass")
} else {
dtoObj["UserPass"] = passlib.EncryptPassword(pass.(string))
}
}
et := (&entity.CommonResource{}).FromPo(repo.newEmptyPo()).FromDto(dtoObj)
err := repo.db.Where("id=?", et.Po.GetId()).Updates(et.Po).Error
if err != nil {
return errcode.New(errcode.DBError, "edit resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), et, err)
}
return nil
}
func (repo *commonResourceRepoImpl) Delete(id int) (*entity.CommonResource, bool, error) {
_, et, find, err := repo.GetById(id)
if err != nil {
return nil, false, err
}
if !find {
return et, false, nil
}
err = repo.db.Where("id=?", id).Unscoped().Delete(repo.poTemplate).Error
if err != nil {
return nil, false, errcode.New(errcode.DBError, "delete resource:%v obj:%+v error:%v", repo.poTemplate.TableName(), id, err)
}
return et, true, nil
}
func (repo *commonResourceRepoImpl) newEmptyPo() model.IModel {
return reflect.New(reflect.TypeOf(repo.poTemplate).Elem()).Interface().(model.IModel)
}
func (repo *commonResourceRepoImpl) parseWhereConditions2Sql(conditions []*dto.GetWhereCondition) (whereSql string, args []any) {
namer := new(schema.NamingStrategy)
to := reflect.TypeOf(repo.poTemplate).Elem()
whereClause := make([]string, 0, len(conditions))
whereArgs := make([]interface{}, 0, len(conditions))
for _, cond := range conditions {
for i := 0; i < to.NumField(); i++ {
field := to.Field(i)
if field.Name != cond.Key {
continue
}
dbFieldName := namer.ColumnName("", field.Name)
if field.Type.Name() == "Time" {
if cond.Value1 == nil {
cond.Value1 = time.Time{}
} else {
cond.Value1, _ = time.ParseInLocation("2006/01/02 15:04:05", cond.Value1.(string), time.Local)
}
if cond.Value2 == nil {
cond.Value2 = time.Time{}
} else {
cond.Value2, _ = time.ParseInLocation("2006/01/02 15:04:05", cond.Value2.(string), time.Local)
}
}
switch field.Tag.Get("where") {
case "eq":
if field.Tag.Get("type") == "[]string" && field.Tag.Get("multi_choice") == "true" {
// eq也要查出来为空的
whereClause = append(whereClause, fmt.Sprintf("JSON_CONTAINS( `%v`, '\"%v\"', '$' ) or `%v` IS NULL",
dbFieldName, cond.Value1, dbFieldName))
} else {
whereClause = append(whereClause, fmt.Sprintf("`%v` = ?", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
}
case "gt":
whereClause = append(whereClause, fmt.Sprintf("`%v` > ?", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
case "lt":
whereClause = append(whereClause, fmt.Sprintf("`%v` < ?", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
case "le":
whereClause = append(whereClause, fmt.Sprintf("`%v` <= ?", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
case "ge":
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ?", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
case "like":
whereClause = append(whereClause, fmt.Sprintf("`%v` like ?", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
case "range":
t1, ok1 := cond.Value1.(time.Time)
t2, ok2 := cond.Value2.(time.Time)
if ok1 || ok2 {
if !t1.IsZero() && !t2.IsZero() {
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? and `%v` <= ?", dbFieldName, dbFieldName))
whereArgs = append(whereArgs, cond.Value1, cond.Value2)
} else if !t1.IsZero() {
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? ", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
} else {
whereClause = append(whereClause, fmt.Sprintf("`%v` <= ? ", dbFieldName))
whereArgs = append(whereArgs, cond.Value2)
}
} else {
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? and `%v` <= ?", dbFieldName, dbFieldName))
whereArgs = append(whereArgs, cond.Value1, cond.Value2)
}
case "":
default:
panic(fmt.Errorf("unsupport where tag %v", field.Tag))
}
}
}
whereSql = strings.Join(whereClause, " AND ")
return whereSql, whereArgs
}